mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: UI refactoring
* Per object permissions * Faster identities listing * Possibility to filter on alias names * fixes see #204
This commit is contained in:
@@ -1 +1 @@
|
||||
[{"pk": 1, "model": "auth.group", "fields": {"name": "DomainAdmins", "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"], ["add_mailbox", "admin", "mailbox"], ["change_mailbox", "admin", "mailbox"], ["delete_mailbox", "admin", "mailbox"], ["add_alias", "admin", "alias"], ["change_alias", "admin", "alias"], ["delete_alias", "admin", "alias"], ["view_mailboxes", "admin", "mailbox"], ["view_aliases", "admin", "alias"], ["view_domaliases", "admin", "domainalias"], ["add_domainalias", "admin", "domainalias"], ["change_domainalias", "admin", "domainalias"], ["delete_domainalias", "admin", "domainalias"]]}},{"pk": 2, "model": "auth.group", "fields": {"name": "SimpleUsers", "permissions": []}},{"pk": 1, "model": "auth.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": "auth.group", "fields": {"name": "DomainAdmins", "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"], ["add_mailbox", "admin", "mailbox"], ["change_mailbox", "admin", "mailbox"], ["delete_mailbox", "admin", "mailbox"], ["add_alias", "admin", "alias"], ["change_alias", "admin", "alias"], ["delete_alias", "admin", "alias"], ["view_mailboxes", "admin", "mailbox"], ["view_aliases", "admin", "alias"], ["view_domaliases", "admin", "domainalias"], ["add_domainalias", "admin", "domainalias"], ["change_domainalias", "admin", "domainalias"], ["delete_domainalias", "admin", "domainalias"]]}},{"pk": 2, "model": "auth.group", "fields": {"name": "SimpleUsers", "permissions": []}},{"pk": 1, "model": "auth.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": "admin.objectaccess", "fields": {"is_owner": false, "user": 1, "content_type": ["admin", "user"], "object_id": 1}}]
|
||||
|
||||
+47
-25
@@ -95,8 +95,6 @@ class DomainForm(forms.ModelForm, DynamicForm):
|
||||
for dalias in d.domainalias_set.all():
|
||||
if not len(filter(lambda name: self.cleaned_data[name] == dalias.name,
|
||||
self.cleaned_data.keys())):
|
||||
events.raiseEvent("DomainAliasDeleted", dalias)
|
||||
ungrant_access_to_object(dalias)
|
||||
dalias.delete()
|
||||
return d
|
||||
|
||||
@@ -114,7 +112,8 @@ class DlistForm(forms.ModelForm, DynamicForm):
|
||||
model = Alias
|
||||
fields = ("enabled",)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
super(DlistForm, self).__init__(*args, **kwargs)
|
||||
self.fields.keyOrder = ['email', 'recipients', 'enabled']
|
||||
|
||||
@@ -138,12 +137,14 @@ class DlistForm(forms.ModelForm, DynamicForm):
|
||||
def clean_email(self):
|
||||
localpart, domname = split_mailbox(self.cleaned_data["email"])
|
||||
try:
|
||||
Domain.objects.get(name=domname)
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
raise forms.ValidationError(_("Domain does not exist"))
|
||||
if not self.user.can_access(domain):
|
||||
raise forms.ValidationError(_("You don't have access to this domain"))
|
||||
return self.cleaned_data["email"]
|
||||
|
||||
def set_recipients(self, user):
|
||||
def set_recipients(self):
|
||||
"""Recipients dispatching
|
||||
|
||||
We make a difference between 'local' recipients (the ones hosted
|
||||
@@ -166,7 +167,7 @@ class DlistForm(forms.ModelForm, DynamicForm):
|
||||
except Domain.DoesNotExist:
|
||||
domain = None
|
||||
if domain:
|
||||
if not user.can_access(domain):
|
||||
if not self.user.can_access(domain):
|
||||
raise PermDeniedException(v)
|
||||
try:
|
||||
mb = Mailbox.objects.get(domain=domain, address=local_part)
|
||||
@@ -209,7 +210,8 @@ class ForwardForm(forms.ModelForm):
|
||||
model = Alias
|
||||
fields = ("enabled",)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
super(ForwardForm, self).__init__(*args, **kwargs)
|
||||
self.fields.keyOrder = ['email', 'recipient', 'enabled']
|
||||
if kwargs.has_key("instance"):
|
||||
@@ -220,9 +222,11 @@ class ForwardForm(forms.ModelForm):
|
||||
def clean_email(self):
|
||||
localpart, domname = split_mailbox(self.cleaned_data["email"])
|
||||
try:
|
||||
Domain.objects.get(name=domname)
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
raise forms.ValidationError(_("Domain does not exist"))
|
||||
if not self.user.can_access(domain):
|
||||
raise forms.ValidationError(_("You don't have access to this domain"))
|
||||
return self.cleaned_data["email"]
|
||||
|
||||
def clean_recipient(self):
|
||||
@@ -235,7 +239,7 @@ class ForwardForm(forms.ModelForm):
|
||||
raise forms.ValidationError(_("Local addresses are forbidden"))
|
||||
return self.cleaned_data["recipient"]
|
||||
|
||||
def set_recipients(self, user):
|
||||
def set_recipients(self):
|
||||
pass
|
||||
|
||||
def save(self, commit=True):
|
||||
@@ -286,32 +290,33 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
self.user = user
|
||||
if user.group == "DomainAdmins":
|
||||
del self.fields["role"]
|
||||
return
|
||||
else:
|
||||
self.fields["role"].choices = \
|
||||
[('', ugettext_lazy("Choose"))] + get_account_roles(user)
|
||||
|
||||
self.fields["role"].choices = \
|
||||
[('', ugettext_lazy("Choose"))] + get_account_roles(user)
|
||||
if kwargs.has_key("instance"):
|
||||
if len(args) \
|
||||
and (args[0].get("password1", "") == "" \
|
||||
and args[0].get("password2", "") == ""):
|
||||
self.fields["password1"].required = False
|
||||
self.fields["password2"].required = False
|
||||
|
||||
u = kwargs["instance"]
|
||||
if u.is_superuser:
|
||||
role = "SuperAdmins"
|
||||
else:
|
||||
try:
|
||||
role = u.groups.all()[0].name
|
||||
except IndexError:
|
||||
pass
|
||||
self.fields["role"].initial = role
|
||||
if user.group != "DomainAdmins":
|
||||
u = kwargs["instance"]
|
||||
if u.is_superuser:
|
||||
role = "SuperAdmins"
|
||||
else:
|
||||
try:
|
||||
role = u.groups.all()[0].name
|
||||
except IndexError:
|
||||
pass
|
||||
self.fields["role"].initial = role
|
||||
|
||||
def clean_username(self):
|
||||
from django.core.validators import validate_email
|
||||
|
||||
if not self.cleaned_data.has_key("role"):
|
||||
return self.cleaned_data["username"]
|
||||
if self.cleaned_data["role"] != "SimpleUsers":
|
||||
return self.cleaned_data
|
||||
return self.cleaned_data["username"]
|
||||
validate_email(self.cleaned_data["username"])
|
||||
return self.cleaned_data["username"]
|
||||
|
||||
@@ -326,7 +331,7 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
def save(self, commit=True):
|
||||
account = super(AccountFormGeneral, self).save(commit=False)
|
||||
if commit:
|
||||
if self.cleaned_data.has_key("password1"):
|
||||
if self.cleaned_data["password1"] != "":
|
||||
account.set_password(self.cleaned_data["password1"])
|
||||
account.save()
|
||||
role = None
|
||||
@@ -396,6 +401,10 @@ class AccountFormMail(forms.Form, DynamicForm):
|
||||
self.cleaned_data["quota"])
|
||||
grant_access_to_object(user, self.mb, is_owner=True)
|
||||
events.raiseEvent("CreateMailbox", user, self.mb)
|
||||
if user.is_superuser:
|
||||
for admin in self.mb.domain.admins:
|
||||
grant_access_to_object(admin, self.mb)
|
||||
|
||||
else:
|
||||
if self.cleaned_data["email"] != self.mb.full_address:
|
||||
if self.mb.rename_dir(domname, locpart):
|
||||
@@ -426,6 +435,9 @@ class AccountFormMail(forms.Form, DynamicForm):
|
||||
al.save([self.mb], [])
|
||||
grant_access_to_object(user, al, is_owner=True)
|
||||
events.raiseEvent("MailboxAliasCreated", user, al)
|
||||
if user.is_superuser:
|
||||
for admin in al.domain.admins:
|
||||
grant_access_to_object(admin, al)
|
||||
|
||||
for alias in self.mb.alias_set.all():
|
||||
if len(alias.get_recipients()) >= 2:
|
||||
@@ -470,11 +482,21 @@ class AccountPermissionsForm(forms.Form, DynamicForm):
|
||||
if not value in current_domains:
|
||||
domain = Domain.objects.get(name=value)
|
||||
grant_access_to_object(self.account, domain)
|
||||
for mb in domain.mailbox_set.all():
|
||||
grant_access_to_object(self.account, mb)
|
||||
grant_access_to_object(self.account, mb.user)
|
||||
for al in Alias.objects.filter(domain=domain):
|
||||
grant_access_to_object(self.account, al)
|
||||
|
||||
for domain in self.account.get_domains():
|
||||
if not len(filter(lambda name: self.cleaned_data[name] == domain.name,
|
||||
self.cleaned_data.keys())):
|
||||
ungrant_access_to_object(domain, self.account)
|
||||
for mb in domain.mailbox_set.all():
|
||||
ungrant_access_to_object(mb, self.account)
|
||||
ungrant_access_to_object(mb.user, self.account)
|
||||
for al in Alias.objects.filter(domain=domain):
|
||||
ungrant_access_to_object(al, self.account)
|
||||
|
||||
class AccountForm(TabForms):
|
||||
|
||||
|
||||
@@ -7,20 +7,21 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def grant_access(self, orm, user, ct, obj, is_owner=False):
|
||||
objaccess = orm["admin.ObjectAccess"](
|
||||
user=user, content_type=ct, object_id=obj.id
|
||||
)
|
||||
objaccess.is_owner = is_owner
|
||||
objaccess.save()
|
||||
|
||||
def forwards(self, orm):
|
||||
"Write your forwards methods here."
|
||||
superusers = orm.User.objects.filter(is_superuser=True)
|
||||
superusers = orm["auth.User"].objects.filter(is_superuser=True)
|
||||
if not len(superusers):
|
||||
# Empty db, nothing to do
|
||||
return
|
||||
|
||||
domadmins = orm.User.objects.filter(groups__name='DomainAdmins')
|
||||
domains = orm.Domain.objects.all()
|
||||
deferred_admin = []
|
||||
|
||||
domct = orm['contenttypes.ContentType'].objects.get(
|
||||
app_label='admin', model='domain'
|
||||
)
|
||||
# 1: all superadmins must be able to access every defined
|
||||
# object. (user, domain, domain alias, mailbox, alias)
|
||||
try:
|
||||
uct = orm['contenttypes.ContentType'].objects.get(
|
||||
app_label='admin', model='user'
|
||||
@@ -30,35 +31,48 @@ class Migration(DataMigration):
|
||||
name='user', app_label='admin', model='user'
|
||||
)
|
||||
uct.save()
|
||||
for account in orm["admin.User"].objects.all():
|
||||
for i, su in enumerate(superusers):
|
||||
self.grant_access(orm, su, uct, account, i == 0)
|
||||
domct = orm['contenttypes.ContentType'].objects.get(
|
||||
app_label='admin', model='domain'
|
||||
)
|
||||
for dom in orm["admin.Domain"].objects.all():
|
||||
for i, su in enumerate(superusers):
|
||||
self.grant_access(orm, su, domct, dom, i == 0)
|
||||
dalct = orm['contenttypes.ContentType'].objects.get(
|
||||
app_label='admin', model='domainalias'
|
||||
)
|
||||
for domalias in orm["admin.DomainAlias"].objects.all():
|
||||
for i, su in enumerate(superusers):
|
||||
self.grant_access(orm, su, dalct, domalias, i == 0)
|
||||
mbct = orm['contenttypes.ContentType'].objects.get(
|
||||
app_label='admin', model='mailbox'
|
||||
)
|
||||
for mb in orm["admin.Mailbox"].objects.all():
|
||||
for i, su in enumerate(superusers):
|
||||
self.grant_access(orm, su, mbct, mb, i == 0)
|
||||
alct = orm['contenttypes.ContentType'].objects.get(
|
||||
app_label='admin', model='alias'
|
||||
)
|
||||
for alias in orm["admin.Alias"].objects.all():
|
||||
for i, su in enumerate(superusers):
|
||||
self.grant_access(orm, su, alct, alias, i == 0)
|
||||
|
||||
for da in domadmins:
|
||||
for i, su in enumerate(superusers):
|
||||
objaccess = orm.ObjectAccess(
|
||||
user=su, content_type=uct, object_id=da.id
|
||||
)
|
||||
if i == 0:
|
||||
objaccess.is_owner = True
|
||||
objaccess.save()
|
||||
|
||||
# 2: domain admins must have access to their domain's content
|
||||
for da in orm["admin.User"].objects.filter(groups__name='DomainAdmins'):
|
||||
dom = da.mailbox_set.all()[0].domain
|
||||
objaccess = orm.ObjectAccess(
|
||||
user=da, content_type=domct, object_id=dom.id, is_owner=True
|
||||
)
|
||||
objaccess.save()
|
||||
deferred_admin += [dom]
|
||||
|
||||
for dom in domains:
|
||||
for i, su in enumerate(superusers):
|
||||
objaccess = orm.ObjectAccess(
|
||||
user=su, content_type=domct, object_id=dom.id
|
||||
)
|
||||
if not dom in deferred_admin:
|
||||
objaccess.is_owner = True
|
||||
objaccess.save()
|
||||
self.grant_access(orm, da, domct, dom)
|
||||
|
||||
for mb in dom.mailbox_set.all():
|
||||
self.grant_access(orm, da, mbct, mb)
|
||||
self.grant_access(orm, da, uct, mb.user)
|
||||
for al in dom.alias_set.all():
|
||||
self.grant_access(orm, da, alct, al)
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
raise RuntimeError("Cannot revert this migration")
|
||||
|
||||
models = {
|
||||
'admin.alias': {
|
||||
|
||||
+57
-40
@@ -69,24 +69,19 @@ class User(DUser):
|
||||
if fromuser == self:
|
||||
raise AdminError(_("You can't delete your own account"))
|
||||
|
||||
if not fromuser.can_access(self):
|
||||
raise PermDeniedException("You don't have access to this account")
|
||||
|
||||
if self.has_mailbox:
|
||||
mb = self.mailbox_set.all()[0]
|
||||
if not fromuser.can_access(mb.domain):
|
||||
raise PermDeniedException(_("You don't have access to this domain"))
|
||||
events.raiseEvent("DeleteMailbox", mb)
|
||||
ungrant_access_to_object(mb)
|
||||
if not fromuser.can_access(mb):
|
||||
raise PermDeniedException(_("You don't have access to this mailbox"))
|
||||
mb.delete(keepdir=keep_mb_dir)
|
||||
elif not fromuser.can_access(self):
|
||||
raise PermDeniedException(_("You don't have access to this account"))
|
||||
|
||||
owner = get_object_owner(self)
|
||||
for ooentry in self.objectaccess_set.all():
|
||||
if ooentry.is_owner:
|
||||
if ooentry.content_object is not None:
|
||||
grant_access_to_object(owner, ooentry.content_object, True)
|
||||
else:
|
||||
print "ORPHELIN!!!"
|
||||
ooentry.delete()
|
||||
for ooentry in self.objectaccess_set.filter(is_owner=True):
|
||||
if ooentry.content_object is not None:
|
||||
grant_access_to_object(owner, ooentry.content_object, True)
|
||||
|
||||
events.raiseEvent("AccountDeleted", self)
|
||||
ungrant_access_to_object(self)
|
||||
@@ -204,24 +199,22 @@ class User(DUser):
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_identities(self):
|
||||
from modoboa.lib.permissions import get_content_type
|
||||
|
||||
userct = get_content_type(self)
|
||||
alct = get_content_type(Alias)
|
||||
return self.objectaccess_set.filter(content_type__in=[userct, alct])
|
||||
|
||||
def get_domains(self):
|
||||
"""Return the domains belonging to this user
|
||||
|
||||
The result is a ``QuerySet`` object, so this function can be used
|
||||
to fill ``ModelChoiceField`` objects.
|
||||
|
||||
:param user: a ``User`` object
|
||||
"""
|
||||
if self.is_superuser:
|
||||
return Domain.objects.all()
|
||||
result = Domain.objects.filter(owners__user=self).distinct()
|
||||
|
||||
userct = self.get_content_type()
|
||||
for entry in self.objectaccess_set.filter(content_type=userct):
|
||||
if not entry.content_object.belongs_to_group('DomainAdmins'):
|
||||
continue
|
||||
result |= entry.content_object.get_domains().distinct()
|
||||
return result
|
||||
return Domain.objects.filter(owners__user=self)
|
||||
|
||||
def get_domaliases(self):
|
||||
"""Return the domain aliases that belong to this user
|
||||
@@ -327,6 +320,9 @@ class ObjectAccess(models.Model):
|
||||
|
||||
class Meta:
|
||||
unique_together = (("user", "content_type", "object_id"),)
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s => %s (%s)" % (self.user, self.content_object, self.content_type)
|
||||
|
||||
class ObjectDates(models.Model):
|
||||
"""Dates recording for admin objects
|
||||
@@ -400,6 +396,10 @@ class Domain(DatesAware):
|
||||
def mbalias_count(self):
|
||||
return len(self.alias_set.all())
|
||||
|
||||
@property
|
||||
def admins(self):
|
||||
return [oa.user for oa in self.owners.filter(user__is_superuser=False)]
|
||||
|
||||
def create_dir(self):
|
||||
if parameters.get_admin("CREATE_DIRECTORIES") == "yes":
|
||||
path = "%s/%s" % (parameters.get_admin("STORAGE_PATH"), self.name)
|
||||
@@ -421,17 +421,21 @@ class Domain(DatesAware):
|
||||
self.name))
|
||||
return True
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
keepdir = False
|
||||
if kwargs.has_key("keepdir"):
|
||||
keepdir = kwargs["keepdir"]
|
||||
del kwargs["keepdir"]
|
||||
# Not very optimized but currently, this is the simple way
|
||||
# I've found to delete all related objects (mailboxes, users
|
||||
# and aliases)!
|
||||
# for mb in self.mailbox_set.all():
|
||||
# mb.delete(keepdir=keepdir)
|
||||
super(Domain, self).delete(*args, **kwargs)
|
||||
def delete(self, keepdir=False):
|
||||
from modoboa.lib.permissions import ungrant_access_to_object, ungrant_access_to_objects
|
||||
|
||||
if len(self.domainalias_set.all()):
|
||||
events.raiseEvent("DomainAliasDeleted", self.domainalias_set.all())
|
||||
ungrant_access_to_objects(self.domainalias_set.all())
|
||||
if len(self.mailbox_set.all()):
|
||||
events.raiseEvent("DeleteMailbox", self.mailbox_set.all())
|
||||
ungrant_access_to_objects(self.mailbox_set.all())
|
||||
if len(self.alias_set.all()):
|
||||
events.raiseEvent("MailboxAliasDelete", self.alias_set.all())
|
||||
ungrant_access_to_objects(self.alias_set.all())
|
||||
events.raiseEvent("DeleteDomain", self)
|
||||
ungrant_access_to_object(self)
|
||||
super(Domain, self).delete()
|
||||
if not keepdir:
|
||||
self.delete_dir()
|
||||
|
||||
@@ -469,6 +473,12 @@ class DomainAlias(DatesAware):
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def delete(self):
|
||||
from modoboa.lib.permissions import ungrant_access_to_object
|
||||
events.raiseEvent("DomainAliasDeleted", self)
|
||||
ungrant_access_to_object(self)
|
||||
super(DomainAlias, self).delete()
|
||||
|
||||
class Mailbox(DatesAware):
|
||||
address = models.CharField(
|
||||
ugettext_lazy('address'), max_length=100,
|
||||
@@ -668,16 +678,16 @@ class Mailbox(DatesAware):
|
||||
self.save(username=line[1].strip(), name=name,
|
||||
password=line[2].strip(), enabled=True)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
keepdir = False
|
||||
if kwargs.has_key("keepdir"):
|
||||
keepdir = kwargs["keepdir"]
|
||||
del kwargs["keepdir"]
|
||||
def delete(self, keepdir=False):
|
||||
from modoboa.lib.permissions import ungrant_access_to_object
|
||||
|
||||
events.raiseEvent("DeleteMailbox", self)
|
||||
ungrant_access_to_object(self)
|
||||
for alias in self.alias_set.all():
|
||||
alias.mboxes.remove(self)
|
||||
if len(alias.mboxes.all()) == 0:
|
||||
alias.delete()
|
||||
super(Mailbox, self).delete(*args, **kwargs)
|
||||
super(Mailbox, self).delete()
|
||||
if not keepdir:
|
||||
self.delete_dir()
|
||||
|
||||
@@ -731,6 +741,13 @@ class Alias(DatesAware):
|
||||
if not t in int_rcpts:
|
||||
self.mboxes.remove(t)
|
||||
|
||||
def delete(self):
|
||||
from modoboa.lib.permissions import ungrant_access_to_object
|
||||
|
||||
events.raiseEvent("MailboxAliasDeleted", self)
|
||||
ungrant_access_to_object(self)
|
||||
super(Alias, self).delete()
|
||||
|
||||
def get_recipients(self):
|
||||
"""Return the recipients list
|
||||
|
||||
|
||||
+15
-4
@@ -183,6 +183,11 @@ class PermissionsTestCase(ModoTestCase):
|
||||
fixtures = ["test_content.json"]
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
FIXME: je n'arrive pas à générer des données de test incluant
|
||||
déjà les permissions (cf. table ObjectAccess). C'est pour
|
||||
cette raison que j'assigne le domaine test.com ici...
|
||||
"""
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
|
||||
super(PermissionsTestCase, self).setUp()
|
||||
@@ -191,9 +196,13 @@ class PermissionsTestCase(ModoTestCase):
|
||||
username=self.user.username, role="DomainAdmins",
|
||||
is_active=self.user.is_active, email="user@test.com"
|
||||
)
|
||||
grant_access_to_object(User.objects.get(username="admin@test.com"),
|
||||
Domain.objects.get(name="test.com"))
|
||||
|
||||
self.admin = User.objects.get(username="admin@test.com")
|
||||
self.check_ajax_post("/modoboa/admin/accounts/edit/%d/" % self.admin.id, dict(
|
||||
username=self.admin.username, role="DomainAdmins",
|
||||
is_active=self.admin.is_active, email="admin@test.com",
|
||||
password1="", password2="", domains="test.com"
|
||||
))
|
||||
|
||||
def tearDown(self):
|
||||
self.clt.logout()
|
||||
|
||||
@@ -224,7 +233,7 @@ class PermissionsTestCase(ModoTestCase):
|
||||
self.assertEqual(self.clt.login(username="admin@test.com", password="toto"),
|
||||
True)
|
||||
admin = User.objects.get(username="admin@test.com")
|
||||
values = dict(username="admin@test.com", first_name="Admin",
|
||||
values = dict(username="admin@test.com", first_name="Admin", password1="", password2="",
|
||||
is_active=True, email="admin@test.com")
|
||||
self.check_ajax_post("/modoboa/admin/accounts/edit/%d/" % admin.id, values)
|
||||
self.assertEqual(admin.group, "DomainAdmins")
|
||||
@@ -247,4 +256,6 @@ class PermissionsTestCase(ModoTestCase):
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
self.assertNotEqual(response["Content-Type"], "application/json")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,15 +10,12 @@ urlpatterns = patterns(
|
||||
(r'^domains/delete/$', 'deldomain'),
|
||||
(r'^domains/import/$', 'import_domains'),
|
||||
|
||||
(r'^mailboxes/search/$', 'mailboxes_search'),
|
||||
|
||||
(r'^settings/$', 'viewparameters'),
|
||||
(r'^settings/parameters/$', 'viewparameters'),
|
||||
(r'^settings/parameters/save/$', 'saveparameters'),
|
||||
(r'^settings/extensions/$', 'viewextensions'),
|
||||
(r'^settings/extensions/save/$', 'saveextensions'),
|
||||
|
||||
(r'^permissions/searchaccount/$', 'search_account'),
|
||||
(r'^permissions/remove/$', 'remove_permission'),
|
||||
|
||||
(r'^identities/$', 'identities'),
|
||||
|
||||
+32
-82
@@ -97,10 +97,9 @@ def editdomain(request, dom_id, tplname="admin/editdomainform.html"):
|
||||
if not request.user.can_access(domain):
|
||||
raise PermDeniedException(_("You can't edit this domain"))
|
||||
|
||||
domadmins = map(lambda oaccess: oaccess.user, domain.owners.all())
|
||||
domadmins = filter(
|
||||
lambda u: request.user.can_access(u) and not u.is_superuser,
|
||||
domadmins
|
||||
domain.admins
|
||||
)
|
||||
if not request.user.is_superuser:
|
||||
domadmins = filter(lambda u: u.group == "DomainAdmins", domadmins)
|
||||
@@ -137,37 +136,12 @@ def deldomain(request):
|
||||
raise PermDeniedException(_("You can't delete this domain"))
|
||||
if mb and mb.domain == dom:
|
||||
raise AdminError(_("You can't delete your own domain"))
|
||||
|
||||
if len(dom.domainalias_set.all()):
|
||||
events.raiseEvent("DomainAliasDeleted", dom.domainalias_set.all())
|
||||
if len(dom.mailbox_set.all()):
|
||||
events.raiseEvent("DeleteMailbox", dom.mailbox_set.all())
|
||||
events.raiseEvent("DeleteDomain", dom)
|
||||
ungrant_access_to_object(dom)
|
||||
dom.delete(keepdir=keepdir)
|
||||
|
||||
msg = ungettext("Domain deleted", "Domains deleted", len(selection))
|
||||
messages.info(request, msg, fail_silently=True)
|
||||
return ajax_response(request)
|
||||
|
||||
@login_required
|
||||
@permission_required("admin.view_mailboxes")
|
||||
@check_domain_access
|
||||
def mailboxes_search(request):
|
||||
if request.method != "POST":
|
||||
return
|
||||
local_part, domain = split_mailbox(request.POST["search"])
|
||||
query = Q(address__startswith=local_part)
|
||||
if domain is not None and domain != "":
|
||||
query &= Q(domain__name__startswith=domain)
|
||||
if request.GET.has_key("domid"):
|
||||
query = Q(domain=request.GET["domid"]) & query
|
||||
elif not request.user.is_superuser:
|
||||
query = Q(domain__in=request.user.get_domains()) & query
|
||||
mboxes = Mailbox.objects.filter(query)
|
||||
result = map(lambda mb: mb.full_address, mboxes)
|
||||
return ajax_simple_response(result)
|
||||
|
||||
def _validate_alias(request, form, successmsg, tplname, commonctx, callback=None):
|
||||
"""Alias validation
|
||||
|
||||
@@ -175,7 +149,7 @@ def _validate_alias(request, form, successmsg, tplname, commonctx, callback=None
|
||||
"""
|
||||
error = None
|
||||
if form.is_valid():
|
||||
form.set_recipients(request.user)
|
||||
form.set_recipients()
|
||||
try:
|
||||
alias = form.save()
|
||||
except IntegrityError:
|
||||
@@ -202,11 +176,14 @@ def _new_alias(request, tplname, formclass, ctx, successmsg):
|
||||
def callback(user, alias):
|
||||
grant_access_to_object(user, alias, is_owner=True)
|
||||
events.raiseEvent("MailboxAliasCreated", user, alias)
|
||||
if user.is_superuser:
|
||||
for admin in alias.domain.admins:
|
||||
grant_access_to_object(admin, alias)
|
||||
|
||||
form = formclass(request.POST)
|
||||
form = formclass(request.user, request.POST)
|
||||
return _validate_alias(request, form, successmsg, tplname, ctx, callback)
|
||||
|
||||
form = formclass()
|
||||
form = formclass(request.user)
|
||||
ctx["form"] = form
|
||||
return _render(request, tplname, ctx)
|
||||
|
||||
@@ -231,15 +208,15 @@ def newforward(request):
|
||||
ForwardForm, ctx, _("Forward created"))
|
||||
|
||||
def _edit_alias(request, alias, tplname, formclass, ctx, successmsg):
|
||||
if not request.user.can_access(alias.domain):
|
||||
raise PermDeniedException(_("You do not have access to this domain"))
|
||||
if not request.user.can_access(alias):
|
||||
raise PermDeniedException(_("You do not have access to this alias"))
|
||||
ctx.update(title=alias.full_address, action_label=_("Update"),
|
||||
action_classes="submit")
|
||||
if request.method == "POST":
|
||||
form = formclass(request.POST, instance=alias)
|
||||
form = formclass(request.user, request.POST, instance=alias)
|
||||
return _validate_alias(request, form, successmsg, tplname, ctx)
|
||||
|
||||
form = formclass(instance=alias)
|
||||
form = formclass(request.user, instance=alias)
|
||||
ctx["form"] = form
|
||||
return _render(request, tplname, ctx)
|
||||
|
||||
@@ -264,10 +241,8 @@ def _del_alias(request, msg, msgs):
|
||||
selection = request.GET["selection"].split(",")
|
||||
for alid in selection:
|
||||
alias = Alias.objects.get(pk=alid)
|
||||
if not request.user.can_access(alias.domain):
|
||||
raise PermDeniedException(_("You do not have access to this domain"))
|
||||
events.raiseEvent("MailboxAliasDeleted", alias)
|
||||
ungrant_access_to_object(alias)
|
||||
if not request.user.can_access(alias):
|
||||
raise PermDeniedException(_("!"))
|
||||
alias.delete()
|
||||
|
||||
msg = ungettext(msg, msgs, len(selection))
|
||||
@@ -289,32 +264,29 @@ def delforward(request):
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.has_perm("auth.add_user") or u.has_perm("admin.add_alias"))
|
||||
def identities(request, tplname='admin/identities.html'):
|
||||
accounts_list = []
|
||||
idents_list = request.user.get_identities()
|
||||
squery = request.GET.get("searchquery", None)
|
||||
mbalias_q = Q(domain__in=request.user.get_domains())
|
||||
if squery:
|
||||
accounts = User.objects.filter(username__contains=squery)
|
||||
uct = get_content_type(User)
|
||||
uids = idents_list.filter(content_type=uct).values_list("object_id", flat=True)
|
||||
objects = [u for u in User.objects.filter(pk__in=uids, username__contains=squery)]
|
||||
alct = get_content_type(Alias)
|
||||
alids = idents_list.filter(content_type=alct).values_list("object_id", flat=True)
|
||||
if squery.find('@') != -1:
|
||||
local_part, domname = split_mailbox(squery)
|
||||
mbaliases = Alias.objects.filter(address__contains=local_part,
|
||||
domain__name__contains=domname)
|
||||
q = Q(address__contains=local_part, domain__name__contains=domname)
|
||||
else:
|
||||
mbaliases = Alias.objects.filter(mbalias_q & Q(address__contains=squery))
|
||||
q = Q(address__contains=squery)
|
||||
objects += [al for al in Alias.objects.filter(Q(pk__in=alids) & q)]
|
||||
else:
|
||||
accounts = User.objects.all()
|
||||
mbaliases = Alias.objects.filter(mbalias_q)
|
||||
|
||||
for account in accounts:
|
||||
if request.user.can_access(account) or \
|
||||
account.has_mailbox and request.user.can_access(account.mailbox_set.all()[0].domain):
|
||||
accounts_list += [account]
|
||||
for mbalias in mbaliases:
|
||||
if len(mbalias.get_recipients()) >= 2 or \
|
||||
not len(mbalias.mboxes.all()):
|
||||
accounts_list += [mbalias]
|
||||
|
||||
objects = []
|
||||
for oa in idents_list:
|
||||
if oa.content_object:
|
||||
objects.append(oa.content_object)
|
||||
return render_listing(request, "identities", tplname,
|
||||
objects=accounts_list, squery=squery)
|
||||
objects=objects, squery=squery)
|
||||
|
||||
@login_required
|
||||
@permission_required("auth.add_user")
|
||||
@@ -332,7 +304,7 @@ def newaccount(request, tplname='admin/newaccount.html'):
|
||||
def create_account(steps):
|
||||
"""Account creation callback
|
||||
|
||||
Called when all the creation steps have been validated.
|
||||
Called when all creation steps have been validated.
|
||||
|
||||
:param steps: the steps data
|
||||
"""
|
||||
@@ -343,7 +315,7 @@ def newaccount(request, tplname='admin/newaccount.html'):
|
||||
events.raiseEvent("AccountCreated", account)
|
||||
|
||||
mailform = steps[1]["form"]
|
||||
mailform.save(request.user, account)
|
||||
mb = mailform.save(request.user, account)
|
||||
|
||||
ctx = dict(
|
||||
title=_("New account"),
|
||||
@@ -386,14 +358,11 @@ def newaccount(request, tplname='admin/newaccount.html'):
|
||||
@transaction.commit_on_success
|
||||
def editaccount(request, accountid, tplname="common/tabforms.html"):
|
||||
account = User.objects.get(pk=accountid)
|
||||
if not request.user.can_access(account):
|
||||
raise PermDeniedException(_("You can't access this account"))
|
||||
mb = None
|
||||
if account.has_mailbox:
|
||||
mb = account.mailbox_set.all()[0]
|
||||
if not request.user.can_access(mb.domain):
|
||||
raise PermDeniedException(_("You don't have access to this domain"))
|
||||
else:
|
||||
if not request.user.can_access(account):
|
||||
raise PermDeniedException(_("You can't access this account"))
|
||||
mb = None
|
||||
|
||||
instances = dict(general=account, mail=mb, perms=account)
|
||||
events.raiseEvent("FillAccountInstances", request.user, account, instances)
|
||||
@@ -440,25 +409,6 @@ def delaccount(request):
|
||||
messages.info(request, msg, fail_silently=True)
|
||||
return ajax_response(request)
|
||||
|
||||
@login_required
|
||||
@permission_required("auth.add_account")
|
||||
@check_domain_access
|
||||
def search_account(request):
|
||||
search = request.POST.get("search", None)
|
||||
if search is None:
|
||||
return ajax_simple_response([])
|
||||
|
||||
query = Q(username__startswith=search)
|
||||
query &= Q(is_superuser=False)
|
||||
if not request.user.has_perm("admin.add_domain"):
|
||||
query &= Q(groups__name="SimpleUsers")
|
||||
else:
|
||||
query &= ~Q(groups__name__in=["DomainAdmins"])
|
||||
|
||||
users = User.objects.filter(query)
|
||||
result = map(lambda u: u.username, users.all())
|
||||
return ajax_simple_response(result)
|
||||
|
||||
@login_required
|
||||
@permission_required("admin.add_domain")
|
||||
def remove_permission(request):
|
||||
|
||||
@@ -113,10 +113,17 @@ def modify_user_record(mailbox, oldmailbox):
|
||||
u.save()
|
||||
|
||||
@events.observe("DeleteMailbox")
|
||||
def remove_user_record(mailbox):
|
||||
def remove_user_record(mailboxes):
|
||||
from models import Users
|
||||
from modoboa.admin.models import Mailbox
|
||||
|
||||
Users.objects.get(email=mailbox.full_address).delete()
|
||||
if isinstance(mailboxes, Mailbox):
|
||||
mailboxes = [mailboxes]
|
||||
for mailbox in mailboxes:
|
||||
try:
|
||||
Users.objects.get(email=mailbox.full_address).delete()
|
||||
except Users.DoesNotExist:
|
||||
pass
|
||||
|
||||
@events.observe("GetStaticContent")
|
||||
def extra_static_content(user):
|
||||
|
||||
@@ -32,6 +32,8 @@ def inc_limit(user, lname):
|
||||
pass
|
||||
|
||||
def dec_limit(user, lname):
|
||||
if user is None:
|
||||
return
|
||||
try:
|
||||
user.limitspool.dec_curvalue(lname)
|
||||
except LimitsPool.DoesNotExist:
|
||||
@@ -96,7 +98,6 @@ def dec_nb_mailboxes(mailboxes):
|
||||
for mailbox in mailboxes:
|
||||
owner = get_object_owner(mailbox)
|
||||
dec_limit(owner, 'mailboxes_limit')
|
||||
# FIXME: Gestion des alias ici
|
||||
|
||||
@events.observe('MailboxAliasCreated')
|
||||
def inc_nb_mbaliases(user, mailboxalias):
|
||||
|
||||
+9
-26
@@ -78,6 +78,15 @@ def ungrant_access_to_object(obj, user=None):
|
||||
else:
|
||||
ObjectAccess.objects.filter(content_type=ct, object_id=obj.id).delete()
|
||||
|
||||
def ungrant_access_to_objects(objects):
|
||||
"""Cancel all accesses for a given objects list
|
||||
|
||||
:param objects: a list of objects inheriting from ``model.Model``
|
||||
"""
|
||||
for obj in objects:
|
||||
ct = get_content_type(obj)
|
||||
ObjectAccess.objects.filter(content_type=ct, object_id=obj.id).delete()
|
||||
|
||||
def get_object_owner(obj):
|
||||
"""Return the unique owner of this object
|
||||
|
||||
@@ -90,29 +99,3 @@ def get_object_owner(obj):
|
||||
except ObjectAccess.DoesNotExist:
|
||||
return None
|
||||
return entry.user
|
||||
|
||||
def check_domain_access(f):
|
||||
"""Decorator to check if the current user can access a domain
|
||||
|
||||
This decorator only applies to url that contain a 'domid' or
|
||||
'mbid' parameter. (for a direct access)
|
||||
|
||||
Raise a ``PermDeniedError`` if the current user can't view the
|
||||
requested object.
|
||||
"""
|
||||
@wraps(f)
|
||||
def dec(request, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
domain = None
|
||||
domid = request.GET.get("domid", None)
|
||||
if domid:
|
||||
domain = Domain.objects.get(pk=domid)
|
||||
else:
|
||||
mbid = request.GET.get("mbid", None)
|
||||
if mbid:
|
||||
domain = Mailbox.objects.get(pk=mbid).domain
|
||||
if domain and not request.user.can_access(domain):
|
||||
raise PermDeniedError(_("You can't access this domain"))
|
||||
|
||||
return f(request, **kwargs)
|
||||
return dec
|
||||
|
||||
Reference in New Issue
Block a user