From c08f0761c5c49c666d22223ff18e1da5a6b73d37 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Thu, 16 Aug 2018 21:49:19 +0200 Subject: Add a simple `list` / `retrieve` documentation link endpoint. --- api/serializers.py | 8 +++- api/tests/test_documentation_links.py | 72 +++++++++++++++++++++++++++++++++++ api/urls.py | 4 +- api/viewsets.py | 44 +++++++++++++++++++-- 4 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 api/tests/test_documentation_links.py (limited to 'api') diff --git a/api/serializers.py b/api/serializers.py index cac94873..1e18dfef 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -1,6 +1,12 @@ from rest_framework.serializers import ModelSerializer -from .models import SnakeName +from .models import DocumentationLink, SnakeName + + +class DocumentationLinkSerializer(ModelSerializer): + class Meta: + model = DocumentationLink + fields = ('package', 'base_url', 'inventory_url') class SnakeNameSerializer(ModelSerializer): diff --git a/api/tests/test_documentation_links.py b/api/tests/test_documentation_links.py new file mode 100644 index 00000000..c3ffe5bb --- /dev/null +++ b/api/tests/test_documentation_links.py @@ -0,0 +1,72 @@ +from django_hosts.resolvers import reverse + +from .base import APISubdomainTestCase +from ..models import DocumentationLink + + +class UnauthedDocumentationLinkAPITests(APISubdomainTestCase): + def setUp(self): + super().setUp() + self.client.force_authenticate(user=None) + + def test_detail_lookup_returns_401(self): + url = reverse('bot:documentationlink-detail', args=('whatever',), host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 401) + + def test_list_returns_401(self): + url = reverse('bot:documentationlink-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 401) + +class EmptyDatabaseDocumentationLinkAPITests(APISubdomainTestCase): + def test_detail_lookup_returns_404(self): + url = reverse('bot:documentationlink-detail', args=('whatever',), host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 404) + + def test_list_all_returns_empty_list(self): + url = reverse('bot:documentationlink-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), []) + + +class DetailLookupDocumentationLinkAPITests(APISubdomainTestCase): + @classmethod + def setUpTestData(cls): + cls.doc_link = DocumentationLink.objects.create( + package='testpackage', + base_url='https://example.com', + inventory_url='https://example.com' + ) + + cls.doc_json = { + 'package': cls.doc_link.package, + 'base_url': cls.doc_link.base_url, + 'inventory_url': cls.doc_link.inventory_url + } + + def test_detail_lookup_unknown_package_returns_404(self): + url = reverse('bot:documentationlink-detail', args=('whatever',), host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 404) + + def test_detail_lookup_created_package_returns_package(self): + url = reverse('bot:documentationlink-detail', args=(self.doc_link.package,), host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), self.doc_json) + + def test_list_all_packages_shows_created_package(self): + url = reverse('bot:documentationlink-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), [self.doc_json]) diff --git a/api/urls.py b/api/urls.py index b0e104cd..78a310f6 100644 --- a/api/urls.py +++ b/api/urls.py @@ -2,13 +2,15 @@ from django.urls import include, path from rest_framework.routers import SimpleRouter from .views import HealthcheckView -from .viewsets import SnakeNameViewSet +from .viewsets import DocumentationLinkViewSet, SnakeNameViewSet # http://www.django-rest-framework.org/api-guide/routers/#simplerouter bot_router = SimpleRouter(trailing_slash=False) +bot_router.register(r'documentation-links', DocumentationLinkViewSet) bot_router.register(r'snake-names', SnakeNameViewSet, base_name='snakename') + app_name = 'api' urlpatterns = ( # Build URLs using something like... diff --git a/api/viewsets.py b/api/viewsets.py index 5e38bdc9..48b2f226 100644 --- a/api/viewsets.py +++ b/api/viewsets.py @@ -1,13 +1,49 @@ +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.response import Response -from rest_framework.viewsets import ViewSet +from rest_framework.viewsets import GenericViewSet, ViewSet -from .models import SnakeName -from .serializers import SnakeNameSerializer +from .models import DocumentationLink, SnakeName +from .serializers import DocumentationLinkSerializer, SnakeNameSerializer + + +class DocumentationLinkViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): + """ + View providing documentation links used in the bot's `Doc` cog. + + ## Routes + ### GET /bot/documentation-links + Return all documentation links in the database in the following format: + + >>> [ + ... { + ... 'package': 'flask', + ... 'base_url': 'https://flask.pocoo.org/docs/dev', + ... 'inventory_url': 'https://flask.pocoo.org/docs/objects.inv' + ... }, + ... # ... + ... ] + + ### GET /bot/documentation-links/ + Look up the documentation object for the given `package`. + If an entry exists, return data in the following format: + + >>> { + ... 'package': 'flask', + ... 'base_url': 'https://flask.pocoo.org/docs/dev', + ... 'inventory_url': 'https://flask.pocoo.org/docs/objects.inv' + ... } + + Otherwise, if no entry for the given `package` exists, returns 404. + """ + + queryset = DocumentationLink.objects.all() + serializer_class = DocumentationLinkSerializer + lookup_field = 'package' class SnakeNameViewSet(ViewSet): """ - View of snake names for the bot's snake cog from our first code jam's winners. + View providing snake names for the bot's snake cog from our first code jam's winners. ## Routes ### GET /bot/snake-names -- cgit v1.2.3