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

Enable changing user type via users admin API #11174

Merged
merged 3 commits into from
Oct 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/11174.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Users admin API can now also modify user type in addition to allowing it to be set on user creation.
9 changes: 7 additions & 2 deletions docs/admin_api/user_admin_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ It returns a JSON body like the following:
"auth_provider": "<provider2>",
"external_id": "<user_id_provider_2>"
}
]
],
"user_type": null
babolivier marked this conversation as resolved.
Show resolved Hide resolved
}
```

Expand Down Expand Up @@ -97,7 +98,8 @@ with a body of:
],
"avatar_url": "<avatar_url>",
"admin": false,
"deactivated": false
"deactivated": false,
"user_type": null
}
```

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

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

Expand Down
3 changes: 3 additions & 0 deletions synapse/rest/admin/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,9 @@ async def on_PUT(
target_user.to_string()
)

if "user_type" in body:
babolivier marked this conversation as resolved.
Show resolved Hide resolved
await self.store.set_user_type(target_user, user_type)
babolivier marked this conversation as resolved.
Show resolved Hide resolved

user = await self.admin_handler.get_user(target_user)
assert user is not None

Expand Down
18 changes: 18 additions & 0 deletions synapse/storage/databases/main/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,24 @@ def set_shadow_banned_txn(txn):

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

async def set_user_type(self, user: UserID, user_type: Optional[UserTypes]) -> None:
"""Sets the user type.

Args:
user: user ID of the user.
user_type: type of the user or None for a user without a type.
"""

def set_user_type_txn(txn):
self.db_pool.simple_update_one_txn(
txn, "users", {"name": user.to_string()}, {"user_type": user_type}
)
self._invalidate_cache_and_stream(
txn, self.get_user_by_id, (user.to_string(),)
)

await self.db_pool.runInteraction("set_user_type", set_user_type_txn)

def _query_for_auth(self, txn, token: str) -> Optional[TokenLookupResult]:
sql = """
SELECT users.name as user_id,
Expand Down
51 changes: 51 additions & 0 deletions tests/rest/admin/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2270,6 +2270,57 @@ def test_set_user_as_admin(self):
self.assertEqual("@user:test", channel.json_body["name"])
self.assertTrue(channel.json_body["admin"])

def test_set_user_type(self):
"""
Test changing user type.
"""

# Set to support type
channel = self.make_request(
babolivier marked this conversation as resolved.
Show resolved Hide resolved
"PUT",
self.url_other_user,
access_token=self.admin_user_tok,
content={"user_type": UserTypes.SUPPORT},
)

self.assertEqual(200, channel.code, msg=channel.json_body)
self.assertEqual("@user:test", channel.json_body["name"])
self.assertEqual(UserTypes.SUPPORT, channel.json_body["user_type"])

# Get user
channel = self.make_request(
"GET",
self.url_other_user,
access_token=self.admin_user_tok,
)

self.assertEqual(200, channel.code, msg=channel.json_body)
self.assertEqual("@user:test", channel.json_body["name"])
self.assertEqual(UserTypes.SUPPORT, channel.json_body["user_type"])

# Change back to a regular user
channel = self.make_request(
"PUT",
self.url_other_user,
access_token=self.admin_user_tok,
content={"user_type": None},
)

self.assertEqual(200, channel.code, msg=channel.json_body)
self.assertEqual("@user:test", channel.json_body["name"])
self.assertIsNone(channel.json_body["user_type"])

# Get user
channel = self.make_request(
"GET",
self.url_other_user,
access_token=self.admin_user_tok,
)

self.assertEqual(200, channel.code, msg=channel.json_body)
self.assertEqual("@user:test", channel.json_body["name"])
self.assertIsNone(channel.json_body["user_type"])

def test_accidental_deactivation_prevention(self):
"""
Ensure an account can't accidentally be deactivated by using a str value
Expand Down