diff --git a/modoboa/core/factories.py b/modoboa/core/factories.py new file mode 100644 index 000000000..19767d20e --- /dev/null +++ b/modoboa/core/factories.py @@ -0,0 +1,34 @@ +import factory +from django.contrib.auth.models import Group +from . import models + + +class GroupFactory(factory.DjangoModelFactory): + FACTORY_FOR = Group + + name = 'DefaultGroup' + + +class UserFactory(factory.DjangoModelFactory): + FACTORY_FOR = models.User + + email = factory.LazyAttribute(lambda a: a.username) + password = '{PLAIN}toto' + + # mailbox = factory.RelatedFactory( + # MailboxFactory, 'user', + # address=factory.LazyAttribute( + # lambda m: m.user.email.replace('@%s' % m.domain.name, '') + # ) + # ) + + @factory.post_generation + def groups(self, create, extracted, **kwargs): + if not create: + # Simple build, do nothing. + return + + if extracted: + # A list of groups were passed in, use them + for group in extracted: + self.groups.add(Group.objects.get(name=group)) diff --git a/modoboa/core/forms.py b/modoboa/core/forms.py index 00c2119a0..4dc7d38ae 100644 --- a/modoboa/core/forms.py +++ b/modoboa/core/forms.py @@ -49,7 +49,7 @@ class ProfileForm(forms.ModelForm): if self.cleaned_data["oldpassword"] == "": return self.cleaned_data["oldpassword"] - if parameters.get_admin("AUTHENTICATION_TYPE", app="admin") != "local": + if parameters.get_admin("AUTHENTICATION_TYPE") != "local": return self.cleaned_data["oldpassword"] if not self.instance.check_password(self.cleaned_data["oldpassword"]): diff --git a/modoboa/core/migrations/0001_initial.py b/modoboa/core/migrations/0001_initial.py new file mode 100644 index 000000000..4b0bbe9ed --- /dev/null +++ b/modoboa/core/migrations/0001_initial.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'User' + db.create_table(u'core_user', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('password', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('last_login', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('is_superuser', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('username', self.gf('django.db.models.fields.CharField')(unique=True, max_length=254)), + ('first_name', self.gf('django.db.models.fields.CharField')(max_length=30, blank=True)), + ('last_name', self.gf('django.db.models.fields.CharField')(max_length=30, blank=True)), + ('email', self.gf('django.db.models.fields.EmailField')(max_length=254, blank=True)), + ('is_staff', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('date_joined', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('is_local', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal(u'core', ['User']) + + # Adding M2M table for field groups on 'User' + db.create_table(u'core_user_groups', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('user', models.ForeignKey(orm[u'core.user'], null=False)), + ('group', models.ForeignKey(orm[u'auth.group'], null=False)) + )) + db.create_unique(u'core_user_groups', ['user_id', 'group_id']) + + # Adding M2M table for field user_permissions on 'User' + db.create_table(u'core_user_user_permissions', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('user', models.ForeignKey(orm[u'core.user'], null=False)), + ('permission', models.ForeignKey(orm[u'auth.permission'], null=False)) + )) + db.create_unique(u'core_user_user_permissions', ['user_id', 'permission_id']) + + # Adding model 'ObjectAccess' + db.create_table(u'core_objectaccess', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.User'])), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('is_owner', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal(u'core', ['ObjectAccess']) + + # Adding unique constraint on 'ObjectAccess', fields ['user', 'content_type', 'object_id'] + db.create_unique(u'core_objectaccess', ['user_id', 'content_type_id', 'object_id']) + + # Adding model 'Extension' + db.create_table(u'core_extension', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=150)), + ('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal(u'core', ['Extension']) + + # Adding model 'Log' + db.create_table(u'core_log', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('message', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('level', self.gf('django.db.models.fields.CharField')(max_length=15)), + ('logger', self.gf('django.db.models.fields.CharField')(max_length=30)), + )) + db.send_create_signal(u'core', ['Log']) + + + def backwards(self, orm): + # Removing unique constraint on 'ObjectAccess', fields ['user', 'content_type', 'object_id'] + db.delete_unique(u'core_objectaccess', ['user_id', 'content_type_id', 'object_id']) + + # Deleting model 'User' + db.delete_table(u'core_user') + + # Removing M2M table for field groups on 'User' + db.delete_table('core_user_groups') + + # Removing M2M table for field user_permissions on 'User' + db.delete_table('core_user_user_permissions') + + # Deleting model 'ObjectAccess' + db.delete_table(u'core_objectaccess') + + # Deleting model 'Extension' + db.delete_table(u'core_extension') + + # Deleting model 'Log' + db.delete_table(u'core_log') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.extension': { + 'Meta': {'object_name': 'Extension'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + u'core.log': { + 'Meta': {'object_name': 'Log'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'logger': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'message': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}) + }, + u'core.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + } + } + + complete_apps = ['core'] \ No newline at end of file diff --git a/modoboa/core/migrations/0002_update_permissions.py b/modoboa/core/migrations/0002_update_permissions.py new file mode 100644 index 000000000..8e8e4c481 --- /dev/null +++ b/modoboa/core/migrations/0002_update_permissions.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + depends_on = ( + ('admin', '0037_rename_tables'), + ) + + def forwards(self, orm): + "Write your forwards methods here." + oldct = orm['contenttypes.ContentType'].objects.get( + app_label='admin', model='user' + ) + newct = orm['contenttypes.ContentType'].objects.get( + app_label='core', model='user' + ) + orm['core.ObjectAccess'].objects.filter(content_type=oldct).update( + content_type=newct + ) + orm['reversion.Version'].objects.filter(content_type=oldct).update( + content_type=newct + ) + oldct.delete() + + def backwards(self, orm): + "Write your backwards methods here." + newct = orm['contenttypes.ContentType'].objects.create( + app_label='admin', model='user', name='user' + ) + oldct = orm['contenttypes.ContentType'].objects.get( + app_label='core', model='user' + ) + orm['core.ObjectAccess'].objects.filter(content_type=oldct).update( + content_type=newct + ) + orm['reversion.Version'].objects.filter(content_type=oldct).update( + content_type=newct + ) + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.extension': { + 'Meta': {'object_name': 'Extension'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + u'core.log': { + 'Meta': {'object_name': 'Log'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'logger': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'message': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}) + }, + u'core.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'reversion.revision': { + 'Meta': {'object_name': 'Revision'}, + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'manager_slug': ('django.db.models.fields.CharField', [], {'default': "u'default'", 'max_length': '200', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']", 'null': 'True', 'blank': 'True'}) + }, + u'reversion.version': { + 'Meta': {'object_name': 'Version'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + 'format': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.TextField', [], {}), + 'object_id_int': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'object_repr': ('django.db.models.fields.TextField', [], {}), + 'revision': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['reversion.Revision']"}), + 'serialized_data': ('django.db.models.fields.TextField', [], {}), + 'type': ('django.db.models.fields.PositiveSmallIntegerField', [], {'db_index': 'True'}) + } + } + + complete_apps = ['reversion', 'core'] + symmetrical = True diff --git a/modoboa/core/migrations/__init__.py b/modoboa/core/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modoboa/core/models.py b/modoboa/core/models.py index 7e8b887c8..71364982d 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -54,7 +54,6 @@ class User(AbstractBaseUser, PermissionsMixin): REQUIRED_FIELDS = ['email'] class Meta: - db_table = "admin_user" ordering = ["username"] password_expr = re.compile(r'(\{(\w+)\}|(\$1\$))(.+)') @@ -86,7 +85,7 @@ class User(AbstractBaseUser, PermissionsMixin): events.raiseEvent("AccountDeleted", self, fromuser, **kwargs) ungrant_access_to_object(self) - super(User, self).delete(*args, **kwargs) + super(User, self).delete() def _crypt_password(self, raw_value): scheme = parameters.get_admin("PASSWORD_SCHEME") @@ -312,13 +311,13 @@ class User(AbstractBaseUser, PermissionsMixin): The expected order is the following:: - loginname, password, first name, last name, enabled, group, address[, domain, ...] + "account", loginname, password, first name, last name, enabled, group, address[, domain, ...] :param user: :param row: a list containing the expected information :param crypt_password: """ - if len(row) < 6: + if len(row) < 7: raise AdminError(_("Invalid line")) role = row[6].strip() if not user.is_superuser and not role in ["SimpleUsers", "DomainAdmins"]: @@ -326,6 +325,16 @@ class User(AbstractBaseUser, PermissionsMixin): _("You can't import an account with a role greater than yours") ) self.username = row[1].strip() + if role == "SimpleUsers": + if (len(row) < 8 or not row[7].strip()): + raise AdminError( + _("The simple user '%s' must have a valid email address" % self.username) + ) + if self.username != row[7].strip(): + raise AdminError( + _("username and email fields must not differ for '%s'" % self.username) + ) + if crypt_password: self.set_password(row[2].strip()) else: @@ -335,6 +344,8 @@ class User(AbstractBaseUser, PermissionsMixin): self.is_active = (row[5].strip() == 'True') self.save(creator=user) self.set_role(role) + if len(row) < 8: + return events.raiseEvent("AccountImported", user, self, row[7:]) def to_csv(self, csvwriter): diff --git a/modoboa/core/tests.py b/modoboa/core/tests.py new file mode 100644 index 000000000..5b3491ba2 --- /dev/null +++ b/modoboa/core/tests.py @@ -0,0 +1,42 @@ +from django.core.urlresolvers import reverse +from modoboa.lib.tests import ModoTestCase +from . import factories + + +class ProfileTestCase(ModoTestCase): + fixtures = ['initial_users.json'] + + def setUp(self): + super(ProfileTestCase, self).setUp() + self.account = factories.UserFactory( + username="user@test.com", groups=('SimpleUsers',) + ) + + def test_update_password(self): + """Password update + + Two cases: + * The default admin changes his password (no associated Mailbox) + * A normal user changes his password + """ + self.check_ajax_post(reverse("modoboa.core.views.user.profile"), + {"oldpassword": "password", + "newpassword": "titi", "confirmation": "titi"}) + self.clt.logout() + + self.assertEqual( + self.clt.login(username="admin", password="titi"), True + ) + self.assertEqual( + self.clt.login(username="user@test.com", password="toto"), True + ) + + self.check_ajax_post( + reverse("modoboa.core.views.user.profile"), + {"oldpassword": "toto", + "newpassword": "tutu", "confirmation": "tutu"} + ) + self.clt.logout() + self.assertEqual( + self.clt.login(username="user@test.com", password="tutu"), True + ) diff --git a/modoboa/extensions/admin/__init__.py b/modoboa/extensions/admin/__init__.py index 4677515d9..763ff5054 100644 --- a/modoboa/extensions/admin/__init__.py +++ b/modoboa/extensions/admin/__init__.py @@ -70,7 +70,7 @@ def admin_menu(target, user): "url" : reverse("modoboa.extensions.admin.views.domain.domains"), "label" : _("Domains")} ] - if user.has_perm("admin.add_user") or user.has_perm("admin.add_alias"): + if user.has_perm("core.add_user") or user.has_perm("admin.add_alias"): entries += [ {"name" : "identities", "url" : reverse("modoboa.extensions.admin.views.identity.identities"), @@ -134,6 +134,7 @@ def export_admin_domains(admin): def import_account_mailbox(user, account, row): account.email = row[0].strip() if account.email != "": + account.save() mailbox, domname = split_mailbox(account.email) try: domain = Domain.objects.get(name=domname) diff --git a/modoboa/extensions/admin/factories.py b/modoboa/extensions/admin/factories.py index 67df7e942..fb41dd231 100644 --- a/modoboa/extensions/admin/factories.py +++ b/modoboa/extensions/admin/factories.py @@ -1,15 +1,8 @@ import factory from django.contrib.auth.models import Group -from modoboa.core.models import User from . import models -class GroupFactory(factory.DjangoModelFactory): - FACTORY_FOR = Group - - name = 'DefaultGroup' - - class MailboxFactory(factory.DjangoModelFactory): FACTORY_FOR = models.Mailbox @@ -17,31 +10,6 @@ class MailboxFactory(factory.DjangoModelFactory): use_domain_quota = True -class UserFactory(factory.DjangoModelFactory): - FACTORY_FOR = User - - email = factory.LazyAttribute(lambda a: a.username) - password = '{PLAIN}toto' - - mailbox = factory.RelatedFactory( - MailboxFactory, 'user', - address=factory.LazyAttribute( - lambda m: m.user.email.replace('@%s' % m.domain.name, '') - ) - ) - - @factory.post_generation - def groups(self, create, extracted, **kwargs): - if not create: - # Simple build, do nothing. - return - - if extracted: - # A list of groups were passed in, use them - for group in extracted: - self.groups.add(Group.objects.get(name=group)) - - class DomainFactory(factory.DjangoModelFactory): FACTORY_FOR = models.Domain diff --git a/modoboa/extensions/admin/forms.py b/modoboa/extensions/admin/forms.py index f483e6ec5..7a12ffe98 100644 --- a/modoboa/extensions/admin/forms.py +++ b/modoboa/extensions/admin/forms.py @@ -625,14 +625,14 @@ class AccountPermissionsForm(forms.Form, DynamicForm): if not hasattr(self, "account") or self.account is None: return - for pos, domain in enumerate(self.account.get_domains()): + for pos, domain in enumerate(Domain.objects.get_for_admin(self.account)): name = "domains_%d" % (pos + 1) self._create_field(DomainNameField, name, domain.name) if len(args) and isinstance(args[0], QueryDict): self._load_from_qdict(args[0], "domains", DomainNameField) def save(self): - current_domains = [dom.name for dom in self.account.get_domains()] + current_domains = [dom.name for dom in Domain.objects.get_for_admin(self.account)] for name, value in self.cleaned_data.items(): if not name.startswith("domains"): continue @@ -642,7 +642,7 @@ class AccountPermissionsForm(forms.Form, DynamicForm): domain = Domain.objects.get(name=value) domain.add_admin(self.account) - for domain in self.account.get_domains(): + for domain in Domain.objects.get_for_admin(self.account): if not len(filter(lambda name: self.cleaned_data[name] == domain.name, self.cleaned_data.keys())): domain.remove_admin(self.account) @@ -671,7 +671,7 @@ class AccountForm(TabForms): if account.is_superuser: return False return self.user.has_perm("admin.add_domain") \ - and account.has_perm("admin.add_user") + and account.has_perm("core.add_user") def _before_is_valid(self, form): if form["id"] == "general": diff --git a/modoboa/extensions/admin/migrations/0037_rename_tables.py b/modoboa/extensions/admin/migrations/0037_rename_tables.py new file mode 100644 index 000000000..01eac0d54 --- /dev/null +++ b/modoboa/extensions/admin/migrations/0037_rename_tables.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + depends_on = ( + ('core', '0001_initial'), + ) + + def forwards(self, orm): + db.rename_table('admin_user', 'core_user') + # Changing field 'Mailbox.user' + db.alter_column(u'admin_mailbox', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.User'])) + + db.rename_table('admin_objectaccess', 'core_objectaccess') + db.alter_column(u'core_objectaccess', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.User'])) + + db.rename_table('admin_user_groups', 'core_user_groups') + db.rename_table('admin_user_user_permissions', 'core_user_user_permissions') + + db.rename_table('admin_extension', 'core_extension') + + db.send_create_signal('core', ['User', 'Extension', 'ObjectAccess']) + + def backwards(self, orm): + db.rename_table('core_user', 'admin_user') + # Changing field 'Mailbox.user' + db.alter_column(u'admin_mailbox', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.User'])) + + db.rename_table('core_objectaccess', 'admin_objectaccess') + db.alter_column(u'admin_objectaccess', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.User'])) + + db.rename_table('core_user_groups', 'admin_user_groups') + db.rename_table('core_user_user_permissions', 'admin_user_user_permissions') + + db.rename_table('core_extension', 'admin_extension') + + db.send_create_signal('admin', ['User', 'Extension', 'ObjectAccess']) + + models = { + 'admin.alias': { + 'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'}, + 'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}), + 'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Alias']", 'symmetrical': 'False'}), + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}), + 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'}) + }, + 'admin.domain': { + 'Meta': {'ordering': "['name']", 'object_name': 'Domain'}, + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'quota': ('django.db.models.fields.IntegerField', [], {}) + }, + 'admin.domainalias': { + 'Meta': {'object_name': 'DomainAlias'}, + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}) + }, + 'admin.mailbox': { + 'Meta': {'object_name': 'Mailbox'}, + 'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}), + 'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}), + 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'quota': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}) + }, + 'admin.objectdates': { + 'Meta': {'object_name': 'ObjectDates'}, + 'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'admin.quota': { + 'Meta': {'object_name': 'Quota'}, + 'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}), + 'mbox': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'quota_value'", 'unique': 'True', 'null': 'True', 'to': "orm['admin.Mailbox']"}), + 'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'}) + }, + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}) + }, + u'core.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + } + } + + complete_apps = ['admin'] diff --git a/modoboa/extensions/admin/models/__init__.py b/modoboa/extensions/admin/models/__init__.py index 8ef79509f..8edb89898 100644 --- a/modoboa/extensions/admin/models/__init__.py +++ b/modoboa/extensions/admin/models/__init__.py @@ -1,8 +1,8 @@ from .domain import Domain from .domain_alias import DomainAlias -from .mailbox import Mailbox, Quota +from .mailbox import Mailbox, Quota, MailboxOperation from .alias import Alias __all__ = [ - 'Domain', 'DomainAlias', 'Mailbox', 'Quota', 'Alias' + 'Domain', 'DomainAlias', 'Mailbox', 'Quota', 'Alias', 'MailboxOperation' ] diff --git a/modoboa/extensions/admin/models/mailbox.py b/modoboa/extensions/admin/models/mailbox.py index d0fb15092..79f3c1f08 100644 --- a/modoboa/extensions/admin/models/mailbox.py +++ b/modoboa/extensions/admin/models/mailbox.py @@ -259,6 +259,9 @@ class MailboxOperation(models.Model): ) argument = models.TextField() + class Meta: + app_label = 'admin' + def __str__(self): if self.type == 'rename': return 'Rename %s -> %s' % (self.argument, self.mailbox.mail_home) diff --git a/modoboa/extensions/admin/static/admin/js/admin.js b/modoboa/extensions/admin/static/admin/js/admin.js index 835ea339d..0e7c225be 100644 --- a/modoboa/extensions/admin/static/admin/js/admin.js +++ b/modoboa/extensions/admin/static/admin/js/admin.js @@ -394,9 +394,6 @@ Identities.prototype = { choices: get_domains_list }); $("#id_recipients").dynamic_input(); - $("#id_int_recipient").autocompleter({ - choices: get_allowed_recipients - }); $(".submit").one('click', $.proxy(function(e) { simple_ajax_form_post(e, { formid: "aliasform", diff --git a/modoboa/extensions/admin/templates/admin/identities.html b/modoboa/extensions/admin/templates/admin/identities.html index e19b57331..53bd55568 100644 --- a/modoboa/extensions/admin/templates/admin/identities.html +++ b/modoboa/extensions/admin/templates/admin/identities.html @@ -16,12 +16,6 @@ function get_account_list(container) { }); } -function get_allowed_recipients(container) { - $.getJSON("{% url 'modoboa.extensions.admin.views.alias.allowed_recipients_list' %}", function(data) { - container.value = data; - }); -} - $(document).ready(function() { admin = new Identities(); }); diff --git a/modoboa/extensions/admin/templatetags/admin_tags.py b/modoboa/extensions/admin/templatetags/admin_tags.py index bbc59e552..59a68b63c 100644 --- a/modoboa/extensions/admin/templatetags/admin_tags.py +++ b/modoboa/extensions/admin/templatetags/admin_tags.py @@ -140,7 +140,7 @@ def identity_actions(user, ident): else: actions = [ {"name": "delalias", - "url": reverse("modoboa.admin.views.delalias") + "?selection=%s" % objid, + "url": reverse("modoboa.extensions.admin.views.alias.delalias") + "?selection=%s" % objid, "img": "icon-trash", "title": _("Delete %s?" % ident.full_address)}, ] diff --git a/modoboa/extensions/admin/tests.py b/modoboa/extensions/admin/tests.py index 9f5569cae..d32ad74f1 100644 --- a/modoboa/extensions/admin/tests.py +++ b/modoboa/extensions/admin/tests.py @@ -9,13 +9,10 @@ TODO: create_directories == yes """ -import os -from django.test import TestCase -from django.test.client import Client -from django.utils import simplejson from django.core.urlresolvers import reverse from django.core.files.base import ContentFile -from modoboa.lib import parameters +from modoboa.core.models import User +from modoboa.core.factories import UserFactory, GroupFactory from modoboa.lib.tests import ModoTestCase from modoboa.extensions.admin.lib import * from modoboa.extensions.admin.models import * @@ -137,9 +134,10 @@ class AccountTestCase(ModoTestCase): def setUp(self): super(AccountTestCase, self).setUp() self.dom = factories.DomainFactory(name="test.com") - self.account = factories.UserFactory( - username="user@test.com", groups=('SimpleUsers',), mailbox__domain=self.dom + self.account = UserFactory( + username="user@test.com", groups=('SimpleUsers',) ) + factories.MailboxFactory(address='user', domain=self.dom, user=self.account) def test_crud(self): values = dict(username="tester@test.com", first_name="Tester", last_name="Toto", @@ -168,28 +166,6 @@ class AccountTestCase(ModoTestCase): self.check_ajax_get(reverse("modoboa.extensions.admin.views.identity.delaccount", args=[account.id]), {}) - def test_update_password(self): - """Password update - - Two cases: - * The default admin changes his password (no associated Mailbox) - * A normal user changes his password - """ - self.check_ajax_post(reverse("modoboa.core.views.user.profile"), - {"oldpassword" : "password", - "newpassword" : "titi", "confirmation" : "titi"}) - self.clt.logout() - - self.assertEqual(self.clt.login(username="admin", password="titi"), True) - self.assertEqual(self.clt.login(username="user@test.com", password="toto"), - True) - - self.check_ajax_post(reverse("modoboa.core.views.user.profile"), - {"oldpassword" : "toto", - "newpassword" : "tutu", "confirmation" : "tutu"}) - self.clt.logout() - self.assertEqual(self.clt.login(username="user@test.com", password="tutu"), True) - class AliasTestCase(ModoTestCase): fixtures = ["initial_users.json"] @@ -197,12 +173,14 @@ class AliasTestCase(ModoTestCase): def setUp(self): super(AliasTestCase, self).setUp() dom = factories.DomainFactory(name="test.com") - factories.UserFactory.create( - username="admin@test.com", groups=('DomainAdmins',), mailbox__domain=dom + u = UserFactory.create( + username="admin@test.com", groups=('DomainAdmins',) ) - factories.UserFactory.create( - username="user@test.com", groups=('SimpleUsers',), mailbox__domain=dom + factories.MailboxFactory(address='admin', domain=dom, user=u) + u = UserFactory.create( + username="user@test.com", groups=('SimpleUsers',) ) + factories.MailboxFactory(address='user', domain=dom, user=u) def test_alias(self): user = User.objects.get(username="user@test.com") @@ -279,22 +257,25 @@ class PermissionsTestCase(ModoTestCase): def setUp(self): super(PermissionsTestCase, self).setUp() dom = factories.DomainFactory(name='test.com') - self.user = factories.UserFactory( - username="user@test.com", groups=('SimpleUsers',), mailbox__domain=dom + self.user = UserFactory( + username="user@test.com", groups=('SimpleUsers',) ) + factories.MailboxFactory(address='user', domain=dom, user=self.user) self.values = dict( username=self.user.username, role="DomainAdmins", is_active=self.user.is_active, email="user@test.com" ) - self.admin = factories.UserFactory( - username="admin@test.com", groups=('DomainAdmins',), mailbox__domain=dom + self.admin = UserFactory( + username="admin@test.com", groups=('DomainAdmins',) ) + factories.MailboxFactory(address='admin', domain=dom, user=self.admin) dom.add_admin(self.admin) dom = factories.DomainFactory(name='test2.com') - factories.UserFactory( - username='user@test2.com', groups=('SimpleUsers',), mailbox__domain=dom + u = UserFactory( + username='user@test2.com', groups=('SimpleUsers',) ) + factories.MailboxFactory(address='user', domain=dom, user=u) def tearDown(self): self.clt.logout() @@ -387,13 +368,15 @@ class ImportTestCase(ModoTestCase): def setUp(self): super(ImportTestCase, self).setUp() dom = factories.DomainFactory(name="test.com") - self.admin = factories.UserFactory.create( - username="admin@test.com", groups=('DomainAdmins',), mailbox__domain=dom + self.admin = UserFactory.create( + username="admin@test.com", groups=('DomainAdmins',) ) + factories.MailboxFactory(address='admin', domain=dom, user=self.admin) dom.add_admin(self.admin) - factories.UserFactory.create( - username="user@test.com", groups=('SimpleUsers',), mailbox__domain=dom + u = UserFactory.create( + username="user@test.com", groups=('SimpleUsers',) ) + factories.MailboxFactory(address='user', domain=dom, user=u) def test_domains_import(self): f = ContentFile(b"""domain; domain1.com; 100; True diff --git a/modoboa/extensions/admin/urls.py b/modoboa/extensions/admin/urls.py index 6f5650814..24a0462c0 100644 --- a/modoboa/extensions/admin/urls.py +++ b/modoboa/extensions/admin/urls.py @@ -34,7 +34,6 @@ urlpatterns += patterns( (r'^aliases/new/$', 'newalias'), (r'^aliases/edit/(?P\d+)/$', 'editalias'), (r'^aliases/delete/$', 'delalias'), - (r'^aliases/allowed_recipients/$', 'allowed_recipients_list'), ) urlpatterns += patterns( diff --git a/modoboa/extensions/admin/views/alias.py b/modoboa/extensions/admin/views/alias.py index 809fe17c6..7ffb9c991 100644 --- a/modoboa/extensions/admin/views/alias.py +++ b/modoboa/extensions/admin/views/alias.py @@ -62,15 +62,6 @@ def _new_alias(request, title, action, successmsg, return render(request, tplname, ctx) -@login_required -@user_passes_test(lambda u: u.has_perm("admin.add_user") - or u.has_perm("admin.add_alias")) -def allowed_recipients_list(request): - ret = [mb.full_address for mb in request.user.get_mailboxes()] - ret += [al.full_address for al in request.user.get_aliases()] - return ajax_simple_response(ret) - - @login_required @permission_required("admin.add_alias") @transaction.commit_on_success diff --git a/modoboa/extensions/admin/views/export.py b/modoboa/extensions/admin/views/export.py index 18098f40b..58c2928f3 100644 --- a/modoboa/extensions/admin/views/export.py +++ b/modoboa/extensions/admin/views/export.py @@ -32,7 +32,7 @@ def _export(content, filename): @login_required @user_passes_test( - lambda u: u.has_perm("admin.add_user") or u.has_perm("admin.add_alias") + lambda u: u.has_perm("core.add_user") or u.has_perm("admin.add_alias") ) def export_identities(request): ctx = { diff --git a/modoboa/extensions/admin/views/import.py b/modoboa/extensions/admin/views/import.py index 6f964c2aa..c1c732aa7 100644 --- a/modoboa/extensions/admin/views/import.py +++ b/modoboa/extensions/admin/views/import.py @@ -134,7 +134,7 @@ def importdata(request, formclass=ImportDataForm): @login_required @user_passes_test( - lambda u: u.has_perm("admin.add_user") or u.has_perm("admin.add_alias") + lambda u: u.has_perm("core.add_user") or u.has_perm("admin.add_alias") ) def import_identities(request): if request.method == "POST": diff --git a/modoboa/extensions/amavis/sql_listing.py b/modoboa/extensions/amavis/sql_listing.py index e92a61b41..fb357d9be 100644 --- a/modoboa/extensions/amavis/sql_listing.py +++ b/modoboa/extensions/amavis/sql_listing.py @@ -8,6 +8,7 @@ from modoboa.lib.webutils import static_url from modoboa.lib.email_listing import MBconnector, EmailListing from modoboa.lib.emailutils import * from modoboa.lib.dbutils import db_type +from modoboa.extensions.admin.models import Domain from models import * @@ -105,7 +106,7 @@ class SQLWrapper(object): q &= Q(rid__email=request.user.email) else: if not request.user.is_superuser: - doms = request.user.get_domains() + doms = Domain.objects.get_for_admin(request.user) regexp = "(%s)" % '|'.join([dom.name for dom in doms]) doms_q = Q(rid__email__regex=regexp) q &= doms_q @@ -131,7 +132,7 @@ class SQLWrapper(object): """ rq = Q(rs='p') if not user.is_superuser: - doms = user.get_domains() + doms = Domain.objects.get_for_admin(user) if not doms.count(): return 0 regexp = "(%s)" % '|'.join([dom.name for dom in doms]) @@ -163,7 +164,7 @@ class PgWrapper(SQLWrapper): ) if not request.user.is_superuser: - doms = request.user.get_domains() + doms = Domain.objects.get_for_admin(request.user) regexp = "(%s)" % '|'.join([dom.name for dom in doms]) where.append("convert_from(maddr.email, 'UTF8') ~ '%s'" % regexp) if rcptfilter is not None: @@ -193,7 +194,7 @@ class PgWrapper(SQLWrapper): def get_pending_requests(self, user): rq = Q(rs='p') if not user.is_superuser: - doms = user.get_domains() + doms = Domain.objects.get_for_admin(user) if not doms.count(): return 0 regexp = "(%s)" % '|'.join([dom.name for dom in doms]) diff --git a/modoboa/extensions/amavis/views.py b/modoboa/extensions/amavis/views.py index 4ccedf61e..cca601a2f 100644 --- a/modoboa/extensions/amavis/views.py +++ b/modoboa/extensions/amavis/views.py @@ -15,7 +15,7 @@ from modoboa.lib.webutils import ( getctx, ajax_response, ajax_simple_response ) from modoboa.lib.email_listing import parse_search_parameters -from modoboa.extensions.admin.models import Mailbox +from modoboa.extensions.admin.models import Mailbox, Domain from templatetags.amextras import quar_menu, viewm_menu from .lib import selfservice, AMrelease from .sql_listing import SQLlisting, SQLemail, get_wrapper @@ -56,7 +56,7 @@ def _listing(request): msgs = None if not request.user.is_superuser and request.user.group != 'SimpleUsers': - if not len(request.user.get_domains()): + if not Domain.objects.get_for_admin(request.user).count(): return empty_quarantine(request) order = request.GET.get("order", "-date") @@ -184,7 +184,7 @@ def viewheaders(request, mail_id): for qm in get_wrapper().get_mail_content(mail_id): content += qm.mail_text msg = email.message_from_string(content) - return _render(request, 'amavis/viewheader.html', { + return render(request, 'amavis/viewheader.html', { "headers": msg.items() }) diff --git a/modoboa/extensions/limits/migrations/0003_auto__chg_field_limitspool_user.py b/modoboa/extensions/limits/migrations/0003_auto__chg_field_limitspool_user.py new file mode 100644 index 000000000..9762fda21 --- /dev/null +++ b/modoboa/extensions/limits/migrations/0003_auto__chg_field_limitspool_user.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + depends_on = ( + ('admin', '0037_rename_tables'), + ) + + def forwards(self, orm): + + # Changing field 'LimitsPool.user' + db.alter_column(u'limits_limitspool', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.User'], unique=True)) + + def backwards(self, orm): + + # Changing field 'LimitsPool.user' + db.alter_column(u'limits_limitspool', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['admin.User'], unique=True)) + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'limits.limit': { + 'Meta': {'unique_together': "(('name', 'pool'),)", 'object_name': 'Limit'}, + 'curvalue': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'maxvalue': ('django.db.models.fields.IntegerField', [], {'default': '-2'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pool': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['limits.LimitsPool']"}) + }, + u'limits.limitspool': { + 'Meta': {'object_name': 'LimitsPool'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.User']", 'unique': 'True'}) + } + } + + complete_apps = ['limits'] diff --git a/modoboa/extensions/stats/views.py b/modoboa/extensions/stats/views.py index 3bfffae5b..a6b95c8e7 100644 --- a/modoboa/extensions/stats/views.py +++ b/modoboa/extensions/stats/views.py @@ -9,7 +9,9 @@ from modoboa.lib.exceptions import ModoboaException, PermDeniedException from modoboa.lib.webutils import ( _render_to_string, ajax_simple_response ) -from modoboa.extensions.admin.models import Domain, Mailbox +from modoboa.extensions.admin.models import ( + Domain, Mailbox +) from modoboa.extensions.stats.grapher import periods, str2Time, Grapher @@ -21,7 +23,7 @@ def index(request): """ deflocation = "graphs/?gset=mailtraffic" if not request.user.is_superuser: - if not len(request.user.get_domains()): + if not Domain.objects.get_for_admin(request.user).count(): raise ModoboaException(_("No statistics available")) period = request.GET.get("period", "day") diff --git a/modoboa/lib/authbackends.py b/modoboa/lib/authbackends.py index 4edefd86d..325dc361d 100644 --- a/modoboa/lib/authbackends.py +++ b/modoboa/lib/authbackends.py @@ -56,7 +56,7 @@ try: return user def authenticate(self, username, password): - auth_type = parameters.get_admin("AUTHENTICATION_TYPE", app="admin") + auth_type = parameters.get_admin("AUTHENTICATION_TYPE", app="core") if auth_type == "ldap": return super(LDAPBackend, self).authenticate(username, password) return None diff --git a/modoboa/lib/cryptutils.py b/modoboa/lib/cryptutils.py index 8808cd240..0c778cda8 100644 --- a/modoboa/lib/cryptutils.py +++ b/modoboa/lib/cryptutils.py @@ -17,7 +17,7 @@ def random_key(l=16): def encrypt(clear): - key = parameters.get_admin("SECRET_KEY", app="admin") + key = parameters.get_admin("SECRET_KEY", app="core") obj = AES.new(key, AES.MODE_ECB) if type(clear) is unicode: clear = clear.encode("utf-8") @@ -30,7 +30,7 @@ def encrypt(clear): def decrypt(ciph): obj = AES.new( - parameters.get_admin("SECRET_KEY", app="admin"), AES.MODE_ECB + parameters.get_admin("SECRET_KEY", app="core"), AES.MODE_ECB ) ciph = base64.b64decode(ciph) clear = obj.decrypt(ciph) diff --git a/modoboa/lib/events.py b/modoboa/lib/events.py index a296374cc..85284b1f2 100644 --- a/modoboa/lib/events.py +++ b/modoboa/lib/events.py @@ -111,7 +111,7 @@ class observe(object): else self.__guess_extension_name(modname) @wraps(f) - def wrapped_f(*args): + def wrapped_f(*args, **kwargs): if extname: from modoboa.core.models import Extension from modoboa.core.extensions import exts_pool @@ -126,7 +126,7 @@ class observe(object): return [] elif not modname in settings.MODOBOA_APPS: return [] - return f(*args) + return f(*args, **kwargs) for evt in self.evtnames: register(evt, wrapped_f) return wrapped_f @@ -149,7 +149,7 @@ def unregister(event, callback): pass -def raiseEvent(event, *args): +def raiseEvent(event, *args, **kwargs): """Raise a specific event Any additional keyword argument will be passed to registered @@ -160,7 +160,7 @@ def raiseEvent(event, *args): if not event in events or not event in callbacks.keys(): return 0 for callback in callbacks[event].values(): - callback(*args) + callback(*args, **kwargs) return 1 diff --git a/modoboa/lib/migrations/0005_rename_table.py b/modoboa/lib/migrations/0005_rename_table.py new file mode 100644 index 000000000..cd5ab6347 --- /dev/null +++ b/modoboa/lib/migrations/0005_rename_table.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + depends_on = ( + ('admin', '0037_rename_tables'), + ) + + def forwards(self, orm): + db.rename_table('lib_log', 'core_log') + db.send_create_signal('core', ['Log']) + + # Changing field 'UserParameter.user' + db.alter_column(u'lib_userparameter', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.User'])) + + def backwards(self, orm): + db.rename_table('core_log', 'lib_log') + db.send_create_signal(u'lib', ['Log']) + + # Changing field 'UserParameter.user' + db.alter_column(u'lib_userparameter', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.User'])) + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.extension': { + 'Meta': {'object_name': 'Extension'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + u'core.log': { + 'Meta': {'object_name': 'Log'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'logger': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'message': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.objectaccess': { + 'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}) + }, + u'core.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'lib.parameter': { + 'Meta': {'object_name': 'Parameter'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'lib.userparameter': { + 'Meta': {'object_name': 'UserParameter'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['core', 'lib'] diff --git a/modoboa/lib/migrations/0006_move_parameters.py b/modoboa/lib/migrations/0006_move_parameters.py new file mode 100644 index 000000000..0913b626a --- /dev/null +++ b/modoboa/lib/migrations/0006_move_parameters.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + depends_on = ( + ('admin', '0037_rename_tables'), + ) + + params = ['AUTHENTICATION_TYPE', 'PASSWORD_SCHEME', 'SECRET_KEY', + 'LOG_MAXIMUM_AGE', 'ITEMS_PER_PAGE', 'DEFAULT_TOP_REDIRECTION'] + + def forwards(self, orm): + "Write your forwards methods here." + for p in orm['lib.Parameter'].objects.filter( + name__in=['admin.%s' % n for n in self.params]): + p.name = p.name.replace('admin.', 'core.') + p.save() + for ldap_p in orm['lib.Parameter'].objects.filter(name__contains='admin.LDAP'): + ldap_p.name = ldap_p.name.replace('admin.', 'core.') + ldap_p.save() + + def backwards(self, orm): + "Write your backwards methods here." + for p in orm['lib.Parameter'].objects.filter( + name__in=['core.%s' % n for n in self.params]): + p.name = p.name.replace('core.', 'admin.') + p.save() + for ldap_p in orm['lib.Parameter'].objects.filter(name__contains='core.LDAP'): + ldap_p.name = ldap_p.name.replace('core.', 'admin.') + ldap_p.save() + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.user': { + 'Meta': {'ordering': "['username']", 'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}) + }, + u'lib.parameter': { + 'Meta': {'object_name': 'Parameter'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'lib.userparameter': { + 'Meta': {'object_name': 'UserParameter'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['lib'] + symmetrical = True