diff --git a/modoboa/core/models.py b/modoboa/core/models.py index cfb194e39..db3d05f22 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -17,7 +17,7 @@ from django.contrib.auth.models import ( from django.contrib.auth.hashers import make_password, is_password_usable from modoboa.lib import events, parameters from modoboa.lib.exceptions import ( - PermDeniedException, InternalError, BadRequest + PermDeniedException, InternalError, BadRequest, Conflict ) from modoboa.lib.sysutils import exec_cmd from modoboa.core.extensions import exts_pool @@ -325,6 +325,12 @@ class User(PermissionsMixin): _("You can't import an account with a role greater than yours") ) self.username = row[1].strip() + try: + User.objects.get(username=self.username) + except User.DoesNotExist: + pass + else: + raise Conflict if role == "SimpleUsers": if (len(row) < 8 or not row[7].strip()): raise BadRequest( diff --git a/modoboa/extensions/admin/models/alias.py b/modoboa/extensions/admin/models/alias.py index 327e4bf0c..62c0d6f5b 100644 --- a/modoboa/extensions/admin/models/alias.py +++ b/modoboa/extensions/admin/models/alias.py @@ -2,7 +2,9 @@ import reversion from django.db import models from django.utils.translation import ugettext as _, ugettext_lazy from modoboa.lib.emailutils import split_mailbox -from modoboa.lib.exceptions import PermDeniedException, BadRequest +from modoboa.lib.exceptions import ( + PermDeniedException, BadRequest, Conflict +) from .base import AdminObject from .domain import Domain from .mailbox import Mailbox @@ -155,6 +157,12 @@ class Alias(AdminObject): raise BadRequest(_("Domain '%s' does not exist" % domname)) if not user.can_access(domain): raise PermDeniedException + try: + Alias.objects.get(address=localpart, domain__name=domain) + except Alias.DoesNotExist: + pass + else: + raise Conflict self.address = localpart self.domain = domain self.enabled = (row[2].strip() == 'True') diff --git a/modoboa/extensions/admin/models/domain.py b/modoboa/extensions/admin/models/domain.py index 7c19710dd..c0a13d459 100644 --- a/modoboa/extensions/admin/models/domain.py +++ b/modoboa/extensions/admin/models/domain.py @@ -4,7 +4,7 @@ from django.db.models.manager import Manager from django.utils.translation import ugettext as _, ugettext_lazy from django.contrib.contenttypes import generic from modoboa.lib import events, parameters -from modoboa.lib.exceptions import BadRequest +from modoboa.lib.exceptions import BadRequest, Conflict from modoboa.core.models import User, ObjectAccess from .base import AdminObject @@ -131,9 +131,24 @@ class Domain(AdminObject): return self.name def from_csv(self, user, row): + """Create a new domain from a CSV entry. + + The expected fields order is the following:: + + "domain", name, quota, enabled + + :param ``core.User`` user: user creating the domain + :param str row: a list containing domain's definition + """ if len(row) < 4: raise BadRequest(_("Invalid line")) self.name = row[1].strip() + try: + Domain.objects.get(name=self.name) + except Domain.DoesNotExist: + pass + else: + raise Conflict try: self.quota = int(row[2].strip()) except ValueError: diff --git a/modoboa/extensions/admin/models/domain_alias.py b/modoboa/extensions/admin/models/domain_alias.py index a24549b96..29fe93037 100644 --- a/modoboa/extensions/admin/models/domain_alias.py +++ b/modoboa/extensions/admin/models/domain_alias.py @@ -38,12 +38,13 @@ class DomainAlias(AdminObject): if len(row) < 4: raise BadRequest(_("Invalid line")) self.name = row[1].strip() - try: - Domain.objects.get(name=self.name) - except Domain.DoesNotExist: - pass - else: - raise Conflict(_("A domain %s already exists" % self.name)) + for model in [DomainAlias, Domain]: + try: + model.objects.get(name=self.name) + except model.DoesNotExist: + pass + else: + raise Conflict domname = row[2].strip() try: self.target = Domain.objects.get(name=domname) diff --git a/modoboa/extensions/admin/tests/account.py b/modoboa/extensions/admin/tests/account.py index 8a79674bf..5ad4d556f 100644 --- a/modoboa/extensions/admin/tests/account.py +++ b/modoboa/extensions/admin/tests/account.py @@ -187,11 +187,6 @@ class PermissionsTestCase(ModoTestCase): account = User.objects.get(username="superadmin2@test.com") self.clt.logout() self.clt.login(username="admin@test.com", password="toto") - self.ajax_get( - reverse("modoboa.extensions.admin.views.identity.delaccount", - args=[account.id]), - {}, 403 - ) self.ajax_post( reverse("modoboa.extensions.admin.views.identity.delaccount", args=[account.id]), {}, 403 diff --git a/modoboa/extensions/admin/tests/export.py b/modoboa/extensions/admin/tests/export.py index c0e727e04..37b49c005 100644 --- a/modoboa/extensions/admin/tests/export.py +++ b/modoboa/extensions/admin/tests/export.py @@ -20,17 +20,27 @@ class ExportTestCase(ModoTestCase): {"filename": "test.csv"} ) + def assertListEqual(self, list1, list2): + list2 = list2.split('\r\n') + for entry in list1.split('\r\n'): + if not entry: + continue + self.assertIn(entry, list2) + def test_export_identities(self): response = self.__export_identities() - self.assertEqual(response.content, "account;admin;{CRYPT}dTTsGDkA5ZHKg;;;True;SuperAdmins;;\r\naccount;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com\r\naccount;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10\r\nalias;alias@test.com;True;user@test.com\r\nforward;forward@test.com;True;user@external.com\r\ndlist;postmaster@test.com;True;toto@titi.com;test@truc.fr\r\n") + self.assertListEqual( + "account;admin;{CRYPT}dTTsGDkA5ZHKg;;;True;SuperAdmins;;\r\naccount;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com\r\naccount;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10\r\nalias;alias@test.com;True;user@test.com\r\nforward;forward@test.com;True;user@external.com\r\ndlist;postmaster@test.com;True;toto@titi.com;test@truc.fr\r\n", + response.content.strip() + ) def test_export_simpleusers(self): response = self.__export_identities( idtfilter="account", grpfilter="SimpleUsers" ) - self.assertEqual( - response.content.strip(), - "account;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10" + self.assertListEqual( + "account;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10", + response.content.strip() ) def test_export_superadmins(self): @@ -46,9 +56,9 @@ class ExportTestCase(ModoTestCase): response = self.__export_identities( idtfilter="account", grpfilter="DomainAdmins" ) - self.assertEqual( - response.content.strip(), - "account;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com" + self.assertListEqual( + "account;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com", + response.content.strip() ) def test_export_aliases(self): diff --git a/modoboa/extensions/admin/tests/import_.py b/modoboa/extensions/admin/tests/import_.py index aeeba148e..8f02fed99 100644 --- a/modoboa/extensions/admin/tests/import_.py +++ b/modoboa/extensions/admin/tests/import_.py @@ -49,7 +49,7 @@ domainalias;test.alias;test.com;True "sourcefile": f } ) - self.assertIn('A domain test.alias already exists', resp.content) + self.assertIn('Object already exists: domainalias', resp.content) def test_identities_import(self): f = ContentFile(b""" diff --git a/modoboa/extensions/admin/views/import.py b/modoboa/extensions/admin/views/import.py index 5ea28efa4..be306e048 100644 --- a/modoboa/extensions/admin/views/import.py +++ b/modoboa/extensions/admin/views/import.py @@ -122,7 +122,7 @@ def importdata(request, formclass=ImportDataForm): fct = fct[0] try: fct(request.user, row, form.cleaned_data) - except IntegrityError, e: + except Conflict: if form.cleaned_data["continue_if_exists"]: continue raise Conflict( diff --git a/modoboa/lib/permissions.py b/modoboa/lib/permissions.py index 5cf677aaf..8834a5cfe 100644 --- a/modoboa/lib/permissions.py +++ b/modoboa/lib/permissions.py @@ -56,21 +56,18 @@ def grant_access_to_object(user, obj, is_owner=False): else: return - try: - ObjectAccess.objects.create(user=user, content_type=ct, - object_id=obj.id, is_owner=is_owner) - if is_owner: - from modoboa.core.models import User - for su in User.objects.filter(is_superuser=True): - if su == user: - continue - try: - ObjectAccess.objects.create(user=su, content_type=ct, object_id=obj.id) - except IntegrityError: - pass - - except IntegrityError, e: - raise ModoboaException(_("Failed to grant access (%s)" % str(e))) + ObjectAccess.objects.create( + user=user, content_type=ct, object_id=obj.id, is_owner=is_owner + ) + if not is_owner: + return + from modoboa.core.models import User + for su in User.objects.filter(is_superuser=True): + if su == user: + continue + ObjectAccess.objects.get_or_create( + user=su, content_type=ct, object_id=obj.id + ) def grant_access_to_objects(user, objects, ct):