0002-toulouse_smart-add-get-intervention-endpoint-55230.patch
passerelle/contrib/toulouse_smart/models.py | ||
---|---|---|
17 | 17 |
import datetime |
18 | 18 | |
19 | 19 |
import lxml.etree as ET |
20 | 20 |
from django.contrib.postgres.fields import JSONField |
21 | 21 |
from django.db import models |
22 | 22 |
from django.utils.text import slugify |
23 | 23 |
from django.utils.timezone import now |
24 | 24 |
from django.utils.translation import ugettext_lazy as _ |
25 |
from requests import RequestException |
|
25 | 26 | |
26 | 27 |
from passerelle.base.models import BaseResource, HTTPResource |
27 | 28 |
from passerelle.utils import xml |
28 | 29 |
from passerelle.utils.api import endpoint |
30 |
from passerelle.utils.jsonresponse import APIError |
|
29 | 31 | |
30 | 32 | |
31 | 33 |
class ToulouseSmartResource(BaseResource, HTTPResource): |
32 | 34 |
category = _('Business Process Connectors') |
33 | 35 | |
34 | 36 |
webservice_base_url = models.URLField(_('Webservice Base URL')) |
35 | 37 | |
36 | 38 |
log_requests_errors = False |
... | ... | |
102 | 104 |
{ |
103 | 105 |
'id': '', |
104 | 106 |
'text': _('Service is unavailable'), |
105 | 107 |
'disabled': True, |
106 | 108 |
} |
107 | 109 |
] |
108 | 110 |
} |
109 | 111 | |
112 |
def request(self, url, json=None): |
|
113 |
if json: |
|
114 |
headers = {'Content-Type': 'application/json'} |
|
115 |
response = self.requests.post(url, headers=headers, json=json) |
|
116 |
else: |
|
117 |
response = self.requests.get(url) |
|
118 |
try: |
|
119 |
response.raise_for_status() |
|
120 |
except RequestException as e: |
|
121 |
raise APIError('failed to %s %s: %s' % ('post' if json else 'get', url, e)) |
|
122 |
return response |
|
123 | ||
124 |
@endpoint( |
|
125 |
name='get-intervention', |
|
126 |
methods=['get'], |
|
127 |
description=_('Retrieve an intervention'), |
|
128 |
perm='can_access', |
|
129 |
parameters={ |
|
130 |
'id': {'description': _('Intervention identifier')}, |
|
131 |
}, |
|
132 |
) |
|
133 |
def get_intervention(self, request, id): |
|
134 |
url = self.webservice_base_url + 'v1/intervention/%s' % id |
|
135 |
response = self.request(url) |
|
136 |
doc = ET.fromstring(response.content) |
|
137 |
return {'data': xml.to_json(doc)} |
|
138 | ||
110 | 139 | |
111 | 140 |
class Cache(models.Model): |
112 | 141 |
resource = models.ForeignKey( |
113 | 142 |
verbose_name=_('Resource'), |
114 | 143 |
to=ToulouseSmartResource, |
115 | 144 |
on_delete=models.CASCADE, |
116 | 145 |
related_name='cache_entries', |
117 | 146 |
) |
tests/data/toulouse_smart/get_intervention.xml | ||
---|---|---|
1 |
<?xml version="1.0"?> |
|
2 |
<Intervention> |
|
3 |
<id>3f0558bd-7d85-49a8-97e4-d07bc7f8dc9b</id> |
|
4 |
<name>DI-20210705-0001</name> |
|
5 |
<description>string</description> |
|
6 |
<geom> |
|
7 |
<type>Point</type> |
|
8 |
<coordinates>1574872.066</coordinates> |
|
9 |
<coordinates>2273333.236</coordinates> |
|
10 |
<crs>EPSG:3943</crs> |
|
11 |
</geom> |
|
12 |
<interventionData/> |
|
13 |
<safeguardRequired>true</safeguardRequired> |
|
14 |
<safeguardDone/> |
|
15 |
<interventionCreated>2021-07-05T10:21:24.921Z</interventionCreated> |
|
16 |
<interventionDesired>2021-06-29T12:54:08.368Z</interventionDesired> |
|
17 |
<interventionDone/> |
|
18 |
<submitter> |
|
19 |
<id/> |
|
20 |
<lastName>string</lastName> |
|
21 |
<firstName>string</firstName> |
|
22 |
<mail>string</mail> |
|
23 |
<furtherInformation/> |
|
24 |
<phoneNumber>06.06.06.06.06</phoneNumber> |
|
25 |
<address>string</address> |
|
26 |
</submitter> |
|
27 |
<submitterType>Usager</submitterType> |
|
28 |
<organizations> |
|
29 |
<organizations> |
|
30 |
<id>f1378d8a-12bf-4c14-913f-22624b0ecab8</id> |
|
31 |
<name>Direction des Pôles</name> |
|
32 |
</organizations> |
|
33 |
<organizations> |
|
34 |
<id>8ad4af63-70b5-416f-a75d-c510d83ce1bd</id> |
|
35 |
<name>Transport Logistique</name> |
|
36 |
</organizations> |
|
37 |
<organizations> |
|
38 |
<id>fe6247ad-e52f-4b13-b265-690b91ce974d</id> |
|
39 |
<name>Pôle Nord</name> |
|
40 |
</organizations> |
|
41 |
</organizations> |
|
42 |
<domain/> |
|
43 |
<state> |
|
44 |
<id>e844e67f-5382-4c0f-94d8-56f618263485</id> |
|
45 |
<name/> |
|
46 |
<stateLabel>Nouveau</stateLabel> |
|
47 |
<closes>false</closes> |
|
48 |
</state> |
|
49 |
<interventionTypeId>f72d370c-4d25-489f-956e-2a0d48433789</interventionTypeId> |
|
50 |
<onPrivateLand>true</onPrivateLand> |
|
51 |
<duplicates/> |
|
52 |
<external_number>string</external_number> |
|
53 |
<external_status>string</external_status> |
|
54 |
<cityId>string</cityId> |
|
55 |
<address>string</address> |
|
56 |
</Intervention> |
tests/test_toulouse_smart.py | ||
---|---|---|
11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | 12 |
# GNU Affero General Public License for more details. |
13 | 13 |
# |
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 |
import functools |
18 | 18 |
import io |
19 |
import os |
|
19 | 20 |
import zipfile |
20 | 21 | |
21 | 22 |
import httmock |
22 | 23 |
import lxml.etree as ET |
23 | 24 |
import pytest |
24 | 25 |
import utils |
25 | 26 |
from test_manager import login |
26 | 27 | |
27 | 28 |
from passerelle.contrib.toulouse_smart.models import ToulouseSmartResource |
28 |
from passerelle.utils.xml import to_json |
|
29 | ||
30 |
TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'toulouse_smart') |
|
29 | 31 | |
30 | 32 | |
31 | 33 |
@pytest.fixture |
32 | 34 |
def smart(db): |
33 | 35 |
return utils.make_resource( |
34 | 36 |
ToulouseSmartResource, |
35 | 37 |
title='Test', |
36 | 38 |
slug='test', |
... | ... | |
67 | 69 |
with httmock.HTTMock(*handlers): |
68 | 70 |
return func(*args, **kwargs) |
69 | 71 | |
70 | 72 |
return wrapper |
71 | 73 | |
72 | 74 |
return decorator |
73 | 75 | |
74 | 76 | |
77 |
def get_xml_file(filename): |
|
78 |
with open(os.path.join(TEST_BASE_DIR, "%s.xml" % filename), 'rb') as desc: |
|
79 |
return desc.read() |
|
80 | ||
81 | ||
75 | 82 |
@mock_response(['/v1/type-intervention', b'<List></List>']) |
76 | 83 |
def test_empty_intervention_types(smart): |
77 | 84 |
assert smart.get_intervention_types() == [] |
78 | 85 | |
79 | 86 | |
80 | 87 |
INTERVENTION_TYPES = '''<List> |
81 | 88 |
<item> |
82 | 89 |
<id>1234</id> |
... | ... | |
189 | 196 |
<validation> |
190 | 197 |
<type>digits</type> |
191 | 198 |
</validation> |
192 | 199 |
</field> |
193 | 200 |
</fields> |
194 | 201 |
</block> |
195 | 202 |
''' |
196 | 203 |
) |
204 | ||
205 | ||
206 |
@mock_response( |
|
207 |
['/v1/intervention', get_xml_file('get_intervention')], |
|
208 |
) |
|
209 |
def test_get_intervention(app, smart): |
|
210 |
resp = app.get(URL + 'get-intervention?id=3f0558bd-7d85-49a8-97e4-d07bc7f8dc9b') |
|
211 |
assert not resp.json['err'] |
|
212 |
assert resp.json['data']['id'] == '3f0558bd-7d85-49a8-97e4-d07bc7f8dc9b' |
|
213 |
assert resp.json['data']['state'] == ["e844e67f-5382-4c0f-94d8-56f618263485", "Nouveau", "false"] |
|
214 | ||
215 | ||
216 |
@mock_response( |
|
217 |
['/v1/intervention', None, 500], |
|
218 |
) |
|
219 |
def test_get_intervention_error_status(app, smart): |
|
220 |
resp = app.get(URL + 'get-intervention?id=3f0558bd-7d85-49a8-97e4-d07bc7f8dc9b') |
|
221 |
assert resp.json['err'] |
|
222 |
assert 'failed to get' in resp.json['err_desc'] |
|
223 | ||
224 | ||
225 |
@mock_response( |
|
226 |
['/v1/intervention', None, 404], |
|
227 |
) |
|
228 |
def test_get_intervention_wrond_id(app, smart): |
|
229 |
resp = app.get(URL + 'get-intervention?id=3f0558bd-7d85-49a8-97e4-d07bc7f8dc9b') |
|
230 |
assert resp.json['err'] |
|
231 |
assert 'failed to get' in resp.json['err_desc'] |
|
232 |
assert '404' in resp.json['err_desc'] |
|
197 |
- |