Projet

Général

Profil

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

Paul Marillonnet, 31 juillet 2020 17:24

Télécharger (3,75 ko)

Voir les différences:

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

 src/authentic2/api_mixins.py | 12 ++++++++++++
 tests/test_api.py            | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
src/authentic2/api_mixins.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.db import transaction
18
from django.utils.translation import ugettext_lazy as _
18 19

  
20
from rest_framework import status
19 21
from rest_framework.settings import api_settings
22
from rest_framework.exceptions import APIException
20 23
from rest_framework.exceptions import ValidationError
21 24
from rest_framework.utils import model_meta
22 25

  
23 26

  
27
class Conflict(APIException):
28
    status_code = status.HTTP_409_CONFLICT
29
    default_detail = _('Cannot process request because of conflicting resources.')
30
    default_code = 'conflict'
31

  
32

  
24 33
class GetOrCreateMixinView(object):
25 34
    _lookup_object = None
26 35

  
......
49 58
            return ModelClass.objects.get(**kwargs)
50 59
        except ModelClass.DoesNotExist:
51 60
            return None
61
        except ModelClass.MultipleObjectsReturned:
62
            raise Conflict('retrieved several instances of model %s for key attributes %s' % (
63
                    ModelClass.__name__, kwargs))
52 64

  
53 65
    def _validate_get_keys(self, keys):
54 66
        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
-