Projet

Général

Profil

0001-planitec-filters-homogenisation-32828.patch

Emmanuel Cazenave, 17 mai 2019 16:09

Télécharger (12,9 ko)

Voir les différences:

Subject: [PATCH] planitec: filters homogenisation (#32828)

 passerelle/contrib/planitech/models.py | 81 +++++++++++++-------------
 tests/test_planitech.py                | 77 +++++++++++++++++++++---
 2 files changed, 109 insertions(+), 49 deletions(-)
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
-