mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Django 1.7 migrations + cleanup.
This commit is contained in:
@@ -266,28 +266,6 @@ creator.
|
||||
* ``owner`` is the original creator
|
||||
* ``domain`` is the ``Domain`` instance being modified
|
||||
|
||||
ExtDisabled
|
||||
===========
|
||||
|
||||
Raised just after an extension has been disabled.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(extension): pass
|
||||
|
||||
* ``extension`` is an ``Extension`` instance
|
||||
|
||||
ExtEnabled
|
||||
==========
|
||||
|
||||
Raised just after an extension has been activated.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(extension): pass
|
||||
|
||||
* ``extension`` is an ``Extension`` instance
|
||||
|
||||
ExtraAccountActions
|
||||
===================
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@ BASE_EVENTS = [
|
||||
"AdminMenuDisplay",
|
||||
"GetStaticContent",
|
||||
|
||||
"ExtEnabled",
|
||||
"ExtDisabled",
|
||||
|
||||
"UserLogin",
|
||||
"UserLogout",
|
||||
|
||||
@@ -58,17 +55,6 @@ def load_core_settings():
|
||||
events.declare(BASE_EVENTS)
|
||||
|
||||
|
||||
@events.observe("ExtDisabled")
|
||||
def unset_default_topredirection(extension):
|
||||
"""
|
||||
Simple callback to change the default redirection if the
|
||||
corresponding extension is being disabled.
|
||||
"""
|
||||
topredirection = parameters.get_admin("DEFAULT_TOP_REDIRECTION")
|
||||
if topredirection == extension.name:
|
||||
parameters.save_admin("DEFAULT_TOP_REDIRECTION", "core")
|
||||
|
||||
|
||||
@events.observe("TopNotifications")
|
||||
def check_for_new_version(request, include_all):
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,7 @@ from modoboa.lib.form_utils import YesNoField, SeparatorField, InlineRadioSelect
|
||||
|
||||
|
||||
def enabled_applications():
|
||||
"""Return the list of currently enabled extensions
|
||||
"""Return the list of installed extensions.
|
||||
|
||||
We check if the table exists before trying to fetch activated
|
||||
extensions because the admin module is always imported by Django,
|
||||
@@ -17,19 +17,11 @@ def enabled_applications():
|
||||
|
||||
:return: a list
|
||||
"""
|
||||
from modoboa.core.models import Extension
|
||||
from modoboa.core.extensions import exts_pool
|
||||
from modoboa.lib.db_utils import db_table_exists
|
||||
|
||||
result = [("user", "user")]
|
||||
if db_table_exists("core_extension"):
|
||||
exts = Extension.objects.filter(enabled=True)
|
||||
for ext in exts:
|
||||
extclass = exts_pool.get_extension(ext.name)
|
||||
if extclass is None:
|
||||
continue
|
||||
if extclass.available_for_topredirection:
|
||||
result.append((ext.name, ext.name))
|
||||
for extension in exts_pool.list_all():
|
||||
result.append((extension["name"], extension["name"]))
|
||||
return sorted(result, key=lambda e: e[0])
|
||||
|
||||
|
||||
|
||||
@@ -63,10 +63,6 @@ class DeployCommand(Command):
|
||||
self._parser.add_argument(
|
||||
'--domain', type=str, default=None,
|
||||
help='The domain under which you want to deploy modoboa')
|
||||
self._parser.add_argument(
|
||||
'--extensions', type=str, nargs='*',
|
||||
help='Deploy with those extensions already enabled'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--lang', type=str, default="en-us",
|
||||
help="Set the default language"
|
||||
@@ -242,11 +238,6 @@ class DeployCommand(Command):
|
||||
"collectstatic", parsed_args.name, '--noinput'
|
||||
)
|
||||
|
||||
if parsed_args.extensions:
|
||||
self._exec_django_command(
|
||||
"manage_extensions", parsed_args.name, *parsed_args.extensions
|
||||
)
|
||||
|
||||
self._exec_django_command(
|
||||
"set_default_site", parsed_args.name, allowed_host
|
||||
)
|
||||
|
||||
@@ -86,7 +86,6 @@ MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'modoboa.lib.middleware.AjaxLoginRedirect',
|
||||
'modoboa.lib.middleware.CommonExceptionCatcher',
|
||||
'modoboa.lib.middleware.ExtControlMiddleware',
|
||||
'modoboa.lib.middleware.RequestCatcherMiddleware',
|
||||
)
|
||||
|
||||
|
||||
+16
-33
@@ -6,11 +6,13 @@ from django.conf.urls import include
|
||||
|
||||
class ModoExtension(object):
|
||||
|
||||
"""Base extension class.
|
||||
"""
|
||||
Base extension class.
|
||||
|
||||
Each Modoboa extension must inherit from this class to be
|
||||
considered as valid.
|
||||
"""
|
||||
|
||||
name = None
|
||||
label = None
|
||||
version = "NA"
|
||||
@@ -27,12 +29,6 @@ class ModoExtension(object):
|
||||
always_active=self.always_active
|
||||
)
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
@@ -45,26 +41,24 @@ class ExtensionsPool(object):
|
||||
self.extensions = {}
|
||||
|
||||
def register_extension(self, ext, show=True):
|
||||
"""Register an extension.
|
||||
|
||||
:param ext: a class inheriting from ``Extension``
|
||||
:param show: list the extension or not
|
||||
"""
|
||||
self.extensions[ext.name] = dict(cls=ext, show=show)
|
||||
|
||||
def get_extension(self, name):
|
||||
"""Retrieve the current instance of an extension."""
|
||||
if name not in self.extensions:
|
||||
return None
|
||||
if "instance" not in self.extensions[name]:
|
||||
self.extensions[name]["instance"] = self.extensions[name]["cls"]()
|
||||
return self.extensions[name]["instance"]
|
||||
|
||||
def is_extension_enabled(self, name):
|
||||
"""Check if an extension is enabled or not."""
|
||||
from modoboa.core.models import Extension
|
||||
|
||||
if name not in self.extensions:
|
||||
return False
|
||||
try:
|
||||
state = Extension.objects.get(name=name).enabled
|
||||
except Extension.DoesNotExist:
|
||||
state = False
|
||||
return state
|
||||
def is_extension_installed(self, name):
|
||||
"""Check if an extension is installed ir not."""
|
||||
return name in settings.MODOBOA_APPS
|
||||
|
||||
def get_extension_infos(self, name):
|
||||
instance = self.get_extension(name)
|
||||
@@ -73,7 +67,7 @@ class ExtensionsPool(object):
|
||||
return instance.infos()
|
||||
|
||||
def load_all(self):
|
||||
"""Load all enabled extensions.
|
||||
"""Load all defined extensions.
|
||||
|
||||
Each extension must be loaded in order to integrate with
|
||||
Modoboa. Only enabled and special extensions are loaded but
|
||||
@@ -83,11 +77,9 @@ class ExtensionsPool(object):
|
||||
|
||||
:return: a list of url maps
|
||||
"""
|
||||
from modoboa.core.models import Extension
|
||||
|
||||
result = []
|
||||
for ext in settings.MODOBOA_APPS:
|
||||
__import__(ext)
|
||||
__import__(ext, locals(), globals(), ["modo_extension"])
|
||||
extname = ext.split('.')[-1]
|
||||
extinstance = self.get_extension(extname)
|
||||
if extinstance is None:
|
||||
@@ -97,25 +89,16 @@ class ExtensionsPool(object):
|
||||
if extinstance.url is not None else extname
|
||||
result += [
|
||||
(r'^%s/' % (baseurl),
|
||||
include("%s.urls" % extinstance.__module__,
|
||||
namespace=extname))
|
||||
include("{0}.urls".format(ext), namespace=extname))
|
||||
]
|
||||
except ImportError:
|
||||
# No urls for this extension
|
||||
pass
|
||||
if not extinstance.always_active:
|
||||
try:
|
||||
ext = Extension.objects.get(name=extname)
|
||||
if not ext.enabled:
|
||||
continue
|
||||
except Extension.DoesNotExist:
|
||||
continue
|
||||
extinstance.load()
|
||||
return result
|
||||
|
||||
def list_all(self):
|
||||
"""List all defined extensions.
|
||||
"""
|
||||
"""List all defined extensions."""
|
||||
result = []
|
||||
for extname, extdef in self.extensions.iteritems():
|
||||
if not extdef["show"]:
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
A management command to clean unknown extensions from the
|
||||
database.
|
||||
|
||||
"""
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
from modoboa.core.models import Extension
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
"""Command definition."""
|
||||
|
||||
help = "Clean unknowns extensions from the database"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""Entry point."""
|
||||
for extension in Extension.objects.all():
|
||||
fullname = "modoboa.extensions.{0}".format(extension.name)
|
||||
if fullname not in settings.MODOBOA_APPS:
|
||||
extension.delete()
|
||||
connection.close()
|
||||
@@ -1,58 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
A management command to enable an extension.
|
||||
"""
|
||||
from optparse import make_option
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from modoboa.core.models import Extension
|
||||
from . import CloseConnectionMixin
|
||||
|
||||
|
||||
class Command(BaseCommand, CloseConnectionMixin):
|
||||
|
||||
"""Command definition."""
|
||||
|
||||
help = "Enable or disable extensions"
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option(
|
||||
"--action", type=str, default="enable",
|
||||
help="The action to take on extensions ('enable' or 'disable')"
|
||||
),
|
||||
)
|
||||
|
||||
def _change_extension_state(self, name, options):
|
||||
"""Change the state of an extension."""
|
||||
newstate = options["action"] == "enable"
|
||||
update_db = True
|
||||
try:
|
||||
extension = Extension.objects.get(name=name)
|
||||
except Extension.DoesNotExist:
|
||||
extension = Extension.objects.create(name=name, enabled=newstate)
|
||||
update_db = False
|
||||
else:
|
||||
if extension.enabled == newstate:
|
||||
return
|
||||
if newstate:
|
||||
extension.on(update_db)
|
||||
else:
|
||||
extension.off(update_db)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""Entry point."""
|
||||
if "all" in args:
|
||||
for fullname in settings.MODOBOA_APPS:
|
||||
if not fullname.startswith("modoboa.extensions"):
|
||||
continue
|
||||
extname = fullname.replace("modoboa.extensions.", "")
|
||||
self._change_extension_state(extname, options)
|
||||
return
|
||||
|
||||
for extname in args:
|
||||
fullname = "modoboa.extensions.{0}".format(extname)
|
||||
if fullname not in settings.MODOBOA_APPS:
|
||||
continue
|
||||
self._change_extension_state(extname, options)
|
||||
@@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0001_initial'),
|
||||
('contenttypes', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(unique=True, max_length=254)),
|
||||
('first_name', models.CharField(max_length=30, blank=True)),
|
||||
('last_name', models.CharField(max_length=30, blank=True)),
|
||||
('email', models.EmailField(max_length=254, blank=True)),
|
||||
('is_staff', models.BooleanField(default=False)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('is_local', models.BooleanField(default=True)),
|
||||
('password', models.CharField(max_length=256, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
|
||||
('groups', models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Permission', blank=True, help_text='Specific permissions for this user.', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['username'],
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Extension',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=150)),
|
||||
('enabled', models.BooleanField(default=False, help_text='Check to enable this extension', verbose_name='enabled')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Log',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('date_created', models.DateTimeField(auto_now_add=True)),
|
||||
('message', models.CharField(max_length=255)),
|
||||
('level', models.CharField(max_length=15)),
|
||||
('logger', models.CharField(max_length=30)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ObjectAccess',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('object_id', models.PositiveIntegerField()),
|
||||
('is_owner', models.BooleanField(default=False)),
|
||||
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='objectaccess',
|
||||
unique_together=set([('user', 'content_type', 'object_id')]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='Extension',
|
||||
),
|
||||
]
|
||||
@@ -1,11 +1,8 @@
|
||||
"""Core models."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.hashers import make_password, is_password_usable
|
||||
from django.contrib.auth.models import (
|
||||
UserManager, Group, PermissionsMixin
|
||||
@@ -20,13 +17,11 @@ from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
import reversion
|
||||
|
||||
from modoboa.core.extensions import exts_pool
|
||||
from modoboa.core.password_hashers import get_password_hasher
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.exceptions import (
|
||||
PermDeniedException, InternalError, BadRequest, Conflict
|
||||
)
|
||||
from modoboa.lib.sysutils import exec_cmd
|
||||
|
||||
|
||||
try:
|
||||
@@ -438,72 +433,6 @@ class ObjectAccess(models.Model):
|
||||
)
|
||||
|
||||
|
||||
class Extension(models.Model):
|
||||
|
||||
"""A modoboa extension."""
|
||||
|
||||
name = models.CharField(max_length=150)
|
||||
enabled = models.BooleanField(
|
||||
ugettext_lazy('enabled'),
|
||||
help_text=ugettext_lazy("Check to enable this extension")
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Extension, self).__init__(*args, **kwargs)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def __get_ext_instance(self):
|
||||
if not self.name:
|
||||
return None
|
||||
if hasattr(self, "instance") and self.instance:
|
||||
return
|
||||
self.instance = exts_pool.get_extension(self.name)
|
||||
if self.instance:
|
||||
self.__get_ext_dir()
|
||||
|
||||
def __get_ext_dir(self):
|
||||
modname = self.instance.__module__
|
||||
path = os.path.realpath(sys.modules[modname].__file__)
|
||||
self.extdir = os.path.dirname(path)
|
||||
|
||||
def on(self, update_db=True):
|
||||
"""Activate this extension."""
|
||||
if update_db:
|
||||
self.enabled = True
|
||||
self.save()
|
||||
|
||||
self.__get_ext_instance()
|
||||
self.instance.load()
|
||||
self.instance.init()
|
||||
|
||||
if self.instance.needs_media:
|
||||
path = os.path.join(settings.MEDIA_ROOT, self.name)
|
||||
exec_cmd("mkdir %s" % path)
|
||||
|
||||
events.raiseEvent("ExtEnabled", self)
|
||||
|
||||
def off(self, update_db=True):
|
||||
"""Disable this extension."""
|
||||
self.__get_ext_instance()
|
||||
if self.instance is None:
|
||||
return
|
||||
self.instance.destroy()
|
||||
|
||||
if update_db:
|
||||
self.enabled = False
|
||||
self.save()
|
||||
|
||||
if self.instance.needs_media:
|
||||
path = os.path.join(settings.MEDIA_ROOT, self.name)
|
||||
exec_cmd("rm -r %s" % path)
|
||||
|
||||
events.raiseEvent("ExtDisabled", self)
|
||||
|
||||
reversion.register(Extension)
|
||||
|
||||
|
||||
class Log(models.Model):
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
message = models.CharField(max_length=255)
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
{% load i18n %}{% load url from future %}
|
||||
<h2>{% trans "Extensions" %} <small>{% trans "Choose the extension(s) to use" %}</small></h2><hr />
|
||||
<form id="settings_form" method="POST" action="{% url 'core:extension_save' %}">
|
||||
{% csrf_token %}
|
||||
<table id="extensions" class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" id="toggle_extensions_sel"></th>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th>{% trans "Version" %}</th>
|
||||
<th>{% trans "Description" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for extension in extensions %}
|
||||
<tr>
|
||||
<td><input type="checkbox" name="select_{{ extension.name }}" value="{{ extension.name }}"{% if extension.selection %} checked=""{% endif %}></td>
|
||||
<td>{{ extension.label }}</td>
|
||||
<td>{{ extension.version }}</td>
|
||||
<td>{{ extension.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
<a href="#" class="btn btn-primary" id="update" name="update">{% trans 'Save' %}</a>
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
|
||||
<h2>{% trans "Extensions" %} <small>{% trans "The extension(s) you are using" %}</small></h2><hr />
|
||||
<table id="extensions" class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th>{% trans "Version" %}</th>
|
||||
<th>{% trans "Description" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for extension in extensions %}
|
||||
<tr>
|
||||
<td>{{ extension.label }}</td>
|
||||
<td>{{ extension.version }}</td>
|
||||
<td>{{ extension.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -17,8 +17,6 @@ urlpatterns = patterns(
|
||||
name="parameter_save"),
|
||||
url(r'^core/extensions/$', 'modoboa.core.views.admin.viewextensions',
|
||||
name="extension_list"),
|
||||
url(r'^core/extensions/save/$', 'modoboa.core.views.admin.saveextensions',
|
||||
name="extension_save"),
|
||||
url(r'^core/info/$', 'modoboa.core.views.admin.information',
|
||||
name="information"),
|
||||
url(r'^core/logs/$', 'modoboa.core.views.admin.logs', name="log_list"),
|
||||
|
||||
@@ -8,7 +8,7 @@ from django.shortcuts import render
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from modoboa.core.models import Extension, Log
|
||||
from modoboa.core.models import Log
|
||||
from modoboa.core.utils import new_version_available
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.listing import get_sort_order, get_listing_page
|
||||
@@ -58,44 +58,12 @@ def viewextensions(request, tplname='core/extensions.html'):
|
||||
from modoboa.core.extensions import exts_pool
|
||||
|
||||
exts = exts_pool.list_all()
|
||||
for ext in exts:
|
||||
try:
|
||||
dbext = Extension.objects.get(name=ext["id"])
|
||||
ext["selection"] = dbext.enabled
|
||||
except Extension.DoesNotExist:
|
||||
dbext = Extension()
|
||||
dbext.name = ext["id"]
|
||||
dbext.enabled = False
|
||||
dbext.save()
|
||||
ext["selection"] = False
|
||||
|
||||
return render_to_json_response({
|
||||
"callback": "extensions",
|
||||
"content": _render_to_string(request, tplname, {"extensions": exts})
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def saveextensions(request):
|
||||
"""Enable of disable extension(s)."""
|
||||
actived_exts = Extension.objects.filter(enabled=True)
|
||||
found = []
|
||||
for k in request.POST.keys():
|
||||
if k.startswith("select_"):
|
||||
parts = k.split("_", 1)
|
||||
dbext = Extension.objects.get(name=parts[1])
|
||||
if dbext not in actived_exts:
|
||||
dbext.on()
|
||||
else:
|
||||
found += [dbext]
|
||||
for ext in actived_exts:
|
||||
if ext not in found:
|
||||
ext.off()
|
||||
|
||||
return render_to_json_response(_("Modifications applied."))
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def information(request, tplname="core/information.html"):
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
# coding: utf-8
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.extensions.admin.models import (
|
||||
Domain, DomainAlias, Mailbox, Alias
|
||||
)
|
||||
from modoboa.lib import parameters, events
|
||||
from modoboa.lib.email_utils import split_mailbox
|
||||
from modoboa.lib.exceptions import PermDeniedException, BadRequest, Conflict
|
||||
|
||||
|
||||
admin_events = [
|
||||
"DomainCreated",
|
||||
"DomainModified",
|
||||
"DomainDeleted",
|
||||
"DomainOwnershipRemoved",
|
||||
"ExtraDomainEntries",
|
||||
"ExtraDomainMenuEntries",
|
||||
"ExtraDomainFilters",
|
||||
"GetDomainActions",
|
||||
"GetDomainModifyLink",
|
||||
"CheckDomainName",
|
||||
|
||||
"DomainAliasCreated",
|
||||
"DomainAliasDeleted",
|
||||
|
||||
"MailboxCreated",
|
||||
"MailboxDeleted",
|
||||
"MailboxModified",
|
||||
|
||||
"MailboxAliasCreated",
|
||||
"MailboxAliasDeleted",
|
||||
|
||||
"ExtraDomainForm",
|
||||
"FillDomainInstances",
|
||||
|
||||
"ExtraAccountForm",
|
||||
"CheckExtraAccountForm",
|
||||
"FillAccountInstances",
|
||||
|
||||
"ExtraDomainImportHelp",
|
||||
"ImportObject"
|
||||
]
|
||||
|
||||
|
||||
class AdminConsole(ModoExtension):
|
||||
name = "admin"
|
||||
label = ugettext_lazy("Administration console")
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Web based console to manage domains, accounts and aliases"
|
||||
)
|
||||
always_active = True
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.admin.app_settings import AdminParametersForm
|
||||
parameters.register(
|
||||
AdminParametersForm, ugettext_lazy("Administration"))
|
||||
events.declare(admin_events)
|
||||
|
||||
def destroy(self):
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(AdminConsole, show=False)
|
||||
|
||||
|
||||
@events.observe("ExtraUprefsRoutes")
|
||||
def extra_routes():
|
||||
from django.conf.urls import url
|
||||
return [
|
||||
url(r'^user/forward/',
|
||||
'modoboa.extensions.admin.views.user.forward',
|
||||
name="user_forward"),
|
||||
]
|
||||
|
||||
|
||||
@events.observe("AdminMenuDisplay")
|
||||
def admin_menu(target, user):
|
||||
if target != "top_menu":
|
||||
return []
|
||||
entries = []
|
||||
if user.has_perm("admin.view_domains"):
|
||||
entries += [
|
||||
{"name": "domains",
|
||||
"url": reverse("admin:domain_list"),
|
||||
"label": _("Domains")}
|
||||
]
|
||||
if user.has_perm("core.add_user") or user.has_perm("admin.add_alias"):
|
||||
entries += [
|
||||
{"name": "identities",
|
||||
"url": reverse("admin:identity_list"),
|
||||
"label": _("Identities")},
|
||||
]
|
||||
return entries
|
||||
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def user_menu(target, user):
|
||||
if target != "uprefs_menu":
|
||||
return []
|
||||
if not user.mailbox_set.count():
|
||||
return []
|
||||
return [
|
||||
{"name": "forward",
|
||||
"class": "ajaxnav",
|
||||
"url": "forward/",
|
||||
"label": ugettext_lazy("Forward")}
|
||||
]
|
||||
|
||||
|
||||
@events.observe("RoleChanged")
|
||||
def grant_access_to_all_objects(user, role):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from modoboa.lib.permissions import grant_access_to_objects
|
||||
from modoboa.core.models import User
|
||||
|
||||
if role != "SuperAdmins":
|
||||
return
|
||||
grant_access_to_objects(
|
||||
user, User.objects.all(),
|
||||
ContentType.objects.get_for_model(User)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Domain.objects.all(),
|
||||
ContentType.objects.get_for_model(Domain)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, DomainAlias.objects.all(),
|
||||
ContentType.objects.get_for_model(DomainAlias)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Mailbox.objects.all(),
|
||||
ContentType.objects.get_for_model(Mailbox)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Alias.objects.all(),
|
||||
ContentType.objects.get_for_model(Alias)
|
||||
)
|
||||
|
||||
|
||||
@events.observe("AccountExported")
|
||||
def export_admin_domains(admin):
|
||||
result = [admin.mailbox_set.all()[0].quota] \
|
||||
if admin.mailbox_set.count() else ['']
|
||||
if admin.group != "DomainAdmins":
|
||||
return result
|
||||
return result + [dom.name for dom in Domain.objects.get_for_admin(admin)]
|
||||
|
||||
|
||||
@events.observe("AccountImported")
|
||||
def import_account_mailbox(user, account, row):
|
||||
"""Handle extra fields when an account is imported.
|
||||
|
||||
Expected fields:
|
||||
|
||||
email address; quota; [domain; ...]
|
||||
|
||||
:param User user: user importing the account
|
||||
:param User account: account being imported
|
||||
:param list rom: list of fields (strings)
|
||||
"""
|
||||
account.email = row[0].strip()
|
||||
if account.email:
|
||||
account.save()
|
||||
mailbox, domname = split_mailbox(account.email)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
raise BadRequest(
|
||||
_("Account import failed (%s): domain does not exist"
|
||||
% account.username)
|
||||
)
|
||||
if not user.can_access(domain):
|
||||
raise PermDeniedException
|
||||
try:
|
||||
mb = Mailbox.objects.get(address=mailbox, domain=domain)
|
||||
except Mailbox.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
raise Conflict(_("Mailbox %s already exists" % account.email))
|
||||
if len(row) == 1:
|
||||
quota = None
|
||||
else:
|
||||
try:
|
||||
quota = int(row[1].strip())
|
||||
except ValueError:
|
||||
raise BadRequest(
|
||||
_("Account import failed (%s): wrong quota value"
|
||||
% account.username)
|
||||
)
|
||||
use_domain_quota = True if not quota else False
|
||||
mb = Mailbox(address=mailbox, domain=domain,
|
||||
user=account, use_domain_quota=use_domain_quota)
|
||||
mb.set_quota(quota, override_rules=user.has_perm("admin.change_domain"))
|
||||
mb.save(creator=user)
|
||||
if account.group == "DomainAdmins":
|
||||
for domname in row[2:]:
|
||||
try:
|
||||
dom = Domain.objects.get(name=domname.strip())
|
||||
except Domain.DoesNotExist:
|
||||
continue
|
||||
dom.add_admin(account)
|
||||
|
||||
|
||||
@events.observe("AccountAutoCreated")
|
||||
def account_auto_created(user):
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.lib import check_if_domain_exists
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
|
||||
if parameters.get_admin("AUTO_CREATE_DOMAIN_AND_MAILBOX") == "no":
|
||||
return
|
||||
localpart, domname = split_mailbox(user.username)
|
||||
if user.group != 'SimpleUsers' and domname is None:
|
||||
return
|
||||
sadmins = User.objects.filter(is_superuser=True)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
label = check_if_domain_exists(
|
||||
domname, [(DomainAlias, _('domain alias'))])
|
||||
if label is not None:
|
||||
return
|
||||
domain = Domain(name=domname, enabled=True, quota=0)
|
||||
domain.save(creator=sadmins[0])
|
||||
for su in sadmins[1:]:
|
||||
grant_access_to_object(su, domain)
|
||||
try:
|
||||
mb = Mailbox.objects.get(domain=domain, address=localpart)
|
||||
except Mailbox.DoesNotExist:
|
||||
mb = Mailbox(
|
||||
address=localpart, domain=domain, user=user, use_domain_quota=True
|
||||
)
|
||||
mb.set_quota(override_rules=True)
|
||||
mb.save(creator=sadmins[0])
|
||||
for su in sadmins[1:]:
|
||||
grant_access_to_object(su, mb)
|
||||
|
||||
|
||||
@events.observe("UserLogin")
|
||||
def user_logged_in(request, username, password):
|
||||
from modoboa.lib.cryptutils import encrypt
|
||||
|
||||
if request.user.mailbox_set.count():
|
||||
request.session["password"] = encrypt(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]
|
||||
if not byuser.can_access(mb):
|
||||
raise PermDeniedException
|
||||
keep_mb_dir = kwargs.get("keep_mb_dir", True)
|
||||
mb.delete(keepdir=keep_mb_dir)
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Alias',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('address', models.CharField(help_text="The alias address (without the domain part). For a 'catch-all' address, just enter an * character.", max_length=254, verbose_name='address')),
|
||||
('extmboxes', models.TextField(blank=True)),
|
||||
('enabled', models.BooleanField(default=True, help_text='Check to activate this alias', verbose_name='enabled')),
|
||||
('aliases', models.ManyToManyField(help_text='The aliases this alias points to', to='admin.Alias')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['domain__name', 'address'],
|
||||
'permissions': (('view_aliases', 'View aliases'),),
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Domain',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(help_text='The domain name', unique=True, max_length=100, verbose_name='name')),
|
||||
('quota', models.IntegerField()),
|
||||
('enabled', models.BooleanField(default=True, help_text='Check to activate this domain', verbose_name='enabled')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
'permissions': (('view_domain', 'View domain'), ('view_domains', 'View domains')),
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='DomainAlias',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(help_text='The alias name', unique=True, max_length=100, verbose_name='name')),
|
||||
('enabled', models.BooleanField(default=True, help_text='Check to activate this alias', verbose_name='enabled')),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_domaliases', 'View domain aliases'),),
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Mailbox',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('address', models.CharField(help_text='Mailbox address (without the @domain.tld part)', max_length=252, verbose_name='address')),
|
||||
('quota', models.PositiveIntegerField()),
|
||||
('use_domain_quota', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_mailboxes', 'View mailboxes'),),
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MailboxOperation',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('type', models.CharField(max_length=20, choices=[(b'rename', b'rename'), (b'delete', b'delete')])),
|
||||
('argument', models.TextField()),
|
||||
('mailbox', models.ForeignKey(blank=True, to='admin.Mailbox', null=True)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ObjectDates',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('creation', models.DateTimeField(auto_now_add=True)),
|
||||
('last_modification', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Quota',
|
||||
fields=[
|
||||
('username', models.EmailField(max_length=254, serialize=False, primary_key=True)),
|
||||
('bytes', models.BigIntegerField(default=0)),
|
||||
('messages', models.IntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mailbox',
|
||||
name='dates',
|
||||
field=models.ForeignKey(to='admin.ObjectDates'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mailbox',
|
||||
name='domain',
|
||||
field=models.ForeignKey(to='admin.Domain'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mailbox',
|
||||
name='user',
|
||||
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domainalias',
|
||||
name='dates',
|
||||
field=models.ForeignKey(to='admin.ObjectDates'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domainalias',
|
||||
name='target',
|
||||
field=models.ForeignKey(verbose_name='target', to='admin.Domain', help_text='The domain this alias points to'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domain',
|
||||
name='dates',
|
||||
field=models.ForeignKey(to='admin.ObjectDates'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alias',
|
||||
name='dates',
|
||||
field=models.ForeignKey(to='admin.ObjectDates'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alias',
|
||||
name='domain',
|
||||
field=models.ForeignKey(to='admin.Domain'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alias',
|
||||
name='mboxes',
|
||||
field=models.ManyToManyField(help_text='The mailboxes this alias points to', to='admin.Mailbox', verbose_name='mailboxes'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='alias',
|
||||
unique_together=set([('address', 'domain')]),
|
||||
),
|
||||
]
|
||||
@@ -38,7 +38,8 @@ class Alias(AdminObject):
|
||||
extmboxes = models.TextField(blank=True)
|
||||
enabled = models.BooleanField(
|
||||
ugettext_lazy('enabled'),
|
||||
help_text=ugettext_lazy("Check to activate this alias")
|
||||
help_text=ugettext_lazy("Check to activate this alias"),
|
||||
default=True
|
||||
)
|
||||
_objectname = 'MailboxAlias'
|
||||
|
||||
|
||||
@@ -28,14 +28,15 @@ class DomainManager(Manager):
|
||||
|
||||
class Domain(AdminObject):
|
||||
|
||||
"""Mail domain.
|
||||
"""
|
||||
"""Mail domain."""
|
||||
|
||||
name = models.CharField(ugettext_lazy('name'), max_length=100, unique=True,
|
||||
help_text=ugettext_lazy("The domain name"))
|
||||
quota = models.IntegerField()
|
||||
enabled = models.BooleanField(
|
||||
ugettext_lazy('enabled'),
|
||||
help_text=ugettext_lazy("Check to activate this domain")
|
||||
help_text=ugettext_lazy("Check to activate this domain"),
|
||||
default=True
|
||||
)
|
||||
owners = generic.GenericRelation(ObjectAccess)
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ from modoboa.lib.exceptions import BadRequest, Conflict
|
||||
|
||||
|
||||
class DomainAlias(AdminObject):
|
||||
|
||||
"""Domain aliases."""
|
||||
|
||||
name = models.CharField(ugettext_lazy("name"), max_length=100, unique=True,
|
||||
help_text=ugettext_lazy("The alias name"))
|
||||
target = models.ForeignKey(
|
||||
@@ -19,7 +22,8 @@ class DomainAlias(AdminObject):
|
||||
)
|
||||
enabled = models.BooleanField(
|
||||
ugettext_lazy('enabled'),
|
||||
help_text=ugettext_lazy("Check to activate this alias")
|
||||
help_text=ugettext_lazy("Check to activate this alias"),
|
||||
default=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
"""Registration with Modoboa takes place here."""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.extensions.admin.models import (
|
||||
Domain, DomainAlias, Mailbox, Alias
|
||||
)
|
||||
from modoboa.lib import parameters, events
|
||||
from modoboa.lib.email_utils import split_mailbox
|
||||
from modoboa.lib.exceptions import PermDeniedException, BadRequest, Conflict
|
||||
|
||||
|
||||
ADMIN_EVENTS = [
|
||||
"DomainCreated",
|
||||
"DomainModified",
|
||||
"DomainDeleted",
|
||||
"DomainOwnershipRemoved",
|
||||
"ExtraDomainEntries",
|
||||
"ExtraDomainMenuEntries",
|
||||
"ExtraDomainFilters",
|
||||
"GetDomainActions",
|
||||
"GetDomainModifyLink",
|
||||
"CheckDomainName",
|
||||
|
||||
"DomainAliasCreated",
|
||||
"DomainAliasDeleted",
|
||||
|
||||
"MailboxCreated",
|
||||
"MailboxDeleted",
|
||||
"MailboxModified",
|
||||
|
||||
"MailboxAliasCreated",
|
||||
"MailboxAliasDeleted",
|
||||
|
||||
"ExtraDomainForm",
|
||||
"FillDomainInstances",
|
||||
|
||||
"ExtraAccountForm",
|
||||
"CheckExtraAccountForm",
|
||||
"FillAccountInstances",
|
||||
|
||||
"ExtraDomainImportHelp",
|
||||
"ImportObject"
|
||||
]
|
||||
|
||||
|
||||
class AdminConsole(ModoExtension):
|
||||
name = "admin"
|
||||
label = ugettext_lazy("Administration console")
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Web based console to manage domains, accounts and aliases"
|
||||
)
|
||||
always_active = True
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.admin.app_settings import AdminParametersForm
|
||||
parameters.register(
|
||||
AdminParametersForm, ugettext_lazy("Administration"))
|
||||
events.declare(ADMIN_EVENTS)
|
||||
|
||||
exts_pool.register_extension(AdminConsole)
|
||||
|
||||
|
||||
@events.observe("ExtraUprefsRoutes")
|
||||
def extra_routes():
|
||||
from django.conf.urls import url
|
||||
return [
|
||||
url(r'^user/forward/',
|
||||
'modoboa.extensions.admin.views.user.forward',
|
||||
name="user_forward"),
|
||||
]
|
||||
|
||||
|
||||
@events.observe("AdminMenuDisplay")
|
||||
def admin_menu(target, user):
|
||||
if target != "top_menu":
|
||||
return []
|
||||
entries = []
|
||||
if user.has_perm("admin.view_domains"):
|
||||
entries += [
|
||||
{"name": "domains",
|
||||
"url": reverse("admin:domain_list"),
|
||||
"label": _("Domains")}
|
||||
]
|
||||
if user.has_perm("core.add_user") or user.has_perm("admin.add_alias"):
|
||||
entries += [
|
||||
{"name": "identities",
|
||||
"url": reverse("admin:identity_list"),
|
||||
"label": _("Identities")},
|
||||
]
|
||||
return entries
|
||||
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def user_menu(target, user):
|
||||
if target != "uprefs_menu":
|
||||
return []
|
||||
if not user.mailbox_set.count():
|
||||
return []
|
||||
return [
|
||||
{"name": "forward",
|
||||
"class": "ajaxnav",
|
||||
"url": "forward/",
|
||||
"label": ugettext_lazy("Forward")}
|
||||
]
|
||||
|
||||
|
||||
@events.observe("RoleChanged")
|
||||
def grant_access_to_all_objects(user, role):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from modoboa.lib.permissions import grant_access_to_objects
|
||||
from modoboa.core.models import User
|
||||
|
||||
if role != "SuperAdmins":
|
||||
return
|
||||
grant_access_to_objects(
|
||||
user, User.objects.all(),
|
||||
ContentType.objects.get_for_model(User)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Domain.objects.all(),
|
||||
ContentType.objects.get_for_model(Domain)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, DomainAlias.objects.all(),
|
||||
ContentType.objects.get_for_model(DomainAlias)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Mailbox.objects.all(),
|
||||
ContentType.objects.get_for_model(Mailbox)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Alias.objects.all(),
|
||||
ContentType.objects.get_for_model(Alias)
|
||||
)
|
||||
|
||||
|
||||
@events.observe("AccountExported")
|
||||
def export_admin_domains(admin):
|
||||
result = [admin.mailbox_set.all()[0].quota] \
|
||||
if admin.mailbox_set.count() else ['']
|
||||
if admin.group != "DomainAdmins":
|
||||
return result
|
||||
return result + [dom.name for dom in Domain.objects.get_for_admin(admin)]
|
||||
|
||||
|
||||
@events.observe("AccountImported")
|
||||
def import_account_mailbox(user, account, row):
|
||||
"""Handle extra fields when an account is imported.
|
||||
|
||||
Expected fields:
|
||||
|
||||
email address; quota; [domain; ...]
|
||||
|
||||
:param User user: user importing the account
|
||||
:param User account: account being imported
|
||||
:param list rom: list of fields (strings)
|
||||
"""
|
||||
account.email = row[0].strip()
|
||||
if account.email:
|
||||
account.save()
|
||||
mailbox, domname = split_mailbox(account.email)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
raise BadRequest(
|
||||
_("Account import failed (%s): domain does not exist"
|
||||
% account.username)
|
||||
)
|
||||
if not user.can_access(domain):
|
||||
raise PermDeniedException
|
||||
try:
|
||||
mb = Mailbox.objects.get(address=mailbox, domain=domain)
|
||||
except Mailbox.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
raise Conflict(_("Mailbox %s already exists" % account.email))
|
||||
if len(row) == 1:
|
||||
quota = None
|
||||
else:
|
||||
try:
|
||||
quota = int(row[1].strip())
|
||||
except ValueError:
|
||||
raise BadRequest(
|
||||
_("Account import failed (%s): wrong quota value"
|
||||
% account.username)
|
||||
)
|
||||
use_domain_quota = True if not quota else False
|
||||
mb = Mailbox(address=mailbox, domain=domain,
|
||||
user=account, use_domain_quota=use_domain_quota)
|
||||
mb.set_quota(quota, override_rules=user.has_perm("admin.change_domain"))
|
||||
mb.save(creator=user)
|
||||
if account.group == "DomainAdmins":
|
||||
for domname in row[2:]:
|
||||
try:
|
||||
dom = Domain.objects.get(name=domname.strip())
|
||||
except Domain.DoesNotExist:
|
||||
continue
|
||||
dom.add_admin(account)
|
||||
|
||||
|
||||
@events.observe("AccountAutoCreated")
|
||||
def account_auto_created(user):
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.lib import check_if_domain_exists
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
|
||||
if parameters.get_admin("AUTO_CREATE_DOMAIN_AND_MAILBOX") == "no":
|
||||
return
|
||||
localpart, domname = split_mailbox(user.username)
|
||||
if user.group != 'SimpleUsers' and domname is None:
|
||||
return
|
||||
sadmins = User.objects.filter(is_superuser=True)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
label = check_if_domain_exists(
|
||||
domname, [(DomainAlias, _('domain alias'))])
|
||||
if label is not None:
|
||||
return
|
||||
domain = Domain(name=domname, enabled=True, quota=0)
|
||||
domain.save(creator=sadmins[0])
|
||||
for su in sadmins[1:]:
|
||||
grant_access_to_object(su, domain)
|
||||
try:
|
||||
mb = Mailbox.objects.get(domain=domain, address=localpart)
|
||||
except Mailbox.DoesNotExist:
|
||||
mb = Mailbox(
|
||||
address=localpart, domain=domain, user=user, use_domain_quota=True
|
||||
)
|
||||
mb.set_quota(override_rules=True)
|
||||
mb.save(creator=sadmins[0])
|
||||
for su in sadmins[1:]:
|
||||
grant_access_to_object(su, mb)
|
||||
|
||||
|
||||
@events.observe("UserLogin")
|
||||
def user_logged_in(request, username, password):
|
||||
from modoboa.lib.cryptutils import encrypt
|
||||
|
||||
if request.user.mailbox_set.count():
|
||||
request.session["password"] = encrypt(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]
|
||||
if not byuser.can_access(mb):
|
||||
raise PermDeniedException
|
||||
keep_mb_dir = kwargs.get("keep_mb_dir", True)
|
||||
mb.delete(keepdir=keep_mb_dir)
|
||||
@@ -1,61 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
Amavis management frontend.
|
||||
|
||||
Provides:
|
||||
|
||||
* SQL quarantine management
|
||||
* Per-domain settings
|
||||
|
||||
"""
|
||||
import sys
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
|
||||
class Amavis(ModoExtension):
|
||||
name = "amavis"
|
||||
label = "Amavis frontend"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple amavis management frontend")
|
||||
url = "quarantine"
|
||||
available_for_topredirection = True
|
||||
|
||||
def init(self):
|
||||
"""Init function
|
||||
|
||||
Only run once, when the extension is enabled. We create records
|
||||
for existing domains to let Amavis consider them local.
|
||||
"""
|
||||
from modoboa.extensions.admin.models import Domain
|
||||
from modoboa.extensions.amavis.models import Users
|
||||
from modoboa.extensions.amavis.lib import (
|
||||
create_user_and_policy, create_user_and_use_policy
|
||||
)
|
||||
|
||||
for dom in Domain.objects.all():
|
||||
try:
|
||||
Users.objects.get(email="@%s" % dom.name)
|
||||
except Users.DoesNotExist:
|
||||
create_user_and_policy(dom.name)
|
||||
for domalias in dom.domainalias_set.all():
|
||||
try:
|
||||
Users.objects.get(email='@%s' % domalias.name)
|
||||
except Users.DoesNotExist:
|
||||
create_user_and_use_policy(domalias.name, dom.name)
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
|
||||
parameters.register(ParametersForm, "Amavis")
|
||||
parameters.register(UserSettings, ugettext_lazy("Quarantine"))
|
||||
from modoboa.extensions.amavis import general_callbacks
|
||||
if 'modoboa.extensions.amavis.general_callbacks' in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(Amavis)
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Maddr',
|
||||
fields=[
|
||||
('partition_tag', models.IntegerField(unique=True, null=True, blank=True)),
|
||||
('id', models.BigIntegerField(serialize=False, primary_key=True)),
|
||||
('email', models.CharField(unique=True, max_length=255)),
|
||||
('domain', models.CharField(max_length=765)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'maddr',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Mailaddr',
|
||||
fields=[
|
||||
('id', models.IntegerField(serialize=False, primary_key=True)),
|
||||
('priority', models.IntegerField()),
|
||||
('email', models.CharField(unique=True, max_length=255)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'mailaddr',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Msgs',
|
||||
fields=[
|
||||
('partition_tag', models.IntegerField(null=True, blank=True)),
|
||||
('mail_id', models.CharField(max_length=12, serialize=False, primary_key=True)),
|
||||
('secret_id', models.CharField(max_length=12, blank=True)),
|
||||
('am_id', models.CharField(max_length=60)),
|
||||
('time_num', models.IntegerField()),
|
||||
('time_iso', models.CharField(max_length=48)),
|
||||
('policy', models.CharField(max_length=765, blank=True)),
|
||||
('client_addr', models.CharField(max_length=765, blank=True)),
|
||||
('size', models.IntegerField()),
|
||||
('originating', models.CharField(max_length=3)),
|
||||
('content', models.CharField(max_length=1, blank=True)),
|
||||
('quar_type', models.CharField(max_length=1, blank=True)),
|
||||
('quar_loc', models.CharField(max_length=255, blank=True)),
|
||||
('dsn_sent', models.CharField(max_length=3, blank=True)),
|
||||
('spam_level', models.FloatField(null=True, blank=True)),
|
||||
('message_id', models.CharField(max_length=765, blank=True)),
|
||||
('from_addr', models.CharField(max_length=765, blank=True)),
|
||||
('subject', models.CharField(max_length=765, blank=True)),
|
||||
('host', models.CharField(max_length=765)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'msgs',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Msgrcpt',
|
||||
fields=[
|
||||
('partition_tag', models.IntegerField(null=True, blank=True)),
|
||||
('mail', models.ForeignKey(primary_key=True, serialize=False, to='amavis.Msgs')),
|
||||
('rseqnum', models.IntegerField(default=0)),
|
||||
('is_local', models.CharField(max_length=3)),
|
||||
('content', models.CharField(max_length=3)),
|
||||
('ds', models.CharField(max_length=3)),
|
||||
('rs', models.CharField(max_length=3)),
|
||||
('bl', models.CharField(max_length=3, blank=True)),
|
||||
('wl', models.CharField(max_length=3, blank=True)),
|
||||
('bspam_level', models.FloatField(null=True, blank=True)),
|
||||
('smtp_resp', models.CharField(max_length=765, blank=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'msgrcpt',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Policy',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('policy_name', models.CharField(max_length=32, blank=True)),
|
||||
('virus_lover', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('spam_lover', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('unchecked_lover', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('banned_files_lover', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('bad_header_lover', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('bypass_virus_checks', models.CharField(default=b'', choices=[(b'N', 'yes'), (b'Y', 'no'), (b'', 'default')], max_length=3, help_text="Bypass virus checks or not. Choose 'default' to use global settings.", null=True, verbose_name='Virus filter')),
|
||||
('bypass_spam_checks', models.CharField(default=b'', choices=[(b'N', 'yes'), (b'Y', 'no'), (b'', 'default')], max_length=3, help_text="Bypass spam checks or not. Choose 'default' to use global settings.", null=True, verbose_name='Spam filter')),
|
||||
('bypass_banned_checks', models.CharField(default=b'', choices=[(b'N', 'yes'), (b'Y', 'no'), (b'', 'default')], max_length=3, help_text="Bypass banned checks or not. Choose 'default' to use global settings.", null=True, verbose_name='Banned filter')),
|
||||
('bypass_header_checks', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('virus_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('spam_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('banned_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('unchecked_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('bad_header_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('clean_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('archive_quarantine_to', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('spam_tag_level', models.FloatField(null=True, blank=True)),
|
||||
('spam_tag2_level', models.FloatField(null=True, blank=True)),
|
||||
('spam_tag3_level', models.FloatField(null=True, blank=True)),
|
||||
('spam_kill_level', models.FloatField(null=True, blank=True)),
|
||||
('spam_dsn_cutoff_level', models.FloatField(null=True, blank=True)),
|
||||
('spam_quarantine_cutoff_level', models.FloatField(null=True, blank=True)),
|
||||
('addr_extension_virus', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('addr_extension_spam', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('addr_extension_banned', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('addr_extension_bad_header', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('warnvirusrecip', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('warnbannedrecip', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('warnbadhrecip', models.CharField(max_length=3, null=True, blank=True)),
|
||||
('newvirus_admin', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('virus_admin', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('banned_admin', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('bad_header_admin', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('spam_admin', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('spam_subject_tag', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('spam_subject_tag2', models.CharField(default=None, max_length=192, blank=True, help_text="Modify spam subject using the specified text. Choose 'default' to use global settings.", null=True, verbose_name='Spam marker')),
|
||||
('spam_subject_tag3', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('message_size_limit', models.IntegerField(null=True, blank=True)),
|
||||
('banned_rulenames', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('disclaimer_options', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('forward_method', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('sa_userconf', models.CharField(max_length=192, null=True, blank=True)),
|
||||
('sa_username', models.CharField(max_length=192, null=True, blank=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'policy',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Quarantine',
|
||||
fields=[
|
||||
('partition_tag', models.IntegerField(null=True, blank=True)),
|
||||
('mail', models.ForeignKey(primary_key=True, serialize=False, to='amavis.Msgs')),
|
||||
('chunk_ind', models.IntegerField()),
|
||||
('mail_text', models.TextField()),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-mail__time_num'],
|
||||
'db_table': 'quarantine',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Users',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, primary_key=True)),
|
||||
('priority', models.IntegerField()),
|
||||
('email', models.CharField(unique=True, max_length=255)),
|
||||
('fullname', models.CharField(max_length=765, blank=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'users',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Wblist',
|
||||
fields=[
|
||||
('rid', models.IntegerField(serialize=False, primary_key=True)),
|
||||
('sid', models.IntegerField(primary_key=True)),
|
||||
('wb', models.CharField(max_length=30)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'wblist',
|
||||
'managed': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
from modoboa.core.extensions import exts_pool
|
||||
|
||||
|
||||
def load_initial_data(apps, schema_editor):
|
||||
"""Load initial data."""
|
||||
Domain = apps.get_model("admin", "Domain")
|
||||
Policy = apps.get_model("amavis", "Policy")
|
||||
Users = apps.get_model("amavis", "Users")
|
||||
|
||||
for dom in Domain.objects.all():
|
||||
name = "@{0}".format(dom.name)
|
||||
policy, created = Policy.objects.get_or_create(policy_name=name[:32])
|
||||
Users.objects.get_or_create(
|
||||
email=name, fullname=name, priority=7, policy=policy)
|
||||
for dalias in dom.domainalias_set.all():
|
||||
name = "@{0}".format(dalias.name)
|
||||
Users.objects.get_or_create(
|
||||
email=name, fullname=name, priority=7, policy=policy)
|
||||
|
||||
if not exts_pool.is_extension_installed(
|
||||
"modoboa.extensions.postfix_relay_domains"):
|
||||
return
|
||||
|
||||
RelayDomain = apps.get_model("postfix_relay_domains", "RelayDomain")
|
||||
|
||||
for dom in RelayDomain.objects.all():
|
||||
name = "@{0}".format(dom.name)
|
||||
policy, created = Policy.objects.get_or_create(policy_name=name[:32])
|
||||
Users.objects.get_or_create(
|
||||
email=name, fullname=name, priority=7, policy=policy)
|
||||
for rdalias in dom.relaydomainalias_set.all():
|
||||
name = "@{0}".format(rdalias.name)
|
||||
Users.objects.get_or_create(
|
||||
email=name, fullname=name, priority=7, policy=policy)
|
||||
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('amavis', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(load_initial_data)
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
Amavis management frontend.
|
||||
|
||||
Provides:
|
||||
|
||||
* SQL quarantine management
|
||||
* Per-domain settings
|
||||
|
||||
"""
|
||||
import sys
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
class Amavis(ModoExtension):
|
||||
name = "amavis"
|
||||
label = "Amavis frontend"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple amavis management frontend")
|
||||
url = "quarantine"
|
||||
available_for_topredirection = True
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
|
||||
parameters.register(ParametersForm, "Amavis")
|
||||
parameters.register(UserSettings, ugettext_lazy("Quarantine"))
|
||||
from modoboa.extensions.amavis import general_callbacks
|
||||
|
||||
exts_pool.register_extension(Amavis)
|
||||
@@ -1,70 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
The *limits* extension
|
||||
----------------------
|
||||
"""
|
||||
import sys
|
||||
from django.contrib.auth.models import Permission, Group
|
||||
from django.db import IntegrityError
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.permissions import add_permissions_to_group
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
levents = [
|
||||
'GetExtraLimitTemplates'
|
||||
]
|
||||
|
||||
|
||||
class Limits(ModoExtension):
|
||||
name = "limits"
|
||||
label = "Limits"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Per administrator resources to limit the number of objects "
|
||||
"they can create"
|
||||
)
|
||||
|
||||
def init(self):
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.models import Domain
|
||||
|
||||
ct = ContentType.objects.get(app_label="admin", model="domain")
|
||||
dagrp = Group.objects.get(name="DomainAdmins")
|
||||
|
||||
grp = Group(name="Resellers")
|
||||
grp.save()
|
||||
grp.permissions.add(*dagrp.permissions.all())
|
||||
|
||||
ct = ContentType.objects.get_for_model(Domain)
|
||||
add_permissions_to_group(
|
||||
"Resellers", [("admin", "domain", "view_domains"),
|
||||
("admin", "domain", "add_domain"),
|
||||
("admin", "domain", "change_domain"),
|
||||
("admin", "domain", "delete_domain")]
|
||||
)
|
||||
|
||||
for user in User.objects.filter(groups__name='DomainAdmins'):
|
||||
try:
|
||||
controls.create_pool(user)
|
||||
except IntegrityError:
|
||||
pass
|
||||
|
||||
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)
|
||||
from modoboa.extensions.limits import general_callbacks
|
||||
if 'modoboa.extensions.limits.general_callbacks' in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
Group.objects.get(name="Resellers").delete()
|
||||
|
||||
exts_pool.register_extension(Limits)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Limit',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('curvalue', models.IntegerField(default=0)),
|
||||
('maxvalue', models.IntegerField(default=-2)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LimitsPool',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='limit',
|
||||
name='pool',
|
||||
field=models.ForeignKey(to='limits.LimitsPool'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='limit',
|
||||
unique_together=set([('name', 'pool')]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import IntegrityError, models, migrations
|
||||
|
||||
from modoboa.lib.migration_tools import add_permissions_to_group
|
||||
from modoboa.extensions.limits import controls
|
||||
|
||||
|
||||
def load_initial_data(apps, schema_editor):
|
||||
"""Load initial data."""
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
Group = apps.get_model("auth", "Group")
|
||||
User = apps.get_model("core", "User")
|
||||
Domain = apps.get_model("admin", "Domain")
|
||||
|
||||
ct = ContentType.objects.get(app_label="admin", model="domain")
|
||||
dagrp = Group.objects.get(name="DomainAdmins")
|
||||
|
||||
grp = Group(name="Resellers")
|
||||
grp.save()
|
||||
grp.permissions.add(*dagrp.permissions.all())
|
||||
|
||||
ct = ContentType.objects.get_for_model(Domain)
|
||||
add_permissions_to_group(
|
||||
apps, "Resellers", [("admin", "domain", "view_domains"),
|
||||
("admin", "domain", "add_domain"),
|
||||
("admin", "domain", "change_domain"),
|
||||
("admin", "domain", "delete_domain")]
|
||||
)
|
||||
|
||||
for user in User.objects.filter(groups__name='DomainAdmins'):
|
||||
try:
|
||||
controls.create_pool(user)
|
||||
except IntegrityError:
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('limits', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(load_initial_data)
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
The *limits* extension
|
||||
----------------------
|
||||
"""
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import events, parameters
|
||||
|
||||
|
||||
EVENTS = [
|
||||
'GetExtraLimitTemplates'
|
||||
]
|
||||
|
||||
|
||||
class Limits(ModoExtension):
|
||||
name = "limits"
|
||||
label = "Limits"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Per administrator resources to limit the number of objects "
|
||||
"they can create"
|
||||
)
|
||||
|
||||
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(EVENTS)
|
||||
from modoboa.extensions.limits import general_callbacks
|
||||
|
||||
exts_pool.register_extension(Limits)
|
||||
@@ -1,77 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
Postfix auto-replies plugin.
|
||||
|
||||
This module provides a way to integrate Modoboa auto-reply
|
||||
functionality into Postfix.
|
||||
|
||||
"""
|
||||
import sys
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.extensions.postfix_autoreply.models import (
|
||||
Transport, Alias
|
||||
)
|
||||
from modoboa.lib import events, parameters
|
||||
|
||||
|
||||
class PostfixAutoreply(ModoExtension):
|
||||
|
||||
"""
|
||||
Auto-reply (vacation) functionality using Postfix.
|
||||
|
||||
"""
|
||||
name = "postfix_autoreply"
|
||||
label = "Postfix autoreply"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Auto-reply (vacation) functionality using Postfix")
|
||||
|
||||
def init(self):
|
||||
from modoboa.extensions.admin.models import Domain
|
||||
from modoboa.extensions.postfix_autoreply.general_callbacks \
|
||||
import onDomainCreated, onMailboxCreated
|
||||
|
||||
for dom in Domain.objects.all():
|
||||
try:
|
||||
Transport.objects.get(domain="autoreply.%s" % dom.name)
|
||||
except Transport.DoesNotExist:
|
||||
onDomainCreated(None, dom)
|
||||
else:
|
||||
continue
|
||||
|
||||
for mb in dom.mailbox_set.all():
|
||||
try:
|
||||
Alias.objects.get(full_address=mb.full_address)
|
||||
except Alias.DoesNotExist:
|
||||
onMailboxCreated(None, mb)
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.postfix_autoreply.app_settings import (
|
||||
ParametersForm
|
||||
)
|
||||
parameters.register(
|
||||
ParametersForm, ugettext_lazy("Automatic replies"))
|
||||
from modoboa.extensions.postfix_autoreply import general_callbacks
|
||||
modname = "modoboa.extensions.postfix_autoreply.general_callbacks"
|
||||
if modname in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(PostfixAutoreply)
|
||||
|
||||
|
||||
@events.observe("ExtraUprefsRoutes")
|
||||
def extra_routes():
|
||||
from django.conf.urls import url
|
||||
|
||||
return [
|
||||
url(r'^user/autoreply/$',
|
||||
'modoboa.extensions.postfix_autoreply.views.autoreply',
|
||||
name="autoreply")
|
||||
]
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('admin', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Alias',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('full_address', models.CharField(max_length=255)),
|
||||
('autoreply_address', models.CharField(max_length=255)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ARhistoric',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('last_sent', models.DateTimeField(auto_now=True)),
|
||||
('sender', models.CharField(max_length=254)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ARmessage',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('subject', models.CharField(help_text='The subject that will appear in sent emails', max_length=255, verbose_name='subject')),
|
||||
('content', models.TextField(help_text='The content that will appear in sent emails', verbose_name='content')),
|
||||
('enabled', models.BooleanField(default=False, help_text='Activate/Deactivate your auto reply', verbose_name='enabled')),
|
||||
('fromdate', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('untildate', models.DateTimeField(null=True, blank=True)),
|
||||
('mbox', models.ForeignKey(to='admin.Mailbox')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Transport',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('domain', models.CharField(max_length=300)),
|
||||
('method', models.CharField(max_length=255)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='arhistoric',
|
||||
name='armessage',
|
||||
field=models.ForeignKey(to='postfix_autoreply.ARmessage'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='arhistoric',
|
||||
unique_together=set([('armessage', 'sender')]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
from modoboa.extensions.postfix_autoreply.general_callbacks import (
|
||||
onDomainCreated, onMailboxCreated
|
||||
)
|
||||
|
||||
|
||||
def load_initial_data(apps, schema_editor):
|
||||
"""Load initial data."""
|
||||
Domain = apps.get_model("admin", "Domain")
|
||||
Transport = apps.get_model("postfix_autoreply", "Transport")
|
||||
Alias = apps.get_model("postfix_autoreply", "Alias")
|
||||
|
||||
for dom in Domain.objects.all():
|
||||
try:
|
||||
Transport.objects.get(domain="autoreply.%s" % dom.name)
|
||||
except Transport.DoesNotExist:
|
||||
onDomainCreated(None, dom)
|
||||
else:
|
||||
continue
|
||||
|
||||
for mb in dom.mailbox_set.all():
|
||||
try:
|
||||
Alias.objects.get(full_address=mb.full_address)
|
||||
except Alias.DoesNotExist:
|
||||
onMailboxCreated(None, mb)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('postfix_autoreply', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(load_initial_data)
|
||||
]
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from modoboa.extensions.admin.models import Mailbox
|
||||
|
||||
|
||||
@@ -26,7 +27,8 @@ class ARmessage(models.Model):
|
||||
)
|
||||
enabled = models.BooleanField(
|
||||
_('enabled'),
|
||||
help_text=_("Activate/Deactivate your auto reply")
|
||||
help_text=_("Activate/Deactivate your auto reply"),
|
||||
default=False
|
||||
)
|
||||
fromdate = models.DateTimeField(default=timezone.now)
|
||||
untildate = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
Postfix auto-replies plugin.
|
||||
|
||||
This module provides a way to integrate Modoboa auto-reply
|
||||
functionality into Postfix.
|
||||
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import events, parameters
|
||||
|
||||
|
||||
class PostfixAutoreply(ModoExtension):
|
||||
|
||||
"""
|
||||
Auto-reply (vacation) functionality using Postfix.
|
||||
|
||||
"""
|
||||
name = "postfix_autoreply"
|
||||
label = "Postfix autoreply"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Auto-reply (vacation) functionality using Postfix")
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.postfix_autoreply.app_settings import (
|
||||
ParametersForm
|
||||
)
|
||||
parameters.register(
|
||||
ParametersForm, ugettext_lazy("Automatic replies"))
|
||||
from modoboa.extensions.postfix_autoreply import general_callbacks
|
||||
|
||||
exts_pool.register_extension(PostfixAutoreply)
|
||||
|
||||
|
||||
@events.observe("ExtraUprefsRoutes")
|
||||
def extra_routes():
|
||||
from django.conf.urls import url
|
||||
|
||||
return [
|
||||
url(r'^user/autoreply/$',
|
||||
'modoboa.extensions.postfix_autoreply.views.autoreply',
|
||||
name="autoreply")
|
||||
]
|
||||
@@ -1,115 +0,0 @@
|
||||
# coding: utf-8
|
||||
import sys
|
||||
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from .models import RelayDomain, RelayDomainAlias, Service
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import events, parameters
|
||||
|
||||
|
||||
EXTENSION_EVENTS = [
|
||||
"RelayDomainCreated",
|
||||
"RelayDomainDeleted",
|
||||
"RelayDomainModified",
|
||||
"RelayDomainAliasCreated",
|
||||
"RelayDomainAliasDeleted",
|
||||
"ExtraRelayDomainForm",
|
||||
"FillRelayDomainInstances"
|
||||
]
|
||||
|
||||
|
||||
def init_limits_dependant_features():
|
||||
"""Populate limits tables.
|
||||
|
||||
Update the pool of every defined user (to add new limits) and
|
||||
update the *Resellers* group with new permissions.
|
||||
"""
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.limits import controls
|
||||
|
||||
for u in User.objects.all():
|
||||
controls.create_pool(u)
|
||||
grp = Group.objects.get(name='Resellers')
|
||||
for model in [RelayDomain, RelayDomainAlias, Service]:
|
||||
ct = ContentType.objects.get_for_model(model)
|
||||
name = model.__name__.lower()
|
||||
for action in ['add', 'change', 'delete']:
|
||||
grp.permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type=ct, codename='%s_%s' % (action, name)
|
||||
)
|
||||
)
|
||||
grp.save()
|
||||
|
||||
|
||||
def init_amavis_dependant_features():
|
||||
"""Populate amavis database.
|
||||
|
||||
We create records for *users* and *policy* tables for each defined
|
||||
relay domain or relay domain alias.
|
||||
"""
|
||||
from modoboa.extensions.amavis.models import Users
|
||||
from modoboa.extensions.amavis.lib import (
|
||||
create_user_and_policy, create_user_and_use_policy
|
||||
)
|
||||
|
||||
for rdom in RelayDomain.objects.all():
|
||||
try:
|
||||
Users.objects.get(email="@%s" % rdom.name)
|
||||
except Users.DoesNotExist:
|
||||
create_user_and_policy(rdom.name)
|
||||
for rdomalias in rdom.relaydomainalias_set.all():
|
||||
try:
|
||||
Users.objects.get(email='@%s' % rdomalias.name)
|
||||
except Users.DoesNotExist:
|
||||
create_user_and_use_policy(rdomalias.name, rdom.name)
|
||||
|
||||
|
||||
class PostfixRelayDomains(ModoExtension):
|
||||
|
||||
"""Extension declaration."""
|
||||
|
||||
name = "postfix_relay_domains"
|
||||
label = "Postfix relay domains"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Relay domains support for Postfix")
|
||||
|
||||
def init(self):
|
||||
"""Initialisation method.
|
||||
|
||||
Only run once, when the extension is enabled. Populates the
|
||||
service table with default entries.
|
||||
"""
|
||||
for service_name in ['relay', 'smtp']:
|
||||
Service.objects.get_or_create(name=service_name)
|
||||
if exts_pool.is_extension_enabled('limits'):
|
||||
init_limits_dependant_features()
|
||||
|
||||
def load(self):
|
||||
from .app_settings import AdminParametersForm
|
||||
|
||||
parameters.register(
|
||||
AdminParametersForm, ugettext_lazy("Relay domains")
|
||||
)
|
||||
events.declare(EXTENSION_EVENTS)
|
||||
from modoboa.extensions.postfix_relay_domains import general_callbacks
|
||||
prefix = "modoboa.extensions.postfix_relay_domains."
|
||||
if prefix + "general_callbacks" in sys.modules:
|
||||
reload(general_callbacks)
|
||||
if exts_pool.is_extension_enabled('limits'):
|
||||
import limits_callbacks
|
||||
if prefix + "limits_callbacks" in sys.modules:
|
||||
reload(limits_callbacks)
|
||||
if exts_pool.is_extension_enabled('amavis'):
|
||||
import amavis_callbacks
|
||||
if prefix + "amavis_callbacks" in sys.modules:
|
||||
reload(amavis_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(PostfixRelayDomains)
|
||||
|
||||
@@ -127,21 +127,3 @@ def get_import_func(objtype):
|
||||
if objtype == 'relaydomainalias':
|
||||
return [import_relaydomainalias]
|
||||
return []
|
||||
|
||||
|
||||
@events.observe('ExtEnabled')
|
||||
def extension_enabled(extension):
|
||||
"""ExtEnabled event listener.
|
||||
|
||||
Usefull when *limits* or *amavis* extensions are activated after
|
||||
*postfix_relay_domains*.
|
||||
|
||||
:param extension: enabled extension
|
||||
"""
|
||||
from modoboa.extensions.postfix_relay_domains import (
|
||||
init_limits_dependant_features, init_amavis_dependant_features
|
||||
)
|
||||
if extension.name == 'limits':
|
||||
init_limits_dependant_features()
|
||||
if extension.name == 'amavis':
|
||||
init_amavis_dependant_features()
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('admin', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='RelayDomain',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(help_text='The domain name', unique=True, max_length=100, verbose_name='name')),
|
||||
('target_host', models.CharField(help_text='Remote destination of this domain', max_length=255, verbose_name='target host')),
|
||||
('enabled', models.BooleanField(default=True, help_text='Check to activate this domain', verbose_name='enabled')),
|
||||
('verify_recipients', models.BooleanField(default=False, help_text='Check for valid recipients', verbose_name='verify recipients')),
|
||||
('dates', models.ForeignKey(to='admin.ObjectDates')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RelayDomainAlias',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(help_text='The alias name', unique=True, max_length=100, verbose_name='name')),
|
||||
('enabled', models.BooleanField(default=True, help_text='Check to activate this alias', verbose_name='enabled')),
|
||||
('dates', models.ForeignKey(to='admin.ObjectDates')),
|
||||
('target', models.ForeignKey(verbose_name='target', to='postfix_relay_domains.RelayDomain', help_text='The relay domain this alias points to')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Service',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(help_text='The service name', unique=True, max_length=100, verbose_name='name')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='relaydomain',
|
||||
name='service',
|
||||
field=models.ForeignKey(to='postfix_relay_domains.Service'),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
from modoboa.core.extensions import exts_pool
|
||||
|
||||
|
||||
def load_initial_data(apps, schema_editor):
|
||||
"""Load initial data."""
|
||||
Service = apps.get_model("postfix_relay_domains", "Service")
|
||||
for service_name in ['relay', 'smtp']:
|
||||
Service.objects.get_or_create(name=service_name)
|
||||
|
||||
if not exts_pool.is_extension_installed("modoboa.extensions.limits"):
|
||||
return
|
||||
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
RelayDomain = apps.get_model("postfix_relay_domains", "RelayDomain")
|
||||
RelayDomainAlias = apps.get_model(
|
||||
"postfix_relay_domains", "RelayDomainAlias")
|
||||
LimitsPool = apps.get_model("limits", "LimitsPool")
|
||||
Limit = apps.get_model("limits", "Limit")
|
||||
|
||||
# Add new limits to existing pools. Set maxvalue to 0 because we
|
||||
# don't want to load the parameters module here...
|
||||
new_limits = ["relay_domains_limit", "relay_domain_aliases_limit"]
|
||||
for pool in LimitsPool.objects.all():
|
||||
for lname in new_limits:
|
||||
Limit.objects.create(name=lname, pool=pool, maxvalue=0)
|
||||
|
||||
# Add new permissions to the Resellers group.
|
||||
grp = Group.objects.get(name='Resellers')
|
||||
for model in [RelayDomain, RelayDomainAlias, Service]:
|
||||
ct = ContentType.objects.get_for_model(model)
|
||||
name = model.__name__.lower()
|
||||
for action in ['add', 'change', 'delete']:
|
||||
grp.permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type=ct, codename='%s_%s' % (action, name)
|
||||
)
|
||||
)
|
||||
grp.save()
|
||||
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('postfix_relay_domains', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(load_initial_data)
|
||||
]
|
||||
@@ -86,14 +86,16 @@ class RelayDomain(AdminObject):
|
||||
ugettext_lazy('target host'), max_length=255,
|
||||
help_text=ugettext_lazy('Remote destination of this domain')
|
||||
)
|
||||
service = models.ForeignKey(Service, default='relay')
|
||||
service = models.ForeignKey(Service)
|
||||
enabled = models.BooleanField(
|
||||
ugettext_lazy('enabled'),
|
||||
help_text=ugettext_lazy('Check to activate this domain')
|
||||
help_text=ugettext_lazy('Check to activate this domain'),
|
||||
default=True
|
||||
)
|
||||
verify_recipients = models.BooleanField(
|
||||
ugettext_lazy('verify recipients'),
|
||||
help_text=ugettext_lazy('Check for valid recipients')
|
||||
help_text=ugettext_lazy('Check for valid recipients'),
|
||||
default=False
|
||||
)
|
||||
|
||||
owners = generic.GenericRelation(ObjectAccess)
|
||||
@@ -173,7 +175,8 @@ class RelayDomainAlias(AdminObject):
|
||||
)
|
||||
enabled = models.BooleanField(
|
||||
ugettext_lazy('enabled'),
|
||||
help_text=ugettext_lazy("Check to activate this alias")
|
||||
help_text=ugettext_lazy("Check to activate this alias"),
|
||||
default=True
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""Declare postfix_relay_domains extension and register it."""
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import events, parameters
|
||||
|
||||
|
||||
EXTENSION_EVENTS = [
|
||||
"RelayDomainCreated",
|
||||
"RelayDomainDeleted",
|
||||
"RelayDomainModified",
|
||||
"RelayDomainAliasCreated",
|
||||
"RelayDomainAliasDeleted",
|
||||
"ExtraRelayDomainForm",
|
||||
"FillRelayDomainInstances"
|
||||
]
|
||||
|
||||
class PostfixRelayDomains(ModoExtension):
|
||||
|
||||
"""Extension declaration."""
|
||||
|
||||
name = "postfix_relay_domains"
|
||||
label = "Postfix relay domains"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Relay domains support for Postfix")
|
||||
|
||||
def load(self):
|
||||
from .app_settings import AdminParametersForm
|
||||
|
||||
parameters.register(
|
||||
AdminParametersForm, ugettext_lazy("Relay domains")
|
||||
)
|
||||
events.declare(EXTENSION_EVENTS)
|
||||
from modoboa.extensions.postfix_relay_domains import general_callbacks
|
||||
if exts_pool.is_extension_installed("modoboa.extensions.limits"):
|
||||
import limits_callbacks
|
||||
if exts_pool.is_extension_installed("modoboa.extensions.amavis"):
|
||||
import amavis_callbacks
|
||||
|
||||
exts_pool.register_extension(PostfixRelayDomains)
|
||||
@@ -1,76 +0,0 @@
|
||||
"""
|
||||
Radicale management frontend.
|
||||
|
||||
"""
|
||||
import sys
|
||||
|
||||
from django.contrib.auth.models import Permission, Group
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.permissions import add_permissions_to_group
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
|
||||
def init_limits_dependant_features():
|
||||
"""Custom initialization if the limits extension activated.
|
||||
|
||||
We mainly define extra permissions.
|
||||
"""
|
||||
add_permissions_to_group(
|
||||
"Resellers",
|
||||
[("radicale", "usercalendar", "add_usercalendar"),
|
||||
("radicale", "usercalendar", "change_usercalendar"),
|
||||
("radicale", "usercalendar", "delete_usercalendar"),
|
||||
("radicale", "sharedcalendar", "add_sharedcalendar"),
|
||||
("radicale", "sharedcalendar", "change_sharedcalendar"),
|
||||
("radicale", "sharedcalendar", "delete_sharedcalendar")]
|
||||
)
|
||||
|
||||
|
||||
class Radicale(ModoExtension):
|
||||
|
||||
"""Radicale extension declaration."""
|
||||
|
||||
name = "radicale"
|
||||
label = ugettext_lazy("Radicale management")
|
||||
version = "1.0"
|
||||
url = "calendars"
|
||||
description = ugettext_lazy(
|
||||
"Management frontend for Radicale, a simple calendar and contact "
|
||||
"server."
|
||||
)
|
||||
|
||||
def init(self):
|
||||
"""Plugin initialization.
|
||||
"""
|
||||
add_permissions_to_group(
|
||||
"DomainAdmins",
|
||||
[("radicale", "usercalendar", "add_usercalendar"),
|
||||
("radicale", "usercalendar", "change_usercalendar"),
|
||||
("radicale", "usercalendar", "delete_usercalendar"),
|
||||
("radicale", "sharedcalendar", "add_sharedcalendar"),
|
||||
("radicale", "sharedcalendar", "change_sharedcalendar"),
|
||||
("radicale", "sharedcalendar", "delete_sharedcalendar")]
|
||||
)
|
||||
if exts_pool.is_extension_enabled('limits'):
|
||||
init_limits_dependant_features()
|
||||
|
||||
def load(self):
|
||||
"""Plugin loading.
|
||||
"""
|
||||
from .app_settings import ParametersForm
|
||||
|
||||
parameters.register(ParametersForm, "Radicale")
|
||||
from modoboa.extensions.radicale import general_callbacks
|
||||
if 'modoboa.extensions.radicale.general_callbacks' in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
"""Plugin unloading.
|
||||
"""
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(Radicale)
|
||||
|
||||
@@ -16,20 +16,3 @@ def top_menu(target, user):
|
||||
"url": reverse('radicale:index')}
|
||||
]
|
||||
return []
|
||||
|
||||
|
||||
@events.observe('ExtEnabled')
|
||||
def extension_enabled(extension):
|
||||
"""ExtEnabled event listener.
|
||||
|
||||
Usefull when *limits* extension is activated after *radicale*.
|
||||
|
||||
:param extension: enabled extension
|
||||
|
||||
"""
|
||||
if extension.name == 'limits':
|
||||
from modoboa.extensions.radicale import (
|
||||
init_limits_dependant_features
|
||||
)
|
||||
|
||||
init_limits_dependant_features()
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('admin', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AccessRule',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('read', models.BooleanField(default=False)),
|
||||
('write', models.BooleanField(default=False)),
|
||||
('last_update', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SharedCalendar',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('domain', models.ForeignKey(to='admin.Domain')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserCalendar',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('mailbox', models.ForeignKey(to='admin.Mailbox')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='accessrule',
|
||||
name='calendar',
|
||||
field=models.ForeignKey(related_name='rules', to='radicale.UserCalendar'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='accessrule',
|
||||
name='mailbox',
|
||||
field=models.ForeignKey(to='admin.Mailbox'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='accessrule',
|
||||
unique_together=set([('mailbox', 'calendar')]),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
from modoboa.core.extensions import exts_pool
|
||||
from modoboa.lib.migration_tools import add_permissions_to_group
|
||||
|
||||
|
||||
def load_initial_data(apps, schema_editor):
|
||||
"""Load initial data."""
|
||||
|
||||
permissions = [
|
||||
("radicale", "usercalendar", "add_usercalendar"),
|
||||
("radicale", "usercalendar", "change_usercalendar"),
|
||||
("radicale", "usercalendar", "delete_usercalendar"),
|
||||
("radicale", "sharedcalendar", "add_sharedcalendar"),
|
||||
("radicale", "sharedcalendar", "change_sharedcalendar"),
|
||||
("radicale", "sharedcalendar", "delete_sharedcalendar")
|
||||
]
|
||||
|
||||
add_permissions_to_group(apps, "DomainAdmins", permissions)
|
||||
if not exts_pool.is_extension_installed(
|
||||
"modoboa.extensions.limits"):
|
||||
return
|
||||
add_permissions_to_group(apps, "Resellers", permissions)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('radicale', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(load_initial_data)
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
Radicale management frontend.
|
||||
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
class Radicale(ModoExtension):
|
||||
|
||||
"""Radicale extension declaration."""
|
||||
|
||||
name = "radicale"
|
||||
label = ugettext_lazy("Radicale management")
|
||||
version = "1.0"
|
||||
url = "calendars"
|
||||
description = ugettext_lazy(
|
||||
"Management frontend for Radicale, a simple calendar and contact "
|
||||
"server."
|
||||
)
|
||||
|
||||
def load(self):
|
||||
"""Plugin loading.
|
||||
"""
|
||||
from .app_settings import ParametersForm
|
||||
|
||||
parameters.register(ParametersForm, "Radicale")
|
||||
from modoboa.extensions.radicale import general_callbacks
|
||||
|
||||
exts_pool.register_extension(Radicale)
|
||||
@@ -1,28 +0,0 @@
|
||||
# coding: utf-8
|
||||
import sys
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
|
||||
class SieveFilters(ModoExtension):
|
||||
name = "sievefilters"
|
||||
label = "Sieve filters"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Plugin to easily create server-side filters")
|
||||
url = "sfilters"
|
||||
available_for_topredirection = True
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
parameters.register(ParametersForm, ugettext_lazy("Sieve filters"))
|
||||
parameters.register(UserSettings, ugettext_lazy("Message filters"))
|
||||
from modoboa.extensions.sievefilters import general_callbacks
|
||||
if 'modoboa.extensions.sievefilters.general_callbacks' in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(SieveFilters)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# coding: utf-8
|
||||
"""Declare and register the sievefilters extension."""
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
class SieveFilters(ModoExtension):
|
||||
name = "sievefilters"
|
||||
label = "Sieve filters"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Plugin to easily create server-side filters")
|
||||
url = "sfilters"
|
||||
available_for_topredirection = True
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
parameters.register(ParametersForm, ugettext_lazy("Sieve filters"))
|
||||
parameters.register(UserSettings, ugettext_lazy("Message filters"))
|
||||
from modoboa.extensions.sievefilters import general_callbacks
|
||||
|
||||
exts_pool.register_extension(SieveFilters)
|
||||
@@ -1,39 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Graphical statistics about emails traffic using RRDtool
|
||||
|
||||
This module provides support to retrieve statistics from postfix log :
|
||||
sent, received, bounced, rejected
|
||||
|
||||
"""
|
||||
import sys
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
|
||||
class Stats(ModoExtension):
|
||||
name = "stats"
|
||||
label = "Statistics"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Graphical statistics about emails traffic using RRDtool"
|
||||
)
|
||||
needs_media = True
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.stats.app_settings import ParametersForm
|
||||
events.declare(["GetGraphSets"])
|
||||
parameters.register(
|
||||
ParametersForm, ugettext_lazy("Graphical statistics")
|
||||
)
|
||||
from modoboa.extensions.stats import general_callbacks
|
||||
if 'modoboa.extensions.stats.general_callbacks' in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(Stats)
|
||||
|
||||
@@ -97,7 +97,8 @@ class LogParser(object):
|
||||
for dom in Domain.objects.all():
|
||||
self.domains += [str(dom.name)]
|
||||
self.data[str(dom.name)] = {}
|
||||
if not exts_pool.is_extension_enabled("postfix_relay_domains"):
|
||||
if not exts_pool.is_extension_installed(
|
||||
"modoboa.extensions.postfix_relay_domains"):
|
||||
return
|
||||
from modoboa.extensions.postfix_relay_domains.models import RelayDomain
|
||||
for rdom in RelayDomain.objects.all():
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Graphical statistics about emails traffic using RRDtool
|
||||
|
||||
This module provides support to retrieve statistics from postfix log :
|
||||
sent, received, bounced, rejected
|
||||
|
||||
"""
|
||||
import sys
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import events, parameters
|
||||
|
||||
|
||||
class Stats(ModoExtension):
|
||||
name = "stats"
|
||||
label = "Statistics"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy(
|
||||
"Graphical statistics about emails traffic using RRDtool"
|
||||
)
|
||||
needs_media = True
|
||||
|
||||
def load(self):
|
||||
from modoboa.extensions.stats.app_settings import ParametersForm
|
||||
events.declare(["GetGraphSets"])
|
||||
parameters.register(
|
||||
ParametersForm, ugettext_lazy("Graphical statistics")
|
||||
)
|
||||
from modoboa.extensions.stats import general_callbacks
|
||||
|
||||
exts_pool.register_extension(Stats)
|
||||
@@ -58,7 +58,8 @@ def check_domain_access(user, pattern):
|
||||
:return: a domain name (str) or None.
|
||||
"""
|
||||
targets = [Domain]
|
||||
if exts_pool.is_extension_enabled("postfix_relay_domains"):
|
||||
if exts_pool.is_extension_installed(
|
||||
"modoboa.extensions.postfix_relay_domains"):
|
||||
from modoboa.extensions.postfix_relay_domains.models import RelayDomain
|
||||
targets.append(RelayDomain)
|
||||
|
||||
@@ -123,7 +124,8 @@ def graphs(request):
|
||||
def get_domain_list(request):
|
||||
"""Get the list of domains (and relay domains) the user can see."""
|
||||
doms = [dom.name for dom in Domain.objects.get_for_admin(request.user)]
|
||||
if exts_pool.is_extension_enabled("postfix_relay_domains"):
|
||||
if exts_pool.is_extension_installed(
|
||||
"modoboa.extensions.postfix_relay_domains"):
|
||||
from modoboa.extensions.postfix_relay_domains.models import RelayDomain
|
||||
doms += [
|
||||
rdom.name for rdom in
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# coding: utf-8
|
||||
import sys
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
|
||||
class Webmail(ModoExtension):
|
||||
name = "webmail"
|
||||
label = "Webmail"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple IMAP webmail")
|
||||
needs_media = True
|
||||
available_for_topredirection = True
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
|
||||
parameters.register(ParametersForm, "Webmail")
|
||||
parameters.register(UserSettings, "Webmail")
|
||||
from modoboa.extensions.webmail import general_callbacks
|
||||
if 'modoboa.extensions.webmail.general_callbacks' in sys.modules:
|
||||
reload(general_callbacks)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister_extension()
|
||||
parameters.unregister()
|
||||
|
||||
exts_pool.register_extension(Webmail)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# coding: utf-8
|
||||
"""Declare and register the webmail extension."""
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
class Webmail(ModoExtension):
|
||||
name = "webmail"
|
||||
label = "Webmail"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple IMAP webmail")
|
||||
needs_media = True
|
||||
available_for_topredirection = True
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
|
||||
parameters.register(ParametersForm, "Webmail")
|
||||
parameters.register(UserSettings, "Webmail")
|
||||
from modoboa.extensions.webmail import general_callbacks
|
||||
|
||||
exts_pool.register_extension(Webmail)
|
||||
+30
-88
@@ -1,34 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
:mod:`events` --- simple events handling
|
||||
:mod:`EVENTS` --- simple EVENTS handling
|
||||
----------------------------------------
|
||||
|
||||
This module provides a simple way of managing events between Modoboa
|
||||
This module provides a simple way of managing EVENTS between Modoboa
|
||||
core application and additional components.
|
||||
|
||||
"""
|
||||
import inspect
|
||||
import re
|
||||
from functools import wraps
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from modoboa.lib.sysutils import guess_extension_name
|
||||
|
||||
|
||||
events = []
|
||||
callbacks = {}
|
||||
EVENTS = []
|
||||
CALLBACKS = {}
|
||||
|
||||
|
||||
def declare(nevents):
|
||||
"""Declare new events
|
||||
"""Declare new events.
|
||||
|
||||
:param list nevents: a list of event names
|
||||
"""
|
||||
for evt in nevents:
|
||||
if evt not in events:
|
||||
events.append(evt)
|
||||
if evt not in EVENTS:
|
||||
EVENTS.append(evt)
|
||||
|
||||
|
||||
def register(event, callback):
|
||||
@@ -39,69 +31,32 @@ def register(event, callback):
|
||||
:param event: the event to listen to
|
||||
:param callback: a function to execute when the event is raised
|
||||
"""
|
||||
# if not event in events:
|
||||
# if not event in EVENTS:
|
||||
# print "Event %s not registered" % event
|
||||
# return 0
|
||||
if event not in callbacks.keys():
|
||||
callbacks[event] = {}
|
||||
if event not in CALLBACKS.keys():
|
||||
CALLBACKS[event] = {}
|
||||
fullname = "%s.%s" % (callback.__module__, callback.__name__)
|
||||
if fullname not in callbacks[event]:
|
||||
callbacks[event][fullname] = callback
|
||||
if fullname not in CALLBACKS[event]:
|
||||
CALLBACKS[event][fullname] = callback
|
||||
return 1
|
||||
|
||||
|
||||
class observe(object):
|
||||
"""Event observing decorator
|
||||
"""Event observing decorator.
|
||||
|
||||
Automatically register the decorated function to observe the given
|
||||
event. If the decorated function is located into an extension, we
|
||||
check before each call if the extension is enabled or not. If
|
||||
that's not the case, the callback is not called.
|
||||
event.
|
||||
|
||||
.. note::
|
||||
|
||||
That's not a really optimized behaviour but I haven't found
|
||||
another solution to achieve that feature.
|
||||
|
||||
:param evtname: the event's name
|
||||
:param evtnames: a list of event names
|
||||
"""
|
||||
def __init__(self, *evtnames, **kwargs):
|
||||
self.evtnames = evtnames
|
||||
if "extname" in kwargs:
|
||||
self.extname = kwargs["extname"]
|
||||
|
||||
def __guess_extension_name(self, modname):
|
||||
if modname.startswith('modoboa.extensions'):
|
||||
m = re.match(r'modoboa\.extensions\.([^\.]+)', modname)
|
||||
if m:
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
def __call__(self, f):
|
||||
modname = inspect.getmodule(inspect.stack()[1][0]).__name__
|
||||
extname = self.extname if hasattr(self, "extname") \
|
||||
else self.__guess_extension_name(modname)
|
||||
|
||||
@wraps(f)
|
||||
def wrapped_f(*args, **kwargs):
|
||||
if extname:
|
||||
from modoboa.core.models import Extension
|
||||
from modoboa.core.extensions import exts_pool
|
||||
try:
|
||||
ext = Extension.objects.get(name=extname)
|
||||
except Extension.DoesNotExist:
|
||||
extdef = exts_pool.get_extension(extname)
|
||||
if not extdef.always_active:
|
||||
return []
|
||||
else:
|
||||
if not ext.enabled:
|
||||
return None
|
||||
elif modname not in settings.MODOBOA_APPS:
|
||||
return []
|
||||
return f(*args, **kwargs)
|
||||
for evt in self.evtnames:
|
||||
register(evt, wrapped_f)
|
||||
return wrapped_f
|
||||
register(evt, f)
|
||||
return f
|
||||
|
||||
|
||||
def unregister(event, callback):
|
||||
@@ -110,57 +65,44 @@ def unregister(event, callback):
|
||||
:param event: the targeted event
|
||||
:param callback: the callback to remove
|
||||
"""
|
||||
if event not in events:
|
||||
if event not in EVENTS:
|
||||
return False
|
||||
if event not in callbacks:
|
||||
if event not in CALLBACKS:
|
||||
return False
|
||||
fullname = "%s.%s" % (callback.__module__, callback.__name__)
|
||||
try:
|
||||
del callbacks[event][fullname]
|
||||
del CALLBACKS[event][fullname]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def unregister_extension(extension=None):
|
||||
"""Unregister all callbacks declared by an extension.
|
||||
|
||||
:param str extension: extension full name (ie. module name)
|
||||
"""
|
||||
if extension is None:
|
||||
extension = guess_extension_name()
|
||||
for evt, values in callbacks.items():
|
||||
for name in values.keys():
|
||||
if extension in name:
|
||||
del callbacks[evt][name]
|
||||
|
||||
|
||||
def raiseEvent(event, *args, **kwargs):
|
||||
"""Raise a specific event
|
||||
|
||||
Any additional keyword argument will be passed to registered
|
||||
callbacks.
|
||||
CALLBACKS.
|
||||
|
||||
:param event: the event to raise
|
||||
"""
|
||||
if event not in events or event not in callbacks:
|
||||
if event not in EVENTS or event not in CALLBACKS:
|
||||
return 0
|
||||
for callback in callbacks[event].values():
|
||||
for callback in CALLBACKS[event].values():
|
||||
callback(*args, **kwargs)
|
||||
return 1
|
||||
|
||||
|
||||
def raiseQueryEvent(event, *args, **kwargs):
|
||||
"""Raise a specific event and wait for answers from callbacks
|
||||
"""Raise a specific event and wait for answers from CALLBACKS
|
||||
|
||||
Any additional keyword argument will be passed to registered
|
||||
callbacks. Callback answers are returned as a list.
|
||||
CALLBACKS. Callback answers are returned as a list.
|
||||
|
||||
:param event: the event to raise
|
||||
"""
|
||||
result = []
|
||||
if event not in events or event not in callbacks:
|
||||
if event not in EVENTS or event not in CALLBACKS:
|
||||
return result
|
||||
for callback in callbacks[event].values():
|
||||
for callback in CALLBACKS[event].values():
|
||||
tmp = callback(*args, **kwargs)
|
||||
if tmp is None:
|
||||
# Callback is registered but associated extension is
|
||||
@@ -174,15 +116,15 @@ def raiseDictEvent(event, *args):
|
||||
"""Raise a specific event and return result as a dictionnary
|
||||
|
||||
Any additional keyword argument will be passed to registered
|
||||
callbacks. Callback answers must be dictionnaries.
|
||||
CALLBACKS. Callback answers must be dictionnaries.
|
||||
|
||||
:param event: the event to raise
|
||||
:return: a dictionnary
|
||||
"""
|
||||
result = {}
|
||||
if event not in events or event not in callbacks:
|
||||
if event not in EVENTS or event not in CALLBACKS:
|
||||
return result
|
||||
for callback in callbacks[event].values():
|
||||
for callback in CALLBACKS[event].values():
|
||||
tmp = callback(*args)
|
||||
if tmp is None:
|
||||
# Callback is registered but associated extension is
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
"""Custom middlewares."""
|
||||
|
||||
import re
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
|
||||
from modoboa.core.extensions import exts_pool
|
||||
from modoboa.core.models import Extension
|
||||
from modoboa.lib.exceptions import ModoboaException
|
||||
from modoboa.lib.signals import request_accessor
|
||||
from modoboa.lib.web_utils import (
|
||||
@@ -15,24 +11,6 @@ from modoboa.lib.web_utils import (
|
||||
)
|
||||
|
||||
|
||||
class ExtControlMiddleware(object):
|
||||
|
||||
def process_view(self, request, view, args, kwargs):
|
||||
m = re.match(r"modoboa\.extensions\.(\w+)", view.__module__)
|
||||
if m is None:
|
||||
return None
|
||||
try:
|
||||
ext = Extension.objects.get(name=m.group(1))
|
||||
except Extension.DoesNotExist:
|
||||
extdef = exts_pool.get_extension(m.group(1))
|
||||
if extdef.always_active:
|
||||
return None
|
||||
raise Http404
|
||||
if ext.enabled:
|
||||
return None
|
||||
raise Http404
|
||||
|
||||
|
||||
class AjaxLoginRedirect(object):
|
||||
|
||||
def process_response(self, request, response):
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
"""Additional functions available for migration scripts."""
|
||||
|
||||
|
||||
def add_permissions_to_group(apps, groupname, permissions):
|
||||
"""Add the specified permissions to a django group."""
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
|
||||
grp = Group.objects.get(name=groupname)
|
||||
for appname, modelname, permname in permissions:
|
||||
ct = ContentType.objects.get_by_natural_key(
|
||||
appname, modelname)
|
||||
grp.permissions.add(
|
||||
Permission.objects.get(content_type=ct, codename=permname)
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Parameter',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('value', models.CharField(max_length=255)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserParameter',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('value', models.CharField(max_length=255)),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
||||
@@ -145,17 +145,3 @@ def get_object_owner(obj):
|
||||
except ObjectAccess.DoesNotExist:
|
||||
return None
|
||||
return entry.user
|
||||
|
||||
|
||||
def add_permissions_to_group(groupname, permissions):
|
||||
"""Add the specified permissions to a django group.
|
||||
"""
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
|
||||
grp = Group.objects.get(name=groupname)
|
||||
for appname, modelname, permname in permissions:
|
||||
ct = ContentType.objects.get_by_natural_key(
|
||||
appname, modelname)
|
||||
grp.permissions.add(
|
||||
Permission.objects.get(content_type=ct, codename=permname)
|
||||
)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
django>=1.6,<1.7
|
||||
django>=1.7
|
||||
django-reversion==1.8.5
|
||||
dj-database-url
|
||||
south>=1.0
|
||||
|
||||
Reference in New Issue
Block a user