wip: relay domains.

Fixed various issues about:
* Permissions
* Limits

Unit tests were also added.

see #491
This commit is contained in:
Antoine Nguyen
2013-10-31 20:35:59 +01:00
parent 971c535f18
commit a11e69074d
18 changed files with 400 additions and 88 deletions
+7 -2
View File
@@ -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"))
+21 -8
View File
@@ -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"]:
+6
View File
@@ -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]
+8 -8
View File
@@ -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"]
+18 -11
View File
@@ -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):
+1 -1
View File
@@ -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);
+2 -1
View File
@@ -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)
+35 -10
View File
@@ -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')
+43 -9
View File
@@ -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
View File
@@ -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):
+5 -3
View File
@@ -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):
+2 -3
View File
@@ -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 {
+1 -11
View File
@@ -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
View File
@@ -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(
'',