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

Commit eef2b9e

Browse files
hanadi92Hanadi Tamimi
andauthored
Filter locked users in the admin API (#16328)
Co-authored-by: Hanadi Tamimi <[email protected]>
1 parent c1e244c commit eef2b9e

File tree

6 files changed

+51
-7
lines changed

6 files changed

+51
-7
lines changed

changelog.d/16328.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

docs/admin_api/user_admin_api.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ It returns a JSON body like the following:
5454
"external_id": "<user_id_provider_2>"
5555
}
5656
],
57-
"user_type": null
57+
"user_type": null,
58+
"locked": false
5859
}
5960
```
6061

@@ -103,7 +104,8 @@ with a body of:
103104
],
104105
"admin": false,
105106
"deactivated": false,
106-
"user_type": null
107+
"user_type": null,
108+
"locked": false
107109
}
108110
```
109111

@@ -184,7 +186,8 @@ A response body like the following is returned:
184186
"shadow_banned": 0,
185187
"displayname": "<User One>",
186188
"avatar_url": null,
187-
"creation_ts": 1560432668000
189+
"creation_ts": 1560432668000,
190+
"locked": false
188191
}, {
189192
"name": "<user_id2>",
190193
"is_guest": 0,
@@ -195,7 +198,8 @@ A response body like the following is returned:
195198
"shadow_banned": 0,
196199
"displayname": "<User Two>",
197200
"avatar_url": "<avatar_url>",
198-
"creation_ts": 1561550621000
201+
"creation_ts": 1561550621000,
202+
"locked": false
199203
}
200204
],
201205
"next_token": "100",
@@ -249,6 +253,8 @@ The following parameters should be set in the URL:
249253
- `not_user_type` - Exclude certain user types, such as bot users, from the request.
250254
Can be provided multiple times. Possible values are `bot`, `support` or "empty string".
251255
"empty string" here means to exclude users without a type.
256+
- `locked` - string representing a bool - Is optional and if `true` will **include** locked users.
257+
Defaults to `false` to exclude locked users. Note: Introduced in v1.93.
252258

253259
Caution. The database only has indexes on the columns `name` and `creation_ts`.
254260
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:
274280
- `avatar_url` - string - The user's avatar URL if they have set one.
275281
- `creation_ts` - integer - The user's creation timestamp in ms.
276282
- `last_seen_ts` - integer - The user's last activity timestamp in ms.
277-
283+
- `locked` - bool - Status if that user has been marked as locked. Note: Introduced in v1.93.
278284
- `next_token`: string representing a positive integer - Indication for pagination. See above.
279285
- `total` - integer - Total number of media.
280286

287+
*Added in Synapse 1.93:* the `locked` query parameter and response field.
281288

282289
## Query current sessions for a user
283290

synapse/rest/admin/users.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class UsersRestServletV2(RestServlet):
6666
The parameter `deactivated` can be used to include deactivated users.
6767
The parameter `order_by` can be used to order the result.
6868
The parameter `not_user_type` can be used to exclude certain user types.
69+
The parameter `locked` can be used to include locked users.
6970
Possible values are `bot`, `support` or "empty string".
7071
"empty string" here means to exclude users without a type.
7172
"""
@@ -107,8 +108,9 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
107108
"The guests parameter is not supported when MSC3861 is enabled.",
108109
errcode=Codes.INVALID_PARAM,
109110
)
110-
deactivated = parse_boolean(request, "deactivated", default=False)
111111

112+
deactivated = parse_boolean(request, "deactivated", default=False)
113+
locked = parse_boolean(request, "locked", default=False)
112114
admins = parse_boolean(request, "admins")
113115

114116
# If support for MSC3866 is not enabled, apply no filtering based on the
@@ -133,6 +135,7 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
133135
UserSortOrder.SHADOW_BANNED.value,
134136
UserSortOrder.CREATION_TS.value,
135137
UserSortOrder.LAST_SEEN_TS.value,
138+
UserSortOrder.LOCKED.value,
136139
),
137140
)
138141

@@ -154,6 +157,7 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
154157
direction,
155158
approved,
156159
not_user_types,
160+
locked,
157161
)
158162

159163
# If support for MSC3866 is not enabled, don't show the approval flag.

synapse/storage/databases/main/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ async def get_users_paginate(
175175
direction: Direction = Direction.FORWARDS,
176176
approved: bool = True,
177177
not_user_types: Optional[List[str]] = None,
178+
locked: bool = False,
178179
) -> Tuple[List[JsonDict], int]:
179180
"""Function to retrieve a paginated list of users from
180181
users list. This will return a json list of users and the
@@ -194,6 +195,7 @@ async def get_users_paginate(
194195
direction: sort ascending or descending
195196
approved: whether to include approved users
196197
not_user_types: list of user types to exclude
198+
locked: whether to include locked users
197199
Returns:
198200
A tuple of a list of mappings from user to information and a count of total users.
199201
"""
@@ -226,6 +228,9 @@ def get_users_paginate_txn(
226228
if not deactivated:
227229
filters.append("deactivated = 0")
228230

231+
if not locked:
232+
filters.append("locked IS FALSE")
233+
229234
if admins is not None:
230235
if admins:
231236
filters.append("admin = 1")
@@ -290,7 +295,7 @@ def get_users_paginate_txn(
290295
sql = f"""
291296
SELECT name, user_type, is_guest, admin, deactivated, shadow_banned,
292297
displayname, avatar_url, creation_ts * 1000 as creation_ts, approved,
293-
eu.user_id is not null as erased, last_seen_ts
298+
eu.user_id is not null as erased, last_seen_ts, locked
294299
{sql_base}
295300
ORDER BY {order_by_column} {order}, u.name ASC
296301
LIMIT ? OFFSET ?

synapse/storage/databases/main/stats.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class UserSortOrder(Enum):
108108
SHADOW_BANNED = "shadow_banned"
109109
CREATION_TS = "creation_ts"
110110
LAST_SEEN_TS = "last_seen_ts"
111+
LOCKED = "locked"
111112

112113

113114
class StatsStore(StateDeltasStore):

tests/rest/admin/test_user.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,32 @@ def test_erasure_status(self) -> None:
11461146
users = {user["name"]: user for user in channel.json_body["users"]}
11471147
self.assertIs(users[user_id]["erased"], True)
11481148

1149+
def test_filter_locked(self) -> None:
1150+
# Create a new user.
1151+
user_id = self.register_user("lockme", "lockme")
1152+
1153+
# Lock them
1154+
self.get_success(self.store.set_user_locked_status(user_id, True))
1155+
1156+
# Locked user should appear in list users API
1157+
channel = self.make_request(
1158+
"GET",
1159+
self.url + "?locked=true",
1160+
access_token=self.admin_user_tok,
1161+
)
1162+
users = {user["name"]: user for user in channel.json_body["users"]}
1163+
self.assertIn(user_id, users)
1164+
self.assertTrue(users[user_id]["locked"])
1165+
1166+
# Locked user should not appear in list users API
1167+
channel = self.make_request(
1168+
"GET",
1169+
self.url + "?locked=false",
1170+
access_token=self.admin_user_tok,
1171+
)
1172+
users = {user["name"]: user for user in channel.json_body["users"]}
1173+
self.assertNotIn(user_id, users)
1174+
11491175
def _order_test(
11501176
self,
11511177
expected_user_list: List[str],

0 commit comments

Comments
 (0)