diff --git a/backend/core/custom_annotations.py b/backend/core/custom_annotations.py index 5296b703b40e7e3f57135c48efa1cc540654b40a..0b1463a54f65cac1b4deb18dea15f2515cc25361 100644 --- a/backend/core/custom_annotations.py +++ b/backend/core/custom_annotations.py @@ -10,7 +10,7 @@ Currently the following options are available def in_groups(user, group_list): - return bool(user.groups.filter(name__in=group_list)) or user.is_superuser + return bool(user.groups.filter(name__in=group_list)) # or user.is_superuser def group_required(*group_names): diff --git a/backend/core/permissions.py b/backend/core/permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..78a03977d1d5f4fedcab1a3677b05ed643cb954f --- /dev/null +++ b/backend/core/permissions.py @@ -0,0 +1,18 @@ +from rest_framework import permissions +from core.custom_annotations import in_groups + +from core.models import Student, Submission, Feedback + + +class StudentRequestOwnData(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + if in_groups(request.user, ['Students']): + student = request.user.student + if isinstance(obj, Student): + return student == obj + elif isinstance(obj, Submission): + return student == obj.student + elif isinstance(obj, Feedback): + return student == obj.of_submission.student + + return False diff --git a/backend/core/serializers.py b/backend/core/serializers.py index 8ff9df315a2fe0893112916ef40eb5126d4d6c17..40e6f2c484f6f8f266ed91964e316f3557c22e44 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -1,91 +1,30 @@ - -import hashlib - from django.contrib.auth.models import User -from rest_framework import serializers - -from core.models import Feedback, Student, Submission, SubmissionType - - -class SubmissionTypeSerializer(serializers.ModelSerializer): - - def create(self, validated_data): - return SubmissionType(**validated_data) - - class Meta: - model = SubmissionType - exclude = ('slug',) +from rest_framework import serializers +from core.models import Student, Submission, Feedback -class CreateStudentSerializer(serializers.ModelSerializer): - username = serializers.CharField(source='user.username') - email = serializers.CharField(source='user.email') - password = serializers.CharField(source='user.password') +class StudentSerializer(serializers.ModelSerializer): + user = serializers.ReadOnlyField(source='user.username') class Meta: model = Student - fields = ('username', 'name', 'email', 'matrikel_no', 'password') - extra_kwargs = {'password': {'write_only': True}} - - def to_representation(self, obj): - return { - 'username' : obj.user.username, - 'name' : obj.name, - 'matrikel_no' : obj.matrikel_no, - } + fields = ('name', 'user', 'exam', 'submissions') - def create(self, validated_data): - user = User( - email=validated_data['email'], - username=validated_data['username'] - ) - user.set_password(validated_data['password']) - - return Student.objects.create( - name=validated_data['name'], - matrikel_no=validated_data['matrikel_no'], - user=user, - ) - - -class CreateSubmissionSerializer(serializers.ModelSerializer): - - type = serializers.SlugRelatedField( - queryset=SubmissionType.objects.all(), - slug_field='name' - ) - - student = serializers.SlugRelatedField( - queryset=User.objects.all(), - slug_field='username' - ) +class SubmissionSerializer(serializers.ModelSerializer): class Meta: model = Submission - fields = ('type', 'text', 'pre_corrections', 'student') + fields = ('seen_by_student', 'text', 'type', 'student', 'feedback') - def create(self, validated_data): - validated_data['student'] = validated_data['student'].student - return Submission.objects.create(**validated_data) +class FeedbackSerializer(serializers.ModelSerializer): + class Meta: + model = Feedback + fields = ('text', 'score') -class AnonymousFeedbackSerializer(serializers.ModelSerializer): - - def to_representation(self, obj): - return { - 'feedback' : obj.text, - 'score' : obj.score, - 'tutor' : obj.of_tutor.username, - 'student' : hashlib.sha256( - obj.of_submission.student.matrikel_no.encode() + - obj.of_submission.student.name.encode()).hexdigest(), - 'code' : obj.of_submission.text - } - - def create(self, validated_data): - return NotImplemented +class UserSerializer(serializers.ModelSerializer): class Meta: - model = Feedback + model = User fields = () diff --git a/backend/core/urls.py b/backend/core/urls.py index b79a568e167b1b441c76339261ed68171ec56176..8dab3821c11496d43053d714cd94b52f49d52c33 100644 --- a/backend/core/urls.py +++ b/backend/core/urls.py @@ -3,6 +3,8 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns from core import views + + urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^login/$', views.Login.as_view(), name='login'), @@ -22,7 +24,11 @@ urlpatterns = [ url(r'^s/submission/view/(?P<slug>\w+)/$', views.StudentSubmissionView.as_view(), name='StudentSubmissionView'), - url(r'^csv/$', views.export_csv, name='export') + url(r'^csv/$', views.export_csv, name='export'), + + url(r'^api/student/(?P<pk>[0-9]+)$', views.StudentApiView.as_view()), + url(r'^api/submission/(?P<pk>[0-9]+)$', views.SubmissionApiView.as_view()), + url(r'^api/feedback/(?P<pk>[0-9]+)$', views.FeedbackApiView.as_view()), ] urlpatterns += staticfiles_urlpatterns() diff --git a/backend/core/views/__init__.py b/backend/core/views/__init__.py index 67868d83114fb61ae463b7c2cd5b9bb0127f5bb1..a38f0ce24b8b4117e4412455222661049ff0ebdd 100644 --- a/backend/core/views/__init__.py +++ b/backend/core/views/__init__.py @@ -7,3 +7,4 @@ from .user_startpages import * from .index import * from .export_csv import * +from .api import * diff --git a/backend/core/views/api.py b/backend/core/views/api.py new file mode 100644 index 0000000000000000000000000000000000000000..7722ebc4349c0fe18767f01f1681ec33cf31a6f0 --- /dev/null +++ b/backend/core/views/api.py @@ -0,0 +1,24 @@ + +from core.models import Student, Submission, Feedback +from core.serializers import SubmissionSerializer, StudentSerializer, FeedbackSerializer +from core.permissions import StudentRequestOwnData +from rest_framework.generics import RetrieveAPIView + + +class StudentApiView(RetrieveAPIView): + permission_classes = (StudentRequestOwnData, ) + queryset = Student.objects.all() + serializer_class = StudentSerializer + + +class SubmissionApiView(RetrieveAPIView): + permission_classes = (StudentRequestOwnData, ) + queryset = Submission.objects.all() + serializer_class = SubmissionSerializer + + +class FeedbackApiView(RetrieveAPIView): + permission_classes = (StudentRequestOwnData, ) + queryset = Feedback.objects.all() + serializer_class = FeedbackSerializer + diff --git a/backend/grady/settings/default.py b/backend/grady/settings/default.py index d9b710ae7fe5a6573327d79ec5d354e0adba36cf..c7b4c1a52893fbd2325087e3e4d80fa2d5d1ce4a 100644 --- a/backend/grady/settings/default.py +++ b/backend/grady/settings/default.py @@ -40,6 +40,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'django_extensions', 'core', + 'rest_framework', ] MIDDLEWARE = [ @@ -70,6 +71,12 @@ TEMPLATES = [ }, ] +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.IsAuthenticated', + ) +} + WSGI_APPLICATION = 'grady.wsgi.application' diff --git a/backend/grady/urls.py b/backend/grady/urls.py index ff39cb407bdfccf3ed42992a532d4120e3ed887b..9acdd9b0e47126124006bc7b2ee0445a4388a42f 100644 --- a/backend/grady/urls.py +++ b/backend/grady/urls.py @@ -20,3 +20,8 @@ urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('core.urls')) ] + +urlpatterns += [ + url(r'^api-auth/', include('rest_framework.urls', + namespace='rest_framework')), +]