Gitlab CSE Unil

views.py 9.49 KB
Newer Older
Julien Furrer's avatar
Julien Furrer committed
1
2
# coding=utf-8
from __future__ import unicode_literals
3
from django.contrib.auth import get_user_model
4
from django.core.exceptions import PermissionDenied
Julien Furrer's avatar
Julien Furrer committed
5
from django.http.response import Http404
6
from django.db.models import Q
7
from django.shortcuts import get_object_or_404
Julien Furrer's avatar
Julien Furrer committed
8

9
from adim.models import AnObj, AnObjMembership, Annotation
10
11
12
from adim.serializers import AnObjSerializer, SharedAnObjSerializer, AnObjListSerializer, \
    AnnotationSerializer, UserSerializer
from adim.permissions import has_anobj_access
Julien Furrer's avatar
Julien Furrer committed
13
from rest_framework import viewsets
14
from rest_framework.response import Response
Julien Furrer's avatar
Julien Furrer committed
15
from rest_framework.decorators import detail_route
Julien Furrer's avatar
Julien Furrer committed
16
17
18


class AnObjViewSet(viewsets.ModelViewSet):
19
20
21
    """
    Viewset for owned AnObj, requested by user who is the owner.
    """
Julien Furrer's avatar
Julien Furrer committed
22
23
    model = AnObj
    serializer_class = AnObjSerializer
24
    # lookup_field = 'uuid'
Julien Furrer's avatar
Julien Furrer committed
25

26
27
28
29
30
31
32
33
34
    def get_serializer_class(self):
        """
        Use a simplified serializer for listing and
        the complete one for other actions
        """
        if self.action == 'list':
            return AnObjListSerializer
        else:
            return self.serializer_class
Julien Furrer's avatar
Julien Furrer committed
35
36

    def get_queryset(self):
37
38
39
40
41
        """
        Return only owner's anobjs for write actions and
        return also shared anobjs to guests for read actions
        """
        user = self.request.user
42
43
        # q = Q(owner=user)
        q = Q(owners=user)
44
45
46
        if self.action == 'list':
            q = q | Q(members=user)

47
        return AnObj.objects.filter(q).distinct()
48

49
    @detail_route(methods=['get', 'patch', 'post', 'delete'])
50
51
52
    def members(self, request, pk=None):
        anobj = self.get_object()

53
        if request.method != 'GET':
54
            user_model = get_user_model()
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
            members = []
            for member_data in request.DATA.get('members', []):
                try:
                    q = Q(pk=-1)
                    if member_data.get('id'):
                        q = Q(pk=member_data.get('id'))
                    elif member_data.get('username'):
                        q = Q(username=member_data.get('username'))
                    members.append(user_model.objects.get(q))

                except user_model.DoesNotExist:
                    if member_data.get('username'):
                        opts_members = anobj.sharing_opts.get('members', [])

                        if request.method in ('PATCH', 'POST'):
                            opts_members.append(member_data.get('username'))
                        elif request.method == 'DELETE':
                            opts_members.remove(member_data.get('username'))

                        anobj.sharing_opts['members'] = opts_members
                        anobj.save()

            if request.method in ('PATCH', 'POST'):
                # anobj.members.add(*members)
                anobj.add_members(*members)
            elif request.method == 'DELETE':
                # anobj.members.remove(*members)
                anobj.remove_members(*members)
83
84
85

        return Response({'users': UserSerializer(instance=anobj.members.all(), many=True).data})

86
87
88
89
90
91
92
93
94
95
96
97
    @detail_route(methods=['patch'])
    def set_publish_mode(self, request, pk=None):
        user = request.user
        anobj = AnObj.objects.get(pk=pk)
        new_publish_mode = int(request.DATA.get('publish_mode', 0))
        if new_publish_mode not in xrange(3):
            raise ValueError("Invalid publish mode")

        # membership = get_object_or_404(AnObjMembership, anobj__id=pk, user=user)
        try:
            membership = AnObjMembership.objects.get(anobj=anobj, user=user)
        except AnObjMembership.DoesNotExist:
98
99
100
            # if user == anobj.owner:
            # if user in anobj.owners.all():
            if anobj.is_owned(user.id):
101
102
103
104
105
                membership = AnObjMembership.objects.create(anobj=anobj, user=user, publish_mode=new_publish_mode)
            else:
                raise Http404()

        if new_publish_mode == 2 and not (
106
107
                anobj.allow_public_publishing or anobj.is_owned(user.id)):
                # anobj.allow_public_publishing or user in anobj.owners.all()):
108
109
110
111
112
113
114
115
            raise PermissionDenied

        if membership.publish_mode != new_publish_mode:
            membership.publish_mode = new_publish_mode
            membership.save()

        return Response({'publish_mode': membership.publish_mode})

116

117
118
119
120
121
122
123
class UAnObjViewSet(AnObjViewSet):
    """
    Accessing AnObj by uuid. extents AnObj
    """
    lookup_field = 'uuid'


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
class SharedAnObjViewSet(AnObjViewSet):
    """
    ViewSet for shared AnObj, requested by a user
    who is not the owner but a member.
    """
    serializer_class = SharedAnObjSerializer

    def get_serializer_class(self):
        """
        Use a simplified serializer for listing and
        the complete one for other actions
        """
        if self.action == 'list':
            return AnObjListSerializer
        else:
            return self.serializer_class

    def get_queryset(self):
        """
        Return only owner's anobjs for write actions and
        return also shared anobjs to guests for read actions
        """
        # return AnObj.objects.filter(members=self.request.user)

        user = self.request.user
149
150
        # q = Q(owner=user)
        q = Q(owners=user)
151
        if self.action in ('list', 'retrieve', 'members'):
152
153
            q = q | Q(members=user)

154
        return AnObj.objects.filter(q).distinct()
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    @detail_route(methods=['get'])
    def members(self, request, pk=None):
        anobj = self.get_object()
        if anobj.allow_public_publishing:
            users = UserSerializer(instance=anobj.members.all(), many=True).data
        else:
            users = []
        return Response({'users': users})
    #
    # @detail_route(methods=['patch'])
    # def set_publish_mode(self, request, pk=None):
    #     user = request.user
    #     anobj = AnObj.objects.get(pk=pk)
    #     membership = get_object_or_404(AnObjMembership, anobj__id=pk, user=user)
    #
    #     new_publish_mode = int(request.DATA.get('publish_mode', 0))
    #     if new_publish_mode not in xrange(3):
    #         raise ValueError("Invalid publish mode")
    #
    #     if new_publish_mode == 2 and not (
    #             anobj.allow_public_publishing or user == anobj.owner):
    #         raise PermissionDenied
    #
    #     if membership.publish_mode != new_publish_mode:
    #         membership.publish_mode = new_publish_mode
    #         membership.save()
    #
    #     return Response({'publish_mode': membership.publish_mode})
    #
185

186

187
188
189
190
191
192
class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    List of registered users for an AnObj.
    The anobj uuid is given as a querystring variable
    ?uuid=<the-uuid-value-for-the-anobj>
    """
193
    model = get_user_model()
194
195
196
197
198
199
200
201
202
203
204
205
    serializer_class = UserSerializer

    def get_queryset(self):
        uuid = self.request.GET.get('uuid', "")
        q = Q(anobjs__uuid=uuid) | Q(shared_anobjs__uuid=uuid)
        return self.model.objects.filter(q)
        # try:
        #
        #     anobj = AnObj.objects.get(uuid=self.request.GET.get('uuid', ""))
        #     return self.model.objects.filter(pk=anobj.owner_id)
        # except AnObj.DoesNotExist:
        #     return []
Julien Furrer's avatar
Julien Furrer committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221


class AnnotationViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allow annotations to be viewed or edited
    """
    model = Annotation
    serializer_class = AnnotationSerializer

    def get_queryset(self):
        if self.request.user.has_perm('adim.can_review_exercise'):
            queryset = Annotation.objects.all()
        else:
            queryset = Annotation.objects.filter(owner=self.request.user)
        return queryset

222
223
    # def list(self, request):
    #     return Response([])
224

Julien Furrer's avatar
Julien Furrer committed
225
226
227
228
229
230
231
    def pre_save(self, obj):
        """
        For new annotation, check annotable access permission
        and set the owner of the annotation
        :param obj:
        :return:
        """
232
        # if not obj.annotable.locked:
Julien Furrer's avatar
Julien Furrer committed
233
234
        #     raise Exception("Annotable locked")

235
236
237
238
239
        if obj.id:
            if obj.owner != self.request.user:
                raise Exception("Annotable access forbidden")

        else:
240
241
242
243
244
245
246
247
            # user = self.request.user
            # anobj_q = Q(pk=obj.annotable_id) & (Q(owner=user) | Q(members=user))
            try:
                anobj = AnObj.objects.get(pk=obj.annotable_id)
                if not has_anobj_access(self.request, anobj):
                    raise Exception("Annotable access forbidden")

            except AnObj.DoesNotExist:
Julien Furrer's avatar
Julien Furrer committed
248
                raise Exception("Annotable access forbidden")
249
            # if not AnObj.objects.filter(anobj_q).exists():
Julien Furrer's avatar
Julien Furrer committed
250
251
252

            obj.owner = self.request.user

253
254
255
        super(AnnotationViewSet, self).pre_save(obj)


256
class SharedAnnotationViewSet(viewsets.ReadOnlyModelViewSet):
257
258
259
    """

    """
260
261
    model = Annotation
    serializer_class = AnnotationSerializer
262

263
264
    def get_queryset(self):
        """
265
266
        Return the shared annotations for this anobj

267
268
        anots = anobj.annotations.filter(owner__anobjmembership__publish_mode__gte=<publish_level>, owner__anobjmembership__anobj=anobj).select_related('owner')
        """
269
        anobj = get_object_or_404(AnObj, pk=self.kwargs.get('anobjs_pk', -1))
270
271
        # publish_level = 1 if self.request.user in anobj.owners.all() else 2
        publish_level = 1 if anobj.is_owned(self.request.user.id) else 2
272
273
274
275
276
277
278

        q = (
            Q(annotable=anobj) &
            Q(owner__anobjmembership__publish_mode__gte=publish_level) &
            Q(owner__anobjmembership__anobj=anobj)
        )
        return Annotation.objects.filter(q).exclude(owner=self.request.user)