0003-maelis-add-bus-lines-endpoint-50081.patch
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 |
- |