mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Important update of the plugin engine.
New plugin that allows the handling of an Amavisd-new SQL quarantine. NB: a DB connections manager has been added inside the lib because Django does not support multiple connections at the same time. The main consequence is that we don't use an ORM and that we have to rewrite a small wrapper that supports several DB (mysql, postgresql, etc.). Adding a dependancy to an existing ORM module (like SQLalchemy) is heavy, we don't want that for now.
This commit is contained in:
+2
-1
@@ -16,7 +16,8 @@ class MailboxForm(forms.ModelForm):
|
||||
quota = forms.IntegerField(label=_("Quota"), required=False)
|
||||
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
|
||||
password2 = forms.CharField(label=_("Confirmation"), widget=forms.PasswordInput)
|
||||
enabled = forms.BooleanField(label=gender("Enabled", "f"), required=False)
|
||||
enabled = forms.BooleanField(label=gender("Enabled", "f"), required=False,
|
||||
initial=True)
|
||||
|
||||
class Meta:
|
||||
model = Mailbox
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ class Domain(models.Model):
|
||||
|
||||
def create_dir(self):
|
||||
path = "%s/%s" % (settings.STORAGE_PATH, self.name)
|
||||
return exec_as_vuser("mkdir %s" % path)
|
||||
return exec_as_vuser("mkdir -p %s" % path)
|
||||
|
||||
def rename_dir(self, newname):
|
||||
code, output = exec_pipe("sudo -u %s mv %s/%s %s/%s" \
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
extensions = []
|
||||
|
||||
def loadextensions():
|
||||
from django.conf import settings
|
||||
|
||||
@@ -12,3 +14,10 @@ def loadextensions():
|
||||
continue
|
||||
module = __import__(m.group(1), globals(), locals(), ['main'])
|
||||
module.main.init()
|
||||
globals()['extensions'] += [module]
|
||||
|
||||
def loadmenus():
|
||||
result = ()
|
||||
for mod in extensions:
|
||||
result += mod.main.urls()
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
"""
|
||||
from django.shortcuts import get_object_or_404, render_to_response
|
||||
from django.conf.urls.defaults import *
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.paginator import Paginator
|
||||
from mailng.lib import events
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib import db
|
||||
from mailng.admin.models import Mailbox
|
||||
|
||||
def init():
|
||||
events.register("UserMenuDisplay", menu)
|
||||
|
||||
def urls():
|
||||
return (r'^mailng/quarantine/',
|
||||
include('mailng.extensions.amavis_quarantine.urls'))
|
||||
|
||||
def menu(**kwargs):
|
||||
return [
|
||||
{"name" : _("Quarantine"),
|
||||
"url" : reverse(index),
|
||||
"img" : "/static/pics/quarantine.png"}
|
||||
]
|
||||
|
||||
def index(request):
|
||||
if not request.user.is_superuser:
|
||||
mb = Mailbox.objects.get(user=request.user.id)
|
||||
filter = "AND maddr.email='%s'" % mb.full_address
|
||||
else:
|
||||
filter = ""
|
||||
cursor = db.getconnection("amavis_quarantine").cursor()
|
||||
cursor.execute("""
|
||||
SELECT msgs.from_addr, maddr.email, msgs.subject, msgs.content, quarantine.mail_id
|
||||
FROM quarantine, maddr, msgrcpt, msgs
|
||||
WHERE quarantine.mail_id=msgrcpt.mail_id
|
||||
AND msgrcpt.rid=maddr.id
|
||||
AND msgrcpt.mail_id=msgs.mail_id
|
||||
AND quarantine.chunk_ind=1
|
||||
%s
|
||||
""" % filter)
|
||||
emails = []
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
emails.append({"from" : row[0], "to" : row[1],
|
||||
"subject" : row[2], "content" : row[3],
|
||||
"mailid" : row[4]})
|
||||
|
||||
# cursor.execute("SELECT count(*) AS cnt FROM quarantine")
|
||||
# row = cursor.fetchone()
|
||||
# cnt = row[0]
|
||||
|
||||
paginator = Paginator(emails, 10)
|
||||
try:
|
||||
pagenum = int(request.GET.get('page', '1'))
|
||||
except ValueError:
|
||||
pagenum = 1
|
||||
page = paginator.page(pagenum)
|
||||
return _render(request, 'amavis_quarantine/index.html', {
|
||||
"count" : len(rows), "emails" : page
|
||||
})
|
||||
@@ -0,0 +1,71 @@
|
||||
{% extends "layout.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="/static/stylesheets/box.css" />
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<style type="text/css">
|
||||
#quarmenu {
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
#navbar {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#actionbar {
|
||||
float: left;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: smaller;
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header">
|
||||
<h1>{% trans "Quarantine" %}</h1>
|
||||
{% if messages %}
|
||||
<div id="infos">
|
||||
{% for m in messages %}
|
||||
{{ m }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div id="subcontent">
|
||||
<b> Il y a {{ count }} messages dans la quarantaine.</b>
|
||||
|
||||
<div id="quarmenu">
|
||||
<div id="actionbar">
|
||||
<input type="button" name="release" value="{% trans "Release" %}" />
|
||||
<input type="button" name="delete" value="{% trans "Delete" %}" />
|
||||
<input type="button" name="deleteall" value="{% trans "Delete all" %}" />
|
||||
</div>
|
||||
<div id="navbar">
|
||||
{% if emails.has_previous %}
|
||||
<a href="?page={{ emails.previous_page_number }}">{% trans "Previous" %}</a>
|
||||
{% endif %}
|
||||
{% if emails.has_next %}
|
||||
<a href="?page={{ emails.next_page_number }}">{% trans "Next" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th width="150px">{% trans "From" %}</th>
|
||||
<th width="150px">{% trans "To" %}</th>
|
||||
<th>{% trans "Subject" %}</th>
|
||||
</tr>
|
||||
{% for m in emails.object_list %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<td><input type="checkbox" name="selection" id="selection" /></td>
|
||||
<td>{{ m.from }}</td><td>{{ m.to }}</td><td>{{ m.subject }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mailng.extensions.amavis_quarantine.main',
|
||||
(r'^$', 'index'),
|
||||
)
|
||||
@@ -16,6 +16,9 @@ def init():
|
||||
events.register("CreateMailbox", onCreateMailbox)
|
||||
events.register("DeleteMailbox", onDeleteMailbox)
|
||||
|
||||
def urls():
|
||||
return ()
|
||||
|
||||
def onCreateDomain(**kwargs):
|
||||
dom = kwargs["dom"]
|
||||
transport = Transport()
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
connections = {}
|
||||
|
||||
def mysql_newconnection(host, dbname, login, password):
|
||||
import MySQLdb
|
||||
return MySQLdb.connect(host=host, db=dbname, user=login, passwd=password)
|
||||
|
||||
def getconnection(name):
|
||||
if not name in connections.keys():
|
||||
from django.conf import settings
|
||||
|
||||
cfg = settings.DB_CONNECTIONS[name]
|
||||
if cfg["driver"] == "mysql":
|
||||
conn = mysql_newconnection(cfg["host"], cfg["dbname"], cfg["login"],
|
||||
cfg["password"])
|
||||
connections[name] = conn
|
||||
return connections[name]
|
||||
|
||||
+11
-1
@@ -9,7 +9,9 @@ core application and additional components.
|
||||
events = ["CreateDomain",
|
||||
"DeleteDomain",
|
||||
"CreateMailbox",
|
||||
"DeleteMailbox"]
|
||||
"DeleteMailbox",
|
||||
|
||||
"UserMenuDisplay"]
|
||||
|
||||
callbacks = {}
|
||||
|
||||
@@ -27,3 +29,11 @@ def raiseEvent(event, **kwargs):
|
||||
for callback in callbacks[event]:
|
||||
callback(**kwargs)
|
||||
return 1
|
||||
|
||||
def raiseQueryEvent(event, **kwargs):
|
||||
result = []
|
||||
if not event in events or not event in callbacks.keys():
|
||||
return result
|
||||
for callback in callbacks[event]:
|
||||
result += callback(**kwargs)
|
||||
return result
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
from django import template
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from mailng import main
|
||||
from mailng.lib import events
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def menu(selection, perms):
|
||||
entries = [
|
||||
{"name" : "autoreply",
|
||||
"url" : reverse(main.views.autoreply),
|
||||
"img" : "/static/pics/auto-reply.png",
|
||||
"label" : _("Auto-reply message")},
|
||||
{"name" : "changepwd",
|
||||
"url" : reverse(main.views.changepassword),
|
||||
"img" : "/static/pics/edit.png",
|
||||
"label" : _("Change password"),
|
||||
"class" : "boxed",
|
||||
"rel" : "{handler:'iframe',size:{x:350,y:220}}"}
|
||||
]
|
||||
|
||||
return render_to_string('main/menu.html',
|
||||
{"selection" : selection, "perms" : perms})
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"perms" : perms})
|
||||
|
||||
@register.simple_tag
|
||||
def loadextmenu(perms):
|
||||
menu = events.raiseQueryEvent("UserMenuDisplay")
|
||||
return render_to_string('main/menulist.html',
|
||||
{"menu" : menu, "perms" : perms})
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 564 B |
@@ -59,7 +59,6 @@ body {
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin: 15px 0;
|
||||
/*height: 600px;*/
|
||||
}
|
||||
|
||||
#loginbox {
|
||||
@@ -129,11 +128,11 @@ body {
|
||||
#content {
|
||||
float: right;
|
||||
width: 750px;
|
||||
height: 400px;
|
||||
background: white;
|
||||
border: 1px solid #333;
|
||||
padding: 5px;
|
||||
margin: 0 0 0 15px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
#content2 {
|
||||
|
||||
@@ -18,7 +18,7 @@ div.row label {
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
form input {
|
||||
input {
|
||||
border: 1px solid #cccccc;
|
||||
color: inherit;
|
||||
/*background-color: #e9e9e9;*/
|
||||
@@ -26,7 +26,7 @@ form input {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
form input:hover {
|
||||
input:hover {
|
||||
color: inherit;
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{% load i18n %}
|
||||
{% load main_extras %}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
@@ -47,6 +48,7 @@
|
||||
<img src="/static/pics/user.png" border="0" />{% trans "Preferences" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% loadextmenu perms %}
|
||||
<li>
|
||||
{% url django.contrib.auth.views.logout_then_login as logout_url %}
|
||||
<a href="{{ logout_url }}">
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
{% load i18n %}
|
||||
<ul>
|
||||
<li {% ifequal selection "autoreply" %}class="selected"{% endifequal %}>
|
||||
{% url main.views.autoreply as ar_url %}
|
||||
<a href="{{ ar_url }}"><img src="/static/pics/auto-reply.png" border="0"/>
|
||||
{% trans "Auto-reply message" %}
|
||||
{% for entry in entries %}
|
||||
<li {% ifequal selection entry.name %}class="selected"{% endifequal %}>
|
||||
<a href="{{ entry.url }}"
|
||||
{% if entry.class %}class={{ entry.class }}{% endif %}
|
||||
{% if entry.rel %}rel={{ entry.rel }}{% endif %}>
|
||||
<img src="{{ entry.img }}" border="0" />
|
||||
{{ entry.label }}
|
||||
</a>
|
||||
</li>
|
||||
{% url main.views.changepassword as chpwd_url %}
|
||||
<li><a href="{{ chpwd_url }}"
|
||||
class="boxed" rel="{handler:'iframe',size:{x:350,y:220}}">
|
||||
<img src="/static/pics/edit.png" border="0"/>
|
||||
{% trans "Change password" %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -5,7 +5,7 @@ from django.conf import settings
|
||||
# from django.contrib import admin
|
||||
# admin.autodiscover()
|
||||
|
||||
from mailng.extensions import loadextensions
|
||||
from mailng.extensions import loadextensions, loadmenus
|
||||
loadextensions()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
@@ -26,6 +26,7 @@ urlpatterns = patterns('',
|
||||
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog',
|
||||
{'packages': ('mailng',),})
|
||||
)
|
||||
urlpatterns += patterns('', loadmenus())
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += patterns(
|
||||
|
||||
Reference in New Issue
Block a user