Commit a2d8c42294272590acc7bf17309aa03bd68f2622
1 parent
033fffbf8e
Exists in
master
added feed
Showing 3 changed files with 39 additions and 16 deletions Side-by-side Diff
flashcards/models.py
View file @
a2d8c42
1 | +from datetime import datetime | |
2 | + | |
1 | 3 | from django.contrib.auth.models import AbstractUser, UserManager |
2 | 4 | from django.core.exceptions import PermissionDenied |
3 | 5 | from django.db.models import * |
4 | 6 | from django.utils.timezone import now |
5 | 7 | from simple_email_confirmation import SimpleEmailConfirmationUserMixin |
6 | 8 | from fields import MaskField |
7 | -from datetime import datetime | |
8 | 9 | |
10 | + | |
9 | 11 | # Hack to fix AbstractUser before subclassing it |
10 | 12 | AbstractUser._meta.get_field('email')._unique = True |
11 | 13 | AbstractUser._meta.get_field('username')._unique = False |
... | ... | @@ -139,7 +141,7 @@ |
139 | 141 | # create_new is True iff the user editing this card is the author of this card |
140 | 142 | # and there are no other users with this card in their decks |
141 | 143 | create_new = user != self.author or \ |
142 | - UserFlashcard.objects.filter(flashcard=self).exclude(user=user).exists() | |
144 | + UserFlashcard.objects.filter(flashcard=self).exclude(user=user).exists() | |
143 | 145 | |
144 | 146 | if 'material_date' in new_flashcard and self.material_date != new_flashcard['material_date']: |
145 | 147 | content_changed |= True |
146 | 148 | |
... | ... | @@ -245,11 +247,15 @@ |
245 | 247 | |
246 | 248 | @property |
247 | 249 | def long_name(self): |
248 | - return '%s %s (%s)' % (self.course_title, self.lecture_times, self.instructor) | |
250 | + return '%s %s (%s)' % (self.course_title, self.lecture_times, self.instructor) | |
249 | 251 | |
250 | 252 | @property |
251 | 253 | def short_name(self): |
252 | 254 | return '%s %s' % (self.department_abbreviation, self.course_num) |
255 | + | |
256 | + def get_feed_for_user(self, user): | |
257 | + qs = Flashcard.objects.filter(section=self).exclude(userflashcard__user=user).order_by('pushed') | |
258 | + return qs | |
253 | 259 | |
254 | 260 | def __unicode__(self): |
255 | 261 | return '%s %s: %s (%s %s)' % ( |
flashcards/tests/test_api.py
View file @
a2d8c42
... | ... | @@ -257,4 +257,10 @@ |
257 | 257 | def test_section_deck(self): |
258 | 258 | response = self.client.get('/api/sections/1/deck/') |
259 | 259 | self.assertEqual(response.status_code, HTTP_200_OK) |
260 | + | |
261 | + def test_section_feed(self): | |
262 | + response = self.client.get('/api/sections/1/feed/') | |
263 | + self.assertEqual(response.status_code, HTTP_200_OK) | |
264 | + print response.data | |
265 | + self.assertEqual(response.data, {}) |
flashcards/views.py
View file @
a2d8c42
... | ... | @@ -4,9 +4,9 @@ |
4 | 4 | from flashcards.serializers import SectionSerializer, UserUpdateSerializer, RegistrationSerializer, UserSerializer, \ |
5 | 5 | PasswordResetSerializer, PasswordResetRequestSerializer, EmailPasswordSerializer, FlashcardSerializer, \ |
6 | 6 | FlashcardUpdateSerializer |
7 | -from rest_framework.decorators import detail_route, permission_classes, api_view, list_route | |
7 | +from rest_framework.decorators import detail_route, permission_classes, api_view | |
8 | 8 | from rest_framework.generics import ListAPIView, GenericAPIView |
9 | -from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin | |
9 | +from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin | |
10 | 10 | from rest_framework.permissions import IsAuthenticated |
11 | 11 | from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet |
12 | 12 | from django.core.mail import send_mail |
... | ... | @@ -24,7 +24,7 @@ |
24 | 24 | pagination_class = StandardResultsSetPagination |
25 | 25 | permission_classes = [IsAuthenticated] |
26 | 26 | |
27 | - @detail_route(methods=['get'], permission_classes=[IsAuthenticated]) | |
27 | + @detail_route(methods=['GET']) | |
28 | 28 | def flashcards(self, request, pk): |
29 | 29 | """ |
30 | 30 | Gets flashcards for a section, excluding hidden cards. |
... | ... | @@ -33,7 +33,7 @@ |
33 | 33 | flashcards = Flashcard.cards_visible_to(request.user).filter(section=self.get_object()) |
34 | 34 | return Response(FlashcardSerializer(flashcards, many=True).data) |
35 | 35 | |
36 | - @detail_route(methods=['post'], permission_classes=[IsAuthenticated]) | |
36 | + @detail_route(methods=['post']) | |
37 | 37 | def enroll(self, request, pk): |
38 | 38 | """ |
39 | 39 | Add the current user to a specified section |
... | ... | @@ -53,7 +53,7 @@ |
53 | 53 | request.user.sections.add(section) |
54 | 54 | return Response(status=HTTP_204_NO_CONTENT) |
55 | 55 | |
56 | - @detail_route(methods=['post'], permission_classes=[IsAuthenticated]) | |
56 | + @detail_route(methods=['post']) | |
57 | 57 | def drop(self, request, pk): |
58 | 58 | """ |
59 | 59 | Remove the current user from a specified section |
60 | 60 | |
61 | 61 | |
... | ... | @@ -71,15 +71,18 @@ |
71 | 71 | section.user_set.remove(request.user) |
72 | 72 | return Response(status=HTTP_204_NO_CONTENT) |
73 | 73 | |
74 | - @list_route(methods=['get'], permission_classes=[IsAuthenticated]) | |
74 | + @detail_route(methods=['GET']) | |
75 | 75 | def search(self, request): |
76 | + """ | |
77 | + Returns a list of sections which match a user's query | |
78 | + """ | |
76 | 79 | query = request.GET.get('q', None) |
77 | 80 | if not query: return Response('[]') |
78 | 81 | qs = Section.search(query.split(' '))[:20] |
79 | 82 | serializer = SectionSerializer(qs, many=True) |
80 | 83 | return Response(serializer.data) |
81 | 84 | |
82 | - @detail_route(methods=['get'], permission_classes=[IsAuthenticated]) | |
85 | + @detail_route(methods=['GET']) | |
83 | 86 | def deck(self, request, pk): |
84 | 87 | """ |
85 | 88 | Gets the contents of a user's deck for a given section. |
86 | 89 | |
... | ... | @@ -90,7 +93,16 @@ |
90 | 93 | serializer = FlashcardSerializer(qs, many=True) |
91 | 94 | return Response(serializer.data) |
92 | 95 | |
96 | + @detail_route(methods=['GET']) | |
97 | + def feed(self, request, pk): | |
98 | + """ | |
99 | + Gets the contents of a user's feed for a section. | |
100 | + Exclude cards that are already in the user's deck | |
101 | + """ | |
102 | + serializer = FlashcardSerializer(self.get_object().get_feed_for_user(request.user), many=True) | |
103 | + return Response(serializer.data) | |
93 | 104 | |
105 | + | |
94 | 106 | class UserSectionListView(ListAPIView): |
95 | 107 | serializer_class = SectionSerializer |
96 | 108 | permission_classes = [IsAuthenticated] |
... | ... | @@ -261,7 +273,7 @@ |
261 | 273 | return Response(status=HTTP_204_NO_CONTENT) |
262 | 274 | |
263 | 275 | |
264 | -class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): | |
276 | +class FlashcardViewSet(GenericViewSet, UpdateModelMixin, CreateModelMixin, RetrieveModelMixin): | |
265 | 277 | queryset = Flashcard.objects.all() |
266 | 278 | serializer_class = FlashcardSerializer |
267 | 279 | permission_classes = [IsAuthenticated] |
... | ... | @@ -275,7 +287,7 @@ |
275 | 287 | headers = self.get_success_headers(serializer.data) |
276 | 288 | return Response(serializer.data, status=HTTP_201_CREATED, headers=headers) |
277 | 289 | |
278 | - @detail_route(methods=['post'], permission_classes=[IsAuthenticated]) | |
290 | + @detail_route(methods=['post']) | |
279 | 291 | def report(self, request, pk): |
280 | 292 | """ |
281 | 293 | Report the given card |
... | ... | @@ -292,7 +304,7 @@ |
292 | 304 | obj.save() |
293 | 305 | return Response(status=HTTP_204_NO_CONTENT) |
294 | 306 | |
295 | - @detail_route(methods=['POST'], permission_classes=[IsAuthenticated]) | |
307 | + @detail_route(methods=['POST']) | |
296 | 308 | def pull(self, request, pk): |
297 | 309 | """ |
298 | 310 | Pull a card from the live feed into the user's deck. |
... | ... | @@ -305,8 +317,7 @@ |
305 | 317 | user.pull(flashcard) |
306 | 318 | return Response(status=HTTP_204_NO_CONTENT) |
307 | 319 | |
308 | - @detail_route(methods=['PATCH'], permission_classes=[IsAuthenticated]) | |
309 | - def patch(self, request, pk): | |
320 | + def update(self, request, *args, **kwargs): | |
310 | 321 | """ |
311 | 322 | Edit settings related to a card for the user. |
312 | 323 | :param request: The request object. |
... | ... | @@ -314,7 +325,7 @@ |
314 | 325 | :return: A 204 response upon success. |
315 | 326 | """ |
316 | 327 | user = request.user |
317 | - flashcard = Flashcard.objects.get(pk=pk) | |
328 | + flashcard = self.get_object() | |
318 | 329 | data = FlashcardUpdateSerializer(data=request.data) |
319 | 330 | data.is_valid(raise_exception=True) |
320 | 331 | new_flashcard = data.validated_data |