Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3046 from matrix-org/dbkr/join_group
Browse files Browse the repository at this point in the history
Implement group join API
  • Loading branch information
lukebarnard1 authored Apr 6, 2018
2 parents e8b03ca + 020a501 commit 135fc5b
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 25 deletions.
17 changes: 15 additions & 2 deletions synapse/federation/transport/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,19 @@ def accept_group_invite(self, destination, group_id, user_id, content):
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
def invite_to_group(self, destination, group_id, user_id, requester_user_id, content):
"""Invite a user to a group
Expand Down Expand Up @@ -858,8 +871,8 @@ def update_group_summary_user(self, destination, group_id, requester_user_id,
)

@log_function
def set_group_joinable(self, destination, group_id, requester_user_id,
content):
def set_group_join_policy(self, destination, group_id, requester_user_id,
content):
"""Sets the join policy for a group
"""
path = PREFIX + "/groups/%s/settings/m.join_policy" % (group_id,)
Expand Down
18 changes: 18 additions & 0 deletions synapse/federation/transport/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,23 @@ def on_POST(self, origin, content, query, group_id, user_id):
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):
"""Leave or kick a user from the group
"""
Expand Down Expand Up @@ -1182,6 +1199,7 @@ def on_PUT(self, origin, content, query, group_id):
FederationGroupsInvitedUsersServlet,
FederationGroupsInviteServlet,
FederationGroupsAcceptInviteServlet,
FederationGroupsJoinServlet,
FederationGroupsRemoveUserServlet,
FederationGroupsSummaryRoomsServlet,
FederationGroupsCategoriesServlet,
Expand Down
78 changes: 58 additions & 20 deletions synapse/groups/groups_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,9 +404,16 @@ def get_group_profile(self, 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)
else:
raise SynapseError(404, "Unknown group")
Expand Down Expand Up @@ -678,30 +685,21 @@ def invite_to_group(self, group_id, user_id, requester_user_id, content):
raise SynapseError(502, "Unknown state returned by HS")

@defer.inlineCallbacks
def accept_invite(self, group_id, requester_user_id, content):
"""User tries to accept an invite to the group.
def _add_user(self, group_id, user_id, content):
"""Add a user to a group based on a content dict.
This is different from them asking to join, and so should error if no
invite exists (and they're not a member of the group)
See accept_invite, join_group.
"""

yield self.check_group_is_ours(group_id, requester_user_id, and_exists=True)

is_invited = yield self.store.is_user_invited_to_local_group(
group_id, requester_user_id,
)
if not is_invited:
raise SynapseError(403, "User not invited to group")

if not self.hs.is_mine_id(requester_user_id):
if not self.hs.is_mine_id(user_id):
local_attestation = self.attestations.create_attestation(
group_id, requester_user_id,
group_id, user_id,
)

remote_attestation = content["attestation"]

yield self.attestations.verify_attestation(
remote_attestation,
user_id=requester_user_id,
user_id=user_id,
group_id=group_id,
)
else:
Expand All @@ -711,13 +709,53 @@ def accept_invite(self, group_id, requester_user_id, content):
is_public = _parse_visibility_from_contents(content)

yield self.store.add_user_to_group(
group_id, requester_user_id,
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
def accept_invite(self, group_id, requester_user_id, content):
"""User tries to accept an invite to the group.
This is different from them asking to join, and so should error if no
invite exists (and they're not a member of the group)
"""

yield self.check_group_is_ours(group_id, requester_user_id, and_exists=True)

is_invited = yield self.store.is_user_invited_to_local_group(
group_id, requester_user_id,
)
if not is_invited:
raise SynapseError(403, "User not invited to group")

local_attestation = yield self._add_user(group_id, requester_user_id, content)

defer.returnValue({
"state": "join",
"attestation": local_attestation,
})

@defer.inlineCallbacks
def join_group(self, group_id, requester_user_id, content):
"""User tries to join the group.
This will error if the group requires an invite/knock to join
"""

group_info = yield self.check_group_is_ours(
group_id, requester_user_id, and_exists=True
)
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({
"state": "join",
"attestation": local_attestation,
Expand Down Expand Up @@ -874,7 +912,7 @@ def _parse_join_policy_dict(join_policy_dict):
"""
join_policy_type = join_policy_dict.get("type")
if not join_policy_type:
return True
return "invite"

if join_policy_type not in ("invite", "open"):
raise SynapseError(
Expand Down
40 changes: 39 additions & 1 deletion synapse/handlers/groups_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,45 @@ def get_users_in_group(self, group_id, requester_user_id):
def join_group(self, group_id, user_id, content):
"""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
def accept_invite(self, group_id, user_id, content):
Expand Down
5 changes: 3 additions & 2 deletions synapse/storage/group_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ def get_group(self, group_id):
"group_id": group_id,
},
retcols=(
"name", "short_description", "long_description", "avatar_url", "is_public"
"name", "short_description", "long_description",
"avatar_url", "is_public", "join_policy",
),
allow_none=True,
desc="is_user_in_group",
desc="get_group",
)

def get_users_in_group(self, group_id, include_private=False):
Expand Down

0 comments on commit 135fc5b

Please sign in to comment.