Projet

Général

Profil

0002-toulouse_smart-add-get-intervention-endpoint-55230.patch

Nicolas Roche (absent jusqu'au 3 avril), 19 juillet 2021 10:22

Télécharger (7,63 ko)

Voir les différences:

Subject: [PATCH 2/7] toulouse_smart: add get-intervention endpoint (#55230)

 passerelle/contrib/toulouse_smart/models.py   | 29 ++++++++++
 .../data/toulouse_smart/get_intervention.xml  | 56 +++++++++++++++++++
 tests/test_toulouse_smart.py                  | 38 ++++++++++++-
 3 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 tests/data/toulouse_smart/get_intervention.xml
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&#xF4;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&#xF4;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
-