1
+ from django .db .models import Value , When , Case , F , Q , OuterRef , Subquery
2
+ from django .db .models .fields import CharField , IntegerField
3
+ from django .db .models .functions import Concat , Cast
1
4
from pyasn1_modules .rfc5126 import ContentType
2
5
from rest_framework import generics
3
6
from rest_framework import permissions as drf_permissions
4
7
from rest_framework .exceptions import NotFound
5
- from django .core .exceptions import ObjectDoesNotExist
8
+ from django .core .exceptions import ObjectDoesNotExist , PermissionDenied
6
9
7
10
from framework .auth .oauth_scopes import CoreScopes
8
11
from api .base .views import JSONAPIBaseView
19
22
CollectionProvider ,
20
23
PreprintProvider ,
21
24
RegistrationProvider ,
22
- AbstractProvider ,
25
+ AbstractProvider , AbstractNode , Preprint , OSFUser ,
23
26
)
24
- from osf .models .notification import NotificationSubscription
27
+ from osf .models .notification import NotificationSubscription , NotificationType
25
28
26
29
27
30
class SubscriptionList (JSONAPIBaseView , generics .ListAPIView , ListFilterMixin ):
@@ -38,8 +41,48 @@ class SubscriptionList(JSONAPIBaseView, generics.ListAPIView, ListFilterMixin):
38
41
required_write_scopes = [CoreScopes .NULL ]
39
42
40
43
def get_queryset (self ):
41
- return NotificationSubscription .objects .filter (
42
- user = self .request .user ,
44
+ user_guid = self .request .user ._id
45
+ from django .contrib .contenttypes .models import ContentType
46
+ provider_ct = ContentType .objects .get (app_label = 'osf' , model = 'abstractprovider' )
47
+
48
+ provider_subquery = AbstractProvider .objects .filter (
49
+ id = Cast (OuterRef ('object_id' ), IntegerField ()),
50
+ ).values ('_id' )[:1 ]
51
+
52
+ node_subquery = AbstractNode .objects .filter (
53
+ id = Cast (OuterRef ('object_id' ), IntegerField ()),
54
+ ).values ('guids___id' )[:1 ]
55
+
56
+ return NotificationSubscription .objects .filter (user = self .request .user ).annotate (
57
+ event_name = Case (
58
+ When (
59
+ notification_type__name = NotificationType .Type .NODE_FILES_UPDATED .value ,
60
+ then = Value ('files_updated' ),
61
+ ),
62
+ When (
63
+ notification_type__name = NotificationType .Type .USER_FILE_UPDATED .value ,
64
+ then = Value ('global_file_updated' ),
65
+ ),
66
+ default = F ('notification_type__name' ),
67
+ output_field = CharField (),
68
+ ),
69
+ legacy_id = Case (
70
+ When (
71
+ notification_type__name = NotificationType .Type .NODE_FILES_UPDATED .value ,
72
+ then = Concat (Subquery (node_subquery ), Value ('_file_updated' )),
73
+ ),
74
+ When (
75
+ notification_type__name = NotificationType .Type .USER_FILE_UPDATED .value ,
76
+ then = Value (f'{ user_guid } _global' ),
77
+ ),
78
+ When (
79
+ Q (notification_type__name = NotificationType .Type .PROVIDER_NEW_PENDING_SUBMISSIONS .value ) &
80
+ Q (content_type = provider_ct ),
81
+ then = Concat (Subquery (provider_subquery ), Value ('_new_pending_submissions' )),
82
+ ),
83
+ default = F ('notification_type__name' ),
84
+ output_field = CharField (),
85
+ ),
43
86
)
44
87
45
88
@@ -67,13 +110,72 @@ class SubscriptionDetail(JSONAPIBaseView, generics.RetrieveUpdateAPIView):
67
110
68
111
def get_object (self ):
69
112
subscription_id = self .kwargs ['subscription_id' ]
113
+ user = self .request .user
114
+
115
+ provider_ct = ContentType .objects .get (app_label = 'osf' , model = 'abstractprovider' )
116
+ node_ct = ContentType .objects .get (app_label = 'osf' , model = 'abstractnode' )
117
+
118
+ provider_subquery = AbstractProvider .objects .filter (
119
+ id = Cast (OuterRef ('object_id' ), IntegerField ()),
120
+ ).values ('_id' )[:1 ]
121
+
122
+ node_subquery = AbstractNode .objects .filter (
123
+ id = Cast (OuterRef ('object_id' ), IntegerField ()),
124
+ ).values ('guids___id' )[:1 ]
125
+
126
+ guid_id , * event_parts = subscription_id .split ('_' )
127
+ event = '_' .join (event_parts )
128
+
129
+ subscription_obj = AbstractNode .load (guid_id ) or Preprint .load (guid_id ) or OSFUser .load (guid_id )
130
+
131
+ if event == 'global' :
132
+ object_filter = Q (
133
+ Q (content_type = ContentType .objects .get_for_model (OSFUser ), object_id = user .id ) |
134
+ Q (content_type__isnull = True , object_id__isnull = True ),
135
+ notification_type__name = NotificationType .Type .USER_FILE_UPDATED .value ,
136
+ )
137
+ else :
138
+ if not subscription_obj :
139
+ raise NotFound
140
+
141
+ object_filter = Q (
142
+ object_id = subscription_obj .id ,
143
+ content_type = ContentType .objects .get_for_model (subscription_obj .__class__ ),
144
+ notification_type__name__icontains = event ,
145
+ )
146
+
147
+ subscription_qs = NotificationSubscription .objects .annotate (
148
+ legacy_id = Case (
149
+ When (
150
+ notification_type__name = NotificationType .Type .NODE_FILES_UPDATED .value ,
151
+ content_type = node_ct ,
152
+ then = Concat (Subquery (node_subquery ), Value ('_file_updated' )),
153
+ ),
154
+ When (
155
+ notification_type__name = NotificationType .Type .USER_FILE_UPDATED .value ,
156
+ then = Value (f'{ user ._id } _global' ),
157
+ ),
158
+ When (
159
+ notification_type__name = NotificationType .Type .PROVIDER_NEW_PENDING_SUBMISSIONS .value ,
160
+ content_type = provider_ct ,
161
+ then = Concat (Subquery (provider_subquery ), Value ('_new_pending_submissions' )),
162
+ ),
163
+ default = F ('notification_type__name' ),
164
+ output_field = CharField (),
165
+ ),
166
+ ).filter (object_filter )
167
+
70
168
try :
71
- obj = NotificationSubscription . objects . get (id = subscription_id )
169
+ subscription = subscription_qs . get ()
72
170
except ObjectDoesNotExist :
73
171
raise NotFound
74
- self .check_object_permissions (self .request , obj )
75
- return obj
76
172
173
+ if subscription .user != user :
174
+ raise PermissionDenied
175
+
176
+ self .check_object_permissions (self .request , subscription )
177
+
178
+ return subscription
77
179
78
180
class AbstractProviderSubscriptionDetail (SubscriptionDetail ):
79
181
view_name = 'provider-notification-subscription-detail'
0 commit comments