Coverage for src/couchers/notifications/notify.py: 100%
16 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-20 11:53 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-20 11:53 +0000
1import logging
3from google.protobuf import empty_pb2
4from google.protobuf.message import Message
5from sqlalchemy.orm import Session
7from couchers.jobs.enqueue import queue_job
8from couchers.models import Notification
9from couchers.notifications.utils import enum_from_topic_action
10from couchers.proto.internal import jobs_pb2
12logger = logging.getLogger(__name__)
15def notify(
16 session: Session,
17 *,
18 user_id: int,
19 topic_action: str,
20 key: str,
21 data: Message | None = None,
22 moderation_state_id: int | None = None,
23) -> None:
24 """
25 Queues a notification given the notification and a target, i.e. a tuple (user_id, topic, key), and an action.
27 Notifications are sent to user identified by user_id, and are collapsed/grouped based on the combination of
28 (topic, key).
30 For example, topic may be "chat" for a group chat/direct message, and the key might be the chat id; so that messages
31 in the same group chat show up in one group.
33 The action is a simple identifier describing the action that caused the notification. For the above example, the
34 action might be "add_admin" if the notification was caused by another user adding an admin into the gorup chat.
36 Each different notification type should have its own action.
38 If moderation_state_id is provided, the notification delivery is deferred until the linked content
39 becomes VISIBLE or UNLISTED. This is used for notifications related to moderated content.
41 The key parameter is required. Pass key="" for notifications that intentionally don't have a key
42 (e.g., security notifications like password changes, or aggregated notifications like chat:missed_messages).
43 """
44 logger.info(f"Generating notification of type {topic_action} for user {user_id}")
45 topic, action = topic_action.split(":")
47 notification = Notification(
48 user_id=user_id,
49 topic_action=enum_from_topic_action[topic, action],
50 key=key,
51 data=(data or empty_pb2.Empty()).SerializeToString(),
52 moderation_state_id=moderation_state_id,
53 )
54 session.add(notification)
55 session.flush()
57 queue_job(
58 session,
59 job_type="handle_notification",
60 payload=jobs_pb2.HandleNotificationPayload(
61 notification_id=notification.id,
62 ),
63 )