Projet

Général

Profil

0001-api-handle-multiple-objects-returned-in-get-or-creat.patch

Paul Marillonnet, 31 juillet 2020 16:29

Télécharger (5,02 ko)

Voir les différences:

Subject: [PATCH] api: handle multiple objects returned in get-or-create mixin
 (#44301)

 src/authentic2/api_exceptions.py | 26 ++++++++++++++++++++++++
 src/authentic2/api_mixins.py     |  7 ++++++-
 tests/test_api.py                | 35 ++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 1 deletion(-)
 create mode 100644 src/authentic2/api_exceptions.py
src/authentic2/api_exceptions.py
1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2020 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from django.utils.translation import ugettext_lazy as _
18

  
19
from rest_framework.exceptions import APIException
20
from rest_framework import status
21

  
22

  
23
class Conflict(APIException):
24
    status_code = status.HTTP_409_CONFLICT
25
    default_detail = _('Cannot process request because of conflicting resources.')
26
    default_code = 'conflict'
src/authentic2/api_mixins.py
1 1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2018 Entr'ouvert
2
# Copyright (C) 2010-2020 Entr'ouvert
3 3
#
4 4
# This program is free software: you can redistribute it and/or modify it
5 5
# under the terms of the GNU Affero General Public License as published
......
20 20
from rest_framework.exceptions import ValidationError
21 21
from rest_framework.utils import model_meta
22 22

  
23
from .api_exceptions import Conflict
24

  
23 25

  
24 26
class GetOrCreateMixinView(object):
25 27
    _lookup_object = None
......
49 51
            return ModelClass.objects.get(**kwargs)
50 52
        except ModelClass.DoesNotExist:
51 53
            return None
54
        except ModelClass.MultipleObjectsReturned:
55
            raise Conflict('retrieved several instances of model %s for key attributes %s' % (
56
                    ModelClass.__name__, kwargs))
52 57

  
53 58
    def _validate_get_keys(self, keys):
54 59
        ModelClass = self._get_model_class()
tests/test_api.py
1420 1420
    assert User.objects.get(id=id).last_name == 'Doe'
1421 1421

  
1422 1422

  
1423
def test_api_users_get_or_create_email_not_unique(settings, app, admin):
1424
    settings.A2_EMAIL_IS_UNIQUE = False
1425
    User = get_user_model()
1426
    OU = get_ou_model()
1427
    ou1 = OU.objects.create(name='OU1', slug='ou1', email_is_unique=True)
1428
    ou2 = OU.objects.create(name='OU2', slug='ou2', email_is_unique=False)
1429

  
1430
    app.authorization = ('Basic', (admin.username, admin.username))
1431
    payload = {
1432
        'email': 'john.doe@example.net',
1433
        'first_name': 'John',
1434
        'last_name': 'Doe',
1435
        'ou': 'ou1'
1436
    }
1437
    # 1. create
1438
    resp = app.post_json('/api/users/?get_or_create=email', params=payload, status=201)
1439
    id_user = resp.json['id']
1440
    assert User.objects.get(id=id_user).first_name == 'John'
1441
    assert User.objects.get(id=id_user).last_name == 'Doe'
1442
    assert User.objects.get(id=id_user).ou == ou1
1443
    # 2. get
1444
    resp = app.post_json('/api/users/?get_or_create=email', params=payload, status=200)
1445
    # 3. explicitly create in a different OU
1446
    payload['ou'] = 'ou2'
1447
    resp = app.post_json('/api/users/', params=payload, status=201)
1448
    id_user2 = resp.json['id']
1449
    assert id_user2 != id_user
1450
    assert User.objects.get(id=id_user2).first_name == 'John'
1451
    assert User.objects.get(id=id_user2).last_name == 'Doe'
1452
    assert User.objects.get(id=id_user2).ou == ou2
1453
    # 4. fail to retrieve a single instance for an ambiguous get-or-create key
1454
    resp = app.post_json('/api/users/?get_or_create=email', params=payload, status=409)
1455
    assert resp.json['errors'] == "retrieved several instances of model User for key attributes {'email': 'john.doe@example.net'}"
1456

  
1457

  
1423 1458
def test_api_users_get_or_create_multi_key(settings, app, admin):
1424 1459
    app.authorization = ('Basic', (admin.username, admin.username))
1425 1460
    # test missing first_name
1426
-