0001-api-list-agenda-s-check-types-66008.patch
lingo/api/urls.py | ||
---|---|---|
1 |
# lingo - payment and billing system |
|
2 |
# Copyright (C) 2022 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.conf.urls import url |
|
18 | ||
19 |
from . import views |
|
20 | ||
21 |
urlpatterns = [ |
|
22 |
url( |
|
23 |
r'^agenda/(?P<agenda_identifier>[\w-]+)/check-types/$', |
|
24 |
views.agenda_check_type_list, |
|
25 |
name='api-agenda-check-types', |
|
26 |
), |
|
27 |
] |
lingo/api/utils.py | ||
---|---|---|
1 |
# lingo - payment and billing system |
|
2 |
# Copyright (C) 2022 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.utils.translation import gettext_lazy as _ |
|
18 |
from rest_framework.response import Response |
|
19 |
from rest_framework.views import exception_handler as DRF_exception_handler |
|
20 | ||
21 | ||
22 |
class APIError(Exception): |
|
23 |
http_status = 200 |
|
24 | ||
25 |
def __init__(self, message, *args, err=1, err_class=None, errors=None): |
|
26 |
self.err_desc = _(message) % args |
|
27 |
self.err = err |
|
28 |
self.err_class = err_class or message % args |
|
29 |
self.errors = errors |
|
30 |
super().__init__(self.err_desc) |
|
31 | ||
32 |
def to_response(self): |
|
33 |
data = { |
|
34 |
'err': self.err, |
|
35 |
'err_class': self.err_class, |
|
36 |
'err_desc': self.err_desc, |
|
37 |
} |
|
38 |
if self.errors: |
|
39 |
data['errors'] = self.errors |
|
40 |
return Response(data, status=self.http_status) |
|
41 | ||
42 | ||
43 |
class APIErrorBadRequest(APIError): |
|
44 |
http_status = 400 |
|
45 | ||
46 | ||
47 |
def exception_handler(exc, context): |
|
48 |
if isinstance(exc, APIError): |
|
49 |
return exc.to_response() |
|
50 | ||
51 |
return DRF_exception_handler(exc, context) |
lingo/api/views.py | ||
---|---|---|
1 |
# lingo - payment and billing system |
|
2 |
# Copyright (C) 2022 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.shortcuts import get_object_or_404 |
|
18 |
from rest_framework.views import APIView |
|
19 | ||
20 |
from lingo.agendas.models import Agenda |
|
21 |
from lingo.api.utils import Response |
|
22 | ||
23 | ||
24 |
class AgendaCheckTypeList(APIView): |
|
25 |
permission_classes = () |
|
26 | ||
27 |
def get(self, request, agenda_identifier=None, format=None): |
|
28 |
agenda = get_object_or_404(Agenda, slug=agenda_identifier) |
|
29 | ||
30 |
check_types = [] |
|
31 |
if agenda.check_type_group: |
|
32 |
check_types = [ |
|
33 |
{'id': x.slug, 'text': x.label, 'kind': x.kind, 'disabled': x.disabled} |
|
34 |
for x in agenda.check_type_group.check_types.all() |
|
35 |
] |
|
36 |
return Response({'data': check_types}) |
|
37 | ||
38 | ||
39 |
agenda_check_type_list = AgendaCheckTypeList.as_view() |
lingo/settings.py | ||
---|---|---|
57 | 57 |
'lingo.agendas', |
58 | 58 |
'lingo.manager', |
59 | 59 |
'lingo.pricing', |
60 |
'lingo.api', |
|
60 | 61 |
) |
61 | 62 | |
62 | 63 |
MIDDLEWARE = ( |
... | ... | |
194 | 195 | |
195 | 196 |
DEBUG_TOOLBAR_CONFIG = {'SHOW_TOOLBAR_CALLBACK': debug_show_toolbar} |
196 | 197 | |
198 |
REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'lingo.api.utils.exception_handler'} |
|
197 | 199 | |
198 | 200 |
local_settings_file = os.environ.get( |
199 | 201 |
'LINGO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py') |
lingo/urls.py | ||
---|---|---|
19 | 19 |
from django.conf.urls.static import static |
20 | 20 |
from django.contrib.staticfiles.urls import staticfiles_urlpatterns |
21 | 21 | |
22 |
from .api.urls import urlpatterns as lingo_api_urls |
|
22 | 23 |
from .manager.urls import urlpatterns as lingo_manager_urls |
23 | 24 |
from .pricing.urls import urlpatterns as lingo_pricing_urls |
24 | 25 |
from .urls_utils import decorated_includes, manager_required |
... | ... | |
28 | 29 |
url(r'^$', homepage, name='homepage'), |
29 | 30 |
url(r'^manage/', decorated_includes(manager_required, include(lingo_manager_urls))), |
30 | 31 |
url(r'^manage/pricing/', decorated_includes(manager_required, include(lingo_pricing_urls))), |
32 |
url(r'^api/', include(lingo_api_urls)), |
|
31 | 33 |
url(r'^login/$', login, name='auth_login'), |
32 | 34 |
url(r'^logout/$', logout, name='auth_logout'), |
33 | 35 |
] |
setup.py | ||
---|---|---|
162 | 162 |
install_requires=[ |
163 | 163 |
'django>=2.2, <2.3', |
164 | 164 |
'gadjo>=0.53', |
165 |
'djangorestframework>=3.4', |
|
165 | 166 |
'requests', |
166 | 167 |
'eopayment>=1.60', |
167 | 168 |
'djangorestframework>=3.3, <3.10', |
tests/test_api.py | ||
---|---|---|
1 |
import pytest |
|
2 | ||
3 |
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup |
|
4 | ||
5 |
pytestmark = pytest.mark.django_db |
|
6 | ||
7 | ||
8 |
def test_agendas_check_types_api(app): |
|
9 |
agenda = Agenda.objects.create(label='Foo bar') |
|
10 |
group = CheckTypeGroup.objects.create(label='Foo bar') |
|
11 |
CheckType.objects.create(label='Foo reason', group=group, kind='absence') |
|
12 |
CheckType.objects.create(label='Bar reason', group=group, kind='presence') |
|
13 |
CheckType.objects.create(label='Baz reason', group=group, kind='presence', disabled=True) |
|
14 |
group2 = CheckTypeGroup.objects.create(label='Foo bar 2') |
|
15 | ||
16 |
resp = app.get('/api/agenda/%s/check-types/' % agenda.slug) |
|
17 |
assert resp.json == {'data': []} |
|
18 | ||
19 |
agenda.check_type_group = group2 |
|
20 |
agenda.save() |
|
21 |
resp = app.get('/api/agenda/%s/check-types/' % agenda.slug) |
|
22 |
assert resp.json == {'data': []} |
|
23 | ||
24 |
agenda.check_type_group = group |
|
25 |
agenda.save() |
|
26 |
resp = app.get('/api/agenda/%s/check-types/' % agenda.slug) |
|
27 |
assert resp.json == { |
|
28 |
'data': [ |
|
29 |
{'id': 'bar-reason', 'kind': 'presence', 'text': 'Bar reason', 'disabled': False}, |
|
30 |
{'id': 'baz-reason', 'kind': 'presence', 'text': 'Baz reason', 'disabled': True}, |
|
31 |
{'id': 'foo-reason', 'kind': 'absence', 'text': 'Foo reason', 'disabled': False}, |
|
32 |
] |
|
33 |
} |
|
34 | ||
35 |
# unknown |
|
36 |
resp = app.get('/api/agenda/xxxx/resources/', status=404) |
|
0 |
- |