Projet

Général

Profil

0001-api-list-agenda-s-check-types-66008.patch

Lauréline Guérin, 07 juin 2022 10:46

Télécharger (8,89 ko)

Voir les différences:

Subject: [PATCH 1/2] 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 ++
 setup.py              |  1 +
 tests/test_api.py     | 36 ++++++++++++++++++++++++++++++
 8 files changed, 158 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
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
-