mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: relay domains.
Fixed various issues about: * Permissions * Limits Unit tests were also added. see #491
This commit is contained in:
@@ -39,8 +39,13 @@ base_events = [
|
||||
]
|
||||
|
||||
|
||||
def load_settings():
|
||||
from .app_settings import GeneralParametersForm, UserSettings
|
||||
def load_core_settings():
|
||||
"""Load core settings.
|
||||
|
||||
This function must be manually called (see :file:`urls.py`) in
|
||||
order to load base settings.
|
||||
"""
|
||||
from modoboa.core.app_settings import GeneralParametersForm, UserSettings
|
||||
|
||||
parameters.register(GeneralParametersForm, ugettext_lazy("General"))
|
||||
parameters.register(UserSettings, ugettext_lazy("General"))
|
||||
|
||||
@@ -37,7 +37,7 @@ class ExtensionsPool(object):
|
||||
"""The extensions manager"""
|
||||
|
||||
def __init__(self):
|
||||
self.extensions = dict()
|
||||
self.extensions = {}
|
||||
|
||||
def register_extension(self, ext, show=True):
|
||||
self.extensions[ext.name] = dict(cls=ext, show=show)
|
||||
@@ -63,6 +63,16 @@ class ExtensionsPool(object):
|
||||
return instance.infos()
|
||||
|
||||
def load_all(self):
|
||||
"""Load all enabled extensions.
|
||||
|
||||
Each extension must be loaded in order to integrate with
|
||||
Modoboa. Only enabled and special extensions are loaded but
|
||||
urls are always returned. The reason is urls are imported only
|
||||
once so must know all of them when the python process
|
||||
starts. Otherwise, it would lead to unexpected 404 errors :p
|
||||
|
||||
:return: a list of url maps
|
||||
"""
|
||||
from modoboa.core.models import Extension
|
||||
|
||||
for ext in settings.MODOBOA_APPS:
|
||||
@@ -70,6 +80,14 @@ class ExtensionsPool(object):
|
||||
result = []
|
||||
for extname in self.extensions.keys():
|
||||
extinstance = self.get_extension(extname)
|
||||
try:
|
||||
baseurl = extinstance.url \
|
||||
if extinstance.url is not None else extname
|
||||
result += [(r'^%s/' % (baseurl),
|
||||
include("%s.urls" % extinstance.__module__))]
|
||||
except ImportError:
|
||||
# No urls for this extension
|
||||
pass
|
||||
if not extinstance.always_active:
|
||||
try:
|
||||
ext = Extension.objects.get(name=extname)
|
||||
@@ -78,16 +96,11 @@ class ExtensionsPool(object):
|
||||
except Extension.DoesNotExist:
|
||||
continue
|
||||
extinstance.load()
|
||||
try:
|
||||
baseurl = extinstance.url if extinstance.url is not None else extname
|
||||
result += [(r'^%s/' % (baseurl),
|
||||
include("%s.urls" % extinstance.__module__))]
|
||||
except ImportError:
|
||||
# No urls for this extension
|
||||
pass
|
||||
return result
|
||||
|
||||
def list_all(self):
|
||||
"""List all defined extensions.
|
||||
"""
|
||||
result = []
|
||||
for extname, extdef in self.extensions.iteritems():
|
||||
if not extdef["show"]:
|
||||
|
||||
@@ -13,6 +13,7 @@ admin_events = [
|
||||
"DomainCreated",
|
||||
"DomainModified",
|
||||
"DomainDeleted",
|
||||
"DomainOwnershipRemoved",
|
||||
"ExtraDomainEntries",
|
||||
"ExtraDomainMenuEntries",
|
||||
"ExtraDomainFilters",
|
||||
@@ -201,6 +202,11 @@ def user_logged_in(request, username, password):
|
||||
|
||||
@events.observe("AccountDeleted")
|
||||
def account_deleted(account, byuser, **kwargs):
|
||||
"""'AccountDeleted' listener.
|
||||
|
||||
When an account is deleted, we also need to remove its mailbox (if
|
||||
any).
|
||||
"""
|
||||
if not account.mailbox_set.count():
|
||||
return
|
||||
mb = account.mailbox_set.all()[0]
|
||||
|
||||
@@ -46,20 +46,20 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
widget=forms.HiddenInput, required=False
|
||||
)
|
||||
else:
|
||||
self.fields["role"].choices = \
|
||||
[('', ugettext_lazy("Choose"))] + get_account_roles(user)
|
||||
self.fields["role"].choices = [('', ugettext_lazy("Choose"))]
|
||||
self.fields["role"].choices += \
|
||||
get_account_roles(user, kwargs['instance']) \
|
||||
if 'instance' in kwargs else get_account_roles(user)
|
||||
|
||||
if "instance" in kwargs:
|
||||
if len(args) \
|
||||
if args \
|
||||
and (args[0].get("password1", "") == ""
|
||||
and args[0].get("password2", "") == ""):
|
||||
self.fields["password1"].required = False
|
||||
self.fields["password2"].required = False
|
||||
|
||||
u = kwargs["instance"]
|
||||
self.fields["role"].initial = u.group
|
||||
|
||||
if not u.is_local \
|
||||
account = kwargs["instance"]
|
||||
self.fields["role"].initial = account.group
|
||||
if not account.is_local \
|
||||
and parameters.get_admin("LDAP_AUTH_METHOD") == "directbind":
|
||||
del self.fields["password1"]
|
||||
del self.fields["password2"]
|
||||
|
||||
@@ -23,6 +23,8 @@ class DomainManager(Manager):
|
||||
|
||||
|
||||
class Domain(AdminObject):
|
||||
"""Mail domain.
|
||||
"""
|
||||
name = models.CharField(ugettext_lazy('name'), max_length=100, unique=True,
|
||||
help_text=ugettext_lazy("The domain name"))
|
||||
quota = models.IntegerField(
|
||||
@@ -84,11 +86,15 @@ class Domain(AdminObject):
|
||||
grant_access_to_object(account, al)
|
||||
|
||||
def remove_admin(self, account):
|
||||
"""Remove an administrator for this domain
|
||||
"""Remove an administrator of this domain.
|
||||
|
||||
:param User account: the administrotor to remove
|
||||
:param User account: administrator to remove
|
||||
"""
|
||||
from modoboa.lib.permissions import ungrant_access_to_object
|
||||
from modoboa.lib.permissions import \
|
||||
ungrant_access_to_object, get_object_owner
|
||||
|
||||
if get_object_owner(self) == account:
|
||||
events.raiseEvent('DomainOwnershipRemoved', account, self)
|
||||
ungrant_access_to_object(self, account)
|
||||
for mb in self.mailbox_set.all():
|
||||
if mb.user.has_perm("admin.add_domain"):
|
||||
@@ -96,26 +102,27 @@ class Domain(AdminObject):
|
||||
ungrant_access_to_object(mb, account)
|
||||
ungrant_access_to_object(mb.user, account)
|
||||
for al in self.alias_set.all():
|
||||
ungrant_access_to_object(al, account)
|
||||
ungrant_access_to_object(al, account)
|
||||
|
||||
def delete(self, fromuser, keepdir=False):
|
||||
from modoboa.lib.permissions import \
|
||||
ungrant_access_to_object, ungrant_access_to_objects
|
||||
"""Custom delete method.
|
||||
"""
|
||||
from modoboa.lib.permissions import ungrant_access_to_objects
|
||||
from .mailbox import Quota
|
||||
|
||||
if self.domainalias_set.count():
|
||||
events.raiseEvent("DomainAliasDeleted", self.domainalias_set.all())
|
||||
ungrant_access_to_objects(self.domainalias_set.all())
|
||||
if self.mailbox_set.count():
|
||||
Quota.objects.filter(username__contains='@%s' % self.name).delete()
|
||||
events.raiseEvent("DeleteMailbox", self.mailbox_set.all())
|
||||
ungrant_access_to_objects(self.mailbox_set.all())
|
||||
if self.alias_set.count():
|
||||
events.raiseEvent("MailboxAliasDelete", self.alias_set.all())
|
||||
events.raiseEvent("MailboxAliasDeleted", self.alias_set.all())
|
||||
ungrant_access_to_objects(self.alias_set.all())
|
||||
if parameters.get_admin("AUTO_ACCOUNT_REMOVAL") == "yes":
|
||||
for account in User.objects.filter(mailbox__domain__name=self.name):
|
||||
account.delete(fromuser, keepdir)
|
||||
elif self.mailbox_set.count():
|
||||
Quota.objects.filter(username__contains='@%s' % self.name).delete()
|
||||
events.raiseEvent("MailboxDeleted", self.mailbox_set.all())
|
||||
ungrant_access_to_objects(self.mailbox_set.all())
|
||||
super(Domain, self).delete()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -238,7 +238,7 @@ def mailbox_deleted_handler(sender, **kwargs):
|
||||
from modoboa.lib.permissions import ungrant_access_to_object
|
||||
|
||||
mb = kwargs['instance']
|
||||
events.raiseEvent("DeleteMailbox", mb)
|
||||
events.raiseEvent("MailboxDeleted", mb)
|
||||
ungrant_access_to_object(mb)
|
||||
for alias in mb.alias_set.all():
|
||||
alias.mboxes.remove(mb)
|
||||
|
||||
@@ -213,11 +213,11 @@ Domains.prototype = {
|
||||
|
||||
domadminsform_init: function() {
|
||||
$("a[name=removeperm]").click(function(e) {
|
||||
var $tr = $(this).parent().parent();
|
||||
var $tr = $(this).parents('tr');
|
||||
simple_ajax_request.apply(this, [e, {
|
||||
ok_cb: function(resp) {
|
||||
$tr.remove();
|
||||
if (!$("#domadmins").children("tr").length) {
|
||||
if (!$("#domadmins").find("tr").length) {
|
||||
$("#admins").html('<div class="alert alert-info">'
|
||||
+ gettext("No domain administrator defined") + "</div>");
|
||||
}
|
||||
@@ -235,7 +235,6 @@ Domains.prototype = {
|
||||
1: this.optionsform_prefill
|
||||
},
|
||||
error_callbacks: {
|
||||
//1: this.generalform_init,
|
||||
2: $.proxy(this.optionsform_init, this)
|
||||
},
|
||||
success_callback: $.proxy(this.reload_listing, this)
|
||||
@@ -254,7 +253,7 @@ Domains.prototype = {
|
||||
});
|
||||
}, this));
|
||||
$(document).trigger('domform_init');
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Domains.prototype = $.extend({}, Admin.prototype, Domains.prototype);
|
||||
|
||||
@@ -12,7 +12,6 @@ from modoboa.lib import events, parameters
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from .models import LimitTemplates
|
||||
from .forms import ResourcePoolForm
|
||||
import controls
|
||||
|
||||
levents = [
|
||||
'GetExtraLimitTemplates'
|
||||
@@ -53,6 +52,8 @@ class Limits(ModoExtension):
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.limits.app_settings import ParametersForm
|
||||
from modoboa.extensions.limits import controls
|
||||
|
||||
parameters.register(ParametersForm, ugettext_lazy("Limits"))
|
||||
events.declare(levents)
|
||||
|
||||
|
||||
@@ -56,8 +56,9 @@ def inc_nb_domains(user, domain):
|
||||
|
||||
|
||||
@events.observe('DomainDeleted')
|
||||
def dec_nb_domains(domain):
|
||||
owner = get_object_owner(domain)
|
||||
def dec_nb_domains(domain, owner=None):
|
||||
if owner is None:
|
||||
owner = get_object_owner(domain)
|
||||
dec_limit_usage(owner, 'domains_limit')
|
||||
for domalias in domain.domainalias_set.all():
|
||||
dec_nb_domaliases(domalias)
|
||||
@@ -105,9 +106,14 @@ def inc_nb_mbaliases(user, mailboxalias):
|
||||
|
||||
|
||||
@events.observe('MailboxAliasDeleted')
|
||||
def dec_nb_mbaliases(mailboxalias):
|
||||
owner = get_object_owner(mailboxalias)
|
||||
dec_limit_usage(owner, 'mailbox_aliases_limit')
|
||||
def dec_nb_mbaliases(mailboxaliases):
|
||||
from modoboa.extensions.admin.models import Alias
|
||||
|
||||
if isinstance(mailboxaliases, Alias):
|
||||
mailboxaliases = [mailboxaliases]
|
||||
for alias in mailboxaliases:
|
||||
owner = get_object_owner(alias)
|
||||
dec_limit_usage(owner, 'mailbox_aliases_limit')
|
||||
|
||||
|
||||
@events.observe('CanCreate')
|
||||
@@ -118,21 +124,20 @@ def can_create_new_object(user, objtype, count=1):
|
||||
@events.observe("AccountCreated")
|
||||
def create_pool(user):
|
||||
owner = get_object_owner(user)
|
||||
if not owner.is_superuser and \
|
||||
not owner.belongs_to_group("Resellers"):
|
||||
if not owner.group in ['SuperAdmins', 'Resellers']:
|
||||
return
|
||||
|
||||
if user.belongs_to_group("DomainAdmins"):
|
||||
if user.group == 'DomainAdmins':
|
||||
check_limit(owner, 'domain_admins_limit')
|
||||
inc_limit_usage(owner, 'domain_admins_limit')
|
||||
|
||||
if user.group in ["DomainAdmins", "Resellers"]:
|
||||
if user.group in ['DomainAdmins', 'Resellers']:
|
||||
p, created = LimitsPool.objects.get_or_create(user=user)
|
||||
p.create_limits(owner)
|
||||
|
||||
|
||||
@events.observe("UserCanSetRole")
|
||||
def user_can_set_role(user, role):
|
||||
def user_can_set_role(user, role, account=None):
|
||||
"""Check if the user can still set this role.
|
||||
|
||||
The only interesting case concerns resellers defining new domain
|
||||
@@ -140,6 +145,7 @@ def user_can_set_role(user, role):
|
||||
operation before any modification is made to :keyword:`account`.
|
||||
|
||||
:param ``User`` user: connected user
|
||||
:param ``User`` account: account modified (None on creation)
|
||||
:param str newrole: role to check
|
||||
"""
|
||||
if role == 'DomainAdmins':
|
||||
@@ -148,6 +154,8 @@ def user_can_set_role(user, role):
|
||||
return [True]
|
||||
if user.is_superuser or not user.limitspool.will_be_reached(lname):
|
||||
return [True]
|
||||
if account is not None and account.group == role:
|
||||
return [True]
|
||||
return [False]
|
||||
|
||||
|
||||
@@ -192,3 +200,20 @@ def on_account_deleted(account, byuser, **kwargs):
|
||||
|
||||
if account.group == "DomainAdmins":
|
||||
dec_limit_usage(owner, 'domain_admins_limit')
|
||||
|
||||
|
||||
@events.observe('DomainOwnershipRemoved')
|
||||
def domain_ownership_removed(reseller, domain):
|
||||
"""DomainOwnershipRemoved listener.
|
||||
|
||||
The access :keyword:`reseller` had to :keyword:`domain` has been
|
||||
removed by a super adminstrator. We must decrement all limit
|
||||
usages.
|
||||
|
||||
:param ``User`` reseller: reseller that created :keyword:`domain`
|
||||
:param ``Domain`` domain: domain
|
||||
"""
|
||||
dec_nb_domains(domain, reseller)
|
||||
for dadmin in domain.admins:
|
||||
if reseller.is_owner(dadmin):
|
||||
dec_limit_usage(reseller, 'domain_admins_limit')
|
||||
|
||||
@@ -12,16 +12,11 @@ from modoboa.extensions.limits.models import LimitTemplates
|
||||
|
||||
class PermissionsTestCase(ExtTestCase):
|
||||
fixtures = ["initial_users.json"]
|
||||
name = "limits"
|
||||
names = ["limits"]
|
||||
|
||||
def setUp(self):
|
||||
super(PermissionsTestCase, self).setUp()
|
||||
dom = DomainFactory(name='test.com')
|
||||
self.admin = UserFactory(
|
||||
username='admin@test.com', groups=('DomainAdmins',)
|
||||
)
|
||||
MailboxFactory(address='admin', domain=dom, user=self.admin)
|
||||
dom.add_admin(self.admin)
|
||||
populate_database()
|
||||
|
||||
def test_domainadmin_deletes_reseller(self):
|
||||
"""Check if a domain admin can delete a reseller.
|
||||
@@ -46,13 +41,21 @@ class PermissionsTestCase(ExtTestCase):
|
||||
|
||||
class ResourceTestCase(ExtTestCase):
|
||||
fixtures = ["initial_users.json"]
|
||||
name = "limits"
|
||||
names = ["limits"]
|
||||
|
||||
def setUp(self):
|
||||
"""Custom setUp method.
|
||||
|
||||
The 'limits' is manually loaded to ensure extra parameters
|
||||
provided by 'postfix_relay_domains' are properly received.
|
||||
"""
|
||||
from modoboa.core.extensions import exts_pool
|
||||
|
||||
super(ResourceTestCase, self).setUp()
|
||||
populate_database()
|
||||
exts_pool.get_extension('limits').load()
|
||||
for tpl in LimitTemplates().templates:
|
||||
parameters.save_admin('DEFLT_%s' % tpl[0].upper(), 2, app='limits')
|
||||
populate_database()
|
||||
|
||||
def _create_account(self, username, role='SimpleUsers', status=200):
|
||||
values = dict(
|
||||
@@ -255,6 +258,37 @@ class ResellerTestCase(ResourceTestCase):
|
||||
self._check_limit('domain_admins', 2, 2)
|
||||
self._check_limit('domains', 3, 3)
|
||||
|
||||
def test_reseller_deletes_domain(self):
|
||||
"""Check if all resources are restored after the deletion.
|
||||
"""
|
||||
self._create_domain('domain.tld', withtpl=True)
|
||||
dom = Domain.objects.get(name="domain.tld")
|
||||
self.ajax_post(
|
||||
reverse("modoboa.extensions.admin.views.domain.deldomain",
|
||||
args=[dom.id]),
|
||||
{}
|
||||
)
|
||||
self._check_limit('domains', 0, 2)
|
||||
self._check_limit('domain_admins', 1, 2)
|
||||
self._check_limit('mailboxes', 0, 2)
|
||||
self._check_limit('mailbox_aliases', 0, 2)
|
||||
|
||||
def test_sadmin_removes_ownership(self):
|
||||
self._create_domain('domain.tld', withtpl=True)
|
||||
dom = Domain.objects.get(name="domain.tld")
|
||||
self.clt.logout()
|
||||
self.clt.login(username='admin', password='password')
|
||||
self.ajax_get(
|
||||
reverse(
|
||||
'modoboa.extensions.admin.views.identity.remove_permission'
|
||||
) + '?domid=%d&daid=%d' % (dom.id, self.user.id)
|
||||
, {}
|
||||
)
|
||||
self._check_limit('domains', 0, 2)
|
||||
self._check_limit('domain_admins', 0, 2)
|
||||
self._check_limit('mailboxes', 0, 2)
|
||||
self._check_limit('mailbox_aliases', 0, 2)
|
||||
|
||||
def test_allocate_from_pool(self):
|
||||
self._create_domain('domain.tld')
|
||||
self._create_account('admin1@domain.tld', role='DomainAdmins')
|
||||
|
||||
@@ -23,6 +23,7 @@ class PostfixRelayDomains(ModoExtension):
|
||||
label = "Postfix relay domains"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Relay domains support for Postfix")
|
||||
depends_on = ['limits']
|
||||
|
||||
def init(self):
|
||||
"""Initialisation method.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import factory
|
||||
from modoboa.core.factories import PermissionFactory
|
||||
from . import models
|
||||
|
||||
|
||||
class ServiceFactory(factory.DjangoModelFactory):
|
||||
FACTORY_FOR = models.Service
|
||||
FACTORY_DJANGO_GET_OR_CREATE = ('name', )
|
||||
|
||||
name = 'dummy'
|
||||
|
||||
|
||||
class RelayDomainFactory(PermissionFactory):
|
||||
FACTORY_FOR = models.RelayDomain
|
||||
|
||||
target_host = 'external.host.tld'
|
||||
service = factory.SubFactory(ServiceFactory)
|
||||
|
||||
|
||||
class RelayDomainAliasFactory(PermissionFactory):
|
||||
FACTORY_FOR = models.RelayDomainAlias
|
||||
|
||||
enabled = True
|
||||
@@ -1,13 +1,201 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.core.factories import UserFactory
|
||||
from modoboa.lib.tests import ExtTestCase
|
||||
from modoboa.extensions.admin import factories
|
||||
from modoboa.extensions.limits.tests import ResourceTestCase
|
||||
from .models import RelayDomain, RelayDomainAlias, Service
|
||||
from .factories import RelayDomainFactory, RelayDomainAliasFactory
|
||||
|
||||
|
||||
class RelayDomainsTestCase(ExtTestCase):
|
||||
fixtures = ["initial_users.json"]
|
||||
name = "postfix_relay_domains"
|
||||
class Operations(object):
|
||||
|
||||
def _create_relay_domain(self, name, status=200):
|
||||
srv, created = Service.objects.get_or_create(name='dummy')
|
||||
values = {
|
||||
'name': name, 'target_host': 'external.host.tld',
|
||||
'service': srv.id, 'enabled': True
|
||||
}
|
||||
return self.ajax_post(
|
||||
reverse("modoboa.extensions.postfix_relay_domains.views.create"),
|
||||
values, status
|
||||
)
|
||||
|
||||
def _relay_domain_alias_operation(self, optype, rdomain, name, status=200):
|
||||
rdom = RelayDomain.objects.get(name=rdomain)
|
||||
values = {
|
||||
'name': rdom.name, 'target_host': rdom.target_host,
|
||||
'service': rdom.service.id
|
||||
}
|
||||
aliases = [alias.name for alias in rdom.relaydomainalias_set.all()]
|
||||
if optype == 'add':
|
||||
aliases.append(name)
|
||||
else:
|
||||
aliases.remove(name)
|
||||
for cpt, alias in enumerate(aliases):
|
||||
fname = 'aliases' if not cpt else 'aliases_%d' % cpt
|
||||
values[fname] = alias
|
||||
return self.ajax_post(
|
||||
reverse("modoboa.extensions.postfix_relay_domains.views.edit",
|
||||
args=[rdom.id]),
|
||||
values, status
|
||||
)
|
||||
|
||||
|
||||
class RelayDomainsTestCase(ExtTestCase, Operations):
|
||||
fixtures = ['initial_users.json']
|
||||
names = ['postfix_relay_domains']
|
||||
|
||||
def setUp(self):
|
||||
super(RelayDomainsTestCase, self).setUp()
|
||||
factories.populate_database()
|
||||
self.rdom = RelayDomainFactory(name='relaydomain.tld')
|
||||
RelayDomainAliasFactory(name='relaydomainalias.tld', target=self.rdom)
|
||||
|
||||
|
||||
def test_create_relaydomain(self):
|
||||
"""Test the creation of a relay domain.
|
||||
|
||||
We also check that unique constraints are respected: domain,
|
||||
relay domain alias.
|
||||
|
||||
FIXME: add a check for domain alias.
|
||||
"""
|
||||
self._create_relay_domain('relaydomain1.tld')
|
||||
rdom = RelayDomain.objects.get(name='relaydomain1.tld')
|
||||
self.assertEqual(rdom.target_host, 'external.host.tld')
|
||||
self.assertEqual(rdom.service.name, 'dummy')
|
||||
self.assertEqual(rdom.enabled, True)
|
||||
self.assertEqual(rdom.verify_recipients, False)
|
||||
|
||||
resp = self._create_relay_domain('test.com', 400)
|
||||
self.assertEqual(resp['form_errors']['name'][0],
|
||||
'A domain with this name already exists')
|
||||
resp = self._create_relay_domain('relaydomainalias.tld', 400)
|
||||
self.assertEqual(
|
||||
resp['form_errors']['name'][0],
|
||||
'A relay domain alias with this name already exists'
|
||||
)
|
||||
|
||||
def test_create_relaydomainalias(self):
|
||||
"""Test the creation of a relay domain alias.
|
||||
|
||||
We also check that unique constraints are respected: domain,
|
||||
relay domain.
|
||||
|
||||
FIXME: add a check for domain alias.
|
||||
"""
|
||||
self._relay_domain_alias_operation(
|
||||
'add', self.rdom.name, 'relaydomainalias1.tld'
|
||||
)
|
||||
resp = self._relay_domain_alias_operation(
|
||||
'add', self.rdom.name, 'test.com', 400
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['form_errors']['aliases_2'][0],
|
||||
'A domain with this name already exists'
|
||||
)
|
||||
resp = self._relay_domain_alias_operation(
|
||||
'add', self.rdom.name, self.rdom.name, 400
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['form_errors']['aliases_2'][0],
|
||||
'A relay domain with this name already exists'
|
||||
)
|
||||
|
||||
def test_edit_relaydomain(self):
|
||||
"""Test the modification of a relay domain.
|
||||
|
||||
Rename 'relaydomain.tld' domain to 'relaydomain.org'
|
||||
"""
|
||||
values = {
|
||||
'name': 'relaydomain.org', 'target_host': self.rdom.target_host,
|
||||
'service': self.rdom.service.id
|
||||
}
|
||||
self.ajax_post(
|
||||
reverse('modoboa.extensions.postfix_relay_domains.views.edit',
|
||||
args=[self.rdom.id]),
|
||||
values
|
||||
)
|
||||
RelayDomain.objects.get(name='relaydomain.org')
|
||||
|
||||
def test_edit_relaydomainalias(self):
|
||||
"""Test the modification of a relay domain alias.
|
||||
|
||||
Rename 'relaydomainalias.tld' domain to 'relaydomainalias.net'
|
||||
"""
|
||||
values = {
|
||||
'name': 'relaydomain.org', 'target_host': self.rdom.target_host,
|
||||
'service': self.rdom.service.id, 'aliases': 'relaydomainalias.net'
|
||||
}
|
||||
self.ajax_post(
|
||||
reverse('modoboa.extensions.postfix_relay_domains.views.edit',
|
||||
args=[self.rdom.id]),
|
||||
values
|
||||
)
|
||||
RelayDomainAlias.objects.get(name='relaydomainalias.net')
|
||||
with self.assertRaises(RelayDomainAlias.DoesNotExist):
|
||||
RelayDomainAlias.objects.get(name='relaydomainalias.tld')
|
||||
|
||||
def test_delete_relaydomain(self):
|
||||
"""Test the removal of a relay domain
|
||||
"""
|
||||
self.ajax_post(
|
||||
reverse("modoboa.extensions.postfix_relay_domains.views.delete",
|
||||
args=[self.rdom.id]),
|
||||
{}
|
||||
)
|
||||
with self.assertRaises(RelayDomain.DoesNotExist):
|
||||
RelayDomain.objects.get(name='relaydomain.tld')
|
||||
|
||||
def test_delete_relaydomainalias(self):
|
||||
"""Test the remove of a relay domain alias
|
||||
"""
|
||||
self._relay_domain_alias_operation(
|
||||
'del', self.rdom.name, 'relaydomainalias.tld'
|
||||
)
|
||||
with self.assertRaises(RelayDomain.DoesNotExist):
|
||||
RelayDomain.objects.get(name='relaydomainalias.tld')
|
||||
|
||||
|
||||
class LimitsTestCase(ResourceTestCase, Operations):
|
||||
names = ['limits', 'postfix_relay_domains']
|
||||
|
||||
def setUp(self):
|
||||
super(LimitsTestCase, self).setUp()
|
||||
self.user = UserFactory(
|
||||
username='reseller', groups=('Resellers',)
|
||||
)
|
||||
self.clt.logout()
|
||||
self.clt.login(username='reseller', password='toto')
|
||||
|
||||
def test_relay_domains_limit(self):
|
||||
self._create_relay_domain('relaydomain1.tld')
|
||||
self._check_limit('relay_domains', 1, 2)
|
||||
self._create_relay_domain('relaydomain2.tld')
|
||||
self._check_limit('relay_domains', 2, 2)
|
||||
resp = self._create_relay_domain('relaydomain3.tld', 403)
|
||||
self._check_limit('relay_domains', 2, 2)
|
||||
self.ajax_post(
|
||||
reverse('modoboa.extensions.postfix_relay_domains.views.delete',
|
||||
args=[RelayDomain.objects.get(name='relaydomain2.tld').id]),
|
||||
{}
|
||||
)
|
||||
self._check_limit('relay_domains', 1, 2)
|
||||
|
||||
def test_relay_domain_aliases_limit(self):
|
||||
self._create_relay_domain('relaydomain1.tld')
|
||||
self._relay_domain_alias_operation(
|
||||
'add', 'relaydomain1.tld', 'relay_domain_alias1.tld'
|
||||
)
|
||||
self._check_limit('relay_domain_aliases', 1, 2)
|
||||
self._relay_domain_alias_operation(
|
||||
'add', 'relaydomain1.tld', 'relay_domain_alias2.tld'
|
||||
)
|
||||
self._check_limit('relay_domain_aliases', 2, 2)
|
||||
self._relay_domain_alias_operation(
|
||||
'add', 'relaydomain1.tld', 'relay_domain_alias3.tld', 403
|
||||
)
|
||||
self._check_limit('relay_domain_aliases', 2, 2)
|
||||
self._relay_domain_alias_operation(
|
||||
'delete', 'relaydomain1.tld', 'relay_domain_alias2.tld'
|
||||
)
|
||||
self._check_limit('relay_domain_aliases', 1, 2)
|
||||
|
||||
+30
-11
@@ -2,23 +2,27 @@
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.db import IntegrityError
|
||||
from modoboa.core.models import ObjectAccess
|
||||
import events
|
||||
from exceptions import ModoboaException
|
||||
from modoboa.core.models import ObjectAccess, User
|
||||
from modoboa.lib import events
|
||||
from modoboa.lib.exceptions import ModoboaException
|
||||
|
||||
|
||||
def get_account_roles(user):
|
||||
"""Return the list of supported account roles
|
||||
def get_account_roles(user, account=None):
|
||||
"""Return the list of available account roles.
|
||||
|
||||
This list can be extended by extensions which listen to the
|
||||
``GetExtraRoles`` event.
|
||||
This function is used to create or modify an account. The returned
|
||||
list can be extended by listening to the ``GetExtraRoles`` event.
|
||||
|
||||
:param ``User`` user: connected user
|
||||
:param ``User`` account: account beeing modified (None on creation)
|
||||
:return: list of strings
|
||||
"""
|
||||
std_roles = [("SimpleUsers", _("Simple user"))]
|
||||
if user.is_superuser:
|
||||
std_roles += [("SuperAdmins", _("Super administrator"))]
|
||||
filters = events.raiseQueryEvent('UserCanSetRole', user, 'DomainAdmins')
|
||||
filters = events.raiseQueryEvent(
|
||||
'UserCanSetRole', user, 'DomainAdmins', account
|
||||
)
|
||||
if user.has_perm("admin.add_domain") and \
|
||||
(not filters or True in filters):
|
||||
std_roles += [("DomainAdmins", _("Domain administrator"))]
|
||||
@@ -92,17 +96,32 @@ def ungrant_access_to_object(obj, user=None):
|
||||
If no user is provided, all entries referencing this object are
|
||||
deleted from the database.
|
||||
|
||||
If a user is provided, we only remove his access. If it was the
|
||||
owner, we give the ownership to the first super admin we find.
|
||||
|
||||
:param obj: an object inheriting from ``models.Model``
|
||||
:param user: a ``User`` object
|
||||
"""
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
if user:
|
||||
if user is not None:
|
||||
try:
|
||||
ObjectAccess.objects.get(user=user, content_type=ct, object_id=obj.id).delete()
|
||||
ObjectAccess.objects.get(
|
||||
user=user, content_type=ct, object_id=obj.id
|
||||
).delete()
|
||||
except ObjectAccess.DoesNotExist:
|
||||
pass
|
||||
try:
|
||||
ObjectAccess.objects.get(
|
||||
content_type=ct, object_id=obj.id, is_owner=True
|
||||
)
|
||||
except ObjectAccess.DoesNotExist:
|
||||
grant_access_to_object(
|
||||
User.objects.filter(is_superuser=True)[0], obj, True
|
||||
)
|
||||
else:
|
||||
ObjectAccess.objects.filter(content_type=ct, object_id=obj.id).delete()
|
||||
ObjectAccess.objects.filter(
|
||||
content_type=ct, object_id=obj.id
|
||||
).delete()
|
||||
|
||||
|
||||
def ungrant_access_to_objects(objects):
|
||||
|
||||
@@ -27,13 +27,15 @@ class ModoTestCase(TestCase):
|
||||
|
||||
|
||||
class ExtTestCase(ModoTestCase):
|
||||
name = None
|
||||
names = []
|
||||
|
||||
def setUp(self, *args, **kwargs):
|
||||
super(ExtTestCase, self).setUp(*args, **kwargs)
|
||||
self.clt.get(reverse("modoboa.core.views.admin.viewextensions"))
|
||||
self.clt.post(reverse("modoboa.core.views.admin.saveextensions"),
|
||||
{"select_%s" % self.name : "1"})
|
||||
self.clt.post(
|
||||
reverse("modoboa.core.views.admin.saveextensions"),
|
||||
dict(("select_%s" % name, "1") for name in self.names)
|
||||
)
|
||||
|
||||
|
||||
class TestParams(parameters.AdminParametersForm):
|
||||
|
||||
@@ -42,11 +42,10 @@
|
||||
type: 'POST', url: $form.attr("action"), data: data, global: false
|
||||
}).done($.proxy(function(resp) {
|
||||
if (!last) {
|
||||
var stepid = resp.stepid + 1;
|
||||
$('input:text:visible:first').focus();
|
||||
this.set_current_title(resp.title);
|
||||
if (this.options.transition_callbacks[stepid] != undefined) {
|
||||
this.options.transition_callbacks[stepid]();
|
||||
if (this.options.transition_callbacks[resp.stepid] != undefined) {
|
||||
this.options.transition_callbacks[resp.stepid]();
|
||||
}
|
||||
this.$element.carousel('next');
|
||||
} else {
|
||||
|
||||
@@ -35,15 +35,6 @@ function modalbox(e, css, defhref, defcb, defclosecb) {
|
||||
type: "GET",
|
||||
url: href
|
||||
}).done(function(data) {
|
||||
if (typeof data === "object") {
|
||||
/*
|
||||
* Compatibility with the old way...
|
||||
*/
|
||||
if (data.status == "ko" && data.respmsg) {
|
||||
$("body").notify("error", data.respmsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var $div = $('<div />', {
|
||||
id: "modalbox", 'class': "modal", html: data
|
||||
});
|
||||
@@ -56,8 +47,7 @@ function modalbox(e, css, defhref, defcb, defclosecb) {
|
||||
if (modalcb != undefined) {
|
||||
if (typeof modalcb === "function") modalcb(); else eval(modalcb + '()');
|
||||
}
|
||||
})
|
||||
.on('hidden', function(e) {
|
||||
}).on('hidden', function(e) {
|
||||
var $target = $(e.target);
|
||||
|
||||
if (!$target.is($(this))) {
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@ from django.conf.urls import patterns, include
|
||||
from django.conf import settings
|
||||
from modoboa.core.extensions import exts_pool
|
||||
from modoboa.lib import parameters, events
|
||||
from modoboa.core import load_settings
|
||||
from modoboa.core import load_core_settings
|
||||
|
||||
load_settings()
|
||||
load_core_settings()
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
|
||||
Reference in New Issue
Block a user