mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-10-01 11:49:51 -04:00
Merge pull request #2374 from matrix-org/erikj/group_server_local
Add local group server support
This commit is contained in:
commit
b3bf6a1218
@ -472,6 +472,99 @@ class TransportLayerClient(object):
|
|||||||
|
|
||||||
defer.returnValue(content)
|
defer.returnValue(content)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_group_profile(self, destination, group_id, requester_user_id):
|
||||||
|
"""Get a group profile
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/profile" % (group_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_group_summary(self, destination, group_id, requester_user_id):
|
||||||
|
"""Get a group summary
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/summary" % (group_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_rooms_in_group(self, destination, group_id, requester_user_id):
|
||||||
|
"""Get all rooms in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/rooms" % (group_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_room_to_group(self, destination, group_id, requester_user_id, room_id,
|
||||||
|
content):
|
||||||
|
"""Add a room to a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/room/%s" % (group_id, room_id,)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_users_in_group(self, destination, group_id, requester_user_id):
|
||||||
|
"""Get users in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/users" % (group_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def accept_group_invite(self, destination, group_id, user_id, content):
|
||||||
|
"""Accept a group invite
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/users/%s/accept_invite" % (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
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/users/%s/invite" % (group_id, user_id)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args=requester_user_id,
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
@log_function
|
@log_function
|
||||||
def invite_to_group_notification(self, destination, group_id, user_id, content):
|
def invite_to_group_notification(self, destination, group_id, user_id, content):
|
||||||
"""Sent by group server to inform a user's server that they have been
|
"""Sent by group server to inform a user's server that they have been
|
||||||
@ -487,6 +580,21 @@ class TransportLayerClient(object):
|
|||||||
ignore_backoff=True,
|
ignore_backoff=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def remove_user_from_group(self, destination, group_id, requester_user_id,
|
||||||
|
user_id, content):
|
||||||
|
"""Remove a user fron a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/users/%s/remove" % (group_id, user_id)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
@log_function
|
@log_function
|
||||||
def remove_user_from_group_notification(self, destination, group_id, user_id,
|
def remove_user_from_group_notification(self, destination, group_id, user_id,
|
||||||
content):
|
content):
|
||||||
@ -517,3 +625,190 @@ class TransportLayerClient(object):
|
|||||||
data=content,
|
data=content,
|
||||||
ignore_backoff=True,
|
ignore_backoff=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def update_group_summary_room(self, destination, group_id, user_id, room_id,
|
||||||
|
category_id, content):
|
||||||
|
"""Update a room entry in a group summary
|
||||||
|
"""
|
||||||
|
if category_id:
|
||||||
|
path = PREFIX + "/groups/%s/summary/categories/%s/rooms/%s" % (
|
||||||
|
group_id, category_id, room_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
path = PREFIX + "/groups/%s/summary/rooms/%s" % (group_id, room_id,)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": user_id},
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def delete_group_summary_room(self, destination, group_id, user_id, room_id,
|
||||||
|
category_id):
|
||||||
|
"""Delete a room entry in a group summary
|
||||||
|
"""
|
||||||
|
if category_id:
|
||||||
|
path = PREFIX + "/groups/%s/summary/categories/%s/rooms/%s" % (
|
||||||
|
group_id, category_id, room_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
path = PREFIX + "/groups/%s/summary/rooms/%s" % (group_id, room_id,)
|
||||||
|
|
||||||
|
return self.client.delete_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_group_categories(self, destination, group_id, requester_user_id):
|
||||||
|
"""Get all categories in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/categories" % (group_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_group_category(self, destination, group_id, requester_user_id, category_id):
|
||||||
|
"""Get category info in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/categories/%s" % (group_id, category_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def update_group_category(self, destination, group_id, requester_user_id, category_id,
|
||||||
|
content):
|
||||||
|
"""Update a category in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/categories/%s" % (group_id, category_id,)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def delete_group_category(self, destination, group_id, requester_user_id,
|
||||||
|
category_id):
|
||||||
|
"""Delete a category in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/categories/%s" % (group_id, category_id,)
|
||||||
|
|
||||||
|
return self.client.delete_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_group_roles(self, destination, group_id, requester_user_id):
|
||||||
|
"""Get all roles in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/roles" % (group_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def get_group_role(self, destination, group_id, requester_user_id, role_id):
|
||||||
|
"""Get a roles info
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/roles/%s" % (group_id, role_id,)
|
||||||
|
|
||||||
|
return self.client.get_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def update_group_role(self, destination, group_id, requester_user_id, role_id,
|
||||||
|
content):
|
||||||
|
"""Update a role in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/roles/%s" % (group_id, role_id,)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def delete_group_role(self, destination, group_id, requester_user_id, role_id):
|
||||||
|
"""Delete a role in a group
|
||||||
|
"""
|
||||||
|
path = PREFIX + "/groups/%s/roles/%s" % (group_id, role_id,)
|
||||||
|
|
||||||
|
return self.client.delete_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def update_group_summary_user(self, destination, group_id, requester_user_id,
|
||||||
|
user_id, role_id, content):
|
||||||
|
"""Update a users entry in a group
|
||||||
|
"""
|
||||||
|
if role_id:
|
||||||
|
path = PREFIX + "/groups/%s/summary/roles/%s/users/%s" % (
|
||||||
|
group_id, role_id, user_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
path = PREFIX + "/groups/%s/summary/users/%s" % (group_id, user_id,)
|
||||||
|
|
||||||
|
return self.client.post_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
data=content,
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@log_function
|
||||||
|
def delete_group_summary_user(self, destination, group_id, requester_user_id,
|
||||||
|
user_id, role_id):
|
||||||
|
"""Delete a users entry in a group
|
||||||
|
"""
|
||||||
|
if role_id:
|
||||||
|
path = PREFIX + "/groups/%s/summary/roles/%s/users/%s" % (
|
||||||
|
group_id, role_id, user_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
path = PREFIX + "/groups/%s/summary/users/%s" % (group_id, user_id,)
|
||||||
|
|
||||||
|
return self.client.delete_json(
|
||||||
|
destination=destination,
|
||||||
|
path=path,
|
||||||
|
args={"requester_user_id": requester_user_id},
|
||||||
|
ignore_backoff=True,
|
||||||
|
)
|
||||||
|
@ -616,7 +616,7 @@ class FederationGroupsProfileServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id):
|
def on_GET(self, origin, content, query, group_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -632,7 +632,7 @@ class FederationGroupsSummaryServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id):
|
def on_GET(self, origin, content, query, group_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -650,7 +650,7 @@ class FederationGroupsRoomsServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id):
|
def on_GET(self, origin, content, query, group_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -668,11 +668,11 @@ class FederationGroupsAddRoomsServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, room_id):
|
def on_POST(self, origin, content, query, group_id, room_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
new_content = yield self.handler.add_room(
|
new_content = yield self.handler.add_room_to_group(
|
||||||
group_id, requester_user_id, room_id, content
|
group_id, requester_user_id, room_id, content
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -686,7 +686,7 @@ class FederationGroupsUsersServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id):
|
def on_GET(self, origin, content, query, group_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -704,7 +704,7 @@ class FederationGroupsInviteServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, user_id):
|
def on_POST(self, origin, content, query, group_id, user_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -739,7 +739,7 @@ class FederationGroupsRemoveUserServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, user_id):
|
def on_POST(self, origin, content, query, group_id, user_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -750,6 +750,40 @@ class FederationGroupsRemoveUserServlet(BaseFederationServlet):
|
|||||||
defer.returnValue((200, new_content))
|
defer.returnValue((200, new_content))
|
||||||
|
|
||||||
|
|
||||||
|
class FederationGroupsLocalInviteServlet(BaseFederationServlet):
|
||||||
|
"""A group server has invited a local user
|
||||||
|
"""
|
||||||
|
PATH = "/groups/local/(?P<group_id>[^/]*)/users/(?P<user_id>[^/]*)/invite$"
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_POST(self, origin, content, query, group_id, user_id):
|
||||||
|
if get_domain_from_id(group_id) != origin:
|
||||||
|
raise SynapseError(403, "group_id doesn't match origin")
|
||||||
|
|
||||||
|
new_content = yield self.handler.on_invite(
|
||||||
|
group_id, user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, new_content))
|
||||||
|
|
||||||
|
|
||||||
|
class FederationGroupsRemoveLocalUserServlet(BaseFederationServlet):
|
||||||
|
"""A group server has removed a local user
|
||||||
|
"""
|
||||||
|
PATH = "/groups/local/(?P<group_id>[^/]*)/users/(?P<user_id>[^/]*)/remove$"
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_POST(self, origin, content, query, group_id, user_id):
|
||||||
|
if get_domain_from_id(group_id) != origin:
|
||||||
|
raise SynapseError(403, "user_id doesn't match origin")
|
||||||
|
|
||||||
|
new_content = yield self.handler.user_removed_from_group(
|
||||||
|
group_id, user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, new_content))
|
||||||
|
|
||||||
|
|
||||||
class FederationGroupsRenewAttestaionServlet(BaseFederationServlet):
|
class FederationGroupsRenewAttestaionServlet(BaseFederationServlet):
|
||||||
"""A group or user's server renews their attestation
|
"""A group or user's server renews their attestation
|
||||||
"""
|
"""
|
||||||
@ -781,7 +815,7 @@ class FederationGroupsSummaryRoomsServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, category_id, room_id):
|
def on_POST(self, origin, content, query, group_id, category_id, room_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -799,7 +833,7 @@ class FederationGroupsSummaryRoomsServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_DELETE(self, origin, content, query, group_id, category_id, room_id):
|
def on_DELETE(self, origin, content, query, group_id, category_id, room_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -824,7 +858,7 @@ class FederationGroupsCategoriesServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id):
|
def on_GET(self, origin, content, query, group_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -844,7 +878,7 @@ class FederationGroupsCategoryServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id, category_id):
|
def on_GET(self, origin, content, query, group_id, category_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -856,7 +890,7 @@ class FederationGroupsCategoryServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, category_id):
|
def on_POST(self, origin, content, query, group_id, category_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -871,7 +905,7 @@ class FederationGroupsCategoryServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_DELETE(self, origin, content, query, group_id, category_id):
|
def on_DELETE(self, origin, content, query, group_id, category_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -894,7 +928,7 @@ class FederationGroupsRolesServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id):
|
def on_GET(self, origin, content, query, group_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -914,7 +948,7 @@ class FederationGroupsRoleServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, group_id, role_id):
|
def on_GET(self, origin, content, query, group_id, role_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -926,7 +960,7 @@ class FederationGroupsRoleServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, role_id):
|
def on_POST(self, origin, content, query, group_id, role_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -941,7 +975,7 @@ class FederationGroupsRoleServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_DELETE(self, origin, content, query, group_id, role_id):
|
def on_DELETE(self, origin, content, query, group_id, role_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -970,7 +1004,7 @@ class FederationGroupsSummaryUsersServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_POST(self, origin, content, query, group_id, role_id, user_id):
|
def on_POST(self, origin, content, query, group_id, role_id, user_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -988,7 +1022,7 @@ class FederationGroupsSummaryUsersServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_DELETE(self, origin, content, query, group_id, role_id, user_id):
|
def on_DELETE(self, origin, content, query, group_id, role_id, user_id):
|
||||||
requester_user_id = query["requester_user_id"]
|
requester_user_id = parse_string_from_args(query, "requester_user_id")
|
||||||
if get_domain_from_id(requester_user_id) != origin:
|
if get_domain_from_id(requester_user_id) != origin:
|
||||||
raise SynapseError(403, "requester_user_id doesn't match origin")
|
raise SynapseError(403, "requester_user_id doesn't match origin")
|
||||||
|
|
||||||
@ -1053,6 +1087,12 @@ GROUP_SERVER_SERVLET_CLASSES = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
GROUP_LOCAL_SERVLET_CLASSES = (
|
||||||
|
FederationGroupsLocalInviteServlet,
|
||||||
|
FederationGroupsRemoveLocalUserServlet,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
GROUP_ATTESTATION_SERVLET_CLASSES = (
|
GROUP_ATTESTATION_SERVLET_CLASSES = (
|
||||||
FederationGroupsRenewAttestaionServlet,
|
FederationGroupsRenewAttestaionServlet,
|
||||||
)
|
)
|
||||||
@ -1083,6 +1123,14 @@ def register_servlets(hs, resource, authenticator, ratelimiter):
|
|||||||
server_name=hs.hostname,
|
server_name=hs.hostname,
|
||||||
).register(resource)
|
).register(resource)
|
||||||
|
|
||||||
|
for servletclass in GROUP_LOCAL_SERVLET_CLASSES:
|
||||||
|
servletclass(
|
||||||
|
handler=hs.get_groups_local_handler(),
|
||||||
|
authenticator=authenticator,
|
||||||
|
ratelimiter=ratelimiter,
|
||||||
|
server_name=hs.hostname,
|
||||||
|
).register(resource)
|
||||||
|
|
||||||
for servletclass in GROUP_ATTESTATION_SERVLET_CLASSES:
|
for servletclass in GROUP_ATTESTATION_SERVLET_CLASSES:
|
||||||
servletclass(
|
servletclass(
|
||||||
handler=hs.get_groups_attestation_renewer(),
|
handler=hs.get_groups_attestation_renewer(),
|
||||||
|
@ -293,7 +293,9 @@ class GroupsServerHandler(object):
|
|||||||
content):
|
content):
|
||||||
"""Add/update a users entry in the group summary
|
"""Add/update a users entry in the group summary
|
||||||
"""
|
"""
|
||||||
yield self.check_group_is_ours(group_id, and_exists=True, and_is_admin=user_id)
|
yield self.check_group_is_ours(
|
||||||
|
group_id, and_exists=True, and_is_admin=requester_user_id,
|
||||||
|
)
|
||||||
|
|
||||||
order = content.get("order", None)
|
order = content.get("order", None)
|
||||||
|
|
||||||
@ -313,7 +315,9 @@ class GroupsServerHandler(object):
|
|||||||
def delete_group_summary_user(self, group_id, requester_user_id, user_id, role_id):
|
def delete_group_summary_user(self, group_id, requester_user_id, user_id, role_id):
|
||||||
"""Remove a user from the group summary
|
"""Remove a user from the group summary
|
||||||
"""
|
"""
|
||||||
yield self.check_group_is_ours(group_id, and_exists=True, and_is_admin=user_id)
|
yield self.check_group_is_ours(
|
||||||
|
group_id, and_exists=True, and_is_admin=requester_user_id,
|
||||||
|
)
|
||||||
|
|
||||||
yield self.store.remove_user_from_summary(
|
yield self.store.remove_user_from_summary(
|
||||||
group_id=group_id,
|
group_id=group_id,
|
||||||
@ -426,7 +430,7 @@ class GroupsServerHandler(object):
|
|||||||
})
|
})
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def add_room(self, group_id, requester_user_id, room_id, content):
|
def add_room_to_group(self, group_id, requester_user_id, room_id, content):
|
||||||
"""Add room to group
|
"""Add room to group
|
||||||
"""
|
"""
|
||||||
yield self.check_group_is_ours(
|
yield self.check_group_is_ours(
|
||||||
@ -462,7 +466,9 @@ class GroupsServerHandler(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.hs.is_mine_id(user_id):
|
if self.hs.is_mine_id(user_id):
|
||||||
raise NotImplementedError()
|
groups_local = self.hs.get_groups_local_handler()
|
||||||
|
res = yield groups_local.on_invite(group_id, user_id, content)
|
||||||
|
local_attestation = None
|
||||||
else:
|
else:
|
||||||
local_attestation = self.attestations.create_attestation(group_id, user_id)
|
local_attestation = self.attestations.create_attestation(group_id, user_id)
|
||||||
content.update({
|
content.update({
|
||||||
@ -590,7 +596,8 @@ class GroupsServerHandler(object):
|
|||||||
|
|
||||||
if is_kick:
|
if is_kick:
|
||||||
if self.hs.is_mine_id(user_id):
|
if self.hs.is_mine_id(user_id):
|
||||||
raise NotImplementedError()
|
groups_local = self.hs.get_groups_local_handler()
|
||||||
|
yield groups_local.user_removed_from_group(group_id, user_id, {})
|
||||||
else:
|
else:
|
||||||
yield self.transport_client.remove_user_from_group_notification(
|
yield self.transport_client.remove_user_from_group_notification(
|
||||||
get_domain_from_id(user_id), group_id, user_id, {}
|
get_domain_from_id(user_id), group_id, user_id, {}
|
||||||
|
307
synapse/handlers/groups_local.py
Normal file
307
synapse/handlers/groups_local.py
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2017 Vector Creations Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
from synapse.api.errors import SynapseError
|
||||||
|
from synapse.types import get_domain_from_id
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Validate attestations
|
||||||
|
# TODO: Allow users to "knock" or simpkly join depending on rules
|
||||||
|
# TODO: is_priveged flag to users and is_public to users and rooms
|
||||||
|
# TODO: Roles
|
||||||
|
# TODO: Audit log for admins (profile updates, membership changes, users who tried
|
||||||
|
# to join but were rejected, etc)
|
||||||
|
# TODO: Flairs
|
||||||
|
# TODO: Add group memebership /sync
|
||||||
|
|
||||||
|
|
||||||
|
def _create_rerouter(func_name):
|
||||||
|
"""Returns a function that looks at the group id and calls the function
|
||||||
|
on federation or the local group server if the group is local
|
||||||
|
"""
|
||||||
|
def f(self, group_id, *args, **kwargs):
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
return getattr(self.groups_server_handler, func_name)(
|
||||||
|
group_id, *args, **kwargs
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
destination = get_domain_from_id(group_id)
|
||||||
|
return getattr(self.transport_client, func_name)(
|
||||||
|
destination, group_id, *args, **kwargs
|
||||||
|
)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsLocalHandler(object):
|
||||||
|
def __init__(self, hs):
|
||||||
|
self.hs = hs
|
||||||
|
self.store = hs.get_datastore()
|
||||||
|
self.room_list_handler = hs.get_room_list_handler()
|
||||||
|
self.groups_server_handler = hs.get_groups_server_handler()
|
||||||
|
self.transport_client = hs.get_federation_transport_client()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.keyring = hs.get_keyring()
|
||||||
|
self.is_mine_id = hs.is_mine_id
|
||||||
|
self.signing_key = hs.config.signing_key[0]
|
||||||
|
self.server_name = hs.hostname
|
||||||
|
self.attestations = hs.get_groups_attestation_signing()
|
||||||
|
|
||||||
|
# Ensure attestations get renewed
|
||||||
|
hs.get_groups_attestation_renewer()
|
||||||
|
|
||||||
|
# The following functions merely route the query to the local groups server
|
||||||
|
# or federation depending on if the group is local or remote
|
||||||
|
|
||||||
|
get_group_profile = _create_rerouter("get_group_profile")
|
||||||
|
get_rooms_in_group = _create_rerouter("get_rooms_in_group")
|
||||||
|
|
||||||
|
add_room_to_group = _create_rerouter("add_room_to_group")
|
||||||
|
|
||||||
|
update_group_summary_room = _create_rerouter("update_group_summary_room")
|
||||||
|
delete_group_summary_room = _create_rerouter("delete_group_summary_room")
|
||||||
|
|
||||||
|
update_group_category = _create_rerouter("update_group_category")
|
||||||
|
delete_group_category = _create_rerouter("delete_group_category")
|
||||||
|
get_group_category = _create_rerouter("get_group_category")
|
||||||
|
get_group_categories = _create_rerouter("get_group_categories")
|
||||||
|
|
||||||
|
update_group_summary_user = _create_rerouter("update_group_summary_user")
|
||||||
|
delete_group_summary_user = _create_rerouter("delete_group_summary_user")
|
||||||
|
|
||||||
|
update_group_role = _create_rerouter("update_group_role")
|
||||||
|
delete_group_role = _create_rerouter("delete_group_role")
|
||||||
|
get_group_role = _create_rerouter("get_group_role")
|
||||||
|
get_group_roles = _create_rerouter("get_group_roles")
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def get_group_summary(self, group_id, requester_user_id):
|
||||||
|
"""Get the group summary for a group.
|
||||||
|
|
||||||
|
If the group is remote we check that the users have valid attestations.
|
||||||
|
"""
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
res = yield self.groups_server_handler.get_group_summary(
|
||||||
|
group_id, requester_user_id
|
||||||
|
)
|
||||||
|
defer.returnValue(res)
|
||||||
|
|
||||||
|
res = yield self.transport_client.get_group_summary(
|
||||||
|
get_domain_from_id(group_id), group_id, requester_user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Loop through the users and validate the attestations.
|
||||||
|
chunk = res["users_section"]["users"]
|
||||||
|
valid_users = []
|
||||||
|
for entry in chunk:
|
||||||
|
g_user_id = entry["user_id"]
|
||||||
|
attestation = entry.pop("attestation")
|
||||||
|
try:
|
||||||
|
yield self.attestations.verify_attestation(
|
||||||
|
attestation,
|
||||||
|
group_id=group_id,
|
||||||
|
user_id=g_user_id,
|
||||||
|
)
|
||||||
|
valid_users.append(entry)
|
||||||
|
except Exception as e:
|
||||||
|
logger.info("Failed to verify user is in group: %s", e)
|
||||||
|
|
||||||
|
res["users_section"]["users"] = valid_users
|
||||||
|
|
||||||
|
res["users_section"]["users"].sort(key=lambda e: e.get("order", 0))
|
||||||
|
res["rooms_section"]["rooms"].sort(key=lambda e: e.get("order", 0))
|
||||||
|
|
||||||
|
defer.returnValue(res)
|
||||||
|
|
||||||
|
def create_group(self, group_id, user_id, content):
|
||||||
|
"""Create a group
|
||||||
|
"""
|
||||||
|
|
||||||
|
logger.info("Asking to create group with ID: %r", group_id)
|
||||||
|
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
return self.groups_server_handler.create_group(
|
||||||
|
group_id, user_id, content
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.transport_client.create_group(
|
||||||
|
get_domain_from_id(group_id), group_id, user_id, content,
|
||||||
|
) # TODO
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def get_users_in_group(self, group_id, requester_user_id):
|
||||||
|
"""Get users in a group
|
||||||
|
"""
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
res = yield self.groups_server_handler.get_users_in_group(
|
||||||
|
group_id, requester_user_id
|
||||||
|
)
|
||||||
|
defer.returnValue(res)
|
||||||
|
|
||||||
|
res = yield self.transport_client.get_users_in_group(
|
||||||
|
get_domain_from_id(group_id), group_id, requester_user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
chunk = res["chunk"]
|
||||||
|
valid_entries = []
|
||||||
|
for entry in chunk:
|
||||||
|
g_user_id = entry["user_id"]
|
||||||
|
attestation = entry.pop("attestation")
|
||||||
|
try:
|
||||||
|
yield self.attestations.verify_attestation(
|
||||||
|
attestation,
|
||||||
|
group_id=group_id,
|
||||||
|
user_id=g_user_id,
|
||||||
|
)
|
||||||
|
valid_entries.append(entry)
|
||||||
|
except Exception as e:
|
||||||
|
logger.info("Failed to verify user is in group: %s", e)
|
||||||
|
|
||||||
|
res["chunk"] = valid_entries
|
||||||
|
|
||||||
|
defer.returnValue(res)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def join_group(self, group_id, user_id, content):
|
||||||
|
"""Request to join a group
|
||||||
|
"""
|
||||||
|
raise NotImplementedError() # TODO
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def accept_invite(self, group_id, user_id, content):
|
||||||
|
"""Accept an invite to a group
|
||||||
|
"""
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
yield self.groups_server_handler.accept_invite(
|
||||||
|
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.accept_group_invite(
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
yield self.store.register_user_group_membership(
|
||||||
|
group_id, user_id,
|
||||||
|
membership="join",
|
||||||
|
is_admin=False,
|
||||||
|
local_attestation=local_attestation,
|
||||||
|
remote_attestation=remote_attestation,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue({})
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def invite(self, group_id, user_id, requester_user_id, config):
|
||||||
|
"""Invite a user to a group
|
||||||
|
"""
|
||||||
|
content = {
|
||||||
|
"requester_user_id": requester_user_id,
|
||||||
|
"config": config,
|
||||||
|
}
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
res = yield self.groups_server_handler.invite_to_group(
|
||||||
|
group_id, user_id, requester_user_id, content,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
res = yield self.transport_client.invite_to_group(
|
||||||
|
get_domain_from_id(group_id), group_id, user_id, requester_user_id,
|
||||||
|
content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue(res)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_invite(self, group_id, user_id, content):
|
||||||
|
"""One of our users were invited to a group
|
||||||
|
"""
|
||||||
|
# TODO: Support auto join and rejection
|
||||||
|
|
||||||
|
if not self.is_mine_id(user_id):
|
||||||
|
raise SynapseError(400, "User not on this server")
|
||||||
|
|
||||||
|
local_profile = {}
|
||||||
|
if "profile" in content:
|
||||||
|
if "name" in content["profile"]:
|
||||||
|
local_profile["name"] = content["profile"]["name"]
|
||||||
|
if "avatar_url" in content["profile"]:
|
||||||
|
local_profile["avatar_url"] = content["profile"]["avatar_url"]
|
||||||
|
|
||||||
|
yield self.store.register_user_group_membership(
|
||||||
|
group_id, user_id,
|
||||||
|
membership="invite",
|
||||||
|
content={"profile": local_profile, "inviter": content["inviter"]},
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue({"state": "invite"})
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def remove_user_from_group(self, group_id, user_id, requester_user_id, content):
|
||||||
|
"""Remove a user from a group
|
||||||
|
"""
|
||||||
|
if user_id == requester_user_id:
|
||||||
|
yield self.store.register_user_group_membership(
|
||||||
|
group_id, user_id,
|
||||||
|
membership="leave",
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Should probably remember that we tried to leave so that we can
|
||||||
|
# retry if the group server is currently down.
|
||||||
|
|
||||||
|
if self.is_mine_id(group_id):
|
||||||
|
res = yield self.groups_server_handler.remove_user_from_group(
|
||||||
|
group_id, user_id, requester_user_id, content,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
content["requester_user_id"] = requester_user_id
|
||||||
|
res = yield self.transport_client.remove_user_from_group(
|
||||||
|
get_domain_from_id(group_id), group_id, requester_user_id,
|
||||||
|
user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue(res)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def user_removed_from_group(self, group_id, user_id, content):
|
||||||
|
"""One of our users was removed/kicked from a group
|
||||||
|
"""
|
||||||
|
# TODO: Check if user in group
|
||||||
|
yield self.store.register_user_group_membership(
|
||||||
|
group_id, user_id,
|
||||||
|
membership="leave",
|
||||||
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def get_joined_groups(self, user_id):
|
||||||
|
group_ids = yield self.store.get_joined_groups(user_id)
|
||||||
|
defer.returnValue({"groups": group_ids})
|
@ -347,7 +347,7 @@ class MatrixFederationHttpClient(object):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def post_json(self, destination, path, data={}, long_retries=False,
|
def post_json(self, destination, path, data={}, long_retries=False,
|
||||||
timeout=None, ignore_backoff=False):
|
timeout=None, ignore_backoff=False, args={}):
|
||||||
""" Sends the specifed json data using POST
|
""" Sends the specifed json data using POST
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -383,6 +383,7 @@ class MatrixFederationHttpClient(object):
|
|||||||
destination,
|
destination,
|
||||||
"POST",
|
"POST",
|
||||||
path,
|
path,
|
||||||
|
query_bytes=encode_query_args(args),
|
||||||
body_callback=body_callback,
|
body_callback=body_callback,
|
||||||
headers_dict={"Content-Type": ["application/json"]},
|
headers_dict={"Content-Type": ["application/json"]},
|
||||||
long_retries=long_retries,
|
long_retries=long_retries,
|
||||||
@ -427,13 +428,6 @@ class MatrixFederationHttpClient(object):
|
|||||||
"""
|
"""
|
||||||
logger.debug("get_json args: %s", args)
|
logger.debug("get_json args: %s", args)
|
||||||
|
|
||||||
encoded_args = {}
|
|
||||||
for k, vs in args.items():
|
|
||||||
if isinstance(vs, basestring):
|
|
||||||
vs = [vs]
|
|
||||||
encoded_args[k] = [v.encode("UTF-8") for v in vs]
|
|
||||||
|
|
||||||
query_bytes = urllib.urlencode(encoded_args, True)
|
|
||||||
logger.debug("Query bytes: %s Retry DNS: %s", args, retry_on_dns_fail)
|
logger.debug("Query bytes: %s Retry DNS: %s", args, retry_on_dns_fail)
|
||||||
|
|
||||||
def body_callback(method, url_bytes, headers_dict):
|
def body_callback(method, url_bytes, headers_dict):
|
||||||
@ -444,7 +438,7 @@ class MatrixFederationHttpClient(object):
|
|||||||
destination,
|
destination,
|
||||||
"GET",
|
"GET",
|
||||||
path,
|
path,
|
||||||
query_bytes=query_bytes,
|
query_bytes=encode_query_args(args),
|
||||||
body_callback=body_callback,
|
body_callback=body_callback,
|
||||||
retry_on_dns_fail=retry_on_dns_fail,
|
retry_on_dns_fail=retry_on_dns_fail,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
@ -460,6 +454,52 @@ class MatrixFederationHttpClient(object):
|
|||||||
|
|
||||||
defer.returnValue(json.loads(body))
|
defer.returnValue(json.loads(body))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def delete_json(self, destination, path, long_retries=False,
|
||||||
|
timeout=None, ignore_backoff=False, args={}):
|
||||||
|
"""Send a DELETE request to the remote expecting some json response
|
||||||
|
|
||||||
|
Args:
|
||||||
|
destination (str): The remote server to send the HTTP request
|
||||||
|
to.
|
||||||
|
path (str): The HTTP path.
|
||||||
|
long_retries (bool): A boolean that indicates whether we should
|
||||||
|
retry for a short or long time.
|
||||||
|
timeout(int): How long to try (in ms) the destination for before
|
||||||
|
giving up. None indicates no timeout.
|
||||||
|
ignore_backoff (bool): true to ignore the historical backoff data and
|
||||||
|
try the request anyway.
|
||||||
|
Returns:
|
||||||
|
Deferred: Succeeds when we get a 2xx HTTP response. The result
|
||||||
|
will be the decoded JSON body.
|
||||||
|
|
||||||
|
Fails with ``HTTPRequestException`` if we get an HTTP response
|
||||||
|
code >= 300.
|
||||||
|
|
||||||
|
Fails with ``NotRetryingDestination`` if we are not yet ready
|
||||||
|
to retry this server.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = yield self._request(
|
||||||
|
destination,
|
||||||
|
"DELETE",
|
||||||
|
path,
|
||||||
|
query_bytes=encode_query_args(args),
|
||||||
|
headers_dict={"Content-Type": ["application/json"]},
|
||||||
|
long_retries=long_retries,
|
||||||
|
timeout=timeout,
|
||||||
|
ignore_backoff=ignore_backoff,
|
||||||
|
)
|
||||||
|
|
||||||
|
if 200 <= response.code < 300:
|
||||||
|
# We need to update the transactions table to say it was sent?
|
||||||
|
check_content_type_is_json(response.headers)
|
||||||
|
|
||||||
|
with logcontext.PreserveLoggingContext():
|
||||||
|
body = yield readBody(response)
|
||||||
|
|
||||||
|
defer.returnValue(json.loads(body))
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def get_file(self, destination, path, output_stream, args={},
|
def get_file(self, destination, path, output_stream, args={},
|
||||||
retry_on_dns_fail=True, max_size=None,
|
retry_on_dns_fail=True, max_size=None,
|
||||||
@ -610,3 +650,15 @@ def check_content_type_is_json(headers):
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Content-Type not application/json: was '%s'" % c_type
|
"Content-Type not application/json: was '%s'" % c_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def encode_query_args(args):
|
||||||
|
encoded_args = {}
|
||||||
|
for k, vs in args.items():
|
||||||
|
if isinstance(vs, basestring):
|
||||||
|
vs = [vs]
|
||||||
|
encoded_args[k] = [v.encode("UTF-8") for v in vs]
|
||||||
|
|
||||||
|
query_bytes = urllib.urlencode(encoded_args, True)
|
||||||
|
|
||||||
|
return query_bytes
|
||||||
|
@ -52,6 +52,7 @@ from synapse.rest.client.v2_alpha import (
|
|||||||
thirdparty,
|
thirdparty,
|
||||||
sendtodevice,
|
sendtodevice,
|
||||||
user_directory,
|
user_directory,
|
||||||
|
groups,
|
||||||
)
|
)
|
||||||
|
|
||||||
from synapse.http.server import JsonResource
|
from synapse.http.server import JsonResource
|
||||||
@ -102,3 +103,4 @@ class ClientRestResource(JsonResource):
|
|||||||
thirdparty.register_servlets(hs, client_resource)
|
thirdparty.register_servlets(hs, client_resource)
|
||||||
sendtodevice.register_servlets(hs, client_resource)
|
sendtodevice.register_servlets(hs, client_resource)
|
||||||
user_directory.register_servlets(hs, client_resource)
|
user_directory.register_servlets(hs, client_resource)
|
||||||
|
groups.register_servlets(hs, client_resource)
|
||||||
|
589
synapse/rest/client/v2_alpha/groups.py
Normal file
589
synapse/rest/client/v2_alpha/groups.py
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2017 Vector Creations Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
from synapse.http.servlet import RestServlet, parse_json_object_from_request
|
||||||
|
from synapse.types import GroupID
|
||||||
|
|
||||||
|
from ._base import client_v2_patterns
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupServlet(RestServlet):
|
||||||
|
"""Get the group profile
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns("/groups/(?P<group_id>[^/]*)/profile$")
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
group_description = yield self.groups_handler.get_group_profile(group_id, user_id)
|
||||||
|
|
||||||
|
defer.returnValue((200, group_description))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSummaryServlet(RestServlet):
|
||||||
|
"""Get the full group summary
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns("/groups/(?P<group_id>[^/]*)/summary$")
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupSummaryServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
get_group_summary = yield self.groups_handler.get_group_summary(group_id, user_id)
|
||||||
|
|
||||||
|
defer.returnValue((200, get_group_summary))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSummaryRoomsCatServlet(RestServlet):
|
||||||
|
"""Update/delete a rooms entry in the summary.
|
||||||
|
|
||||||
|
Matches both:
|
||||||
|
- /groups/:group/summary/rooms/:room_id
|
||||||
|
- /groups/:group/summary/categories/:category/rooms/:room_id
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/summary"
|
||||||
|
"(/categories/(?P<category_id>[^/]+))?"
|
||||||
|
"/rooms/(?P<room_id>[^/]*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupSummaryRoomsCatServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, category_id, room_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
resp = yield self.groups_handler.update_group_summary_room(
|
||||||
|
group_id, user_id,
|
||||||
|
room_id=room_id,
|
||||||
|
category_id=category_id,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_DELETE(self, request, group_id, category_id, room_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
resp = yield self.groups_handler.delete_group_summary_room(
|
||||||
|
group_id, user_id,
|
||||||
|
room_id=room_id,
|
||||||
|
category_id=category_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupCategoryServlet(RestServlet):
|
||||||
|
"""Get/add/update/delete a group category
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/categories/(?P<category_id>[^/]+)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupCategoryServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id, category_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
category = yield self.groups_handler.get_group_category(
|
||||||
|
group_id, user_id,
|
||||||
|
category_id=category_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, category))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, category_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
resp = yield self.groups_handler.update_group_category(
|
||||||
|
group_id, user_id,
|
||||||
|
category_id=category_id,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_DELETE(self, request, group_id, category_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
resp = yield self.groups_handler.delete_group_category(
|
||||||
|
group_id, user_id,
|
||||||
|
category_id=category_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupCategoriesServlet(RestServlet):
|
||||||
|
"""Get all group categories
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/categories/$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupCategoriesServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
category = yield self.groups_handler.get_group_categories(
|
||||||
|
group_id, user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, category))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupRoleServlet(RestServlet):
|
||||||
|
"""Get/add/update/delete a group role
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/roles/(?P<role_id>[^/]+)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupRoleServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id, role_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
category = yield self.groups_handler.get_group_role(
|
||||||
|
group_id, user_id,
|
||||||
|
role_id=role_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, category))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, role_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
resp = yield self.groups_handler.update_group_role(
|
||||||
|
group_id, user_id,
|
||||||
|
role_id=role_id,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_DELETE(self, request, group_id, role_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
resp = yield self.groups_handler.delete_group_role(
|
||||||
|
group_id, user_id,
|
||||||
|
role_id=role_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupRolesServlet(RestServlet):
|
||||||
|
"""Get all group roles
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/roles/$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupRolesServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
category = yield self.groups_handler.get_group_roles(
|
||||||
|
group_id, user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, category))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSummaryUsersRoleServlet(RestServlet):
|
||||||
|
"""Update/delete a user's entry in the summary.
|
||||||
|
|
||||||
|
Matches both:
|
||||||
|
- /groups/:group/summary/users/:room_id
|
||||||
|
- /groups/:group/summary/roles/:role/users/:user_id
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/summary"
|
||||||
|
"(/roles/(?P<role_id>[^/]+))?"
|
||||||
|
"/users/(?P<user_id>[^/]*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupSummaryUsersRoleServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, role_id, user_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
resp = yield self.groups_handler.update_group_summary_user(
|
||||||
|
group_id, requester_user_id,
|
||||||
|
user_id=user_id,
|
||||||
|
role_id=role_id,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_DELETE(self, request, group_id, role_id, user_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
resp = yield self.groups_handler.delete_group_summary_user(
|
||||||
|
group_id, requester_user_id,
|
||||||
|
user_id=user_id,
|
||||||
|
role_id=role_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupRoomServlet(RestServlet):
|
||||||
|
"""Get all rooms in a group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns("/groups/(?P<group_id>[^/]*)/rooms$")
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupRoomServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
result = yield self.groups_handler.get_rooms_in_group(group_id, user_id)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupUsersServlet(RestServlet):
|
||||||
|
"""Get all users in a group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns("/groups/(?P<group_id>[^/]*)/users$")
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupUsersServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
result = yield self.groups_handler.get_users_in_group(group_id, user_id)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupCreateServlet(RestServlet):
|
||||||
|
"""Create a group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns("/create_group$")
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupCreateServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
self.server_name = hs.hostname
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_POST(self, request):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
# TODO: Create group on remote server
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
localpart = content.pop("localpart")
|
||||||
|
group_id = GroupID.create(localpart, self.server_name).to_string()
|
||||||
|
|
||||||
|
result = yield self.groups_handler.create_group(group_id, user_id, content)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAdminRoomsServlet(RestServlet):
|
||||||
|
"""Add a room to the group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/admin/rooms/(?P<room_id>[^/]*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupAdminRoomsServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, room_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
result = yield self.groups_handler.add_room_to_group(
|
||||||
|
group_id, user_id, room_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAdminUsersInviteServlet(RestServlet):
|
||||||
|
"""Invite a user to the group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/admin/users/invite/(?P<user_id>[^/]*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupAdminUsersInviteServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
self.store = hs.get_datastore()
|
||||||
|
self.is_mine_id = hs.is_mine_id
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, user_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
config = content.get("config", {})
|
||||||
|
result = yield self.groups_handler.invite(
|
||||||
|
group_id, user_id, requester_user_id, config,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAdminUsersKickServlet(RestServlet):
|
||||||
|
"""Kick a user from the group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/admin/users/remove/(?P<user_id>[^/]*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupAdminUsersKickServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id, user_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
result = yield self.groups_handler.remove_user_from_group(
|
||||||
|
group_id, user_id, requester_user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSelfLeaveServlet(RestServlet):
|
||||||
|
"""Leave a joined group
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/self/leave$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupSelfLeaveServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
result = yield self.groups_handler.remove_user_from_group(
|
||||||
|
group_id, requester_user_id, requester_user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSelfJoinServlet(RestServlet):
|
||||||
|
"""Attempt to join a group, or knock
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/self/join$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupSelfJoinServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
result = yield self.groups_handler.join_group(
|
||||||
|
group_id, requester_user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSelfAcceptInviteServlet(RestServlet):
|
||||||
|
"""Accept a group invite
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/groups/(?P<group_id>[^/]*)/self/accept_invite$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupSelfAcceptInviteServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, group_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
requester_user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
result = yield self.groups_handler.accept_invite(
|
||||||
|
group_id, requester_user_id, content,
|
||||||
|
)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsForUserServlet(RestServlet):
|
||||||
|
"""Get all groups the logged in user is joined to
|
||||||
|
"""
|
||||||
|
PATTERNS = client_v2_patterns(
|
||||||
|
"/joined_groups$"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
super(GroupsForUserServlet, self).__init__()
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
self.groups_handler = hs.get_groups_local_handler()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
user_id = requester.user.to_string()
|
||||||
|
|
||||||
|
result = yield self.groups_handler.get_joined_groups(user_id)
|
||||||
|
|
||||||
|
defer.returnValue((200, result))
|
||||||
|
|
||||||
|
|
||||||
|
def register_servlets(hs, http_server):
|
||||||
|
GroupServlet(hs).register(http_server)
|
||||||
|
GroupSummaryServlet(hs).register(http_server)
|
||||||
|
GroupUsersServlet(hs).register(http_server)
|
||||||
|
GroupRoomServlet(hs).register(http_server)
|
||||||
|
GroupCreateServlet(hs).register(http_server)
|
||||||
|
GroupAdminRoomsServlet(hs).register(http_server)
|
||||||
|
GroupAdminUsersInviteServlet(hs).register(http_server)
|
||||||
|
GroupAdminUsersKickServlet(hs).register(http_server)
|
||||||
|
GroupSelfLeaveServlet(hs).register(http_server)
|
||||||
|
GroupSelfJoinServlet(hs).register(http_server)
|
||||||
|
GroupSelfAcceptInviteServlet(hs).register(http_server)
|
||||||
|
GroupsForUserServlet(hs).register(http_server)
|
||||||
|
GroupCategoryServlet(hs).register(http_server)
|
||||||
|
GroupCategoriesServlet(hs).register(http_server)
|
||||||
|
GroupSummaryRoomsCatServlet(hs).register(http_server)
|
||||||
|
GroupRoleServlet(hs).register(http_server)
|
||||||
|
GroupRolesServlet(hs).register(http_server)
|
||||||
|
GroupSummaryUsersRoleServlet(hs).register(http_server)
|
@ -50,6 +50,7 @@ from synapse.handlers.initial_sync import InitialSyncHandler
|
|||||||
from synapse.handlers.receipts import ReceiptsHandler
|
from synapse.handlers.receipts import ReceiptsHandler
|
||||||
from synapse.handlers.read_marker import ReadMarkerHandler
|
from synapse.handlers.read_marker import ReadMarkerHandler
|
||||||
from synapse.handlers.user_directory import UserDirectoyHandler
|
from synapse.handlers.user_directory import UserDirectoyHandler
|
||||||
|
from synapse.handlers.groups_local import GroupsLocalHandler
|
||||||
from synapse.groups.groups_server import GroupsServerHandler
|
from synapse.groups.groups_server import GroupsServerHandler
|
||||||
from synapse.groups.attestations import GroupAttestionRenewer, GroupAttestationSigning
|
from synapse.groups.attestations import GroupAttestionRenewer, GroupAttestationSigning
|
||||||
from synapse.http.client import SimpleHttpClient, InsecureInterceptableContextFactory
|
from synapse.http.client import SimpleHttpClient, InsecureInterceptableContextFactory
|
||||||
@ -141,6 +142,7 @@ class HomeServer(object):
|
|||||||
'read_marker_handler',
|
'read_marker_handler',
|
||||||
'action_generator',
|
'action_generator',
|
||||||
'user_directory_handler',
|
'user_directory_handler',
|
||||||
|
'groups_local_handler',
|
||||||
'groups_server_handler',
|
'groups_server_handler',
|
||||||
'groups_attestation_signing',
|
'groups_attestation_signing',
|
||||||
'groups_attestation_renewer',
|
'groups_attestation_renewer',
|
||||||
@ -314,6 +316,9 @@ class HomeServer(object):
|
|||||||
def build_user_directory_handler(self):
|
def build_user_directory_handler(self):
|
||||||
return UserDirectoyHandler(self)
|
return UserDirectoyHandler(self)
|
||||||
|
|
||||||
|
def build_groups_local_handler(self):
|
||||||
|
return GroupsLocalHandler(self)
|
||||||
|
|
||||||
def build_groups_server_handler(self):
|
def build_groups_server_handler(self):
|
||||||
return GroupsServerHandler(self)
|
return GroupsServerHandler(self)
|
||||||
|
|
||||||
|
@ -756,6 +756,95 @@ class GroupServerStore(SQLBaseStore):
|
|||||||
desc="add_room_to_group",
|
desc="add_room_to_group",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def register_user_group_membership(self, group_id, user_id, membership,
|
||||||
|
is_admin=False, content={},
|
||||||
|
local_attestation=None,
|
||||||
|
remote_attestation=None,
|
||||||
|
):
|
||||||
|
"""Registers that a local user is a member of a (local or remote) group.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
group_id (str)
|
||||||
|
user_id (str)
|
||||||
|
membership (str)
|
||||||
|
is_admin (bool)
|
||||||
|
content (dict): Content of the membership, e.g. includes the inviter
|
||||||
|
if the user has been invited.
|
||||||
|
local_attestation (dict): If remote group then store the fact that we
|
||||||
|
have given out an attestation, else None.
|
||||||
|
remote_attestation (dict): If remote group then store the remote
|
||||||
|
attestation from the group, else None.
|
||||||
|
"""
|
||||||
|
def _register_user_group_membership_txn(txn):
|
||||||
|
# TODO: Upsert?
|
||||||
|
self._simple_delete_txn(
|
||||||
|
txn,
|
||||||
|
table="local_group_membership",
|
||||||
|
keyvalues={
|
||||||
|
"group_id": group_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self._simple_insert_txn(
|
||||||
|
txn,
|
||||||
|
table="local_group_membership",
|
||||||
|
values={
|
||||||
|
"group_id": group_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
"is_admin": is_admin,
|
||||||
|
"membership": membership,
|
||||||
|
"content": json.dumps(content),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Insert profile to ensure it comes down stream if its a join.
|
||||||
|
|
||||||
|
if membership == "join":
|
||||||
|
if local_attestation:
|
||||||
|
self._simple_insert_txn(
|
||||||
|
txn,
|
||||||
|
table="group_attestations_renewals",
|
||||||
|
values={
|
||||||
|
"group_id": group_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
"valid_until_ms": local_attestation["valid_until_ms"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if remote_attestation:
|
||||||
|
self._simple_insert_txn(
|
||||||
|
txn,
|
||||||
|
table="group_attestations_remote",
|
||||||
|
values={
|
||||||
|
"group_id": group_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
"valid_until_ms": remote_attestation["valid_until_ms"],
|
||||||
|
"attestation_json": json.dumps(remote_attestation),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._simple_delete_txn(
|
||||||
|
txn,
|
||||||
|
table="group_attestations_renewals",
|
||||||
|
keyvalues={
|
||||||
|
"group_id": group_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self._simple_delete_txn(
|
||||||
|
txn,
|
||||||
|
table="group_attestations_remote",
|
||||||
|
keyvalues={
|
||||||
|
"group_id": group_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
yield self.runInteraction(
|
||||||
|
"register_user_group_membership",
|
||||||
|
_register_user_group_membership_txn,
|
||||||
|
)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def create_group(self, group_id, user_id, name, avatar_url, short_description,
|
def create_group(self, group_id, user_id, name, avatar_url, short_description,
|
||||||
long_description,):
|
long_description,):
|
||||||
@ -837,3 +926,14 @@ class GroupServerStore(SQLBaseStore):
|
|||||||
defer.returnValue(json.loads(row["attestation_json"]))
|
defer.returnValue(json.loads(row["attestation_json"]))
|
||||||
|
|
||||||
defer.returnValue(None)
|
defer.returnValue(None)
|
||||||
|
|
||||||
|
def get_joined_groups(self, user_id):
|
||||||
|
return self._simple_select_onecol(
|
||||||
|
table="local_group_membership",
|
||||||
|
keyvalues={
|
||||||
|
"user_id": user_id,
|
||||||
|
"membership": "join",
|
||||||
|
},
|
||||||
|
retcol="group_id",
|
||||||
|
desc="get_joined_groups",
|
||||||
|
)
|
||||||
|
@ -142,3 +142,16 @@ CREATE TABLE group_attestations_remote (
|
|||||||
CREATE INDEX group_attestations_remote_g_idx ON group_attestations_remote(group_id, user_id);
|
CREATE INDEX group_attestations_remote_g_idx ON group_attestations_remote(group_id, user_id);
|
||||||
CREATE INDEX group_attestations_remote_u_idx ON group_attestations_remote(user_id);
|
CREATE INDEX group_attestations_remote_u_idx ON group_attestations_remote(user_id);
|
||||||
CREATE INDEX group_attestations_remote_v_idx ON group_attestations_remote(valid_until_ms);
|
CREATE INDEX group_attestations_remote_v_idx ON group_attestations_remote(valid_until_ms);
|
||||||
|
|
||||||
|
|
||||||
|
-- The group membership for the HS's users
|
||||||
|
CREATE TABLE local_group_membership (
|
||||||
|
group_id TEXT NOT NULL,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
is_admin BOOLEAN NOT NULL,
|
||||||
|
membership TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX local_group_membership_u_idx ON local_group_membership(user_id, group_id);
|
||||||
|
CREATE INDEX local_group_membership_g_idx ON local_group_membership(group_id);
|
||||||
|
@ -156,6 +156,11 @@ class EventID(DomainSpecificString):
|
|||||||
SIGIL = "$"
|
SIGIL = "$"
|
||||||
|
|
||||||
|
|
||||||
|
class GroupID(DomainSpecificString):
|
||||||
|
"""Structure representing a group ID."""
|
||||||
|
SIGIL = "+"
|
||||||
|
|
||||||
|
|
||||||
class StreamToken(
|
class StreamToken(
|
||||||
namedtuple("Token", (
|
namedtuple("Token", (
|
||||||
"room_key",
|
"room_key",
|
||||||
|
Loading…
Reference in New Issue
Block a user