From 6c7eee0a1f4317f861e5a0efd441b296ddd637de Mon Sep 17 00:00:00 2001 From: Mateusz Mandera Date: Sat, 27 Feb 2021 14:21:59 +0100 Subject: [PATCH] presence: Document that a user can disable their presence updates. This is a crucial detail, as it makes UserPresence an unreliable indicator of when users were recently active. It should be documented more clearly. --- docs/subsystems/presence.md | 3 +++ zerver/models.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/subsystems/presence.md b/docs/subsystems/presence.md index 5d1e058ed3..ec67ec972b 100644 --- a/docs/subsystems/presence.md +++ b/docs/subsystems/presence.md @@ -45,6 +45,9 @@ about that data structure: accurately compute whether that user is offline (even if the last data from the server was 45 seconds ago, and the user was last online 4:30 before the client received that server data). +* Users can disable their own presence updates in user settings + (`UserProfile.presence_enabled` is the flag storing [this user + preference](https://zulip.com/help/status-and-availability#disable-updating-availability)). * The `status_from_timestamp` function in `static/js/presence.js` is useful sample code; the `OFFLINE_THRESHOLD_SECS` check is critical to correct output. diff --git a/zerver/models.py b/zerver/models.py index c1cbf8ced8..643d546ea5 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -2817,6 +2817,17 @@ def get_huddle_backend(huddle_hash: str, id_list: List[int]) -> Huddle: class UserActivity(models.Model): + """Data table recording the last time each user hit Zulip endpoints + via which Clients; unlike UserPresence, these data are not exposed + to users via the Zulip API. + + Useful for debugging as well as to answer analytics questions like + "How many users have accessed the Zulip mobile app in the last + month?" or "Which users/organizations have recently used API + endpoint X that is about to be desupported" for communications + and database migration purposes. + """ + id: int = models.AutoField(auto_created=True, primary_key=True, verbose_name="ID") user_profile: UserProfile = models.ForeignKey(UserProfile, on_delete=CASCADE) client: Client = models.ForeignKey(Client, on_delete=CASCADE) @@ -2841,6 +2852,10 @@ class UserActivityInterval(models.Model): class UserPresence(models.Model): """A record from the last time we heard from a given user on a given client. + NOTE: Users can disable updates to this table (see UserProfile.presence_enabled), + so this cannot be used to determine if a user was recently active on Zulip. + The UserActivity table is recommended for that purpose. + This is a tricky subsystem, because it is highly optimized. See the docs: https://zulip.readthedocs.io/en/latest/subsystems/presence.html """