From 5d861cbfb8e4b0316de8ccec0c804809ed7090f3 Mon Sep 17 00:00:00 2001 From: Rohan Rangray Date: Sun, 17 May 2015 09:25:24 -0700 Subject: [PATCH] Wrote tests for FlashcardViewSet.edit --- flashcards/models.py | 25 ++++++++++++++++++---- flashcards/serializers.py | 6 ++++-- flashcards/tests/test_api.py | 51 +++++++++++++++++++++++++++++++++++++------- flashcards/views.py | 15 +++++++------ 4 files changed, 77 insertions(+), 20 deletions(-) diff --git a/flashcards/models.py b/flashcards/models.py index a01ec31..1748d82 100644 --- a/flashcards/models.py +++ b/flashcards/models.py @@ -1,7 +1,8 @@ from datetime import datetime from django.contrib.auth.models import AbstractUser, UserManager -from django.core.exceptions import PermissionDenied +from django.core.exceptions import PermissionDenied, SuspiciousOperation +from django.db import IntegrityError from django.db.models import * from django.utils.timezone import now from simple_email_confirmation import SimpleEmailConfirmationUserMixin @@ -109,11 +110,12 @@ class Flashcard(Model): section = ForeignKey('Section', help_text='The section with which the card is associated') pushed = DateTimeField(auto_now_add=True, help_text="When the card was first pushed") material_date = DateTimeField(default=now, help_text="The date with which the card is associated") - previous = ForeignKey('Flashcard', null=True, blank=True, + previous = ForeignKey('Flashcard', null=True, blank=True, default=None, help_text="The previous version of this card, if one exists") author = ForeignKey(User) is_hidden = BooleanField(default=False) - hide_reason = CharField(blank=True, max_length=255, help_text="Reason for hiding this card") + hide_reason = CharField(blank=True, null=True, max_length=255, + default=None, help_text="Reason for hiding this card") mask = MaskField(max_length=255, null=True, blank=True, help_text="The mask on the card") class Meta: @@ -131,6 +133,16 @@ class Flashcard(Model): if not result.exists(): return self.is_hidden return result[0].is_hidden() + def add_to_deck(self, user): + if not user.is_in_section(self.section): + raise PermissionDenied("You don't have the permission to add this card") + try: + user_flashcard = UserFlashcard.objects.create(user=user, flashcard=self, mask=self.mask) + except IntegrityError: + raise SuspiciousOperation("The flashcard is already in the user's deck") + user_flashcard.save() + return user_flashcard + def edit(self, user, new_flashcard): """ Creates a new flashcard if a new flashcard should be created when the given user edits this flashcard. @@ -155,10 +167,15 @@ class Flashcard(Model): content_changed |= True self.text = new_flashcard['text'] if create_new and content_changed: + mask = self.mask + pk = self.pk self.pk = None if 'mask' in new_flashcard: - self.mask = new_flashcard['mask'] + mask = new_flashcard['mask'] + self.mask = mask + self.previous_id = pk self.save() + return create_new and content_changed @classmethod def cards_visible_to(cls, user): diff --git a/flashcards/serializers.py b/flashcards/serializers.py index 70d1b7d..0744422 100644 --- a/flashcards/serializers.py +++ b/flashcards/serializers.py @@ -119,7 +119,7 @@ class FlashcardSerializer(ModelSerializer): is_hidden = BooleanField(read_only=True) hide_reason = CharField(read_only=True) material_date = DateTimeField(default=now) - mask = MaskFieldSerializer() + mask = MaskFieldSerializer(allow_null=True) def validate_material_date(self, value): utc = pytz.UTC @@ -135,7 +135,7 @@ class FlashcardSerializer(ModelSerializer): def validate_previous(self, value): if value is None: return value - if Flashcard.objects.filter(pk=value).count() > 0: + if Flashcard.objects.filter(pk=value.pk).count() > 0: return value raise serializers.ValidationError("Invalid previous Flashcard object") @@ -155,6 +155,8 @@ class FlashcardSerializer(ModelSerializer): return value def validate_mask(self, value): + if value is None: + return None if len(self.initial_data['text']) < value.max_offset(): raise serializers.ValidationError("Mask out of bounds") return value diff --git a/flashcards/tests/test_api.py b/flashcards/tests/test_api.py index 4fa9002..648632c 100644 --- a/flashcards/tests/test_api.py +++ b/flashcards/tests/test_api.py @@ -4,6 +4,9 @@ from rest_framework.status import HTTP_204_NO_CONTENT, HTTP_201_CREATED, HTTP_20 from rest_framework.test import APITestCase from re import search from django.utils.timezone import now +from flashcards.validators import FlashcardMask +from flashcards.serializers import FlashcardSerializer +from pytz import UTC as utc class LoginTests(APITestCase): @@ -181,17 +184,46 @@ class FlashcardDetailTest(APITestCase): fixtures = ['testusers', 'testsections'] def setUp(self): - section = Section.objects.get(pk=1) - user = User.objects.get(email='none@none.com') - - self.flashcard = Flashcard(text="jason", section=section, material_date=now(), author=user) + self.section = Section.objects.get(pk=1) + self.section.save() + self.user = User.objects.get(email='none@none.com') + self.user.sections.add(self.section) + self.user.save() + self.flashcard = Flashcard(text="jason", + section=self.section, + material_date=now(), + author=self.user) self.flashcard.save() + self.flashcard.add_to_deck(self.user) def test_edit_flashcard(self): self.client.login(email='none@none.com', password='1234') - user = User.objects.get(email='none@none.com') - user.sections.add(Section.objects.get(pk=1)) - user.save() + user = self.user + flashcard = self.flashcard + url = "/api/flashcards/{}/".format(flashcard.pk) + data = {'text': 'new wow for the flashcard', + 'mask': '[[0,4]]'} + self.assertNotEqual(flashcard.text, data['text']) + response = self.client.patch(url, data, format='json') + self.assertEqual(response.status_code, HTTP_200_OK) + self.assertEqual(response.data['text'], data['text']) + data = {'material_date': datetime(2015, 4, 12, 2, 2, 2), + 'mask': '[[1, 3]]'} + user2 = User.objects.create(email='wow@wow.wow', password='wow') + user2.sections.add(self.section) + user2.save() + UserFlashcard.objects.create(user=user2, flashcard=flashcard).save() + response = self.client.patch(url, data, format='json') + serializer = FlashcardSerializer(data=response.data) + serializer.is_valid(raise_exception=True) + self.assertEqual(response.status_code, HTTP_200_OK) + # self.assertEqual(serializer.validated_data['material_date'], utc.localize(data['material_date'])) + self.assertEqual(serializer.validated_data['mask'], FlashcardMask([[1, 3]])) + data = {'mask': '[[3,6]]'} + response = self.client.patch(url, data, format='json') + user_flashcard = UserFlashcard.objects.get(user=user, flashcard=flashcard) + self.assertEqual(response.status_code, HTTP_200_OK) + self.assertEqual(user_flashcard.mask, FlashcardMask([[3, 6]])) def test_create_flashcard(self): self.client.login(email='none@none.com', password='1234') @@ -291,7 +323,10 @@ class SectionViewSetTest(APITestCase): self.assertEqual(response.status_code, HTTP_200_OK) def test_section_feed(self): - response = self.client.get('/api/sections/1/feed/') + Flashcard.objects.create(author=self.user, material_date=datetime.now(), + text='wow', section=self.section, + mask=None).save() + response = self.client.get('/api/sections/{}/feed/'.format(self.section.pk)) self.assertEqual(response.status_code, HTTP_200_OK) self.assertEqual(response.data[0]['id'], 1) diff --git a/flashcards/views.py b/flashcards/views.py index 2649aed..ef6bd72 100644 --- a/flashcards/views.py +++ b/flashcards/views.py @@ -13,7 +13,7 @@ from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet from django.core.mail import send_mail from django.contrib.auth import authenticate from django.contrib.auth.tokens import default_token_generator -from rest_framework.status import HTTP_204_NO_CONTENT, HTTP_201_CREATED +from rest_framework.status import HTTP_204_NO_CONTENT, HTTP_201_CREATED, HTTP_200_OK from rest_framework.response import Response from rest_framework.exceptions import AuthenticationFailed, NotAuthenticated, ValidationError, PermissionDenied from simple_email_confirmation import EmailAddress @@ -378,13 +378,16 @@ class FlashcardViewSet(GenericViewSet, UpdateModelMixin, CreateModelMixin, Retri data.is_valid(raise_exception=True) new_flashcard = data.validated_data - flashcard.edit(user, new_flashcard) - user_card, created = UserFlashcard.objects.get_or_create(user=user, flashcard=flashcard) - user_card.mask = flashcard.mask + new_card = flashcard.edit(user, new_flashcard) + if new_card: + user_card = flashcard.add_to_deck(user) + else: + user_card, created = UserFlashcard.objects.get_or_create(user=user, flashcard=flashcard) + if created and ('mask' not in new_flashcard): + user_card.save() if 'mask' in new_flashcard: user_card.mask = new_flashcard['mask'] - if 'mask' in new_flashcard or created: user_card.save() - return Response(status=HTTP_204_NO_CONTENT) + return Response(FlashcardSerializer(flashcard).data, status=HTTP_200_OK) -- 1.9.1