1
+ import json
2
+ import datetime
3
+
4
+ from pywebpush import webpush , WebPushException
5
+
1
6
from django .db .models import Q , ProtectedError , Prefetch
2
- from django .contrib .auth import authenticate
3
7
from django .conf import settings
8
+ from django .contrib .auth import authenticate
4
9
from django .db import IntegrityError
10
+ from django .utils import timezone
5
11
6
12
from rest_framework import viewsets , mixins , filters , status
7
13
from rest_framework .response import Response
8
14
from rest_framework .permissions import (
9
15
AllowAny , IsAuthenticated , DjangoModelPermissions )
10
16
from rest_framework .decorators import (
11
- detail_route , api_view , authentication_classes , permission_classes )
17
+ list_route , detail_route , api_view , authentication_classes , permission_classes )
12
18
from rest_framework .generics import get_object_or_404
13
19
from rest_framework .exceptions import APIException , NotFound
14
20
from rest_framework .authtoken .models import Token
20
26
from dispatch .models import (
21
27
Article , File , Image , ImageAttachment , ImageGallery , Issue ,
22
28
Page , Author , Person , Section , Tag , Topic , User , Video ,
23
- Poll , PollAnswer , PollVote , Invite )
29
+ Poll , PollAnswer , PollVote , Invite , Notification , Subscription ,
30
+ SubscriptionCount )
24
31
25
32
from dispatch .core .settings import get_settings
26
33
from dispatch .admin .registration import reset_password
31
38
FileSerializer , IssueSerializer , ImageGallerySerializer , TagSerializer ,
32
39
TopicSerializer , PersonSerializer , UserSerializer , IntegrationSerializer ,
33
40
ZoneSerializer , WidgetSerializer , TemplateSerializer , VideoSerializer ,
34
- PollSerializer , PollVoteSerializer , InviteSerializer )
41
+ PollSerializer , PollVoteSerializer , NotificationSerializer , InviteSerializer ,
42
+ SubscriptionSerializer , SubscriptionCountSerializer )
35
43
from dispatch .api .exceptions import (
36
44
ProtectedResourceError , BadCredentials , PollClosed , InvalidPoll ,
37
- UnpermittedActionError )
45
+ UnpermittedActionError , AlreadySubscribed )
38
46
39
47
from dispatch .theme import ThemeManager
40
48
from dispatch .theme .exceptions import ZoneNotFound , TemplateNotFound
@@ -87,7 +95,7 @@ def get_queryset(self):
87
95
'authors'
88
96
)
89
97
90
- queryset = queryset .order_by ('-updated_at' )
98
+ queryset = queryset .order_by ('-updated_at' )
91
99
92
100
q = self .request .query_params .get ('q' , None )
93
101
section = self .request .query_params .get ('section' , None )
@@ -99,7 +107,7 @@ def get_queryset(self):
99
107
100
108
if section is not None :
101
109
queryset = queryset .filter (section_id = section )
102
-
110
+
103
111
if tags is not None :
104
112
for tag in tags :
105
113
queryset = queryset .filter (tags__id = tag )
@@ -387,6 +395,78 @@ def vote(self, request, pk=None):
387
395
388
396
return Response (serializer .data )
389
397
398
+ class SubscriptionCountViewSet (DispatchModelViewSet ):
399
+ """Viewset for the SubscriptionCount model views."""
400
+
401
+ model = SubscriptionCount
402
+ serializer_class = SubscriptionCountSerializer
403
+ queryset = SubscriptionCount .objects .filter (date__gte = timezone .now () - datetime .timedelta (days = 90 )).order_by ('-date' )
404
+
405
+ def get_permissions (self ):
406
+ """
407
+ Instantiates and returns the list of permissions that this view requires.
408
+ """
409
+ if self .action == 'create' :
410
+ permission_classes = [AllowAny ,]
411
+ else :
412
+ permission_classes = [IsAuthenticated ,]
413
+ return [permission () for permission in permission_classes ]
414
+
415
+ def create (self , request ):
416
+ try :
417
+ subscription_count = Subscription .objects .all ().count ()
418
+ data = {
419
+ 'count' : subscription_count
420
+ }
421
+ serializer = SubscriptionCountSerializer (data = data )
422
+ serializer .is_valid (raise_exception = True )
423
+ serializer .save ()
424
+
425
+ return Response ({ 'detail' : 'Subscriber count recorded' })
426
+ except :
427
+ return Response ({ 'detail' : 'Subscriber count for today has already been created' }, status .HTTP_400_BAD_REQUEST )
428
+
429
+ class NotificationsViewSet (DispatchModelViewSet ):
430
+ """Viewset for the Poll model views."""
431
+
432
+ model = Notification
433
+ serializer_class = NotificationSerializer
434
+ permission_classes = (IsAuthenticated ,)
435
+ queryset = Notification .objects .all ().order_by ('scheduled_push_time' )
436
+
437
+ @detail_route (permission_classes = [AllowAny ], methods = ['post' , 'patch' ],)
438
+ def subscribe (self , request , pk = None ):
439
+ data = {
440
+ 'endpoint' : request .data ['endpoint' ],
441
+ 'auth' : request .data ['keys' ]['auth' ],
442
+ 'p256dh' : request .data ['keys' ]['p256dh' ],
443
+ }
444
+
445
+ try :
446
+ serializer = SubscriptionSerializer (data = data )
447
+ serializer .is_valid (raise_exception = True )
448
+ serializer .save ()
449
+ return Response (serializer .data )
450
+ except :
451
+ raise AlreadySubscribed ()
452
+
453
+ return Response (serializer .data )
454
+
455
+ @list_route (permission_classes = [AllowAny ], methods = ['post' ],)
456
+ def push (self , request ):
457
+ notification = Notification .objects \
458
+ .filter (scheduled_push_time__lte = timezone .now ()) \
459
+ .order_by ('scheduled_push_time' ) \
460
+ .first ()
461
+
462
+ if notification is not None :
463
+ article = Article .objects .get (parent__id = notification .article .parent_id , is_published = True )
464
+ if article is not None :
465
+ DispatchPublishableMixin .push_notification (article )
466
+ notification .delete ()
467
+
468
+ return Response (status = status .HTTP_200_OK )
469
+
390
470
class TemplateViewSet (viewsets .GenericViewSet ):
391
471
"""Viewset for Template views."""
392
472
permission_classes = (IsAuthenticated ,)
0 commit comments