0001-misc-retrieve-check-types-from-lingo-66015.patch
chrono/utils/lingo.py | ||
---|---|---|
1 |
# chrono - agendas 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 |
import dataclasses |
|
18 |
import json |
|
19 | ||
20 |
from django.conf import settings |
|
21 |
from lingo.utils import requests |
|
22 |
from requests.exceptions import RequestException |
|
23 | ||
24 | ||
25 |
def is_lingo_enabled(): |
|
26 |
return hasattr(settings, 'KNOWN_SERVICES') and settings.KNOWN_SERVICES.get('lingo') |
|
27 | ||
28 | ||
29 |
def get_lingo_service(): |
|
30 |
if not is_lingo_enabled(): |
|
31 |
return {} |
|
32 |
return list(settings.KNOWN_SERVICES.get('lingo').values())[0] |
|
33 | ||
34 | ||
35 |
def get_lingo_json(path, log_errors=True): |
|
36 |
lingo_site = get_lingo_service() |
|
37 |
if lingo_site is None: |
|
38 |
return |
|
39 |
try: |
|
40 |
response = requests.get( |
|
41 |
path, |
|
42 |
remote_service=lingo_site, |
|
43 |
without_user=True, |
|
44 |
headers={'accept': 'application/json'}, |
|
45 |
log_errors=log_errors, |
|
46 |
) |
|
47 |
response.raise_for_status() |
|
48 |
except RequestException as e: |
|
49 |
if e.response is not None: |
|
50 |
try: |
|
51 |
# return json if available (on 404 responses by example) |
|
52 |
return e.response.json() |
|
53 |
except json.JSONDecodeError: |
|
54 |
pass |
|
55 |
return |
|
56 |
return response.json() |
|
57 | ||
58 | ||
59 |
@dataclasses.dataclass |
|
60 |
class CheckType: |
|
61 |
slug: str |
|
62 |
label: str |
|
63 |
kind: str |
|
64 | ||
65 | ||
66 |
def get_agenda_check_types(agenda): |
|
67 |
result = get_lingo_json('api/agenda/%s/check-types/' % agenda.slug) |
|
68 |
if result is None: |
|
69 |
return [] |
|
70 |
if result.get('data') is None: |
|
71 |
return [] |
|
72 | ||
73 |
check_types = [] |
|
74 |
for ct in result['data']: |
|
75 |
check_types.append(CheckType(slug=ct['id'], label=ct['text'], kind=ct['kind'])) |
|
76 |
return check_types |
tests/settings.py | ||
---|---|---|
27 | 27 |
'backoffice-menu-url': 'http://example.org/manage/', |
28 | 28 |
} |
29 | 29 |
}, |
30 |
'lingo': { |
|
31 |
'default': { |
|
32 |
'title': 'test', |
|
33 |
'url': 'http://lingo.example.org', |
|
34 |
'secret': 'chrono', |
|
35 |
'orig': 'chrono', |
|
36 |
'backoffice-menu-url': 'http://example.org/manage/', |
|
37 |
} |
|
38 |
}, |
|
30 | 39 |
} |
31 | 40 | |
32 | 41 |
LEGACY_URLS_MAPPING = {'old.org': 'new.org'} |
tests/test_utils.py | ||
---|---|---|
1 | 1 |
import datetime |
2 |
import json |
|
3 |
from unittest import mock |
|
2 | 4 | |
5 |
from requests.exceptions import ConnectionError |
|
6 |
from requests.models import Response |
|
7 | ||
8 |
from chrono.agendas.models import Agenda |
|
3 | 9 |
from chrono.utils.date import get_weekday_index |
10 |
from chrono.utils.lingo import CheckType, get_agenda_check_types |
|
4 | 11 | |
5 | 12 | |
6 | 13 |
def test_get_weekday_index(): |
... | ... | |
21 | 28 |
assert get_weekday_index(date.replace(day=28)) == 4 |
22 | 29 |
assert get_weekday_index(date.replace(day=29)) == 5 |
23 | 30 |
assert get_weekday_index(date.replace(day=30)) == 5 |
31 | ||
32 | ||
33 |
CHECK_TYPES_DATA = [ |
|
34 |
{'id': 'bar-reason', 'kind': 'presence', 'text': 'Bar reason'}, |
|
35 |
{'id': 'foo-reason', 'kind': 'absence', 'text': 'Foo reason'}, |
|
36 |
] |
|
37 | ||
38 | ||
39 |
class MockedRequestResponse(mock.Mock): |
|
40 |
status_code = 200 |
|
41 | ||
42 |
def json(self): |
|
43 |
return json.loads(self.content) |
|
44 | ||
45 | ||
46 |
def test_get_agenda_check_types_no_service(settings): |
|
47 |
agenda = Agenda(slug='foo') |
|
48 | ||
49 |
settings.KNOWN_SERVICES = {} |
|
50 |
assert get_agenda_check_types(agenda) == [] |
|
51 | ||
52 |
settings.KNOWN_SERVICES = {'other': []} |
|
53 |
assert get_agenda_check_types(agenda) == [] |
|
54 | ||
55 | ||
56 |
def test_get_agenda_check_types(): |
|
57 |
agenda = Agenda(slug='foo') |
|
58 | ||
59 |
with mock.patch('requests.Session.get') as requests_get: |
|
60 |
requests_get.side_effect = ConnectionError() |
|
61 |
assert get_agenda_check_types(agenda) == [] |
|
62 | ||
63 |
with mock.patch('requests.Session.get') as requests_get: |
|
64 |
mock_resp = Response() |
|
65 |
mock_resp.status_code = 500 |
|
66 |
requests_get.return_value = mock_resp |
|
67 |
assert get_agenda_check_types(agenda) == [] |
|
68 | ||
69 |
with mock.patch('requests.Session.get') as requests_get: |
|
70 |
mock_resp = Response() |
|
71 |
mock_resp.status_code = 404 |
|
72 |
requests_get.return_value = mock_resp |
|
73 |
assert get_agenda_check_types(agenda) == [] |
|
74 | ||
75 |
with mock.patch('requests.Session.get') as requests_get: |
|
76 |
requests_get.return_value = MockedRequestResponse(content=json.dumps({'foo': 'bar'})) |
|
77 |
assert get_agenda_check_types(agenda) == [] |
|
78 | ||
79 |
data = {'data': []} |
|
80 |
with mock.patch('requests.Session.get') as requests_get: |
|
81 |
requests_get.return_value = MockedRequestResponse(content=json.dumps(data)) |
|
82 |
assert get_agenda_check_types(agenda) == [] |
|
83 |
assert requests_get.call_args_list[0][0] == ('api/agenda/foo/check-types/',) |
|
84 |
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://lingo.example.org' |
|
85 | ||
86 |
data = {'data': CHECK_TYPES_DATA} |
|
87 |
with mock.patch('requests.Session.get') as requests_get: |
|
88 |
requests_get.return_value = MockedRequestResponse(content=json.dumps(data)) |
|
89 |
assert get_agenda_check_types(agenda) == [ |
|
90 |
CheckType(slug='bar-reason', label='Bar reason', kind='presence'), |
|
91 |
CheckType(slug='foo-reason', label='Foo reason', kind='absence'), |
|
92 |
] |
|
24 |
- |