Co-authored-by: Hanadi Tamimi <hanadi.tamimi@sdui.de>tags/v1.93.0rc1
@@ -0,0 +1 @@ | |||
Report whether a user is `locked` in the [List Accounts admin API](https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#list-accounts), and exclude locked users by default. |
@@ -54,7 +54,8 @@ It returns a JSON body like the following: | |||
"external_id": "<user_id_provider_2>" | |||
} | |||
], | |||
"user_type": null | |||
"user_type": null, | |||
"locked": false | |||
} | |||
``` | |||
@@ -103,7 +104,8 @@ with a body of: | |||
], | |||
"admin": false, | |||
"deactivated": false, | |||
"user_type": null | |||
"user_type": null, | |||
"locked": false | |||
} | |||
``` | |||
@@ -184,7 +186,8 @@ A response body like the following is returned: | |||
"shadow_banned": 0, | |||
"displayname": "<User One>", | |||
"avatar_url": null, | |||
"creation_ts": 1560432668000 | |||
"creation_ts": 1560432668000, | |||
"locked": false | |||
}, { | |||
"name": "<user_id2>", | |||
"is_guest": 0, | |||
@@ -195,7 +198,8 @@ A response body like the following is returned: | |||
"shadow_banned": 0, | |||
"displayname": "<User Two>", | |||
"avatar_url": "<avatar_url>", | |||
"creation_ts": 1561550621000 | |||
"creation_ts": 1561550621000, | |||
"locked": false | |||
} | |||
], | |||
"next_token": "100", | |||
@@ -249,6 +253,8 @@ The following parameters should be set in the URL: | |||
- `not_user_type` - Exclude certain user types, such as bot users, from the request. | |||
Can be provided multiple times. Possible values are `bot`, `support` or "empty string". | |||
"empty string" here means to exclude users without a type. | |||
- `locked` - string representing a bool - Is optional and if `true` will **include** locked users. | |||
Defaults to `false` to exclude locked users. Note: Introduced in v1.93. | |||
Caution. The database only has indexes on the columns `name` and `creation_ts`. | |||
This means that if a different sort order is used (`is_guest`, `admin`, | |||
@@ -274,10 +280,11 @@ The following fields are returned in the JSON response body: | |||
- `avatar_url` - string - The user's avatar URL if they have set one. | |||
- `creation_ts` - integer - The user's creation timestamp in ms. | |||
- `last_seen_ts` - integer - The user's last activity timestamp in ms. | |||
- `locked` - bool - Status if that user has been marked as locked. Note: Introduced in v1.93. | |||
- `next_token`: string representing a positive integer - Indication for pagination. See above. | |||
- `total` - integer - Total number of media. | |||
*Added in Synapse 1.93:* the `locked` query parameter and response field. | |||
## Query current sessions for a user | |||
@@ -66,6 +66,7 @@ class UsersRestServletV2(RestServlet): | |||
The parameter `deactivated` can be used to include deactivated users. | |||
The parameter `order_by` can be used to order the result. | |||
The parameter `not_user_type` can be used to exclude certain user types. | |||
The parameter `locked` can be used to include locked users. | |||
Possible values are `bot`, `support` or "empty string". | |||
"empty string" here means to exclude users without a type. | |||
""" | |||
@@ -107,8 +108,9 @@ class UsersRestServletV2(RestServlet): | |||
"The guests parameter is not supported when MSC3861 is enabled.", | |||
errcode=Codes.INVALID_PARAM, | |||
) | |||
deactivated = parse_boolean(request, "deactivated", default=False) | |||
deactivated = parse_boolean(request, "deactivated", default=False) | |||
locked = parse_boolean(request, "locked", default=False) | |||
admins = parse_boolean(request, "admins") | |||
# If support for MSC3866 is not enabled, apply no filtering based on the | |||
@@ -133,6 +135,7 @@ class UsersRestServletV2(RestServlet): | |||
UserSortOrder.SHADOW_BANNED.value, | |||
UserSortOrder.CREATION_TS.value, | |||
UserSortOrder.LAST_SEEN_TS.value, | |||
UserSortOrder.LOCKED.value, | |||
), | |||
) | |||
@@ -154,6 +157,7 @@ class UsersRestServletV2(RestServlet): | |||
direction, | |||
approved, | |||
not_user_types, | |||
locked, | |||
) | |||
# If support for MSC3866 is not enabled, don't show the approval flag. | |||
@@ -175,6 +175,7 @@ class DataStore( | |||
direction: Direction = Direction.FORWARDS, | |||
approved: bool = True, | |||
not_user_types: Optional[List[str]] = None, | |||
locked: bool = False, | |||
) -> Tuple[List[JsonDict], int]: | |||
"""Function to retrieve a paginated list of users from | |||
users list. This will return a json list of users and the | |||
@@ -194,6 +195,7 @@ class DataStore( | |||
direction: sort ascending or descending | |||
approved: whether to include approved users | |||
not_user_types: list of user types to exclude | |||
locked: whether to include locked users | |||
Returns: | |||
A tuple of a list of mappings from user to information and a count of total users. | |||
""" | |||
@@ -226,6 +228,9 @@ class DataStore( | |||
if not deactivated: | |||
filters.append("deactivated = 0") | |||
if not locked: | |||
filters.append("locked IS FALSE") | |||
if admins is not None: | |||
if admins: | |||
filters.append("admin = 1") | |||
@@ -290,7 +295,7 @@ class DataStore( | |||
sql = f""" | |||
SELECT name, user_type, is_guest, admin, deactivated, shadow_banned, | |||
displayname, avatar_url, creation_ts * 1000 as creation_ts, approved, | |||
eu.user_id is not null as erased, last_seen_ts | |||
eu.user_id is not null as erased, last_seen_ts, locked | |||
{sql_base} | |||
ORDER BY {order_by_column} {order}, u.name ASC | |||
LIMIT ? OFFSET ? | |||
@@ -108,6 +108,7 @@ class UserSortOrder(Enum): | |||
SHADOW_BANNED = "shadow_banned" | |||
CREATION_TS = "creation_ts" | |||
LAST_SEEN_TS = "last_seen_ts" | |||
LOCKED = "locked" | |||
class StatsStore(StateDeltasStore): | |||
@@ -1146,6 +1146,32 @@ class UsersListTestCase(unittest.HomeserverTestCase): | |||
users = {user["name"]: user for user in channel.json_body["users"]} | |||
self.assertIs(users[user_id]["erased"], True) | |||
def test_filter_locked(self) -> None: | |||
# Create a new user. | |||
user_id = self.register_user("lockme", "lockme") | |||
# Lock them | |||
self.get_success(self.store.set_user_locked_status(user_id, True)) | |||
# Locked user should appear in list users API | |||
channel = self.make_request( | |||
"GET", | |||
self.url + "?locked=true", | |||
access_token=self.admin_user_tok, | |||
) | |||
users = {user["name"]: user for user in channel.json_body["users"]} | |||
self.assertIn(user_id, users) | |||
self.assertTrue(users[user_id]["locked"]) | |||
# Locked user should not appear in list users API | |||
channel = self.make_request( | |||
"GET", | |||
self.url + "?locked=false", | |||
access_token=self.admin_user_tok, | |||
) | |||
users = {user["name"]: user for user in channel.json_body["users"]} | |||
self.assertNotIn(user_id, users) | |||
def _order_test( | |||
self, | |||
expected_user_list: List[str], | |||