forked from MirrorHub/synapse
Merge pull request #3046 from matrix-org/dbkr/join_group
Implement group join API
This commit is contained in:
commit
135fc5b9cd
5 changed files with 136 additions and 28 deletions
|
@ -614,6 +614,19 @@ class TransportLayerClient(object):
|
||||||
ignore_backoff=True,
|
ignore_backoff=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def join_group(self, destination, group_id, user_id, content):
|
||||||
|
"""Attempts to join a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/users/%s/join" % (group_id, user_id)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
@log_function
|
@log_function
|
||||||
def invite_to_group(self, destination, group_id, user_id, requester_user_id, content):
|
def invite_to_group(self, destination, group_id, user_id, requester_user_id, content):
|
||||||
"""Invite a user to a group
|
"""Invite a user to a group
|
||||||
|
@ -858,8 +871,8 @@ class TransportLayerClient(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
@log_function
|
@log_function
|
||||||
def set_group_joinable(self, destination, group_id, requester_user_id,
|
def set_group_join_policy(self, destination, group_id, requester_user_id,
|
||||||
content):
|
content):
|
||||||
"""Sets the join policy for a group
|
"""Sets the join policy for a group
|
||||||
"""
|
"""
|
||||||
path = PREFIX + "/groups/%s/settings/m.join_policy" % (group_id,)
|
path = PREFIX + "/groups/%s/settings/m.join_policy" % (group_id,)
|
||||||
|
|
|
@ -803,6 +803,23 @@ class FederationGroupsAcceptInviteServlet(BaseFederationServlet):
|
||||||
defer.returnValue((200, new_content))
|
defer.returnValue((200, new_content))
|
||||||
|
|
||||||
|
|
||||||
|
class FederationGroupsJoinServlet(BaseFederationServlet):
|
||||||
|
"""Attempt to join a group
|
||||||
|
"""
|
||||||
|
PATH = "/groups/(?P<group_id>[^/]*)/users/(?P<user_id>[^/]*)/join$"
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_POST(self, origin, content, query, group_id, user_id):
|
||||||
|
if get_domain_from_id(user_id) != origin:
|
||||||
|
raise SynapseError(403, "user_id doesn't match origin")
|
||||||
|
|
||||||
|
new_content = yield self.handler.join_group(
|
||||||
|
group_id, user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, new_content))
|
||||||
|
|
||||||
|
|
||||||
class FederationGroupsRemoveUserServlet(BaseFederationServlet):
|
class FederationGroupsRemoveUserServlet(BaseFederationServlet):
|
||||||
"""Leave or kick a user from the group
|
"""Leave or kick a user from the group
|
||||||
"""
|
"""
|
||||||
|
@ -1182,6 +1199,7 @@ GROUP_SERVER_SERVLET_CLASSES = (
|
||||||
FederationGroupsInvitedUsersServlet,
|
FederationGroupsInvitedUsersServlet,
|
||||||
FederationGroupsInviteServlet,
|
FederationGroupsInviteServlet,
|
||||||
FederationGroupsAcceptInviteServlet,
|
FederationGroupsAcceptInviteServlet,
|
||||||
|
FederationGroupsJoinServlet,
|
||||||
FederationGroupsRemoveUserServlet,
|
FederationGroupsRemoveUserServlet,
|
||||||
FederationGroupsSummaryRoomsServlet,
|
FederationGroupsSummaryRoomsServlet,
|
||||||
FederationGroupsCategoriesServlet,
|
FederationGroupsCategoriesServlet,
|
||||||
|
|
|
@ -404,9 +404,16 @@ class GroupsServerHandler(object):
|
||||||
|
|
||||||
yield self.check_group_is_ours(group_id, requester_user_id)
|
yield self.check_group_is_ours(group_id, requester_user_id)
|
||||||
|
|
||||||
group_description = yield self.store.get_group(group_id)
|
group = yield self.store.get_group(group_id)
|
||||||
|
|
||||||
|
if group:
|
||||||
|
cols = [
|
||||||
|
"name", "short_description", "long_description",
|
||||||
|
"avatar_url", "is_public",
|
||||||
|
]
|
||||||
|
group_description = {key: group[key] for key in cols}
|
||||||
|
group_description["is_openly_joinable"] = group["join_policy"] == "open"
|
||||||
|
|
||||||
if group_description:
|
|
||||||
defer.returnValue(group_description)
|
defer.returnValue(group_description)
|
||||||
else:
|
else:
|
||||||
raise SynapseError(404, "Unknown group")
|
raise SynapseError(404, "Unknown group")
|
||||||
|
@ -677,6 +684,40 @@ class GroupsServerHandler(object):
|
||||||
else:
|
else:
|
||||||
raise SynapseError(502, "Unknown state returned by HS")
|
raise SynapseError(502, "Unknown state returned by HS")
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def _add_user(self, group_id, user_id, content):
|
||||||
|
"""Add a user to a group based on a content dict.
|
||||||
|
|
||||||
|
See accept_invite, join_group.
|
||||||
|
"""
|
||||||
|
if not self.hs.is_mine_id(user_id):
|
||||||
|
local_attestation = self.attestations.create_attestation(
|
||||||
|
group_id, user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
remote_attestation = content["attestation"]
|
||||||
|
|
||||||
|
yield self.attestations.verify_attestation(
|
||||||
|
remote_attestation,
|
||||||
|
user_id=user_id,
|
||||||
|
group_id=group_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
local_attestation = None
|
||||||
|
remote_attestation = None
|
||||||
|
|
||||||
|
is_public = _parse_visibility_from_contents(content)
|
||||||
|
|
||||||
|
yield self.store.add_user_to_group(
|
||||||
|
group_id, user_id,
|
||||||
|
is_admin=False,
|
||||||
|
is_public=is_public,
|
||||||
|
local_attestation=local_attestation,
|
||||||
|
remote_attestation=remote_attestation,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue(local_attestation)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def accept_invite(self, group_id, requester_user_id, content):
|
def accept_invite(self, group_id, requester_user_id, content):
|
||||||
"""User tries to accept an invite to the group.
|
"""User tries to accept an invite to the group.
|
||||||
|
@ -693,30 +734,27 @@ class GroupsServerHandler(object):
|
||||||
if not is_invited:
|
if not is_invited:
|
||||||
raise SynapseError(403, "User not invited to group")
|
raise SynapseError(403, "User not invited to group")
|
||||||
|
|
||||||
if not self.hs.is_mine_id(requester_user_id):
|
local_attestation = yield self._add_user(group_id, requester_user_id, content)
|
||||||
local_attestation = self.attestations.create_attestation(
|
|
||||||
group_id, requester_user_id,
|
|
||||||
)
|
|
||||||
remote_attestation = content["attestation"]
|
|
||||||
|
|
||||||
yield self.attestations.verify_attestation(
|
defer.returnValue({
|
||||||
remote_attestation,
|
"state": "join",
|
||||||
user_id=requester_user_id,
|
"attestation": local_attestation,
|
||||||
group_id=group_id,
|
})
|
||||||
)
|
|
||||||
else:
|
|
||||||
local_attestation = None
|
|
||||||
remote_attestation = None
|
|
||||||
|
|
||||||
is_public = _parse_visibility_from_contents(content)
|
@defer.inlineCallbacks
|
||||||
|
def join_group(self, group_id, requester_user_id, content):
|
||||||
|
"""User tries to join the group.
|
||||||
|
|
||||||
yield self.store.add_user_to_group(
|
This will error if the group requires an invite/knock to join
|
||||||
group_id, requester_user_id,
|
"""
|
||||||
is_admin=False,
|
|
||||||
is_public=is_public,
|
group_info = yield self.check_group_is_ours(
|
||||||
local_attestation=local_attestation,
|
group_id, requester_user_id, and_exists=True
|
||||||
remote_attestation=remote_attestation,
|
|
||||||
)
|
)
|
||||||
|
if group_info['join_policy'] != "open":
|
||||||
|
raise SynapseError(403, "Group is not publicly joinable")
|
||||||
|
|
||||||
|
local_attestation = yield self._add_user(group_id, requester_user_id, content)
|
||||||
|
|
||||||
defer.returnValue({
|
defer.returnValue({
|
||||||
"state": "join",
|
"state": "join",
|
||||||
|
@ -874,7 +912,7 @@ def _parse_join_policy_dict(join_policy_dict):
|
||||||
"""
|
"""
|
||||||
join_policy_type = join_policy_dict.get("type")
|
join_policy_type = join_policy_dict.get("type")
|
||||||
if not join_policy_type:
|
if not join_policy_type:
|
||||||
return True
|
return "invite"
|
||||||
|
|
||||||
if join_policy_type not in ("invite", "open"):
|
if join_policy_type not in ("invite", "open"):
|
||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
|
|
|
@ -229,7 +229,45 @@ class GroupsLocalHandler(object):
|
||||||
def join_group(self, group_id, user_id, content):
|
def join_group(self, group_id, user_id, content):
|
||||||
"""Request to join a group
|
"""Request to join a group
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError() # TODO
|
if self.is_mine_id(group_id):
|
||||||
|
yield self.groups_server_handler.join_group(
|
||||||
|
group_id, user_id, content
|
||||||
|
)
|
||||||
|
local_attestation = None
|
||||||
|
remote_attestation = None
|
||||||
|
else:
|
||||||
|
local_attestation = self.attestations.create_attestation(group_id, user_id)
|
||||||
|
content["attestation"] = local_attestation
|
||||||
|
|
||||||
|
res = yield self.transport_client.join_group(
|
||||||
|
get_domain_from_id(group_id), group_id, user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
remote_attestation = res["attestation"]
|
||||||
|
|
||||||
|
yield self.attestations.verify_attestation(
|
||||||
|
remote_attestation,
|
||||||
|
group_id=group_id,
|
||||||
|
user_id=user_id,
|
||||||
|
server_name=get_domain_from_id(group_id),
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Check that the group is public and we're being added publically
|
||||||
|
is_publicised = content.get("publicise", False)
|
||||||
|
|
||||||
|
token = yield self.store.register_user_group_membership(
|
||||||
|
group_id, user_id,
|
||||||
|
membership="join",
|
||||||
|
is_admin=False,
|
||||||
|
local_attestation=local_attestation,
|
||||||
|
remote_attestation=remote_attestation,
|
||||||
|
is_publicised=is_publicised,
|
||||||
|
)
|
||||||
|
self.notifier.on_new_event(
|
||||||
|
"groups_key", token, users=[user_id],
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue({})
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def accept_invite(self, group_id, user_id, content):
|
def accept_invite(self, group_id, user_id, content):
|
||||||
|
|
|
@ -55,10 +55,11 @@ class GroupServerStore(SQLBaseStore):
|
||||||
"group_id": group_id,
|
"group_id": group_id,
|
||||||
},
|
},
|
||||||
retcols=(
|
retcols=(
|
||||||
"name", "short_description", "long_description", "avatar_url", "is_public"
|
"name", "short_description", "long_description",
|
||||||
|
"avatar_url", "is_public", "join_policy",
|
||||||
),
|
),
|
||||||
allow_none=True,
|
allow_none=True,
|
||||||
desc="is_user_in_group",
|
desc="get_group",
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_users_in_group(self, group_id, include_private=False):
|
def get_users_in_group(self, group_id, include_private=False):
|
||||||
|
|
Loading…
Reference in a new issue