mirror of
https://github.com/element-hq/synapse
synced 2024-06-30 16:03:32 +00:00
Added presence update on change of profile information and config flags for selective presence tracking
Signed-off-by: Michael Hollister <michael@futo.org>
This commit is contained in:
parent
37558d5e4c
commit
16a21470dd
1
changelog.d/16992.feature
Normal file
1
changelog.d/16992.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Added presence update on change of profile information and config flags for selective presence tracking. Contributed by @Michael-Hollister.
|
|
@ -83,6 +83,8 @@ class UserPresenceState:
|
||||||
last_user_sync_ts: int
|
last_user_sync_ts: int
|
||||||
status_msg: Optional[str]
|
status_msg: Optional[str]
|
||||||
currently_active: bool
|
currently_active: bool
|
||||||
|
displayname: Optional[str]
|
||||||
|
avatar_url: Optional[str]
|
||||||
|
|
||||||
def as_dict(self) -> JsonDict:
|
def as_dict(self) -> JsonDict:
|
||||||
return attr.asdict(self)
|
return attr.asdict(self)
|
||||||
|
@ -101,4 +103,6 @@ class UserPresenceState:
|
||||||
last_user_sync_ts=0,
|
last_user_sync_ts=0,
|
||||||
status_msg=None,
|
status_msg=None,
|
||||||
currently_active=False,
|
currently_active=False,
|
||||||
|
displayname=None,
|
||||||
|
avatar_url=None,
|
||||||
)
|
)
|
||||||
|
|
|
@ -384,6 +384,16 @@ class ServerConfig(Config):
|
||||||
# Whether to internally track presence, requires that presence is enabled,
|
# Whether to internally track presence, requires that presence is enabled,
|
||||||
self.track_presence = self.presence_enabled and presence_enabled != "untracked"
|
self.track_presence = self.presence_enabled and presence_enabled != "untracked"
|
||||||
|
|
||||||
|
# Disabling server-side presence tracking
|
||||||
|
self.sync_presence_tracking = presence_config.get(
|
||||||
|
"sync_presence_tracking", True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Disabling federation presence tracking
|
||||||
|
self.federation_presence_tracking = presence_config.get(
|
||||||
|
"federation_presence_tracking", True
|
||||||
|
)
|
||||||
|
|
||||||
# Custom presence router module
|
# Custom presence router module
|
||||||
# This is the legacy way of configuring it (the config should now be put in the modules section)
|
# This is the legacy way of configuring it (the config should now be put in the modules section)
|
||||||
self.presence_router_module_class = None
|
self.presence_router_module_class = None
|
||||||
|
|
|
@ -1428,6 +1428,17 @@ class FederationHandlerRegistry:
|
||||||
if not self.config.server.track_presence and edu_type == EduTypes.PRESENCE:
|
if not self.config.server.track_presence and edu_type == EduTypes.PRESENCE:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (
|
||||||
|
not self.config.server.federation_presence_tracking
|
||||||
|
and edu_type == EduTypes.PRESENCE
|
||||||
|
):
|
||||||
|
filtered_edus = []
|
||||||
|
for e in content["push"]:
|
||||||
|
# Process only profile presence updates to reduce resource impact
|
||||||
|
if "status_msg" in e or "displayname" in e or "avatar_url" in e:
|
||||||
|
filtered_edus.append(e)
|
||||||
|
content["push"] = filtered_edus
|
||||||
|
|
||||||
# Check if we have a handler on this instance
|
# Check if we have a handler on this instance
|
||||||
handler = self.edu_handlers.get(edu_type)
|
handler = self.edu_handlers.get(edu_type)
|
||||||
if handler:
|
if handler:
|
||||||
|
|
|
@ -201,6 +201,7 @@ class BasePresenceHandler(abc.ABC):
|
||||||
|
|
||||||
self._presence_enabled = hs.config.server.presence_enabled
|
self._presence_enabled = hs.config.server.presence_enabled
|
||||||
self._track_presence = hs.config.server.track_presence
|
self._track_presence = hs.config.server.track_presence
|
||||||
|
self._sync_presence_tracking = hs.config.server.sync_presence_tracking
|
||||||
|
|
||||||
self._federation = None
|
self._federation = None
|
||||||
if hs.should_send_federation():
|
if hs.should_send_federation():
|
||||||
|
@ -451,6 +452,8 @@ class BasePresenceHandler(abc.ABC):
|
||||||
state = {
|
state = {
|
||||||
"presence": current_presence_state.state,
|
"presence": current_presence_state.state,
|
||||||
"status_message": current_presence_state.status_msg,
|
"status_message": current_presence_state.status_msg,
|
||||||
|
"displayname": current_presence_state.displayname,
|
||||||
|
"avatar_url": current_presence_state.avatar_url,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Copy the presence state to the tip of the presence stream.
|
# Copy the presence state to the tip of the presence stream.
|
||||||
|
@ -579,7 +582,11 @@ class WorkerPresenceHandler(BasePresenceHandler):
|
||||||
Called by the sync and events servlets to record that a user has connected to
|
Called by the sync and events servlets to record that a user has connected to
|
||||||
this worker and is waiting for some events.
|
this worker and is waiting for some events.
|
||||||
"""
|
"""
|
||||||
if not affect_presence or not self._track_presence:
|
if (
|
||||||
|
not affect_presence
|
||||||
|
or not self._track_presence
|
||||||
|
or not self._sync_presence_tracking
|
||||||
|
):
|
||||||
return _NullContextManager()
|
return _NullContextManager()
|
||||||
|
|
||||||
# Note that this causes last_active_ts to be incremented which is not
|
# Note that this causes last_active_ts to be incremented which is not
|
||||||
|
@ -648,6 +655,8 @@ class WorkerPresenceHandler(BasePresenceHandler):
|
||||||
row.last_user_sync_ts,
|
row.last_user_sync_ts,
|
||||||
row.status_msg,
|
row.status_msg,
|
||||||
row.currently_active,
|
row.currently_active,
|
||||||
|
row.displayname,
|
||||||
|
row.avatar_url,
|
||||||
)
|
)
|
||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
|
@ -1140,7 +1149,11 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
client that is being used by a user.
|
client that is being used by a user.
|
||||||
presence_state: The presence state indicated in the sync request
|
presence_state: The presence state indicated in the sync request
|
||||||
"""
|
"""
|
||||||
if not affect_presence or not self._track_presence:
|
if (
|
||||||
|
not affect_presence
|
||||||
|
or not self._track_presence
|
||||||
|
or not self._sync_presence_tracking
|
||||||
|
):
|
||||||
return _NullContextManager()
|
return _NullContextManager()
|
||||||
|
|
||||||
curr_sync = self._user_device_to_num_current_syncs.get((user_id, device_id), 0)
|
curr_sync = self._user_device_to_num_current_syncs.get((user_id, device_id), 0)
|
||||||
|
@ -1340,6 +1353,8 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
|
|
||||||
new_fields["status_msg"] = push.get("status_msg", None)
|
new_fields["status_msg"] = push.get("status_msg", None)
|
||||||
new_fields["currently_active"] = push.get("currently_active", False)
|
new_fields["currently_active"] = push.get("currently_active", False)
|
||||||
|
new_fields["displayname"] = push.get("displayname", None)
|
||||||
|
new_fields["avatar_url"] = push.get("avatar_url", None)
|
||||||
|
|
||||||
prev_state = await self.current_state_for_user(user_id)
|
prev_state = await self.current_state_for_user(user_id)
|
||||||
updates.append(prev_state.copy_and_replace(**new_fields))
|
updates.append(prev_state.copy_and_replace(**new_fields))
|
||||||
|
@ -1369,6 +1384,8 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
the `state` dict.
|
the `state` dict.
|
||||||
"""
|
"""
|
||||||
status_msg = state.get("status_msg", None)
|
status_msg = state.get("status_msg", None)
|
||||||
|
displayname = state.get("displayname", None)
|
||||||
|
avatar_url = state.get("avatar_url", None)
|
||||||
presence = state["presence"]
|
presence = state["presence"]
|
||||||
|
|
||||||
if presence not in self.VALID_PRESENCE:
|
if presence not in self.VALID_PRESENCE:
|
||||||
|
@ -1414,6 +1431,8 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
else:
|
else:
|
||||||
# Syncs do not override the status message.
|
# Syncs do not override the status message.
|
||||||
new_fields["status_msg"] = status_msg
|
new_fields["status_msg"] = status_msg
|
||||||
|
new_fields["displayname"] = displayname
|
||||||
|
new_fields["avatar_url"] = avatar_url
|
||||||
|
|
||||||
await self._update_states(
|
await self._update_states(
|
||||||
[prev_state.copy_and_replace(**new_fields)], force_notify=force_notify
|
[prev_state.copy_and_replace(**new_fields)], force_notify=force_notify
|
||||||
|
@ -1634,6 +1653,8 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
if state.state != PresenceState.OFFLINE
|
if state.state != PresenceState.OFFLINE
|
||||||
or now - state.last_active_ts < 7 * 24 * 60 * 60 * 1000
|
or now - state.last_active_ts < 7 * 24 * 60 * 60 * 1000
|
||||||
or state.status_msg is not None
|
or state.status_msg is not None
|
||||||
|
or state.displayname is not None
|
||||||
|
or state.avatar_url is not None
|
||||||
]
|
]
|
||||||
|
|
||||||
await self._federation_queue.send_presence_to_destinations(
|
await self._federation_queue.send_presence_to_destinations(
|
||||||
|
@ -1668,6 +1689,14 @@ def should_notify(
|
||||||
notify_reason_counter.labels(user_location, "status_msg_change").inc()
|
notify_reason_counter.labels(user_location, "status_msg_change").inc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if old_state.displayname != new_state.displayname:
|
||||||
|
notify_reason_counter.labels(user_location, "displayname_change").inc()
|
||||||
|
return True
|
||||||
|
|
||||||
|
if old_state.avatar_url != new_state.avatar_url:
|
||||||
|
notify_reason_counter.labels(user_location, "avatar_url_change").inc()
|
||||||
|
return True
|
||||||
|
|
||||||
if old_state.state != new_state.state:
|
if old_state.state != new_state.state:
|
||||||
notify_reason_counter.labels(user_location, "state_change").inc()
|
notify_reason_counter.labels(user_location, "state_change").inc()
|
||||||
state_transition_counter.labels(
|
state_transition_counter.labels(
|
||||||
|
@ -1725,6 +1754,8 @@ def format_user_presence_state(
|
||||||
* status_msg: Optional. Included if `status_msg` is set on `state`. The user's
|
* status_msg: Optional. Included if `status_msg` is set on `state`. The user's
|
||||||
status.
|
status.
|
||||||
* currently_active: Optional. Included only if `state.state` is "online".
|
* currently_active: Optional. Included only if `state.state` is "online".
|
||||||
|
* displayname: Optional. The current display name for this user, if any.
|
||||||
|
* avatar_url: Optional. The current avatar URL for this user, if any.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -1733,7 +1764,9 @@ def format_user_presence_state(
|
||||||
"user_id": "@alice:example.com",
|
"user_id": "@alice:example.com",
|
||||||
"last_active_ago": 16783813918,
|
"last_active_ago": 16783813918,
|
||||||
"status_msg": "Hello world!",
|
"status_msg": "Hello world!",
|
||||||
"currently_active": True
|
"currently_active": True,
|
||||||
|
"displayname": "Alice",
|
||||||
|
"avatar_url": "mxc://localhost/wefuiwegh8742w"
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
content: JsonDict = {"presence": state.state}
|
content: JsonDict = {"presence": state.state}
|
||||||
|
@ -1745,6 +1778,10 @@ def format_user_presence_state(
|
||||||
content["status_msg"] = state.status_msg
|
content["status_msg"] = state.status_msg
|
||||||
if state.state == PresenceState.ONLINE:
|
if state.state == PresenceState.ONLINE:
|
||||||
content["currently_active"] = state.currently_active
|
content["currently_active"] = state.currently_active
|
||||||
|
if state.displayname:
|
||||||
|
content["displayname"] = state.displayname
|
||||||
|
if state.avatar_url:
|
||||||
|
content["avatar_url"] = state.avatar_url
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,19 @@ class ProfileHandler:
|
||||||
if propagate:
|
if propagate:
|
||||||
await self._update_join_states(requester, target_user)
|
await self._update_join_states(requester, target_user)
|
||||||
|
|
||||||
|
if self.hs.config.server.track_presence:
|
||||||
|
presence_handler = self.hs.get_presence_handler()
|
||||||
|
current_presence_state = await presence_handler.get_state(target_user)
|
||||||
|
|
||||||
|
state = {
|
||||||
|
"presence": current_presence_state.state,
|
||||||
|
"status_message": current_presence_state.status_msg,
|
||||||
|
"displayname": new_displayname,
|
||||||
|
"avatar_url": current_presence_state.avatar_url,
|
||||||
|
}
|
||||||
|
|
||||||
|
await presence_handler.set_state(target_user, requester.device_id, state)
|
||||||
|
|
||||||
async def get_avatar_url(self, target_user: UserID) -> Optional[str]:
|
async def get_avatar_url(self, target_user: UserID) -> Optional[str]:
|
||||||
if self.hs.is_mine(target_user):
|
if self.hs.is_mine(target_user):
|
||||||
try:
|
try:
|
||||||
|
@ -293,6 +306,19 @@ class ProfileHandler:
|
||||||
if propagate:
|
if propagate:
|
||||||
await self._update_join_states(requester, target_user)
|
await self._update_join_states(requester, target_user)
|
||||||
|
|
||||||
|
if self.hs.config.server.track_presence:
|
||||||
|
presence_handler = self.hs.get_presence_handler()
|
||||||
|
current_presence_state = await presence_handler.get_state(target_user)
|
||||||
|
|
||||||
|
state = {
|
||||||
|
"presence": current_presence_state.state,
|
||||||
|
"status_message": current_presence_state.status_msg,
|
||||||
|
"displayname": current_presence_state.displayname,
|
||||||
|
"avatar_url": new_avatar_url,
|
||||||
|
}
|
||||||
|
|
||||||
|
await presence_handler.set_state(target_user, requester.device_id, state)
|
||||||
|
|
||||||
@cached()
|
@cached()
|
||||||
async def check_avatar_size_and_mime_type(self, mxc: str) -> bool:
|
async def check_avatar_size_and_mime_type(self, mxc: str) -> bool:
|
||||||
"""Check that the size and content type of the avatar at the given MXC URI are
|
"""Check that the size and content type of the avatar at the given MXC URI are
|
||||||
|
|
|
@ -330,6 +330,8 @@ class PresenceStream(_StreamFromIdGen):
|
||||||
last_user_sync_ts: int
|
last_user_sync_ts: int
|
||||||
status_msg: str
|
status_msg: str
|
||||||
currently_active: bool
|
currently_active: bool
|
||||||
|
displayname: str
|
||||||
|
avatar_url: str
|
||||||
|
|
||||||
NAME = "presence"
|
NAME = "presence"
|
||||||
ROW_TYPE = PresenceStreamRow
|
ROW_TYPE = PresenceStreamRow
|
||||||
|
|
|
@ -181,6 +181,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
"last_user_sync_ts",
|
"last_user_sync_ts",
|
||||||
"status_msg",
|
"status_msg",
|
||||||
"currently_active",
|
"currently_active",
|
||||||
|
"displayname",
|
||||||
|
"avatar_url",
|
||||||
"instance_name",
|
"instance_name",
|
||||||
),
|
),
|
||||||
values=[
|
values=[
|
||||||
|
@ -193,6 +195,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
state.last_user_sync_ts,
|
state.last_user_sync_ts,
|
||||||
state.status_msg,
|
state.status_msg,
|
||||||
state.currently_active,
|
state.currently_active,
|
||||||
|
state.displayname,
|
||||||
|
state.avatar_url,
|
||||||
self._instance_name,
|
self._instance_name,
|
||||||
)
|
)
|
||||||
for stream_id, state in zip(stream_orderings, presence_states)
|
for stream_id, state in zip(stream_orderings, presence_states)
|
||||||
|
@ -232,7 +236,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
sql = """
|
sql = """
|
||||||
SELECT stream_id, user_id, state, last_active_ts,
|
SELECT stream_id, user_id, state, last_active_ts,
|
||||||
last_federation_update_ts, last_user_sync_ts,
|
last_federation_update_ts, last_user_sync_ts,
|
||||||
status_msg, currently_active
|
status_msg, currently_active, displayname,
|
||||||
|
avatar_url
|
||||||
FROM presence_stream
|
FROM presence_stream
|
||||||
WHERE ? < stream_id AND stream_id <= ?
|
WHERE ? < stream_id AND stream_id <= ?
|
||||||
ORDER BY stream_id ASC
|
ORDER BY stream_id ASC
|
||||||
|
@ -285,6 +290,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
"last_user_sync_ts",
|
"last_user_sync_ts",
|
||||||
"status_msg",
|
"status_msg",
|
||||||
"currently_active",
|
"currently_active",
|
||||||
|
"displayname",
|
||||||
|
"avatar_url",
|
||||||
),
|
),
|
||||||
desc="get_presence_for_users",
|
desc="get_presence_for_users",
|
||||||
),
|
),
|
||||||
|
@ -299,8 +306,10 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
last_user_sync_ts=last_user_sync_ts,
|
last_user_sync_ts=last_user_sync_ts,
|
||||||
status_msg=status_msg,
|
status_msg=status_msg,
|
||||||
currently_active=bool(currently_active),
|
currently_active=bool(currently_active),
|
||||||
|
displayname=displayname,
|
||||||
|
avatar_url=avatar_url,
|
||||||
)
|
)
|
||||||
for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active in rows
|
for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active, displayname, avatar_url, in rows
|
||||||
}
|
}
|
||||||
|
|
||||||
async def should_user_receive_full_presence_with_token(
|
async def should_user_receive_full_presence_with_token(
|
||||||
|
@ -427,6 +436,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
"last_user_sync_ts",
|
"last_user_sync_ts",
|
||||||
"status_msg",
|
"status_msg",
|
||||||
"currently_active",
|
"currently_active",
|
||||||
|
"displayname",
|
||||||
|
"avatar_url",
|
||||||
),
|
),
|
||||||
order_direction="ASC",
|
order_direction="ASC",
|
||||||
),
|
),
|
||||||
|
@ -440,6 +451,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
last_user_sync_ts,
|
last_user_sync_ts,
|
||||||
status_msg,
|
status_msg,
|
||||||
currently_active,
|
currently_active,
|
||||||
|
displayname,
|
||||||
|
avatar_url,
|
||||||
) in rows:
|
) in rows:
|
||||||
users_to_state[user_id] = UserPresenceState(
|
users_to_state[user_id] = UserPresenceState(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
|
@ -449,6 +462,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
last_user_sync_ts=last_user_sync_ts,
|
last_user_sync_ts=last_user_sync_ts,
|
||||||
status_msg=status_msg,
|
status_msg=status_msg,
|
||||||
currently_active=bool(currently_active),
|
currently_active=bool(currently_active),
|
||||||
|
displayname=displayname,
|
||||||
|
avatar_url=avatar_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
# We've run out of updates to query
|
# We've run out of updates to query
|
||||||
|
@ -471,7 +486,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
# query.
|
# query.
|
||||||
sql = (
|
sql = (
|
||||||
"SELECT user_id, state, last_active_ts, last_federation_update_ts,"
|
"SELECT user_id, state, last_active_ts, last_federation_update_ts,"
|
||||||
" last_user_sync_ts, status_msg, currently_active FROM presence_stream"
|
" last_user_sync_ts, status_msg, currently_active, displayname, avatar_url "
|
||||||
|
" FROM presence_stream"
|
||||||
" WHERE state != ?"
|
" WHERE state != ?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -489,8 +505,10 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore)
|
||||||
last_user_sync_ts=last_user_sync_ts,
|
last_user_sync_ts=last_user_sync_ts,
|
||||||
status_msg=status_msg,
|
status_msg=status_msg,
|
||||||
currently_active=bool(currently_active),
|
currently_active=bool(currently_active),
|
||||||
|
displayname=displayname,
|
||||||
|
avatar_url=avatar_url,
|
||||||
)
|
)
|
||||||
for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active in rows
|
for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active, displayname, avatar_url, in rows
|
||||||
]
|
]
|
||||||
|
|
||||||
def take_presence_startup_info(self) -> List[UserPresenceState]:
|
def take_presence_startup_info(self) -> List[UserPresenceState]:
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
SCHEMA_VERSION = 85 # remember to update the list below when updating
|
SCHEMA_VERSION = 86 # remember to update the list below when updating
|
||||||
"""Represents the expectations made by the codebase about the database schema
|
"""Represents the expectations made by the codebase about the database schema
|
||||||
|
|
||||||
This should be incremented whenever the codebase changes its requirements on the
|
This should be incremented whenever the codebase changes its requirements on the
|
||||||
|
@ -139,12 +139,15 @@ Changes in SCHEMA_VERSION = 84
|
||||||
|
|
||||||
Changes in SCHEMA_VERSION = 85
|
Changes in SCHEMA_VERSION = 85
|
||||||
- Add a column `suspended` to the `users` table
|
- Add a column `suspended` to the `users` table
|
||||||
|
|
||||||
|
Changes in SCHEMA_VERSION = 86
|
||||||
|
- Added displayname and avatar_url columns to presence_stream
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
SCHEMA_COMPAT_VERSION = (
|
SCHEMA_COMPAT_VERSION = (
|
||||||
# Transitive links are no longer written to `event_auth_chain_links`
|
# Added displayname and avatar_url columns to presence_stream
|
||||||
84
|
86
|
||||||
)
|
)
|
||||||
"""Limit on how far the synapse codebase can be rolled back without breaking db compat
|
"""Limit on how far the synapse codebase can be rolled back without breaking db compat
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
--
|
||||||
|
-- This file is licensed under the Affero General Public License (AGPL) version 3.
|
||||||
|
--
|
||||||
|
-- Copyright (C) 2023 New Vector, Ltd
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- This file is licensed under the Affero General Public License (AGPL) version 3.
|
||||||
|
--
|
||||||
|
-- Copyright (C) 2024 New Vector, Ltd
|
||||||
|
--
|
||||||
|
-- This program is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as
|
||||||
|
-- published by the Free Software Foundation, either version 3 of the
|
||||||
|
-- License, or (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- See the GNU Affero General Public License for more details:
|
||||||
|
-- <https://www.gnu.org/licenses/agpl-3.0.html>.
|
||||||
|
|
||||||
|
ALTER TABLE presence_stream ADD COLUMN displayname TEXT;
|
||||||
|
ALTER TABLE presence_stream ADD COLUMN avatar_url TEXT;
|
|
@ -450,6 +450,8 @@ class FilteringTestCase(unittest.HomeserverTestCase):
|
||||||
last_user_sync_ts=0,
|
last_user_sync_ts=0,
|
||||||
status_msg=None,
|
status_msg=None,
|
||||||
currently_active=False,
|
currently_active=False,
|
||||||
|
displayname=None,
|
||||||
|
avatar_url=None,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -478,6 +480,8 @@ class FilteringTestCase(unittest.HomeserverTestCase):
|
||||||
last_user_sync_ts=0,
|
last_user_sync_ts=0,
|
||||||
status_msg=None,
|
status_msg=None,
|
||||||
currently_active=False,
|
currently_active=False,
|
||||||
|
displayname=None,
|
||||||
|
avatar_url=None,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -366,6 +366,8 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||||
last_user_sync_ts=1,
|
last_user_sync_ts=1,
|
||||||
status_msg="I'm online!",
|
status_msg="I'm online!",
|
||||||
currently_active=True,
|
currently_active=True,
|
||||||
|
displayname=None,
|
||||||
|
avatar_url=None,
|
||||||
)
|
)
|
||||||
presence_states.append(presence_state)
|
presence_states.append(presence_state)
|
||||||
|
|
||||||
|
@ -718,6 +720,8 @@ class PresenceHandlerInitTestCase(unittest.HomeserverTestCase):
|
||||||
last_user_sync_ts=now,
|
last_user_sync_ts=now,
|
||||||
status_msg=None,
|
status_msg=None,
|
||||||
currently_active=True,
|
currently_active=True,
|
||||||
|
displayname=None,
|
||||||
|
avatar_url=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue