maelis: add child-activities endpoint (#49616)
This commit is contained in:
parent
ece9f1e17a
commit
7098b10e0b
|
@ -400,6 +400,51 @@ class Maelis(BaseResource):
|
|||
activities = serialize_object(r)
|
||||
return {'data': [utils.normalize_activity(a) for a in activities]}
|
||||
|
||||
@endpoint(
|
||||
display_category=_('Activities'),
|
||||
perm='can_access',
|
||||
display_order=2,
|
||||
description=_('Get child activities'),
|
||||
name='child-activities',
|
||||
parameters={
|
||||
'NameID': {'description': _('Publik ID')},
|
||||
'childID': {'description': _('Child ID')},
|
||||
'subscribingStatus': {
|
||||
'description': _('subscribed, not-subscribed or None')},
|
||||
'queryDate': {'description': _('Optional querying date (YYYY-MM-DD)')}
|
||||
})
|
||||
def child_activities(self, request, NameID, childID,
|
||||
subscribingStatus=None, queryDate=None):
|
||||
if subscribingStatus:
|
||||
if subscribingStatus != 'subscribed' and subscribingStatus != 'not-subscribed':
|
||||
raise APIError('wrong value for subscribingStatus: %s' % subscribingStatus)
|
||||
if queryDate:
|
||||
try:
|
||||
start_date = parse_date(queryDate)
|
||||
except ValueError as exc:
|
||||
raise APIError('input is well formatted but not a valid date: %s' % exc)
|
||||
if not start_date:
|
||||
raise APIError("input isn't well formatted, YYYY-MM-DD expected")
|
||||
if not queryDate:
|
||||
start_date = timezone.now().date()
|
||||
if start_date.strftime('%m-%d') >= '05-01':
|
||||
# start displaying next year activities on may
|
||||
school_year = start_date.year
|
||||
else:
|
||||
school_year = start_date.year - 1
|
||||
end_date = utils.get_datetime('%s-07-31' % (school_year + 1))
|
||||
|
||||
child_info = self.get_child_info(NameID, childID)
|
||||
r = self.call('ActivityService?wsdl', 'readActivityList',
|
||||
schoolyear=school_year,
|
||||
numPerson=childID,
|
||||
dateStartCalend=start_date,
|
||||
dateEndCalend=end_date)
|
||||
|
||||
flatted_activities = utils.flatten_activities(serialize_object(r))
|
||||
utils.mark_subscribed_flatted_activities(flatted_activities, child_info)
|
||||
data = utils.flatted_activities_as_list(flatted_activities, subscribingStatus)
|
||||
return {'data': data}
|
||||
|
||||
@endpoint(
|
||||
display_category=_('Activities'),
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from copy import copy
|
||||
from copy import copy, deepcopy
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
@ -204,3 +204,74 @@ def decompose_event(event):
|
|||
date_string, event['category_id'], new_event['slot_id'])
|
||||
new_event['text'] = component['text']
|
||||
yield new_event
|
||||
|
||||
|
||||
def flatten_activities(activities):
|
||||
data = {}
|
||||
for activity in activities:
|
||||
if activity.get('openDayList'):
|
||||
del activity['openDayList']
|
||||
activity_id = activity['activityPortail']['idAct']
|
||||
activity_text = activity['activityPortail']['label']
|
||||
activity_obj = deepcopy(activity)
|
||||
del activity_obj['unitPortailList']
|
||||
if not activity_obj['activityPortail']['activityType']:
|
||||
activity_obj['activityPortail']['activityType'] = {
|
||||
"code" : "?",
|
||||
"libelle" : "Inconnu",
|
||||
"natureSpec" : {
|
||||
"code" : "?",
|
||||
"libelle" : "Inconnu"
|
||||
}
|
||||
}
|
||||
|
||||
units = {}
|
||||
for unit in activity['unitPortailList']:
|
||||
unit_id = unit['idUnit']
|
||||
unit_text = unit['label']
|
||||
unit_obj = deepcopy(unit)
|
||||
del unit_obj['placeList']
|
||||
|
||||
places = {}
|
||||
for place in unit['placeList']:
|
||||
place_id = place['id']
|
||||
place_text = place['lib']
|
||||
|
||||
places[place_text] = {
|
||||
'id': '%s-%s-%s' % (activity_id, unit_id, place_id),
|
||||
'text': '%s / %s / %s' % (activity_text, unit_text, place_text),
|
||||
'activity_id': activity_id,
|
||||
'unit_id': unit_id,
|
||||
'place_id': place_id,
|
||||
'activity_text': activity_text,
|
||||
'unit_text': unit_text,
|
||||
'place_text': place_text,
|
||||
'activity_object': activity_obj,
|
||||
'unit_object': unit_obj,
|
||||
'place_object': place,
|
||||
}
|
||||
units[unit_id] = places
|
||||
data[activity_id] = units
|
||||
return data
|
||||
|
||||
|
||||
def mark_subscribed_flatted_activities(flatted_activities, child_info):
|
||||
for child_activity in child_info['subscribeActivityList']:
|
||||
activity = flatted_activities[child_activity['idActivity']]
|
||||
for child_unit in child_activity['subscribesUnit']:
|
||||
unit = activity[child_unit['idUnit']]
|
||||
place = unit[child_activity['place']]
|
||||
place['user_subscribing_status'] = 'subscribed'
|
||||
|
||||
|
||||
def flatted_activities_as_list(flatted_activities, filtering_status):
|
||||
data = []
|
||||
for activity in [a[1] for a in sorted(flatted_activities.items())]:
|
||||
for unit in [u[1] for u in sorted(activity.items())]:
|
||||
for place in sorted(unit.values(), key=lambda p: p['place_id']):
|
||||
status = place.get('user_subscribing_status')
|
||||
if not status:
|
||||
status = place['user_subscribing_status'] = 'not-subscribed'
|
||||
if not filtering_status or status == filtering_status:
|
||||
data.append(place)
|
||||
return data
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,6 +46,30 @@ def activity_service_wsdl():
|
|||
return get_xml_file('ActivityService.wsdl')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def catalog_mocked_get(activity_service_wsdl, family_service_wsdl):
|
||||
return (
|
||||
utils.FakedResponse(content=family_service_wsdl,
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'}),
|
||||
utils.FakedResponse(content=activity_service_wsdl,
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'}),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def catalog_mocked_post():
|
||||
return (
|
||||
utils.FakedResponse(content=get_xml_file('readFamily.xml'),
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'}),
|
||||
utils.FakedResponse(content=get_xml_file('readActivityListResponse.xml'),
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'}),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def connector(db):
|
||||
return utils.setup_access_rights(Maelis.objects.create(
|
||||
|
@ -126,24 +150,10 @@ def test_family_info(mocked_post, mocked_get, family_service_wsdl,
|
|||
|
||||
@mock.patch('passerelle.utils.Request.get')
|
||||
@mock.patch('passerelle.utils.Request.post')
|
||||
def test_activity_list(mocked_post, mocked_get, family_service_wsdl,
|
||||
activity_service_wsdl, connector, app):
|
||||
mocked_get.side_effect = (
|
||||
utils.FakedResponse(content=family_service_wsdl,
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'}),
|
||||
utils.FakedResponse(content=activity_service_wsdl,
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'})
|
||||
)
|
||||
mocked_post.side_effect = (
|
||||
utils.FakedResponse(content=get_xml_file('readFamily.xml'),
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'}),
|
||||
utils.FakedResponse(content=get_xml_file('readActivityListResponse.xml'),
|
||||
status_code=200,
|
||||
headers={'Content-Type': 'text/xml'})
|
||||
)
|
||||
def test_activity_list(mocked_post, mocked_get,
|
||||
catalog_mocked_get, catalog_mocked_post, connector, app):
|
||||
mocked_get.side_effect = catalog_mocked_get
|
||||
mocked_post.side_effect = catalog_mocked_post
|
||||
Link.objects.create(resource=connector, family_id='3264', name_id='local')
|
||||
resp = app.get('/maelis/test/activity-list?NameID=local&personID=21293')
|
||||
assert resp.json['data']
|
||||
|
@ -326,3 +336,44 @@ def test_get_child_planning(mocked_post, mocked_get, legacy, nb_events, nb_booke
|
|||
assert len(data) == nb_events
|
||||
assert len([s for s in data if s['user_booking_status'] == 'booked']) == nb_booked
|
||||
assert resp.json == get_json_file(response)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('parameters, nb_subscribed, nb_not_subscribed', [
|
||||
('&subscribingStatus=', 2, 27),
|
||||
('&subscribingStatus=subscribed', 2, 0),
|
||||
('&subscribingStatus=not-subscribed', 0, 27),
|
||||
])
|
||||
@mock.patch('passerelle.utils.Request.get')
|
||||
@mock.patch('passerelle.utils.Request.post')
|
||||
def test_child_activities(mocked_post, mocked_get, parameters, nb_subscribed, nb_not_subscribed,
|
||||
catalog_mocked_get, catalog_mocked_post, connector, app):
|
||||
mocked_get.side_effect = catalog_mocked_get
|
||||
mocked_post.side_effect = catalog_mocked_post
|
||||
Link.objects.create(resource=connector, family_id='3264', name_id='local')
|
||||
url = '/maelis/test/child-activities?NameID=local&childID=21293'
|
||||
url += parameters
|
||||
resp = app.get(url)
|
||||
if parameters == '&subscribingStatus=':
|
||||
assert resp.json == get_json_file('child_activities')
|
||||
status = [x['user_subscribing_status'] for x in resp.json['data']]
|
||||
assert len([x for x in status if x == 'subscribed']) == nb_subscribed
|
||||
assert len([x for x in status if x == 'not-subscribed']) == nb_not_subscribed
|
||||
|
||||
@pytest.mark.parametrize('parameters, err_desc', [
|
||||
('&childID=99999', 'Child not found'),
|
||||
('&childID=21293&subscribingStatus=not-a-status', 'wrong value for subscribingStatus'),
|
||||
("&childID=21293&queryDate=2020-02-31", 'not a valid date'),
|
||||
("&childID=21293&queryDate=not-a-date", 'YYYY-MM-DD expected'),
|
||||
])
|
||||
@mock.patch('passerelle.utils.Request.get')
|
||||
@mock.patch('passerelle.utils.Request.post')
|
||||
def test_child_activities_errors(mocked_post, mocked_get, parameters, err_desc,
|
||||
catalog_mocked_get, catalog_mocked_post, connector, app):
|
||||
mocked_get.side_effect = catalog_mocked_get
|
||||
mocked_post.side_effect = catalog_mocked_post
|
||||
Link.objects.create(resource=connector, family_id='3264', name_id='local')
|
||||
url = '/maelis/test/child-activities?NameID=local'
|
||||
url += parameters
|
||||
resp = app.get(url)
|
||||
assert resp.json['err']
|
||||
assert err_desc in resp.json['err_desc']
|
||||
|
|
Loading…
Reference in New Issue