Projet

Général

Profil

0003-data_transfer-validate-models-before-updating-creati.patch

Benjamin Dauvergne, 15 avril 2020 11:42

Télécharger (3,36 ko)

Voir les différences:

Subject: [PATCH 3/4] data_transfer: validate models before updating/creating
 them (#41342)

To prevent collision between roles when altering their name and their
slug is already unique. Ex.:

   R1(slug=a, name=A) -import-> R1(slug=a, name=B)
   R2(slug=b, name=B)
 src/authentic2/data_transfer.py | 29 ++++++++++++++++++++++++++++-
 tests/test_data_transfer.py     | 17 +++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)
src/authentic2/data_transfer.py
16 16

  
17 17
from functools import wraps
18 18

  
19
from django.core.exceptions import ValidationError
19
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
20 20
from django.contrib.contenttypes.models import ContentType
21 21
from django.utils.translation import ugettext_lazy as _
22
from django.utils.text import format_lazy
22 23

  
23 24
from django_rbac.models import Operation
24 25
from django_rbac.utils import (
25 26
    get_ou_model, get_role_model, get_role_parenting_model, get_permission_model)
26 27

  
28
from authentic2.decorators import errorcollector
27 29
from authentic2.a2_rbac.models import RoleAttribute
28 30
from authentic2.utils.lazy import lazy_join
29 31

  
......
31 33
def update_model(obj, d):
32 34
    for attr, value in d.items():
33 35
        setattr(obj, attr, value)
36
    errors = {}
37
    with errorcollector(errors):
38
        if hasattr(obj, 'validate'):
39
            obj.validate()
40

  
41
    with errorcollector(errors):
42
        if hasattr(obj, 'validate_unique'):
43
            obj.validate_unique()
44
    if errors:
45
        errorlist = []
46
        for key, messages in list(errors.items()):
47
            if key == NON_FIELD_ERRORS:
48
                errorlist.extend(messages)
49
            else:
50
                value = getattr(obj, key)
51

  
52
                def error_list(messages):
53
                    for message in messages:
54
                        if isinstance(message, ValidationError):
55
                            yield message.message
56
                        else:
57
                            yield message
58
                for message in error_list(messages):
59
                    errorlist.append(format_lazy(u'{}="{}": {}', obj.__class__._meta.get_field(key).verbose_name, value, message))
60
        raise ValidationError(errorlist)
34 61
    obj.save()
35 62

  
36 63

  
tests/test_data_transfer.py
542 542
    d = export_site(ExportContext(export_ous=False))
543 543
    assert 'ous' not in d
544 544

  
545

  
546
def test_role_validate_unique(db):
547
    ou = OU.objects.create(name='ou', slug='ou')
548
    Role.objects.create(name='role1', slug='role1', ou=ou)
549
    Role.objects.create(name='role2', slug='role2', ou=ou)
550

  
551
    data = {
552
        'roles': [
553
            {
554
                'name': 'role1',
555
                'slug': 'role2',
556
                'ou': {'slug': 'ou'},
557
            }
558
        ]
559
    }
560
    with pytest.raises(ValidationError, match=r'Role "role1": name="role1": Name already used'):
561
        import_site(data)
545
-