Commit f66f9ca7d57d78ac11fbdd127116c521b15c8e68

Authored by Rohan Rangray
1 parent 512a58de33
Exists in master

Fixed SwaggerUI problem with /study/

Showing 7 changed files with 71 additions and 47 deletions Side-by-side Diff

flashcards/serializers.py View file @ f66f9ca
... ... @@ -166,36 +166,16 @@
166 166  
167 167  
168 168 class QuizRequestSerializer(serializers.Serializer):
169   - # sections = PrimaryKeyRelatedField(queryset=Section.objects.all(),required=False, many=True)
170 169 sections = ListField(child=IntegerField(min_value=1), required=False)
171 170 material_date_begin = DateTimeField(default=QUARTER_START)
172 171 material_date_end = DateTimeField(default=QUARTER_END)
173 172  
174   - def __init__(self, user, instance=None, data=empty, **kwargs):
175   - assert instance is not None or data is not empty
176   - super(QuizRequestSerializer, self).__init__(instance=instance, data=data, **kwargs)
177   - self.user = user
178   - self.user_flashcard = None
  173 + def update(self, instance, validated_data):
  174 + pass
179 175  
180 176 def create(self, validated_data):
181   - return UserFlashcardQuiz.objects.create(user_flashcard=self.user_flashcard)
  177 + return validated_data
182 178  
183   - def update(self, instance, validated_data):
184   - for attr in validated_data:
185   - setattr(instance, attr, validated_data[attr])
186   - instance.save()
187   - return instance
188   -
189   - def _get_user_flashcard(self, attrs):
190   - user_flashcard_filter = UserFlashcard.objects.filter(
191   - user=self.user, flashcard__section__in=attrs['sections'],
192   - flashcard__material_date__gte=attrs['material_date_begin'],
193   - flashcard__material_date__lte=attrs['material_date_end']
194   - )
195   - if not user_flashcard_filter.exists():
196   - raise serializers.ValidationError("Your deck for that section is empty")
197   - self.user_flashcard = user_flashcard_filter.order_by('?').first()
198   -
199 179 def validate_material_date_begin(self, value):
200 180 if QUARTER_START <= value <= QUARTER_END:
201 181 return value
202 182  
203 183  
... ... @@ -208,18 +188,17 @@
208 188  
209 189 def validate_sections(self, value):
210 190 if value is None:
211   - return self.user.sections
  191 + return Section.objects.all()
212 192 section_filter = Section.objects.filter(pk__in=value)
213 193 if not section_filter.exists():
214   - raise serializers.ValidationError("You aren't enrolled in those section(s)")
215   - return section_filter
  194 + raise serializers.ValidationError("Those aren't valid sections")
  195 + return value
216 196  
217 197 def validate(self, attrs):
218 198 if attrs['material_date_begin'] > attrs['material_date_end']:
219 199 raise serializers.ValidationError("Invalid range")
220 200 if 'sections' not in attrs:
221 201 attrs['sections'] = self.validate_sections(None)
222   - self._get_user_flashcard(attrs)
223 202 return attrs
224 203  
225 204  
... ... @@ -242,8 +221,8 @@
242 221 }
243 222  
244 223 def _validate_mask(self, value):
245   - if not isinstance(value, tuple) and value is not None:
246   - raise serializers.ValidationError("The selected mask has to be a list")
  224 + if not isinstance(value, list) and value is not None:
  225 + raise serializers.ValidationError("The selected mask has to be a list " + str(value))
247 226 if value is None or len(value) == 0:
248 227 return []
249 228 if len(value) == 2 and (0 <= value[0] and value[1] <= len(self.instance.user_flashcard.flashcard.text)):
flashcards/tests/test_api.py View file @ f66f9ca
... ... @@ -3,7 +3,7 @@
3 3 from rest_framework.status import HTTP_204_NO_CONTENT, HTTP_201_CREATED, HTTP_200_OK, HTTP_403_FORBIDDEN
4 4 from rest_framework.test import APITestCase
5 5 from re import search
6   -import datetime
  6 +from datetime import datetime
7 7 from django.utils.timezone import now
8 8 from flashcards.validators import FlashcardMask
9 9 from flashcards.serializers import FlashcardSerializer
... ... @@ -220,7 +220,7 @@
220 220 response = self.client.patch(url, data, format='json')
221 221 self.assertEqual(response.status_code, HTTP_200_OK)
222 222 self.assertEqual(response.data['text'], data['text'])
223   - data = {'material_date': datetime.datetime(2015, 4, 12, 2, 2, 2),
  223 + data = {'material_date': datetime(2015, 4, 12, 2, 2, 2),
224 224 'mask': '[[1, 3]]'}
225 225 user2 = User.objects.create(email='wow@wow.wow', password='wow')
226 226 user2.sections.add(self.section)
227 227  
... ... @@ -378,10 +378,23 @@
378 378 self.user = User.objects.get(email='none@none.com')
379 379 self.section = Section.objects.get(pk=1)
380 380 self.flashcard = Flashcard(text="This is a flashcard", section=self.section, material_date=now(),
381   - author=self.user, mask={(0,4), (5,7)})
  381 + author=self.user, mask={(0, 4), (5, 7)})
382 382 self.flashcard.save()
383 383 self.flashcard.refresh_from_db()
384 384 self.user_flashcard = UserFlashcard(flashcard=self.flashcard, user=self.user,
385 385 mask=self.flashcard.mask, pulled=datetime.now())
386 386 self.user_flashcard.save()
  387 +
  388 + def test_quiz_create(self):
  389 + url = '/api/study/'
  390 + data = {'section': 1}
  391 + response = self.client.post(url, data, format='json')
  392 + self.assertEqual(response.status_code, HTTP_200_OK)
  393 + self.assertEqual(response.data['pk'], 1)
  394 + self.assertEqual(response.data['section'], self.section.pk)
  395 + self.assertEqual(response.data['text'], self.flashcard.text)
  396 + self.assertIn(response.data['mask'], [[0, 4], [5, 7]])
  397 +
  398 + def test_quiz_response(self):
  399 +
flashcards/tests/test_models.py View file @ f66f9ca
... ... @@ -179,12 +179,23 @@
179 179  
180 180 def test_quiz_request(self):
181 181 data = {'sections': [1], 'material_date_begin': QUARTER_START, 'material_date_end': QUARTER_END}
182   - serializer = QuizRequestSerializer(user=self.user, data=data)
  182 + serializer = QuizRequestSerializer(data=data)
183 183 serializer.is_valid(raise_exception=True)
184   - user_flashcard_quiz = serializer.create(serializer.validated_data)
  184 + validated_data = serializer.create(serializer.validated_data)
  185 + user_flashcard = UserFlashcard.objects.filter(user=self.user,
  186 + flashcard__section__pk__in=validated_data['sections'],
  187 + flashcard__material_date__gte=validated_data['material_date_begin'],
  188 + flashcard__material_date__lte=validated_data['material_date_end'])
  189 + self.assertTrue(user_flashcard.exists())
  190 + user_flashcard = user_flashcard.first()
  191 + self.assertEqual(user_flashcard, self.user_flashcard)
  192 + mask = user_flashcard.mask.get_random_blank()
  193 + word = user_flashcard.flashcard.text[slice(*mask)]
  194 + user_flashcard_quiz = UserFlashcardQuiz(user_flashcard=user_flashcard,
  195 + blanked_word=word)
  196 + user_flashcard_quiz.save()
185 197 self.assertTrue(isinstance(user_flashcard_quiz, UserFlashcardQuiz))
186   - mask = user_flashcard_quiz.user_flashcard.mask.get_random_blank()
187   - self.assertIn(mask, [(24, 33), (0, 4)])
  198 + self.assertIn(mask, [[24, 33], [0, 4]])
188 199 user_flashcard_quiz.blanked_word = user_flashcard_quiz.user_flashcard.flashcard.text[slice(*mask)]
189 200 self.assertIn(user_flashcard_quiz.blanked_word, ["This", "Flashcard"])
190 201 user_flashcard_quiz.save()
flashcards/validators.py View file @ f66f9ca
... ... @@ -17,8 +17,8 @@
17 17  
18 18 def get_random_blank(self):
19 19 if self.max_offset() > 0:
20   - return sample(self, 1)[0]
21   - return ()
  20 + return list(sample(self, 1)[0])
  21 + return []
22 22  
23 23 def _iterable_check(self, iterable):
24 24 if not isinstance(iterable, Iterable) or not all([isinstance(i, Iterable) for i in iterable]):
flashcards/views.py View file @ f66f9ca
... ... @@ -4,7 +4,7 @@
4 4 from django.contrib import auth
5 5 from django.shortcuts import get_object_or_404
6 6 from flashcards.api import StandardResultsSetPagination, IsEnrolledInAssociatedSection, IsFlashcardReviewer
7   -from flashcards.models import Section, User, Flashcard, FlashcardHide, UserFlashcardQuiz
  7 +from flashcards.models import Section, User, Flashcard, FlashcardHide, UserFlashcard, UserFlashcardQuiz
8 8 from flashcards.notifications import notify_new_card
9 9 from flashcards.serializers import SectionSerializer, UserUpdateSerializer, RegistrationSerializer, UserSerializer, \
10 10 PasswordResetSerializer, PasswordResetRequestSerializer, EmailPasswordSerializer, FlashcardSerializer, \
11 11  
12 12  
13 13  
14 14  
15 15  
16 16  
... ... @@ -343,24 +343,43 @@
343 343  
344 344  
345 345 class UserFlashcardQuizViewSet(GenericViewSet, CreateModelMixin, UpdateModelMixin):
346   - queryset = UserFlashcardQuiz.objects.all()
347   - serializer_class = QuizAnswerRequestSerializer
348 346 permission_classes = [IsAuthenticated, IsFlashcardReviewer]
  347 + queryset = UserFlashcardQuiz.objects.all()
349 348  
  349 + def get_serializer_class(self):
  350 + if self.request.method == 'POST':
  351 + return QuizRequestSerializer
  352 + return QuizAnswerRequestSerializer
  353 +
350 354 def create(self, request, *args, **kwargs):
351 355 """
352 356 Return a card based on the request params.
353 357 :param request: A request object.
354 358 :param format: Format of the request.
355 359 :return: A response containing
  360 + request_serializer: serializers.QuizRequestSerializer
  361 + response_serializer: serializers.QuizResponseSerializer
356 362 """
357   - serializer = QuizRequestSerializer(user=request.user, data=request.data)
  363 + serializer = QuizRequestSerializer(data=request.data)
358 364 serializer.is_valid(raise_exception=True)
359   - user_flashcard_quiz = serializer.create(serializer.validated_data)
360   - mask = sample(user_flashcard_quiz.user_flashcard.mask.get_random_blank(), 1)
361   - user_flashcard_quiz.blanked_word = user_flashcard_quiz.user_flashcard.flashcard.text[slice(*mask)]
  365 + data = serializer.validated_data
  366 + user_flashcard_filter = UserFlashcard.objects.filter(
  367 + user=request.user, flashcard__section__pk__in=data['sections'],
  368 + flashcard__material_date__gte=data['material_date_begin'],
  369 + flashcard__material_date__lte=data['material_date_end']
  370 + )
  371 +
  372 + if not user_flashcard_filter.exists():
  373 + raise ValidationError("No matching flashcard found in your decks")
  374 +
  375 + user_flashcard = user_flashcard_filter.order_by('?').first()
  376 + mask = user_flashcard.mask.get_random_blank()
  377 + user_flashcard_quiz = UserFlashcardQuiz(user_flashcard=user_flashcard,
  378 + blanked_word=user_flashcard.flashcard.text[slice(*mask)])
362 379 user_flashcard_quiz.save()
363   - return Response(QuizResponseSerializer(instance=user_flashcard_quiz, mask=mask).data, status=HTTP_200_OK)
  380 + assert user_flashcard_quiz is not None
  381 + response = QuizResponseSerializer(instance=user_flashcard_quiz, mask=mask)
  382 + return Response(response.data, status=HTTP_200_OK)
364 383  
365 384 def partial_update(self, request, *args, **kwargs):
366 385 """
... ... @@ -368,6 +387,7 @@
368 387 :param request: A request object.
369 388 :param format: Format of the request.
370 389 :return: A response containing
  390 + request_serializer: serializers.QuizAnswerRequestSerializer
371 391 """
372 392 user_flashcard_quiz = self.get_object()
373 393 serializer = QuizAnswerRequestSerializer(instance=user_flashcard_quiz, data=request.data)
requirements.txt View file @ f66f9ca
... ... @@ -3,7 +3,7 @@
3 3 django-websocket-redis
4 4 #gevent==1.0.1
5 5 #greenlet==0.4.5
6   -#redis==2.10.3
  6 +redis==2.10.3
7 7 six==1.9.0
8 8 djangorestframework
9 9 docutils
scripts/run_production.sh View file @ f66f9ca
... ... @@ -4,4 +4,5 @@
4 4 # newrelic-admin run-program /srv/flashy-backend/venv/bin/gunicorn --pid /run/flashy/gunicorn.pid -w 6 -n flashy -b 127.0.0.1:7002 flashy.wsgi
5 5 uwsgi /etc/uwsgi/websocket.ini --touch-reload=/etc/uwsgi/websocket.ini &
6 6 newrelic-admin run-program uwsgi /etc/uwsgi/flashy.ini --touch-reload=/etc/uwsgi/flashy.ini
  7 +trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT