From a2d8c42294272590acc7bf17309aa03bd68f2622 Mon Sep 17 00:00:00 2001 From: Andrew Buss Date: Sat, 16 May 2015 17:34:25 -0700 Subject: [PATCH] added feed --- flashcards/models.py | 12 +++++++++--- flashcards/tests/test_api.py | 6 ++++++ flashcards/views.py | 37 ++++++++++++++++++++++++------------- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/flashcards/models.py b/flashcards/models.py index 836be63..382e95e 100644 --- a/flashcards/models.py +++ b/flashcards/models.py @@ -1,10 +1,12 @@ +from datetime import datetime + from django.contrib.auth.models import AbstractUser, UserManager from django.core.exceptions import PermissionDenied from django.db.models import * from django.utils.timezone import now from simple_email_confirmation import SimpleEmailConfirmationUserMixin from fields import MaskField -from datetime import datetime + # Hack to fix AbstractUser before subclassing it AbstractUser._meta.get_field('email')._unique = True @@ -139,7 +141,7 @@ class Flashcard(Model): # create_new is True iff the user editing this card is the author of this card # and there are no other users with this card in their decks create_new = user != self.author or \ - UserFlashcard.objects.filter(flashcard=self).exclude(user=user).exists() + UserFlashcard.objects.filter(flashcard=self).exclude(user=user).exists() if 'material_date' in new_flashcard and self.material_date != new_flashcard['material_date']: content_changed |= True @@ -245,12 +247,16 @@ class Section(Model): @property def long_name(self): - return '%s %s (%s)' % (self.course_title, self.lecture_times, self.instructor) + return '%s %s (%s)' % (self.course_title, self.lecture_times, self.instructor) @property def short_name(self): return '%s %s' % (self.department_abbreviation, self.course_num) + def get_feed_for_user(self, user): + qs = Flashcard.objects.filter(section=self).exclude(userflashcard__user=user).order_by('pushed') + return qs + def __unicode__(self): return '%s %s: %s (%s %s)' % ( self.department_abbreviation, self.course_num, self.course_title, self.instructor, self.quarter) diff --git a/flashcards/tests/test_api.py b/flashcards/tests/test_api.py index ae00b98..b761e33 100644 --- a/flashcards/tests/test_api.py +++ b/flashcards/tests/test_api.py @@ -257,3 +257,9 @@ class SectionViewSetTest(APITestCase): def test_section_deck(self): response = self.client.get('/api/sections/1/deck/') self.assertEqual(response.status_code, HTTP_200_OK) + + def test_section_feed(self): + response = self.client.get('/api/sections/1/feed/') + self.assertEqual(response.status_code, HTTP_200_OK) + print response.data + self.assertEqual(response.data, {}) diff --git a/flashcards/views.py b/flashcards/views.py index a086634..9742283 100644 --- a/flashcards/views.py +++ b/flashcards/views.py @@ -4,9 +4,9 @@ from flashcards.models import Section, User, Flashcard, FlashcardHide, UserFlash from flashcards.serializers import SectionSerializer, UserUpdateSerializer, RegistrationSerializer, UserSerializer, \ PasswordResetSerializer, PasswordResetRequestSerializer, EmailPasswordSerializer, FlashcardSerializer, \ FlashcardUpdateSerializer -from rest_framework.decorators import detail_route, permission_classes, api_view, list_route +from rest_framework.decorators import detail_route, permission_classes, api_view from rest_framework.generics import ListAPIView, GenericAPIView -from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin +from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet from django.core.mail import send_mail @@ -24,7 +24,7 @@ class SectionViewSet(ReadOnlyModelViewSet): pagination_class = StandardResultsSetPagination permission_classes = [IsAuthenticated] - @detail_route(methods=['get'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['GET']) def flashcards(self, request, pk): """ Gets flashcards for a section, excluding hidden cards. @@ -33,7 +33,7 @@ class SectionViewSet(ReadOnlyModelViewSet): flashcards = Flashcard.cards_visible_to(request.user).filter(section=self.get_object()) return Response(FlashcardSerializer(flashcards, many=True).data) - @detail_route(methods=['post'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['post']) def enroll(self, request, pk): """ Add the current user to a specified section @@ -53,7 +53,7 @@ class SectionViewSet(ReadOnlyModelViewSet): request.user.sections.add(section) return Response(status=HTTP_204_NO_CONTENT) - @detail_route(methods=['post'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['post']) def drop(self, request, pk): """ Remove the current user from a specified section @@ -71,15 +71,18 @@ class SectionViewSet(ReadOnlyModelViewSet): section.user_set.remove(request.user) return Response(status=HTTP_204_NO_CONTENT) - @list_route(methods=['get'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['GET']) def search(self, request): + """ + Returns a list of sections which match a user's query + """ query = request.GET.get('q', None) if not query: return Response('[]') qs = Section.search(query.split(' '))[:20] serializer = SectionSerializer(qs, many=True) return Response(serializer.data) - @detail_route(methods=['get'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['GET']) def deck(self, request, pk): """ Gets the contents of a user's deck for a given section. @@ -90,6 +93,15 @@ class SectionViewSet(ReadOnlyModelViewSet): serializer = FlashcardSerializer(qs, many=True) return Response(serializer.data) + @detail_route(methods=['GET']) + def feed(self, request, pk): + """ + Gets the contents of a user's feed for a section. + Exclude cards that are already in the user's deck + """ + serializer = FlashcardSerializer(self.get_object().get_feed_for_user(request.user), many=True) + return Response(serializer.data) + class UserSectionListView(ListAPIView): serializer_class = SectionSerializer @@ -261,7 +273,7 @@ def reset_password(request, format=None): return Response(status=HTTP_204_NO_CONTENT) -class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): +class FlashcardViewSet(GenericViewSet, UpdateModelMixin, CreateModelMixin, RetrieveModelMixin): queryset = Flashcard.objects.all() serializer_class = FlashcardSerializer permission_classes = [IsAuthenticated] @@ -275,7 +287,7 @@ class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=HTTP_201_CREATED, headers=headers) - @detail_route(methods=['post'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['post']) def report(self, request, pk): """ Report the given card @@ -292,7 +304,7 @@ class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): obj.save() return Response(status=HTTP_204_NO_CONTENT) - @detail_route(methods=['POST'], permission_classes=[IsAuthenticated]) + @detail_route(methods=['POST']) def pull(self, request, pk): """ Pull a card from the live feed into the user's deck. @@ -305,8 +317,7 @@ class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): user.pull(flashcard) return Response(status=HTTP_204_NO_CONTENT) - @detail_route(methods=['PATCH'], permission_classes=[IsAuthenticated]) - def patch(self, request, pk): + def update(self, request, *args, **kwargs): """ Edit settings related to a card for the user. :param request: The request object. @@ -314,7 +325,7 @@ class FlashcardViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixin): :return: A 204 response upon success. """ user = request.user - flashcard = Flashcard.objects.get(pk=pk) + flashcard = self.get_object() data = FlashcardUpdateSerializer(data=request.data) data.is_valid(raise_exception=True) new_flashcard = data.validated_data -- 1.9.1