diff --git a/flashcards/models.py b/flashcards/models.py index 940ee41..5ae89dd 100644 --- a/flashcards/models.py +++ b/flashcards/models.py @@ -63,6 +63,15 @@ class EmailOnlyUserManager(UserManager): return self._create_user(email, password, True, True, **extra_fields) +class FlashcardAlreadyPulledException(Exception): + pass + + + +class FlashcardNotInDeckException(Exception): + pass + + class User(AbstractUser, SimpleEmailConfirmationUserMixin): """ An extension of Django's default user model. @@ -81,7 +90,10 @@ class User(AbstractUser, SimpleEmailConfirmationUserMixin): if not self.is_in_section(flashcard.section): raise ValueError("User not in the section this flashcard belongs to") - user_card = UserFlashcard.objects.create(user=self, flashcard=flashcard) + try: + user_card = UserFlashcard.objects.create(user=self, flashcard=flashcard) + except IntegrityError: + raise FlashcardAlreadyPulledException() user_card.save() import flashcards.notifications @@ -95,12 +107,11 @@ class User(AbstractUser, SimpleEmailConfirmationUserMixin): try: import flashcards.notifications - user_card = UserFlashcard.objects.get(user=self, flashcard=flashcard) user_card.delete() flashcards.notifications.notify_score_change(flashcard) except UserFlashcard.DoesNotExist: - raise ValueError('Cannot unpull card that is not pulled.') + raise FlashcardNotInDeckException() def get_deck(self, section): if not self.is_in_section(section): diff --git a/flashcards/views.py b/flashcards/views.py index 26f909d..7f4d297 100644 --- a/flashcards/views.py +++ b/flashcards/views.py @@ -5,7 +5,8 @@ from django.shortcuts import get_object_or_404 from django.utils.log import getLogger from flashcards.api import StandardResultsSetPagination, IsEnrolledInAssociatedSection, IsFlashcardReviewer, \ IsAuthenticatedAndConfirmed -from flashcards.models import Section, User, Flashcard, FlashcardHide, UserFlashcard, UserFlashcardQuiz +from flashcards.models import Section, User, Flashcard, FlashcardHide, UserFlashcard, UserFlashcardQuiz, \ + FlashcardAlreadyPulledException from flashcards.notifications import notify_new_card from flashcards.serializers import SectionSerializer, UserUpdateSerializer, RegistrationSerializer, UserSerializer, \ PasswordResetSerializer, PasswordResetRequestSerializer, EmailPasswordSerializer, FlashcardSerializer, \ @@ -276,6 +277,7 @@ def reset_password(request, format=None): return Response(status=HTTP_204_NO_CONTENT) + class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): queryset = Flashcard.objects.all() serializer_class = FlashcardSerializer @@ -333,7 +335,7 @@ class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): request.user.pull(self.get_object()) log_event(request, str(self.get_object())) return Response(status=HTTP_204_NO_CONTENT) - except IntegrityError, e: + except FlashcardAlreadyPulledException: raise ValidationError('Cannot pull a card already in deck') @detail_route(methods=['POST']) @@ -345,9 +347,13 @@ class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): """ user = request.user flashcard = self.get_object() - user.unpull(flashcard) - log_event(request, str(self.get_object())) - return Response(status=HTTP_204_NO_CONTENT) + try: + user.unpull(flashcard) + log_event(request, str(self.get_object())) + return Response(status=HTTP_204_NO_CONTENT) + except FlashcardNotInDeckException: + raise ValidationError('Cannot unpull a card not in deck') + def partial_update(self, request, *args, **kwargs): """