Gitlab CSE Unil

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

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

Julien Furrer's avatar
Julien Furrer committed
20
21
22
23
24
from rest_framework.views import APIView
from rest_framework.parsers import FileUploadParser


class AnObjViewSet(viewsets.ModelViewSet):
25
26
27
    """
    Viewset for owned AnObj, requested by user who is the owner.
    """
Julien Furrer's avatar
Julien Furrer committed
28
29
    model = AnObj
    serializer_class = AnObjSerializer
30
    # lookup_field = 'uuid'
Julien Furrer's avatar
Julien Furrer committed
31

32
33
34
35
36
37
38
39
40
    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
41
42

    def get_queryset(self):
43
44
45
46
47
        """
        Return only owner's anobjs for write actions and
        return also shared anobjs to guests for read actions
        """
        user = self.request.user
48
49
        # q = Q(owner=user)
        q = Q(owners=user)
50
51
52
        if self.action == 'list':
            q = q | Q(members=user)

53
        return AnObj.objects.filter(q).distinct()
54

55
    @detail_route(methods=['get', 'patch', 'post', 'delete'])
56
57
58
    def members(self, request, pk=None):
        anobj = self.get_object()

59
        if request.method != 'GET':
60
            user_model = get_user_model()
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
            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)
89
90
91

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

92
93
94
95
96
97
98
99
100
101
102
103
    @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:
104
105
106
            # if user == anobj.owner:
            # if user in anobj.owners.all():
            if anobj.is_owned(user.id):
107
108
109
110
111
                membership = AnObjMembership.objects.create(anobj=anobj, user=user, publish_mode=new_publish_mode)
            else:
                raise Http404()

        if new_publish_mode == 2 and not (
112
113
                anobj.allow_public_publishing or anobj.is_owned(user.id)):
                # anobj.allow_public_publishing or user in anobj.owners.all()):
114
115
116
117
118
119
120
121
            raise PermissionDenied

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

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

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

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
148
149
        # q = Q(owner=user)
        q = Q(owners=user)
150
        if self.action in ('list', 'retrieve', 'members'):
151
152
            q = q | Q(members=user)

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

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
    @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})
    #
184

185

186
187
188
189
190
191
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>
    """
192
    model = get_user_model()
193
194
195
196
197
198
199
200
201
202
203
204
    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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220


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

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

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

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

        else:
239
240
241
242
243
244
245
246
            # 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
247
                raise Exception("Annotable access forbidden")
248
            # if not AnObj.objects.filter(anobj_q).exists():
Julien Furrer's avatar
Julien Furrer committed
249
250
251

            obj.owner = self.request.user

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


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

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

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

266
267
        anots = anobj.annotations.filter(owner__anobjmembership__publish_mode__gte=<publish_level>, owner__anobjmembership__anobj=anobj).select_related('owner')
        """
268
        anobj = get_object_or_404(AnObj, pk=self.kwargs.get('anobjs_pk', -1))
269
270
        # 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
271
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)

279