Projet

Général

Profil

0002-toulouse_smart-do-not-crash-on-unmanaged-property-ty.patch

Nicolas Roche, 26 janvier 2022 17:20

Télécharger (6,33 ko)

Voir les différences:

Subject: [PATCH 2/2] toulouse_smart: do not crash on unmanaged property type
 (#60989)

 passerelle/contrib/toulouse_smart/models.py |  6 +++++
 tests/test_toulouse_smart.py                | 30 +++++++++++++++++++++
 2 files changed, 36 insertions(+)
passerelle/contrib/toulouse_smart/models.py
177 177
        for prop in intervention_type.get('properties') or []:
178 178
            varname = slugify(prop['name']).replace('-', '_')
179 179
            if block.get(varname):
180 180
                if 'type' not in prop:
181 181
                    raise APIError(
182 182
                        'unknwon type for the %s/%s property' % (intervention_type['name'], prop['name']),
183 183
                        http_status=400,
184 184
                    )
185
                if prop['type'] not in cast:
186
                    raise APIError(
187
                        'unmanaged "%s" type for the %s/%s property'
188
                        % (prop['type'], intervention_type['name'], prop['name']),
189
                        http_status=400,
190
                    )
185 191
                try:
186 192
                    data[prop['name']] = cast[prop['type']](block[varname])
187 193
                except ValueError:
188 194
                    raise APIError(
189 195
                        "cannot cast '%s' field to %s : '%s'" % (varname, cast[prop['type']], block[varname]),
190 196
                        http_status=400,
191 197
                    )
192 198
            elif prop['required']:
tests/test_toulouse_smart.py
155 155
              <displayName>Champ 2</displayName>
156 156
              <type>int</type>
157 157
              <required>true</required>
158 158
           </properties>
159 159
           <properties>
160 160
              <name>FIELD3</name>
161 161
              <displayName>Champ 3</displayName>
162 162
           </properties>
163
          <properties>
164
              <name>FIELD4</name>
165
              <displayName>Champ 4</displayName>
166
              <type>plop</type>
167
           </properties>
163 168
       </properties>
164 169
   </item>
165 170
   <item>
166 171
       <id>0002</id>
167 172
       <name>empty</name>
168 173
   </item>
169 174
</List>'''.encode()
170 175

  
......
182 187
                    'displayName': 'Champ 1',
183 188
                    'required': False,
184 189
                    'type': 'item',
185 190
                    'defaultValue': 'Ne sait pas',
186 191
                    'restrictedValues': ['Candélabre', 'Mât', 'Ne sait pas'],
187 192
                },
188 193
                {'name': 'FIELD2', 'displayName': 'Champ 2', 'required': True, 'type': 'int'},
189 194
                {'name': 'FIELD3', 'displayName': 'Champ 3', 'required': False},
195
                {'name': 'FIELD4', 'displayName': 'Champ 4', 'required': False, 'type': 'plop'},
190 196
            ],
191 197
        },
192 198
        {
193 199
            'id': '0002',
194 200
            'name': 'empty',
195 201
            'order': 2,
196 202
        },
197 203
    ]
......
223 229
    login(app)
224 230
    resp = app.get('/manage' + URL + 'type-intervention/')
225 231
    assert [[td.text for td in tr.cssselect('td,th')] for tr in resp.pyquery('tr')] == [
226 232
        ["Nom du type d'intervention", 'Nom', 'Type', 'Requis', 'Valeur par défaut'],
227 233
        ['1 - coin'],
228 234
        [None, 'TYPE-OBJET', 'item («Candélabre», «Mât», «Ne sait pas»)', '✘', 'Ne sait pas'],
229 235
        [None, 'FIELD2', 'int', '✔', None],
230 236
        [None, 'FIELD3', None, '✘', None],
237
        [None, 'FIELD4', 'plop', '✘', None],
231 238
        ['2 - empty'],
232 239
    ]
233 240
    resp = resp.click('Export to blocks')
234 241
    with zipfile.ZipFile(io.BytesIO(resp.body)) as zip_file:
235 242
        assert zip_file.namelist() == ['block-coin.wcs']
236 243
        with zip_file.open('block-coin.wcs') as fd:
237 244
            content = ET.tostring(ET.fromstring(fd.read()), pretty_print=True).decode()
238 245
            assert (
......
277 284
      <type>string</type>
278 285
      <required>False</required>
279 286
      <varname>field3</varname>
280 287
      <display_locations>
281 288
        <display_location>validation</display_location>
282 289
        <display_location>summary</display_location>
283 290
      </display_locations>
284 291
    </field>
292
    <field>
293
      <id>5e9c34f3-ffd9-62c7-5006-79dbff961286</id>
294
      <label>Champ 4</label>
295
      <type>plop</type>
296
      <required>False</required>
297
      <varname>field4</varname>
298
      <display_locations>
299
        <display_location>validation</display_location>
300
        <display_location>summary</display_location>
301
      </display_locations>
302
    </field>
285 303
  </fields>
286 304
</block>
287 305
'''
288 306
            )
289 307

  
290 308

  
291 309
INTERVENTION_ID = json.loads(get_json_file('create_intervention'))['id']
292 310

  
......
511 529
def test_create_intervention_no_type_to_cast(mocked_uuid4, app, smart):
512 530
    payload = deepcopy(CREATE_INTERVENTION_PAYLOAD)
513 531
    payload['fields']['coin_raw'][0]['field3'] = 'plop value'
514 532
    resp = app.post_json(URL + 'create-intervention/', params=payload, status=400)
515 533
    assert resp.json['err']
516 534
    assert resp.json['err_desc'] == 'unknwon type for the coin/FIELD3 property'
517 535

  
518 536

  
537
@mock_response(
538
    ['/v1/type-intervention', None, INTERVENTION_TYPES],
539
)
540
@mock.patch("django.db.models.fields.UUIDField.get_default", return_value=UUID)
541
def test_create_intervention_unmanaged_type_to_cast(mocked_uuid4, app, smart):
542
    payload = deepcopy(CREATE_INTERVENTION_PAYLOAD)
543
    payload['fields']['coin_raw'][0]['field4'] = 'plop value'
544
    resp = app.post_json(URL + 'create-intervention/', params=payload, status=400)
545
    assert resp.json['err']
546
    assert resp.json['err_desc'] == 'unmanaged "plop" type for the coin/FIELD4 property'
547

  
548

  
519 549
@mock_response(
520 550
    ['/v1/type-intervention', None, INTERVENTION_TYPES],
521 551
)
522 552
def test_create_intervention_missing_value(app, smart):
523 553
    field_payload = {
524 554
        'coin_raw': [
525 555
            {
526 556
                'type_objet': 'Candélabre',
527
-