Coverage for src/couchers/notifications/push.py: 95%
21 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-04-16 15:13 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-04-16 15:13 +0000
1import functools
2import json
4from sqlalchemy.sql import func
6from couchers import urls
7from couchers.config import config
8from couchers.jobs.enqueue import queue_job
9from couchers.models import PushNotificationSubscription
10from couchers.notifications.push_api import get_vapid_public_key_from_private_key
11from couchers.sql import couchers_select as select
12from proto.internal import jobs_pb2
15@functools.cache
16def get_vapid_public_key():
17 return get_vapid_public_key_from_private_key(config["PUSH_NOTIFICATIONS_VAPID_PRIVATE_KEY"])
20def push_to_subscription(
21 session,
22 *,
23 push_notification_subscription_id: int,
24 user_id: int,
25 topic_action: str,
26 key: str = None,
27 title: str,
28 body: str,
29 icon: str = None,
30 url: str = None,
31 ttl: int = 0,
32):
33 queue_job(
34 session,
35 job_type="send_raw_push_notification",
36 payload=jobs_pb2.SendRawPushNotificationPayload(
37 data=json.dumps(
38 {
39 "title": config["NOTIFICATION_PREFIX"] + title[:500],
40 "body": body[:2000],
41 "icon": icon or urls.icon_url(),
42 "url": url,
43 "user_id": user_id,
44 "topic_action": topic_action,
45 "key": key or "",
46 }
47 ).encode("utf8"),
48 push_notification_subscription_id=push_notification_subscription_id,
49 ttl=ttl,
50 ),
51 priority=7,
52 )
55def _push_to_user(session, user_id, topic_action, key, title, body, icon, url, ttl):
56 """
57 Same as above but for a given user
58 """
59 sub_ids = (
60 session.execute(
61 select(PushNotificationSubscription.id)
62 .where(PushNotificationSubscription.user_id == user_id)
63 .where(PushNotificationSubscription.disabled_at > func.now())
64 )
65 .scalars()
66 .all()
67 )
68 for sub_id in sub_ids:
69 push_to_subscription(
70 session,
71 push_notification_subscription_id=sub_id,
72 user_id=user_id,
73 topic_action=topic_action,
74 key=key,
75 title=title,
76 body=body,
77 icon=icon,
78 url=url,
79 ttl=ttl,
80 )
83def push_to_user(
84 session,
85 *,
86 user_id: int,
87 topic_action: str,
88 key: str = None,
89 title: str,
90 body: str,
91 icon: str = None,
92 url: str = None,
93 ttl: int = 0,
94):
95 """
96 This indirection is so that this can be easily mocked. Not sure how to do it better :(
97 """
98 _push_to_user(
99 session,
100 user_id=user_id,
101 topic_action=topic_action,
102 key=key,
103 title=title,
104 body=body,
105 icon=icon,
106 url=url,
107 ttl=ttl,
108 )