mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Ticket #52
From now, users can store their own "preferences" inside MailNG.
This commit is contained in:
+14
-14
@@ -3,17 +3,17 @@
|
||||
from mailng.lib import parameters
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
parameters.register("admin","STORAGE_PATH", "string", "/var/vmail",
|
||||
help=_("Path to the root directory where messages are stored"))
|
||||
parameters.register("admin", "VIRTUAL_UID", "string", "vmail",
|
||||
help=_("UID of the virtual user which owns domains/mailboxes/messages on the filesystem"))
|
||||
parameters.register("admin", "VIRTUAL_GID", "string", "vmail",
|
||||
help=_("GID of the virtual user which owns domains/mailboxes/messages on the filesystem"))
|
||||
parameters.register("admin", "MAILBOX_TYPE", "list", "maildir",
|
||||
values=[("maildir", "maildir"), ("mbox", "mbox")],
|
||||
help=_("Mailboxes storage format"))
|
||||
parameters.register("admin", "MAILDIR_ROOT", "string", ".maildir",
|
||||
help=_("Sub-directory (inside the mailbox) where messages are stored when using the maildir format"))
|
||||
parameters.register("admin", "PASSWORD_SCHEME", "list", "crypt",
|
||||
values=[("crypt", "crypt"), ("md5", "md5"), ("clear", "clear")],
|
||||
help=_("Scheme used to crypt mailbox passwords"))
|
||||
parameters.register_admin("admin","STORAGE_PATH", type="string", deflt="/var/vmail",
|
||||
help=_("Path to the root directory where messages are stored"))
|
||||
parameters.register_admin("admin", "VIRTUAL_UID", type="string", deflt="vmail",
|
||||
help=_("UID of the virtual user which owns domains/mailboxes/messages on the filesystem"))
|
||||
parameters.register_admin("admin", "VIRTUAL_GID", type="string", deflt="vmail",
|
||||
help=_("GID of the virtual user which owns domains/mailboxes/messages on the filesystem"))
|
||||
parameters.register_admin("admin", "MAILBOX_TYPE", type="list", deflt="maildir",
|
||||
values=[("maildir", "maildir"), ("mbox", "mbox")],
|
||||
help=_("Mailboxes storage format"))
|
||||
parameters.register_admin("admin", "MAILDIR_ROOT", type="string", deflt=".maildir",
|
||||
help=_("Sub-directory (inside the mailbox) where messages are stored when using the maildir format"))
|
||||
parameters.register_admin("admin", "PASSWORD_SCHEME", type="list", deflt="crypt",
|
||||
values=[("crypt", "crypt"), ("md5", "md5"), ("clear", "clear")],
|
||||
help=_("Scheme used to crypt mailbox passwords"))
|
||||
|
||||
+8
-8
@@ -19,17 +19,17 @@ class Domain(models.Model):
|
||||
)
|
||||
|
||||
def create_dir(self):
|
||||
path = "%s/%s" % (parameters.get("admin", "STORAGE_PATH"), self.name)
|
||||
path = "%s/%s" % (parameters.get_admin("admin", "STORAGE_PATH"), self.name)
|
||||
return exec_as_vuser("mkdir -p %s" % path)
|
||||
|
||||
def rename_dir(self, newname):
|
||||
stpath = parameters.get("admin", "STORAGE_PATH")
|
||||
stpath = parameters.get_admin("admin", "STORAGE_PATH")
|
||||
return exec_as_vuser("mv %s/%s %s/%s" \
|
||||
% (stpath, self.name, stpath, newname))
|
||||
|
||||
def delete_dir(self):
|
||||
return exec_as_vuser("rm -r %s/%s" \
|
||||
% (parameters.get("admin", "STORAGE_PATH"),
|
||||
% (parameters.get_admin("admin", "STORAGE_PATH"),
|
||||
self.name))
|
||||
|
||||
def __str__(self):
|
||||
@@ -57,14 +57,14 @@ class Mailbox(models.Model):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Mailbox, self).__init__(*args, **kwargs)
|
||||
self.mbtype = parameters.get("admin", "MAILBOX_TYPE")
|
||||
self.mdirroot = parameters.get("admin", "MAILDIR_ROOT")
|
||||
self.mbtype = parameters.get_admin("admin", "MAILBOX_TYPE")
|
||||
self.mdirroot = parameters.get_admin("admin", "MAILDIR_ROOT")
|
||||
|
||||
def __str__(self):
|
||||
return "%s" % (self.address)
|
||||
|
||||
def create_dir(self, domain):
|
||||
path = "%s/%s/%s" % (parameters.get("admin", "STORAGE_PATH"),
|
||||
path = "%s/%s/%s" % (parameters.get_admin("admin", "STORAGE_PATH"),
|
||||
domain.name, self.address)
|
||||
if os.path.exists(path):
|
||||
return True
|
||||
@@ -86,7 +86,7 @@ class Mailbox(models.Model):
|
||||
return True
|
||||
|
||||
def rename_dir(self, domain, newaddress):
|
||||
path = "%s/%s" % (parameters.get("admin", "STORAGE_PATH"), domain)
|
||||
path = "%s/%s" % (parameters.get_admin("admin", "STORAGE_PATH"), domain)
|
||||
code = exec_as_vuser("mv %s/%s %s/%s" \
|
||||
% (path, self.address, path, newaddress))
|
||||
if code:
|
||||
@@ -95,7 +95,7 @@ class Mailbox(models.Model):
|
||||
|
||||
def delete_dir(self):
|
||||
return exec_as_vuser("rm -r %s/%s/%s" \
|
||||
% (parameters.get("admin", "STORAGE_PATH"),
|
||||
% (parameters.get_admin("admin", "STORAGE_PATH"),
|
||||
self.domain.name, self.address))
|
||||
|
||||
class Alias(models.Model):
|
||||
|
||||
+11
-10
@@ -179,8 +179,8 @@ def newmailbox(request, dom_id=None):
|
||||
|
||||
mb.password = crypt_password(request.POST["password1"])
|
||||
|
||||
mb.uid = pwd.getpwnam(parameters.get("admin", "VIRTUAL_UID")).pw_uid
|
||||
mb.gid = pwd.getpwnam(parameters.get("admin", "VIRTUAL_GID")).pw_gid
|
||||
mb.uid = pwd.getpwnam(parameters.get_admin("admin", "VIRTUAL_UID")).pw_uid
|
||||
mb.gid = pwd.getpwnam(parameters.get_admin("admin", "VIRTUAL_GID")).pw_gid
|
||||
mb.domain = domain
|
||||
mb.quota = request.POST["quota"]
|
||||
if not mb.quota:
|
||||
@@ -415,14 +415,15 @@ def viewparameters(request):
|
||||
gparams = []
|
||||
for app in apps:
|
||||
tmp = {"name" : app, "params" : []}
|
||||
for p in sorted(parameters._params[app]):
|
||||
for p in sorted(parameters._params[app]['A']):
|
||||
param_def = parameters._params[app]['A'][p]
|
||||
newdef = {"name" : p,
|
||||
"value" : parameters.get(app, p),
|
||||
"help" : parameters._params[app][p]["help"],
|
||||
"default" : parameters._params[app][p]["default"],
|
||||
"type" : parameters._params[app][p]["type"]}
|
||||
if "values" in parameters._params[app][p].keys():
|
||||
newdef["values"] = parameters._params[app][p]["values"]
|
||||
"value" : parameters.get_admin(app, p),
|
||||
"help" : param_def["help"],
|
||||
"default" : param_def["default"],
|
||||
"type" : param_def["type"]}
|
||||
if "values" in param_def.keys():
|
||||
newdef["values"] = param_def["values"]
|
||||
tmp["params"] += [newdef]
|
||||
gparams += [tmp]
|
||||
|
||||
@@ -437,6 +438,6 @@ def saveparameters(request):
|
||||
if pname == "update":
|
||||
continue
|
||||
app, name = pname.split('.')
|
||||
parameters.save(app, name, v)
|
||||
parameters.save_admin(app, name, v)
|
||||
request.user.message_set.create(message=_("Configuration saved."))
|
||||
return HttpResponseRedirect(reverse(admin.views.viewparameters))
|
||||
|
||||
@@ -5,7 +5,7 @@ from mailng.lib import db, parameters
|
||||
|
||||
if __name__ == "__main__":
|
||||
conn = db.getconnection("amavis_quarantine")
|
||||
max_messages_age = parameters.get("amavis_quarantine", "MAX_MESSAGES_AGE")
|
||||
max_messages_age = parameters.get_admin("amavis_quarantine", "MAX_MESSAGES_AGE")
|
||||
|
||||
print "Deleting messages older than %d days..." % max_messages_age
|
||||
db.execute(conn, """
|
||||
|
||||
@@ -6,14 +6,14 @@ from mailng.lib import parameters
|
||||
|
||||
class AMrelease(object):
|
||||
def __init__(self):
|
||||
mode = parameters.get("amavis_quarantine", "AM_PDP_MODE")
|
||||
mode = parameters.get_admin("amavis_quarantine", "AM_PDP_MODE")
|
||||
if mode == "inet":
|
||||
host = parameters.get("amavis_quarantine", 'AM_PDP_HOST')
|
||||
port = parameters.get("amavis_quarantine", 'AM_PDP_PORT')
|
||||
host = parameters.get_admin("amavis_quarantine", 'AM_PDP_HOST')
|
||||
port = parameters.get_admin("amavis_quarantine", 'AM_PDP_PORT')
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.connect((host, int(port)))
|
||||
else:
|
||||
path = parameters.get("amavis_quarantine", 'AM_PDP_SOCKET')
|
||||
path = parameters.get_admin("amavis_quarantine", 'AM_PDP_SOCKET')
|
||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.sock.connect(path)
|
||||
|
||||
|
||||
@@ -16,18 +16,20 @@ def infos():
|
||||
|
||||
def init():
|
||||
events.register("UserMenuDisplay", menu)
|
||||
parameters.register("amavis_quarantine", "MAX_MESSAGES_AGE", "int", 14,
|
||||
help=_("Quarantine messages maximum age (in days) before deletion"))
|
||||
parameters.register("amavis_quarantine", "AM_PDP_MODE", "list", "unix",
|
||||
values=[("inet", "inet"), ("unix", "unix")],
|
||||
help="")
|
||||
parameters.register("amavis_quarantine", "AM_PDP_HOST", "string", "localhost",
|
||||
help="")
|
||||
parameters.register("amavis_quarantine", "AM_PDP_PORT", "int", 9998,
|
||||
help="")
|
||||
parameters.register("amavis_quarantine", "AM_PDP_SOCKET", "string",
|
||||
"/var/amavis/amavisd.sock",
|
||||
help="")
|
||||
parameters.register_admin("amavis_quarantine", "MAX_MESSAGES_AGE", type="int",
|
||||
deflt=14,
|
||||
help=_("Quarantine messages maximum age (in days) before deletion"))
|
||||
parameters.register_admin("amavis_quarantine", "AM_PDP_MODE", type="list",
|
||||
deflt="unix",
|
||||
values=[("inet", "inet"), ("unix", "unix")],
|
||||
help="")
|
||||
parameters.register_admin("amavis_quarantine", "AM_PDP_HOST", type="string",
|
||||
deflt="localhost", help="")
|
||||
parameters.register_admin("amavis_quarantine", "AM_PDP_PORT", type="int",
|
||||
deflt=9998, help="")
|
||||
parameters.register_admin("amavis_quarantine", "AM_PDP_SOCKET", type="string",
|
||||
deflt="/var/amavis/amavisd.sock",
|
||||
help="")
|
||||
|
||||
def destroy():
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
|
||||
@@ -28,8 +28,9 @@ def init():
|
||||
events.register("ModifyMailbox", onModifyMailbox)
|
||||
events.register("UserMenuDisplay", menu)
|
||||
|
||||
parameters.register("postfix_autoreply", "AUTOREPLIES_TIMEOUT", "int", 86400,
|
||||
help=_("Timeout in seconds between two auto-replies to the same recipient"))
|
||||
parameters.register_admin("postfix_autoreply", "AUTOREPLIES_TIMEOUT",
|
||||
type="int", deflt=86400,
|
||||
help=_("Timeout in seconds between two auto-replies to the same recipient"))
|
||||
|
||||
def destroy():
|
||||
events.unregister("CreateDomain", onCreateDomain)
|
||||
|
||||
+23
-3
@@ -7,13 +7,33 @@ from django.db import models
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Renaming model 'ARmessage'
|
||||
db.rename_table('main_armessage', 'postfix_autoreply_armessage')
|
||||
# Renaming/Creating model 'ARmessage'
|
||||
try:
|
||||
db.rename_table('main_armessage', 'postfix_autoreply_armessage')
|
||||
except Exception:
|
||||
db.create_table('postfix_autoreply_armessage', (
|
||||
('mbox', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.Mailbox'])),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('subject', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('content', self.gf('django.db.models.fields.TextField')()),
|
||||
('enabled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True))
|
||||
))
|
||||
db.send_create_signal('postfix_autoreply', ['ARmessage'])
|
||||
|
||||
db.add_column('postfix_autoreply_armessage', 'untildate',
|
||||
models.DateTimeField(null=True))
|
||||
|
||||
# Renaming model 'ARhistoric'
|
||||
db.rename_table('main_arhistoric', 'postfix_autoreply_arhistoric')
|
||||
try:
|
||||
db.rename_table('main_arhistoric', 'postfix_autoreply_arhistoric')
|
||||
except Exception:
|
||||
db.create_table('postfix_autoreply_arhistoric', (
|
||||
('armessage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['postfix_autoreply.ARmessage'])),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('last_sent', self.gf('django.db.models.fields.DateTimeField')(auto_now=True)),
|
||||
('sender', self.gf('django.db.models.fields.TextField')()),
|
||||
))
|
||||
db.send_create_signal('postfix_autoreply', ['ARhistoric'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
@@ -29,7 +29,7 @@ if __name__ == "__main__":
|
||||
|
||||
try:
|
||||
lastar = ARhistoric.objects.get(armessage=armessage.id, sender=sender)
|
||||
parameters.get("postfix_autoreply", "AUTOREPLIES_TIMEOUT")
|
||||
parameters.get_admin("postfix_autoreply", "AUTOREPLIES_TIMEOUT")
|
||||
delta = datetime.timedelta(seconds=timeout)
|
||||
if lastar.last_sent + delta > datetime.datetime.now():
|
||||
sys.exit(0)
|
||||
|
||||
@@ -55,8 +55,8 @@ tpl = {'traffic':traffic_avg_template,
|
||||
|
||||
class Grapher(object):
|
||||
def __init__(self):
|
||||
self.rrd_rootdir = parameters.get("stats", "RRD_ROOTDIR")
|
||||
self.img_rootdir = parameters.get("stats", "IMG_ROOTDIR")
|
||||
self.rrd_rootdir = parameters.get_admin("stats", "RRD_ROOTDIR")
|
||||
self.img_rootdir = parameters.get_admin("stats", "IMG_ROOTDIR")
|
||||
|
||||
def process(self, target, suffix, start, end, tpl=traffic_avg_template):
|
||||
rrdfile = "%s/%s.rrd" % (self.rrd_rootdir, target)
|
||||
|
||||
@@ -276,8 +276,8 @@ class LogParser(object):
|
||||
G.make_defaults(dom, tpl=grapher.size_avg_template)
|
||||
|
||||
if __name__ == "__main__":
|
||||
log_file = parameters.get("stats", "LOGFILE")
|
||||
rrd_rootdir = parameters.get("stats", "RRD_ROOTDIR")
|
||||
log_file = parameters.get_admin("stats", "LOGFILE")
|
||||
rrd_rootdir = parameters.get_admin("stats", "RRD_ROOTDIR")
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-l","--logFile", default=log_file,
|
||||
|
||||
@@ -21,12 +21,15 @@ def infos():
|
||||
|
||||
def init():
|
||||
events.register("AdminMenuDisplay", menu)
|
||||
parameters.register("stats", "LOGFILE", "string", "/var/log/mail.log",
|
||||
help=_("Path to log file used to collect statistics"))
|
||||
parameters.register("stats", "RRD_ROOTDIR", "string", "/tmp/mailng",
|
||||
help=_("Path to directory where RRD files are stored"))
|
||||
parameters.register("stats", "IMG_ROOTDIR", "string", "/tmp/mailng",
|
||||
help=_("Path to directory where PNG files are stored"))
|
||||
parameters.register_admin("stats", "LOGFILE", type="string",
|
||||
deflt="/var/log/mail.log",
|
||||
help=_("Path to log file used to collect statistics"))
|
||||
parameters.register_admin("stats", "RRD_ROOTDIR", type="string",
|
||||
deflt="/tmp/mailng",
|
||||
help=_("Path to directory where RRD files are stored"))
|
||||
parameters.register_admin("stats", "IMG_ROOTDIR", type="string",
|
||||
deflt="/tmp/mailng",
|
||||
help=_("Path to directory where PNG files are stored"))
|
||||
|
||||
def destroy():
|
||||
events.unregister("AdminMenuDisplay", menu)
|
||||
|
||||
@@ -53,7 +53,7 @@ def graph_display(request,dom_id,graph_t=graph_types):
|
||||
"page" : "Domain statistics", "graph" : graph_nature,
|
||||
"domain": domain, "domains" : domains, "messages" : errors,
|
||||
"types" : graph_type, "tmp_path" : tmp_path,
|
||||
"img_rootdir" : parameters.get("stats", "IMG_ROOTDIR")})
|
||||
"img_rootdir" : parameters.get_admin("stats", "IMG_ROOTDIR")})
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
@@ -75,7 +75,7 @@ def adminindex(request):
|
||||
"graphs" : graph_list,
|
||||
"periods" : ["day", "week", "month", "year","Custom"],
|
||||
"period" : period, "cal" : CH_print,
|
||||
"img_rootdir" : parameters.get("stats", "IMG_ROOTDIR")})
|
||||
"img_rootdir" : parameters.get_admin("stats", "IMG_ROOTDIR")})
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
@@ -109,7 +109,7 @@ def custom_period(request):
|
||||
"start" : start_ref,
|
||||
"end" : end_ref,
|
||||
"messages" : ["Custom period not selected"],
|
||||
"img_rootdir" : parameters.get("stats", "IMG_ROOTDIR")})
|
||||
"img_rootdir" : parameters.get_admin("stats", "IMG_ROOTDIR")})
|
||||
|
||||
period_name = "%s_%s" %(start.replace('/',''),end.replace('/',''))
|
||||
G = Grapher()
|
||||
@@ -130,7 +130,7 @@ def custom_period(request):
|
||||
"start" : start_ref,
|
||||
"end" : end_ref,
|
||||
"messages" : None,
|
||||
"img_rootdir" : parameters.get("stats", "IMG_ROOTDIR")})
|
||||
"img_rootdir" : parameters.get_admin("stats", "IMG_ROOTDIR")})
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -147,4 +147,4 @@ def index(request, dom_id=None):
|
||||
"graphs" : graph_list,
|
||||
"periods" : ["day", "week", "month", "year","Custom"],
|
||||
"period" : period,
|
||||
"img_rootdir" : parameters.get("stats", "IMG_ROOTDIR")})
|
||||
"img_rootdir" : parameters.get_admin("stats", "IMG_ROOTDIR")})
|
||||
|
||||
@@ -140,11 +140,9 @@ class IMAPconnector(object):
|
||||
__metaclass__ = ConnectionsManager
|
||||
|
||||
def __init__(self, user=None, password=None):
|
||||
print "IMAP constructor"
|
||||
|
||||
self.criterions = []
|
||||
self.address = parameters.get("webmail", "IMAP_SERVER")
|
||||
self.port = int(parameters.get("webmail", "IMAP_PORT"))
|
||||
self.address = parameters.get_admin("webmail", "IMAP_SERVER")
|
||||
self.port = int(parameters.get_admin("webmail", "IMAP_PORT"))
|
||||
self.invalid = False
|
||||
status, msg = self.login(user, password)
|
||||
if not status:
|
||||
@@ -153,7 +151,7 @@ class IMAPconnector(object):
|
||||
def login(self, user, passwd):
|
||||
import imaplib
|
||||
try:
|
||||
secured = parameters.get("webmail", "IMAP_SECURED")
|
||||
secured = parameters.get_admin("webmail", "IMAP_SECURED")
|
||||
if secured == "yes":
|
||||
self.m = imaplib.IMAP4_SSL(self.address, self.port)
|
||||
else:
|
||||
@@ -321,7 +319,8 @@ class ImapListing(EmailListing):
|
||||
reset_wm_url = False
|
||||
|
||||
def __init__(self, user, **kwargs):
|
||||
self.mbc = IMAPconnector(user=user)
|
||||
self.user = user
|
||||
self.mbc = IMAPconnector(user=user.username)
|
||||
if kwargs.has_key("pattern"):
|
||||
self.parse_search_parameters(kwargs["criteria"],
|
||||
kwargs["pattern"])
|
||||
@@ -345,8 +344,11 @@ class ImapListing(EmailListing):
|
||||
md_folders = [{"name" : "INBOX", "icon" : "overview.png"},
|
||||
{"name" : 'Drafts'},
|
||||
{"name" : 'Junk'},
|
||||
{"name" : 'Sent'},
|
||||
{"name" : 'Trash', "icon" : "trash.png"}]
|
||||
{"name" : parameters.get_user(self.user, "webmail",
|
||||
"SENT_FOLDER")},
|
||||
{"name" : parameters.get_user(self.user, "webmail",
|
||||
"TRASH_FOLDER"),
|
||||
"icon" : "trash.png"}]
|
||||
folders = self.mbc.listfolders(md_folders=md_folders)
|
||||
md_folders += self.__parse_folders(folders)
|
||||
for fd in md_folders:
|
||||
|
||||
+24
-14
@@ -8,20 +8,30 @@ def init():
|
||||
events.register("UserMenuDisplay", menu)
|
||||
events.register("UserLogin", userlogin)
|
||||
events.register("UserLogout", userlogout)
|
||||
parameters.register("webmail", "IMAP_SERVER", "string", "127.0.0.1",
|
||||
help=_("Address of your IMAP server"))
|
||||
parameters.register("webmail", "IMAP_SECURED", "list_yesno", "no",
|
||||
help=_("Use a secured connection to access IMAP server"))
|
||||
parameters.register("webmail", "IMAP_PORT", "int", "143",
|
||||
help=_("Listening port of your IMAP server"))
|
||||
parameters.register("webmail", "SMTP_SERVER", "string", "127.0.0.1",
|
||||
help=_("Address of your SMTP server"))
|
||||
parameters.register("webmail", "SMTP_PORT", "int", "25",
|
||||
help=_("Listening port of your SMTP server"))
|
||||
parameters.register("webmail", "SMTP_AUTHENTICATION", "list_yesno", "no",
|
||||
help=_("Server needs authentication"))
|
||||
parameters.register("webmail", "SMTP_SECURED", "list_yesno", "no",
|
||||
help=_("Use a secured connection to access SMTP server"))
|
||||
parameters.register_admin("webmail", "IMAP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=_("Address of your IMAP server"))
|
||||
parameters.register_admin("webmail", "IMAP_SECURED", type="list_yesno",
|
||||
deflt="no",
|
||||
help=_("Use a secured connection to access IMAP server"))
|
||||
parameters.register_admin("webmail", "IMAP_PORT", type="int", deflt="143",
|
||||
help=_("Listening port of your IMAP server"))
|
||||
parameters.register_admin("webmail", "SMTP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=_("Address of your SMTP server"))
|
||||
parameters.register_admin("webmail", "SMTP_PORT", type="int", deflt="25",
|
||||
help=_("Listening port of your SMTP server"))
|
||||
parameters.register_admin("webmail", "SMTP_AUTHENTICATION", type="list_yesno",
|
||||
deflt="no",
|
||||
help=_("Server needs authentication"))
|
||||
parameters.register_admin("webmail", "SMTP_SECURED", type="list_yesno",
|
||||
deflt="no",
|
||||
help=_("Use a secured connection to access SMTP server"))
|
||||
|
||||
parameters.register_user("webmail", "TRASH_FOLDER", type="string", deflt="Trash",
|
||||
help=_("Folder where deleted messages go"))
|
||||
parameters.register_user("webmail", "SENT_FOLDER", type="string", deflt="Sent",
|
||||
help=_("Folder where copies of sent messages go"))
|
||||
|
||||
def destroy():
|
||||
events.unregister("UserMenuDisplay", menu)
|
||||
|
||||
+14
-13
@@ -47,7 +47,7 @@ def folder(request, name, updatenav=True):
|
||||
optparams["criteria"] = request.session["criteria"]
|
||||
else:
|
||||
optparams["reset"] = True
|
||||
lst = ImapListing(request.user.username,
|
||||
lst = ImapListing(request.user,
|
||||
baseurl=name, folder=name, order=order, **optparams)
|
||||
|
||||
page = lst.paginator.getpage(request.session["page"])
|
||||
@@ -67,14 +67,14 @@ def folder(request, name, updatenav=True):
|
||||
@login_required
|
||||
@is_not_localadmin()
|
||||
def index(request):
|
||||
#try:
|
||||
navp = request.session.has_key("navparams") \
|
||||
and request.session["navparams"] or {}
|
||||
lst = ImapListing(request.user.username,
|
||||
baseurl="INBOX", navparams=navp, folder="INBOX",
|
||||
empty=True)
|
||||
#except Exception, exp:
|
||||
# return _render_error(request, user_context={"error" : exp})
|
||||
try:
|
||||
navp = request.session.has_key("navparams") \
|
||||
and request.session["navparams"] or {}
|
||||
lst = ImapListing(request.user,
|
||||
baseurl="INBOX", navparams=navp, folder="INBOX",
|
||||
empty=True)
|
||||
except Exception, exp:
|
||||
return _render_error(request, user_context={"error" : exp})
|
||||
return lst.render(request)
|
||||
|
||||
def fetchmail(request, folder, mail_id, all=False):
|
||||
@@ -211,18 +211,19 @@ def send_mail(request, withctx=False, origmsg=None):
|
||||
msg["Cc"] = request.POST["cc"]
|
||||
rcpts += msg["Cc"].split(",")
|
||||
try:
|
||||
s = smtplib.SMTP(parameters.get("webmail", "SMTP_SERVER"))
|
||||
if parameters.get("webmail", "SMTP_SECURED") == "yes":
|
||||
s = smtplib.SMTP(parameters.get_admin("webmail", "SMTP_SERVER"))
|
||||
if parameters.get_admin("webmail", "SMTP_SECURED") == "yes":
|
||||
s.starttls()
|
||||
except (smtplib.SMTPException, ssl.SSLError), error:
|
||||
print error
|
||||
# Prévoir la remontée de cette erreur au niveau du client!!
|
||||
|
||||
if parameters.get("webmail", "SMTP_AUTHENTICATION") == "yes":
|
||||
if parameters.get_admin("webmail", "SMTP_AUTHENTICATION") == "yes":
|
||||
s.login(request.user.username, request.session["password"])
|
||||
s.sendmail(msg['From'], rcpts, msg.as_string())
|
||||
s.quit()
|
||||
IMAPconnector(user=request.user.username).push_mail("Sent", msg)
|
||||
sentfolder = parameters.get_user(request.user, "webmail", "SENT_FOLDER")
|
||||
IMAPconnector(user=request.user.username).push_mail(sentfolder, msg)
|
||||
ctx = getctx("ok", url=__get_current_url(request))
|
||||
else:
|
||||
ctx = getctx("ko", level=2, listing=render_to_string("webmail/compose.html",
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ def _render_error(request, errortpl="error", user_context={}):
|
||||
|
||||
def exec_as_vuser(cmd):
|
||||
code, output = exec_cmd("sudo -u %s %s" \
|
||||
% (parameters.get("admin", "VIRTUAL_UID"), cmd))
|
||||
% (parameters.get_admin("admin", "VIRTUAL_UID"), cmd))
|
||||
if code:
|
||||
exec_cmd("echo '%s' >> /tmp/vmail.log" % output)
|
||||
return False
|
||||
@@ -57,13 +57,13 @@ def decode(s, encodings=('utf8', 'latin1', 'windows-1252', 'ascii')):
|
||||
|
||||
def is_not_localadmin(errortpl="error"):
|
||||
def dec(f):
|
||||
def wrapped_f(request, **kwargs):
|
||||
def wrapped_f(request, *args, **kwargs):
|
||||
if request.user.id == 1:
|
||||
return _render_error(request, errortpl, {
|
||||
"error" : _("Invalid action, %s is a local user" \
|
||||
% request.user.username)
|
||||
})
|
||||
return f(request, **kwargs)
|
||||
return f(request, *args, **kwargs)
|
||||
return wrapped_f
|
||||
return dec
|
||||
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ class SimpleBackend:
|
||||
return None
|
||||
|
||||
def check_password(password, crypted):
|
||||
scheme = parameters.get("admin", "PASSWORD_SCHEME")
|
||||
scheme = parameters.get_admin("admin", "PASSWORD_SCHEME")
|
||||
if scheme == "crypt":
|
||||
return crypt.crypt(password, crypted) == crypted
|
||||
if scheme == "md5":
|
||||
@@ -35,7 +35,7 @@ def check_password(password, crypted):
|
||||
return password
|
||||
|
||||
def crypt_password(password):
|
||||
scheme = parameters.get("admin", "PASSWORD_SCHEME")
|
||||
scheme = parameters.get_admin("admin", "PASSWORD_SCHEME")
|
||||
if scheme == "crypt":
|
||||
salt = ''.join(Random().sample(string.letters + string.digits, 2))
|
||||
return crypt.crypt(password, salt)
|
||||
|
||||
@@ -15,20 +15,75 @@ class Migration(SchemaMigration):
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
))
|
||||
db.send_create_signal('lib', ['Parameter'])
|
||||
|
||||
# Adding model 'UserParameter'
|
||||
db.create_table('lib_userparameter', (
|
||||
('value', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
|
||||
))
|
||||
db.send_create_signal('lib', ['UserParameter'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'Parameter'
|
||||
db.delete_table('lib_parameter')
|
||||
|
||||
# Deleting model 'UserParameter'
|
||||
db.delete_table('lib_userparameter')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'lib.parameter': {
|
||||
'Meta': {'object_name': 'Parameter'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'lib.userparameter': {
|
||||
'Meta': {'object_name': 'UserParameter'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
|
||||
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class Parameter(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
value = models.CharField(max_length=255)
|
||||
|
||||
class UserParameter(models.Model):
|
||||
user = models.ForeignKey(User)
|
||||
name = models.CharField(max_length=255)
|
||||
value = models.CharField(max_length=255)
|
||||
|
||||
+49
-11
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import string
|
||||
from mailng.lib.models import Parameter
|
||||
from mailng.lib.models import *
|
||||
|
||||
"""
|
||||
This interface provides a simple way to declare and store parameters
|
||||
@@ -14,6 +14,7 @@ Only super users will be able to access this part of the web interface.
|
||||
"""
|
||||
|
||||
_params = {}
|
||||
_levels = {'A' : 'admin', 'U' : 'user'}
|
||||
|
||||
class NotDefined(Exception):
|
||||
def __init__(self, app, name):
|
||||
@@ -24,16 +25,32 @@ class NotDefined(Exception):
|
||||
return "Application '%s' and/or parameter '%s' not defined" \
|
||||
% (self.app, self.name)
|
||||
|
||||
def register(app, name, type="string", deflt=None, help=None, **kwargs):
|
||||
def __is_defined(app, level, name):
|
||||
if not level in _levels.keys() \
|
||||
or not app in _params.keys() \
|
||||
or not name in _params[app][level].keys():
|
||||
raise NotDefined(app, name)
|
||||
|
||||
def __register(app, level, name, type="string", deflt=None, help=None, **kwargs):
|
||||
"""Register a new parameter.
|
||||
|
||||
app corresponds to a core component (admin, main) or an extension.
|
||||
"""
|
||||
if not app in _params.keys():
|
||||
_params[app] = {}
|
||||
_params[app][name] = {"type" : type, "default" : deflt, "help" : help}
|
||||
for lvl in _levels.keys():
|
||||
_params[app][lvl] = {}
|
||||
if not level in _levels.keys():
|
||||
return
|
||||
_params[app][level][name] = {"type" : type, "default" : deflt, "help" : help}
|
||||
for k, v in kwargs.iteritems():
|
||||
_params[app][name][k] = v
|
||||
_params[app][level][name][k] = v
|
||||
|
||||
def register_admin(app, name, **kwargs):
|
||||
return __register(app, 'A', name, **kwargs)
|
||||
|
||||
def register_user(app, name, **kwargs):
|
||||
return __register(app, 'U', name, **kwargs)
|
||||
|
||||
def unregister_app(app):
|
||||
if not _params.has_key(app):
|
||||
@@ -41,9 +58,9 @@ def unregister_app(app):
|
||||
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)
|
||||
def save_admin(app, name, value):
|
||||
__is_defined(app, 'A', name)
|
||||
|
||||
fullname = "%s.%s" % (app, name)
|
||||
try:
|
||||
p = Parameter.objects.get(name=fullname)
|
||||
@@ -55,11 +72,32 @@ def save(app, name, value):
|
||||
p.save()
|
||||
return True
|
||||
|
||||
def get(app, name):
|
||||
if not app in _params.keys() or not name in _params[app].keys():
|
||||
raise NotDefined(app, name)
|
||||
def save_user(user, app, name, value):
|
||||
__is_defined(app, 'U', name)
|
||||
fullname = "%s.%s" % (app, name)
|
||||
try:
|
||||
p = UserParameter.objects.get(user=user, name=fullname)
|
||||
except UserParameter.DoesNotExist:
|
||||
p = UserParameter()
|
||||
p.user = user
|
||||
p.name = fullname
|
||||
if p.value != value:
|
||||
p.value = value
|
||||
p.save()
|
||||
return True
|
||||
|
||||
def get_admin(app, name):
|
||||
__is_defined(app, "A", name)
|
||||
try:
|
||||
p = Parameter.objects.get(name="%s.%s" % (app, name))
|
||||
except Parameter.DoesNotExist:
|
||||
return _params[app][name]["default"]
|
||||
return _params[app]["A"][name]["default"]
|
||||
return p.value
|
||||
|
||||
def get_user(user, app, name):
|
||||
__is_defined(app, "U", name)
|
||||
try:
|
||||
p = UserParameter.objects.get(user=user, name="%s.%s" % (app, name))
|
||||
except UserParameter.DoesNotExist:
|
||||
return _params[app]["U"][name]["default"]
|
||||
return p.value
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
window.addEvent('domready', function() {
|
||||
new DatePicker("#untildate", {
|
||||
pickerClass: "datepicker_vista",
|
||||
allowEmpty: true
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
window.addEvent('domready', function() {
|
||||
var tip = new Tips($$(".Tips"));
|
||||
var accordion = new Accordion('h3.atStart', 'div.atStart', {
|
||||
opacity: true,
|
||||
onActive: function(toggler, element){
|
||||
toggler.setStyle('color', '#ff3300');
|
||||
},
|
||||
|
||||
onBackground: function(toggler, element){
|
||||
toggler.setStyle('color', '#222');
|
||||
}
|
||||
}, $('accordion'));
|
||||
|
||||
new DatePicker("#untildate", {
|
||||
pickerClass: "datepicker_vista",
|
||||
allowEmpty: true
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@ window.addEvent('domready', function() {
|
||||
var tip = new Tips($$(".Tips"));
|
||||
|
||||
var accordion = new Accordion('h3.atStart', 'div.atStart', {
|
||||
opacity: false,
|
||||
opacity: true,
|
||||
onActive: function(toggler, element){
|
||||
toggler.setStyle('color', '#ff3300');
|
||||
},
|
||||
|
||||
@@ -4,19 +4,8 @@
|
||||
{% settings_menu "parameters" user %}
|
||||
{% endblock %}
|
||||
{% block setcontent %}
|
||||
{% load i18n %}
|
||||
{% url admin.views.saveparameters as action %}
|
||||
<form method="POST" action="{{ action }}">
|
||||
<div id="accordion">
|
||||
{% for app in gparams %}
|
||||
<h3 class="toggler atStart">{{ app.name }}</h3>
|
||||
<div class="element atStart">
|
||||
{% for p in app.params %}
|
||||
{% param app.name p %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p><input type="submit" name="update" value="{% trans 'Save' %}" /></p>
|
||||
{% include "common/parameters.html" %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{% load i18n %}
|
||||
{% load admin_extras %}
|
||||
<p><input type="submit" name="update" value="{% trans 'Save' %}" /></p>
|
||||
<div id="accordion">
|
||||
{% for app in gparams %}
|
||||
<h3 class="toggler atStart">{{ app.name }}</h3>
|
||||
<div class="element atStart">
|
||||
{% for p in app.params %}
|
||||
{% param app.name p %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<script src="/static/js/calendar.js" type="text/javascript"></script>
|
||||
<script src="/static/js/main.js" type="text/javascript"></script>
|
||||
<script src="/static/js/preferences.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/stylesheets/calendar.css" />
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "General" %}{% endblock %}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{% extends "nlayout.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<script src="/static/js/preferences.js" type="text/javascript"></script>
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "Preferences" %}{% endblock %}
|
||||
{% block content %}
|
||||
<form method="POST" action="{% url userprefs.views.savepreferences %}">
|
||||
{% include "common/parameters.html" %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -40,7 +40,7 @@ if settings.DEBUG:
|
||||
urlpatterns += patterns(
|
||||
'',
|
||||
(r'^img/stats/(?P<path>.*)/$', 'django.views.static.serve',
|
||||
{'document_root': parameters.get("stats", "IMG_ROOTDIR")})
|
||||
{'document_root': parameters.get_admin("stats", "IMG_ROOTDIR")})
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ def uprefs_menu(user):
|
||||
entries = [
|
||||
{"name" : "userprefs",
|
||||
"img" : "/static/pics/user.png",
|
||||
"label" : _("Preferences"),
|
||||
"label" : _("Options"),
|
||||
"class" : "topdropdown",
|
||||
"menu" : [
|
||||
{"name" : "changepwd",
|
||||
@@ -20,9 +20,14 @@ def uprefs_menu(user):
|
||||
"img" : "/static/pics/edit.png",
|
||||
"label" : _("Change password"),
|
||||
"class" : "boxed",
|
||||
"rel" : "{handler:'iframe',size:{x:350,y:220}}"}
|
||||
"rel" : "{handler:'iframe',size:{x:350,y:220}}"},
|
||||
{"name" : "preferences",
|
||||
"img" : "/static/pics/user.png",
|
||||
"label" : _("Preferences"),
|
||||
"url" : reverse(userprefs.views.preferences),
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
entries[0]["menu"] += events.raiseQueryEvent("UserMenuDisplay",
|
||||
target="user_menu_bar")
|
||||
|
||||
@@ -2,6 +2,8 @@ from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mailng.userprefs.views',
|
||||
url(r'^$', 'index'),
|
||||
(r'^preferences/$', 'preferences'),
|
||||
(r'^preferences/save/$', 'savepreferences'),
|
||||
(r'^changepassword/$', 'changepassword'),
|
||||
(r'^confirm/$', 'confirm'),
|
||||
)
|
||||
|
||||
+35
-7
@@ -8,7 +8,7 @@ from django.contrib.auth.decorators \
|
||||
import login_required
|
||||
from django.utils import simplejson
|
||||
from django.utils.translation import ugettext as _
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko, parameters
|
||||
from mailng.lib.authbackends import crypt_password
|
||||
from forms import ChangePasswordForm
|
||||
from mailng.admin.models import Mailbox
|
||||
@@ -17,12 +17,6 @@ from mailng.admin.models import Mailbox
|
||||
def index(request):
|
||||
mb = Mailbox.objects.get(user=request.user.id)
|
||||
return _render(request, "userprefs/index.html", {})
|
||||
# try:
|
||||
# arm = ARmessage.objects.filter(mbox=mb.id, enabled=True)
|
||||
# except ARmessage.DoesNotExist:
|
||||
# arm = None
|
||||
# return _render(request, "userprefs/index.html", {"arm" : arm})
|
||||
|
||||
|
||||
@login_required
|
||||
def changepassword(request):
|
||||
@@ -46,6 +40,40 @@ def changepassword(request):
|
||||
"form" : form
|
||||
})
|
||||
|
||||
@login_required
|
||||
def preferences(request):
|
||||
apps = sorted(parameters._params.keys())
|
||||
gparams = []
|
||||
for app in apps:
|
||||
if not len(parameters._params[app]['U']):
|
||||
continue
|
||||
tmp = {"name" : app, "params" : []}
|
||||
for p in sorted(parameters._params[app]['U']):
|
||||
param_def = parameters._params[app]['U'][p]
|
||||
newdef = {"name" : p,
|
||||
"value" : parameters.get_user(request.user, app, p),
|
||||
"help" : param_def["help"],
|
||||
"default" : param_def["default"],
|
||||
"type" : param_def["type"]}
|
||||
if "values" in param_def.keys():
|
||||
newdef["values"] = param_def["values"]
|
||||
tmp["params"] += [newdef]
|
||||
gparams += [tmp]
|
||||
|
||||
return _render(request, 'userprefs/preferences.html', {
|
||||
"gparams" : gparams
|
||||
})
|
||||
|
||||
@login_required
|
||||
def savepreferences(request):
|
||||
for pname, v in request.POST.iteritems():
|
||||
if pname == "update":
|
||||
continue
|
||||
app, name = pname.split('.')
|
||||
parameters.save_user(request.user, app, name, v)
|
||||
|
||||
return HttpResponseRedirect(reverse(preferences))
|
||||
|
||||
@login_required
|
||||
def confirm(request):
|
||||
return render_to_response('userprefs/confirm.html', {
|
||||
|
||||
Reference in New Issue
Block a user