mirror of
https://github.com/element-hq/synapse.git
synced 2024-12-15 17:51:10 +00:00
Filter locked users in the admin API (#16328)
Co-authored-by: Hanadi Tamimi <hanadi.tamimi@sdui.de>
This commit is contained in:
parent
c1e244c8f7
commit
eef2b9e344
6 changed files with 51 additions and 7 deletions
1
changelog.d/16328.feature
Normal file
1
changelog.d/16328.feature
Normal file
|
@ -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>"
|
"external_id": "<user_id_provider_2>"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"user_type": null
|
"user_type": null,
|
||||||
|
"locked": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -103,7 +104,8 @@ with a body of:
|
||||||
],
|
],
|
||||||
"admin": false,
|
"admin": false,
|
||||||
"deactivated": 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,
|
"shadow_banned": 0,
|
||||||
"displayname": "<User One>",
|
"displayname": "<User One>",
|
||||||
"avatar_url": null,
|
"avatar_url": null,
|
||||||
"creation_ts": 1560432668000
|
"creation_ts": 1560432668000,
|
||||||
|
"locked": false
|
||||||
}, {
|
}, {
|
||||||
"name": "<user_id2>",
|
"name": "<user_id2>",
|
||||||
"is_guest": 0,
|
"is_guest": 0,
|
||||||
|
@ -195,7 +198,8 @@ A response body like the following is returned:
|
||||||
"shadow_banned": 0,
|
"shadow_banned": 0,
|
||||||
"displayname": "<User Two>",
|
"displayname": "<User Two>",
|
||||||
"avatar_url": "<avatar_url>",
|
"avatar_url": "<avatar_url>",
|
||||||
"creation_ts": 1561550621000
|
"creation_ts": 1561550621000,
|
||||||
|
"locked": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"next_token": "100",
|
"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.
|
- `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".
|
Can be provided multiple times. Possible values are `bot`, `support` or "empty string".
|
||||||
"empty string" here means to exclude users without a type.
|
"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`.
|
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`,
|
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.
|
- `avatar_url` - string - The user's avatar URL if they have set one.
|
||||||
- `creation_ts` - integer - The user's creation timestamp in ms.
|
- `creation_ts` - integer - The user's creation timestamp in ms.
|
||||||
- `last_seen_ts` - integer - The user's last activity 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.
|
- `next_token`: string representing a positive integer - Indication for pagination. See above.
|
||||||
- `total` - integer - Total number of media.
|
- `total` - integer - Total number of media.
|
||||||
|
|
||||||
|
*Added in Synapse 1.93:* the `locked` query parameter and response field.
|
||||||
|
|
||||||
## Query current sessions for a user
|
## 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 `deactivated` can be used to include deactivated users.
|
||||||
The parameter `order_by` can be used to order the result.
|
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 `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".
|
Possible values are `bot`, `support` or "empty string".
|
||||||
"empty string" here means to exclude users without a type.
|
"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.",
|
"The guests parameter is not supported when MSC3861 is enabled.",
|
||||||
errcode=Codes.INVALID_PARAM,
|
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")
|
admins = parse_boolean(request, "admins")
|
||||||
|
|
||||||
# If support for MSC3866 is not enabled, apply no filtering based on the
|
# 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.SHADOW_BANNED.value,
|
||||||
UserSortOrder.CREATION_TS.value,
|
UserSortOrder.CREATION_TS.value,
|
||||||
UserSortOrder.LAST_SEEN_TS.value,
|
UserSortOrder.LAST_SEEN_TS.value,
|
||||||
|
UserSortOrder.LOCKED.value,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -154,6 +157,7 @@ class UsersRestServletV2(RestServlet):
|
||||||
direction,
|
direction,
|
||||||
approved,
|
approved,
|
||||||
not_user_types,
|
not_user_types,
|
||||||
|
locked,
|
||||||
)
|
)
|
||||||
|
|
||||||
# If support for MSC3866 is not enabled, don't show the approval flag.
|
# If support for MSC3866 is not enabled, don't show the approval flag.
|
||||||
|
|
|
@ -175,6 +175,7 @@ class DataStore(
|
||||||
direction: Direction = Direction.FORWARDS,
|
direction: Direction = Direction.FORWARDS,
|
||||||
approved: bool = True,
|
approved: bool = True,
|
||||||
not_user_types: Optional[List[str]] = None,
|
not_user_types: Optional[List[str]] = None,
|
||||||
|
locked: bool = False,
|
||||||
) -> Tuple[List[JsonDict], int]:
|
) -> Tuple[List[JsonDict], int]:
|
||||||
"""Function to retrieve a paginated list of users from
|
"""Function to retrieve a paginated list of users from
|
||||||
users list. This will return a json list of users and the
|
users list. This will return a json list of users and the
|
||||||
|
@ -194,6 +195,7 @@ class DataStore(
|
||||||
direction: sort ascending or descending
|
direction: sort ascending or descending
|
||||||
approved: whether to include approved users
|
approved: whether to include approved users
|
||||||
not_user_types: list of user types to exclude
|
not_user_types: list of user types to exclude
|
||||||
|
locked: whether to include locked users
|
||||||
Returns:
|
Returns:
|
||||||
A tuple of a list of mappings from user to information and a count of total users.
|
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:
|
if not deactivated:
|
||||||
filters.append("deactivated = 0")
|
filters.append("deactivated = 0")
|
||||||
|
|
||||||
|
if not locked:
|
||||||
|
filters.append("locked IS FALSE")
|
||||||
|
|
||||||
if admins is not None:
|
if admins is not None:
|
||||||
if admins:
|
if admins:
|
||||||
filters.append("admin = 1")
|
filters.append("admin = 1")
|
||||||
|
@ -290,7 +295,7 @@ class DataStore(
|
||||||
sql = f"""
|
sql = f"""
|
||||||
SELECT name, user_type, is_guest, admin, deactivated, shadow_banned,
|
SELECT name, user_type, is_guest, admin, deactivated, shadow_banned,
|
||||||
displayname, avatar_url, creation_ts * 1000 as creation_ts, approved,
|
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}
|
{sql_base}
|
||||||
ORDER BY {order_by_column} {order}, u.name ASC
|
ORDER BY {order_by_column} {order}, u.name ASC
|
||||||
LIMIT ? OFFSET ?
|
LIMIT ? OFFSET ?
|
||||||
|
|
|
@ -108,6 +108,7 @@ class UserSortOrder(Enum):
|
||||||
SHADOW_BANNED = "shadow_banned"
|
SHADOW_BANNED = "shadow_banned"
|
||||||
CREATION_TS = "creation_ts"
|
CREATION_TS = "creation_ts"
|
||||||
LAST_SEEN_TS = "last_seen_ts"
|
LAST_SEEN_TS = "last_seen_ts"
|
||||||
|
LOCKED = "locked"
|
||||||
|
|
||||||
|
|
||||||
class StatsStore(StateDeltasStore):
|
class StatsStore(StateDeltasStore):
|
||||||
|
|
|
@ -1146,6 +1146,32 @@ class UsersListTestCase(unittest.HomeserverTestCase):
|
||||||
users = {user["name"]: user for user in channel.json_body["users"]}
|
users = {user["name"]: user for user in channel.json_body["users"]}
|
||||||
self.assertIs(users[user_id]["erased"], True)
|
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(
|
def _order_test(
|
||||||
self,
|
self,
|
||||||
expected_user_list: List[str],
|
expected_user_list: List[str],
|
||||||
|
|
Loading…
Reference in a new issue