From ba77a40f732d758ca285e1d058f208ff1b77a472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= Date: Tue, 7 Jun 2022 10:41:13 +0200 Subject: [PATCH] api: list agenda's check types (#66008) --- lingo/api/__init__.py | 0 lingo/api/urls.py | 27 +++++++++++++++++++++++ lingo/api/utils.py | 51 +++++++++++++++++++++++++++++++++++++++++++ lingo/api/views.py | 39 +++++++++++++++++++++++++++++++++ lingo/settings.py | 2 ++ lingo/urls.py | 2 ++ tests/test_api.py | 35 +++++++++++++++++++++++++++++ 7 files changed, 156 insertions(+) create mode 100644 lingo/api/__init__.py create mode 100644 lingo/api/urls.py create mode 100644 lingo/api/utils.py create mode 100644 lingo/api/views.py create mode 100644 tests/test_api.py diff --git a/lingo/api/__init__.py b/lingo/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lingo/api/urls.py b/lingo/api/urls.py new file mode 100644 index 0000000..d2d6893 --- /dev/null +++ b/lingo/api/urls.py @@ -0,0 +1,27 @@ +# lingo - payment and billing system +# Copyright (C) 2022 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url( + r'^agenda/(?P[\w-]+)/check-types/$', + views.agenda_check_type_list, + name='api-agenda-check-types', + ), +] diff --git a/lingo/api/utils.py b/lingo/api/utils.py new file mode 100644 index 0000000..77450e9 --- /dev/null +++ b/lingo/api/utils.py @@ -0,0 +1,51 @@ +# lingo - payment and billing system +# Copyright (C) 2022 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.utils.translation import gettext_lazy as _ +from rest_framework.response import Response +from rest_framework.views import exception_handler as DRF_exception_handler + + +class APIError(Exception): + http_status = 200 + + def __init__(self, message, *args, err=1, err_class=None, errors=None): + self.err_desc = _(message) % args + self.err = err + self.err_class = err_class or message % args + self.errors = errors + super().__init__(self.err_desc) + + def to_response(self): + data = { + 'err': self.err, + 'err_class': self.err_class, + 'err_desc': self.err_desc, + } + if self.errors: + data['errors'] = self.errors + return Response(data, status=self.http_status) + + +class APIErrorBadRequest(APIError): + http_status = 400 + + +def exception_handler(exc, context): + if isinstance(exc, APIError): + return exc.to_response() + + return DRF_exception_handler(exc, context) diff --git a/lingo/api/views.py b/lingo/api/views.py new file mode 100644 index 0000000..b9da3be --- /dev/null +++ b/lingo/api/views.py @@ -0,0 +1,39 @@ +# lingo - payment and billing system +# Copyright (C) 2022 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.shortcuts import get_object_or_404 +from rest_framework.views import APIView + +from lingo.agendas.models import Agenda +from lingo.api.utils import Response + + +class AgendaCheckTypeList(APIView): + permission_classes = () + + def get(self, request, agenda_identifier=None, format=None): + agenda = get_object_or_404(Agenda, slug=agenda_identifier) + + check_types = [] + if agenda.check_type_group: + check_types = [ + {'id': x.slug, 'text': x.label, 'kind': x.kind} + for x in agenda.check_type_group.check_types.filter(disabled=False) + ] + return Response({'data': check_types}) + + +agenda_check_type_list = AgendaCheckTypeList.as_view() diff --git a/lingo/settings.py b/lingo/settings.py index 8a1209f..37b5325 100644 --- a/lingo/settings.py +++ b/lingo/settings.py @@ -55,6 +55,7 @@ INSTALLED_APPS = ( 'eopayment', 'gadjo', 'lingo.agendas', + 'lingo.api', 'lingo.manager', 'lingo.pricing', ) @@ -194,6 +195,7 @@ def debug_show_toolbar(request): DEBUG_TOOLBAR_CONFIG = {'SHOW_TOOLBAR_CALLBACK': debug_show_toolbar} +REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'lingo.api.utils.exception_handler'} local_settings_file = os.environ.get( 'LINGO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py') diff --git a/lingo/urls.py b/lingo/urls.py index a822257..1e18323 100644 --- a/lingo/urls.py +++ b/lingo/urls.py @@ -19,6 +19,7 @@ from django.conf.urls import include, url from django.conf.urls.static import static from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from .api.urls import urlpatterns as lingo_api_urls from .manager.urls import urlpatterns as lingo_manager_urls from .pricing.urls import urlpatterns as lingo_pricing_urls from .urls_utils import decorated_includes, manager_required @@ -28,6 +29,7 @@ urlpatterns = [ url(r'^$', homepage, name='homepage'), url(r'^manage/', decorated_includes(manager_required, include(lingo_manager_urls))), url(r'^manage/pricing/', decorated_includes(manager_required, include(lingo_pricing_urls))), + url(r'^api/', include(lingo_api_urls)), url(r'^login/$', login, name='auth_login'), url(r'^logout/$', logout, name='auth_logout'), ] diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..cbcb689 --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,35 @@ +import pytest + +from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup + +pytestmark = pytest.mark.django_db + + +def test_agendas_check_types_api(app): + agenda = Agenda.objects.create(label='Foo bar') + group = CheckTypeGroup.objects.create(label='Foo bar') + CheckType.objects.create(label='Foo reason', group=group, kind='absence') + CheckType.objects.create(label='Bar reason', group=group, kind='presence') + CheckType.objects.create(label='Baz reason', group=group, kind='presence', disabled=True) + group2 = CheckTypeGroup.objects.create(label='Foo bar 2') + + resp = app.get('/api/agenda/%s/check-types/' % agenda.slug) + assert resp.json == {'data': []} + + agenda.check_type_group = group2 + agenda.save() + resp = app.get('/api/agenda/%s/check-types/' % agenda.slug) + assert resp.json == {'data': []} + + agenda.check_type_group = group + agenda.save() + resp = app.get('/api/agenda/%s/check-types/' % agenda.slug) + assert resp.json == { + 'data': [ + {'id': 'bar-reason', 'kind': 'presence', 'text': 'Bar reason'}, + {'id': 'foo-reason', 'kind': 'absence', 'text': 'Foo reason'}, + ] + } + + # unknown + resp = app.get('/api/agenda/xxxx/resources/', status=404)