diff --git a/synapse/groups/groups_server.py b/synapse/groups/groups_server.py
index 8cb922ddc7..6f09253b87 100644
--- a/synapse/groups/groups_server.py
+++ b/synapse/groups/groups_server.py
@@ -719,6 +719,27 @@ class GroupsServerHandler(GroupsServerWorkerHandler):
raise NotImplementedError()
+ async def change_user_admin_in_group(
+ self, group_id, user_id, want_admin, requester_user_id, content
+ ):
+ """Promotes or demotes a user in a group.
+ """
+
+ await self.check_group_is_ours(group_id, requester_user_id, and_exists=True)
+
+ if requester_user_id == user_id:
+ raise SynapseError(400, "User cannot target themselves")
+
+ is_admin = await self.store.is_user_admin_in_group(
+ group_id, requester_user_id
+ )
+ if not is_admin:
+ raise SynapseError(403, "User is not admin in group")
+
+ await self.store.change_user_admin_in_group(group_id, user_id, want_admin)
+
+ return {}
+
async def remove_user_from_group(
self, group_id, user_id, requester_user_id, content
):
diff --git a/synapse/handlers/groups_local.py b/synapse/handlers/groups_local.py
index 0e2656ccb3..aa98d6b441 100644
--- a/synapse/handlers/groups_local.py
+++ b/synapse/handlers/groups_local.py
@@ -461,6 +461,25 @@ class GroupsLocalHandler(GroupsLocalWorkerHandler):
return {"state": "invite", "user_profile": user_profile}
+ async def change_user_admin_in_group(
+ self, group_id, user_id, want_admin, requester_user_id, content
+ ):
+ """Promotes or demotes a user in a group.
+ """
+
+ if not self.is_mine_id(user_id):
+ raise SynapseError(400, "User not on this server")
+
+ # TODO: We should probably support federation, but this is fine for now
+ if not self.is_mine_id(group_id):
+ raise SynapseError(400, "Group not on this server")
+
+ res = await self.groups_server_handler.change_user_admin_in_group(
+ group_id, user_id, want_admin, requester_user_id, content
+ )
+
+ return res
+
async def remove_user_from_group(
self, group_id, user_id, requester_user_id, content
):
diff --git a/synapse/rest/client/v2_alpha/groups.py b/synapse/rest/client/v2_alpha/groups.py
index d84a6d7e11..1efe60f3a7 100644
--- a/synapse/rest/client/v2_alpha/groups.py
+++ b/synapse/rest/client/v2_alpha/groups.py
@@ -548,6 +548,31 @@ class GroupAdminUsersKickServlet(RestServlet):
return 200, result
+class GroupAdminChangeAdminServlet(RestServlet):
+ """Promote or demote a user in the group
+ """
+
+ PATTERNS = client_patterns(
+ "/groups/(?P<group_id>[^/]*)/admin/users/admins/(?P<user_id>[^/]*)$"
+ )
+
+ def __init__(self, hs):
+ super(GroupAdminChangeAdminServlet, self).__init__()
+ self.auth = hs.get_auth()
+ self.clock = hs.get_clock()
+ self.groups_handler = hs.get_groups_local_handler()
+
+ async def on_POST(self, request, group_id, user_id):
+ requester = await self.auth.get_user_by_req(request)
+ requester_user_id = requester.user.to_string()
+
+ content = parse_json_object_from_request(request)
+ want_admin = content["is_admin"]
+ result = await self.groups_handler.change_user_admin_in_group(
+ group_id, user_id, want_admin, requester_user_id, content
+ )
+
+ return 200, result
class GroupSelfLeaveServlet(RestServlet):
"""Leave a joined group
@@ -722,6 +747,7 @@ def register_servlets(hs, http_server):
GroupAdminRoomsConfigServlet(hs).register(http_server)
GroupAdminUsersInviteServlet(hs).register(http_server)
GroupAdminUsersKickServlet(hs).register(http_server)
+ GroupAdminChangeAdminServlet(hs).register(http_server)
GroupSelfLeaveServlet(hs).register(http_server)
GroupSelfJoinServlet(hs).register(http_server)
GroupSelfAcceptInviteServlet(hs).register(http_server)
diff --git a/synapse/storage/databases/main/group_server.py b/synapse/storage/databases/main/group_server.py
index 380db3a3f3..95d9868c3c 100644
--- a/synapse/storage/databases/main/group_server.py
+++ b/synapse/storage/databases/main/group_server.py
@@ -1038,6 +1038,14 @@ class GroupServerStore(GroupServerWorkerStore):
"remove_user_from_group", _remove_user_from_group_txn
)
+ def change_user_admin_in_group(self, group_id, user_id, is_admin):
+ return self.db_pool.simple_update(
+ table="group_users",
+ keyvalues={"group_id": group_id, "user_id": user_id},
+ updatevalues={"is_admin": is_admin},
+ desc="change_user_admin_in_group"
+ )
+
def add_room_to_group(self, group_id, room_id, is_public):
return self.db_pool.simple_insert(
table="group_rooms",
|