mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-22 01:25:44 +03:00
Add knock information in admin exported data (#11171)
Signed-off-by: Rafael Goncalves <rafaelgoncalves@riseup.net>
This commit is contained in:
parent
e002faee01
commit
0e16b418f6
5 changed files with 99 additions and 2 deletions
1
changelog.d/11171.misc
Normal file
1
changelog.d/11171.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Add knock information in admin export. Contributed by Rafael Gonçalves.
|
|
@ -145,6 +145,20 @@ class FileExfiltrationWriter(ExfiltrationWriter):
|
|||
for event in state.values():
|
||||
print(json.dumps(event), file=f)
|
||||
|
||||
def write_knock(self, room_id, event, state):
|
||||
self.write_events(room_id, [event])
|
||||
|
||||
# We write the knock state somewhere else as they aren't full events
|
||||
# and are only a subset of the state at the event.
|
||||
room_directory = os.path.join(self.base_directory, "rooms", room_id)
|
||||
os.makedirs(room_directory, exist_ok=True)
|
||||
|
||||
knock_state = os.path.join(room_directory, "knock_state")
|
||||
|
||||
with open(knock_state, "a") as f:
|
||||
for event in state.values():
|
||||
print(json.dumps(event), file=f)
|
||||
|
||||
def finished(self):
|
||||
return self.base_directory
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ class AdminHandler:
|
|||
Membership.LEAVE,
|
||||
Membership.BAN,
|
||||
Membership.INVITE,
|
||||
Membership.KNOCK,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -122,6 +123,13 @@ class AdminHandler:
|
|||
invited_state = invite.unsigned["invite_room_state"]
|
||||
writer.write_invite(room_id, invite, invited_state)
|
||||
|
||||
if room.membership == Membership.KNOCK:
|
||||
event_id = room.event_id
|
||||
knock = await self.store.get_event(event_id, allow_none=True)
|
||||
if knock:
|
||||
knock_state = knock.unsigned["knock_room_state"]
|
||||
writer.write_knock(room_id, knock, knock_state)
|
||||
|
||||
continue
|
||||
|
||||
# We only want to bother fetching events up to the last time they
|
||||
|
@ -238,6 +246,20 @@ class ExfiltrationWriter(metaclass=abc.ABCMeta):
|
|||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@abc.abstractmethod
|
||||
def write_knock(
|
||||
self, room_id: str, event: EventBase, state: StateMap[dict]
|
||||
) -> None:
|
||||
"""Write a knock for the room, with associated knock state.
|
||||
|
||||
Args:
|
||||
room_id: The room ID the knock is for.
|
||||
event: The knock event.
|
||||
state: A subset of the state at the knock, with a subset of the
|
||||
event keys (type, state_key content and sender).
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@abc.abstractmethod
|
||||
def finished(self) -> Any:
|
||||
"""Called when all data has successfully been exported and written.
|
||||
|
|
|
@ -17,8 +17,9 @@ from unittest.mock import Mock
|
|||
|
||||
import synapse.rest.admin
|
||||
import synapse.storage
|
||||
from synapse.api.constants import EventTypes
|
||||
from synapse.rest.client import login, room
|
||||
from synapse.api.constants import EventTypes, JoinRules
|
||||
from synapse.api.room_versions import RoomVersions
|
||||
from synapse.rest.client import knock, login, room
|
||||
|
||||
from tests import unittest
|
||||
|
||||
|
@ -28,6 +29,7 @@ class ExfiltrateData(unittest.HomeserverTestCase):
|
|||
synapse.rest.admin.register_servlets_for_client_rest_resource,
|
||||
login.register_servlets,
|
||||
room.register_servlets,
|
||||
knock.register_servlets,
|
||||
]
|
||||
|
||||
def prepare(self, reactor, clock, hs):
|
||||
|
@ -201,3 +203,32 @@ class ExfiltrateData(unittest.HomeserverTestCase):
|
|||
self.assertEqual(args[0], room_id)
|
||||
self.assertEqual(args[1].content["membership"], "invite")
|
||||
self.assertTrue(args[2]) # Assert there is at least one bit of state
|
||||
|
||||
def test_knock(self):
|
||||
"""Tests that knock get handled correctly."""
|
||||
# create a knockable v7 room
|
||||
room_id = self.helper.create_room_as(
|
||||
self.user1, room_version=RoomVersions.V7.identifier, tok=self.token1
|
||||
)
|
||||
self.helper.send_state(
|
||||
room_id,
|
||||
EventTypes.JoinRules,
|
||||
{"join_rule": JoinRules.KNOCK},
|
||||
tok=self.token1,
|
||||
)
|
||||
|
||||
self.helper.send(room_id, body="Hello!", tok=self.token1)
|
||||
self.helper.knock(room_id, self.user2, tok=self.token2)
|
||||
|
||||
writer = Mock()
|
||||
|
||||
self.get_success(self.admin_handler.export_user_data(self.user2, writer))
|
||||
|
||||
writer.write_events.assert_not_called()
|
||||
writer.write_state.assert_not_called()
|
||||
writer.write_knock.assert_called_once()
|
||||
|
||||
args = writer.write_knock.call_args[0]
|
||||
self.assertEqual(args[0], room_id)
|
||||
self.assertEqual(args[1].content["membership"], "knock")
|
||||
self.assertTrue(args[2]) # Assert there is at least one bit of state
|
||||
|
|
|
@ -120,6 +120,35 @@ class RestHelper:
|
|||
expect_code=expect_code,
|
||||
)
|
||||
|
||||
def knock(self, room=None, user=None, reason=None, expect_code=200, tok=None):
|
||||
temp_id = self.auth_user_id
|
||||
self.auth_user_id = user
|
||||
path = "/knock/%s" % room
|
||||
if tok:
|
||||
path = path + "?access_token=%s" % tok
|
||||
|
||||
data = {}
|
||||
if reason:
|
||||
data["reason"] = reason
|
||||
|
||||
channel = make_request(
|
||||
self.hs.get_reactor(),
|
||||
self.site,
|
||||
"POST",
|
||||
path,
|
||||
json.dumps(data).encode("utf8"),
|
||||
)
|
||||
|
||||
assert (
|
||||
int(channel.result["code"]) == expect_code
|
||||
), "Expected: %d, got: %d, resp: %r" % (
|
||||
expect_code,
|
||||
int(channel.result["code"]),
|
||||
channel.result["body"],
|
||||
)
|
||||
|
||||
self.auth_user_id = temp_id
|
||||
|
||||
def leave(self, room=None, user=None, expect_code=200, tok=None):
|
||||
self.change_membership(
|
||||
room=room,
|
||||
|
|
Loading…
Reference in a new issue