0001-data_transfer-validate-uniqueness-of-roles-41342.patch
src/authentic2/data_transfer.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS |
|
17 | 18 |
from django.contrib.contenttypes.models import ContentType |
19 |
from django.utils.translation import ugettext_lazy as _ |
|
18 | 20 | |
19 | 21 |
from django_rbac.models import Operation |
20 | 22 |
from django_rbac.utils import ( |
21 | 23 |
get_ou_model, get_role_model, get_role_parenting_model, get_permission_model) |
24 | ||
25 |
from authentic2.decorators import errorcollector |
|
22 | 26 |
from authentic2.a2_rbac.models import RoleAttribute |
23 | 27 | |
24 | 28 | |
25 | 29 |
def update_model(obj, d): |
26 | 30 |
for attr, value in d.items(): |
27 | 31 |
setattr(obj, attr, value) |
32 |
errors = {} |
|
33 |
with errorcollector(errors): |
|
34 |
if hasattr(obj, 'validate'): |
|
35 |
obj.validate() |
|
36 | ||
37 |
with errorcollector(errors): |
|
38 |
if hasattr(obj, 'validate_unique'): |
|
39 |
obj.validate_unique() |
|
40 |
if errors: |
|
41 |
errorlist = [] |
|
42 |
for key, messages in list(errors.items()): |
|
43 |
if key == NON_FIELD_ERRORS: |
|
44 |
errorlist.extend(messages) |
|
45 |
else: |
|
46 |
value = getattr(obj, key) |
|
47 |
for error in messages: |
|
48 |
for message in error if isinstance(error, ValidationError) else [error]: |
|
49 |
errorlist.append(_(u'%s %s="%s": %s') % (obj.__class__._meta.verbose_name, key, value, message)) |
|
50 |
del errors[key] |
|
51 |
raise DataImportError(ValidationError(errorlist)) |
|
28 | 52 |
obj.save() |
29 | 53 | |
30 | 54 |
src/authentic2/manager/views.py | ||
---|---|---|
17 | 17 |
import json |
18 | 18 |
import inspect |
19 | 19 | |
20 |
from django.core.exceptions import PermissionDenied |
|
20 |
from django.core.exceptions import PermissionDenied, ValidationError
|
|
21 | 21 |
from django.db import transaction |
22 | 22 |
from django.views.generic.base import ContextMixin |
23 | 23 |
from django.views.generic import (FormView, UpdateView, CreateView, DeleteView, TemplateView, |
... | ... | |
708 | 708 | |
709 | 709 |
def form_valid(self, form): |
710 | 710 |
try: |
711 |
json_site = json.loads(force_text(
|
|
712 |
self.request.FILES['site_json'].read()))
|
|
711 |
json_site = json.loads( |
|
712 |
force_text(self.request.FILES['site_json'].read()))
|
|
713 | 713 |
except ValueError: |
714 | 714 |
form.add_error('site_json', _('File is not in the expected JSON format.')) |
715 | 715 |
return self.form_invalid(form) |
... | ... | |
718 | 718 |
with transaction.atomic(): |
719 | 719 |
import_site(json_site, ImportContext()) |
720 | 720 |
except DataImportError as e: |
721 |
form.add_error('site_json', six.text_type(e)) |
|
721 |
if e.args and isinstance(e.args[0], ValidationError): |
|
722 |
e = e.args[0] |
|
723 |
else: |
|
724 |
e = six.text_type(e) |
|
725 |
form.add_error('site_json', e) |
|
722 | 726 |
return self.form_invalid(form) |
723 | 727 | |
724 | 728 |
return super(SiteImportView, self).form_valid(form) |
tests/test_data_transfer.py | ||
---|---|---|
540 | 540 |
d = export_site(ExportContext(export_ous=False)) |
541 | 541 |
assert 'ous' not in d |
542 | 542 | |
543 | ||
544 |
def test_role_validate_unique(db): |
|
545 |
ou = OU.objects.create(name='ou', slug='ou') |
|
546 |
Role.objects.create(name='role1', slug='role1', ou=ou) |
|
547 |
Role.objects.create(name='role2', slug='role2', ou=ou) |
|
548 | ||
549 |
data = { |
|
550 |
'roles': [ |
|
551 |
{ |
|
552 |
'name': 'role1', |
|
553 |
'slug': 'role2', |
|
554 |
'ou': {'slug': 'ou'}, |
|
555 |
} |
|
556 |
] |
|
557 |
} |
|
558 |
with pytest.raises(DataImportError, match=r'role name="role1": Name already used'): |
|
559 |
import_site(data) |
|
543 |
- |