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 1 commit
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.bugfix
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.
babolivier marked this conversation as resolved.
Show resolved Hide resolved
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
possible options are: `bot` and `support`.
jaywink marked this conversation as resolved.
Show resolved Hide resolved

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("support", channel.json_body["user_type"])
jaywink marked this conversation as resolved.
Show resolved Hide resolved

# 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("support", channel.json_body["user_type"])
jaywink marked this conversation as resolved.
Show resolved Hide resolved

# 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