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
				
			
		synapse
federation/transport
groups
handlers
storage
|  | @ -614,6 +614,19 @@ class TransportLayerClient(object): | |||
|             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 | ||||
|  | @ -858,8 +871,8 @@ class TransportLayerClient(object): | |||
|         ) | ||||
| 
 | ||||
|     @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,) | ||||
|  |  | |||
|  | @ -803,6 +803,23 @@ class FederationGroupsAcceptInviteServlet(BaseFederationServlet): | |||
|         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 | ||||
|     """ | ||||
|  | @ -1182,6 +1199,7 @@ GROUP_SERVER_SERVLET_CLASSES = ( | |||
|     FederationGroupsInvitedUsersServlet, | ||||
|     FederationGroupsInviteServlet, | ||||
|     FederationGroupsAcceptInviteServlet, | ||||
|     FederationGroupsJoinServlet, | ||||
|     FederationGroupsRemoveUserServlet, | ||||
|     FederationGroupsSummaryRoomsServlet, | ||||
|     FederationGroupsCategoriesServlet, | ||||
|  |  | |||
|  | @ -404,9 +404,16 @@ class GroupsServerHandler(object): | |||
| 
 | ||||
|         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") | ||||
|  | @ -677,6 +684,40 @@ class GroupsServerHandler(object): | |||
|         else: | ||||
|             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 | ||||
|     def accept_invite(self, group_id, requester_user_id, content): | ||||
|         """User tries to accept an invite to the group. | ||||
|  | @ -693,30 +734,27 @@ class GroupsServerHandler(object): | |||
|         if not is_invited: | ||||
|             raise SynapseError(403, "User not invited to group") | ||||
| 
 | ||||
|         if not self.hs.is_mine_id(requester_user_id): | ||||
|             local_attestation = self.attestations.create_attestation( | ||||
|                 group_id, requester_user_id, | ||||
|             ) | ||||
|             remote_attestation = content["attestation"] | ||||
|         local_attestation = yield self._add_user(group_id, requester_user_id, content) | ||||
| 
 | ||||
|             yield self.attestations.verify_attestation( | ||||
|                 remote_attestation, | ||||
|                 user_id=requester_user_id, | ||||
|                 group_id=group_id, | ||||
|             ) | ||||
|         else: | ||||
|             local_attestation = None | ||||
|             remote_attestation = None | ||||
|         defer.returnValue({ | ||||
|             "state": "join", | ||||
|             "attestation": local_attestation, | ||||
|         }) | ||||
| 
 | ||||
|         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( | ||||
|             group_id, requester_user_id, | ||||
|             is_admin=False, | ||||
|             is_public=is_public, | ||||
|             local_attestation=local_attestation, | ||||
|             remote_attestation=remote_attestation, | ||||
|         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", | ||||
|  | @ -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( | ||||
|  |  | |||
|  | @ -229,7 +229,45 @@ class GroupsLocalHandler(object): | |||
|     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): | ||||
|  |  | |||
|  | @ -55,10 +55,11 @@ class GroupServerStore(SQLBaseStore): | |||
|                 "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): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue