From 0b9aed128a36324979d78039f68f89494d60fe31 Mon Sep 17 00:00:00 2001 From: Aarni Halinen Date: Tue, 16 Jun 2020 22:31:32 +0300 Subject: [PATCH] Add identifying string to Signups and list them on Forms --- webapp/migrations/0063_signup_list_name.py | 19 ++++++++++ webapp/models.py | 8 +++- webapp/serializers.py | 43 ++++++++++++---------- webapp/tests/signup_fixture.py | 6 ++- webapp/tests/test_signup.py | 11 ++---- webapp/tests/test_signup_errors.py | 32 +++++++--------- webapp/views.py | 16 ++++++-- 7 files changed, 85 insertions(+), 50 deletions(-) create mode 100644 webapp/migrations/0063_signup_list_name.py diff --git a/webapp/migrations/0063_signup_list_name.py b/webapp/migrations/0063_signup_list_name.py new file mode 100644 index 0000000..5460300 --- /dev/null +++ b/webapp/migrations/0063_signup_list_name.py @@ -0,0 +1,19 @@ +# Generated by Django 2.1.5 on 2020-06-16 18:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0062_auto_20191110_2117'), + ] + + operations = [ + migrations.AddField( + model_name='signup', + name='list_name', + field=models.CharField(default='', max_length=255, verbose_name='Name'), + preserve_default=False, + ), + ] diff --git a/webapp/models.py b/webapp/models.py index 0184260..4f5d99d 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -100,6 +100,10 @@ class SignupForm(models.Model): def __str__(self): return _('#{} {}').format(self.id, self.title) + @property + def signups(self): + return Signup.objects.filter(signupForm=self) + @property def schema(self): questions = self.questions @@ -157,9 +161,11 @@ class Signup(models.Model): signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE) time = models.DateTimeField(default=timezone.now) answer = JSONField() + # Answer we use in signupForm signups field. Frontend uses first questions answer as this value. + list_name = models.CharField(_('Name'), max_length=255) def __str__(self): - return _('Sign-ups: {}').format(self.signupForm) + return f"{self.signupForm}: {self.list_name} ({self.pk})" class Meta: verbose_name = _('Sign-up') diff --git a/webapp/serializers.py b/webapp/serializers.py index 765f40a..938bc6d 100644 --- a/webapp/serializers.py +++ b/webapp/serializers.py @@ -2,12 +2,35 @@ from rest_framework import serializers from webapp.models import * +class SignupSerializer(serializers.ModelSerializer): + signupForm_id = serializers.PrimaryKeyRelatedField( + source="signupForm", + queryset=SignupForm.objects.all() + ) + answer = serializers.JSONField() + + class Meta: + model = Signup + fields = ('id', 'signupForm_id', 'answer', 'list_name') + extra_kwargs = { + 'url': { + 'view_name': 'signup-detail', + } + } + + class SignupFormSerializer(serializers.HyperlinkedModelSerializer): questions = serializers.JSONField() + signups = serializers.SlugRelatedField( + slug_field="list_name", + many=True, + read_only=True, + required=False + ) class Meta: model = SignupForm - fields = ('id', 'title', 'start_time', 'end_time', 'questions') + fields = ('id', 'title', 'start_time', 'end_time', 'questions', 'signups') class EventSerializer(serializers.ModelSerializer): @@ -50,24 +73,6 @@ class EventSerializer(serializers.ModelSerializer): return instance -class SignupSerializer(serializers.ModelSerializer): - signupForm = SignupFormSerializer(read_only=True, required=False) - signupForm_id = serializers.PrimaryKeyRelatedField( - source="signupForm", - queryset=SignupForm.objects.all() - ) - answer = serializers.JSONField() - - class Meta: - model = Signup - fields = ('id', 'signupForm', 'signupForm_id', 'answer') - extra_kwargs = { - 'url': { - 'view_name': 'signup-detail', - } - } - - class SavedQuestionsSerializer(serializers.ModelSerializer): question = serializers.JSONField() diff --git a/webapp/tests/signup_fixture.py b/webapp/tests/signup_fixture.py index 1ba09f1..1beb305 100644 --- a/webapp/tests/signup_fixture.py +++ b/webapp/tests/signup_fixture.py @@ -23,15 +23,17 @@ def createSignupForm(name="Form1", start_time=timezone.now(), end_time=month_fro ) -def createSignupObject(form, answer): +def createSignupObject(list_name, form, answer): return Signup.objects.create( + list_name=list_name, signupForm=form, answer=answer ) -def createSignupRequest(form_id, answer): +def createSignupRequest(list_name, form_id, answer): return { + "list_name": list_name, "signupForm_id": form_id, "answer": answer } diff --git a/webapp/tests/test_signup.py b/webapp/tests/test_signup.py index 729f9a4..4f0664e 100644 --- a/webapp/tests/test_signup.py +++ b/webapp/tests/test_signup.py @@ -1,7 +1,7 @@ from unittest import skip from django.contrib.auth.models import User from rest_framework import status -from rest_framework.test import APITestCase, force_authenticate +from rest_framework.test import APITestCase from webapp.serializers import SignupSerializer from webapp.models import Signup from webapp.tests.signup_fixture import createSignupForm, createSignupObject, createSignupRequest, ALL_QUESTION_TYPES, ALL_QUESTION_TYPES_ANSWER @@ -13,13 +13,10 @@ class SignupTestCase(APITestCase): def setUp(self): self.signupForm = createSignupForm() - self.signupFormText = createSignupForm(name="Form2", questions=[ALL_QUESTION_TYPES[0]]) - self.signupFormRadio = createSignupForm(name="Form3", questions=[ALL_QUESTION_TYPES[1]]) - self.signupFormCheck = createSignupForm(name="Form4", questions=[ALL_QUESTION_TYPES[2]]) self.hiddenForm = createSignupForm(visible=False) - self.signup1 = createSignupObject(self.signupForm, ALL_QUESTION_TYPES) - self.signup2 = createSignupObject(self.signupForm, ALL_QUESTION_TYPES) + self.signup1 = createSignupObject("1", self.signupForm, ALL_QUESTION_TYPES) + self.signup2 = createSignupObject("2", self.signupForm, ALL_QUESTION_TYPES) username, password = "test_admin", "password123" self.authClient = User.objects.create_superuser(username, "myemail@test.com", password) @@ -47,7 +44,7 @@ class SignupTestCase(APITestCase): self.assertEqual(response.data, expected.data) def test_create_signup(self): - new = createSignupRequest(self.signupForm.id, ALL_QUESTION_TYPES_ANSWER) + new = createSignupRequest("asd", self.signupForm.id, ALL_QUESTION_TYPES_ANSWER) response = self.client.post(URL, new, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Signup.objects.count(), 3) diff --git a/webapp/tests/test_signup_errors.py b/webapp/tests/test_signup_errors.py index 7cb4867..08247a3 100644 --- a/webapp/tests/test_signup_errors.py +++ b/webapp/tests/test_signup_errors.py @@ -1,7 +1,6 @@ from django.contrib.auth.models import User from rest_framework import status -from rest_framework.test import APITestCase, force_authenticate -from webapp.serializers import SignupSerializer +from rest_framework.test import APITestCase from webapp.models import Signup from webapp.tests.signup_fixture import createSignupForm, createSignupObject, createSignupRequest, ALL_QUESTION_TYPES, ALL_QUESTION_TYPES_ANSWER @@ -16,8 +15,8 @@ class SignupErrorTestCase(APITestCase): self.signupFormCheck = createSignupForm(name="Form4", questions=[ALL_QUESTION_TYPES[2]]) self.hiddenForm = createSignupForm(visible=False) - self.signup1 = createSignupObject(self.signupForm, ALL_QUESTION_TYPES) - self.signup2 = createSignupObject(self.signupForm, ALL_QUESTION_TYPES) + self.signup1 = createSignupObject("1", self.signupForm, ALL_QUESTION_TYPES) + self.signup2 = createSignupObject("2", self.signupForm, ALL_QUESTION_TYPES) username, password = "test_admin", "password123" self.authClient = User.objects.create_superuser(username, "myemail@test.com", password) @@ -28,66 +27,63 @@ class SignupErrorTestCase(APITestCase): def test_get_single_unauthorized(self): id = self.signup1.id - expected = SignupSerializer( - Signup.objects.get(id=id) - ) response = self.client.get(f"{URL}{id}/", format="json") self.assertTrue(response.status_code, status.HTTP_401_UNAUTHORIZED) def test_create_signup_404(self): - new = createSignupRequest(3001, ALL_QUESTION_TYPES_ANSWER) + new = createSignupRequest("asd", 3001, ALL_QUESTION_TYPES_ANSWER) response = self.client.post(URL, new, format="json") self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(Signup.objects.count(), 2) def test_create_signup_hidden(self): - new = createSignupRequest(self.hiddenForm.id, ALL_QUESTION_TYPES_ANSWER) + new = createSignupRequest("asd", self.hiddenForm.id, ALL_QUESTION_TYPES_ANSWER) response = self.client.post(URL, new, format="json") self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(Signup.objects.count(), 2) def test_create_empty_body(self): - response = self.client.post(URL, createSignupRequest(self.signupForm.id, {}), format="json") + response = self.client.post(URL, createSignupRequest("", self.signupForm.id, {}), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_array_body(self): - response = self.client.post(URL, createSignupRequest(self.signupForm.id, []), format="json") + response = self.client.post(URL, createSignupRequest("", self.signupForm.id, []), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_extra_body(self): testInput = ALL_QUESTION_TYPES_ANSWER.copy() testInput["newId"] = "Oon extraa" - response = self.client.post(URL, createSignupRequest(self.signupForm.id, testInput), format="json") + response = self.client.post(URL, createSignupRequest("", self.signupForm.id, testInput), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_bad_id(self): - response = self.client.post(URL, createSignupRequest(self.signupFormText.id, {"malformed": "TekstiƤ"}), format="json") + response = self.client.post(URL, createSignupRequest("", self.signupFormText.id, {"malformed": "TekstiƤ"}), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_bad_type_text(self): - response = self.client.post(URL, createSignupRequest(self.signupFormText.id, {"j5CeRZDvl": 123}), format="json") + response = self.client.post(URL, createSignupRequest("", self.signupFormText.id, {"j5CeRZDvl": 123}), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_bad_data_checkbox(self): - response = self.client.post(URL, createSignupRequest(self.signupFormCheck.id, { + response = self.client.post(URL, createSignupRequest("", self.signupFormCheck.id, { "i10d426d5": ["D"] }), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_bad_type_checkbox(self): - response = self.client.post(URL, createSignupRequest(self.signupFormCheck.id, { + response = self.client.post(URL, createSignupRequest("", self.signupFormCheck.id, { "i10d426d5": {"j5CeRZDvl": {"asd": "123"}} }), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_bad_radio(self): - response = self.client.post(URL, createSignupRequest(self.signupFormRadio.id, { + response = self.client.post(URL, createSignupRequest("", self.signupFormRadio.id, { "RHJhSoaLD": [] }), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_bad_type_radio(self): - response = self.client.post(URL, createSignupRequest(self.signupFormRadio.id, { + response = self.client.post(URL, createSignupRequest("", self.signupFormRadio.id, { "RHJhSoaLD": {"asd": "123"} }), format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/webapp/views.py b/webapp/views.py index 89111a1..2961794 100644 --- a/webapp/views.py +++ b/webapp/views.py @@ -10,9 +10,9 @@ from django.shortcuts import render from django.views.decorators.http import require_http_methods from django_filters import rest_framework as filters from django.core.exceptions import ObjectDoesNotExist -from rest_framework import permissions, routers, viewsets +from rest_framework import routers, viewsets from rest_framework.filters import OrderingFilter, SearchFilter -from rest_framework.permissions import IsAuthenticatedOrReadOnly +from rest_framework.permissions import IsAuthenticatedOrReadOnly, BasePermission from jsonschema import validate from jsonschema.exceptions import ValidationError @@ -22,7 +22,7 @@ from webapp.serializers import (EventSerializer, SignupFormSerializer, SignupSer OccupationSerializer, TagSerializer) -class IsPostOrIsAuthenticated(permissions.BasePermission): +class IsPostOrIsAuthenticated(BasePermission): def has_permission(self, request, view): if request.method == 'POST': @@ -63,6 +63,16 @@ class SignupFormViewSet(viewsets.ModelViewSet): # filter_fields = '__all__' # search_fields = '__all__' + def create(self, request, *args, **kwargs): + try: + schema = { + "type": "array", + } + validate(instance=request.data["questions"], schema=schema) + return super().create(request, *args, **kwargs) + except ValidationError as err: + return JsonResponse(status=400, data={"error": err.message}) + def get_queryset(self): if self.request.user.is_authenticated: return SignupForm.objects.all().order_by('start_time')