diff --git a/modoboa/core/fixtures/initial_users.json b/modoboa/core/fixtures/initial_users.json index bf60843ba..0986e6fb0 100644 --- a/modoboa/core/fixtures/initial_users.json +++ b/modoboa/core/fixtures/initial_users.json @@ -1 +1 @@ -[{"pk": 1, "model": "core.user", "fields": {"username": "admin", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": false, "last_login": "2012-01-26 15:19:25", "groups": [], "user_permissions": [], "password": "{CRYPT}dTTsGDkA5ZHKg", "email": "", "date_joined": "2012-01-26 15:19:25"}},{"pk": 1, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["core", "user"], "object_id": 1}}] \ No newline at end of file +[{"pk": 1, "model": "core.user", "fields": {"username": "admin", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": false, "last_login": "2012-01-26T15:19:26+01:00", "groups": [], "user_permissions": [], "password": "{CRYPT}dTTsGDkA5ZHKg", "email": "", "date_joined": "2012-01-26T15:19:26+01:00"}},{"pk": 1, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["core", "user"], "object_id": 1}}] \ No newline at end of file diff --git a/modoboa/core/models.py b/modoboa/core/models.py index 73afefc4a..3b906618d 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -304,11 +304,13 @@ class User(PermissionsMixin): self.post_create(creator) def from_csv(self, user, row, crypt_password=True): - """Create a new account from a CSV file entry + """Create a new account from a CSV file entry. The expected order is the following:: - "account", loginname, password, first name, last name, enabled, group, address[, domain, ...] + "account", loginname, password, first name, last name, enabled, group + + Additional fields can be added using the *AccountImported* event. :param user: a ``core.User`` instance :param row: a list containing the expected information @@ -346,6 +348,12 @@ class User(PermissionsMixin): events.raiseEvent("AccountImported", user, self, row[7:]) def to_csv(self, csvwriter): + """Export this account. + + The CSV format is used to export. + + :param csvwriter: csv object + """ row = ["account", self.username.encode("utf-8"), self.password.encode("utf-8"), self.first_name.encode("utf-8"), self.last_name.encode("utf-8"), self.is_active, self.group, self.email.encode("utf-8")] diff --git a/modoboa/extensions/admin/__init__.py b/modoboa/extensions/admin/__init__.py index 8a7629a80..7cc61f157 100644 --- a/modoboa/extensions/admin/__init__.py +++ b/modoboa/extensions/admin/__init__.py @@ -133,13 +133,25 @@ def grant_access_to_all_objects(user, role): @events.observe("AccountExported") def export_admin_domains(admin): + result = [admin.mailbox_set.all()[0].quota] \ + if admin.mailbox_set.count() else [''] if admin.group != "DomainAdmins": - return [] - return [dom.name for dom in Domain.objects.get_for_admin(admin)] + return result + return result + [dom.name for dom in Domain.objects.get_for_admin(admin)] @events.observe("AccountImported") def import_account_mailbox(user, account, row): + """Handle extra fields when an account is imported. + + Expected fields: + + email address; quota; [domain; ...] + + :param User user: user importing the account + :param User account: account being imported + :param list rom: list of fields (strings) + """ account.email = row[0].strip() if account.email != "": account.save() @@ -152,12 +164,14 @@ def import_account_mailbox(user, account, row): ) if not user.can_access(domain): raise PermDeniedException + quota = int(row[1].strip()) + use_domain_quota = True if not quota else False mb = Mailbox(address=mailbox, domain=domain, - user=account, use_domain_quota=True) - mb.set_quota(override_rules=user.has_perm("admin.change_domain")) + user=account, use_domain_quota=use_domain_quota) + mb.set_quota(quota, override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) if account.group == "DomainAdmins": - for domname in row[1:]: + for domname in row[2:]: try: dom = Domain.objects.get(name=domname.strip()) except Domain.DoesNotExist: diff --git a/modoboa/extensions/admin/factories.py b/modoboa/extensions/admin/factories.py index 9ab089912..306d29914 100644 --- a/modoboa/extensions/admin/factories.py +++ b/modoboa/extensions/admin/factories.py @@ -13,11 +13,13 @@ class MailboxFactory(PermissionFactory): FACTORY_FOR = models.Mailbox quota = 10 + enabled = True class AliasFactory(PermissionFactory): FACTORY_FOR = models.Alias + enabled = True def populate_database(): """Create test data. diff --git a/modoboa/extensions/admin/fixtures/initial_users.json b/modoboa/extensions/admin/fixtures/initial_users.json deleted file mode 100644 index b67729ef2..000000000 --- a/modoboa/extensions/admin/fixtures/initial_users.json +++ /dev/null @@ -1 +0,0 @@ -[{"pk": 1, "model": "core.user", "fields": {"username": "admin", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": false, "is_local": true, "last_login": "2012-01-26 15:19:25", "groups": [], "user_permissions": [], "password": "{CRYPT}dTTsGDkA5ZHKg", "email": "", "date_joined": "2012-01-26 15:19:25"}},{"pk": 1, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["core", "user"], "object_id": 1}}] \ No newline at end of file diff --git a/modoboa/extensions/admin/fixtures/test_content.json b/modoboa/extensions/admin/fixtures/test_content.json deleted file mode 100644 index 98782351b..000000000 --- a/modoboa/extensions/admin/fixtures/test_content.json +++ /dev/null @@ -1 +0,0 @@ -[{"pk": 2, "model": "admin.user", "fields": {"username": "user@test.com", "is_active": "True", "is_superuser": "False", "password": "{PLAIN}toto", "groups": [2]}},{"pk": 3, "model": "admin.user", "fields": {"username": "admin@test.com", "is_active": "True", "is_superuser": "False", "password": "{PLAIN}toto", "groups": [1]}},{"pk": 4, "model": "admin.user", "fields": {"username": "superadmin@test.com", "is_active": "True", "is_superuser": "True", "password": "{PLAIN}toto", "groups": []}},{"pk": 1, "model": "admin.ObjectDates", "fields": {"creation": "2011-09-07 09:27:07.579603", "last_modification": "2011-09-07 09:27:07.579603"}}, {"pk": 2, "model": "admin.ObjectDates", "fields": {"creation": "2011-09-07 09:27:07.579603", "last_modification": "2011-09-07 09:27:07.579603"}}, {"pk": 3, "model": "admin.ObjectDates", "fields": {"creation": "2011-09-07 09:27:07.579603", "last_modification": "2011-09-07 09:27:07.579603"}}, {"pk": 1, "model": "admin.Domain", "fields": {"name" : "test.com", "quota" : "100", "dates": "1"}}, {"pk": 1, "model": "admin.Mailbox", "fields": {"address": "user", "domain": "1", "dates": "1", "quota": "10", "user": "2"}}, {"pk": 2, "model": "admin.Mailbox", "fields": {"address": "admin", "domain": "1", "dates": "2", "quota": "10", "user": "3"}}, {"pk": 3, "model": "admin.Mailbox", "fields": {"address": "superadmin", "domain": "1", "dates": "3", "quota": "10", "user": "4"}}, {"pk": "user@test.com", "model": "admin.Quota", "fields": {"mbox": 1, "username": "user@test.com", "bytes": 0, "messages": 0}}, {"pk": "admin@test.com", "model": "admin.Quota", "fields": {"mbox": 2, "username": "admin@test.com", "bytes": 0, "messages": 0}}, {"pk": "superadmin@test.com", "model": "admin.Quota", "fields": {"mbox": 3, "username": "superadmin@test.com", "bytes": 0, "messages": 0}},{"pk": 2, "model": "admin.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "user"], "object_id": 2}},{"pk": 3, "model": "admin.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "user"], "object_id": 3}}] diff --git a/modoboa/extensions/admin/tests/export.py b/modoboa/extensions/admin/tests/export.py index 093865af4..c0e727e04 100644 --- a/modoboa/extensions/admin/tests/export.py +++ b/modoboa/extensions/admin/tests/export.py @@ -22,7 +22,7 @@ class ExportTestCase(ModoTestCase): 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;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;test2.com\r\naccount;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com\r\nalias;alias@test.com;False;user@test.com\r\nforward;forward@test.com;False;user@external.com\r\ndlist;postmaster@test.com;False;toto@titi.com;test@truc.fr\r\n") + 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") def test_export_simpleusers(self): response = self.__export_identities( @@ -30,7 +30,7 @@ class ExportTestCase(ModoTestCase): ) self.assertEqual( response.content.strip(), - "account;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com" + "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" ) def test_export_superadmins(self): @@ -39,7 +39,7 @@ class ExportTestCase(ModoTestCase): ) self.assertEqual( response.content.strip(), - "account;admin;{CRYPT}dTTsGDkA5ZHKg;;;True;SuperAdmins;" + "account;admin;{CRYPT}dTTsGDkA5ZHKg;;;True;SuperAdmins;;" ) def test_export_domainadmins(self): @@ -48,26 +48,26 @@ class ExportTestCase(ModoTestCase): ) self.assertEqual( response.content.strip(), - "account;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;test2.com" + "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" ) def test_export_aliases(self): response = self.__export_identities(idtfilter="alias") self.assertEqual( response.content.strip(), - "alias;alias@test.com;False;user@test.com" + "alias;alias@test.com;True;user@test.com" ) def test_export_forwards(self): response = self.__export_identities(idtfilter="forward") self.assertEqual( response.content.strip(), - "forward;forward@test.com;False;user@external.com" + "forward;forward@test.com;True;user@external.com" ) def test_export_dlists(self): response = self.__export_identities(idtfilter="dlist") self.assertEqual( response.content.strip(), - "dlist;postmaster@test.com;False;toto@titi.com;test@truc.fr" + "dlist;postmaster@test.com;True;toto@titi.com;test@truc.fr" ) diff --git a/modoboa/extensions/admin/tests/import_.py b/modoboa/extensions/admin/tests/import_.py index 89ffdffdd..aeeba148e 100644 --- a/modoboa/extensions/admin/tests/import_.py +++ b/modoboa/extensions/admin/tests/import_.py @@ -53,8 +53,8 @@ domainalias;test.alias;test.com;True def test_identities_import(self): f = ContentFile(b""" -account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com -account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; test.com +account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; 0 +account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; 5; test.com alias; alias1@test.com; True; user1@test.com forward; fwd1@test.com; True; user@extdomain.com dlist; dlist@test.com; True; user1@test.com; user@extdomain.com @@ -65,20 +65,26 @@ dlist; dlist@test.com; True; user1@test.com; user@extdomain.com ) admin = User.objects.get(username="admin") u1 = User.objects.get(username="user1@test.com") + mb1 = u1.mailbox_set.all()[0] self.assertTrue(admin.is_owner(u1)) self.assertEqual(u1.email, "user1@test.com") self.assertEqual(u1.first_name, "User") self.assertEqual(u1.last_name, "One") self.assertTrue(u1.is_active) self.assertEqual(u1.group, "SimpleUsers") - self.assertTrue(admin.is_owner(u1.mailbox_set.all()[0])) - self.assertEqual(u1.mailbox_set.all()[0].full_address, "user1@test.com") + self.assertTrue(mb1.use_domain_quota) + self.assertEqual(mb1.quota, 0) + self.assertTrue(admin.is_owner(mb1)) + self.assertEqual(mb1.full_address, "user1@test.com") self.assertTrue(self.clt.login(username="user1@test.com", password="toto")) da = User.objects.get(username="truc@test.com") + damb = da.mailbox_set.all()[0] self.assertEqual(da.first_name, u"René") self.assertEqual(da.group, "DomainAdmins") - self.assertEqual(da.mailbox_set.all()[0].full_address, "truc@test.com") + self.assertEqual(damb.quota, 5) + self.assertFalse(damb.use_domain_quota) + self.assertEqual(damb.full_address, "truc@test.com") dom = Domain.objects.get(name="test.com") self.assertIn(da, dom.admins) u = User.objects.get(username="user@test.com") @@ -97,10 +103,22 @@ dlist; dlist@test.com; True; user1@test.com; user@extdomain.com self.assertIn("user@extdomain.com", dlist.extmboxes) self.assertTrue(admin.is_owner(dlist)) + def test_import_invalid_quota(self): + self.clt.logout() + self.clt.login(username="admin@test.com", password="toto") + f = ContentFile(b""" +account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; 20 +""", name="identities.csv") + resp = self.clt.post( + reverse("modoboa.extensions.admin.views.import.import_identities"), + {"sourcefile": f, "crypt_password": True} + ) + self.assertIn('Quota is greater than the allowed', resp.content) + def test_import_duplicate(self): f = ContentFile(b""" -account; admin@test.com; toto; Admin; ; True; DomainAdmins; admin@test.com; test.com -account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; test.com +account; admin@test.com; toto; Admin; ; True; DomainAdmins; admin@test.com; 0; test.com +account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; 0; test.com """, name="identities.csv") self.clt.post( reverse("modoboa.extensions.admin.views.import.import_identities"), @@ -119,7 +137,7 @@ account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; te self.clt.logout() self.assertTrue(self.clt.login(username="admin@test.com", password="toto")) f = ContentFile(b""" -account; sa@test.com; toto; Super; Admin; True; SuperAdmins; superadmin@test.com +account; sa@test.com; toto; Super; Admin; True; SuperAdmins; superadmin@test.com; 50 """, name="identities.csv") self.clt.post( reverse("modoboa.extensions.admin.views.import.import_identities"), diff --git a/modoboa/extensions/admin/views/import.py b/modoboa/extensions/admin/views/import.py index 52497d051..5ea28efa4 100644 --- a/modoboa/extensions/admin/views/import.py +++ b/modoboa/extensions/admin/views/import.py @@ -152,7 +152,7 @@ def import_identities(request): helptext = _("""Provide a CSV file where lines respect one of the following formats: