Skip to content

Commit

Permalink
feat: add push notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
aarushtools committed Sep 5, 2024
1 parent 1888e89 commit 7d829ab
Show file tree
Hide file tree
Showing 60 changed files with 2,693 additions and 176 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,10 @@ package-lock.json
# Virtual environments
venv/
.venv/

# Webpush
/keys/webpush/
/keys/

# Keys
*.pem
3 changes: 3 additions & 0 deletions config/docker/initial_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ python3 -u manage.py import_sports $(date +%m)

echo -e "${BLUE}${BOLD}Creating CSL apps...${CLEAR}"
python3 -u manage.py dev_create_cslapps

echo -e "${BLUE}${BOLD}Generating vapid keys...${CLEAR}"
python3 create_vapid_keys.py
25 changes: 25 additions & 0 deletions config/scripts/create_vapid_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import base64
import os

from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from py_vapid import Vapid

PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.makedirs(os.path.join(PROJECT_ROOT, "keys", "webpush"))

# Generate VAPID key pair
vapid = Vapid()
vapid.generate_keys()

# Get public and private keys for the vapid key pair
vapid.save_public_key(os.path.join(PROJECT_ROOT, "keys", "webpush", "public_key.pem"))
public_key_bytes = vapid.public_key.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)

vapid.save_key(os.path.join(PROJECT_ROOT, "keys", "webpush", "private_key.pem"))


# Convert the public key to applicationServerKey format
application_server_key = base64.urlsafe_b64encode(public_key_bytes).replace(b"=", b"").decode("utf8")

with open(os.path.join(PROJECT_ROOT, "keys", "webpush", "ApplicationServerKey.key"), "w", encoding="utf-8") as f:
f.write(application_server_key)
3 changes: 2 additions & 1 deletion cron/eighth-absence.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
timestamp=$(date +"%Y-%m-%d-%H%M")
cd /usr/local/www/intranet3
./cron/env.sh ./manage.py absence_email --silent
echo "Absence email sent at $timestamp." >> /var/log/ion/email.log
./cron/env.sh ./manage.py absence_notify --silent
echo "Absence email and push notification sent at $timestamp." >> /var/log/ion/email.log
96 changes: 96 additions & 0 deletions docs/sourcedoc/intranet.apps.announcements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,102 @@ intranet.apps.announcements.views module
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_BACKUP\_1087 module
------------------------------------------------------

.. automodule:: intranet.apps.announcements.views_BACKUP_1087
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_BACKUP\_1114 module
------------------------------------------------------

.. automodule:: intranet.apps.announcements.views_BACKUP_1114
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_BACKUP\_1972 module
------------------------------------------------------

.. automodule:: intranet.apps.announcements.views_BACKUP_1972
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_BASE\_1087 module
----------------------------------------------------

.. automodule:: intranet.apps.announcements.views_BASE_1087
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_BASE\_1114 module
----------------------------------------------------

.. automodule:: intranet.apps.announcements.views_BASE_1114
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_BASE\_1972 module
----------------------------------------------------

.. automodule:: intranet.apps.announcements.views_BASE_1972
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_LOCAL\_1087 module
-----------------------------------------------------

.. automodule:: intranet.apps.announcements.views_LOCAL_1087
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_LOCAL\_1114 module
-----------------------------------------------------

.. automodule:: intranet.apps.announcements.views_LOCAL_1114
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_LOCAL\_1972 module
-----------------------------------------------------

.. automodule:: intranet.apps.announcements.views_LOCAL_1972
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_REMOTE\_1087 module
------------------------------------------------------

.. automodule:: intranet.apps.announcements.views_REMOTE_1087
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_REMOTE\_1114 module
------------------------------------------------------

.. automodule:: intranet.apps.announcements.views_REMOTE_1114
:members:
:undoc-members:
:show-inheritance:

intranet.apps.announcements.views\_REMOTE\_1972 module
------------------------------------------------------

.. automodule:: intranet.apps.announcements.views_REMOTE_1972
:members:
:undoc-members:
:show-inheritance:

Module contents
---------------

Expand Down
8 changes: 8 additions & 0 deletions docs/sourcedoc/intranet.apps.bus.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ intranet.apps.bus.urls module
:undoc-members:
:show-inheritance:

intranet.apps.bus.utils module
------------------------------

.. automodule:: intranet.apps.bus.utils
:members:
:undoc-members:
:show-inheritance:

intranet.apps.bus.views module
------------------------------

Expand Down
8 changes: 8 additions & 0 deletions docs/sourcedoc/intranet.apps.eighth.management.commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ intranet.apps.eighth.management.commands.absence\_email module
:undoc-members:
:show-inheritance:

intranet.apps.eighth.management.commands.absence\_notify module
---------------------------------------------------------------

.. automodule:: intranet.apps.eighth.management.commands.absence_notify
:members:
:undoc-members:
:show-inheritance:

intranet.apps.eighth.management.commands.delete\_duplicate\_signups module
--------------------------------------------------------------------------

Expand Down
48 changes: 48 additions & 0 deletions docs/sourcedoc/intranet.apps.notifications.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ intranet.apps.notifications package
Submodules
----------

intranet.apps.notifications.admin module
----------------------------------------

.. automodule:: intranet.apps.notifications.admin
:members:
:undoc-members:
:show-inheritance:

intranet.apps.notifications.api module
--------------------------------------

.. automodule:: intranet.apps.notifications.api
:members:
:undoc-members:
:show-inheritance:

intranet.apps.notifications.emails module
-----------------------------------------

Expand All @@ -12,6 +28,14 @@ intranet.apps.notifications.emails module
:undoc-members:
:show-inheritance:

intranet.apps.notifications.forms module
----------------------------------------

.. automodule:: intranet.apps.notifications.forms
:members:
:undoc-members:
:show-inheritance:

intranet.apps.notifications.models module
-----------------------------------------

Expand All @@ -20,6 +44,14 @@ intranet.apps.notifications.models module
:undoc-members:
:show-inheritance:

intranet.apps.notifications.serializers module
----------------------------------------------

.. automodule:: intranet.apps.notifications.serializers
:members:
:undoc-members:
:show-inheritance:

intranet.apps.notifications.tasks module
----------------------------------------

Expand All @@ -28,6 +60,14 @@ intranet.apps.notifications.tasks module
:undoc-members:
:show-inheritance:

intranet.apps.notifications.tests module
----------------------------------------

.. automodule:: intranet.apps.notifications.tests
:members:
:undoc-members:
:show-inheritance:

intranet.apps.notifications.urls module
---------------------------------------

Expand All @@ -36,6 +76,14 @@ intranet.apps.notifications.urls module
:undoc-members:
:show-inheritance:

intranet.apps.notifications.utils module
----------------------------------------

.. automodule:: intranet.apps.notifications.utils
:members:
:undoc-members:
:show-inheritance:

intranet.apps.notifications.views module
----------------------------------------

Expand Down
8 changes: 8 additions & 0 deletions docs/sourcedoc/intranet.apps.polls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ intranet.apps.polls.models module
:undoc-members:
:show-inheritance:

intranet.apps.polls.notifications module
----------------------------------------

.. automodule:: intranet.apps.polls.notifications
:members:
:undoc-members:
:show-inheritance:

intranet.apps.polls.tests module
--------------------------------

Expand Down
21 changes: 18 additions & 3 deletions intranet/apps/announcements/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["expiration_date"].help_text = "By default, announcements expire after two weeks. To change this, click in the box above."

self.fields["notify_post"].help_text = "If this box is checked, students who have signed up for notifications will receive an email."
self.fields["notify_post"].help_text = (
"If this box is checked, students who have signed up for email "
"notifications will receive an email "
"and those who have signed up for push notifications will receive a "
"push notification."
)

self.fields["notify_email_all"].help_text = (
"This will send an email notification to all of the users who can see this post. This option "
Expand Down Expand Up @@ -41,7 +46,12 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["expiration_date"].help_text = "By default, announcements expire after two weeks. To change this, click in the box above."

self.fields["notify_post_resend"].help_text = "If this box is checked, students who have signed up for notifications will receive an email."
self.fields["notify_post_resend"].help_text = (
"If this box is checked, students who have signed up for email "
"notifications will receive an email "
"and those who have signed up for push notifications will "
"receive a push notification."
)

self.fields["notify_email_all_resend"].help_text = (
"This will resend an email notification to all of the users who can see this post. This option "
Expand Down Expand Up @@ -105,7 +115,12 @@ class AnnouncementAdminForm(forms.Form):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["notify_post"].help_text = "If this box is checked, students who have signed up for notifications will receive an email."
self.fields["notify_post"].help_text = (
"If this box is checked, students who have signed up for email "
"notifications will receive an email "
"and those who have signed up for push notifications will receive a "
"push notification."
)
self.fields["notify_email_all"].help_text = (
"This will send an email notification to all of the users who can see this post. This option "
"does NOT take users' email notification preferences into account, so please use with care."
Expand Down
34 changes: 32 additions & 2 deletions intranet/apps/announcements/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.core import exceptions
from django.db.models import Q
from django.urls import reverse
from django.utils.html import strip_tags
from push_notifications.models import WebPushDevice
from requests_oauthlib import OAuth1
from sentry_sdk import capture_exception

from ...utils.date import get_senior_graduation_year
from ..notifications.tasks import email_send_task
from ..notifications.tasks import email_send_task, send_bulk_notification
from ..notifications.utils import truncate_content, truncate_title
from ..users.models import User
from .models import Announcement

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -135,7 +141,7 @@ def announcement_posted_email(request, obj, send_all=False):
emails.append(u.notification_email)
users_send.append(u)

if not settings.PRODUCTION and len(emails) > 3:
if not settings.PRODUCTION and len(emails) > 3 and not settings.FORCE_EMAIL_SEND:
raise exceptions.PermissionDenied("You're about to email a lot of people, and you aren't in production!")

base_url = request.build_absolute_uri(reverse("index"))
Expand Down Expand Up @@ -200,3 +206,27 @@ def notify_twitter(status):
req = requests.post(url, data=data, auth=auth, timeout=15)

return req.text


def announcement_posted_push_notification(obj: Announcement) -> None:
"""Send a (Web)push notification to users when an announcement is posted.
obj: The announcement object
"""

if not obj.groups.all():
users = User.objects.filter(push_notification_preferences__announcement_notifications=True)
devices = WebPushDevice.objects.filter(user__in=users)
else:
users = User.objects.filter(Q(groups__in=obj.groups.all()) & Q(push_notification_preferences__announcement_notifications=True))
devices = WebPushDevice.objects.filter(user__in=users)

send_bulk_notification.delay(
filtered_objects=devices,
title=f"Announcement: {truncate_title(obj.title)} ({obj.get_author()})",
body=truncate_content(strip_tags(obj.content_no_links)),
data={
"url": settings.PUSH_NOTIFICATIONS_BASE_URL + reverse("view_announcement", args=[obj.id]),
},
)
2 changes: 2 additions & 0 deletions intranet/apps/announcements/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
admin_request_announcement_email,
announcement_approved_email,
announcement_posted_email,
announcement_posted_push_notification,
announcement_posted_twitter,
request_announcement_email,
)
Expand Down Expand Up @@ -48,6 +49,7 @@ def announcement_posted_hook(request, obj):
"""
if obj.notify_post:
announcement_posted_twitter(request, obj)
announcement_posted_push_notification(obj)
try:
notify_all = obj.notify_email_all
except AttributeError:
Expand Down
Loading

0 comments on commit 7d829ab

Please sign in to comment.