views.py 4.35 KB
Newer Older
1 2
from django.contrib.auth import get_user_model
from django.db import transaction
3
from django_filters.rest_framework import DjangoFilterBackend
4 5
from edx_rest_framework_extensions.authentication import JwtAuthentication
from rest_framework import permissions, viewsets
6 7
from rest_framework.decorators import list_route
from rest_framework.response import Response
8

9 10 11
from experiments import filters, serializers
from experiments.models import ExperimentData, ExperimentKeyValue
from experiments.permissions import IsStaffOrOwner, IsStaffOrReadOnly
12 13
from openedx.core.lib.api.authentication import SessionAuthenticationAllowInactiveUser

14 15
User = get_user_model()  # pylint: disable=invalid-name

16 17 18 19 20 21 22

class ExperimentDataViewSet(viewsets.ModelViewSet):
    authentication_classes = (JwtAuthentication, SessionAuthenticationAllowInactiveUser,)
    filter_backends = (DjangoFilterBackend,)
    filter_class = filters.ExperimentDataFilter
    permission_classes = (permissions.IsAuthenticated, IsStaffOrOwner,)
    queryset = ExperimentData.objects.all()
23
    serializer_class = serializers.ExperimentDataSerializer
24
    _cached_users = {}
25 26 27 28 29

    def filter_queryset(self, queryset):
        queryset = queryset.filter(user=self.request.user)
        return super(ExperimentDataViewSet, self).filter_queryset(queryset)

30 31
    def get_serializer_class(self):
        if self.action == 'create':
32 33
            return serializers.ExperimentDataCreateSerializer
        return serializers.ExperimentDataSerializer
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
    def create_or_update(self, request, *args, **kwargs):
        # If we have a primary key, treat this as a regular update request
        if self.kwargs.get('pk'):
            return self.update(request, *args, **kwargs)

        # If we only have data, check to see if an instance exists in the database. If so, update it.
        # Otherwise, create a new instance.
        experiment_id = request.data.get('experiment_id')
        key = request.data.get('key')

        if experiment_id and key:
            try:
                obj = self.get_queryset().get(user=self.request.user, experiment_id=experiment_id, key=key)
                self.kwargs['pk'] = obj.pk
                self.request.data['id'] = obj.pk
                return self.update(request, *args, **kwargs)
            except ExperimentData.DoesNotExist:
                pass

54
        self.action = 'create'
55
        return self.create(request, *args, **kwargs)
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 83

    def _cache_users(self, usernames):
        users = User.objects.filter(username__in=usernames)
        self._cached_users = {user.username: user for user in users}

    def _get_user(self, username):
        user = self._cached_users.get(username)

        if not user:
            user = User.objects.get(username=username)
            self._cached_users[username] = user

        return user

    @list_route(methods=['put'], permission_classes=[permissions.IsAdminUser])
    def bulk_upsert(self, request):
        upserted = []
        self._cache_users([datum['user'] for datum in request.data])

        with transaction.atomic():
            for item in request.data:
                user = self._get_user(username=item['user'])
                datum, __ = ExperimentData.objects.update_or_create(
                    user=user, experiment_id=item['experiment_id'], key=item['key'], defaults={'value': item['value']})
                upserted.append(datum)

            serializer = self.get_serializer(upserted, many=True)
            return Response(serializer.data)
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105


class ExperimentKeyValueViewSet(viewsets.ModelViewSet):
    authentication_classes = (JwtAuthentication, SessionAuthenticationAllowInactiveUser,)
    filter_backends = (DjangoFilterBackend,)
    filter_class = filters.ExperimentKeyValueFilter
    permission_classes = (IsStaffOrReadOnly,)
    queryset = ExperimentKeyValue.objects.all()
    serializer_class = serializers.ExperimentKeyValueSerializer

    @list_route(methods=['put'], permission_classes=[permissions.IsAdminUser])
    def bulk_upsert(self, request):
        upserted = []

        with transaction.atomic():
            for item in request.data:
                datum, __ = ExperimentKeyValue.objects.update_or_create(
                    experiment_id=item['experiment_id'], key=item['key'], defaults={'value': item['value']})
                upserted.append(datum)

            serializer = self.get_serializer(upserted, many=True)
            return Response(serializer.data)