0001-planitec-filters-homogenisation-32828.patch
passerelle/contrib/planitech/models.py | ||
---|---|---|
283 | 283 |
raise APIError(error_msg) |
284 | 284 |
return mste.decode(response.json()) |
285 | 285 | |
286 |
def _get_places_by_capacity(self, min_capacity, max_capacity): |
|
287 |
places = self._get_places_referential() |
|
288 |
min_capacity = int(min_capacity) |
|
289 |
max_capacity = int(max_capacity) |
|
290 |
return [place['identifier'] for place in places.values() |
|
291 |
if (min_capacity <= place['capacity'] <= max_capacity) |
|
292 |
and place['capacity']] |
|
293 | ||
294 |
def _get_places_referential(self, refresh_cache=False): |
|
286 |
def _raw_get_places_referential(self, refresh_cache=False): |
|
295 | 287 |
cache_key = 'planitech-%s-places' % self.id |
296 | 288 |
ref = cache.get(cache_key) |
297 | 289 |
if ref is None or refresh_cache: |
... | ... | |
342 | 334 |
cache.set(cache_key, ref) |
343 | 335 |
return ref |
344 | 336 | |
345 |
def _filter_places_referential(self, places_ref, ref_filters): |
|
346 |
# Strip filter name from their prefix |
|
347 |
filters = {} |
|
348 |
for p_name, p_value in ref_filters.items(): |
|
349 |
if p_name.startswith('referential_'): |
|
350 |
p_name = p_name.replace('referential_', '') |
|
351 |
filters[p_name] = p_value |
|
352 | ||
353 |
# Filter on custom attributes |
|
354 |
if filters: |
|
355 |
res = {} |
|
356 |
for place_id, place in places_ref.items(): |
|
357 |
for filter_name, filter_value in filters.items(): |
|
358 |
for field in self.custom_fields: |
|
359 |
if filter_name == field['name']: |
|
360 |
if field['type'] == 'int': |
|
361 |
filter_value = int(filter_value) |
|
362 |
if place.get(filter_name) == filter_value: |
|
363 |
res[place_id] = place |
|
364 |
places_ref = res |
|
365 | ||
366 |
return places_ref |
|
337 |
def _get_places_referential(self, min_capacity=0, max_capacity=100000, **kwargs): |
|
338 | ||
339 |
ref = self._raw_get_places_referential() |
|
340 |
res = {} |
|
341 | ||
342 |
try: |
|
343 |
min_capacity, max_capacity = int(min_capacity), int(max_capacity) |
|
344 |
except ValueError: |
|
345 |
raise APIError("min_capacity and max_capacity must be integers") |
|
346 | ||
347 |
for place_id, place_data in ref.items(): |
|
348 |
# Filter on capacity |
|
349 |
if 'capacity' in place_data: |
|
350 |
if place_data['capacity'] < min_capacity or place_data['capacity'] > max_capacity: |
|
351 |
continue |
|
352 | ||
353 |
# Filter on custom fields |
|
354 |
skip = False |
|
355 |
for filter_name, filter_value in kwargs.items(): |
|
356 |
for field in self.custom_fields: |
|
357 |
if filter_name == field['name']: |
|
358 |
if field['type'] == 'int': |
|
359 |
filter_value = int(filter_value) |
|
360 |
if place_data.get(filter_name) != filter_value: |
|
361 |
skip = True |
|
362 |
if skip: |
|
363 |
continue |
|
364 |
res[place_id] = place_data |
|
365 | ||
366 |
return res |
|
367 | 367 | |
368 | 368 |
def _login(self): |
369 | 369 |
try: |
... | ... | |
485 | 485 |
} |
486 | 486 | |
487 | 487 |
def hourly(self): |
488 |
self._get_places_referential(refresh_cache=True) |
|
488 |
self._raw_get_places_referential(refresh_cache=True)
|
|
489 | 489 | |
490 | 490 |
def _date_display(self, raw_data): |
491 | 491 |
available_dates = set() |
... | ... | |
507 | 507 |
available_places = [] |
508 | 508 |
for place in raw_data.get('availablePlaces', []): |
509 | 509 |
available_places.append(int(place['placeIdentifier'])) |
510 |
places_ref = self._get_places_referential() |
|
510 |
places_ref = self._raw_get_places_referential()
|
|
511 | 511 |
res = [] |
512 | 512 |
for place in available_places: |
513 | 513 |
res.append({"id": place, "text": places_ref[place]['label']}) |
514 | 514 |
return res |
515 | 515 | |
516 | 516 |
def _full_display(self, raw_data): |
517 |
places_ref = self._get_places_referential() |
|
517 |
places_ref = self._raw_get_places_referential()
|
|
518 | 518 |
res = { |
519 | 519 |
'date': self._date_display(raw_data), |
520 | 520 |
'place': self._place_display(raw_data) |
... | ... | |
624 | 624 |
# Places restriction |
625 | 625 |
if place_id is not None: |
626 | 626 |
places_id = [int(place_id)] |
627 |
elif kwargs: |
|
628 |
places_id = self._filter_places_referential( |
|
629 |
self._get_places_referential(), kwargs).keys() |
|
630 | 627 |
else: |
631 |
places_id = self._get_places_by_capacity(int(min_capacity), int(max_capacity)) |
|
628 |
places_id = self._get_places_referential( |
|
629 |
min_capacity=min_capacity, max_capacity=max_capacity, **kwargs).keys() |
|
632 | 630 | |
633 | 631 |
params = { |
634 | 632 |
"placeIdentifiers": [float(p_id) for p_id in places_id], |
... | ... | |
673 | 671 |
id_ = int(id) |
674 | 672 |
except ValueError: |
675 | 673 |
raise APIError('ID must be an integer') |
676 |
ref = self._get_places_referential() |
|
674 |
ref = self._raw_get_places_referential()
|
|
677 | 675 |
if id_ not in ref: |
678 | 676 |
raise APIError('No place with ID %s' % id_) |
679 | 677 |
return { |
680 |
'data': self._get_places_referential()[int(id_)]
|
|
678 |
'data': ref[int(id_)]
|
|
681 | 679 |
} |
682 | 680 | |
683 | 681 |
@endpoint(description_get=_('Get places referential'), methods=['get'], perm='can_access') |
684 | 682 |
def getplacesreferential(self, request, **kwargs): |
685 | 683 |
return { |
686 |
'data': self._filter_places_referential( |
|
687 |
self._get_places_referential(), kwargs) |
|
684 |
'data': self._get_places_referential(**kwargs) |
|
688 | 685 |
} |
689 | 686 | |
690 | 687 |
@endpoint(description_get=_('Get reservation infos'), methods=['get'], perm='can_access') |
tests/test_planitech.py | ||
---|---|---|
95 | 95 |
if referential is not None: |
96 | 96 |
mock_get_referential = mock.Mock(return_value=referential) |
97 | 97 |
monkeypatch.setattr( |
98 |
models.PlanitechConnector, '_get_places_referential', mock_get_referential) |
|
98 |
models.PlanitechConnector, '_raw_get_places_referential', mock_get_referential)
|
|
99 | 99 | |
100 | 100 |
return mock_call_planitech |
101 | 101 | |
... | ... | |
329 | 329 |
{ |
330 | 330 |
'placesList': [ |
331 | 331 |
{'identifier': 1.0, 'label': 'salle 1'}, |
332 |
{'identifier': 2.0, 'label': 'salle 2'} |
|
332 |
{'identifier': 2.0, 'label': 'salle 2'}, |
|
333 |
{'identifier': 3.0, 'label': 'salle 3'} |
|
333 | 334 |
] |
334 | 335 |
}, |
335 | 336 |
{ |
... | ... | |
342 | 343 |
{ |
343 | 344 |
'identifier': 2.0, 'capacity': 20.0, |
344 | 345 |
'some_custom_field': 'Yes' |
346 |
}, |
|
347 |
{ |
|
348 |
'identifier': 3.0, 'capacity': 30.0, |
|
349 |
'some_custom_field': 'Yes' |
|
345 | 350 |
} |
346 | 351 |
] |
347 | 352 |
} |
... | ... | |
349 | 354 |
mock_planitech(monkeypatch, side_effect=side_effect) |
350 | 355 |
response = app.get('/planitech/slug-planitech/getplacesreferential') |
351 | 356 |
expected_res = { |
357 |
'3': { |
|
358 |
u'capacity': 30, u'label': u'salle 3', u'identifier': 3, |
|
359 |
'street_number': None, 'address': None, |
|
360 |
'city': None, 'zipcode': None, 'some_custom_field': 'Yes' |
|
361 |
}, |
|
352 | 362 |
'2': { |
353 | 363 |
u'capacity': 20, u'label': u'salle 2', u'identifier': 2, |
354 | 364 |
'street_number': None, 'address': None, |
... | ... | |
362 | 372 |
} |
363 | 373 |
assert response.json['data'] == expected_res |
364 | 374 | |
375 |
# Filter on custom fields |
|
376 |
mock_planitech(monkeypatch, side_effect=side_effect) |
|
377 |
response = app.get( |
|
378 |
'/planitech/slug-planitech/getplacesreferential?some_custom_field=Yes') |
|
379 |
assert response.json['data'] == { |
|
380 |
'3': { |
|
381 |
u'capacity': 30, u'label': u'salle 3', u'identifier': 3, |
|
382 |
'street_number': None, 'address': None, |
|
383 |
'city': None, 'zipcode': None, 'some_custom_field': 'Yes' |
|
384 |
}, |
|
385 |
'2': { |
|
386 |
u'capacity': 20, u'label': u'salle 2', u'identifier': 2, |
|
387 |
'street_number': None, 'address': None, |
|
388 |
'city': None, 'zipcode': None, 'some_custom_field': 'Yes' |
|
389 |
} |
|
390 |
} |
|
391 | ||
392 |
# Filter on custom fields and capacity |
|
365 | 393 |
mock_planitech(monkeypatch, side_effect=side_effect) |
366 | 394 |
response = app.get( |
367 |
'/planitech/slug-planitech/getplacesreferential?referential_some_custom_field=Yes') |
|
395 |
'/planitech/slug-planitech/getplacesreferential?some_custom_field=Yes' |
|
396 |
'&min_capacity=25') |
|
368 | 397 |
assert response.json['data'] == { |
398 |
'3': { |
|
399 |
u'capacity': 30, u'label': u'salle 3', u'identifier': 3, |
|
400 |
'street_number': None, 'address': None, |
|
401 |
'city': None, 'zipcode': None, 'some_custom_field': 'Yes' |
|
402 |
} |
|
403 |
} |
|
404 | ||
405 |
# Unkown filter filters nothing |
|
406 |
response = app.get('/planitech/slug-planitech/getplacesreferential?unkownfilter=foo') |
|
407 |
expected_res = { |
|
408 |
'3': { |
|
409 |
u'capacity': 30, u'label': u'salle 3', u'identifier': 3, |
|
410 |
'street_number': None, 'address': None, |
|
411 |
'city': None, 'zipcode': None, 'some_custom_field': 'Yes' |
|
412 |
}, |
|
369 | 413 |
'2': { |
370 | 414 |
u'capacity': 20, u'label': u'salle 2', u'identifier': 2, |
371 | 415 |
'street_number': None, 'address': None, |
372 | 416 |
'city': None, 'zipcode': None, 'some_custom_field': 'Yes' |
417 |
}, |
|
418 |
'1': { |
|
419 |
u'capacity': 10, u'label': u'salle 1', u'identifier': 1, |
|
420 |
'street_number': 1, 'address': 'rue planitech', |
|
421 |
'city': 'thecity', 'zipcode': '00000', 'some_custom_field': None |
|
373 | 422 |
} |
374 | 423 |
} |
424 |
assert response.json['data'] == expected_res |
|
375 | 425 | |
376 | 426 | |
377 | 427 |
def test_getplace(app, connector, monkeypatch): |
... | ... | |
510 | 560 | |
511 | 561 |
def freegaps_data(): |
512 | 562 |
referential = { |
563 |
3.0: { |
|
564 |
u'capacity': 30.0, u'label': u'salle 2', u'identifier': 2.0, |
|
565 |
u'some_custom_field': u'Yes' |
|
566 |
}, |
|
513 | 567 |
2.0: { |
514 | 568 |
u'capacity': 20.0, u'label': u'salle 2', u'identifier': 2.0, |
515 | 569 |
u'some_custom_field': u'Yes' |
... | ... | |
619 | 673 |
call_params = mock_call_planitech.call_args[0][2] |
620 | 674 |
assert call_params['startingDate'] == datetime(2018, 11, 11, 10, 0) |
621 | 675 |
assert call_params['endingDate'] == datetime(2018, 11, 12, 00, 0) |
622 |
assert call_params['placeIdentifiers'] == [1.0, 2.0] |
|
676 |
assert call_params['placeIdentifiers'] == [1.0, 2.0, 3.0]
|
|
623 | 677 |
assert call_params['requestedStartingTime'] == 0.0 # means startingDate |
624 | 678 |
assert call_params['requestedEndingTime'] == 60.0 # means startingDate + 60 minutes |
625 | 679 |
assert call_params['reservationDays'] == [0, 6] # means every day of the week |
... | ... | |
645 | 699 |
call_params = mock_call_planitech.call_args[0][2] |
646 | 700 |
assert call_params['placeIdentifiers'] == [1.0] |
647 | 701 | |
648 |
# place_id parameter override capacity
|
|
702 |
# place_id disable filtering
|
|
649 | 703 |
mock_call_planitech.reset_mock() |
650 | 704 |
response = app.get( |
651 | 705 |
'/planitech/slug-planitech/getfreegaps?start_time=11:00&&end_time=14:00' |
... | ... | |
668 | 722 |
mock_call_planitech.reset_mock() |
669 | 723 |
response = app.get( |
670 | 724 |
'/planitech/slug-planitech/getfreegaps?start_time=11:00&&end_time=14:00' |
671 |
'&start_date=2018-11-11&referential_some_custom_field=Yes&display=place'
|
|
725 |
'&start_date=2018-11-11&some_custom_field=Yes&display=place' |
|
672 | 726 |
) |
673 | 727 |
call_params = mock_call_planitech.call_args[0][2] |
674 |
assert call_params['placeIdentifiers'] == [2.0] |
|
728 |
assert call_params['placeIdentifiers'] == [2.0, 3.0] |
|
729 | ||
730 |
# custom field and capacity restriction |
|
731 |
mock_call_planitech.reset_mock() |
|
732 |
response = app.get( |
|
733 |
'/planitech/slug-planitech/getfreegaps?start_time=11:00&&end_time=14:00' |
|
734 |
'&start_date=2018-11-11&some_custom_field=Yes&min_capacity=25&display=place' |
|
735 |
) |
|
736 |
call_params = mock_call_planitech.call_args[0][2] |
|
737 |
assert call_params['placeIdentifiers'] == [3.0] |
|
675 | 738 | |
676 | 739 |
# BAD REQUEST |
677 | 740 |
# bad date format |
678 |
- |