Projet

Général

Profil

0003-maelis-add-bus-lines-endpoint-50081.patch

Nicolas Roche, 14 janvier 2021 18:31

Télécharger (13,1 ko)

Voir les différences:

Subject: [PATCH 3/4] maelis: add bus-lines endpoint (#50081)

 passerelle/apps/maelis/models.py | 50 ++++++++++++++++++++++++++++++++
 passerelle/apps/maelis/utils.py  | 46 +++++++++++++++++++++--------
 tests/data/maelis/bus_lines.json | 25 ++++++++++++++++
 tests/test_maelis.py             | 41 ++++++++++++++++++++++++++
 4 files changed, 150 insertions(+), 12 deletions(-)
 create mode 100644 tests/data/maelis/bus_lines.json
passerelle/apps/maelis/models.py
445 445
        school_year, start_date, end_date = self.get_activities_dates(queryDate)
446 446
        child_info = self.get_child_info(NameID, childID)
447 447
        activities = self.get_child_activities(childID, school_year, start_date, end_date)
448 448
        flatted_activities = utils.flatten_activities(activities, start_date, end_date)
449 449
        utils.mark_subscribed_flatted_activities(flatted_activities, child_info)
450 450
        data = utils.flatted_activities_as_list(flatted_activities, subscribingStatus)
451 451
        return {'data': data}
452 452

  
453
    @endpoint(
454
        display_category=_('Activities'),
455
        perm='can_access',
456
        display_order=3,
457
        description=_('Get bus lines (units)'),
458
        name='bus-lines',
459
        parameters={
460
            'NameID': {'description': _('Publik ID')},
461
            'childID': {'description': _('Child ID')},
462
            'activityID': {'description': _('Activity ID')},
463
            'unitID': {'description': _('Unit ID')},
464
            'queryDate': {'description': _('Optional querying date (YYYY-MM-DD)')},
465
            'direction': {
466
                'description': _('aller, retour or None')},
467
    })
468
    def bus_lines(self, request, NameID, childID, activityID, unitID, queryDate=None, direction=None):
469
        if direction and direction.lower() not in ('aller', 'retour'):
470
            raise APIError('wrong value for direction: %s' % direction)
471
        school_year, start_date, end_date = self.get_activities_dates(queryDate)
472
        self.get_child_info(NameID, childID)
473
        activities = self.get_child_activities(childID, school_year, start_date, end_date)
474
        flatted_activities = utils.flatten_activities(activities, start_date, end_date)
475
        legacy_activity_info = flatted_activities[activityID]['info']
476
        legacy_unit_info = flatted_activities[activityID]['units'][unitID]['info']
477

  
478
        bus_lines = []
479
        bus_activity_id = legacy_activity_info['bus_activity_id']
480
        for bus_unit_id in legacy_activity_info['bus_unit_ids']:
481
            bus_unit_info = flatted_activities[bus_activity_id]['units'][bus_unit_id]['info']
482
            if direction and direction.lower() not in bus_unit_info['unit_text']:
483
                continue
484
            unit_calendar_letter = bus_unit_info['unit_calendar_letter']
485
            unit_weekly_planning = ""
486
            for letter in legacy_activity_info['activity_weekly_planning_mask']:
487
                if letter == '0':
488
                    unit_weekly_planning += unit_calendar_letter
489
                else:
490
                    unit_weekly_planning += '1'
491
            bus_lines.append({
492
                'id': bus_unit_info['unit_id'],
493
                'text': bus_unit_info['unit_text'],
494
                'unit_id': bus_unit_info['unit_id'],
495
                'activity_id': bus_activity_id,
496
                'unit_calendar_letter': unit_calendar_letter,
497
                'unit_weekly_planning': unit_weekly_planning,
498
                'subscribe_start_date': legacy_unit_info['unit_start_date'],
499
                'subscribe_end_date': legacy_unit_info['unit_end_date'],
500
            })
501
        return {'data': bus_lines}
502

  
453 503
    @endpoint(
454 504
        display_category=_('Activities'),
455 505
        perm='can_access',
456 506
        display_order=3,
457 507
        description=_('Read child planning'),
458 508
        name='child-planning',
459 509
        parameters={
460 510
            'NameID': {'description': _('Publik ID')},
passerelle/apps/maelis/utils.py
242 242
            activity_weekly_planning_mask = ""
243 243
            for letters in zip(*planning_masks):
244 244
                if '1' in letters:
245 245
                    activity_weekly_planning_mask += '1'
246 246
                else:
247 247
                    activity_weekly_planning_mask += '0'
248 248
        else:
249 249
            activity_weekly_planning_mask = "0000000"
250
        bus_unit_ids = []
251
        bus_activity_id = None
252
        if activity['activityPortail'].get('activityBusList'):
253
            bus_activity_id = activity['activityPortail']['activityBusList'][0]['activity']['id']
254
            for bus_unit in activity['activityPortail']['activityBusList'][0]['unitList']:
255
                bus_unit_ids.append(bus_unit['idUnit'])
256
        activity_info = {
257
            'activity_id': activity_id,
258
            'activity_text': activity_text,
259
            'activity_object': activity_obj,
260
            'activity_weekly_planning_mask': activity_weekly_planning_mask,
261
            'bus_activity_id': bus_activity_id,
262
            'bus_unit_ids': bus_unit_ids,
263
        }
250 264

  
251 265
        units = {}
252 266
        for unit in activity['unitPortailList']:
253 267
            unit_id = unit['idUnit']
254 268
            unit_text = unit_text_legacy = unit['label']
255 269
            match = regex.match(unit_text)
256 270
            if match:
257 271
                unit_text = unit_text[match.end():].strip()
......
267 281
            unit_end_date = unit['dateEnd'] or end_date
268 282
            unit_calendar_letter = unit['calendarLetter']
269 283
            unit_weekly_planning = ""
270 284
            for letter in activity_weekly_planning_mask:
271 285
                if letter == '0':
272 286
                    unit_weekly_planning += unit_calendar_letter
273 287
                else:
274 288
                    unit_weekly_planning += '1'
289
            unit_info = {
290
                'unit_id': unit_id,
291
                'unit_text' : unit_text,
292
                'text_first_part': text_first_part,
293
                'unit_object': unit_obj,
294
                'unit_start_date': unit_start_date,
295
                'unit_end_date': unit_end_date,
296
                'unit_calendar_letter': unit_calendar_letter,
297
                'unit_weekly_planning': unit_weekly_planning,
298
            }
275 299

  
276 300
            places = {}
277 301
            for place in unit['placeList']:
278 302
                place_id = place['id']
279 303
                place_text_legacy = place['lib']
280 304
                place_text = ' '.join([w.capitalize() for w in place_text_legacy.split(' ')])
281 305

  
282 306
                places[place_text_legacy] = {
......
295 319
                    'subscribe_start_date': unit_start_date,
296 320
                    'subscribe_end_date': unit_end_date,
297 321
                    'unit_calendar_letter': unit_calendar_letter,
298 322
                    'unit_weekly_planning': unit_weekly_planning,
299 323
                    'activity_object': activity_obj,
300 324
                    'unit_object': unit_obj,
301 325
                    'place_object': place,
302 326
                }
303
            units[unit_id] = places
304
        data[activity_id] = units
327
            units[unit_id] = {'info': unit_info, 'places': places}
328
        data[activity_id] = {'info': activity_info, 'units': units}
305 329
    return data
306 330

  
307 331

  
308 332
def mark_subscribed_flatted_activities(flatted_activities, child_info):
309 333
    for child_activity in child_info['subscribeActivityList']:
310 334
        activity = flatted_activities[child_activity['idActivity']]
311 335
        for child_unit in child_activity['subscribesUnit']:
312
            unit = activity[child_unit['idUnit']]
313
            place = unit[child_activity['place']]
336
            unit = activity['units'][child_unit['idUnit']]
337
            place = unit['places'][child_activity['place']]
314 338
            place['user_subscribing_status'] = 'subscribed'
315 339
            place['unsubscribe_start_date'] = child_unit['dateStart']
316 340

  
317 341

  
318 342
def flatted_activities_as_list(flatted_activities, filtering_status):
319 343
    data = []
320 344
    for activity in [a[1] for a in sorted(flatted_activities.items())]:
321
        for unit in [u[1] for u in sorted(activity.items())]:
322
            is_unit_subscribable = True
345
        for unit in [u[1] for u in sorted(activity['units'].items())]:
346
            unit_info = unit['info']
347
            if unit_info['unit_object']['subscribePublication'] != 'E':
348
                continue
323 349
            is_unit_subscribed = False
324
            for place in unit.values():
325
                if place['unit_object']['subscribePublication'] != 'E':
326
                    is_unit_subscribable = False
350
            for place in unit['places'].values():
327 351
                if place.get('user_subscribing_status'):
328 352
                    is_unit_subscribed = True
329 353
                else:
330 354
                    place['user_subscribing_status'] = 'not-subscribed'
331
            if not is_unit_subscribable:
332
                continue
333 355
            if filtering_status == 'not-subscribed' and is_unit_subscribed:
334 356
                continue
335
            for place in sorted(unit.values(), key=lambda p: p['place_id']):
357
            for place in sorted(unit['places'].values(), key=lambda p: p['place_id']):
336 358
                if not filtering_status or place['user_subscribing_status'] == filtering_status:
337 359
                    data.append(place)
338 360
    return data
tests/data/maelis/bus_lines.json
1
{
2
    "data": [
3
        {
4
            "activity_id": "A10003151396",
5
            "id": "A10003151403",
6
            "subscribe_end_date": "2020-12-31T00:00:00+01:00",
7
            "subscribe_start_date": "2020-12-28T00:00:00+01:00",
8
            "text": "Ligne mistral / retour",
9
            "unit_calendar_letter": "B",
10
            "unit_id": "A10003151403",
11
            "unit_weekly_planning": "BBBBB11"
12
        },
13
        {
14
            "activity_id": "A10003151396",
15
            "id": "A10003151402",
16
            "subscribe_end_date": "2020-12-31T00:00:00+01:00",
17
            "subscribe_start_date": "2020-12-28T00:00:00+01:00",
18
            "text": "Ligne mistral/ aller",
19
            "unit_calendar_letter": "A",
20
            "unit_id": "A10003151402",
21
            "unit_weekly_planning": "AAAAA11"
22
        }
23
    ],
24
    "err": 0
25
}
tests/test_maelis.py
422 422
            status_code=200,
423 423
            headers={'Content-Type': 'text/xml'})
424 424
    )
425 425
    Link.objects.create(resource=connector, family_id='3264', name_id='local')
426 426
    resp = app.get('/maelis/test/unsubscribe/?NameID=local&childID=21293'
427 427
                   + '&activityID=A10003121692&start_date=2020-08-01')
428 428
    assert not resp.json['err']
429 429
    assert resp.json['data'] is None
430

  
431

  
432
@pytest.mark.parametrize('parameters, nb_bus_lines', [
433
    ('&direction=', 2),
434
    ('&direction=Aller', 1),
435
    ('&direction=retour', 1),
436
])
437
@mock.patch('passerelle.utils.Request.get')
438
@mock.patch('passerelle.utils.Request.post')
439
def test_bus_lines(mocked_post, mocked_get, parameters, nb_bus_lines,
440
                   catalog_mocked_get, catalog_mocked_post, connector, app):
441
    mocked_get.side_effect = catalog_mocked_get
442
    mocked_post.side_effect = catalog_mocked_post
443
    Link.objects.create(resource=connector, family_id='3264', name_id='local')
444
    url = '/maelis/test/bus-lines?NameID=local&childID=21293'
445
    url += '&activityID=A10003131850&unitID=A10003131903&queryDate=2020-12-15'
446
    url += parameters
447
    resp = app.get(url)
448
    if parameters == '&direction=':
449
        assert resp.json == get_json_file('bus_lines')
450
    assert len(resp.json['data']) == nb_bus_lines
451

  
452

  
453
@pytest.mark.parametrize('parameters, err_desc', [
454
    ('&childID=99999', 'Child not found'),
455
    ('&childID=21293&queryDate=2020-02-31', 'not a valid date'),
456
    ('&childID=21293&queryDate=not-a-date', 'YYYY-MM-DD expected'),
457
    ('&childID=21293&direction=heaven', 'wrong value for direction'),
458
])
459
@mock.patch('passerelle.utils.Request.get')
460
@mock.patch('passerelle.utils.Request.post')
461
def test_child_activities_errors(mocked_post, mocked_get, parameters, err_desc,
462
                                 catalog_mocked_get, catalog_mocked_post, connector, app):
463
    mocked_get.side_effect = catalog_mocked_get
464
    mocked_post.side_effect = catalog_mocked_post
465
    Link.objects.create(resource=connector, family_id='3264', name_id='local')
466
    url = '/maelis/test/bus-lines?NameID=local&activityID=1&unitID=2'
467
    url += parameters
468
    resp = app.get(url)
469
    assert resp.json['err']
470
    assert err_desc in resp.json['err_desc']
430
-