예제 #1
0
 def test_get_count_without_order_filter(self):
     for content in range(0, 10):
         SBContent(content="this is content number 2-%d" % content,
                   to_be_deleted=True).save()
     queryset = NeoQuerySet(SBContent)\
         .filter("WHERE res.to_be_deleted=False")
     self.assertEqual(queryset.count(), 50)
예제 #2
0
 def get_queryset(self):
     sort_by = self.request.query_params.get('ordering', "")
     sort_by, ordering = get_ordering(sort_by)
     if ordering == "DESC":
         descending = True
     else:
         descending = False
     if sort_by == "" or sort_by == "vote_count":
         query = "(q:Question {object_uuid: '%s'})-" \
                 "[:POSSIBLE_ANSWER]->(res:Solution) " \
                 "WHERE res.to_be_deleted=false " \
                 "OPTIONAL MATCH (res)<-[vs:PLEB_VOTES]-() " \
                 "WHERE vs.active=True" % self.kwargs[self.lookup_field]
         reduce_query = ", reduce(vote_count = 0, v in collect(vs)|" \
                        "CASE WHEN v.vote_type=True THEN vote_count+1 " \
                        "WHEN v.vote_type=False THEN vote_count-1 " \
                        "ELSE vote_count END) as reduction " \
                        "ORDER BY reduction"
         return NeoQuerySet(Solution, query=query,
                            distinct=True,
                            descending=not descending).order_by(reduce_query)
     else:
         query = "(a:Question {object_uuid:'%s'})-" \
                 "[:POSSIBLE_ANSWER]->" \
                 "(res:Solution)" % self.kwargs[self.lookup_field]
         return NeoQuerySet(Solution, query=query, distinct=True,
                            descending=descending)\
             .filter("WHERE res.to_be_deleted=false")\
             .order_by(sort_by)
예제 #3
0
 def test_get_count_with_order_filter_distinct_reversed(self):
     for content in range(0, 15):
         SBContent(content="this is content number 2-%d" % content,
                   to_be_deleted=True).save()
     queryset = NeoQuerySet(SBContent, distinct=True, descending=True)\
         .order_by('ORDER BY res.created')\
         .filter("WHERE res.to_be_deleted=True")
     self.assertEqual(queryset.count(), 15)
     self.assertEqual(queryset[:1][0].content,
                      "this is content number 2-14")
예제 #4
0
 def missions(self, request, owner_username):
     query = '(quest:Quest {owner_username: "******"})-' \
             '[:EMBARKS_ON]->(res:Mission)' % owner_username
     if request.user.username == owner_username:
         queryset = NeoQuerySet(Mission, query=query)
     else:
         queryset = NeoQuerySet(
             Mission, query=query).filter('WHERE res.active')
     return self.get_paginated_response(
         MissionSerializer(self.paginate_queryset(queryset), many=True,
                           context={'request': request}).data)
예제 #5
0
 def test_get_list_with_filter(self):
     for content in range(0, 3):
         SBContent(content="this is content number 2-%d" % content,
                   to_be_deleted=True).save()
     queryset = NeoQuerySet(SBContent) \
         .filter("WHERE res.to_be_deleted=True")\
         .order_by('ORDER BY res.created')
     query_res = list(queryset)
     self.assertEqual(queryset.count(), 3)
     self.assertEqual(query_res[0].content, "this is content number 2-0")
     self.assertEqual(query_res[1].content, "this is content number 2-1")
     self.assertEqual(query_res[2].content, "this is content number 2-2")
예제 #6
0
 def get_queryset(self):
     query = '(res:Mission {active: true})<-[:EMBARKS_ON]-' \
             '(quest:Quest {active: true})'
     if self.request.query_params.get('affects', "") == "me":
         query = '(pleb:Pleb {username: "******"})-[:LIVES_AT]->' \
                 '(address:Address)-[:ENCOMPASSED_BY*..]->' \
                 '(location:Location)<-[:WITHIN]-' \
                 '(res:Mission {active: true})<-[:EMBARKS_ON]-' \
                 '(quest:Quest {active: true})' % self.request.user.username
     elif self.request.query_params.get('affects', "") == "friends":
         query = '(pleb:Pleb {username: "******"})-[:FOLLOWING]' \
                 '->(friends:Pleb)-[:LIVES_AT]->' \
                 '(address:Address)-[:ENCOMPASSED_BY*..]->' \
                 '(location:Location)<-[:WITHIN]-' \
                 '(res:Mission {active: true})<-[:EMBARKS_ON]-' \
                 '(quest:Quest {active: true})' % self.request.user.username
     elif self.request.query_params.get(
             'submitted_for_review', "") == "true":
         active = self.request.query_params.get('active', '')
         if active == 'true' or active == 'false':
             query = '(res:Mission {submitted_for_review:true, ' \
                     'active:%s})' % active
     return NeoQuerySet(
         Mission, query=query, distinct=True, descending=True) \
         .filter('WHERE NOT ((res)-[:FOCUSED_ON]->'
                 '(:Position {verified:false}))') \
         .order_by('ORDER BY res.created')
예제 #7
0
 def get_queryset(self):
     query_params = self.request.query_params
     if query_params.get("completed") == "true":
         query = "(res:Order {paid: true, completed: true})"
     else:
         query = "(res:Order {paid: true, completed: false})"
     return NeoQuerySet(
         Order, query=query, distinct=True, descending=True)\
         .order_by('ORDER BY res.created')
예제 #8
0
 def endorsed(self, request, username):
     query = '(p:Pleb {username:"******"})-' \
             '[:ENDORSES]->(res:Mission)' % username
     queryset = NeoQuerySet(Mission, query=query).filter('WHERE res.active')
     return self.get_paginated_response(
         self.serializer_class(self.paginate_queryset(queryset),
                               many=True,
                               context={
                                   'request': request
                               }).data)
예제 #9
0
 def following(self, request, username=None):
     queryset = NeoQuerySet(Pleb,
                            query='(p:Pleb {username:"******"})-[r:FOLLOWING]->'
                            '(res:Pleb)' %
                            username).filter('WHERE r.active')
     return self.get_paginated_response(
         PlebSerializerNeo(self.paginate_queryset(queryset),
                           many=True,
                           context={
                               'request': request
                           }).data)
예제 #10
0
 def get_queryset(self):
     sort_by = self.request.query_params.get('ordering', '')
     mission = self.request.query_params.get('mission', '')
     tagged_as = get_tagged_as(
         self.request.query_params.get('tagged_as', ''))
     sort_by, ordering = get_ordering(sort_by)
     mission_query = ''
     query = "(res:Question)%s" % tagged_as
     if ordering == "DESC":
         descending = True
     else:
         descending = False
     if mission:
         mission_query = '(m:Mission {object_uuid:"%s"})-' \
                         '[:ASSOCIATED_WITH]->' % mission
     if sort_by == "" or sort_by == "vote_count":
         query = "%s(res:Question)%s " \
                 "WHERE res.to_be_deleted=false " \
                 "OPTIONAL MATCH (res)<-[vs:PLEB_VOTES]-() " \
                 "WHERE vs.active=True " % (mission_query, tagged_as)
         queryset = NeoQuerySet(
             Question, query=query, distinct=True,
             descending=not descending)\
             .order_by(", reduce(vote_count = 0, v in collect(vs)| "
                       "CASE WHEN v.vote_type=True THEN vote_count+1 "
                       "WHEN v.vote_type=False THEN vote_count-1 "
                       "ELSE vote_count END) as reduce_res "
                       "ORDER BY reduce_res")
     else:
         queryset = NeoQuerySet(
             Question, query=query, distinct=True, descending=descending) \
             .filter('WHERE res.to_be_deleted=false') \
             .order_by(sort_by)
     # Quick cache implementation to reduce load of refresh clickers
     # Under load neo takes about 15-30 seconds to store off the
     # updates of a vote anyways so this can be added when necessary
     # if sort_by == "" or sort_by == "vote_count":
     #    if questions is None:
     #        cache.set('question_list_vote_sort', queryset, 30)
     return queryset
예제 #11
0
 def public_content(self, request, username=None):
     filter_by = request.query_params.get('filter', "")
     try:
         additional_params = get_filter_params(filter_by, SBContent())
     except (IndexError, KeyError, ValueError):
         return Response(errors.QUERY_DETERMINATION_EXCEPTION,
                         status=status.HTTP_400_BAD_REQUEST)
     query = '(res:SBPublicContent)-[:OWNED_BY]->(a:Pleb ' \
             '{username: "******"})' % username
     queryset = NeoQuerySet(SBContent, query=query).filter(
         'WHERE res.to_be_deleted=false %s' % additional_params)
     return self.get_paginated_response(
         self.serializer_class(self.paginate_queryset(queryset),
                               many=True,
                               context={
                                   'request': request
                               }).data)
예제 #12
0
 def test_get_spliced_list(self):
     queryset = NeoQuerySet(SBContent).order_by('ORDER BY res.created')
     generated_list = queryset[:5]
     self.assertEqual(len(generated_list), 5)
     self.assertEqual(generated_list[0].content, "this is content number 0")
     self.assertEqual(generated_list[1].content, "this is content number 1")
     self.assertEqual(generated_list[2].content, "this is content number 2")
     self.assertEqual(generated_list[3].content, "this is content number 3")
     self.assertEqual(generated_list[4].content, "this is content number 4")
     generated_list = queryset[20:25]
     self.assertEqual(len(generated_list), 5)
     self.assertEqual(generated_list[0].content,
                      "this is content number 20")
     self.assertEqual(generated_list[1].content,
                      "this is content number 21")
     self.assertEqual(generated_list[2].content,
                      "this is content number 22")
     self.assertEqual(generated_list[3].content,
                      "this is content number 23")
     self.assertEqual(generated_list[4].content,
                      "this is content number 24")
     generated_list = queryset[30:40]
     self.assertEqual(len(generated_list), 10)
     self.assertEqual(generated_list[0].content,
                      "this is content number 30")
     self.assertEqual(generated_list[1].content,
                      "this is content number 31")
     self.assertEqual(generated_list[2].content,
                      "this is content number 32")
     self.assertEqual(generated_list[3].content,
                      "this is content number 33")
     self.assertEqual(generated_list[4].content,
                      "this is content number 34")
     self.assertEqual(generated_list[5].content,
                      "this is content number 35")
     self.assertEqual(generated_list[6].content,
                      "this is content number 36")
     self.assertEqual(generated_list[7].content,
                      "this is content number 37")
     self.assertEqual(generated_list[8].content,
                      "this is content number 38")
     self.assertEqual(generated_list[9].content,
                      "this is content number 39")
예제 #13
0
 def test_get_spliced_list_reverse(self):
     queryset = NeoQuerySet(SBContent, descending=True)\
         .order_by('ORDER BY res.created')
     generated_list = queryset[:5]
     self.assertEqual(len(generated_list), 5)
     self.assertEqual(generated_list[0].content,
                      "this is content number 49")
     self.assertEqual(generated_list[1].content,
                      "this is content number 48")
     self.assertEqual(generated_list[2].content,
                      "this is content number 47")
     self.assertEqual(generated_list[3].content,
                      "this is content number 46")
     self.assertEqual(generated_list[4].content,
                      "this is content number 45")
     generated_list = queryset[20:25]
     self.assertEqual(len(generated_list), 5)
     self.assertEqual(generated_list[0].content,
                      "this is content number 29")
     self.assertEqual(generated_list[1].content,
                      "this is content number 28")
     self.assertEqual(generated_list[2].content,
                      "this is content number 27")
     self.assertEqual(generated_list[3].content,
                      "this is content number 26")
     self.assertEqual(generated_list[4].content,
                      "this is content number 25")
     generated_list = queryset[40:50]
     self.assertEqual(len(generated_list), 10)
     self.assertEqual(generated_list[0].content, "this is content number 9")
     self.assertEqual(generated_list[1].content, "this is content number 8")
     self.assertEqual(generated_list[2].content, "this is content number 7")
     self.assertEqual(generated_list[3].content, "this is content number 6")
     self.assertEqual(generated_list[4].content, "this is content number 5")
     self.assertEqual(generated_list[5].content, "this is content number 4")
     self.assertEqual(generated_list[6].content, "this is content number 3")
     self.assertEqual(generated_list[7].content, "this is content number 2")
     self.assertEqual(generated_list[8].content, "this is content number 1")
     self.assertEqual(generated_list[9].content, "this is content number 0")
예제 #14
0
class ProfileViewSet(viewsets.ModelViewSet):
    """
    This endpoint provides information for each of the registered users. It
    should not be used for creating users though as we lean on the Framework
    to accomplish user creation and authentication. This however is where all
    non-base attributes can be accessed. Users can access any other user's
    information as long as their authenticated but are limited to Read access
    if they are not the owner of the profile.

    Limitations:
    Currently we don't have fine grained permissions that enable us to restrict
    access to certain fields based on friendship status or user set permissions.
    We instead manage this in the frontend and only allow users browsing the
    web interface to see certain information. This is all done in the template
    though and any tech savvy person will still be able to check out the
    endpoint for the information. We'll want to eventually limit that here
    or in the serializer rather than higher up on the stack.
    """
    serializer_class = PlebSerializerNeo
    lookup_field = "username"
    queryset = NeoQuerySet(Pleb)
    permission_classes = (IsAnonCreateReadOnlyOrIsAuthenticated, )

    def get_object(self):
        return Pleb.get(self.kwargs[self.lookup_field])

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = Pleb.get(username=request.user.username, cache_buster=True)
        serializer = self.get_serializer(instance,
                                         data=request.data,
                                         partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        return Response(serializer.data)

    def destroy(self, request, *args, **kwargs):
        return Response({"detail": "TBD"},
                        status=status.HTTP_501_NOT_IMPLEMENTED)

    @detail_route(methods=['get'], serializer_class=QuestionSerializerNeo)
    def questions(self, request, username=None):
        filter_by = request.query_params.get('filter', "")
        try:
            additional_params = get_filter_params(filter_by, SBContent())
        except (IndexError, KeyError, ValueError):
            return Response(errors.QUERY_DETERMINATION_EXCEPTION,
                            status=status.HTTP_400_BAD_REQUEST)
        query = '(a:Pleb {username: "******"})<-[:OWNED_BY]-' \
                '(res:Question)' % username
        queryset = NeoQuerySet(Question, query=query).filter(
            'WHERE res.to_be_deleted=false %s' % additional_params)
        return self.get_paginated_response(
            self.serializer_class(self.paginate_queryset(queryset),
                                  many=True,
                                  context={
                                      'request': request
                                  }).data)

    @detail_route(methods=['get'], serializer_class=ContentSerializer)
    def public_content(self, request, username=None):
        filter_by = request.query_params.get('filter', "")
        try:
            additional_params = get_filter_params(filter_by, SBContent())
        except (IndexError, KeyError, ValueError):
            return Response(errors.QUERY_DETERMINATION_EXCEPTION,
                            status=status.HTTP_400_BAD_REQUEST)
        query = '(res:SBPublicContent)-[:OWNED_BY]->(a:Pleb ' \
                '{username: "******"})' % username
        queryset = NeoQuerySet(SBContent, query=query).filter(
            'WHERE res.to_be_deleted=false %s' % additional_params)
        return self.get_paginated_response(
            self.serializer_class(self.paginate_queryset(queryset),
                                  many=True,
                                  context={
                                      'request': request
                                  }).data)

    @detail_route(methods=['get'],
                  permission_classes=(IsAuthenticatedOrReadOnly, ))
    def public(self, request, username=None):
        return get_public_content(self, username, request)

    @detail_route(methods=['post'],
                  permission_classes=(IsAuthenticated, IsSelfOrReadOnly))
    def follow(self, request, username=None):
        """
        This endpoint allows users to follow other users.
        :param username:
        :param request:
        """
        queryset = self.get_object()
        is_following = queryset.is_following(request.user.username)
        if is_following:
            return Response(
                {
                    "detail": "Already following user.",
                    "status": status.HTTP_200_OK
                },
                status=status.HTTP_200_OK)
        queryset.follow(request.user.username)
        return Response(
            {
                "detail": "Successfully followed user.",
                "status": status.HTTP_200_OK
            },
            status=status.HTTP_200_OK)

    @detail_route(methods=['get'], permission_classes=(IsAuthenticated, ))
    def followers(self, request, username=None):
        queryset = NeoQuerySet(Pleb,
                               query='(p:Pleb {username:"******"})<-[r:FOLLOWING]-'
                               '(res:Pleb)' %
                               username).filter('WHERE r.active')
        return self.get_paginated_response(
            PlebSerializerNeo(self.paginate_queryset(queryset),
                              many=True,
                              context={
                                  'request': request
                              }).data)

    @detail_route(methods=['get'], permission_classes=(IsAuthenticated, ))
    def following(self, request, username=None):
        queryset = NeoQuerySet(Pleb,
                               query='(p:Pleb {username:"******"})-[r:FOLLOWING]->'
                               '(res:Pleb)' %
                               username).filter('WHERE r.active')
        return self.get_paginated_response(
            PlebSerializerNeo(self.paginate_queryset(queryset),
                              many=True,
                              context={
                                  'request': request
                              }).data)

    @detail_route(methods=['post'],
                  permission_classes=(IsAuthenticated, IsSelfOrReadOnly))
    def unfollow(self, request, username=None):
        """
        This endpoint allows users to unfollow other users.
        :param username:
        :param request:
        """
        queryset = self.get_object()
        is_following = queryset.is_following(request.user.username)
        if not is_following:
            return Response(
                {
                    "detail": "Already not following user.",
                    "status": status.HTTP_200_OK
                },
                status=status.HTTP_200_OK)
        queryset.unfollow(request.user.username)
        return Response(
            {
                "detail": "Successfully unfollowed user.",
                "status": status.HTTP_200_OK
            },
            status=status.HTTP_200_OK)

    @detail_route(methods=['get'])
    def friends(self, request, username=None):
        # Discuss, does it make more sense to have friends here or have a
        # separate endpoint /v1/friends/ that just
        # lists all the friends for the user who is making the query? I think
        # both places are valid. /v1/profiles/username/friends does enable you
        # to look at friends of friends more easily
        # However /v1/friends/username/ allows for a simpler defriend and
        # accessing method as you're able to go from
        # /v1/friends/ to /v1/friends/username/ to your method rather than
        # /v1/profiles/username/friends/ to /v1/profiles/username/ to your
        # method. But maybe we make both available.
        # Added in the ORDER BY to ensure order for the infinite scroll
        # loading on a users friend list page
        query = 'MATCH (a:Pleb {username: "******"})-' \
                '[:FRIENDS_WITH {active: true}]->' \
                '(b:Pleb) RETURN DISTINCT b ORDER BY b.first_name' % username
        res, col = db.cypher_query(query)
        [row[0].pull() for row in res]
        queryset = [Pleb.inflate(row[0]) for row in res]
        page = self.paginate_queryset(queryset)
        serializer = self.get_serializer(page,
                                         many=True,
                                         context={'request': request})
        return self.get_paginated_response(serializer.data)

    @detail_route(methods=['get'], permission_classes=(IsAuthenticated, ))
    def reputation(self, request, username=None):
        user = self.get_object()
        return Response(
            {
                "reputation": user.reputation,
                "reputation_change": user.reputation_change
            },
            status=status.HTTP_200_OK)

    @detail_route(methods=['get'], permission_classes=(IsAuthenticated, ))
    def senators(self, request, username=None):
        # TODO this may be able to be refined to [:REPRESENTED_BY]->(s:Senator)
        senators = cache.get("%s_senators" % username)
        if senators is None:
            query = "MATCH (a:Pleb {username: '******'})-[:HAS_SENATOR]->" \
                    "(s:PublicOfficial) RETURN s" % username
            res, col = db.cypher_query(query)
            [row[0].pull() for row in res]
            senators = [PublicOfficial.inflate(row[0]) for row in res]
            cache.set("%s_senators" % username, senators, timeout=1800)
        if len(senators) == 0:
            return Response([], status=status.HTTP_200_OK)
        return Response(PublicOfficialSerializer(senators, many=True).data,
                        status=status.HTTP_200_OK)

    @detail_route(methods=['get'], permission_classes=(IsAuthenticated, ))
    def house_representative(self, request, username=None):
        # TODO this may be able to be refined to
        # [:REPRESENTED_BY]->(s:HouseRepresentative)
        house_rep = cache.get("%s_house_representative" % username)
        if house_rep is None:
            query = "MATCH (a:Pleb {username: '******'})-" \
                    "[:HAS_HOUSE_REPRESENTATIVE]->" \
                    "(s:PublicOfficial) RETURN s" % username
            res, col = db.cypher_query(query)
            try:
                house_rep = PublicOfficial.inflate(res[0][0])
                cache.set("%s_house_representative" % username,
                          house_rep,
                          timeout=1800)
            except IndexError:
                return Response({}, status=status.HTTP_200_OK)
        return Response(PublicOfficialSerializer(house_rep).data,
                        status=status.HTTP_200_OK)

    @detail_route(methods=['get'], permission_classes=(IsAuthenticated, ))
    def president(self, request, username=None):
        president = cache.get("%s_president" % username)
        if president is None:
            query = 'MATCH (p:Pleb {username:"******"})-[:HAS_PRESIDENT]->' \
                    '(o:PublicOfficial) RETURN o' % username
            res, _ = db.cypher_query(query)
            try:
                president = PublicOfficial.inflate(res[0][0])
                cache.set("%s_president" % username, president, timeout=1800)
            except IndexError:
                return Response({}, status=status.HTTP_200_OK)
        return Response(PublicOfficialSerializer(president).data,
                        status=status.HTTP_200_OK)

    @detail_route(methods=['get'],
                  serializer_class=MissionSerializer,
                  permission_classes=(IsAuthenticatedOrReadOnly, ))
    def missions(self, request, username):
        query = '(quest:Quest {owner_username: "******"})-' \
                '[:EMBARKS_ON]->(res:Mission)' % username
        queryset = NeoQuerySet(Mission, query=query).filter('WHERE res.active')
        return self.get_paginated_response(
            self.serializer_class(self.paginate_queryset(queryset),
                                  many=True,
                                  context={
                                      'request': request
                                  }).data)

    @detail_route(methods=["GET"],
                  serializer_class=MissionSerializer,
                  permission_classes=(IsAuthenticatedOrReadOnly, ))
    def endorsed(self, request, username):
        query = '(p:Pleb {username:"******"})-' \
                '[:ENDORSES]->(res:Mission)' % username
        queryset = NeoQuerySet(Mission, query=query).filter('WHERE res.active')
        return self.get_paginated_response(
            self.serializer_class(self.paginate_queryset(queryset),
                                  many=True,
                                  context={
                                      'request': request
                                  }).data)
예제 #15
0
 def get_queryset(self):
     return NeoQuerySet(Quest)
예제 #16
0
 def test_get_count_with_order(self):
     queryset = NeoQuerySet(SBContent).order_by('ORDER BY res.created')
     self.assertEqual(queryset.count(), 50)
예제 #17
0
 def get_queryset(self):
     return NeoQuerySet(NewsArticle)
예제 #18
0
 def test_get_count_without_order(self):
     queryset = NeoQuerySet(SBContent)
     self.assertEqual(queryset.count(), 50)
예제 #19
0
 def test_get_list(self):
     queryset = NeoQuerySet(SBContent)
     generated_list = list(queryset)
     self.assertEqual(len(generated_list), 50)