mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Refactored extension API
* Modoboa extensions must now declare themselves * Now using django 1.3 *staticfiles* module * Better distinction between *static* content and *media* content see #197
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
.*~$
|
||||
^[^\.]+\.pyc
|
||||
^[^\.]+\.mo
|
||||
sitestatic
|
||||
scripts
|
||||
static/tmp
|
||||
static/js/ckeditor
|
||||
settings.py
|
||||
|
||||
+22
-29
@@ -10,7 +10,7 @@ from modoboa.lib import parameters, events
|
||||
from modoboa.lib.exceptions import PermDeniedException
|
||||
from modoboa.lib.sysutils import exec_cmd, exec_as_vuser
|
||||
from modoboa.lib.emailutils import split_mailbox
|
||||
from modoboa.extensions import get_ext_module
|
||||
from modoboa.extensions import exts_pool
|
||||
from exceptions import *
|
||||
import os, sys
|
||||
import pwd
|
||||
@@ -806,56 +806,49 @@ class Extension(models.Model):
|
||||
help_text=ugettext_lazy("Check to enable this extension")
|
||||
)
|
||||
|
||||
def init(self):
|
||||
module = get_ext_module(self.name)
|
||||
if hasattr(module, "init"):
|
||||
module.init()
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Extension, self).__init__(*args, **kwargs)
|
||||
self.instance = exts_pool.get_extension(self.name)
|
||||
self.__get_ext_dir()
|
||||
|
||||
def load(self):
|
||||
module = get_ext_module(self.name)
|
||||
if hasattr(module, "load"):
|
||||
module.load()
|
||||
|
||||
def unload(self):
|
||||
module = get_ext_module(self.name)
|
||||
module.destroy()
|
||||
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):
|
||||
self.enabled = True
|
||||
self.save()
|
||||
|
||||
self.load()
|
||||
self.init()
|
||||
self.instance.load()
|
||||
self.instance.init()
|
||||
|
||||
extdir = "%s/extensions/%s" % (settings.MODOBOA_DIR, self.name)
|
||||
scriptdir = "%s/%s" % (extdir, "scripts")
|
||||
if self.instance.needs_media:
|
||||
path = os.path.join(settings.MEDIA_ROOT, self.name)
|
||||
exec_cmd("mkdir %s" % path)
|
||||
|
||||
scriptdir = "%s/%s" % (self.extdir, "scripts")
|
||||
if os.path.exists(scriptdir):
|
||||
targetdir = os.path.join(settings.MODOBOA_DIR, "scripts")
|
||||
exec_cmd("ln -s %s %s/%s" % (scriptdir, targetdir, self.name))
|
||||
|
||||
staticpath = "%s/%s" % (extdir, "static")
|
||||
if os.path.exists(staticpath):
|
||||
exec_cmd("ln -s %s/static %s/static/%s" % \
|
||||
(extdir, settings.MODOBOA_DIR, self.name))
|
||||
|
||||
events.raiseEvent("ExtEnabled", self)
|
||||
|
||||
def off(self):
|
||||
self.unload()
|
||||
self.instance.destroy()
|
||||
|
||||
self.enabled = False
|
||||
self.save()
|
||||
|
||||
extdir = "%s/extensions/%s" % (settings.MODOBOA_DIR, self.name)
|
||||
scriptdir = "%s/%s" % (extdir, "scripts")
|
||||
if self.instance.needs_media:
|
||||
path = os.path.join(settings.MEDIA_ROOT, self.name)
|
||||
exec_cmd("rm -r %s" % path)
|
||||
|
||||
scriptdir = "%s/%s" % (self.extdir, "scripts")
|
||||
if os.path.exists(scriptdir):
|
||||
target = "%s/scripts/%s" % (settings.MODOBOA_DIR, self.name)
|
||||
exec_cmd("rm %s" % target)
|
||||
|
||||
staticpath = "%s/%s" % (extdir, "static")
|
||||
if os.path.exists(staticpath):
|
||||
exec_cmd("rm -r %s/static/%s" % (settings.MODOBOA_DIR, self.name))
|
||||
|
||||
events.raiseEvent("ExtDisabled", self)
|
||||
|
||||
def populate_callback(sender, user=None, **kwargs):
|
||||
|
||||
+2
-2
@@ -41,11 +41,11 @@ class DomainsTable(tables.Table):
|
||||
class ExtensionsTable(tables.Table):
|
||||
idkey = "id"
|
||||
selection = tables.SelectionColumn("selection", width="4%", header=False)
|
||||
name = tables.Column("name", label=ugettext_lazy("Name"), width="15%")
|
||||
label = tables.Column("label", label=ugettext_lazy("Name"), width="15%")
|
||||
version = tables.Column("version", label=ugettext_lazy("Version"), width="6%")
|
||||
descr = tables.Column("description", label=ugettext_lazy("Description"))
|
||||
|
||||
cols_order = ["selection", "name", "version", "descr"]
|
||||
cols_order = ["selection", "label", "version", "descr"]
|
||||
|
||||
class IdentitiesTable(tables.Table):
|
||||
idkey = "id"
|
||||
|
||||
+2
-2
@@ -494,9 +494,9 @@ def saveparameters(request):
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def viewextensions(request, tplname='admin/extensions.html'):
|
||||
from modoboa.extensions import list_extensions
|
||||
from modoboa.extensions import exts_pool
|
||||
|
||||
exts = list_extensions()
|
||||
exts = exts_pool.list_all()
|
||||
for ext in exts:
|
||||
try:
|
||||
dbext = Extension.objects.get(name=ext["id"])
|
||||
|
||||
+61
-55
@@ -4,65 +4,71 @@ import re
|
||||
from django.conf import settings
|
||||
from django.conf.urls.defaults import include
|
||||
|
||||
def isinstalled(ext):
|
||||
return "modoboa.extensions.%s" % ext in settings.INSTALLED_APPS
|
||||
class ModoExtension(object):
|
||||
"""Base extension class
|
||||
|
||||
def get_ext_module(extname):
|
||||
modname = "modoboa.extensions.%s" % extname
|
||||
if not sys.modules.has_key(modname):
|
||||
__import__(modname)
|
||||
return sys.modules[modname]
|
||||
Each Modoboa extension must inherit from this class to be
|
||||
considered as valid.
|
||||
"""
|
||||
name = None
|
||||
version = "0.1"
|
||||
description = ""
|
||||
url = None
|
||||
needs_media = False
|
||||
|
||||
def get_extension_infos(name):
|
||||
return get_ext_module(name).infos()
|
||||
def infos(self):
|
||||
return dict(name=self.name, label=self.label, version=self.version,
|
||||
description=self.description, url=self.url)
|
||||
|
||||
def loadextensions(prefix):
|
||||
# To avoid a circular import...
|
||||
from modoboa.admin.models import Extension
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
basedir = "%s/extensions" % settings.MODOBOA_DIR
|
||||
result = []
|
||||
for f in os.listdir(basedir):
|
||||
if not os.path.isdir("%s/%s" % (basedir, f)):
|
||||
continue
|
||||
if not isinstalled(f):
|
||||
continue
|
||||
try:
|
||||
ext = Extension.objects.get(name=f)
|
||||
if ext.enabled:
|
||||
ext.load()
|
||||
except Extension.DoesNotExist:
|
||||
pass
|
||||
module = get_ext_module(f)
|
||||
baseurl = module.baseurl if hasattr(module, "baseurl") \
|
||||
else f
|
||||
result += [(r'%s%s/' % (prefix, baseurl),
|
||||
include("modoboa.extensions.%s.urls" % f))]
|
||||
return result
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
def list_extensions():
|
||||
basedir = "%s/extensions" % settings.MODOBOA_DIR
|
||||
result = []
|
||||
for d in os.listdir(basedir):
|
||||
if not os.path.isdir("%s/%s" % (basedir, d)):
|
||||
continue
|
||||
if not isinstalled(d):
|
||||
continue
|
||||
isvalid = True
|
||||
for f in ['urls.py', '__init__.py', 'views.py']:
|
||||
if not os.path.exists("%s/%s/%s" % (basedir, d, f)):
|
||||
isvalid = False
|
||||
break
|
||||
if isvalid:
|
||||
module = __import__(d, globals(), locals())
|
||||
|
||||
class ExtensionsPool(object):
|
||||
"""The extensions manager"""
|
||||
|
||||
def __init__(self):
|
||||
self.extensions = dict()
|
||||
|
||||
def register_extension(self, ext):
|
||||
self.extensions[ext.name] = dict(cls=ext)
|
||||
|
||||
def get_extension(self, name):
|
||||
if not self.extensions.has_key(name):
|
||||
return None
|
||||
if not self.extensions[name].has_key("instance"):
|
||||
self.extensions[name]["instance"] = self.extensions[name]["cls"]()
|
||||
return self.extensions[name]["instance"]
|
||||
|
||||
def load_all(self, prefix):
|
||||
from modoboa.admin.models import Extension
|
||||
|
||||
result = []
|
||||
for extname, extdef in self.extensions.iteritems():
|
||||
extinstance = self.get_extension(extname)
|
||||
try:
|
||||
infos = module.infos()
|
||||
infos["id"] = d
|
||||
if os.path.isdir("%s/%s/templates" % (basedir, d)):
|
||||
infos["templates"] = True
|
||||
else:
|
||||
infos["templates"] = False
|
||||
result += [infos]
|
||||
except AttributeError:
|
||||
ext = Extension.objects.get(name=extname)
|
||||
if ext.enabled:
|
||||
extinstance.load()
|
||||
except Extension.DoesNotExist:
|
||||
pass
|
||||
return result
|
||||
baseurl = extinstance.url if extinstance.url is not None else extname
|
||||
result += [(r'%s%s/' % (prefix, baseurl),
|
||||
include("%s.urls" % extinstance.__module__))]
|
||||
return result
|
||||
|
||||
def list_all(self):
|
||||
result = []
|
||||
for extname, extdef in self.extensions.iteritems():
|
||||
infos = extdef["instance"].infos()
|
||||
infos["id"] = extname
|
||||
result += [infos]
|
||||
return sorted(result, key=lambda i: i["name"])
|
||||
|
||||
exts_pool = ExtensionsPool()
|
||||
|
||||
@@ -7,78 +7,78 @@ from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import Template, Context
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
|
||||
baseurl = "quarantine"
|
||||
class AmavisQuarantine(ModoExtension):
|
||||
name = "amavis_quarantine"
|
||||
label = "Amavis quarantine"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple amavis quarantine management tool")
|
||||
url = "quarantine"
|
||||
|
||||
def infos():
|
||||
return {
|
||||
"name" : "Amavis quarantine",
|
||||
"version" : "1.0",
|
||||
"description" : _("Simple amavis quarantine management tool"),
|
||||
"url" : "quarantine"
|
||||
}
|
||||
def init(self):
|
||||
"""Init function
|
||||
|
||||
Only run once, when the extension is enabled. We create records
|
||||
for existing mailboxes in order Amavis considers them local.
|
||||
"""
|
||||
from modoboa.admin.models import Mailbox
|
||||
from models import Users
|
||||
|
||||
for mb in Mailbox.objects.all():
|
||||
try:
|
||||
u = Users.objects.get(email=mb.full_address)
|
||||
except Users.DoesNotExist:
|
||||
u = Users()
|
||||
u.email = mb.full_address
|
||||
u.fullname = mb.user.fullname
|
||||
u.local = "1"
|
||||
u.priority = 7
|
||||
u.policy_id = 1
|
||||
u.save()
|
||||
|
||||
def init():
|
||||
"""Init function
|
||||
def load(self):
|
||||
parameters.register_admin(
|
||||
"MAX_MESSAGES_AGE", type="int",
|
||||
deflt=14,
|
||||
help=_("Quarantine messages maximum age (in days) before deletion")
|
||||
)
|
||||
parameters.register_admin(
|
||||
"RELEASED_MSGS_CLEANUP", type="list_yesno", deflt="no",
|
||||
help=_("Remove messages marked as released while cleaning up the database")
|
||||
)
|
||||
parameters.register_admin("AM_PDP_MODE", type="list",
|
||||
deflt="unix",
|
||||
values=[("inet", "inet"), ("unix", "unix")],
|
||||
help=ugettext_lazy("Mode used to access the PDP server"))
|
||||
parameters.register_admin("AM_PDP_HOST", type="string",
|
||||
deflt="localhost",
|
||||
help=ugettext_lazy("PDP server address (if inet mode)"))
|
||||
parameters.register_admin("AM_PDP_PORT", type="int",
|
||||
deflt=9998,
|
||||
help=ugettext_lazy("PDP server port (if inet mode)"))
|
||||
parameters.register_admin("AM_PDP_SOCKET", type="string",
|
||||
deflt="/var/amavis/amavisd.sock",
|
||||
help=ugettext_lazy("Path to the PDP server socket (if unix mode)"))
|
||||
parameters.register_admin("CHECK_REQUESTS_INTERVAL", type="int",
|
||||
deflt=30,
|
||||
help=ugettext_lazy("Interval between two release requests checks"))
|
||||
parameters.register_admin("USER_CAN_RELEASE", type="list_yesno", deflt="no",
|
||||
help=ugettext_lazy("Allow users to directly release their messages"))
|
||||
parameters.register_admin("SELF_SERVICE", type="list_yesno", deflt="no",
|
||||
help=ugettext_lazy("Activate the 'self-service' mode"))
|
||||
|
||||
parameters.register_user(
|
||||
"MESSAGES_PER_PAGE", type="int", deflt=40,
|
||||
label="Number of displayed emails per page",
|
||||
help=ugettext_lazy("Sets the maximum number of messages displayed in a page")
|
||||
)
|
||||
|
||||
Only run once, when the extension is enabled. We create records
|
||||
for existing mailboxes in order Amavis considers them local.
|
||||
"""
|
||||
from modoboa.admin.models import Mailbox
|
||||
from models import Users
|
||||
def destroy(self):
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("amavis_quarantine")
|
||||
|
||||
for mb in Mailbox.objects.all():
|
||||
try:
|
||||
u = Users.objects.get(email=mb.full_address)
|
||||
except Users.DoesNotExist:
|
||||
u = Users()
|
||||
u.email = mb.full_address
|
||||
u.fullname = mb.user.fullname
|
||||
u.local = "1"
|
||||
u.priority = 7
|
||||
u.policy_id = 1
|
||||
u.save()
|
||||
|
||||
def load():
|
||||
parameters.register_admin(
|
||||
"MAX_MESSAGES_AGE", type="int",
|
||||
deflt=14,
|
||||
help=_("Quarantine messages maximum age (in days) before deletion")
|
||||
)
|
||||
parameters.register_admin(
|
||||
"RELEASED_MSGS_CLEANUP", type="list_yesno", deflt="no",
|
||||
help=_("Remove messages marked as released while cleaning up the database")
|
||||
)
|
||||
parameters.register_admin("AM_PDP_MODE", type="list",
|
||||
deflt="unix",
|
||||
values=[("inet", "inet"), ("unix", "unix")],
|
||||
help=ugettext_lazy("Mode used to access the PDP server"))
|
||||
parameters.register_admin("AM_PDP_HOST", type="string",
|
||||
deflt="localhost",
|
||||
help=ugettext_lazy("PDP server address (if inet mode)"))
|
||||
parameters.register_admin("AM_PDP_PORT", type="int",
|
||||
deflt=9998,
|
||||
help=ugettext_lazy("PDP server port (if inet mode)"))
|
||||
parameters.register_admin("AM_PDP_SOCKET", type="string",
|
||||
deflt="/var/amavis/amavisd.sock",
|
||||
help=ugettext_lazy("Path to the PDP server socket (if unix mode)"))
|
||||
parameters.register_admin("CHECK_REQUESTS_INTERVAL", type="int",
|
||||
deflt=30,
|
||||
help=ugettext_lazy("Interval between two release requests checks"))
|
||||
parameters.register_admin("USER_CAN_RELEASE", type="list_yesno", deflt="no",
|
||||
help=ugettext_lazy("Allow users to directly release their messages"))
|
||||
parameters.register_admin("SELF_SERVICE", type="list_yesno", deflt="no",
|
||||
help=ugettext_lazy("Activate the 'self-service' mode"))
|
||||
|
||||
parameters.register_user(
|
||||
"MESSAGES_PER_PAGE", type="int", deflt=40,
|
||||
label="Number of displayed emails per page",
|
||||
help=ugettext_lazy("Sets the maximum number of messages displayed in a page")
|
||||
)
|
||||
|
||||
def destroy():
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("amavis_quarantine")
|
||||
exts_pool.register_extension(AmavisQuarantine)
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{% extends "fixed.html" %}{% load i18n %}
|
||||
{% block pagetitle %}{% trans "Quarantine management" %}{% endblock %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}amavis_quarantine/css/quarantine.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.htmltable.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/searchbar.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}amavis_quarantine/js/quarantine.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}amavis_quarantine/css/quarantine.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.htmltable.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/searchbar.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}amavis_quarantine/js/quarantine.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var qm = new Quarantine({
|
||||
|
||||
+10
-10
@@ -3,19 +3,19 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Modoboa</title>
|
||||
<link rel="icon" type="image/png" href="{{ MEDIA_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}amavis_quarantine/css/selfservice.css" />
|
||||
<script src="{{ MEDIA_URL }}js/jquery.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/global.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/notify.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}amavis_quarantine/js/selfservice.js" type="text/javascript"></script>
|
||||
<link rel="icon" type="image/png" href="{{ STATIC_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}amavis_quarantine/css/selfservice.css" />
|
||||
<script src="{{ STATIC_URL }}js/jquery.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/global.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/notify.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}amavis_quarantine/js/selfservice.js" type="text/javascript"></script>
|
||||
{% url django.views.i18n.javascript_catalog as catalog_url %}
|
||||
<script type="text/javascript" src="{{ catalog_url }}"></script>
|
||||
<script type="text/javascript">
|
||||
set_media_url("{{ MEDIA_URL }}");
|
||||
set_media_url("{{ STATIC_URL }}");
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -103,7 +103,7 @@ def quar_menu(user):
|
||||
else:
|
||||
extraopts = []
|
||||
extracontent = render_to_string('common/email_searchbar.html', {
|
||||
"MEDIA_URL" : settings.MEDIA_URL,
|
||||
"STATIC_URL" : settings.STATIC_URL,
|
||||
"extraopts" : extraopts
|
||||
})
|
||||
|
||||
|
||||
@@ -10,51 +10,49 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events
|
||||
from modoboa.lib.webutils import static_url
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
from models import *
|
||||
from forms import ResourcePoolForm
|
||||
import controls
|
||||
import views
|
||||
|
||||
baseurl = "limits"
|
||||
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():
|
||||
from modoboa.admin.models import User, Domain
|
||||
def init(self):
|
||||
from modoboa.admin.models import User, 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(Permission)
|
||||
for pname in ["view_permissions"]:
|
||||
perm = Permission.objects.get(content_type=ct, codename=pname)
|
||||
grp.permissions.add(perm)
|
||||
|
||||
ct = ContentType.objects.get_for_model(Domain)
|
||||
for pname in ["view_domains", "add_domain", "change_domain", "delete_domain"]:
|
||||
perm = Permission.objects.get(content_type=ct, codename=pname)
|
||||
grp.permissions.add(perm)
|
||||
grp.save()
|
||||
|
||||
for user in User.objects.filter(groups__name='DomainAdmins'):
|
||||
try:
|
||||
controls.create_pool(user)
|
||||
except IntegrityError:
|
||||
pass
|
||||
|
||||
ct = ContentType.objects.get(app_label="admin", model="domain")
|
||||
dagrp = Group.objects.get(name="DomainAdmins")
|
||||
def destroy(self):
|
||||
Group.objects.get(name="Resellers").delete()
|
||||
|
||||
grp = Group(name="Resellers")
|
||||
grp.save()
|
||||
grp.permissions.add(*dagrp.permissions.all())
|
||||
|
||||
ct = ContentType.objects.get_for_model(Permission)
|
||||
for pname in ["view_permissions"]:
|
||||
perm = Permission.objects.get(content_type=ct, codename=pname)
|
||||
grp.permissions.add(perm)
|
||||
|
||||
ct = ContentType.objects.get_for_model(Domain)
|
||||
for pname in ["view_domains", "add_domain", "change_domain", "delete_domain"]:
|
||||
perm = Permission.objects.get(content_type=ct, codename=pname)
|
||||
grp.permissions.add(perm)
|
||||
grp.save()
|
||||
|
||||
for user in User.objects.filter(groups__name='DomainAdmins'):
|
||||
try:
|
||||
controls.create_pool(user)
|
||||
except IntegrityError:
|
||||
pass
|
||||
|
||||
def destroy():
|
||||
Group.objects.get(name="Resellers").delete()
|
||||
|
||||
def infos():
|
||||
return {
|
||||
"name" : "Limits",
|
||||
"version" : "1.0",
|
||||
"description" : _("Per administrator resources to limit the number of objects they can create"),
|
||||
"url" : baseurl
|
||||
}
|
||||
exts_pool.register_extension(Limits)
|
||||
|
||||
@events.observe("GetExtraRoles")
|
||||
def get_extra_roles(user):
|
||||
|
||||
@@ -10,49 +10,49 @@ from django.conf.urls.defaults import include
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy, get_language
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import static_url
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
from models import *
|
||||
|
||||
def infos():
|
||||
return {
|
||||
"name" : "Postfix autoreply",
|
||||
"version" : "1.0",
|
||||
"description" : _("Auto-reply (vacation) functionality using Postfix"),
|
||||
"url" : "postfix_autoreply"
|
||||
}
|
||||
class PostfixAutoreply(ModoExtension):
|
||||
name = "postfix_autoreply"
|
||||
label = "Postfix autoreply"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Auto-reply (vacation) functionality using Postfix")
|
||||
|
||||
def init():
|
||||
from modoboa.admin.models import Domain
|
||||
|
||||
for dom in Domain.objects.all():
|
||||
try:
|
||||
trans = Transport.objects.get(domain="autoreply.%s" % dom.name)
|
||||
except Transport.DoesNotExist:
|
||||
onCreateDomain(None, dom)
|
||||
else:
|
||||
continue
|
||||
|
||||
for mb in dom.mailbox_set.all():
|
||||
def init(self):
|
||||
from modoboa.admin.models import Domain
|
||||
|
||||
for dom in Domain.objects.all():
|
||||
try:
|
||||
alias = Alias.objects.get(full_address=mb.full_address)
|
||||
except Alias.DoesNotExist:
|
||||
onCreateMailbox(None, mb)
|
||||
trans = Transport.objects.get(domain="autoreply.%s" % dom.name)
|
||||
except Transport.DoesNotExist:
|
||||
onCreateDomain(None, dom)
|
||||
else:
|
||||
continue
|
||||
|
||||
def load():
|
||||
parameters.register_admin(
|
||||
"AUTOREPLIES_TIMEOUT",
|
||||
type="int", deflt=86400,
|
||||
help=ugettext_lazy("Timeout in seconds between two auto-replies to the same recipient")
|
||||
)
|
||||
for mb in dom.mailbox_set.all():
|
||||
try:
|
||||
alias = Alias.objects.get(full_address=mb.full_address)
|
||||
except Alias.DoesNotExist:
|
||||
onCreateMailbox(None, mb)
|
||||
|
||||
def destroy():
|
||||
events.unregister("CreateDomain", onCreateDomain)
|
||||
events.unregister("DeleteDomain", onDeleteDomain)
|
||||
events.unregister("CreateMailbox", onCreateMailbox)
|
||||
events.unregister("DeleteMailbox", onDeleteMailbox)
|
||||
events.unregister("ModifyMailbox", onModifyMailbox)
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("postfix_autoreply")
|
||||
def load(self):
|
||||
parameters.register_admin(
|
||||
"AUTOREPLIES_TIMEOUT",
|
||||
type="int", deflt=86400,
|
||||
help=ugettext_lazy("Timeout in seconds between two auto-replies to the same recipient")
|
||||
)
|
||||
|
||||
def destroy(self):
|
||||
events.unregister("CreateDomain", onCreateDomain)
|
||||
events.unregister("DeleteDomain", onDeleteDomain)
|
||||
events.unregister("CreateMailbox", onCreateMailbox)
|
||||
events.unregister("DeleteMailbox", onDeleteMailbox)
|
||||
events.unregister("ModifyMailbox", onModifyMailbox)
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("postfix_autoreply")
|
||||
|
||||
exts_pool.register_extension(PostfixAutoreply)
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
|
||||
@@ -2,46 +2,45 @@
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import static_url
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
from sievelib.managesieve import SUPPORTED_AUTH_MECHS
|
||||
|
||||
baseurl = "sfilters"
|
||||
class SieveFilters(ModoExtension):
|
||||
name = "sievefilters"
|
||||
label = "Sieve filters"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Plugin to easily create server-side filters")
|
||||
url = "sfilters"
|
||||
|
||||
def load():
|
||||
parameters.register_app(uparams_opts=dict(needs_mailbox=True))
|
||||
def load(self):
|
||||
parameters.register_app(uparams_opts=dict(needs_mailbox=True))
|
||||
|
||||
parameters.register_admin("SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your MANAGESIEVE server"))
|
||||
parameters.register_admin("PORT", type="int", deflt="2000",
|
||||
help=ugettext_lazy("Listening port of your MANAGESIEVE server"))
|
||||
parameters.register_admin("STARTTLS", type="list_yesno", deflt="no",
|
||||
help=ugettext_lazy("Use the STARTTLS extension"))
|
||||
|
||||
parameters.register_admin("SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your MANAGESIEVE server"))
|
||||
parameters.register_admin("PORT", type="int", deflt="2000",
|
||||
help=ugettext_lazy("Listening port of your MANAGESIEVE server"))
|
||||
parameters.register_admin("STARTTLS", type="list_yesno", deflt="no",
|
||||
help=ugettext_lazy("Use the STARTTLS extension"))
|
||||
values = [('AUTO', 'auto')]
|
||||
for m in SUPPORTED_AUTH_MECHS:
|
||||
values += [(m, m.lower())]
|
||||
parameters.register_admin("AUTHENTICATION_MECH", type="list", deflt="auto",
|
||||
values=values,
|
||||
help=ugettext_lazy("Prefered authentication mechanism"))
|
||||
|
||||
values = [('AUTO', 'auto')]
|
||||
for m in SUPPORTED_AUTH_MECHS:
|
||||
values += [(m, m.lower())]
|
||||
parameters.register_admin("AUTHENTICATION_MECH", type="list", deflt="auto",
|
||||
values=values,
|
||||
help=ugettext_lazy("Prefered authentication mechanism"))
|
||||
|
||||
# User parameters
|
||||
parameters.register_user("EDITOR_MODE", type="list", deflt="raw",
|
||||
label=ugettext_lazy("Editor mode"),
|
||||
values=[("raw", "raw"), ("gui", "simplified")],
|
||||
help=ugettext_lazy("Select the mode you want the editor to work in"))
|
||||
# User parameters
|
||||
parameters.register_user("EDITOR_MODE", type="list", deflt="raw",
|
||||
label=ugettext_lazy("Editor mode"),
|
||||
values=[("raw", "raw"), ("gui", "simplified")],
|
||||
help=ugettext_lazy("Select the mode you want the editor to work in"))
|
||||
|
||||
def destroy():
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("sievefilters")
|
||||
def destroy(self):
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("sievefilters")
|
||||
|
||||
def infos():
|
||||
return {
|
||||
"name" : "Sieve filters",
|
||||
"version" : "1.0",
|
||||
"description" : _("Plugin to easily create server-side filters"),
|
||||
"url" : "sfilters"
|
||||
}
|
||||
exts_pool.register_extension(SieveFilters)
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{% extends "twocols.html" %}{% load i18n sfilters_tags %}
|
||||
{% block pagetitle %}{% trans "Message filters" %}{% endblock %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}sievefilters/css/style.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}sievefilters/js/lib.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/dynamic_input.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}sievefilters/js/jquery.dynfields.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}sievefilters/css/style.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}sievefilters/js/lib.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/dynamic_input.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}sievefilters/js/jquery.dynfields.js"></script>
|
||||
<script type="text/javascript">
|
||||
var history = new History({
|
||||
deflocation: "{{ default_script }}",
|
||||
|
||||
@@ -11,32 +11,32 @@ from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.conf.urls.defaults import *
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import static_url
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
|
||||
def infos():
|
||||
return {
|
||||
"name" : "Statistics",
|
||||
"version" : "1.0",
|
||||
"description" : _("Graphical statistics about emails traffic using RRDtool"),
|
||||
"url" : "stats"
|
||||
}
|
||||
class Stats(ModoExtension):
|
||||
name = "stats"
|
||||
label = "Statistics"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Graphical statistics about emails traffic using RRDtool")
|
||||
|
||||
def load():
|
||||
parameters.register_admin("LOGFILE", type="string",
|
||||
deflt="/var/log/mail.log",
|
||||
help=ugettext_lazy("Path to log file used to collect statistics"))
|
||||
parameters.register_admin("RRD_ROOTDIR", type="string",
|
||||
deflt="/tmp/modoboa",
|
||||
help=ugettext_lazy("Path to directory where RRD files are stored"))
|
||||
parameters.register_admin("IMG_ROOTDIR", type="string",
|
||||
deflt="/tmp/modoboa",
|
||||
help=ugettext_lazy("Path to directory where PNG files are stored"))
|
||||
parameters.register_admin("GRAPHS_LOCATION", type="string",
|
||||
deflt="graphs",
|
||||
help=ugettext_lazy("Graphics location (to build URLs)"))
|
||||
def load(self):
|
||||
parameters.register_admin("LOGFILE", type="string",
|
||||
deflt="/var/log/mail.log",
|
||||
help=ugettext_lazy("Path to log file used to collect statistics"))
|
||||
parameters.register_admin("RRD_ROOTDIR", type="string",
|
||||
deflt="/tmp/modoboa",
|
||||
help=ugettext_lazy("Path to directory where RRD files are stored"))
|
||||
parameters.register_admin("IMG_ROOTDIR", type="string",
|
||||
deflt="/tmp/modoboa",
|
||||
help=ugettext_lazy("Path to directory where PNG files are stored"))
|
||||
parameters.register_admin("GRAPHS_LOCATION", type="string",
|
||||
deflt="graphs",
|
||||
help=ugettext_lazy("Graphics location (to build URLs)"))
|
||||
|
||||
def destroy():
|
||||
events.unregister("AdminMenuDisplay", menu)
|
||||
def destroy(self):
|
||||
events.unregister("AdminMenuDisplay", menu)
|
||||
|
||||
exts_pool.register_extension(Stats)
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
{% endif %}
|
||||
{% for elems in graphs %}
|
||||
<h3>{% trans elems.label %}</h3>
|
||||
<p><img src="{{ MEDIA_URL }}{{ graphs_loc }}/{{ elems.name }}_{{ domain }}_AVERAGE_{% ifequal period 'custom' %}{{ period_name }}{% else %}{{ period }}{% endifequal %}.png"
|
||||
<p><img src="{{ STATIC_URL }}{{ graphs_loc }}/{{ elems.name }}_{{ domain }}_AVERAGE_{% ifequal period 'custom' %}{{ period_name }}{% else %}{{ period }}{% endifequal %}.png"
|
||||
alt="{% trans 'No statistics available' %}" /></p>
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{% extends "fixed.html" %}{% load i18n %}
|
||||
{% block pagetitle %}{% trans "Graphical statistics" %}{% endblock %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}stats/css/stats.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}stats/js/stats.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}stats/css/stats.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}stats/js/stats.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var stats = new Stats({
|
||||
|
||||
@@ -3,76 +3,78 @@ from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import static_url
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
|
||||
def load():
|
||||
parameters.register_app(uparams_opts=dict(needs_mailbox=True))
|
||||
class Webmail(ModoExtension):
|
||||
name = "webmail"
|
||||
label = "Webmail"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple IMAP webmail")
|
||||
needs_media = True
|
||||
|
||||
def load(self):
|
||||
parameters.register_app(uparams_opts=dict(needs_mailbox=True))
|
||||
|
||||
parameters.register_admin("IMAP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your IMAP server"))
|
||||
parameters.register_admin("IMAP_SECURED", type="list_yesno",
|
||||
deflt="no",
|
||||
help=ugettext_lazy("Use a secured connection to access IMAP server"))
|
||||
parameters.register_admin("IMAP_PORT", type="int", deflt="143",
|
||||
help=ugettext_lazy("Listening port of your IMAP server"))
|
||||
parameters.register_admin("SMTP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your SMTP server"))
|
||||
parameters.register_admin("SMTP_SECURED_MODE", type="list",
|
||||
values=[("none", ugettext_lazy("None")),
|
||||
("starttls", "STARTTLS"),
|
||||
("ssl", "SSL/TLS")],
|
||||
deflt="none",
|
||||
help=ugettext_lazy("Use a secured connection to access SMTP server"))
|
||||
parameters.register_admin("SMTP_PORT", type="int", deflt="25",
|
||||
help=ugettext_lazy("Listening port of your SMTP server"))
|
||||
parameters.register_admin("SMTP_AUTHENTICATION", type="list_yesno",
|
||||
deflt="no",
|
||||
help=ugettext_lazy("Server needs authentication"))
|
||||
parameters.register_admin("MAX_ATTACHMENT_SIZE", type="int", deflt=2048,
|
||||
help=ugettext_lazy("Maximum attachment size in bytes (or KB, MB, GB if specified)"))
|
||||
|
||||
parameters.register_user("MESSAGES_PER_PAGE", type="int", deflt=40,
|
||||
label=ugettext_lazy("Number of displayed emails per page"),
|
||||
help=ugettext_lazy("Sets the maximum number of messages displayed in a page"))
|
||||
parameters.register_user("REFRESH_INTERVAL", type="int", deflt=300,
|
||||
label=ugettext_lazy("Listing refresh rate"),
|
||||
help=ugettext_lazy("Automatic folder refresh rate (in seconds)"))
|
||||
parameters.register_user("TRASH_FOLDER", type="string", deflt="Trash",
|
||||
label=ugettext_lazy("Trash folder"),
|
||||
help=ugettext_lazy("Folder where deleted messages go"))
|
||||
parameters.register_user("SENT_FOLDER", type="string", deflt="Sent",
|
||||
label=ugettext_lazy("Sent folder"),
|
||||
help=ugettext_lazy("Folder where copies of sent messages go"))
|
||||
parameters.register_user("DRAFTS_FOLDER", type="string", deflt="Drafts",
|
||||
label=ugettext_lazy("Drafts folder"),
|
||||
help=ugettext_lazy("Folder where drafts go"))
|
||||
parameters.register_user("SIGNATURE", type="text", deflt="",
|
||||
label=ugettext_lazy("Signature text"),
|
||||
help=ugettext_lazy("User defined email signature"))
|
||||
parameters.register_user("EDITOR", type="list", deflt="plain",
|
||||
label=ugettext_lazy("Default editor"),
|
||||
values=[("html", "html"), ("plain", "text")],
|
||||
help=ugettext_lazy("The default editor to use when composing a message"))
|
||||
parameters.register_user("DISPLAYMODE", type="list", deflt="plain",
|
||||
label=ugettext_lazy("Default message display mode"),
|
||||
values=[("html", "html"), ("plain", "text")],
|
||||
help=ugettext_lazy("The default mode used when displaying a message"))
|
||||
parameters.register_user("ENABLE_LINKS", type="list_yesno", deflt="no",
|
||||
label=ugettext_lazy("Enable HTML links display"),
|
||||
help=ugettext_lazy("Enable/Disable HTML links display"))
|
||||
|
||||
parameters.register_admin("IMAP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your IMAP server"))
|
||||
parameters.register_admin("IMAP_SECURED", type="list_yesno",
|
||||
deflt="no",
|
||||
help=ugettext_lazy("Use a secured connection to access IMAP server"))
|
||||
parameters.register_admin("IMAP_PORT", type="int", deflt="143",
|
||||
help=ugettext_lazy("Listening port of your IMAP server"))
|
||||
parameters.register_admin("SMTP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your SMTP server"))
|
||||
parameters.register_admin("SMTP_SECURED_MODE", type="list",
|
||||
values=[("none", ugettext_lazy("None")),
|
||||
("starttls", "STARTTLS"),
|
||||
("ssl", "SSL/TLS")],
|
||||
deflt="none",
|
||||
help=ugettext_lazy("Use a secured connection to access SMTP server"))
|
||||
parameters.register_admin("SMTP_PORT", type="int", deflt="25",
|
||||
help=ugettext_lazy("Listening port of your SMTP server"))
|
||||
parameters.register_admin("SMTP_AUTHENTICATION", type="list_yesno",
|
||||
deflt="no",
|
||||
help=ugettext_lazy("Server needs authentication"))
|
||||
parameters.register_admin("MAX_ATTACHMENT_SIZE", type="int", deflt=2048,
|
||||
help=ugettext_lazy("Maximum attachment size in bytes (or KB, MB, GB if specified)"))
|
||||
|
||||
parameters.register_user("MESSAGES_PER_PAGE", type="int", deflt=40,
|
||||
label=ugettext_lazy("Number of displayed emails per page"),
|
||||
help=ugettext_lazy("Sets the maximum number of messages displayed in a page"))
|
||||
parameters.register_user("REFRESH_INTERVAL", type="int", deflt=300,
|
||||
label=ugettext_lazy("Listing refresh rate"),
|
||||
help=ugettext_lazy("Automatic folder refresh rate (in seconds)"))
|
||||
parameters.register_user("TRASH_FOLDER", type="string", deflt="Trash",
|
||||
label=ugettext_lazy("Trash folder"),
|
||||
help=ugettext_lazy("Folder where deleted messages go"))
|
||||
parameters.register_user("SENT_FOLDER", type="string", deflt="Sent",
|
||||
label=ugettext_lazy("Sent folder"),
|
||||
help=ugettext_lazy("Folder where copies of sent messages go"))
|
||||
parameters.register_user("DRAFTS_FOLDER", type="string", deflt="Drafts",
|
||||
label=ugettext_lazy("Drafts folder"),
|
||||
help=ugettext_lazy("Folder where drafts go"))
|
||||
parameters.register_user("SIGNATURE", type="text", deflt="",
|
||||
label=ugettext_lazy("Signature text"),
|
||||
help=ugettext_lazy("User defined email signature"))
|
||||
parameters.register_user("EDITOR", type="list", deflt="plain",
|
||||
label=ugettext_lazy("Default editor"),
|
||||
values=[("html", "html"), ("plain", "text")],
|
||||
help=ugettext_lazy("The default editor to use when composing a message"))
|
||||
parameters.register_user("DISPLAYMODE", type="list", deflt="plain",
|
||||
label=ugettext_lazy("Default message display mode"),
|
||||
values=[("html", "html"), ("plain", "text")],
|
||||
help=ugettext_lazy("The default mode used when displaying a message"))
|
||||
parameters.register_user("ENABLE_LINKS", type="list_yesno", deflt="no",
|
||||
label=ugettext_lazy("Enable HTML links display"),
|
||||
help=ugettext_lazy("Enable/Disable HTML links display"))
|
||||
def destroy(self):
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("webmail")
|
||||
|
||||
def destroy():
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
parameters.unregister_app("webmail")
|
||||
|
||||
def infos():
|
||||
return {
|
||||
"name" : "Webmail",
|
||||
"version" : "1.0",
|
||||
"description" : _("Simple IMAP webmail"),
|
||||
"url" : "webmail"
|
||||
}
|
||||
exts_pool.register_extension(Webmail)
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
|
||||
@@ -25,7 +25,7 @@ class WMtable(tables.Table):
|
||||
idkey = "imapid"
|
||||
select = tables.ImgColumn(
|
||||
"select", cssclass="draggable left", width="1%",
|
||||
defvalue="%spics/grippy.png" % settings.MEDIA_URL,
|
||||
defvalue="%spics/grippy.png" % settings.STATIC_URL,
|
||||
header="<input type='checkbox' name='toggleselect' id='toggleselect' />"
|
||||
)
|
||||
flags = tables.ImgColumn("flags", width="4%")
|
||||
@@ -458,9 +458,8 @@ def find_images_in_body(body):
|
||||
if src is None:
|
||||
continue
|
||||
o = urlparse(src)
|
||||
dirname = os.path.dirname(o.path).replace(settings.MEDIA_URL, "")
|
||||
fname = os.path.basename(o.path)
|
||||
path = os.path.join(settings.MEDIA_ROOT, dirname, fname)
|
||||
path = os.path.join(settings.MEDIA_ROOT, "webmail", fname)
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
cid = "%s@modoboa" % os.path.splitext(fname)[0]
|
||||
@@ -504,7 +503,7 @@ def save_attachment(f):
|
||||
"""
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
dstdir = os.path.join(settings.MEDIA_ROOT, "tmp")
|
||||
dstdir = os.path.join(settings.MEDIA_ROOT, "webmail")
|
||||
try:
|
||||
fp = NamedTemporaryFile(dir=dstdir, delete=False)
|
||||
except Exception, e:
|
||||
@@ -521,7 +520,7 @@ def clean_attachments(attlist):
|
||||
(random name, real name).
|
||||
"""
|
||||
for att in attlist:
|
||||
fullpath = os.path.join(settings.MEDIA_ROOT, "tmp", att["tmpname"])
|
||||
fullpath = os.path.join(settings.MEDIA_ROOT, "webmail", att["tmpname"])
|
||||
try:
|
||||
os.remove(fullpath)
|
||||
except OSError, e:
|
||||
@@ -569,7 +568,7 @@ def create_mail_attachment(attdef):
|
||||
|
||||
maintype, subtype = attdef["content-type"].split("/")
|
||||
res = MIMEBase(maintype, subtype)
|
||||
fp = open(os.path.join(settings.MEDIA_ROOT, "tmp", attdef["tmpname"]), "rb")
|
||||
fp = open(os.path.join(settings.MEDIA_ROOT, "webmail", attdef["tmpname"]), "rb")
|
||||
res.set_payload(fp.read())
|
||||
fp.close()
|
||||
Encoders.encode_base64(res)
|
||||
|
||||
+1
-1
@@ -813,7 +813,7 @@ Webmail.prototype = {
|
||||
CKEDITOR.remove(instance);
|
||||
}
|
||||
CKEDITOR.replace(this.editorid, {
|
||||
customConfig: static_url("js/editor_config.js")
|
||||
customConfig: get_static_url("js/editor_config.js")
|
||||
});
|
||||
CKEDITOR.on("instanceReady", $.proxy(function(evt) {
|
||||
this.resize_editor();
|
||||
@@ -6,7 +6,7 @@
|
||||
<input type="button" class="btn btn-primary" id="submit" name="submit" value="{% trans 'Attach' %}" />
|
||||
</div>
|
||||
<div id="upload_status" style="display:none">
|
||||
<img src="{{ MEDIA_URL }}css/spinner.gif" /> {% trans "Uploading.." %}
|
||||
<img src="{{ STATIC_URL }}css/spinner.gif" /> {% trans "Uploading.." %}
|
||||
</div>
|
||||
<iframe id="upload_target" name="upload_target" src="#"
|
||||
style="width:0;height:0;border:0px solid #fff;"></iframe>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% render_field form.subject %}
|
||||
<div id="attachments" name="{% url modoboa.extensions.webmail.views.attachments %}">
|
||||
<div>
|
||||
<img src="{{ MEDIA_URL }}pics/attachment.png" />
|
||||
<img src="{{ STATIC_URL }}pics/attachment.png" />
|
||||
{% trans "Attachments" %}
|
||||
</div>
|
||||
<div id="list">
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{% extends "fixed.html" %}{% load i18n libextras %}
|
||||
{% block pagetitle %}Webmail{% endblock %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}webmail/css/webmail.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/ckeditor/ckeditor.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.htmltable.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/searchbar.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}webmail/js/webmail.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}webmail/css/webmail.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/ckeditor/ckeditor.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.htmltable.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/searchbar.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}webmail/js/webmail.js"></script>
|
||||
<script type="text/javascript">
|
||||
var webmail = undefined;
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ def listmailbox_menu(selection, folder, user):
|
||||
"url" : reverse(webmail.views.empty, args=[folder])}
|
||||
]
|
||||
searchbar = render_to_string('common/email_searchbar.html', {
|
||||
"MEDIA_URL" : settings.MEDIA_URL
|
||||
"STATIC_URL" : settings.STATIC_URL
|
||||
})
|
||||
return render_to_string('common/buttons_list.html', dict(
|
||||
selection=selection, entries=entries, extracontent=searchbar,
|
||||
|
||||
@@ -253,7 +253,7 @@ def delattachment(request):
|
||||
for att in request.session["compose_mail"]["attachments"]:
|
||||
if att["tmpname"] == request.GET["name"]:
|
||||
request.session["compose_mail"]["attachments"].remove(att)
|
||||
fullpath = os.path.join(settings.MEDIA_ROOT, "tmp", att["tmpname"])
|
||||
fullpath = os.path.join(settings.MEDIA_ROOT, "webmail", att["tmpname"])
|
||||
try:
|
||||
os.remove(fullpath)
|
||||
except OSError, e:
|
||||
|
||||
@@ -110,7 +110,7 @@ class EmailListing(object):
|
||||
def render_navbar(page, baseurl=None):
|
||||
if page is None:
|
||||
return ""
|
||||
context = {"page" : page, "MEDIA_URL" : settings.MEDIA_URL, "baseurl" : baseurl}
|
||||
context = {"page" : page, "STATIC_URL" : settings.STATIC_URL, "baseurl" : baseurl}
|
||||
return render_to_string("common/pagination_bar.html", context)
|
||||
|
||||
def fetch(self, request, id_start, id_stop):
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ def _render(request, tpl, user_context):
|
||||
"""Custom rendering function
|
||||
|
||||
Just a wrapper which automatically adds a RequestContext instance
|
||||
(useful to use settings variables like MEDIA_URL inside templates)
|
||||
(useful to use settings variables like STATIC_URL inside templates)
|
||||
"""
|
||||
return render_to_response(tpl, user_context,
|
||||
context_instance=template.RequestContext(request))
|
||||
@@ -109,7 +109,7 @@ def static_url(path):
|
||||
"""
|
||||
if path.startswith("/"):
|
||||
path = path[1:]
|
||||
return "%s%s" % (settings.MEDIA_URL, path)
|
||||
return "%s%s" % (settings.STATIC_URL, path)
|
||||
|
||||
def size2integer(value):
|
||||
"""Try to convert a string representing a size to an integer value
|
||||
|
||||
+6
-2
@@ -64,12 +64,15 @@ LOGIN_REDIRECT_URL = '/modoboa/admin/'
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = os.path.join(MODOBOA_DIR, 'static')
|
||||
MEDIA_ROOT = os.path.join(MODOBOA_DIR, 'media')
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
MEDIA_URL = '/static/'
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
STATIC_ROOT = os.path.join(MODOBOA_DIR, 'sitestatic')
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||
# trailing slash.
|
||||
@@ -112,6 +115,7 @@ INSTALLED_APPS = (
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'south',
|
||||
'modoboa',
|
||||
'modoboa.auth',
|
||||
|
||||
+5
-5
@@ -2,22 +2,22 @@
|
||||
* Global javascript utilities
|
||||
*/
|
||||
|
||||
var media_url = "";
|
||||
var static_url = "";
|
||||
|
||||
/*
|
||||
* A simple function to initialize the value of the global variable
|
||||
* 'media_url' (corresponding to django's MEDIA_URL variable).
|
||||
*/
|
||||
function set_media_url(url) {
|
||||
media_url = url;
|
||||
function set_static_url(url) {
|
||||
static_url = url;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shortcut function that construct an url from the media_url and the
|
||||
* given value.
|
||||
*/
|
||||
function static_url(value) {
|
||||
return media_url + value;
|
||||
function get_static_url(value) {
|
||||
return static_url + value;
|
||||
}
|
||||
|
||||
function modalbox(e, css, defhref, defcb, defclosecb) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "twocols.html" %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/admin.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/admin.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/admin.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/admin.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
{% block pagetitle %}{% trans "Identities" %}{% endblock %}
|
||||
{% block html_head %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/creation_wizard.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/autocompleter.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/creation_wizard.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/autocompleter.js"></script>
|
||||
<script type="text/javascript">
|
||||
function get_domains_list(container) {
|
||||
$.getJSON("{% url modoboa.admin.views.domains_list %}", function(data) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<iframe id="import_target" name="import_target" src="#"
|
||||
style="width:0;height:0;border:0px solid #fff;"></iframe>
|
||||
<div id="import_status" style="text-align: center;display:none">
|
||||
<img src="{{MEDIA_URL}}css/spinner.gif" /> {% trans "Importing..." %}
|
||||
<img src="{{STATIC_URL}}css/spinner.gif" /> {% trans "Importing..." %}
|
||||
</div>
|
||||
<div id="import_result"></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "admin/header.html" %}{% load i18n admin_extras libextras %}
|
||||
{% block html_head %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/dynamic_input.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/dynamic_input.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#searchquery").focus(function() {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<th id="{{ c.name }}" width="{{ c.width }}">
|
||||
{% endif %}
|
||||
{{ c|safe }}
|
||||
<span style="float: right"><img style="display: none" alt="" src="{{ MEDIA_URL }}pics/transparent.png" /></span>
|
||||
<span style="float: right"><img style="display: none" alt="" src="{{ STATIC_URL }}pics/transparent.png" /></span>
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/viewmail.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/viewmail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="table-container">
|
||||
|
||||
+14
-14
@@ -3,23 +3,23 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{% block pagetitle %}{% endblock %}</title>
|
||||
<link rel="icon" type="image/png" href="{{ MEDIA_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/datepicker.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/custom.css" />
|
||||
<script src="{{ MEDIA_URL }}js/jquery.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap-datepicker.js" type="text/javascript"></script>
|
||||
{% if LANGUAGE_CODE != "en" %}<script src="{{ MEDIA_URL }}js/locales/bootstrap-datepicker.{{ LANGUAGE_CODE }}.js" type="text/javascript"></script>{% endif %}
|
||||
<script src="{{ MEDIA_URL }}js/global.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/confirmation.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/notify.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/poller.js" type="text/javascript"></script>
|
||||
<link rel="icon" type="image/png" href="{{ STATIC_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/datepicker.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/custom.css" />
|
||||
<script src="{{ STATIC_URL }}js/jquery.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/bootstrap-datepicker.js" type="text/javascript"></script>
|
||||
{% if LANGUAGE_CODE != "en" %}<script src="{{ STATIC_URL }}js/locales/bootstrap-datepicker.{{ LANGUAGE_CODE }}.js" type="text/javascript"></script>{% endif %}
|
||||
<script src="{{ STATIC_URL }}js/global.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/confirmation.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/notify.js" type="text/javascript"></script>
|
||||
<script src="{{ STATIC_URL }}js/poller.js" type="text/javascript"></script>
|
||||
{% url django.views.i18n.javascript_catalog as catalog_url %}
|
||||
<script type="text/javascript" src="{{ catalog_url }}"></script>
|
||||
<script type="text/javascript">
|
||||
set_media_url("{{ MEDIA_URL }}");
|
||||
set_static_url("{{ STATIC_URL }}");
|
||||
</script>
|
||||
{% extra_head_content user %}
|
||||
{% block html_head %}{% endblock %}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{% trans "Welcome to Modoboa" %}</title>
|
||||
<link rel="icon" type="image/png" href="{{ MEDIA_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/login.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/bootstrap.js"></script>
|
||||
<link rel="icon" type="image/png" href="{{ STATIC_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/login.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/bootstrap.js"></script>
|
||||
{% url django.views.i18n.javascript_catalog as catalog_url %}
|
||||
<script type="text/javascript" src="{{ catalog_url }}"></script>
|
||||
<script type="text/javascript">
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="offset4">
|
||||
<div class="row">
|
||||
<div id="logo" class="span3">
|
||||
<img src="{{ MEDIA_URL }}css/modoboa.png" />
|
||||
<img src="{{ STATIC_URL }}css/modoboa.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -14,12 +14,14 @@ urlpatterns = patterns('',
|
||||
(r'^%s$' % prefix, 'modoboa.lib.webutils.topredirection'),
|
||||
(r'^%sadmin/' % prefix, include('modoboa.admin.urls')),
|
||||
(r'^%suserprefs/' % prefix, include('modoboa.userprefs.urls')),
|
||||
(r'^%sdemo/' % prefix, include('modoboa.demo.urls')),
|
||||
(r'^%sdemo/' % prefix, include('modoboa.demo.urls')),
|
||||
(r'^%stemplot/' % prefix, include('templot.frontends.modoboa.urls')),
|
||||
(r'^accounts/login/$', 'modoboa.auth.views.dologin'),
|
||||
(r'^accounts/logout/$', 'modoboa.auth.views.dologout'),
|
||||
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog',
|
||||
{'packages': ('modoboa',),}),
|
||||
*loadextensions(prefix)
|
||||
# *loadextensions(prefix)
|
||||
*exts_pool.load_all(prefix)
|
||||
)
|
||||
|
||||
if settings.DEBUG:
|
||||
|
||||
Reference in New Issue
Block a user