From 1e78648ecd1c5fed0baf00927fcfd7201ec234ae Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Fri, 14 Jun 2013 15:00:34 +0200 Subject: [PATCH] * force floating point operation for postgres * documentation update see #391 --- doc/integration/imap_and_smtp.rst | 107 ++++++++++++++++++++++++++++++ modoboa/admin/views.py | 2 +- 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/doc/integration/imap_and_smtp.rst b/doc/integration/imap_and_smtp.rst index 885570356..74a29ebcf 100644 --- a/doc/integration/imap_and_smtp.rst +++ b/doc/integration/imap_and_smtp.rst @@ -148,6 +148,19 @@ activated ones:: mail_plugins = quota +Inside *conf.d/10-master.conf*, update the *dict* service to set +proper permissions:: + + service dict { + # If dict proxy is used, mail processes should have access to its socket. + # For example: mode=0660, group=vmail and global mail_access_groups=vmail + unix_listener dict { + mode = 0600 + user = + #group = + } + } + Inside *conf.d/20-imap.conf*, activate the ``imap_quota`` plugin:: protocol imap { @@ -189,6 +202,100 @@ Finally, edit the *dovecot-dict-sql.conf* file and put the following content ins value_field = messages } +*PostgreSQL* users +------------------ + +Database schema update +^^^^^^^^^^^^^^^^^^^^^^ + +The `admin_quota` table is created by *Django* but unfortunately it +doesn't support `DEFAULT` constraints (it only simulates them when the +ORM is used). As *PostgreSQL* is a bit strict about constraint +violations, you must execute the following query manually:: + + db=> ALTER TABLE admin_quota ALTER COLUMN bytes SET DEFAULT 0; + db=> ALTER TABLE admin_quota ALTER COLUMN messages SET DEFAULT 0; + +Trigger +^^^^^^^ + +As indicated on `Dovecot's wiki +`_, you need a trigger to +properly update the quota. Unfortunately, the provided example won't +work for Modoboa. You should use the following one instead: + +.. sourcecode:: sql + + CREATE OR REPLACE FUNCTION merge_quota() RETURNS TRIGGER AS $$ + BEGIN + IF NEW.messages < 0 OR NEW.messages IS NULL THEN + -- ugly kludge: we came here from this function, really do try to insert + IF NEW.messages IS NULL THEN + NEW.messages = 0; + ELSE + NEW.messages = -NEW.messages; + END IF; + return NEW; + END IF; + + LOOP + UPDATE admin_quota SET bytes = bytes + NEW.bytes, + messages = messages + NEW.messages + WHERE username = NEW.username; + IF found THEN + RETURN NULL; + END IF; + + BEGIN + IF NEW.messages = 0 THEN + RETURN NEW; + ELSE + NEW.messages = - NEW.messages; + return NEW; + END IF; + EXCEPTION WHEN unique_violation THEN + -- someone just inserted the record, update it + END; + END LOOP; + END; + $$ LANGUAGE plpgsql; + + CREATE OR REPLACE FUNCTION set_mboxid() RETURNS TRIGGER AS $$ + DECLARE + mboxid INTEGER; + BEGIN + SELECT admin_mailbox.id INTO STRICT mboxid FROM admin_mailbox INNER JOIN admin_user ON admin_mailbox.user_id=admin_user.id WHERE admin_user.username=NEW.username; + UPDATE admin_quota SET mbox_id = mboxid + WHERE username = NEW.username; + RETURN NULL; + END; + $$ LANGUAGE plpgsql; + + DROP TRIGGER IF EXISTS mergequota ON admin_quota; + CREATE TRIGGER mergequota BEFORE INSERT ON admin_quota + FOR EACH ROW EXECUTE PROCEDURE merge_quota(); + + DROP TRIGGER IF EXISTS setmboxid ON admin_quota; + CREATE TRIGGER setmboxid AFTER INSERT ON admin_quota + FOR EACH ROW EXECUTE PROCEDURE set_mboxid(); + +Copy this example into a file (for example: *quota-trigger.sql*) on +server running *postgres* and execute the following commands:: + + $ su - postgres + $ psql < /path/to/quota-trigger.sql + $ exit + +Forcing recalculation +--------------------- + +For existing installations, *Dovecot* (> 2) offers a command to +recalculate the current quota usages. For example, if you want to +update all usages, run the following command:: + + $ doveadmin quota recalc -A + +Be carefull, it can take a while to execute. ManageSieve/Sieve ================= diff --git a/modoboa/admin/views.py b/modoboa/admin/views.py index 60e9ebf27..402c25899 100644 --- a/modoboa/admin/views.py +++ b/modoboa/admin/views.py @@ -395,7 +395,7 @@ def list_quotas(request, tplname="admin/quotas.html"): mboxes = mboxes.order_by("%s%s" % (sort_dir, sort_order)) elif sort_order == "quota_usage": if db_type() == "postgres": - select = '(admin_quota.bytes / (CAST(admin_mailbox.quota AS BIGINT) * 1048576)) * 100' + select = '(admin_quota.bytes::float / (CAST(admin_mailbox.quota AS BIGINT) * 1048576)) * 100' else: select = 'admin_quota.bytes / (admin_mailbox.quota * 1048576) * 100' mboxes = mboxes.extra(