fix: Compute user last seen timestamp from last seen devices (#18948)
## Fix last seen timestamp in `/_synapse/admin/v2/users` response
Fixes #18955
The last seen timestamps contained in `/_synapse/admin/v2/users`
responses were computed as follows:
```sql
[...]
LEFT JOIN (
SELECT user_id, MAX(last_seen) AS last_seen_ts
FROM user_ips GROUP BY user_id
) ls ON u.name = ls.user_id
[...]
```
4367fb2d07/synapse/storage/databases/main/__init__.py (L302C1-L305C44)
This leads to empty timestamps (as in: user was never seen) if users are
inactive for longer than
[`user_ips_max_age`](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#user_ips_max_age).
The fix is quite trivial: Use the `devices` table, as this one also
contains last seen timestamps but is *not* periodically purged.
We are using this for automatic user account deletion (via
[synadm](https://codeberg.org/synadm/synadm)) and the patched code works
as intended, whereas the unpatched version wants to delete users during
long vacations. 🫣
This commit is contained in:
1
changelog.d/18948.bugfix
Normal file
1
changelog.d/18948.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Compute a user's last seen timestamp from their devices' last seen timestamps instead of IPs, because the latter are automatically cleared according to `user_ips_max_age`.
|
||||
@@ -299,10 +299,14 @@ class DataStore(
|
||||
FROM users as u
|
||||
LEFT JOIN profiles AS p ON u.name = p.full_user_id
|
||||
LEFT JOIN erased_users AS eu ON u.name = eu.user_id
|
||||
LEFT JOIN (
|
||||
SELECT user_id, MAX(last_seen) AS last_seen_ts
|
||||
FROM devices GROUP BY user_id
|
||||
) lsd ON u.name = lsd.user_id
|
||||
LEFT JOIN (
|
||||
SELECT user_id, MAX(last_seen) AS last_seen_ts
|
||||
FROM user_ips GROUP BY user_id
|
||||
) ls ON u.name = ls.user_id
|
||||
) lsi ON u.name = lsi.user_id
|
||||
{where_clause}
|
||||
"""
|
||||
sql = "SELECT COUNT(*) as total_users " + sql_base
|
||||
@@ -312,7 +316,8 @@ 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, locked
|
||||
eu.user_id is not null as erased,
|
||||
COALESCE(lsd.last_seen_ts, lsi.last_seen_ts) as last_seen_ts, locked
|
||||
{sql_base}
|
||||
ORDER BY {order_by_column} {order}, u.name ASC
|
||||
LIMIT ? OFFSET ?
|
||||
|
||||
Reference in New Issue
Block a user