mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Version 0.6 !!
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
:q
|
||||
Installation
|
||||
============
|
||||
|
||||
@@ -31,6 +32,17 @@ Run the initialisation script. It will insert needed data into the database :
|
||||
export PYTHONPATH=$PWD/..
|
||||
DJANGO_SETTINGS_MODULE=mailng.settings ./scripts/populate.py
|
||||
|
||||
How to upgrade
|
||||
--------------
|
||||
|
||||
0.5 -> 0.6 : No modifications have been made to the core SQL schema so you
|
||||
just have to decompress the new tarball at the same location than your
|
||||
current installation. Once done, go to MailNG repository and run::
|
||||
|
||||
python manage.py syncdb
|
||||
|
||||
You must also modify 'settings.py' in order to activate new components.
|
||||
|
||||
Host configuration
|
||||
------------------
|
||||
|
||||
@@ -109,20 +121,71 @@ Then, use the following configuration in your /etc/postfix/main.cf file
|
||||
virtual_alias_maps = mysql:/etc/postfix/sql-aliases.cf
|
||||
# Stuff after
|
||||
|
||||
NB: Mailng only supports maildir format for now. Others will surely be
|
||||
added soon.
|
||||
NB: Mailng supports both maildir and mbox formats. You can specify
|
||||
which format to use by modifying the MAILBOX_TYPE variable located
|
||||
inside 'settings.py'.
|
||||
|
||||
Tips to activate auto-reply messages in Postifx
|
||||
-----------------------------------------------
|
||||
|
||||
Since version 0.6, mail users can define an auto-reply message with MailNG.
|
||||
To make Postfix understand this feature, you need to update your configuration
|
||||
files as follow::
|
||||
|
||||
# /etc/postfix/main.cf
|
||||
transport_maps = mysql:/etc/postfix/maps/sql-transport.cf
|
||||
virtual_alias_maps = mysql:/etc/postfix/maps/sql-aliases.cf
|
||||
mysql:/etc/postfix/maps/sql-autoreplies.cf
|
||||
|
||||
# /etc/postfix/master.cf
|
||||
autoreply unix - n n - - pipe
|
||||
flags= user=nobody argv=<path_to_mailng>/scripts/autoreply $sender $mailbox
|
||||
|
||||
Then, create new map files with the following content::
|
||||
|
||||
# /etc/postfix/maps/sql-transport.cf
|
||||
user = <user>
|
||||
password = <password>
|
||||
dbname = <database>
|
||||
hosts = 127.0.0.1
|
||||
query = SELECT method FROM postfix_autoreply_transport WHERE domain='%s'
|
||||
|
||||
# /etc/postfix/maps/sql-autoreplies.cf
|
||||
user = <user>
|
||||
password = <password>
|
||||
dbname = <database>
|
||||
hosts = 127.0.0.1
|
||||
query = SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'
|
||||
|
||||
NB: auto-reply messages are just sent one time per sender for a
|
||||
pre-defined time period. By default, this period is equal to 1 day
|
||||
(86400s), you can adjust this value by modifying the AUTOREPLY_TIMEOUT
|
||||
variable located inside 'settings.py'.
|
||||
|
||||
NB: Be sure that both 'autoreply' and 'autoreply.py' scripts (located
|
||||
inside the 'scripts' directory) have good permissions (ie. 0755).
|
||||
|
||||
Tips to link Mailng with dovecot
|
||||
--------------------------------
|
||||
|
||||
Edit your main Dovecot config file (/etc/dovecot/dovecot.conf) and put the
|
||||
If you are using 'maildir' format to store mailboxes, add the
|
||||
following line inside your main Dovecot config file
|
||||
(/etc/dovecot/dovecot.conf)::
|
||||
|
||||
mail_location = maildir:<path_to_mailboxes>/%d/%n/.maildir
|
||||
|
||||
If you are using 'mbox' format, put the following::
|
||||
|
||||
mail_location = mbox:<path_to_mailboxes>/%d/%n/:INBOX=<path_to_mailboxes>/%d/%n/Inbox
|
||||
|
||||
To make the authentication work, edit 'dovecot.conf' and add the
|
||||
following inside::
|
||||
|
||||
auth default {
|
||||
# ... stuff before
|
||||
|
||||
passdb sql {
|
||||
# Path for SQL configuration file, see /etc/dovecot/dovecot-sql.conf for
|
||||
# Path for SQL configuration file, see /etc/dovecot/dovecot-sql.conf for
|
||||
# example
|
||||
args = /etc/dovecot/dovecot-sql.conf
|
||||
}
|
||||
@@ -155,23 +218,28 @@ Put the following lines inside your dovecot.conf file::
|
||||
mail_plugins = quota quota_imap
|
||||
}
|
||||
|
||||
Before continuing, you need to know which quota backend must be user
|
||||
(function of mailboxes format)::
|
||||
* 'mbox' : backend=dirsize,
|
||||
* 'maildir' : backend=maildir.
|
||||
|
||||
If you use version prior to 1.1, add also the following configuration::
|
||||
|
||||
plugin {
|
||||
# 10 MB default quota limit
|
||||
quota = maildir:storage=10240
|
||||
quota = <backend>:storage=10240
|
||||
}
|
||||
|
||||
Then modify the above user_query inside dovecot-sql.conf file like
|
||||
that to activate per user quotas::
|
||||
|
||||
user_query = SELECT path AS home, uid, gid, concat('maildir:storage=', quota / 1024) AS quota FROM admin_mailbox WHERE full_address = '%u'
|
||||
user_query = SELECT path AS home, uid, gid, concat('<backend>:storage=', quota / 1024) AS quota FROM admin_mailbox WHERE full_address = '%u'
|
||||
|
||||
For version >= 1.1, put the following configuration inside dovecot.conf file::
|
||||
|
||||
plugin {
|
||||
# Default 10M storage limit with an extra 5M limit when saving to Trash.
|
||||
quota = maildir:User quota
|
||||
quota = <backend>:User quota
|
||||
quota_rule = *:storage=10M
|
||||
quota_rule2 = Trash:storage=5M
|
||||
}
|
||||
|
||||
+8
-8
@@ -18,9 +18,7 @@ class Domain(models.Model):
|
||||
|
||||
def create_dir(self):
|
||||
path = "%s/%s" % (settings.STORAGE_PATH, self.name)
|
||||
if exec_as_vuser("mkdir %s" % path):
|
||||
return False
|
||||
return True
|
||||
return exec_as_vuser("mkdir %s" % path)
|
||||
|
||||
def rename_dir(self, newname):
|
||||
code, output = exec_pipe("sudo -u %s mv %s/%s %s/%s" \
|
||||
@@ -74,14 +72,16 @@ class Mailbox(models.Model):
|
||||
except AttributeError:
|
||||
mbtype = "maildir"
|
||||
if mbtype == "mbox":
|
||||
template = ["Inbox", "Drafts", "Sent", "Trash", "Junk"]
|
||||
for dir in template:
|
||||
exec_as_vuser("touch %s/%s" % (path, dir))
|
||||
|
||||
self.path = "%s/%s/Inbox" % (domain.name, self.address)
|
||||
else:
|
||||
template = [".Drafts/", ".Sent/", ".Trash/", ".Junk/"]
|
||||
for dir in template:
|
||||
for sdir in ["cur", "new", "tmp"]:
|
||||
exec_as_vuser("mkdir -p %s/%s/%s" % (path, dir, sdir))
|
||||
|
||||
self.path = "%s/%s/" % (domain.name, self.address)
|
||||
else:
|
||||
exec_as_vuser("mkdir %s/.maildir/" % path)
|
||||
exec_as_vuser("mkdir -p %s/.maildir/%s/%s" % (path, dir, sdir))
|
||||
self.path = "%s/%s/.maildir/" % (domain.name, self.address)
|
||||
return True
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from mailng.admin.models import Domain, Mailbox, Alias
|
||||
from forms import MailboxForm, DomainForm, AliasForm, PermissionForm
|
||||
from mailng.lib.authbackends import crypt_password
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib import events
|
||||
|
||||
def is_superuser(user):
|
||||
if not user.is_superuser:
|
||||
@@ -50,6 +51,7 @@ def newdomain(request):
|
||||
domain = form.save(commit=False)
|
||||
if domain.create_dir():
|
||||
form.save()
|
||||
events.raiseEvent("CreateDomain", dom=domain)
|
||||
ctx = _ctx_ok(reverse(admin.views.domains))
|
||||
return HttpResponse(simplejson.dumps(ctx),
|
||||
mimetype="application/json")
|
||||
@@ -98,6 +100,7 @@ def editdomain(request, dom_id):
|
||||
@permission_required("admin.delete_domain")
|
||||
def deldomain(request, dom_id):
|
||||
domain = Domain.objects.get(pk=dom_id)
|
||||
events.raiseEvent("DeleteDomain", dom=domain)
|
||||
domain.delete_dir()
|
||||
domain.delete()
|
||||
return HttpResponseRedirect('/mailng/admin/')
|
||||
@@ -157,6 +160,9 @@ def newmailbox(request, dom_id=None):
|
||||
mb.quota = domain.quota
|
||||
mb.full_address = "%s@%s" % (mb.address, domain.name)
|
||||
mb.save()
|
||||
|
||||
events.raiseEvent("CreateMailbox", mbox=mb)
|
||||
|
||||
ctx = _ctx_ok(reverse(admin.views.mailboxes, args=[domain.id]))
|
||||
return HttpResponse(simplejson.dumps(ctx),
|
||||
mimetype="application/json")
|
||||
@@ -221,6 +227,7 @@ def editmailbox(request, dom_id, mbox_id=None):
|
||||
@permission_required("admin.delete_mailbox")
|
||||
def delmailbox(request, dom_id, mbox_id=None):
|
||||
mb = Mailbox.objects.get(pk=mbox_id)
|
||||
events.raiseEvent("DeleteMailbox", mbox=mb)
|
||||
mb.delete_dir()
|
||||
mb.user.delete()
|
||||
mb.delete()
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import re
|
||||
|
||||
def loadextensions():
|
||||
from django.conf import settings
|
||||
|
||||
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'])
|
||||
module.main.init()
|
||||
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Postfix auto-replies plugin.
|
||||
|
||||
This module provides a way to integrate MailNG auto-reply
|
||||
functionality into Postfix.
|
||||
|
||||
"""
|
||||
from mailng.lib import events
|
||||
from models import Transport, Alias
|
||||
|
||||
def init():
|
||||
events.register("CreateDomain", onCreateDomain)
|
||||
events.register("DeleteDomain", onDeleteDomain)
|
||||
events.register("CreateMailbox", onCreateMailbox)
|
||||
events.register("DeleteMailbox", onDeleteMailbox)
|
||||
|
||||
def onCreateDomain(**kwargs):
|
||||
dom = kwargs["dom"]
|
||||
transport = Transport()
|
||||
transport.domain = "autoreply.%s" % dom.name
|
||||
transport.method = "autoreply:"
|
||||
transport.save()
|
||||
|
||||
def onDeleteDomain(**kwargs):
|
||||
dom = kwargs["dom"]
|
||||
trans = Transport.objects.get(domain="autoreply.%s" % dom.name)
|
||||
trabs.delete()
|
||||
|
||||
def onCreateMailbox(**kwargs):
|
||||
mbox = kwargs["mbox"]
|
||||
alias = Alias()
|
||||
alias.full_address = mbox.full_address
|
||||
alias.autoreply_address = \
|
||||
"%s@autoreply.%s" % (mbox.full_address, mbox.domain.name)
|
||||
alias.save()
|
||||
|
||||
def onDeleteMailbox(**kwargs):
|
||||
mbox = kwargs["mbox"]
|
||||
alias = Alias.objects.get(full_address=mbox.full_address)
|
||||
alias.delete()
|
||||
@@ -0,0 +1,10 @@
|
||||
from django.db import models
|
||||
from mailng.admin.models import Domain, Mailbox
|
||||
|
||||
class Transport(models.Model):
|
||||
domain = models.CharField(max_length=300)
|
||||
method = models.CharField(max_length=255)
|
||||
|
||||
class Alias(models.Model):
|
||||
full_address = models.CharField(max_length=255)
|
||||
autoreply_address = models.CharField(max_length=255)
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This module provides a simple way of managing events between MailNG
|
||||
core application and additional components.
|
||||
|
||||
"""
|
||||
|
||||
events = ["CreateDomain",
|
||||
"DeleteDomain",
|
||||
"CreateMailbox",
|
||||
"DeleteMailbox"]
|
||||
|
||||
callbacks = {}
|
||||
|
||||
def register(event, callback):
|
||||
if not event in events:
|
||||
return 0
|
||||
if not event in callbacks.keys():
|
||||
callbacks[event] = []
|
||||
callbacks[event].append(callback)
|
||||
return 1
|
||||
|
||||
def raiseEvent(event, **kwargs):
|
||||
if not event in events or not event in callbacks.keys():
|
||||
return 0
|
||||
for callback in callbacks[event]:
|
||||
callback(**kwargs)
|
||||
return 1
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-06-17 10:13+0200\n"
|
||||
"POT-Creation-Date: 2009-06-19 10:29+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -25,11 +25,11 @@ msgstr ""
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: admin/forms.py:18
|
||||
#: admin/forms.py:18 main/forms.py:21
|
||||
msgid "Confirmation"
|
||||
msgstr ""
|
||||
|
||||
#: admin/forms.py:32
|
||||
#: admin/forms.py:32 main/forms.py:36
|
||||
msgid "Passwords mismatch"
|
||||
msgstr "Les mots de passe diffèrent"
|
||||
|
||||
@@ -54,43 +54,43 @@ msgstr "Super administrateur"
|
||||
msgid "Domain administrator"
|
||||
msgstr "Admin. de domaine"
|
||||
|
||||
#: admin/models.py:9 admin/models.py:48
|
||||
#: admin/models.py:9 admin/models.py:46
|
||||
msgid "name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: admin/models.py:11 admin/models.py:112 main/models.py:9
|
||||
#: admin/models.py:11 admin/models.py:110 main/models.py:9
|
||||
msgid "enabled"
|
||||
msgstr "Activé"
|
||||
|
||||
#: admin/models.py:49 admin/models.py:109
|
||||
#: admin/models.py:47 admin/models.py:107
|
||||
msgid "address"
|
||||
msgstr "Adresse"
|
||||
|
||||
#: admin/models.py:51
|
||||
#: admin/models.py:49
|
||||
msgid "password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: admin/models.py:111
|
||||
#: admin/models.py:109
|
||||
msgid "mailbox"
|
||||
msgstr "Boite aux lettres"
|
||||
|
||||
#: admin/views.py:26
|
||||
#: admin/views.py:21
|
||||
msgid "Permission denied."
|
||||
msgstr "Permission refusée."
|
||||
|
||||
#: admin/views.py:54 admin/views.py:85
|
||||
#: admin/views.py:49 admin/views.py:81
|
||||
msgid "Domain with this name already defined"
|
||||
msgstr "Un domaine avec ce nom existe déjà"
|
||||
|
||||
#: admin/views.py:62
|
||||
#: admin/views.py:58
|
||||
msgid "Failed to initialise domain, check permissions"
|
||||
msgstr "Impossible d'initialiser le domaine, vérifier les permissions"
|
||||
|
||||
#: admin/views.py:88
|
||||
#: admin/views.py:84
|
||||
msgid "Failed to rename domain, check permissions"
|
||||
msgstr "Impossible de renommer le domaine, vérifier les permissions"
|
||||
|
||||
#: admin/views.py:138 admin/views.py:191
|
||||
#: admin/views.py:135 admin/views.py:191
|
||||
msgid "Mailbox with this address already exists"
|
||||
msgstr "Une boite aux lettres pour cette adresse existe déjà"
|
||||
|
||||
@@ -103,7 +103,7 @@ msgstr ""
|
||||
msgid "Failed to rename mailbox, check permissions"
|
||||
msgstr "Impossible de renommer la boite aux lettres, vérifier les permissions."
|
||||
|
||||
#: admin/views.py:261 admin/views.py:290
|
||||
#: admin/views.py:262 admin/views.py:291
|
||||
msgid "Alias with this address already exists"
|
||||
msgstr "Un alias avec cette adresse existe déjà"
|
||||
|
||||
@@ -115,6 +115,18 @@ msgstr "Activé"
|
||||
msgid "enabled_f"
|
||||
msgstr "Activée"
|
||||
|
||||
#: main/forms.py:17
|
||||
msgid "Old password"
|
||||
msgstr "Ancien mot de passe"
|
||||
|
||||
#: main/forms.py:19
|
||||
msgid "New password"
|
||||
msgstr "Nouveau mot de passe"
|
||||
|
||||
#: main/forms.py:31
|
||||
msgid "Old password mismatchs"
|
||||
msgstr "L'ancien mot de passe est incorrect"
|
||||
|
||||
#: main/models.py:7
|
||||
msgid "subject"
|
||||
msgstr "sujet"
|
||||
@@ -123,7 +135,7 @@ msgstr "sujet"
|
||||
msgid "content"
|
||||
msgstr "contenu"
|
||||
|
||||
#: main/views.py:34
|
||||
#: main/views.py:45
|
||||
msgid "Auto reply message updated successfully."
|
||||
msgstr "Message de réponse auto. mis à jour."
|
||||
|
||||
@@ -237,7 +249,8 @@ msgid "yes,no"
|
||||
msgstr "oui,non"
|
||||
|
||||
#: templates/admin/editalias.html:14 templates/admin/editdomain.html:15
|
||||
#: templates/admin/editmailbox.html:16 templates/main/autoreply.html:16
|
||||
#: templates/admin/editmailbox.html:16 templates/main/autoreply.html:17
|
||||
#: templates/main/chpassword.html:15
|
||||
msgid "Update"
|
||||
msgstr "Mettre à jour"
|
||||
|
||||
@@ -297,15 +310,23 @@ msgstr "Aucun admin de domaine défini."
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/main/header.html:5
|
||||
msgid "General"
|
||||
msgstr "Général"
|
||||
|
||||
#: templates/main/menu.html:5
|
||||
#: templates/main/chpassword.html:7 templates/main/menu.html:13
|
||||
msgid "Change password"
|
||||
msgstr "Changer de mot de passe"
|
||||
|
||||
#: templates/main/menu.html:10
|
||||
#: templates/main/header.html:8
|
||||
msgid "General"
|
||||
msgstr "Général"
|
||||
|
||||
#: templates/main/index.html:11
|
||||
msgid "Your auto-reply message is activated."
|
||||
msgstr "Votre réponse automatique est active."
|
||||
|
||||
#: templates/main/index.html:13
|
||||
msgid "Your auto-reply message is not activated."
|
||||
msgstr "Votre réponse automatique n'est pas active."
|
||||
|
||||
#: templates/main/menu.html:6
|
||||
msgid "Auto-reply message"
|
||||
msgstr "Message de réponse automatique"
|
||||
|
||||
|
||||
+7
-2
@@ -13,11 +13,16 @@ from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib.authbackends import crypt_password
|
||||
from forms import ARmessageForm, ChangePasswordForm
|
||||
from models import ARmessage
|
||||
from admin.models import Mailbox
|
||||
from mailng.admin.models import Mailbox
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
return _render(request, "main/index.html", {})
|
||||
mb = Mailbox.objects.get(user=request.user.id)
|
||||
try:
|
||||
arm = ARmessage.objects.filter(mbox=mb.id, enabled=True)
|
||||
except ARmessage.DoesNotExist:
|
||||
arm = None
|
||||
return _render(request, "main/index.html", {"arm" : arm})
|
||||
|
||||
@login_required
|
||||
def autoreply(request):
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
BASEDIR=/home/tonio
|
||||
export PYTHONPATH=$BASEDIR
|
||||
export DJANGO_SETTINGS_MODULE=mailng.settings
|
||||
|
||||
$BASEDIR/mailng/scripts/autoreply.py $1 $2
|
||||
@@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
@@ -38,7 +39,12 @@ if __name__ == "__main__":
|
||||
msg['Subject'] = armessage.subject
|
||||
msg['From'] = mailbox
|
||||
msg['To'] = sender
|
||||
print msg
|
||||
|
||||
s = smtplib.SMTP()
|
||||
s.connect()
|
||||
s.sendmail(mailbox, sender, msg.as_string())
|
||||
s.quit()
|
||||
|
||||
lastar.last_sent = datetime.datetime.now()
|
||||
lastar.save()
|
||||
sys.exit(0)
|
||||
|
||||
@@ -80,6 +80,9 @@ INSTALLED_APPS = (
|
||||
'django.contrib.sites',
|
||||
'mailng.admin',
|
||||
'mailng.main'
|
||||
|
||||
# MailNG extensions here.
|
||||
# 'mailng.extensions.postfix_autoreply'
|
||||
)
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
window.addEvent('domready', function() {
|
||||
SqueezeBox.assign($$('a.boxed'), {
|
||||
parse: 'rel'
|
||||
});
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 863 B |
@@ -297,4 +297,9 @@ body {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.info {
|
||||
float: left;
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -5,5 +5,13 @@
|
||||
{% menu "" perms %}
|
||||
{% endblock %}
|
||||
{% block subcontent %}
|
||||
|
||||
<div class="info">
|
||||
<img src="/static/pics/info.png" border="0" />
|
||||
{% if arm %}
|
||||
{% trans "Your auto-reply message is activated." %}
|
||||
{% else %}
|
||||
{% trans "Your auto-reply message is not activated." %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,15 +1,15 @@
|
||||
{% load i18n %}
|
||||
<ul>
|
||||
{% 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>
|
||||
<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" %}
|
||||
</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>
|
||||
</ul>
|
||||
Reference in New Issue
Block a user