mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
@@ -106,6 +106,7 @@ TEMPLATE_LOADERS = (
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.transaction.TransactionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
@@ -154,8 +155,8 @@ MODOBOA_APPS = (
|
||||
'modoboa.lib',
|
||||
# Modoboa extensions here.
|
||||
'modoboa.extensions.admin',
|
||||
'modoboa.extensions.limits',
|
||||
'modoboa.extensions.postfix_relay_domains',
|
||||
'modoboa.extensions.limits',
|
||||
'modoboa.extensions.postfix_autoreply',
|
||||
'modoboa.extensions.webmail',
|
||||
'modoboa.extensions.stats',
|
||||
|
||||
@@ -76,11 +76,13 @@ class ExtensionsPool(object):
|
||||
"""
|
||||
from modoboa.core.models import Extension
|
||||
|
||||
result = []
|
||||
for ext in settings.MODOBOA_APPS:
|
||||
__import__(ext)
|
||||
result = []
|
||||
for extname in self.extensions.keys():
|
||||
extname = ext.split('.')[-1]
|
||||
extinstance = self.get_extension(extname)
|
||||
if extinstance is None:
|
||||
continue
|
||||
try:
|
||||
baseurl = extinstance.url \
|
||||
if extinstance.url is not None else extname
|
||||
@@ -106,7 +108,7 @@ class ExtensionsPool(object):
|
||||
for extname, extdef in self.extensions.iteritems():
|
||||
if not extdef["show"]:
|
||||
continue
|
||||
infos = extdef["instance"].infos()
|
||||
infos = self.get_extension_infos(extname)
|
||||
infos["id"] = extname
|
||||
result += [infos]
|
||||
return sorted(result, key=lambda i: i["name"])
|
||||
|
||||
+29
-7
@@ -4,9 +4,11 @@ import re
|
||||
import hashlib
|
||||
import crypt
|
||||
import base64
|
||||
import logging
|
||||
from random import Random
|
||||
import reversion
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_delete
|
||||
from django.dispatch import receiver
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
@@ -463,24 +465,44 @@ class Log(models.Model):
|
||||
|
||||
@receiver(reversion.post_revision_commit)
|
||||
def post_revision_commit(sender, **kwargs):
|
||||
import logging
|
||||
|
||||
if kwargs["revision"].user is None:
|
||||
return
|
||||
logger = logging.getLogger("modoboa.admin")
|
||||
for version in kwargs["versions"]:
|
||||
if version.type == reversion.models.VERSION_ADD:
|
||||
prev_revisions = reversion.get_for_object(version.object)
|
||||
if prev_revisions.count() == 1:
|
||||
action = _("added")
|
||||
level = "info"
|
||||
elif version.type == reversion.models.VERSION_CHANGE:
|
||||
else:
|
||||
action = _("modified")
|
||||
level = "warning"
|
||||
else:
|
||||
action = _("deleted")
|
||||
level = "critical"
|
||||
message = _("%(object)s '%(name)s' %(action)s by user %(user)s") % {
|
||||
"object": unicode(version.content_type).capitalize(),
|
||||
"name": version.object_repr, "action": action,
|
||||
"user": kwargs["revision"].user.username
|
||||
}
|
||||
getattr(logger, level)(message)
|
||||
|
||||
|
||||
@receiver(post_delete)
|
||||
def post_delete_hook(sender, instance, **kwargs):
|
||||
"""Custom post-delete hook.
|
||||
|
||||
We want to know who was responsible for an object deletion.
|
||||
"""
|
||||
from reversion.models import Version
|
||||
|
||||
if not reversion.is_registered(sender):
|
||||
return
|
||||
del_list = reversion.get_deleted(sender)
|
||||
try:
|
||||
version = del_list.get(object_id=instance.id)
|
||||
except Version.DoesNotExist:
|
||||
return
|
||||
logger = logging.getLogger("modoboa.admin")
|
||||
msg = _("%(object)s '%(name)s' %(action)s by user %(user)s") % {
|
||||
"object": unicode(version.content_type).capitalize(),
|
||||
"name": version.object_repr, "action": _("deleted"),
|
||||
"user": version.revision.user.username
|
||||
}
|
||||
logger.critical(msg)
|
||||
|
||||
@@ -45,7 +45,7 @@ def settings_menu(selection, user):
|
||||
"label": _("Information")},
|
||||
{"name": "logs",
|
||||
"class": "ajaxlink",
|
||||
"url": "logs/",
|
||||
"url": "logs/&sort_order=-date_created",
|
||||
"label": _("Logs")},
|
||||
{"name": "parameters",
|
||||
"class": "ajaxlink",
|
||||
|
||||
@@ -107,7 +107,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
username = q['username'].replace('@%s' % self.oldname, '@%s' % domain.name)
|
||||
Quota.objects.filter(username=q['username']).update(username=username)
|
||||
|
||||
def save(self, user, commit=True):
|
||||
def save(self, user, commit=True, domalias_post_create=False):
|
||||
"""Custom save method
|
||||
|
||||
Updating a domain may have consequences on other objects
|
||||
@@ -148,7 +148,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
else:
|
||||
continue
|
||||
al = DomainAlias(name=alias, target=d, enabled=d.enabled)
|
||||
al.save(creator=user)
|
||||
al.save(creator=user) if domalias_post_create else al.save()
|
||||
|
||||
if old_mail_homes is not None:
|
||||
self.update_mailbox_quotas(d)
|
||||
@@ -253,5 +253,6 @@ class DomainForm(TabForms):
|
||||
As forms interact with each other, it is easier to make custom
|
||||
code to save them.
|
||||
"""
|
||||
for f in self.forms:
|
||||
self.forms[0]['instance'].save(user, domalias_post_create=True)
|
||||
for f in self.forms[1:]:
|
||||
f["instance"].save(user)
|
||||
|
||||
@@ -148,4 +148,13 @@ class Domain(AdminObject):
|
||||
for dalias in self.domainalias_set.all():
|
||||
dalias.to_csv(csvwriter)
|
||||
|
||||
def post_create(self, creator):
|
||||
"""Post creation actions.
|
||||
|
||||
:param ``User`` creator: user whos created this domain
|
||||
"""
|
||||
super(Domain, self).post_create(creator)
|
||||
for domalias in self.domainalias_set.all():
|
||||
domalias.post_create(creator)
|
||||
|
||||
reversion.register(Domain)
|
||||
|
||||
@@ -392,7 +392,7 @@ Identities.prototype = {
|
||||
$("#wizard").cwizard({
|
||||
formid: "newaccount_form",
|
||||
transition_callbacks: {
|
||||
2: this.mailform_prefill
|
||||
1: this.mailform_prefill
|
||||
},
|
||||
success_callback: $.proxy(this.reload_listing, this)
|
||||
});
|
||||
|
||||
@@ -115,6 +115,14 @@ def list_quotas(request, tplname="admin/quotas.html"):
|
||||
@permission_required("core.add_user")
|
||||
@transaction.commit_on_success
|
||||
def newaccount(request, tplname='common/wizard_forms.html'):
|
||||
"""Create a new account.
|
||||
|
||||
.. note:: An issue still remains int this code: if all validation
|
||||
steps are successful but an error occurs after we call 'save',
|
||||
the account will be created. It happens transaction management
|
||||
doesn't work very well with nested functions. Need to wait for
|
||||
django 1.6 and atomicity.
|
||||
"""
|
||||
cwizard = CreationWizard()
|
||||
cwizard.add_step(AccountFormGeneral, _("General"),
|
||||
[dict(classes="btn-inverse next", label=_("Next"))],
|
||||
@@ -135,16 +143,9 @@ def newaccount(request, tplname='common/wizard_forms.html'):
|
||||
if retcode == 2:
|
||||
genform = cwizard.steps[0]["form"]
|
||||
account = genform.save()
|
||||
try:
|
||||
account.post_create(request.user)
|
||||
mailform = cwizard.steps[1]["form"]
|
||||
mailform.save(request.user, account)
|
||||
except ModoboaException:
|
||||
# A bit uggly: transaction management doesn't work very
|
||||
# well with nested functions. Need to wait for django 1.6
|
||||
# and atomicity.
|
||||
account.delete(request.user, False)
|
||||
raise
|
||||
account.post_create(request.user)
|
||||
mailform = cwizard.steps[1]["form"]
|
||||
mailform.save(request.user, account)
|
||||
return render_to_json_response(_("Account created"))
|
||||
return render_to_json_response({
|
||||
'stepid': data, 'form_errors': cwizard.errors
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.template import Template, Context
|
||||
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.extensions.admin.models import DomainAlias
|
||||
from modoboa.extensions.amavis.lib import (
|
||||
create_user_and_policy, update_user_and_policy, delete_user_and_policy,
|
||||
create_user_and_use_policy, delete_user
|
||||
@@ -36,13 +36,16 @@ def on_domain_deleted(domain):
|
||||
|
||||
|
||||
@events.observe("DomainAliasCreated")
|
||||
def on_relay_domain_alias_created(user, domainalias):
|
||||
def on_domain_alias_created(user, domainalias):
|
||||
create_user_and_use_policy(domainalias.name, domainalias.target.name)
|
||||
|
||||
|
||||
@events.observe("DomainAliasDeleted")
|
||||
def on_relay_domain_alias_deleted(domainalias):
|
||||
delete_user(domainalias.name)
|
||||
def on_domain_alias_deleted(domainaliases):
|
||||
if isinstance(domainaliases, DomainAlias):
|
||||
domainaliases = [domainaliases]
|
||||
for domainalias in domainaliases:
|
||||
delete_user(domainalias.name)
|
||||
|
||||
|
||||
@events.observe("GetStaticContent")
|
||||
|
||||
@@ -82,7 +82,7 @@ class RelayDomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def save(self, user, commit=True):
|
||||
def save(self, user, commit=True, rdomalias_post_create=False):
|
||||
"""Custom save method.
|
||||
|
||||
As relay domain aliases are defined using the same form as
|
||||
@@ -119,7 +119,8 @@ class RelayDomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
al = RelayDomainAlias(
|
||||
name=alias, target=rd, enabled=rd.enabled
|
||||
)
|
||||
al.save(creator=user)
|
||||
al.save(creator=user) \
|
||||
if rdomalias_post_create else al.save()
|
||||
return rd
|
||||
|
||||
|
||||
@@ -151,5 +152,6 @@ class RelayDomainForm(TabForms):
|
||||
As forms interact with each other, it is easier to make custom
|
||||
code to save them.
|
||||
"""
|
||||
for f in self.forms:
|
||||
self.forms[0]['instance'].save(user, rdomalias_post_create=True)
|
||||
for f in self.forms[1:]:
|
||||
f["instance"].save(user)
|
||||
|
||||
@@ -106,32 +106,6 @@ def extra_limit_templates():
|
||||
]
|
||||
|
||||
|
||||
@events.observe('GetExtraParameters')
|
||||
def extra_parameters(app, level):
|
||||
from django import forms
|
||||
|
||||
if app != 'limits' or level != 'A':
|
||||
return {}
|
||||
return {
|
||||
'deflt_relay_domains_limit': forms.IntegerField(
|
||||
label=ugettext_lazy("Relay domains"),
|
||||
initial=0,
|
||||
help_text=ugettext_lazy(
|
||||
"Maximum number of allowed relay domains for a new administrator"
|
||||
),
|
||||
widget=forms.widgets.TextInput(attrs={"class": "span1"})
|
||||
),
|
||||
'deflt_relay_domain_aliases_limit': forms.IntegerField(
|
||||
label=ugettext_lazy("Relay domain aliases"),
|
||||
initial=0,
|
||||
help_text=ugettext_lazy(
|
||||
"Maximum number of allowed relay domain aliases for a new administrator"
|
||||
),
|
||||
widget=forms.widgets.TextInput(attrs={"class": "span1"})
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@events.observe('ExtraDomainImportHelp')
|
||||
def extra_domain_import_help():
|
||||
return [ugettext_lazy("""
|
||||
|
||||
@@ -1,9 +1,36 @@
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from modoboa.lib import events
|
||||
from modoboa.lib.permissions import get_object_owner
|
||||
from modoboa.extensions.limits.lib import inc_limit_usage, dec_limit_usage
|
||||
from .models import RelayDomainAlias
|
||||
|
||||
|
||||
@events.observe('GetExtraParameters')
|
||||
def extra_parameters(app, level):
|
||||
from django import forms
|
||||
|
||||
if app != 'limits' or level != 'A':
|
||||
return {}
|
||||
return {
|
||||
'deflt_relay_domains_limit': forms.IntegerField(
|
||||
label=ugettext_lazy("Relay domains"),
|
||||
initial=0,
|
||||
help_text=ugettext_lazy(
|
||||
"Maximum number of allowed relay domains for a new administrator"
|
||||
),
|
||||
widget=forms.widgets.TextInput(attrs={"class": "span1"})
|
||||
),
|
||||
'deflt_relay_domain_aliases_limit': forms.IntegerField(
|
||||
label=ugettext_lazy("Relay domain aliases"),
|
||||
initial=0,
|
||||
help_text=ugettext_lazy(
|
||||
"Maximum number of allowed relay domain aliases for a new administrator"
|
||||
),
|
||||
widget=forms.widgets.TextInput(attrs={"class": "span1"})
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@events.observe('RelayDomainCreated')
|
||||
def inc_relaydomains_count(user, rdomain):
|
||||
inc_limit_usage(user, 'relay_domains_limit')
|
||||
|
||||
@@ -139,6 +139,15 @@ class RelayDomain(AdminObject):
|
||||
self.verify_recipients = (row[5].strip() == 'True')
|
||||
self.save(creator=user)
|
||||
|
||||
def post_create(self, creator):
|
||||
"""Post creation actions.
|
||||
|
||||
:param ``User`` creator: user whos created this relay domain
|
||||
"""
|
||||
super(RelayDomain, self).post_create(creator)
|
||||
for rdomalias in self.relaydomainalias_set.all():
|
||||
rdomalias.post_create(creator)
|
||||
|
||||
reversion.register(RelayDomain)
|
||||
|
||||
|
||||
|
||||
@@ -23,9 +23,7 @@ def create(request, tplname="postfix_relay_domains/new_relaydomain_form.html"):
|
||||
if form.is_valid():
|
||||
rdom = form.save(request.user)
|
||||
rdom.post_create(request.user)
|
||||
return render_to_json_response(
|
||||
{"respmsg": _("Relay domain created")}
|
||||
)
|
||||
return render_to_json_response(_("Relay domain created"))
|
||||
return render_to_json_response(
|
||||
{'form_errors': form.errors}, status=400
|
||||
)
|
||||
|
||||
@@ -17,6 +17,8 @@ _params = {'A': {}, 'U': {}}
|
||||
|
||||
|
||||
class NotDefined(ModoboaException):
|
||||
http_code = 404
|
||||
|
||||
def __init__(self, app, name):
|
||||
self.app = app
|
||||
self.name = name
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
django
|
||||
django-reversion==1.7.1
|
||||
django-reversion>=1.8.0
|
||||
dj-database-url
|
||||
south
|
||||
lxml
|
||||
|
||||
Reference in New Issue
Block a user