mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Against : webmail navigation improvement...
It's now possible to write and send text emails.
This commit is contained in:
@@ -16,6 +16,12 @@ class Qtable(tables.Table):
|
||||
def parse_date(self, value):
|
||||
return datetime.fromtimestamp(value)
|
||||
|
||||
def parse(self, header, value):
|
||||
try:
|
||||
return getattr(self, "parse_%s" % header)(value)
|
||||
except AttributeError:
|
||||
return value
|
||||
|
||||
class SQLconnector(MBconnector):
|
||||
def __init__(self, filter=None):
|
||||
self.conn = db.getconnection("amavis_quarantine")
|
||||
@@ -76,10 +82,8 @@ LIMIT %d,%d
|
||||
|
||||
class SQLlisting(EmailListing):
|
||||
tpl = "amavis_quarantine/index.html"
|
||||
tbltype = Qtable
|
||||
|
||||
def __init__(self, filter, **kwargs):
|
||||
self.mbc = SQLconnector(filter)
|
||||
EmailListing.__init__(self, **kwargs)
|
||||
|
||||
def fetch(self, id_start, id_stop):
|
||||
return Qtable(self.mbc.fetch(start=id_start, stop=id_stop))
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
class ComposeMailForm(forms.Form):
|
||||
from_ = forms.CharField(label=_("From"))
|
||||
to = forms.CharField(label=_("To"), widget=forms.Textarea())
|
||||
subject = forms.CharField(label=_("Subject"), max_length=255)
|
||||
|
||||
@@ -119,6 +119,10 @@ class IMAPconnector(MBconnector):
|
||||
result += [name]
|
||||
return sorted(result)
|
||||
|
||||
def msgseen(self, imapid):
|
||||
folder, id = imapid.split("/")
|
||||
self.m.store(id, "+FLAGS", "\\Seen")
|
||||
|
||||
def fetch(self, start=None, stop=None, folder=None, all=False):
|
||||
if not start and not stop:
|
||||
return []
|
||||
@@ -155,9 +159,10 @@ class IMAPconnector(MBconnector):
|
||||
|
||||
class ImapListing(EmailListing):
|
||||
tpl = "webmail/index.html"
|
||||
tbltype = WMtable
|
||||
|
||||
def __init__(self, user, password, baseurl=None, **kwargs):
|
||||
self.mbc = IMAPconnector(parameters.get("webmail", "SERVER_ADDRESS"), 143)
|
||||
self.mbc = IMAPconnector(parameters.get("webmail", "IMAP_SERVER"), 143)
|
||||
status, text = self.mbc.login(user, password)
|
||||
if not status:
|
||||
print "Login error: %s" % text
|
||||
@@ -175,7 +180,3 @@ class ImapListing(EmailListing):
|
||||
for fd in folders:
|
||||
md_folders += [{"name" : fd}]
|
||||
return md_folders
|
||||
|
||||
def fetch(self, id_start, id_stop):
|
||||
return WMtable(self.mbc.fetch(start=id_start, stop=id_stop,
|
||||
folder=self.folder))
|
||||
|
||||
+70
-27
@@ -11,12 +11,18 @@ from mailng.admin.models import Mailbox
|
||||
from mailng.lib import events, parameters
|
||||
from mailng.lib import _render
|
||||
from imap_listing import *
|
||||
from forms import *
|
||||
from templatetags.webextras import *
|
||||
|
||||
mbc = None
|
||||
|
||||
def init():
|
||||
events.register("UserMenuDisplay", menu)
|
||||
events.register("UserLogin", userlogin)
|
||||
parameters.register("webmail", "SERVER_ADDRESS", "string", "127.0.0.1",
|
||||
help=_("Mailboxes server address"))
|
||||
parameters.register("webmail", "IMAP_SERVER", "string", "127.0.0.1",
|
||||
help=_("Address of your IMAP server"))
|
||||
parameters.register("webmail", "SMTP_SERVER", "string", "127.0.0.1",
|
||||
help=_("Address of your SMTP server"))
|
||||
|
||||
def urls():
|
||||
return (r'^mailng/webmail/',
|
||||
@@ -34,32 +40,40 @@ def menu(**kwargs):
|
||||
def userlogin(**kwargs):
|
||||
kwargs["request"].session["password"] = kwargs["password"]
|
||||
|
||||
def folder_ajax(request, name, pageid, menu=False):
|
||||
lst = ImapListing(request.user.username, request.session["password"],
|
||||
reverse(folder, args=[name]), folder=name)
|
||||
page = lst.paginator.getpage(pageid)
|
||||
if page:
|
||||
content = lst.fetch(request, page.id_start, page.id_stop)
|
||||
navbar = lst.render_navbar(page)
|
||||
else:
|
||||
content = "Empty folder"
|
||||
navbar = ""
|
||||
ctx = {"status" : "ok", "listing" : content, "navbar" : navbar}
|
||||
if menu or "menu" in request.GET.keys():
|
||||
from templatetags.webextras import listing_menu
|
||||
ctx["menu"] = listing_menu("", request.user.get_all_permissions())
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
|
||||
@login_required
|
||||
def folder(request, name=None):
|
||||
if not name:
|
||||
name = "INBOX"
|
||||
pageid = request.GET.has_key("page") and int(request.GET["page"]) or 1
|
||||
request.session["folder"] = name
|
||||
request.session["page"] = pageid
|
||||
if "mode" in request.GET.keys() and request.GET["mode"] == "ajax":
|
||||
return folder_ajax(request, name, pageid)
|
||||
lst = ImapListing(request.user.username, request.session["password"],
|
||||
reverse(folder, args=[name]), folder=name)
|
||||
pageid = request.GET.has_key("page") and int(request.GET["page"]) or 1
|
||||
if "mode" in request.GET.keys() and request.GET["mode"] == "ajax":
|
||||
page = lst.paginator.getpage(pageid)
|
||||
if page:
|
||||
content = lst.fetch(page.id_start, page.id_stop).render(request)
|
||||
navbar = lst.render_navbar(page)
|
||||
else:
|
||||
content = "Empty folder"
|
||||
navbar = ""
|
||||
ctx = {"status" : "ok", "listing" : content, "navbar" : navbar,
|
||||
"menu" : "", "current_page" : pageid}
|
||||
if "menu" in request.GET.keys():
|
||||
from templatetags.webextras import listing_menu
|
||||
ctx["menu"] = listing_menu("", request.user.get_all_permissions())
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
return lst.render(request, pageid=int(pageid))
|
||||
|
||||
def fetchmail(request, folder, mail_id, all=False):
|
||||
mbc = IMAPconnector(parameters.get("webmail", "SERVER_ADDRESS"), 143)
|
||||
mbc.login(request.user.username, request.session["password"])
|
||||
global mbc
|
||||
if not mbc:
|
||||
mbc = IMAPconnector(parameters.get("webmail", "IMAP_SERVER"), 143)
|
||||
mbc.login(request.user.username, request.session["password"])
|
||||
res = mbc.fetch(start=mail_id, folder=folder, all=all)
|
||||
if len(res):
|
||||
return res[0]
|
||||
@@ -68,26 +82,55 @@ def fetchmail(request, folder, mail_id, all=False):
|
||||
@login_required
|
||||
def viewmail(request, folder, mail_id=None):
|
||||
header = fetchmail(request, folder, mail_id)
|
||||
pageid = request.GET.has_key("page") and request.GET["page"] or "1"
|
||||
if header:
|
||||
from templatetags.webextras import viewm_menu
|
||||
menu = viewm_menu("", folder, mail_id, pageid,
|
||||
menu = viewm_menu("", request.session["folder"], mail_id,
|
||||
request.session["page"],
|
||||
request.user.get_all_permissions())
|
||||
folder, imapid = header["imapid"].split("/")
|
||||
mailcontent = render_to_string("webmail/viewmail.html", {
|
||||
"header" : header, "folder" : folder, "imapid" : imapid
|
||||
})
|
||||
ctx = {"status" : "ok", "menu" : menu, "mailcontent" : mailcontent}
|
||||
ctx = {"status" : "ok", "menu" : menu, "listing" : mailcontent}
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
# return _render(request, "webmail/viewmail.html", {
|
||||
# "header" : header, "folder" : folder, "pageid" : pageid,
|
||||
# "menu" : menu
|
||||
# })
|
||||
|
||||
@login_required
|
||||
def getmailcontent(request, folder, mail_id):
|
||||
from mailng.lib.email_listing import Email
|
||||
|
||||
msg = fetchmail(request, folder, mail_id, True)
|
||||
email = Email(msg)
|
||||
if "class" in msg.keys() and msg["class"] == "unseen":
|
||||
global mbc
|
||||
mbc.msgseen(msg["imapid"])
|
||||
|
||||
email = Email(msg, mode="html", links="1")
|
||||
return email.render(request)
|
||||
|
||||
@login_required
|
||||
def compose(request):
|
||||
if request.method == "POST":
|
||||
form = ComposeMailForm(request.POST)
|
||||
if form.is_valid():
|
||||
from email.mime.text import MIMEText
|
||||
import smtplib
|
||||
|
||||
msg = MIMEText(request.POST["id_body"].encode("utf-8"),
|
||||
_charset="utf-8")
|
||||
msg["Subject"] = request.POST["subject"]
|
||||
msg["From"] = request.POST["from_"]
|
||||
msg["to"] = request.POST["to"]
|
||||
s = smtplib.SMTP(parameters.get("webmail", "SMTP_SERVER"))
|
||||
s.sendmail(msg['From'], [msg['To']], msg.as_string())
|
||||
s.quit()
|
||||
return folder_ajax(request, request.session["folder"],
|
||||
request.session["page"], True)
|
||||
|
||||
form = ComposeMailForm()
|
||||
form.fields["from_"].initial = request.user.username
|
||||
menu = compose_menu("", request.session["folder"], request.session["page"],
|
||||
request.user.get_all_permissions())
|
||||
content = render_to_string("webmail/compose.html", {
|
||||
"form" : form
|
||||
})
|
||||
ctx = {"status" : "ok", "menu" : menu, "listing" : content}
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{% load i18n %}
|
||||
<style type="text/css">
|
||||
#compose-container {
|
||||
margin: 0 auto;
|
||||
width: 95%;
|
||||
}
|
||||
div.row {
|
||||
clear: both;
|
||||
padding-top: 5px;
|
||||
}
|
||||
div.row label {
|
||||
float: left;
|
||||
width: 120px;
|
||||
font-size: small;
|
||||
padding: 3px 0;
|
||||
}
|
||||
textarea {
|
||||
border: 1px solid #cccccc;
|
||||
background-color: #eee;
|
||||
width: 80%;
|
||||
height: 40px;
|
||||
font-size: medium;
|
||||
}
|
||||
textarea:hover {
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
#id_body {
|
||||
background: white;
|
||||
width: 100%;
|
||||
}
|
||||
input {
|
||||
width: 80%;
|
||||
padding: 0;
|
||||
}
|
||||
#mailheader {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% url extensions.webmail.main.compose as compurl %}
|
||||
<form method="POST" action="{{ compurl }}" id="composemail">
|
||||
<div id="compose-container">
|
||||
<div id="mailheader">
|
||||
{% include "common/genericform.html" %}
|
||||
</div>
|
||||
<textarea id="id_body" name="id_body"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,5 +1,5 @@
|
||||
<table id="headers">
|
||||
{% for hdr in headers %}
|
||||
<tr><th>{{ hdr.name }}</th><td>{{ hdr.value }}</td></tr>
|
||||
<tr><th width="150px">{{ hdr.name }}</th><td>{{ hdr.value }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
@@ -46,59 +46,81 @@
|
||||
}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
updatelisting = function(resp, overflow) {
|
||||
if ($defined(resp.menu)) {
|
||||
$("menubar").set("html", resp.menu);
|
||||
}
|
||||
$("listing").set("html", resp.listing);
|
||||
$("listing").setStyle("overflow", overflow);
|
||||
if ($defined(resp.navbar)) {
|
||||
$("navbar").set("html", resp.navbar);
|
||||
$("navbar").getChildren("a").addEvent("click", navbarcallback);
|
||||
}
|
||||
$$("a[name=compose]").addEvent("click", loadCompose);
|
||||
}
|
||||
|
||||
{% url extensions.webmail.main.folder as view_url %}
|
||||
loadMail = function(event) {
|
||||
event.stop();
|
||||
if (event.target.parentNode.id) {
|
||||
var url = "{{ view_url }}" + event.target.parentNode.id + "?page="
|
||||
+ $("pagenum").value;
|
||||
var url = "{{ view_url }}" + event.target.parentNode.id;
|
||||
event.target.parentNode.setStyle("background", "#ffffcc");
|
||||
new Request.JSON({url: url, onSuccess: function(resp) {
|
||||
$("menubar").set("html", resp.menu);
|
||||
$("listing").set("html", resp.mailcontent);
|
||||
$("listing").setStyle("overflow", "hidden");
|
||||
$$("a[name=back]").addEvent("click", loadfolder);
|
||||
updatelisting(resp, "hidden");
|
||||
$$("a[name=back]").addEvent("click", loadFolder);
|
||||
setDivHeight("mailcontent", $("table-container").getSize().y, 0);
|
||||
}}).get();
|
||||
}
|
||||
}
|
||||
updatelisting = function(resp) {
|
||||
if (resp.menu != "") {
|
||||
$("menubar").set("html", resp.menu);
|
||||
}
|
||||
$("pagenum").value = resp.current_page;
|
||||
$("listing").set("html", resp.listing);
|
||||
$("listing").setStyle("overflow", "auto");
|
||||
$$("tr").addEvent("click", loadMail);
|
||||
$("navbar").set("html", resp.navbar);
|
||||
$("navbar").getChildren("a").addEvent("click", navbarcallback);
|
||||
}
|
||||
navbarcallback = function(event) {
|
||||
|
||||
loadCompose = function(event) {
|
||||
event.stop();
|
||||
new Request.JSON({url: event.target.getParent().get("href"), onSuccess: function(resp) {
|
||||
updatelisting(resp);
|
||||
new Request.JSON({url: event.target, onSuccess: function(resp) {
|
||||
updatelisting(resp, "hidden");
|
||||
$$("a[name=back]").addEvent("click", loadFolder);
|
||||
$$("a[name=sendmail]").addEvent("click", function(evt) {
|
||||
evt.stop();
|
||||
$("composemail").set("send", {
|
||||
onSuccess: function(res) {
|
||||
updatelisting(JSON.decode(res));
|
||||
$$("tr").addEvent("click", loadMail);
|
||||
}
|
||||
});
|
||||
$("composemail").send();
|
||||
});
|
||||
setDivHeight("id_body", $("mailheader").getSize().y + 20, 0);
|
||||
}}).get();
|
||||
}
|
||||
|
||||
loadFolder = function(event, obj) {
|
||||
obj = typeof(obj) != "undefined" ? obj : event.target;
|
||||
event.stop();
|
||||
new Request.JSON({url: obj.get("href"), onSuccess: function(resp) {
|
||||
updatelisting(resp, "auto");
|
||||
$$("tr").addEvent("click", loadMail);
|
||||
}}).get({"mode" : "ajax"});
|
||||
}
|
||||
|
||||
navbarcallback = function(event) {
|
||||
loadFolder(event, event.target.getParent());
|
||||
}
|
||||
|
||||
select = function(obj) {
|
||||
$$("a[name=loadfolder]").each(function(item) {
|
||||
item.getParent().setStyle("background", "white");
|
||||
});
|
||||
obj.getParent().setStyle("background", "#FFFFCC");
|
||||
}
|
||||
loadfolder = function(event) {
|
||||
event.stop();
|
||||
new Request.JSON({url: event.target.get("href"), onSuccess: function(resp) {
|
||||
updatelisting(resp);
|
||||
}}).get({"mode" : "ajax"});
|
||||
}
|
||||
|
||||
foldercallback = function(event) {
|
||||
select(event.target);
|
||||
loadfolder(event);
|
||||
loadFolder(event, event.target);
|
||||
}
|
||||
|
||||
$$("a[name=loadfolder]").addEvent("click", foldercallback);
|
||||
$("navbar").getChildren("a").addEvent("click", navbarcallback);
|
||||
$$("tr").addEvent("click", loadMail);
|
||||
$$("a[name=compose]").addEvent("click", loadCompose);
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "Webmail" %}{% endblock %}
|
||||
{% block menu %}
|
||||
|
||||
@@ -21,11 +21,28 @@ def viewm_menu(selection, folder, mail_id, page_id, perms):
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"perms" : perms})
|
||||
|
||||
@register.simple_tag
|
||||
def compose_menu(selection, folder, page_id, perms):
|
||||
entries = [
|
||||
{"name" : "back",
|
||||
"url" : reverse(webmail.main.folder, args=[folder]) \
|
||||
+ "?page=%s" % page_id + "&menu=1",
|
||||
"img" : "/static/pics/back.png",
|
||||
"label" : _("Back to list")},
|
||||
{"name" : "sendmail",
|
||||
"url" : "",
|
||||
"img" : "/static/pics/send-receive.png",
|
||||
"label" : _("Send")},
|
||||
]
|
||||
return render_to_string('main/menu.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"perms" : perms})
|
||||
|
||||
@register.simple_tag
|
||||
def listing_menu(selection, perms):
|
||||
entries = [
|
||||
{"name" : "newmail",
|
||||
"url" : "",
|
||||
{"name" : "compose",
|
||||
"url" : reverse(webmail.main.compose),
|
||||
"img" : "/static/pics/edit.png",
|
||||
"label" : _("New message")}
|
||||
]
|
||||
|
||||
@@ -2,6 +2,7 @@ from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mailng.extensions.webmail.main',
|
||||
url(r'^$', "folder", name="index"),
|
||||
(r'^compose/$', "compose"),
|
||||
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/content/$', 'getmailcontent'),
|
||||
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/$', 'viewmail'),
|
||||
url(r'^(?P<name>.+)/$', "folder", name="folder"),
|
||||
|
||||
+13
-2
@@ -1,8 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import re
|
||||
import lxml
|
||||
import lxml.html
|
||||
from django.template.loader import render_to_string
|
||||
from django.template import Template
|
||||
from django.template import Template, Context
|
||||
from mailng.lib import _render, decode
|
||||
|
||||
attached_map = {}
|
||||
@@ -89,12 +91,21 @@ class EmailListing:
|
||||
def getfolders(self):
|
||||
return None
|
||||
|
||||
def fetch(self, request, id_start, id_stop):
|
||||
table = self.tbltype(self.mbc.fetch(start=id_start, stop=id_stop,
|
||||
folder=self.folder)).render(request)
|
||||
tpl = Template("""
|
||||
<form method="POST" id="listingform">
|
||||
{{ table }}
|
||||
</form>""")
|
||||
return tpl.render(Context({"table" : table}))
|
||||
|
||||
def render(self, request, pageid=1, **kwargs):
|
||||
page = self.paginator.getpage(pageid)
|
||||
if not page:
|
||||
listing = "Empty folder"
|
||||
else:
|
||||
listing = self.fetch(page.id_start, page.id_stop).render(request)
|
||||
listing = self.fetch(request, page.id_start, page.id_stop)
|
||||
elapsed = kwargs.has_key("start") and time.time() - kwargs["start"] or 0
|
||||
return _render(request, self.tpl, {
|
||||
"listing" : listing, "elapsed" : elapsed,
|
||||
|
||||
+3
-1
@@ -75,9 +75,11 @@ setDivHeight = function(id, extrah, modulo) {
|
||||
var contentsize = $(document.body).getSize().y
|
||||
- $("topmenubar").getSize().y
|
||||
- $("header").getSize().y
|
||||
- ($("navbar").getSize().y)
|
||||
- extrah;
|
||||
|
||||
if ($("navbar")) {
|
||||
contentsize -= $("navbar").getSize().y;
|
||||
}
|
||||
if (modulo) {
|
||||
contentsize -= contentsize % modulo;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
@@ -46,11 +46,7 @@ window.addEvent("domready", function() {
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% block leftcol %}{% endblock %}
|
||||
|
||||
<form method="POST" action="{{ actionurl }}" id="listingform">
|
||||
<input type="hidden" name="pagenum" id="pagenum" value="{{ current_page }}" />
|
||||
<div id="listing">{{ listing }}</div>
|
||||
</form>
|
||||
<div id="listing">{{ listing }}</div>
|
||||
<div class="spacer"></div>
|
||||
<div id="navbar">{{ navbar }}</div>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user