Skip to content

Commit

Permalink
Add timestamp filter for the Messaging ViewSet (#1973)
Browse files Browse the repository at this point in the history
* Add timestamp as a filter field
* Support datetime lookups on the timestamp filter
* Add messaging routes to the API router
* Add support for hour and minute datetime lookup
  • Loading branch information
DavisRayM authored Dec 18, 2020
1 parent 853883b commit 0af9d5f
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 8 deletions.
2 changes: 1 addition & 1 deletion onadata/apps/api/tests/viewsets/test_ona_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ def test_number_of_viewsets(self):
request = self.factory.get(path)
request.resolver_match = resolve(path)
response = view(request)
self.assertEquals(len(response.data), 28)
self.assertEquals(len(response.data), 29)
2 changes: 2 additions & 0 deletions onadata/apps/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from onadata.apps.api.viewsets.xform_submission_viewset import \
XFormSubmissionViewSet
from onadata.apps.api.viewsets.xform_viewset import XFormViewSet
from onadata.apps.messaging.viewsets import MessagingViewSet
from onadata.apps.restservice.viewsets.restservices_viewset import \
RestServicesViewSet

Expand Down Expand Up @@ -128,6 +129,7 @@ def get_urls(self):
router.register(r'media', AttachmentViewSet, basename='attachment')
router.register(
r'merged-datasets', MergedXFormViewSet, basename='merged-xform')
router.register(r'messaging', MessagingViewSet, basename="messaging")
router.register(r'metadata', MetaDataViewSet, basename='metadata')
router.register(r'notes', NoteViewSet)
router.register(r'open-data', OpenDataViewSet, basename='open-data')
Expand Down
3 changes: 0 additions & 3 deletions onadata/apps/main/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,6 @@
re_path(r'^static/(?P<path>.*)$', staticfiles_views.serve)
]

# messaging urls
urlpatterns.append(url('^', include('onadata.apps.messaging.urls')))

CUSTOM_URLS = getattr(settings, 'CUSTOM_MAIN_URLS', None)

if CUSTOM_URLS:
Expand Down
45 changes: 45 additions & 0 deletions onadata/apps/messaging/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,59 @@
Messaging viewset filters module.
"""
from __future__ import unicode_literals
from actstream.models import Action

from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from rest_framework import exceptions, filters
from django_filters import rest_framework as rest_filters

from onadata.apps.messaging.utils import TargetDoesNotExist, get_target


DATETIME_LOOKUPS = [
"exact",
"gt",
"lt",
"gte",
"lte",
"year",
"year__gt",
"year__lt",
"year__gte",
"year__lte",
"month",
"month__gt",
"month__lt",
"month__gte",
"month__lte",
"day",
"day__gt",
"day__lt",
"day__gte",
"day__lte",
"hour",
"hour__gt",
"hour__lt",
"hour__gte",
"hour__lte",
"minute",
"minute__gt",
"minute__lt",
"minute__gte",
"minute__lte",
]


class ActionFilterSet(rest_filters.FilterSet):
class Meta:
model = Action
fields = {
"verb": ["exact"],
"timestamp": DATETIME_LOOKUPS
}


class TargetTypeFilterBackend(filters.BaseFilterBackend):
"""
A filter backend that filters by target type.
Expand Down
273 changes: 273 additions & 0 deletions onadata/apps/messaging/tests/test_messaging_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,276 @@ def test_retrieve_permissions(self):
force_authenticate(request, user=user)
response = view(request=request, pk=message_data['id'])
self.assertEqual(response.status_code, 200)

@override_settings(USE_TZ=False)
def test_messaging_timestamp_filter(self):
"""
Test that a user is able to filter messages using the timestamp
"""
user = _create_user()
message_one = self._create_message(user)
message_two = self._create_message(user)

view = MessagingViewSet.as_view({'get': 'list'})
message_one_timestamp = message_one['timestamp']
target_id = user.id
request = self.factory.get(
f'/messaging?timestamp={message_one_timestamp}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)

self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
self.assertEqual(
response.data[0].get('id'), message_one['id'])

# Test able to filter using gt & gte lookups
request = self.factory.get(
f'/messaging?timestamp__gt={message_one_timestamp}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
self.assertEqual(
response.data[0].get('id'), message_two['id'])

request = self.factory.get(
f'/messaging?timestamp__gte={message_one_timestamp}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

# Test able to filter using lt & lte lookups
message_two_timestamp = message_two['timestamp']
request = self.factory.get(
f'/messaging?timestamp__lt={message_two_timestamp}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
self.assertEqual(
response.data[0].get('id'), message_one['id'])

message_two_timestamp = message_two['timestamp']
request = self.factory.get(
f'/messaging?timestamp__lte={message_two_timestamp}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

# Test able to use day filters
day = Action.objects.get(
id=message_one['id']).timestamp.day

request = self.factory.get(
f'/messaging?timestamp__day={day}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__day__gt={day}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__day__gte={day}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__day__lt={day}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__day__lte={day}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

# Test able to use month filters
month = Action.objects.get(
id=message_one['id']).timestamp.month

request = self.factory.get(
f'/messaging?timestamp__month={month}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__month__gt={month}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__month__gte={month}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__month__lt={month}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__month__lte={month}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

# Test able to use year filters
year = Action.objects.get(
id=message_one['id']).timestamp.year

request = self.factory.get(
f'/messaging?timestamp__year={year}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__year__gt={year}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__year__gte={year}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__year__lt={year}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__year__lte={year}&'
f'target_type=user&target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

# Test able to use hour & minute filters
hour = Action.objects.get(
id=message_one['id']).timestamp.hour
minute = Action.objects.get(
id=message_one['id']).timestamp.minute

request = self.factory.get(
f'/messaging?timestamp__hour={hour}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__hour__lt={hour}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__hour__gt={hour}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__hour__lte={hour}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__hour__gte={hour}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__minute__gt={minute}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__minute__lt={minute}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

request = self.factory.get(
f'/messaging?timestamp__minute__gte={minute}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

request = self.factory.get(
f'/messaging?timestamp__minute__lte={minute}&target_type=user&'
f'target_id={target_id}')
force_authenticate(request, user=user)
response = view(request=request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
8 changes: 4 additions & 4 deletions onadata/apps/messaging/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from rest_framework.permissions import IsAuthenticated

from onadata.apps.messaging.constants import MESSAGE_VERBS
from onadata.apps.messaging.filters import (TargetIDFilterBackend,
TargetTypeFilterBackend,
UserFilterBackend)
from onadata.apps.messaging.filters import (
ActionFilterSet, TargetIDFilterBackend, TargetTypeFilterBackend,
UserFilterBackend)
from onadata.apps.messaging.permissions import TargetObjectPermissions
from onadata.apps.messaging.serializers import MessageSerializer

Expand All @@ -30,4 +30,4 @@ class MessagingViewSet(mixins.CreateModelMixin, mixins.ListModelMixin,
permission_classes = [IsAuthenticated, TargetObjectPermissions]
filter_backends = (TargetTypeFilterBackend, TargetIDFilterBackend,
UserFilterBackend, DjangoFilterBackend)
filter_fields = ['verb']
filterset_class = ActionFilterSet

0 comments on commit 0af9d5f

Please sign in to comment.