Skip to content

Commit 4909092

Browse files
committed
feat: add push notifications
1 parent 393bc16 commit 4909092

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2773
-181
lines changed

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,10 @@ package-lock.json
5656
# Virtual environments
5757
venv/
5858
.venv/
59+
60+
# Webpush
61+
/keys/webpush/
62+
/keys/
63+
64+
# Keys
65+
*.pem

config/docker/initial_setup.sh

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ echo -e "${BLUE}${BOLD}Creating eighth period blocks...${CLEAR}"
3939
python3 create_blocks.py -l A B -c 60
4040
python3 create_blocks.py -l A B C -i 4 -c 15
4141

42+
echo -e "${BLUE}${BOLD}Generating vapid keys...${CLEAR}"
43+
python3 create_vapid_keys.py
44+
4245
echo -e "${BLUE}${BOLD}Cleaning up scripts...${CLEAR}"
4346
for file in config/scripts/*.py; do
4447
rm "$(basename "$file")"

config/scripts/create_vapid_keys.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import base64
2+
import os
3+
4+
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
5+
from py_vapid import Vapid
6+
7+
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
8+
os.makedirs(os.path.join(PROJECT_ROOT, "keys", "webpush"))
9+
10+
# Generate VAPID key pair
11+
vapid = Vapid()
12+
vapid.generate_keys()
13+
14+
# Get public and private keys for the vapid key pair
15+
vapid.save_public_key(os.path.join(PROJECT_ROOT, "keys", "webpush", "public_key.pem"))
16+
public_key_bytes = vapid.public_key.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)
17+
18+
vapid.save_key(os.path.join(PROJECT_ROOT, "keys", "webpush", "private_key.pem"))
19+
20+
21+
# Convert the public key to applicationServerKey format
22+
application_server_key = base64.urlsafe_b64encode(public_key_bytes).replace(b"=", b"").decode("utf8")
23+
24+
with open(os.path.join(PROJECT_ROOT, "keys", "webpush", "ApplicationServerKey.key"), "w", encoding="utf-8") as f:
25+
f.write(application_server_key)

cron/eighth-absence.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
timestamp=$(date +"%Y-%m-%d-%H%M")
55
cd /usr/local/www/intranet3
66
./cron/env.sh ./manage.py absence_email --silent
7-
echo "Absence email sent at $timestamp." >> /var/log/ion/email.log
7+
./cron/env.sh ./manage.py absence_notify --silent
8+
echo "Absence email and push notification sent at $timestamp." >> /var/log/ion/email.log

docs/sourcedoc/intranet.apps.announcements.rst

+96
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,102 @@ intranet.apps.announcements.views module
7676
:undoc-members:
7777
:show-inheritance:
7878

79+
intranet.apps.announcements.views\_BACKUP\_1087 module
80+
------------------------------------------------------
81+
82+
.. automodule:: intranet.apps.announcements.views_BACKUP_1087
83+
:members:
84+
:undoc-members:
85+
:show-inheritance:
86+
87+
intranet.apps.announcements.views\_BACKUP\_1114 module
88+
------------------------------------------------------
89+
90+
.. automodule:: intranet.apps.announcements.views_BACKUP_1114
91+
:members:
92+
:undoc-members:
93+
:show-inheritance:
94+
95+
intranet.apps.announcements.views\_BACKUP\_1972 module
96+
------------------------------------------------------
97+
98+
.. automodule:: intranet.apps.announcements.views_BACKUP_1972
99+
:members:
100+
:undoc-members:
101+
:show-inheritance:
102+
103+
intranet.apps.announcements.views\_BASE\_1087 module
104+
----------------------------------------------------
105+
106+
.. automodule:: intranet.apps.announcements.views_BASE_1087
107+
:members:
108+
:undoc-members:
109+
:show-inheritance:
110+
111+
intranet.apps.announcements.views\_BASE\_1114 module
112+
----------------------------------------------------
113+
114+
.. automodule:: intranet.apps.announcements.views_BASE_1114
115+
:members:
116+
:undoc-members:
117+
:show-inheritance:
118+
119+
intranet.apps.announcements.views\_BASE\_1972 module
120+
----------------------------------------------------
121+
122+
.. automodule:: intranet.apps.announcements.views_BASE_1972
123+
:members:
124+
:undoc-members:
125+
:show-inheritance:
126+
127+
intranet.apps.announcements.views\_LOCAL\_1087 module
128+
-----------------------------------------------------
129+
130+
.. automodule:: intranet.apps.announcements.views_LOCAL_1087
131+
:members:
132+
:undoc-members:
133+
:show-inheritance:
134+
135+
intranet.apps.announcements.views\_LOCAL\_1114 module
136+
-----------------------------------------------------
137+
138+
.. automodule:: intranet.apps.announcements.views_LOCAL_1114
139+
:members:
140+
:undoc-members:
141+
:show-inheritance:
142+
143+
intranet.apps.announcements.views\_LOCAL\_1972 module
144+
-----------------------------------------------------
145+
146+
.. automodule:: intranet.apps.announcements.views_LOCAL_1972
147+
:members:
148+
:undoc-members:
149+
:show-inheritance:
150+
151+
intranet.apps.announcements.views\_REMOTE\_1087 module
152+
------------------------------------------------------
153+
154+
.. automodule:: intranet.apps.announcements.views_REMOTE_1087
155+
:members:
156+
:undoc-members:
157+
:show-inheritance:
158+
159+
intranet.apps.announcements.views\_REMOTE\_1114 module
160+
------------------------------------------------------
161+
162+
.. automodule:: intranet.apps.announcements.views_REMOTE_1114
163+
:members:
164+
:undoc-members:
165+
:show-inheritance:
166+
167+
intranet.apps.announcements.views\_REMOTE\_1972 module
168+
------------------------------------------------------
169+
170+
.. automodule:: intranet.apps.announcements.views_REMOTE_1972
171+
:members:
172+
:undoc-members:
173+
:show-inheritance:
174+
79175
Module contents
80176
---------------
81177

docs/sourcedoc/intranet.apps.bus.rst

+8
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ intranet.apps.bus.urls module
7676
:undoc-members:
7777
:show-inheritance:
7878

79+
intranet.apps.bus.utils module
80+
------------------------------
81+
82+
.. automodule:: intranet.apps.bus.utils
83+
:members:
84+
:undoc-members:
85+
:show-inheritance:
86+
7987
intranet.apps.bus.views module
8088
------------------------------
8189

docs/sourcedoc/intranet.apps.eighth.management.commands.rst

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ intranet.apps.eighth.management.commands.absence\_email module
1212
:undoc-members:
1313
:show-inheritance:
1414

15+
intranet.apps.eighth.management.commands.absence\_notify module
16+
---------------------------------------------------------------
17+
18+
.. automodule:: intranet.apps.eighth.management.commands.absence_notify
19+
:members:
20+
:undoc-members:
21+
:show-inheritance:
22+
1523
intranet.apps.eighth.management.commands.delete\_duplicate\_signups module
1624
--------------------------------------------------------------------------
1725

docs/sourcedoc/intranet.apps.notifications.rst

+48
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ intranet.apps.notifications package
44
Submodules
55
----------
66

7+
intranet.apps.notifications.admin module
8+
----------------------------------------
9+
10+
.. automodule:: intranet.apps.notifications.admin
11+
:members:
12+
:undoc-members:
13+
:show-inheritance:
14+
15+
intranet.apps.notifications.api module
16+
--------------------------------------
17+
18+
.. automodule:: intranet.apps.notifications.api
19+
:members:
20+
:undoc-members:
21+
:show-inheritance:
22+
723
intranet.apps.notifications.emails module
824
-----------------------------------------
925

@@ -12,6 +28,14 @@ intranet.apps.notifications.emails module
1228
:undoc-members:
1329
:show-inheritance:
1430

31+
intranet.apps.notifications.forms module
32+
----------------------------------------
33+
34+
.. automodule:: intranet.apps.notifications.forms
35+
:members:
36+
:undoc-members:
37+
:show-inheritance:
38+
1539
intranet.apps.notifications.models module
1640
-----------------------------------------
1741

@@ -20,6 +44,14 @@ intranet.apps.notifications.models module
2044
:undoc-members:
2145
:show-inheritance:
2246

47+
intranet.apps.notifications.serializers module
48+
----------------------------------------------
49+
50+
.. automodule:: intranet.apps.notifications.serializers
51+
:members:
52+
:undoc-members:
53+
:show-inheritance:
54+
2355
intranet.apps.notifications.tasks module
2456
----------------------------------------
2557

@@ -28,6 +60,14 @@ intranet.apps.notifications.tasks module
2860
:undoc-members:
2961
:show-inheritance:
3062

63+
intranet.apps.notifications.tests module
64+
----------------------------------------
65+
66+
.. automodule:: intranet.apps.notifications.tests
67+
:members:
68+
:undoc-members:
69+
:show-inheritance:
70+
3171
intranet.apps.notifications.urls module
3272
---------------------------------------
3373

@@ -36,6 +76,14 @@ intranet.apps.notifications.urls module
3676
:undoc-members:
3777
:show-inheritance:
3878

79+
intranet.apps.notifications.utils module
80+
----------------------------------------
81+
82+
.. automodule:: intranet.apps.notifications.utils
83+
:members:
84+
:undoc-members:
85+
:show-inheritance:
86+
3987
intranet.apps.notifications.views module
4088
----------------------------------------
4189

docs/sourcedoc/intranet.apps.polls.rst

+8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ intranet.apps.polls.models module
2828
:undoc-members:
2929
:show-inheritance:
3030

31+
intranet.apps.polls.notifications module
32+
----------------------------------------
33+
34+
.. automodule:: intranet.apps.polls.notifications
35+
:members:
36+
:undoc-members:
37+
:show-inheritance:
38+
3139
intranet.apps.polls.tests module
3240
--------------------------------
3341

intranet/apps/announcements/forms.py

+24-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ class Meta:
2323
fields = ["title", "author", "content", "groups", "expiration_date", "notify_post", "notify_email_all", "update_added_date", "pinned"]
2424
help_texts = {
2525
"expiration_date": "By default, announcements expire after two weeks. Choose the shortest time necessary.",
26-
"notify_post": "If this box is checked, students who have signed up for notifications will receive an email.",
26+
"notify_post": (
27+
"If this box is checked, students who have signed up for email "
28+
"notifications will receive an email "
29+
"and those who have signed up for push notifications will receive a "
30+
"push notification."
31+
),
2732
"notify_email_all": (
2833
"This will send an email notification to all of the users who can see this post. "
2934
"This option does NOT take users' email notification preferences into account, so please use with care."
@@ -50,9 +55,12 @@ def __init__(self, user, *args, **kwargs):
5055
else:
5156
self.fields["activity"].queryset = []
5257
self.fields["activity"].required = True
53-
self.fields[
54-
"notify_post"
55-
].help_text = "If this box is checked, students who have subscribed to your club's announcements will receive an email."
58+
self.fields["notify_post"].help_text = (
59+
"If this box is checked, students who have signed up for email "
60+
"notifications will receive an email "
61+
"and those who have signed up for push notifications will receive a "
62+
"push notification."
63+
)
5664

5765
if "instance" in kwargs: # Don't allow changing the activity once the announcement has been created
5866
self.fields["activity"].widget.attrs["disabled"] = True
@@ -92,7 +100,12 @@ def __init__(self, *args, **kwargs):
92100
super().__init__(*args, **kwargs)
93101
self.fields["expiration_date"].help_text = "By default, announcements expire after two weeks. Choose the shortest time necessary."
94102

95-
self.fields["notify_post_resend"].help_text = "If this box is checked, students who have signed up for notifications will receive an email."
103+
self.fields["notify_post_resend"].help_text = (
104+
"If this box is checked, students who have signed up for email "
105+
"notifications will receive an email "
106+
"and those who have signed up for push notifications will "
107+
"receive a push notification."
108+
)
96109

97110
self.fields["notify_email_all_resend"].help_text = (
98111
"This will resend an email notification to all of the users who can see this post. This option "
@@ -153,7 +166,12 @@ class AnnouncementAdminForm(forms.Form):
153166

154167
def __init__(self, *args, **kwargs):
155168
super().__init__(*args, **kwargs)
156-
self.fields["notify_post"].help_text = "If this box is checked, students who have signed up for notifications will receive an email."
169+
self.fields["notify_post"].help_text = (
170+
"If this box is checked, students who have signed up for email "
171+
"notifications will receive an email "
172+
"and those who have signed up for push notifications will receive a "
173+
"push notification."
174+
)
157175
self.fields["notify_email_all"].help_text = (
158176
"This will send an email notification to all of the users who can see this post. This option "
159177
"does NOT take users' email notification preferences into account, so please use with care."

0 commit comments

Comments
 (0)