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

Commit 63cbdd8

Browse files
jaywinkbabolivier
andauthored
Enable changing user type via users admin API (#11174)
Users admin API can now also modify user type in addition to allowing it to be set on user creation. Signed-off-by: Jason Robinson <[email protected]> Co-authored-by: Brendan Abolivier <[email protected]>
1 parent c1510c9 commit 63cbdd8

File tree

5 files changed

+80
-2
lines changed

5 files changed

+80
-2
lines changed

changelog.d/11174.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Users admin API can now also modify user type in addition to allowing it to be set on user creation.

docs/admin_api/user_admin_api.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ It returns a JSON body like the following:
5050
"auth_provider": "<provider2>",
5151
"external_id": "<user_id_provider_2>"
5252
}
53-
]
53+
],
54+
"user_type": null
5455
}
5556
```
5657

@@ -97,7 +98,8 @@ with a body of:
9798
],
9899
"avatar_url": "<avatar_url>",
99100
"admin": false,
100-
"deactivated": false
101+
"deactivated": false,
102+
"user_type": null
101103
}
102104
```
103105

@@ -135,6 +137,9 @@ Body parameters:
135137
unchanged on existing accounts and set to `false` for new accounts.
136138
A user cannot be erased by deactivating with this API. For details on
137139
deactivating users see [Deactivate Account](#deactivate-account).
140+
- `user_type` - string or null, optional. If provided, the user type will be
141+
adjusted. If `null` given, the user type will be cleared. Other
142+
allowed options are: `bot` and `support`.
138143

139144
If the user already exists then optional parameters default to the current value.
140145

synapse/rest/admin/users.py

+3
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ async def on_PUT(
326326
target_user.to_string()
327327
)
328328

329+
if "user_type" in body:
330+
await self.store.set_user_type(target_user, user_type)
331+
329332
user = await self.admin_handler.get_user(target_user)
330333
assert user is not None
331334

synapse/storage/databases/main/registration.py

+18
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,24 @@ def set_shadow_banned_txn(txn):
499499

500500
await self.db_pool.runInteraction("set_shadow_banned", set_shadow_banned_txn)
501501

502+
async def set_user_type(self, user: UserID, user_type: Optional[UserTypes]) -> None:
503+
"""Sets the user type.
504+
505+
Args:
506+
user: user ID of the user.
507+
user_type: type of the user or None for a user without a type.
508+
"""
509+
510+
def set_user_type_txn(txn):
511+
self.db_pool.simple_update_one_txn(
512+
txn, "users", {"name": user.to_string()}, {"user_type": user_type}
513+
)
514+
self._invalidate_cache_and_stream(
515+
txn, self.get_user_by_id, (user.to_string(),)
516+
)
517+
518+
await self.db_pool.runInteraction("set_user_type", set_user_type_txn)
519+
502520
def _query_for_auth(self, txn, token: str) -> Optional[TokenLookupResult]:
503521
sql = """
504522
SELECT users.name as user_id,

tests/rest/admin/test_user.py

+51
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,57 @@ def test_set_user_as_admin(self):
22702270
self.assertEqual("@user:test", channel.json_body["name"])
22712271
self.assertTrue(channel.json_body["admin"])
22722272

2273+
def test_set_user_type(self):
2274+
"""
2275+
Test changing user type.
2276+
"""
2277+
2278+
# Set to support type
2279+
channel = self.make_request(
2280+
"PUT",
2281+
self.url_other_user,
2282+
access_token=self.admin_user_tok,
2283+
content={"user_type": UserTypes.SUPPORT},
2284+
)
2285+
2286+
self.assertEqual(200, channel.code, msg=channel.json_body)
2287+
self.assertEqual("@user:test", channel.json_body["name"])
2288+
self.assertEqual(UserTypes.SUPPORT, channel.json_body["user_type"])
2289+
2290+
# Get user
2291+
channel = self.make_request(
2292+
"GET",
2293+
self.url_other_user,
2294+
access_token=self.admin_user_tok,
2295+
)
2296+
2297+
self.assertEqual(200, channel.code, msg=channel.json_body)
2298+
self.assertEqual("@user:test", channel.json_body["name"])
2299+
self.assertEqual(UserTypes.SUPPORT, channel.json_body["user_type"])
2300+
2301+
# Change back to a regular user
2302+
channel = self.make_request(
2303+
"PUT",
2304+
self.url_other_user,
2305+
access_token=self.admin_user_tok,
2306+
content={"user_type": None},
2307+
)
2308+
2309+
self.assertEqual(200, channel.code, msg=channel.json_body)
2310+
self.assertEqual("@user:test", channel.json_body["name"])
2311+
self.assertIsNone(channel.json_body["user_type"])
2312+
2313+
# Get user
2314+
channel = self.make_request(
2315+
"GET",
2316+
self.url_other_user,
2317+
access_token=self.admin_user_tok,
2318+
)
2319+
2320+
self.assertEqual(200, channel.code, msg=channel.json_body)
2321+
self.assertEqual("@user:test", channel.json_body["name"])
2322+
self.assertIsNone(channel.json_body["user_type"])
2323+
22732324
def test_accidental_deactivation_prevention(self):
22742325
"""
22752326
Ensure an account can't accidentally be deactivated by using a str value

0 commit comments

Comments
 (0)