Skip to content

Commit

Permalink
Merge pull request #65 from OpenLXP/dev
Browse files Browse the repository at this point in the history
add api notifications support
  • Loading branch information
JDTobin authored Mar 27, 2024
2 parents d960036 + 61e06cd commit e98ea9d
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 0 deletions.
5 changes: 5 additions & 0 deletions app/core/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@

class CoreConfig(AppConfig):
name = 'core'

def ready(self):
super(CoreConfig, self).ready()
import core.signals
core.signals.interest_list_notify
Empty file.
35 changes: 35 additions & 0 deletions app/core/management/commands/clear_old_notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from datetime import timedelta

from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import timezone
from notifications.base.models import is_soft_delete
from notifications.models import Notification


class Command(BaseCommand):
"""This command deletes notifications that are older than some limit"""

def handle(self, *args, **options):
expiration_delta = settings.NOTIFICATIONS_EXPIRE_AFTER
if expiration_delta and isinstance(expiration_delta, timedelta):
curr = timezone.now()
limit = curr - expiration_delta
bad_notifications = Notification.objects.all().\
filter(timestamp__date__lt=limit)
if is_soft_delete():
bad_notifications.mark_all_as_deleted()
self.stdout.write(
self.style.SUCCESS(f"{bad_notifications.count()} old"
" notifications marked deleted"))
else:
count, _ = bad_notifications.delete()
self.stdout.write(
self.style.SUCCESS(f"{count} old notifications deleted"))
else:
self.stdout.write(
self.style.WARNING(
"NOTIFICATIONS_EXPIRE_AFTER must be set to "
"a timedelta in settings.py "
)
)
19 changes: 19 additions & 0 deletions app/core/management/commands/clear_read_notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.core.management.base import BaseCommand
from notifications.base.models import is_soft_delete
from notifications.models import Notification


class Command(BaseCommand):
"""This command deletes notifications that have already been read"""

def handle(self, *args, **options):
bad_notifications = Notification.objects.all().read()
if is_soft_delete():
bad_notifications.mark_all_as_deleted()
self.stdout.write(
self.style.SUCCESS(f"{bad_notifications.count()} read"
" notifications marked deleted"))
else:
count, _ = bad_notifications.delete()
self.stdout.write(
self.style.SUCCESS(f"{count} read notifications deleted"))
13 changes: 13 additions & 0 deletions app/core/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.db.models.signals import m2m_changed
from django.dispatch import receiver
from notifications.signals import notify

from .models import InterestList


@receiver(m2m_changed, sender=InterestList.experiences.through)
def interest_list_notify(sender, instance, action, reverse, pk_set, **kwargs):
if action == 'post_add' and not reverse:
notify.send(instance, recipient=instance.subscribers.all(),
verb='experiences added', added=pk_set,
list_name=instance.name)
73 changes: 73 additions & 0 deletions app/core/tests/test_commands_unit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from django.conf import settings
from django.core.management import call_command
from django.test import tag

from core.models import Experience, InterestList
from users.models import XDSUser

from .test_setup import TestSetUp


@tag('unit')
class CommandTests(TestSetUp):
"""Test cases for notification commands """

def test_clear_old_notifications(self):
"""Test that only old notifications are cleared"""
id = '12345'
course = Experience(metadata_key_hash=id)
course.save()
id_2 = '54321'
course_2 = Experience(metadata_key_hash=id_2)
course_2.save()
user = XDSUser.objects.create_user(self.email,
self.password,
first_name=self.first_name,
last_name=self.last_name)
list = InterestList(owner=user,
name="test list",
description="test desc")
list.save()
list.subscribers.add(user)
list.experiences.add(course)
self.assertEqual(user.notifications.count(), 1)

expiration_delta = settings.NOTIFICATIONS_EXPIRE_AFTER

notification_old = user.notifications.first()
notification_old.timestamp = notification_old.timestamp - \
expiration_delta - expiration_delta
notification_old.mark_as_read()

list.experiences.add(course_2)
self.assertEqual(user.notifications.count(), 2)

call_command('clear_old_notifications')
self.assertEqual(user.notifications.count(), 1)

def test_clear_read_notifications(self):
"""Test that only read notifications are cleared"""
id = '12345'
course = Experience(metadata_key_hash=id)
course.save()
id_2 = '54321'
course_2 = Experience(metadata_key_hash=id_2)
course_2.save()
user = XDSUser.objects.create_user(self.email,
self.password,
first_name=self.first_name,
last_name=self.last_name)
list = InterestList(owner=user,
name="test list",
description="test desc")
list.save()
list.subscribers.add(user)
list.experiences.add(course)
self.assertEqual(user.notifications.count(), 1)

user.notifications.first().mark_as_read()
list.experiences.add(course_2)
self.assertEqual(user.notifications.count(), 2)

call_command('clear_read_notifications')
self.assertEqual(user.notifications.count(), 1)
11 changes: 11 additions & 0 deletions app/openlxp_xds_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
https://docs.djangoproject.com/en/3.1/ref/settings/
"""

import datetime
import mimetypes
import os
import sys
Expand Down Expand Up @@ -53,6 +54,7 @@
'es_api',
'users',
'configurations',
'notifications',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -269,4 +271,13 @@

EMAIL_BACKEND = 'django_ses.SESBackend'


# Django-notifications package settings
DJANGO_NOTIFICATIONS_CONFIG = {
'USE_JSONFIELD': True,
}

# when notifications should be automatically deleted, should be days or greater
NOTIFICATIONS_EXPIRE_AFTER = datetime.timedelta(days=30)

DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880
3 changes: 3 additions & 0 deletions app/openlxp_xds_project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
import notifications.urls
from django.conf import settings
from django.conf.urls import url
from django.conf.urls.static import static
Expand All @@ -29,4 +30,6 @@
path('api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
url('', include('openlxp_authentication.urls')),
url('^inbox/notifications/',
include(notifications.urls, namespace='notifications')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Django>=3.2.3,<4.0

djangorestframework>=3.12.2,<3.13.0

django-notifications-hq>=1.8.3, <2.0

flake8>=3.8.4,<3.9.0

gunicorn>=20.0.4,<20.1.0
Expand Down

0 comments on commit e98ea9d

Please sign in to comment.