From 61ac0b0468179ffe34928f9ac34cfbcaee86ca76 Mon Sep 17 00:00:00 2001 From: Lauren Barker Date: Mon, 3 Jul 2017 10:25:29 -0400 Subject: [PATCH 1/4] Fix user endpoint and add tests --- api/views/workflow.py | 4 +-- tests/api/test_user_endpoint.py | 49 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/api/test_user_endpoint.py diff --git a/api/views/workflow.py b/api/views/workflow.py index 8da559fb3..30e1c906c 100644 --- a/api/views/workflow.py +++ b/api/views/workflow.py @@ -22,7 +22,7 @@ from api.permissions import ReadOnlyOrTokenHasScopeOrIsAuthenticated from api.serializers import FullNormalizedDataSerializer, BasicNormalizedDataSerializer, \ RawDatumSerializer, ShareUserSerializer, SourceSerializer -from share.models import RawDatum, NormalizedData, Source, SourceConfig, Transformer +from share.models import RawDatum, NormalizedData, Source, SourceConfig, Transformer, ShareUser from share.tasks import disambiguate from share.harvest.serialization import DictSerializer from share.harvest.base import FetchResult @@ -39,7 +39,7 @@ class ShareUserViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = ShareUserSerializer def get_queryset(self): - return [self.request.user, ] + return ShareUser.objects.filter(pk=self.request.user.pk) class SourceViewSet(viewsets.ReadOnlyModelViewSet): diff --git a/tests/api/test_user_endpoint.py b/tests/api/test_user_endpoint.py new file mode 100644 index 000000000..ac4b1cb29 --- /dev/null +++ b/tests/api/test_user_endpoint.py @@ -0,0 +1,49 @@ +import pytest +import json + + +@pytest.fixture +def post_body_share_user(): + return json.dumps({ + 'data': { + 'type': 'ShareUser', + 'attributes': { + 'username': 'TestUser' + } + } + }) + + +@pytest.mark.django_db +class TestSourcesGet: + endpoint = '/api/v2/user/' + + def test_logged_in(self, client, share_user): + resp = client.get(self.endpoint, HTTP_AUTHORIZATION=share_user.authorization()) + assert resp.status_code == 200 + assert resp.json()['meta']['pagination']['count'] == 1 + + def test_not_logged_in(self, client): + resp = client.get(self.endpoint) + assert resp.status_code == 200 + assert resp.json()['meta']['pagination']['count'] == 0 + + +@pytest.mark.django_db +class TestSourcesPost: + endpoint = '/api/v2/user/' + + def test_unauthorized_post(self, client, post_body_share_user): + assert client.post( + self.endpoint, + post_body_share_user, + content_type='application/vnd.api+json' + ).status_code == 401 + + def test_authorized_post(self, client, share_user, post_body_share_user): + assert client.post( + self.endpoint, + post_body_share_user, + content_type='application/vnd.api+json', + HTTP_AUTHORIZATION=share_user.authorization(), + ).status_code == 405 From 85e792ef22dd87e02b2d79fc0e6240615ce10714 Mon Sep 17 00:00:00 2001 From: Oludare Oludare Date: Tue, 6 Jun 2017 09:48:56 -0400 Subject: [PATCH 2/4] Creating new endpoint for Source Config --- api/serializers.py | 6 ++++++ api/urls.py | 1 + api/views/__init__.py | 1 + api/views/sourceConfig.py | 10 ++++++++++ 4 files changed, 18 insertions(+) create mode 100644 api/views/sourceConfig.py diff --git a/api/serializers.py b/api/serializers.py index 1eaf5f3f0..ffd6f7570 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -139,6 +139,12 @@ class Meta: fields = ('name', 'home_page', 'long_title', 'icon') +class SourceConfigSerializer(ShareModelSerializer): + class Meta: + model = models.SourceConfig + fields = '__all__' + + class SiteBannerSerializer(ShareModelSerializer): color = serializers.SerializerMethodField() diff --git a/api/urls.py b/api/urls.py index ec60b1804..5fb0e50bc 100644 --- a/api/urls.py +++ b/api/urls.py @@ -86,6 +86,7 @@ def register_url(self, subclass, viewset): register_route(r'rawdata', views.RawDatumViewSet) register_route(r'user', views.ShareUserViewSet) register_route(r'sources', views.SourceViewSet) +register_route(r'sourceConfig', views.SourceConfigViewSet) router.register(r'normalizeddata', views.NormalizedDataViewSet, base_name='normalizeddata') diff --git a/api/views/__init__.py b/api/views/__init__.py index 68bec4096..e3653bca0 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -5,3 +5,4 @@ from .registration import * # noqa from .schema import * # noqa from .banner import * # noqa +from .sourceConfig import * # noqa diff --git a/api/views/sourceConfig.py b/api/views/sourceConfig.py new file mode 100644 index 000000000..7485a3021 --- /dev/null +++ b/api/views/sourceConfig.py @@ -0,0 +1,10 @@ +from rest_framework import viewsets + +from api.serializers import SourceConfigSerializer +from share.models import SourceConfig + +class SourceConfigViewSet(viewsets.ReadOnlyModelViewSet): + serializer_class = SourceConfigSerializer + + def get_queryset(self): + return SourceConfig.objects.all() From d7109675417a06c46d5607b1076ee60e40028507 Mon Sep 17 00:00:00 2001 From: Oludare Olugbemi Date: Wed, 28 Jun 2017 13:23:41 -0400 Subject: [PATCH 3/4] PR Changes --- api/urls.py | 2 +- api/views/__init__.py | 2 +- api/views/{sourceConfig.py => source_config.py} | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) rename api/views/{sourceConfig.py => source_config.py} (76%) diff --git a/api/urls.py b/api/urls.py index 5fb0e50bc..21ed06a85 100644 --- a/api/urls.py +++ b/api/urls.py @@ -86,7 +86,7 @@ def register_url(self, subclass, viewset): register_route(r'rawdata', views.RawDatumViewSet) register_route(r'user', views.ShareUserViewSet) register_route(r'sources', views.SourceViewSet) -register_route(r'sourceConfig', views.SourceConfigViewSet) +register_route(r'source_config', views.SourceConfigViewSet) router.register(r'normalizeddata', views.NormalizedDataViewSet, base_name='normalizeddata') diff --git a/api/views/__init__.py b/api/views/__init__.py index e3653bca0..634d7ec46 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -5,4 +5,4 @@ from .registration import * # noqa from .schema import * # noqa from .banner import * # noqa -from .sourceConfig import * # noqa +from .source_config import * # noqa diff --git a/api/views/sourceConfig.py b/api/views/source_config.py similarity index 76% rename from api/views/sourceConfig.py rename to api/views/source_config.py index 7485a3021..515bbc627 100644 --- a/api/views/sourceConfig.py +++ b/api/views/source_config.py @@ -5,6 +5,4 @@ class SourceConfigViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = SourceConfigSerializer - - def get_queryset(self): - return SourceConfig.objects.all() + queryset = SourceConfig.objects.all() From 0ff51a2392b4da9637a06ac320bfb32a87d3c09d Mon Sep 17 00:00:00 2001 From: Lauren Barker Date: Wed, 12 Jul 2017 09:36:29 -0400 Subject: [PATCH 4/4] Add harvester and tranformer endpoints Inherit from ShareObjectViewSet for SourceViewSet Get configs from API --- api/serializers.py | 16 ++++++++++++++-- api/urls.py | 4 +++- api/views/source_config.py | 23 +++++++++++++++++++---- api/views/workflow.py | 7 +++++-- project/settings.py | 1 + tests/api/test_sources_endpoint.py | 11 +++++++++-- 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/api/serializers.py b/api/serializers.py index ffd6f7570..2edcf61bf 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -136,7 +136,7 @@ class Meta: class SourceSerializer(ShareModelSerializer): class Meta: model = models.Source - fields = ('name', 'home_page', 'long_title', 'icon') + fields = '__all__' class SourceConfigSerializer(ShareModelSerializer): @@ -144,7 +144,19 @@ class Meta: model = models.SourceConfig fields = '__all__' - + +class HarvesterSerializer(ShareModelSerializer): + class Meta: + model = models.Harvester + fields = '__all__' + + +class TransformerSerializer(ShareModelSerializer): + class Meta: + model = models.Transformer + fields = '__all__' + + class SiteBannerSerializer(ShareModelSerializer): color = serializers.SerializerMethodField() diff --git a/api/urls.py b/api/urls.py index 21ed06a85..145ef4f39 100644 --- a/api/urls.py +++ b/api/urls.py @@ -86,7 +86,9 @@ def register_url(self, subclass, viewset): register_route(r'rawdata', views.RawDatumViewSet) register_route(r'user', views.ShareUserViewSet) register_route(r'sources', views.SourceViewSet) -register_route(r'source_config', views.SourceConfigViewSet) +register_route(r'sourceconfigs', views.SourceConfigViewSet) +register_route(r'harvesters', views.HarvesterViewSet) +register_route(r'transformers', views.TransformerViewSet) router.register(r'normalizeddata', views.NormalizedDataViewSet, base_name='normalizeddata') diff --git a/api/views/source_config.py b/api/views/source_config.py index 515bbc627..3d69be09a 100644 --- a/api/views/source_config.py +++ b/api/views/source_config.py @@ -1,8 +1,23 @@ -from rest_framework import viewsets +from api.serializers import SourceConfigSerializer, HarvesterSerializer, TransformerSerializer +from api.views.share import ShareObjectViewSet +from api.pagination import FuzzyPageNumberPagination -from api.serializers import SourceConfigSerializer -from share.models import SourceConfig +from share.models import SourceConfig, Harvester, Transformer -class SourceConfigViewSet(viewsets.ReadOnlyModelViewSet): + +class SourceConfigViewSet(ShareObjectViewSet): + pagination_class = FuzzyPageNumberPagination serializer_class = SourceConfigSerializer queryset = SourceConfig.objects.all() + + +class HarvesterViewSet(ShareObjectViewSet): + pagination_class = FuzzyPageNumberPagination + serializer_class = HarvesterSerializer + queryset = Harvester.objects.all() + + +class TransformerViewSet(ShareObjectViewSet): + pagination_class = FuzzyPageNumberPagination + serializer_class = TransformerSerializer + queryset = Transformer.objects.all() diff --git a/api/views/workflow.py b/api/views/workflow.py index 30e1c906c..f1a319ef7 100644 --- a/api/views/workflow.py +++ b/api/views/workflow.py @@ -27,6 +27,8 @@ from share.harvest.serialization import DictSerializer from share.harvest.base import FetchResult from share.util import IDObfuscator +from api.views.share import ShareObjectViewSet +from api.pagination import FuzzyPageNumberPagination logger = logging.getLogger(__name__) __all__ = ('NormalizedDataViewSet', 'RawDatumViewSet', 'ShareUserViewSet', 'SourceViewSet', 'V1DataView') @@ -42,18 +44,19 @@ def get_queryset(self): return ShareUser.objects.filter(pk=self.request.user.pk) -class SourceViewSet(viewsets.ReadOnlyModelViewSet): +class SourceViewSet(ShareObjectViewSet): filter_backends = (filters.OrderingFilter, ) ordering = ('id', ) ordering_fields = ('long_title', ) serializer_class = SourceSerializer permission_classes = [DjangoModelPermissionsOrAnonReadOnly, ] + pagination_class = FuzzyPageNumberPagination queryset = Source.objects.none() # Required for DjangoModelPermissions VALID_IMAGE_TYPES = ('image/png', 'image/jpeg') - def get_queryset(self): + def get_queryset(self, *args): return Source.objects.exclude(icon='').exclude(is_deleted=True) def create(self, request, *args, **kwargs): diff --git a/project/settings.py b/project/settings.py index 918752ed4..19ef0edde 100644 --- a/project/settings.py +++ b/project/settings.py @@ -455,6 +455,7 @@ EMBER_SHARE_PREFIX = os.environ.get('EMBER_SHARE_PREFIX', 'share' if DEBUG else '') EMBER_SHARE_URL = os.environ.get('EMBER_SHARE_URL', 'http://localhost:4200').rstrip('/') + '/' SHARE_API_URL = os.environ.get('SHARE_API_URL', 'http://localhost:8000').rstrip('/') + '/' +SHARE_API_URL_PRODUCTION = os.environ.get('SHARE_API_URL_PRODUCTION', 'https://share.osf.io/api/v2').rstrip('/') + '/' SHARE_WEB_URL = os.environ.get('SHARE_WEB_URL', SHARE_API_URL + EMBER_SHARE_PREFIX).rstrip('/') + '/' SHARE_USER_AGENT = os.environ.get('SHARE_USER_AGENT', 'SHAREbot/{} (+{})'.format(VERSION, SHARE_WEB_URL)) diff --git a/tests/api/test_sources_endpoint.py b/tests/api/test_sources_endpoint.py index 0b372575c..93c5384cd 100644 --- a/tests/api/test_sources_endpoint.py +++ b/tests/api/test_sources_endpoint.py @@ -3,6 +3,7 @@ import time import httpretty +from furl import furl from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType @@ -18,8 +19,8 @@ def exceptionCallback(request, uri, headers): - time.sleep(6) - return (400, headers, uri) + time.sleep(6) + return (400, headers, uri) @pytest.fixture @@ -110,6 +111,12 @@ def test_no_icon(self, client): assert resp.status_code == 200 assert resp.json()['meta']['pagination']['count'] == total - 1 + def test_get_object(self, client): + s = Source.objects.first() + resp = client.get(furl(self.endpoint).join(IDObfuscator.encode_id(s.pk, Source) + '/').url) + assert resp.status_code == 200 + assert IDObfuscator.decode_id(resp.json()['data']['id']) == s.pk + @pytest.mark.django_db class TestSourcesPost: