This is not finished yet. More work than what I expected but the main part is done.
It will need a lot of testing... There is still a bug when activating a new extension
in development mode (ie. with python web server), I think it does not occur behind
a real web server.
This commit is contained in:
tonio
2010-05-04 17:25:23 +02:00
parent af8c33e659
commit 7480e479e7
15 changed files with 171 additions and 52 deletions
+53 -2
View File
@@ -2,7 +2,7 @@ from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from mailng.lib import parameters
from mailng.lib import exec_as_vuser
from mailng.lib import exec_cmd, exec_as_vuser
import os
class Domain(models.Model):
@@ -38,7 +38,7 @@ class Domain(models.Model):
class Mailbox(models.Model):
name = models.CharField(_('name'), max_length=100,
help_text=_("First name and last name of mailbox owner"))
address = models.CharField(_('address'), max_length=100,
address = models.CharField(_('address'), max_length=10,
help_text=_("Mailbox address (without the @domain.tld part)"))
full_address = models.CharField(max_length=150)
password = models.CharField(_('password'), max_length=100)
@@ -111,3 +111,54 @@ class Alias(models.Model):
permissions = (
("view_aliases", "View aliases"),
)
class Extension(models.Model):
name = models.CharField(max_length=150)
enabled = models.BooleanField(_('enabled'),
help_text=_("Check to enable this extension"))
has_templates = models.BooleanField()
def on(self):
from django.core.management import sql, color
from django.db import connection, models
style = color.no_style()
cursor = connection.cursor()
module = __import__("mailng.extensions.%s" % self.name,
globals(), locals(), ['main', 'models'])
try:
extmodels = module.models
except AttributeError:
extmodels = None
if extmodels is not None:
mods = []
for k, v in extmodels.__dict__.iteritems():
try:
if not issubclass(v, models.Model):
continue
statements, pending = \
connection.creation.sql_create_model(v, style)
try:
for sql in statements:
cursor.execute(sql)
except Exception, msg:
pass
except TypeError:
pass
if self.has_templates:
code, output = exec_cmd("ln -s ../extensions/%s/templates templates/%s" \
% (self.name, self.name))
module.main.init()
self.enabled = True
self.save()
def off(self):
if self.has_templates:
code, output = exec_cmd("rm -f templates/%s" % self.name)
print output
self.enabled = False
self.save()
module = __import__("mailng.extensions.%s" % self.name,
globals(), locals(), ['main', 'models'])
module.main.destroy()
-1
View File
@@ -118,7 +118,6 @@ def param(app, definition):
values = definition["values"]
value = definition.has_key("value") \
and definition["value"] or definition["default"]
print name, values
for v in values:
selected = ""
if value == v[0]:
+1
View File
@@ -20,6 +20,7 @@ urlpatterns = patterns('mailng.admin.views',
(r'^settings/addperm/$', 'addpermission'),
(r'^settings/delperm/(?P<mbox_id>\d+)/(?P<group>\w+)/$', 'deletepermission'),
(r'^settings/extensions/$', 'viewextensions'),
(r'^settings/extensions/save/$', 'saveextensions'),
(r'^settings/parameters/$', 'viewparameters'),
(r'^settings/parameters/save/$', 'saveparameters'),
)
+46 -2
View File
@@ -12,7 +12,7 @@ from django.contrib.auth.decorators \
import login_required, permission_required, user_passes_test
from django.contrib.auth.models import User, Group
from mailng import admin, main
from mailng.admin.models import Domain, Mailbox, Alias
from mailng.admin.models import Domain, Mailbox, Alias, Extension
from forms import MailboxForm, DomainForm, AliasForm, PermissionForm
from mailng.lib.authbackends import crypt_password
from mailng.lib import _render, _ctx_ok, _ctx_ko
@@ -447,6 +447,50 @@ def saveparameters(request):
@user_passes_test(lambda u: u.is_superuser)
def viewextensions(request):
from mailng.extensions import list_extensions
from mailng.lib import tables
class ExtensionsTable(tables.Table):
idkey = "id"
selection = tables.SelectionColumn("selection", width="4%", first=True)
_1_name = tables.Column("name", label=_("Name"), width="15%")
_2_version = tables.Column("version", label=_("Version"), width="6%")
_3_descr = tables.Column("description", label=_("Description"))
exts = list_extensions()
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.has_templates = ext["templates"]
dbext.save()
ext["selection"] = False
tbl = ExtensionsTable(exts)
return _render(request, 'admin/extensions.html', {
"extensions" : list_extensions()
"extensions" : tbl.render(request)
})
@login_required
@user_passes_test(lambda u: u.is_superuser)
def saveextensions(request):
from mailng import extensions
actived_exts = Extension.objects.filter(enabled=True)
found = []
for k, v in request.POST.iteritems():
if k.startswith("select_"):
parts = k.split("_", 1)
dbext = Extension.objects.get(name=parts[1])
if not dbext in actived_exts:
dbext.on()
else:
found += [dbext]
for ext in actived_exts:
if not ext in found:
ext.off()
return HttpResponseRedirect(reverse(admin.views.viewextensions))
+17 -11
View File
@@ -2,29 +2,29 @@
import os
import re
extensions = []
extensions = {}
def loadextensions():
from django.conf import settings
from admin.models import Extension
expr = re.compile("mailng\.extensions\.(.+)")
for app in settings.INSTALLED_APPS:
m = expr.match(app)
if not m:
continue
module = __import__(m.group(1), globals(), locals(), ['main'])
exts = Extension.objects.filter(enabled=True)
for ext in exts:
module = __import__(ext.name, globals(), locals(), ['main'])
module.main.init()
globals()['extensions'] += [module]
globals()['extensions'][ext] = module
def loadmenus():
result = []
for mod in extensions:
for name, mod in extensions.iteritems():
u = mod.main.urls()
if u == ():
continue
result += (u,)
return result
def isenabled(ext):
return extensions.has_key(ext)
def list_extensions():
basedir = "extensions"
result = []
@@ -39,7 +39,13 @@ def list_extensions():
if isvalid:
module = __import__(d, globals(), locals(), ['main'])
try:
result += [module.main.infos()]
infos = module.main.infos()
infos["id"] = d
if os.path.isdir("%s/%s/templates" % (basedir, d)):
infos["templates"] = True
else:
infos["templates"] = False
result += [infos]
except AttributeError:
pass
return result
+4
View File
@@ -46,6 +46,10 @@ def init():
"/var/amavis/amavisd.sock",
help="")
def destroy():
events.unregister("UserMenuDisplay", menu)
parameters.unregister_app("amavis_quarantine")
def urls():
return (r'^mailng/quarantine/',
include('mailng.extensions.amavis_quarantine.urls'))
+3
View File
@@ -41,6 +41,9 @@ def init():
parameters.register("stats", "IMG_ROOTDIR", "string", "/tmp/mailng",
help=_("Path to directory where PNG files are stored"))
def destroy():
events.unregister("AdminMenuDisplay", menu)
def urls():
return (r'^mailng/stats/',
include('mailng.extensions.stats.urls'))
-1
View File
@@ -16,7 +16,6 @@ from mailng.lib import tables, imap_utf7, parameters
class WMtable(tables.Table):
tableid = "emails"
idkey = "imapid"
# selection = tables.SelectionColumn("selection", width="20px", first=True)
_1_flags = tables.ImgColumn("flags", width="4%",
header="<input type='checkbox' name='toggleselect' id='toggleselect' />")
_2_subject = tables.Column("subject", label=_("Subject"),
+5 -2
View File
@@ -34,6 +34,11 @@ def init():
parameters.register("webmail", "SMTP_SECURED", "list_yesno", "no",
help=_("Use a secured connection to access SMTP server"))
def destroy():
events.unregister("UserMenuDisplay", menu)
events.unregister("UserLogin", userlogin)
parameters.unregister_app("webmail")
def infos():
return {
"name" : "Webmail",
@@ -139,14 +144,12 @@ def viewmail(request, folder, mail_id=None):
def getmailcontent(request, folder, mail_id):
msg = fetchmail(request, folder, mail_id, True)
if "class" in msg.keys() and msg["class"] == "unseen":
#IMAPconnector(request).msg_read(*msg["imapid"].split("/"))
IMAPconnector(request).msg_read(folder, mail_id)
email = ImapEmail(msg, mode="html", links="1")
try:
pageid = request.session["page"]
except KeyError:
pageid = "1"
#folder, imapid = msg["imapid"].split("/")
return _render(request, "common/viewmail.html", {
"headers" : email.render_headers(folder, mail_id),
"folder" : folder, "imapid" : mail_id, "mailbody" : email.body,
+7
View File
@@ -27,6 +27,13 @@ def register(event, callback):
callbacks[event].append(callback)
return 1
def unregister(event, callback):
if not event in events:
return False
if not callbacks.has_key(event):
return False
callbacks[event].remove(callback)
def raiseEvent(event, **kwargs):
if not event in events or not event in callbacks.keys():
return 0
+6
View File
@@ -35,6 +35,12 @@ def register(app, name, type="string", deflt=None, help=None, **kwargs):
for k, v in kwargs.iteritems():
_params[app][name][k] = v
def unregister_app(app):
if not _params.has_key(app):
return False
del _params[app]
return True
def save(app, name, value):
if not app in _params.keys() or not name in _params[app].keys():
raise NotDefined(app, name)
+20 -24
View File
@@ -19,13 +19,14 @@ class Column:
label = getattr(self, "name")
return label
class SelectionColumn(Column):
def __str__(self):
return "<input type='checkbox' name='selectall' id='selectall' />"
def render(self, value):
return "<input type='checkbox' name='%s' value='%s' />" \
% (self.name, value)
def render(self, value, selection):
return "<input type='checkbox' id='%s' name='select_%s' value='%s' %s/>" \
% (self.name, value, value, selection and "checked" or "")
class ImgColumn(Column):
sortable = False
@@ -56,33 +57,28 @@ class Table(object):
nrow = {"id" : row[self.idkey], "cols" : []}
for c in self.columns:
newcol = {"name" : c.name}
try:
newcol["width"] = getattr(c, "width")
except AttributeError:
pass
try:
newcol["align"] = getattr(c, "align")
except:
pass
for key in ["width", "align", "cssclass"]:
try:
newcol[key] = getattr(c, key)
except AttributeError:
newcol[key] = ""
if isinstance(c, SelectionColumn):
newcol["value"] = c.render(row[self.idkey])
newcol["safe"] = True
if isinstance(c, ImgColumn):
selection = row.has_key(c.name) and row[c.name] or False
newcol["value"] = c.render(row[self.idkey], selection)
newcol["safe"] = True
elif isinstance(c, ImgColumn):
key = "img_%s" % c.name
if key in row.keys():
newcol["value"] = c.render(row[key])
newcol["safe"] = True
if row.has_key(c.name):
try:
cssclass = getattr(c, "cssclass")
except AttributeError:
cssclass = ""
elif row.has_key(c.name):
if "class" in row.keys():
cssclass += (cssclass != "") and ", %s" % row["class"] or row["class"]
newcol["value"] = self.parse(c.name, row[c.name])
newcol["class"] = cssclass
newcol["cssclass"] += newcol["cssclass"] != "" \
and ", %s" % row["class"] or row["class"]
try:
newcol["value"] = self.parse(c.name, row[c.name])
except AttributeError:
newcol["value"] = row[c.name]
nrow["cols"] += [newcol]
self.rows += [nrow]
+5 -6
View File
@@ -5,10 +5,9 @@
{% endblock %}
{% block setcontent %}
{% load i18n %}
<table>
<tr><th>{% trans "Name" %}</th><th>{% trans "Version" %}</th><th>{% trans "Description" %}</th></tr>
{% for ext in extensions %}
<tr><td>{{ ext.name }}</td><td>{{ ext.version }}</td><td>{{ ext.description }}</td></tr>
{% endfor %}
</table>
<form method="POST" action="{% url admin.views.saveextensions %}">
{{ extensions }}
<br />
<input type="submit" name="apply" value="{% trans "Apply" %}" />
</form>
{% endblock %}
+1 -1
View File
@@ -2,7 +2,7 @@
{% for row in table.rows %}
<tr id="{{ row.id }}" class="{% cycle 'odd' 'even' %}">
{% for cell in row.cols %}
<td name="{{ cell.name }}" width="{{ cell.width }}" align="{{ cell.align }}" class="{{ cell.class }}">
<td name="{{ cell.name }}" width="{{ cell.width }}" align="{{ cell.align }}" class="{{ cell.cssclass }}">
{% if cell.safe %}{{ cell.value|safe }}{% else %}{{ cell.value }}{% endif %}
</td>
{% endfor %}
+3 -2
View File
@@ -5,7 +5,7 @@ from django.conf import settings
# from django.contrib import admin
# admin.autodiscover()
from mailng.extensions import loadextensions, loadmenus
from mailng.extensions import loadextensions, loadmenus, isenabled
from mailng.lib import parameters
loadextensions()
@@ -27,6 +27,7 @@ urlpatterns = patterns('',
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog',
{'packages': ('mailng',),})
)
menus = loadmenus()
if menus != ():
urlpatterns += patterns('', *menus)
@@ -38,7 +39,7 @@ if settings.DEBUG:
{'document_root': settings.STATIC_ROOTDIR})
)
# Stats
if 'mailng.extensions.stats' in settings.INSTALLED_APPS:
if isenabled('stats'):
urlpatterns += patterns(
'',
(r'^img/stats/(?P<path>.*)/$', 'django.views.static.serve',