Skip to content
This repository has been archived by the owner on May 12, 2022. It is now read-only.

Commit

Permalink
Add API to purge notifications
Browse files Browse the repository at this point in the history
This commit introduces API endpoints to request the removal of
notifications for specific users and to remove notifications containing
specific payloads.

Version bumped to 0.9.0
  • Loading branch information
viadanna committed Dec 12, 2019
1 parent c7ded99 commit 7ab4307
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 7 deletions.
22 changes: 22 additions & 0 deletions edx_notifications/lib/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
All in-proc API endpoints for acting as a Notifications Admin
"""
from edx_notifications.stores.store import notification_store


def purge_user_data(user_ids):
"""
This will purge the notifications and preferences for the given user IDs
:param user_ids: and iterable of user IDs
"""
store = notification_store()
store.purge_notifications_for_users(user_ids)


def purge_notifications_with_payload(payload):
"""
This will purge the notifications and containing the given payload
:payload: string content contained in notifications payload
"""
store = notification_store()
store.purge_notifications_containing(payload)
25 changes: 25 additions & 0 deletions edx_notifications/server/api/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Administration endpoints
"""
from django.http import HttpResponseBadRequest, HttpResponse, HttpResponseForbidden

from edx_notifications.lib.admin import purge_user_data
from edx_notifications.server.api.api_utils import AuthenticatedAPIView


class DeleteUsersData(AuthenticatedAPIView):
"""
POST removes all data for given user IDs
"""

def post(self, request):
"""
HTTP POST Handler
"""
if 'user_ids' not in request.data:
return HttpResponseBadRequest('Missing user ids')
if not request.user.is_staff:
return HttpResponseForbidden()
user_ids = request.data.get('user_ids')
purge_user_data(user_ids)
return HttpResponse(status=204)
51 changes: 51 additions & 0 deletions edx_notifications/server/api/tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Tests for the administration endpoints
"""
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test import TestCase

from edx_notifications.server.api.tests.utils import TestClient


class AdminAPITests(TestCase):
"""
Tests for the admin.py
"""

def setUp(self):
"""
Create clients
"""

self.admin_client = TestClient()
self.admin_user = User(username='admin', is_staff=True)
self.admin_user.save()
self.admin_client.login_user(self.admin_user)

self.client = TestClient()
self.user = User(username='user', is_staff=False)
self.user.save()
self.client.login_user(self.user)

def test_purge_user_data(self):
"""
Make sure purging user data works
"""

response = self.admin_client.post(
reverse('edx_notifications.admin.delete_users_data'),
{'user_ids': [self.admin_user.id]}
)
self.assertEqual(response.status_code, 204)

def test_admin_required_to_purge(self):
"""
Make sure purging is only available to staff users
"""

response = self.client.post(
reverse('edx_notifications.admin.delete_users_data'),
{'user_ids': [self.admin_user.id]}
)
self.assertEqual(response.status_code, 403)
2 changes: 2 additions & 0 deletions edx_notifications/server/api/url_regex.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@
CONSUMER_USER_PREFERENCES_DETAIL_REGEX = r'edx_notifications/v1/consumer/user_preferences/(?P<name>[0-9A-Za-z-]+)$'
CONSUMER_USER_PREFERENCES_DETAIL_NO_PARAM_REGEX = r'edx_notifications/v1/consumer/user_preferences/$'
CONSUMER_RENDERERS_TEMPLATES_REGEX = r'edx_notifications/v1/consumer/renderers/templates$'

ADMIN_USERS_DELETE = r'edx_notifications/v1/admin/user/delete$'
14 changes: 9 additions & 5 deletions edx_notifications/server/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
All URL mappings for HTTP-based APIs
"""
from django.conf.urls import patterns, url

from rest_framework.urlpatterns import format_suffix_patterns

from edx_notifications.server.api import consumer as consumer_views

from edx_notifications.server.api import consumer as consumer_views, admin as admin_views
from .url_regex import (
CONSUMER_NOTIFICATIONS_COUNT_REGEX,
CONSUMER_NOTIFICATION_DETAIL_REGEX,
Expand All @@ -17,8 +15,9 @@
CONSUMER_USER_PREFERENCES_DETAIL_REGEX,
CONSUMER_NOTIFICATIONS_PREFERENCES_REGEX,
CONSUMER_USER_PREFERENCES_REGEX,
CONSUMER_USER_PREFERENCES_DETAIL_NO_PARAM_REGEX)

CONSUMER_USER_PREFERENCES_DETAIL_NO_PARAM_REGEX,
ADMIN_USERS_DELETE
)

urlpatterns = patterns( # pylint: disable=invalid-name
'',
Expand Down Expand Up @@ -72,6 +71,11 @@
consumer_views.UserPreferenceDetail.as_view(),
name='edx_notifications.consumer.user_preferences.detail.no_param'
),
url(
ADMIN_USERS_DELETE,
admin_views.DeleteUsersData.as_view(),
name='edx_notifications.admin.delete_users_data'
),

)

Expand Down
6 changes: 6 additions & 0 deletions edx_notifications/server/api/urls_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
CONSUMER_NOTIFICATIONS_PREFERENCES_REGEX,
CONSUMER_USER_PREFERENCES_REGEX,
CONSUMER_USER_PREFERENCES_DETAIL_NO_PARAM_REGEX,
ADMIN_USERS_DELETE
)


Expand Down Expand Up @@ -79,4 +80,9 @@ def mock_handler(request): # pylint: disable=unused-argument
mock_handler,
name='edx_notifications.consumer.user_preferences.detail.no_param'
),
url(
ADMIN_USERS_DELETE,
mock_handler,
name='edx_notifications.admin.delete_user_notifications'
),
)
22 changes: 21 additions & 1 deletion edx_notifications/stores/sql/store_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
SQLNotificationType,
SQLUserNotification,
SQLNotificationCallbackTimer,
SQLNotificationPreference, SQLUserNotificationPreferences)
SQLNotificationPreference,
SQLUserNotificationPreferences,
SQLUserNotificationArchive
)


class SQLNotificationStoreProvider(BaseNotificationStoreProvider):
Expand Down Expand Up @@ -554,3 +557,20 @@ def get_all_namespaces(self, start_datetime=None, end_datetime=None):
result_set = result_set.values_list('namespace', flat=True).order_by('namespace').distinct()

return result_set

def purge_notifications_for_users(self, user_ids):
"""
This will remove all notifications and preferences for given user IDs
"""
user_notifications = SQLUserNotification.objects.filter(user_id__in=user_ids)
archived_notifications = SQLUserNotificationArchive.objects.filter(user_id__in=user_ids)
SQLNotificationMessage.objects.filter(id__in=user_notifications.values('msg_id')).delete()
SQLNotificationMessage.objects.filter(id__in=archived_notifications.values('msg_id')).delete()
SQLUserNotificationArchive.objects.filter(user_id__in=user_ids).delete()
SQLUserNotificationPreferences.objects.filter(user_id__in=user_ids).delete()

def purge_notifications_containing(self, payload):
"""
This will remove all notifications which contains the given payload
"""
SQLNotificationMessage.objects.filter(payload__contains=payload).delete()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def load_requirements(*requirements_paths):

setup(
name='edx-notifications',
version='0.8.3',
version='0.9.0',
description='Notification subsystem for Open edX',
long_description=open('README.md').read(),
author='edX',
Expand Down

0 comments on commit 7ab4307

Please sign in to comment.