mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge branch 'master' into feature/radicale
This commit is contained in:
+2
-2
@@ -19,7 +19,7 @@ easy. Actually, all current features are extensions.
|
||||
|
||||
It is written in Python and uses the `Django
|
||||
<https://www.djangoproject.com>`_, `jQuery <http://jquery.com>`_ and
|
||||
`Bootstap, from Twitter <http://twitter.github.com/bootstrap/>`_
|
||||
`Bootstrap, from Twitter <http://twitter.github.com/bootstrap/>`_
|
||||
frameworks.
|
||||
|
||||
*************
|
||||
@@ -37,7 +37,7 @@ Main features
|
||||
Documentation
|
||||
*************
|
||||
|
||||
A detailled `documentation <https://modoboa.readthedocs.org/>`_ will help you
|
||||
A detailed `documentation <https://modoboa.readthedocs.org/>`_ will help you
|
||||
to install, use or extend Modoboa.
|
||||
|
||||
*************
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ copyright = u'2014, Antoine Nguyen'
|
||||
# The short X.Y version.
|
||||
version = '1.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.1.4'
|
||||
release = '1.1.5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -66,6 +66,14 @@ The *admin* application exposes several parameters, they are presented below:
|
||||
| |is specified | |
|
||||
+--------------------+--------------------+--------------------+
|
||||
|
||||
.. note::
|
||||
|
||||
If you are not familiar with virtual domain hosting, you should
|
||||
take a look at `postfix's documentation
|
||||
<http://www.postfix.org/VIRTUAL_README.html>`_. This `How to
|
||||
<https://help.ubuntu.com/community/PostfixVirtualMailBoxClamSmtpHowto>`_
|
||||
also contains useful information.
|
||||
|
||||
.. note::
|
||||
|
||||
A random secret key will be generated each time the *Parameters*
|
||||
@@ -76,6 +84,20 @@ The *admin* application exposes several parameters, they are presented below:
|
||||
Specific LDAP parameters are also available, see :ref:`LDAP
|
||||
authentication <ldap_auth>`.
|
||||
|
||||
***********
|
||||
Media files
|
||||
***********
|
||||
|
||||
Modoboa uses a specific directory to upload files (ie. when the
|
||||
webmail is in use) or to create ones (ex: graphical statistics). This
|
||||
directory is named ``media`` and is located inside modoboa's
|
||||
installation directory (called ``modoboa_site`` in this
|
||||
documentation).
|
||||
|
||||
To work properly, the system user which runs modoboa (``www-data``,
|
||||
``apache``, whatever) must have write access to this directory.
|
||||
|
||||
|
||||
*************
|
||||
Customization
|
||||
*************
|
||||
@@ -297,6 +319,9 @@ online panel.
|
||||
To use it, you can setup a cron job to run every night::
|
||||
|
||||
0 0 * * * <modoboa_site>/manage.py cleanlogs
|
||||
#
|
||||
# Or like this if you use a virtual environment:
|
||||
# 0 0 * * * <virtualenv path/bin/python> <modoboa_site>/manage.py cleanlogs
|
||||
|
||||
Cleaning the session table
|
||||
==========================
|
||||
@@ -311,3 +336,6 @@ cleanup``. That script deletes any session in the session table whose
|
||||
For example, you could setup a cron job to run this script every night::
|
||||
|
||||
0 0 * * * <modoboa_site>/manage.py cleanup
|
||||
#
|
||||
# Or like this if you use a virtual environment:
|
||||
# 0 0 * * * <virtualenv path/bin/python> <modoboa_site>/manage.py cleanup
|
||||
|
||||
@@ -91,7 +91,7 @@ sure your database is using UTF8 as a default charset.
|
||||
Deployment
|
||||
**********
|
||||
|
||||
`modoboa-admin.py`, a command line tool, let you deploy a
|
||||
`modoboa-admin.py`, a command line tool, lets you deploy a
|
||||
*ready-to-use* Modoboa site using only one instruction::
|
||||
|
||||
$ modoboa-admin.py deploy modoboa_example --syncdb --collectstatic [--with-amavis] [--dburl database-url] [--amavis_dburl database-url]
|
||||
@@ -155,8 +155,9 @@ server::
|
||||
|
||||
You should be able to access Modoboa at http://localhost:8000/.
|
||||
|
||||
For a fully working interface using the embedded HTTP server, you need to set the ``DEBUG``
|
||||
parameter in settings.py to ``True``.
|
||||
For a fully working interface using the embedded HTTP server, you need
|
||||
to set the ``DEBUG`` parameter in settings.py to ``True``.
|
||||
|
||||
For a production environment, we recommend using a stable webserver
|
||||
like :ref:`apache2` or :ref:`nginx-label`. Don't forget to set ``DEBUG`` back to ``False``.
|
||||
like :ref:`apache2` or :ref:`nginx-label`. Don't forget to set
|
||||
``DEBUG`` back to ``False``.
|
||||
|
||||
@@ -99,8 +99,46 @@ This plugin provides a simple management frontend for `amavisd-new
|
||||
you're planning to use the :ref:`selfservice`, you'll need version
|
||||
**2.8.0**.
|
||||
|
||||
Database
|
||||
========
|
||||
Quick Amavis setup
|
||||
==================
|
||||
|
||||
By default, amavis doesn't use a database. To configure this
|
||||
behaviour, you first need to create a dedicated database. This step is a
|
||||
bit manual since no *ready-to-use* SQL schema is provided by
|
||||
amavis. The information is located inside README files, one for `MySQL
|
||||
<http://www.amavis.org/README.sql-mysql.txt>`_ and one for `PostgreSQL
|
||||
<http://www.amavis.org/README.sql-pg.txt>`_.
|
||||
|
||||
Then, you must tell amavis to use this database for lookups and
|
||||
quarantined messages storing. Here is a working configuration sample::
|
||||
|
||||
@lookup_sql_dsn =
|
||||
(['DBI:<driver>:database=<database>;host=<dbhost>;port=<dbport>', '<dbuser>', '<password>]']);
|
||||
|
||||
@storage_sql_dsn =
|
||||
(['DBI:<driver>:database=<database>;host=<dbhost>;port=<dbport>', '<dbuser>', '<password>]']);
|
||||
|
||||
$virus_quarantine_method = 'sql:';
|
||||
$spam_quarantine_method = 'sql:';
|
||||
$banned_files_quarantine_method = 'sql:';
|
||||
$bad_header_quarantine_method = 'sql:';
|
||||
|
||||
$virus_quarantine_to = 'virus-quarantine';
|
||||
$banned_quarantine_to = 'banned-quarantine';
|
||||
$bad_header_quarantine_to = 'bad-header-quarantine';
|
||||
$spam_quarantine_to = 'spam-quarantine';
|
||||
|
||||
Replace values between ``<>`` by yours. To know how to configure
|
||||
amavis to allow quarantined messages release, read this :ref:`section
|
||||
<amavis_release>`.
|
||||
|
||||
.. note::
|
||||
|
||||
Amavis configuration allows for separate lookup and storage
|
||||
databases but Modoboa doesn't support it yet.
|
||||
|
||||
Connect Modoboa and Amavis
|
||||
==========================
|
||||
|
||||
You must tell to Modoboa where it can find the amavis
|
||||
database. Inside :file:`settings.py`, add a new connection to the
|
||||
@@ -120,17 +158,6 @@ database. Inside :file:`settings.py`, add a new connection to the
|
||||
|
||||
Replace values between ``<>`` with yours.
|
||||
|
||||
.. note::
|
||||
|
||||
Modoboa doesn't create amavis tables. You need to install them
|
||||
following the `official documentation
|
||||
<http://www.amavis.org/#doc>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
Amavis configuration allows for separate lookup and storage
|
||||
databases but Modoboa doesn't support it yet.
|
||||
|
||||
Cleanup
|
||||
-------
|
||||
|
||||
@@ -140,6 +167,9 @@ purge the quarantine database. To use it, add the following line
|
||||
inside root's crontab::
|
||||
|
||||
0 0 * * * <modoboa_site>/manage.py qcleanup
|
||||
#
|
||||
# Or like this if you use a virtual environment:
|
||||
# 0 0 * * * <virtualenv path/bin/python> <modoboa_site>/manage.py qcleanup
|
||||
|
||||
Replace ``modoboa_site`` with the path of your Modoboa instance.
|
||||
|
||||
@@ -147,6 +177,8 @@ By default, messages older than 14 days are automatically purged. You
|
||||
can modify this value by changing the ``MAX_MESSAGES_AGE`` parameter
|
||||
in the online panel.
|
||||
|
||||
.. _amavis_release:
|
||||
|
||||
Release messages
|
||||
================
|
||||
|
||||
@@ -206,6 +238,9 @@ administrators or domain administrators. To use it, add the following
|
||||
example line to root's crontab::
|
||||
|
||||
0 12 * * * <modoboa_site>/manage.py amnotify --baseurl='<modoboa_url>'
|
||||
#
|
||||
# Or like this if you use a virtual environment:
|
||||
# 0 12 * * * <virtualenv path/bin/python> <modoboa_site>/manage.py amnotify --baseurl='<modoboa_url>'
|
||||
|
||||
You are free to change the frequency.
|
||||
|
||||
@@ -279,7 +314,7 @@ files (see `rrdtool <http://oss.oetiker.ch/rrdtool/>`_) and then
|
||||
generates graphics in PNG format.
|
||||
|
||||
To use it, go to the online parameters panel and adapt the following
|
||||
ones to your environnement:
|
||||
ones to your environment:
|
||||
|
||||
+--------------------+--------------------+--------------------------+
|
||||
|Name |Description |Default value |
|
||||
@@ -307,6 +342,9 @@ To finish, you need to collect information periodically in order to
|
||||
feed the RRD files. Add the following line into root's crontab::
|
||||
|
||||
*/5 * * * * <modoboa_site>/manage.py logparser &> /dev/null
|
||||
#
|
||||
# Or like this if you use a virtual environment:
|
||||
# 0/5 * * * * <virtualenv path/bin/python> <modoboa_site>/manage.py logparser &> /dev/null
|
||||
|
||||
Replace ``<modoboa_site>`` with the path of your Modoboa instance.
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ requires a migration.
|
||||
|
||||
$ python manage.py migrate admin
|
||||
|
||||
#. Update SQL queries used in your environnement (see
|
||||
#. Update SQL queries used in your environment (see
|
||||
:ref:`postfix` or :ref:`dovecot`).
|
||||
|
||||
#. Update Postfix configuration so that it can handle domain aliases
|
||||
|
||||
@@ -155,7 +155,7 @@ MySQL users
|
||||
|
||||
user_query = SELECT '<mailboxes storage directory>/%d/%n' AS home, <uid> as uid, <gid> as gid, concat('*:bytes=', mb.quota, 'M') AS quota_rule FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.address='%n' AND dom.name='%d'
|
||||
|
||||
iterate_query = SELECT email AS username FROM core_user
|
||||
iterate_query = SELECT email AS username FROM core_user WHERE email<>''
|
||||
|
||||
.. _dovecot_pg_queries:
|
||||
|
||||
@@ -174,7 +174,7 @@ PostgreSQL users
|
||||
|
||||
user_query = SELECT '<mailboxes storage directory>/%d/%n' AS home, <uid> as uid, <gid> as gid, '*:bytes=' || mb.quota || 'M' AS quota_rule FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.address='%n' AND dom.name='%d'
|
||||
|
||||
iterate_query = SELECT email AS username FROM core_user
|
||||
iterate_query = SELECT email AS username FROM core_user WHERE email<>''
|
||||
|
||||
SQLite users
|
||||
------------
|
||||
@@ -191,7 +191,7 @@ SQLite users
|
||||
|
||||
user_query = SELECT '<mailboxes storage directory>/%d/%n' AS home, <uid> as uid, <gid> as gid, ('*:bytes=' || mb.quota || 'M') AS quota_rule FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.address='%n' AND dom.name='%d'
|
||||
|
||||
iterate_query = SELECT email AS username FROM core_user
|
||||
iterate_query = SELECT email AS username FROM core_user WHERE email<>''
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -330,69 +330,16 @@ Trigger
|
||||
|
||||
As indicated on `Dovecot's wiki
|
||||
<http://wiki2.dovecot.org/Quota/Dict>`_, 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:
|
||||
properly update the quota.
|
||||
|
||||
.. sourcecode:: sql
|
||||
A working copy of this trigger is available on `Modoboa's website
|
||||
<http://modoboa.org/resources/modoboa_postgres_trigger.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 core_user ON admin_mailbox.user_id=core_user.id WHERE core_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: :file:`quota-trigger.sql`) on
|
||||
server running postgres and execute the following commands::
|
||||
Download this file and copy it on the server running postgres. Then,
|
||||
execute the following commands::
|
||||
|
||||
$ su - postgres
|
||||
$ psql [modoboa database] < /path/to/quota-trigger.sql
|
||||
$ psql [modoboa database] < /path/to/modoboa_postgres_trigger.sql
|
||||
$ exit
|
||||
|
||||
Replace ``[modoboa database]`` by the appropriate value.
|
||||
|
||||
@@ -48,45 +48,15 @@ following content inside::
|
||||
|
||||
This is just one possible configuration.
|
||||
|
||||
.. note::
|
||||
Django 1.3 users, please consult this `page <https://docs.djangoproject.com/en/1.3/howto/deployment/modwsgi/>`_,
|
||||
it contains an example :file:`wsgi.py` file.
|
||||
To use mod_wsgi daemon mode, add the two following directives just
|
||||
under ``WSGIScriptAlias``::
|
||||
|
||||
.. note::
|
||||
You will certainly need more configuration in order to launch
|
||||
Apache.
|
||||
WSGIDaemonProcess example.com python-path=<path to your site's dir>:<virtualenv path>/lib/python2.7/site-packages
|
||||
WSGIProcessGroup example.com
|
||||
|
||||
mod_python
|
||||
==========
|
||||
|
||||
First, make sure that mod_python is installed on your server.
|
||||
|
||||
Create a new virtualhost in your Apache configuration and put the
|
||||
following content inside::
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName <your value>
|
||||
DocumentRoot <path to your site's dir>
|
||||
|
||||
<Location "/">
|
||||
SetHandler mod_python
|
||||
PythonHandler django.core.handlers.modpython
|
||||
PythonPath "['<path to directory that contains your site's dir>'] + sys.path"
|
||||
SetEnv DJANGO_SETTINGS_MODULE <your site's name>.settings
|
||||
</Location>
|
||||
|
||||
Alias "/sitestatic" "<path to your site's dir>/sitestatic"
|
||||
<Location "/sitestatic/">
|
||||
SetHandler None
|
||||
</Location>
|
||||
|
||||
Alias "/media" "<path to your site's dir>/media"
|
||||
<Location "/media/">
|
||||
SetHandler None
|
||||
</Location>
|
||||
</VirtualHost>
|
||||
|
||||
This is just one possible configuration.
|
||||
Replace values between ``<>`` with yours. If you don't use a
|
||||
`virtualenv <http://virtualenv.readthedocs.org/en/latest/>`_, just
|
||||
remove the last part of the ``WSGIDaemonProcess`` directive.
|
||||
|
||||
.. note::
|
||||
You will certainly need more configuration in order to launch
|
||||
|
||||
@@ -10,19 +10,29 @@ from . import Command
|
||||
|
||||
class MapFilesGenerator(object):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, dbinfo=None):
|
||||
"""Constructor.
|
||||
"""
|
||||
self.template = Template("""user = {{ dbuser }}
|
||||
password = {{ dbpass }}
|
||||
dbname = {{ dbname }}
|
||||
hosts = {{ dbhost }}
|
||||
query = {{ query|safe }}
|
||||
""")
|
||||
self.tpl_context = {
|
||||
'dbhost': raw_input('Database host: '),
|
||||
'dbname': raw_input('Database name: '),
|
||||
'dbuser': raw_input('Username: '),
|
||||
'dbpass': getpass.getpass('Password: ')
|
||||
}
|
||||
if dbinfo is None:
|
||||
self.tpl_context = {
|
||||
'dbhost': raw_input('Database host: '),
|
||||
'dbname': raw_input('Database name: '),
|
||||
'dbuser': raw_input('Username: '),
|
||||
'dbpass': getpass.getpass('Password: ')
|
||||
}
|
||||
else:
|
||||
self.tpl_context = {
|
||||
'dbhost': dbinfo['HOST'],
|
||||
'dbname': dbinfo['NAME'],
|
||||
'dbuser': dbinfo['USER'],
|
||||
'dbpass': dbinfo['PASSWORD']
|
||||
}
|
||||
if not self.tpl_context['dbhost']:
|
||||
self.tpl_context['dbhost'] = '127.0.0.1'
|
||||
|
||||
@@ -77,13 +87,18 @@ query = {{ query|safe }}
|
||||
|
||||
class SQLiteMapFilesGenerator(MapFilesGenerator):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, dbinfo=None):
|
||||
self.template = Template("""dbpath = {{ dbpath }}
|
||||
query = {{ query|safe }}
|
||||
""")
|
||||
self.tpl_context = {
|
||||
'dbpath': raw_input('Database path: ')
|
||||
}
|
||||
if dbinfo is None:
|
||||
self.tpl_context = {
|
||||
'dbpath': raw_input('Database path: ')
|
||||
}
|
||||
else:
|
||||
self.tpl_context = {
|
||||
'dbpath': dbinfo['NAME']
|
||||
}
|
||||
|
||||
|
||||
class MapFile(object):
|
||||
@@ -194,14 +209,30 @@ class PostfixMapsCommand(Command):
|
||||
default='mysql',
|
||||
help='Used database type'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--dburl', type=str, nargs=1, default=None,
|
||||
help="url of Modoboa's database"
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--categories', type=str, nargs='*', default=['std'],
|
||||
help='Map file categories to generate (choices: std, autoreply)'
|
||||
)
|
||||
|
||||
def handle(self, parsed_args):
|
||||
"""Command entry point.
|
||||
"""
|
||||
dbinfo = None
|
||||
if parsed_args.dburl:
|
||||
import dj_database_url
|
||||
dbinfo = dj_database_url.config(default=parsed_args.dburl[0])
|
||||
if 'sqlite' in dbinfo['ENGINE']:
|
||||
parsed_args.dbtype = 'sqlite'
|
||||
elif 'psycopg2' in dbinfo['ENGINE']:
|
||||
parsed_args.dbtype = 'postgres'
|
||||
else:
|
||||
parsed_args.dbtype = 'mysql'
|
||||
if parsed_args.dbtype == 'sqlite':
|
||||
g = SQLiteMapFilesGenerator()
|
||||
g = SQLiteMapFilesGenerator(dbinfo)
|
||||
else:
|
||||
g = MapFilesGenerator()
|
||||
g = MapFilesGenerator(dbinfo)
|
||||
g.render(parsed_args)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
|
||||
from modoboa.lib.sysutils import exec_cmd
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
from . import factories
|
||||
|
||||
@@ -40,3 +46,58 @@ class ProfileTestCase(ModoTestCase):
|
||||
self.assertTrue(
|
||||
self.clt.login(username="user@test.com", password="tutu")
|
||||
)
|
||||
|
||||
|
||||
class ModoboaAdminCommandTestCase(TestCase):
|
||||
MAP_FILES = {
|
||||
"std": [
|
||||
"sql-domains.cf", "sql-domain-aliases.cf", "sql-aliases.cf",
|
||||
"sql-domain-aliases-mailboxes.cf", "sql-catchall-aliases.cf",
|
||||
"sql-maintain.cf"
|
||||
],
|
||||
"autoreply": ["sql-autoreplies-transport.cf", "sql-autoreplies.cf"],
|
||||
"relaydomains": [
|
||||
"sql-relaydomains.cf", "sql-relaydomains-transport.cf",
|
||||
"sql-relaydomain-aliases-transport.cf",
|
||||
"sql-relay-recipient-verification.cf"
|
||||
]
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
self.workdir = tempfile.mkdtemp()
|
||||
|
||||
def tearDown(self):
|
||||
exec_cmd("rm -rf {}".format(self.workdir))
|
||||
|
||||
def _test_maps_generation(self, engine, categories=None):
|
||||
if categories is None:
|
||||
categories = ["std", "autoreply", "relaydomains"]
|
||||
dburl = "{}://user:password@localhost/testdb".format(engine)
|
||||
code, output = exec_cmd(
|
||||
"modoboa-admin.py postfix_maps --categories {} --dburl {} {}".format(
|
||||
" ".join(categories), dburl, self.workdir
|
||||
)
|
||||
)
|
||||
self.assertEqual(code, 0)
|
||||
for category in categories:
|
||||
for mapfile in self.MAP_FILES[category]:
|
||||
path = "{}/{}".format(self.workdir, mapfile)
|
||||
self.assertTrue(os.path.exists(path))
|
||||
with open(path) as fpo:
|
||||
content = fpo.read()
|
||||
if engine != "sqlite":
|
||||
self.assertIn("user = user", content)
|
||||
self.assertIn("password = password", content)
|
||||
self.assertIn("dbname = testdb", content)
|
||||
self.assertIn("hosts = localhost", content)
|
||||
else:
|
||||
self.assertIn("dbpath = testdb", content)
|
||||
|
||||
def test_postgres_maps(self):
|
||||
self._test_maps_generation("postgres")
|
||||
|
||||
def test_mysql_maps(self):
|
||||
self._test_maps_generation("mysql")
|
||||
|
||||
def test_sqlite_maps(self):
|
||||
self._test_maps_generation("sqlite")
|
||||
|
||||
@@ -1 +1,304 @@
|
||||
[{"pk": 1, "model": "core.user", "fields": {"username": "admin", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": false, "last_login": "2012-05-03T16:58:51+01:00", "groups": [], "user_permissions": [], "password": "{CRYPT}dTTsGDkA5ZHKg", "email": "", "date_joined": "2012-01-26T15:19:25+01:00"}}, {"pk": 2, "model": "core.user", "fields": {"username": "admin@demo.local", "first_name": "Demo", "last_name": "Administrator", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2012-05-24T05:00:12+01:00", "groups": [1], "user_permissions": [], "password": "{CRYPT}SJ2bQWwabfH/6", "email": "admin@demo.local", "date_joined": "2012-05-03T16:50:15+01:00"}}, {"pk": 4, "model": "core.user", "fields": {"username": "user@demo.local", "first_name": "Demo", "last_name": "User", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2012-05-03T16:56:50+01:00", "groups": [2], "user_permissions": [], "password": "{CRYPT}2iAFXtxUA6.7Y", "email": "user@demo.local", "date_joined": "2012-05-03T16:56:50+01:00"}}, {"pk": 2, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "domain"], "object_id": 1}}, {"pk": 3, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["core", "user"], "object_id": 2}}, {"pk": 4, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "mailbox"], "object_id": 1}}, {"pk": 5, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "alias"], "object_id": 1}}, {"pk": 6, "model": "core.objectaccess", "fields": {"is_owner": false, "user": 2, "content_type": ["admin", "domain"], "object_id": 1}}, {"pk": 7, "model": "core.objectaccess", "fields": {"is_owner": false, "user": 2, "content_type": ["admin", "mailbox"], "object_id": 1}}, {"pk": 8, "model": "core.objectaccess", "fields": {"is_owner": false, "user": 2, "content_type": ["core", "user"], "object_id": 2}}, {"pk": 9, "model": "core.objectaccess", "fields": {"is_owner": false, "user": 2, "content_type": ["admin", "alias"], "object_id": 1}}, {"pk": 13, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["core", "user"], "object_id": 4}}, {"pk": 14, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "mailbox"], "object_id": 3}}, {"pk": 15, "model": "core.objectaccess", "fields": {"is_owner": false, "user": 2, "content_type": ["admin", "mailbox"], "object_id": 3}}, {"pk": 16, "model": "core.objectaccess", "fields": {"is_owner": false, "user": 2, "content_type": ["core", "user"], "object_id": 4}}, {"pk": 1, "model": "admin.objectdates", "fields": {"creation": "2012-05-03T16:49:40+01:00", "last_modification": "2012-05-03T16:49:40+01:00"}}, {"pk": 2, "model": "admin.objectdates", "fields": {"creation": "2012-05-03T16:50:15+01:00", "last_modification": "2012-05-03T16:50:36+01:00"}}, {"pk": 3, "model": "admin.objectdates", "fields": {"creation": "2012-05-03T16:50:15+01:00", "last_modification": "2012-05-03T16:50:15+01:00"}}, {"pk": 4, "model": "admin.objectdates", "fields": {"creation": "2012-05-03T16:51:04+01:00", "last_modification": "2012-05-03T16:51:04+01:00"}}, {"pk": 5, "model": "admin.objectdates", "fields": {"creation": "2012-05-03T16:56:50+01:00", "last_modification": "2012-05-03T16:56:50+01:00"}}, {"pk": 1, "model": "admin.domain", "fields": {"dates": 1, "enabled": true, "name": "demo.local", "quota": 10}}, {"pk": 1, "model": "admin.mailbox", "fields": {"dates": 2, "quota": 10, "user": 2, "domain": 1, "address": "admin"}}, {"pk": 3, "model": "admin.mailbox", "fields": {"dates": 5, "quota": 10, "user": 4, "domain": 1, "address": "user"}}, {"pk": 1, "model": "admin.alias", "fields": {"dates": 3, "enabled": true, "domain": 1, "mboxes": [1], "address": "postmaster", "extmboxes": ""}}, {"pk": 1, "model": "core.extension", "fields": {"enabled": true, "name": "limits"}}, {"pk": 2, "model": "core.extension", "fields": {"enabled": true, "name": "postfix_autoreply"}}, {"pk": 3, "model": "core.extension", "fields": {"enabled": true, "name": "stats"}}, {"pk": 4, "model": "core.extension", "fields": {"enabled": true, "name": "amavis"}}, {"pk": 5, "model": "core.extension", "fields": {"enabled": true, "name": "webmail"}}, {"pk": 6, "model": "core.extension", "fields": {"enabled": true, "name": "sievefilters"}}, {"pk": 7, "model": "core.extension", "fields": {"enabled": true, "name": "postfix_relay_domains"}}, {"pk": "admin@demo.local", "model": "admin.quota", "fields": {"mbox": 1, "username": "admin@demo.local", "bytes": 0, "messages": 0}}, {"pk": "user@demo.local", "model": "admin.quota", "fields": {"mbox": 3, "username": "user@demo.local", "bytes": 0, "messages": 0}}]
|
||||
[
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "core.user",
|
||||
"fields": {
|
||||
"username": "admin",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_active": true,
|
||||
"is_superuser": true,
|
||||
"is_staff": false,
|
||||
"last_login": "2012-05-03T16:58:51+01:00",
|
||||
"groups": [],
|
||||
"user_permissions": [],
|
||||
"password": "{CRYPT}dTTsGDkA5ZHKg",
|
||||
"email": "",
|
||||
"date_joined": "2012-01-26T15:19:25+01:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "core.user",
|
||||
"fields": {
|
||||
"username": "admin@demo.local",
|
||||
"first_name": "Demo",
|
||||
"last_name": "Administrator",
|
||||
"is_active": true,
|
||||
"is_superuser": false,
|
||||
"is_staff": false,
|
||||
"last_login": "2012-05-24T05:00:12+01:00",
|
||||
"groups": [1],
|
||||
"user_permissions": [],
|
||||
"password": "{CRYPT}SJ2bQWwabfH/6",
|
||||
"email": "admin@demo.local",
|
||||
"date_joined": "2012-05-03T16:50:15+01:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 4,
|
||||
"model": "core.user",
|
||||
"fields": {
|
||||
"username": "user@demo.local",
|
||||
"first_name": "Demo", "last_name": "User",
|
||||
"is_active": true,
|
||||
"is_superuser": false,
|
||||
"is_staff": false,
|
||||
"last_login": "2012-05-03T16:56:50+01:00",
|
||||
"groups": [2],
|
||||
"user_permissions": [],
|
||||
"password": "{CRYPT}2iAFXtxUA6.7Y",
|
||||
"email": "user@demo.local",
|
||||
"date_joined": "2012-05-03T16:56:50+01:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": true,
|
||||
"user": 1,
|
||||
"content_type": ["admin", "domain"],
|
||||
"object_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": true,
|
||||
"user": 1,
|
||||
"content_type": ["core", "user"],
|
||||
"object_id": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 4,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": true,
|
||||
"user": 1,
|
||||
"content_type": ["admin", "mailbox"],
|
||||
"object_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 5,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": true,
|
||||
"user": 1,
|
||||
"content_type": ["admin", "alias"],
|
||||
"object_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 6,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": false,
|
||||
"user": 2,
|
||||
"content_type": ["admin", "domain"],
|
||||
"object_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 7,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": false,
|
||||
"user": 2,
|
||||
"content_type": ["admin", "mailbox"],
|
||||
"object_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 8,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": false,
|
||||
"user": 2,
|
||||
"content_type": ["core", "user"],
|
||||
"object_id": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 9,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": false,
|
||||
"user": 2,
|
||||
"content_type": ["admin",
|
||||
"alias"],
|
||||
"object_id": 1}},
|
||||
{
|
||||
"pk": 13,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": true,
|
||||
"user": 1,
|
||||
"content_type": ["core",
|
||||
"user"],
|
||||
"object_id": 4}},
|
||||
{
|
||||
"pk": 14,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": true,
|
||||
"user": 1,
|
||||
"content_type": ["admin",
|
||||
"mailbox"],
|
||||
"object_id": 3}},
|
||||
{
|
||||
"pk": 15,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": false,
|
||||
"user": 2,
|
||||
"content_type": ["admin",
|
||||
"mailbox"],
|
||||
"object_id": 3}},
|
||||
{
|
||||
"pk": 16,
|
||||
"model": "core.objectaccess",
|
||||
"fields": {
|
||||
"is_owner": false,
|
||||
"user": 2,
|
||||
"content_type": ["core",
|
||||
"user"],
|
||||
"object_id": 4}},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "admin.objectdates",
|
||||
"fields": {
|
||||
"creation": "2012-05-03T16:49:40+01:00",
|
||||
"last_modification": "2012-05-03T16:49:40+01:00"}},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "admin.objectdates",
|
||||
"fields": {
|
||||
"creation": "2012-05-03T16:50:15+01:00",
|
||||
"last_modification": "2012-05-03T16:50:36+01:00"}},
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "admin.objectdates",
|
||||
"fields": {
|
||||
"creation": "2012-05-03T16:50:15+01:00",
|
||||
"last_modification": "2012-05-03T16:50:15+01:00"}},
|
||||
{
|
||||
"pk": 4,
|
||||
"model": "admin.objectdates",
|
||||
"fields": {
|
||||
"creation": "2012-05-03T16:51:04+01:00",
|
||||
"last_modification": "2012-05-03T16:51:04+01:00"}},
|
||||
{
|
||||
"pk": 5,
|
||||
"model": "admin.objectdates",
|
||||
"fields": {
|
||||
"creation": "2012-05-03T16:56:50+01:00",
|
||||
"last_modification": "2012-05-03T16:56:50+01:00"}},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "admin.domain",
|
||||
"fields": {
|
||||
"dates": 1,
|
||||
"enabled": true,
|
||||
"name": "demo.local",
|
||||
"quota": 10}},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "admin.mailbox",
|
||||
"fields": {
|
||||
"dates": 2,
|
||||
"quota": 10,
|
||||
"user": 2,
|
||||
"domain": 1,
|
||||
"address": "admin",
|
||||
"quota_value": "admin@demo.local"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "admin.mailbox",
|
||||
"fields": {
|
||||
"dates": 5,
|
||||
"quota": 10,
|
||||
"user": 4,
|
||||
"domain": 1,
|
||||
"address": "user",
|
||||
"quota_value": "user@demo.local"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "admin.alias",
|
||||
"fields": {
|
||||
"dates": 3,
|
||||
"enabled": true,
|
||||
"domain": 1,
|
||||
"mboxes": [1],
|
||||
"address": "postmaster",
|
||||
"extmboxes": ""}},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "limits"}},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "postfix_autoreply"}},
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "stats"}},
|
||||
{
|
||||
"pk": 4,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "amavis"}},
|
||||
{
|
||||
"pk": 5,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "webmail"}},
|
||||
{
|
||||
"pk": 6,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "sievefilters"}},
|
||||
{
|
||||
"pk": 7,
|
||||
"model": "core.extension",
|
||||
"fields": {
|
||||
"enabled": true,
|
||||
"name": "postfix_relay_domains"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": "admin@demo.local",
|
||||
"model": "admin.quota",
|
||||
"fields": {
|
||||
"username": "admin@demo.local",
|
||||
"bytes": 0,
|
||||
"messages": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": "user@demo.local",
|
||||
"model": "admin.quota",
|
||||
"fields": {
|
||||
"username": "user@demo.local",
|
||||
"bytes": 0,
|
||||
"messages": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -105,7 +105,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
return cleaned_data
|
||||
|
||||
def update_mailbox_quotas(self, domain):
|
||||
"""Update all quota records associated to this domain
|
||||
"""Update all quota records associated to this domain.
|
||||
|
||||
This method must be called only when a domain gets renamed. As
|
||||
the primary key used for a quota is an email address, rename a
|
||||
@@ -119,9 +119,14 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
perfomant at all as it will generate one query per quota
|
||||
record to update.
|
||||
"""
|
||||
for q in Quota.objects.filter(username__contains="@%s" % self.oldname).values('username'):
|
||||
username = q['username'].replace('@%s' % self.oldname, '@%s' % domain.name)
|
||||
Quota.objects.filter(username=q['username']).update(username=username)
|
||||
for q in Quota.objects.filter(username__contains="@%s" % self.oldname):
|
||||
username = q.username.replace(
|
||||
'@%s' % self.oldname, '@%s' % domain.name)
|
||||
newq = Quota.objects.create(
|
||||
username=username, bytes=q.bytes, messages=q.messages)
|
||||
q.mailbox.quota_value = newq
|
||||
q.mailbox.save()
|
||||
q.delete()
|
||||
|
||||
def save(self, user, commit=True, domalias_post_create=False):
|
||||
"""Custom save method
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'Mailbox.quota_value'
|
||||
db.add_column(u'admin_mailbox', 'quota_value',
|
||||
self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.Quota'], null=True),
|
||||
keep_default=False)
|
||||
|
||||
# Deleting field 'Quota.mbox'
|
||||
db.delete_column(u'admin_quota', 'mbox_id')
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'Mailbox.quota_value'
|
||||
db.delete_column(u'admin_mailbox', 'quota_value_id')
|
||||
|
||||
# Adding field 'Quota.mbox'
|
||||
db.add_column(u'admin_quota', 'mbox',
|
||||
self.gf('django.db.models.fields.related.OneToOneField')(related_name='quota_value', unique=True, null=True, to=orm['admin.Mailbox']),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
models = {
|
||||
'admin.alias': {
|
||||
'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Alias']", 'symmetrical': 'False'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'})
|
||||
},
|
||||
'admin.domain': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Domain'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'quota': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'admin.domainalias': {
|
||||
'Meta': {'object_name': 'DomainAlias'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"})
|
||||
},
|
||||
'admin.mailbox': {
|
||||
'Meta': {'object_name': 'Mailbox'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'quota': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'quota_value': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Quota']", 'null': 'True'}),
|
||||
'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
'admin.mailboxoperation': {
|
||||
'Meta': {'object_name': 'MailboxOperation'},
|
||||
'argument': ('django.db.models.fields.TextField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Mailbox']", 'null': 'True', 'blank': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||
},
|
||||
'admin.objectdates': {
|
||||
'Meta': {'object_name': 'ObjectDates'},
|
||||
'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
'admin.quota': {
|
||||
'Meta': {'object_name': 'Quota'},
|
||||
'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'})
|
||||
},
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'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'})
|
||||
},
|
||||
u'core.objectaccess': {
|
||||
'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
u'core.user': {
|
||||
'Meta': {'ordering': "['username']", 'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'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': '256'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['admin']
|
||||
@@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
"Write your forwards methods here."
|
||||
for mailbox in orm.Mailbox.objects.all():
|
||||
quota, created = orm.Quota.objects.get_or_create(
|
||||
pk="%s@%s" % (mailbox.address, mailbox.domain.name)
|
||||
)
|
||||
mailbox.quota_value = quota
|
||||
mailbox.save()
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
for mailbox in orm.Mailbox.objects.all():
|
||||
mailbox.quota_value = None
|
||||
mailbox.save()
|
||||
|
||||
models = {
|
||||
'admin.alias': {
|
||||
'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Alias']", 'symmetrical': 'False'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'})
|
||||
},
|
||||
'admin.domain': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Domain'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'quota': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'admin.domainalias': {
|
||||
'Meta': {'object_name': 'DomainAlias'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"})
|
||||
},
|
||||
'admin.mailbox': {
|
||||
'Meta': {'object_name': 'Mailbox'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'quota': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'quota_value': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Quota']", 'null': 'True'}),
|
||||
'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
'admin.mailboxoperation': {
|
||||
'Meta': {'object_name': 'MailboxOperation'},
|
||||
'argument': ('django.db.models.fields.TextField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Mailbox']", 'null': 'True', 'blank': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||
},
|
||||
'admin.objectdates': {
|
||||
'Meta': {'object_name': 'ObjectDates'},
|
||||
'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
'admin.quota': {
|
||||
'Meta': {'object_name': 'Quota'},
|
||||
'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'})
|
||||
},
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'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'})
|
||||
},
|
||||
u'core.objectaccess': {
|
||||
'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
u'core.user': {
|
||||
'Meta': {'ordering': "['username']", 'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'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': '256'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['admin']
|
||||
symmetrical = True
|
||||
@@ -0,0 +1,125 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Changing field 'Mailbox.quota_value'
|
||||
db.alter_column(u'admin_mailbox', 'quota_value_id', self.gf('django.db.models.fields.related.ForeignKey')(default=0, to=orm['admin.Quota']))
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Changing field 'Mailbox.quota_value'
|
||||
db.alter_column(u'admin_mailbox', 'quota_value_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.Quota'], null=True))
|
||||
|
||||
models = {
|
||||
'admin.alias': {
|
||||
'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Alias']", 'symmetrical': 'False'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'})
|
||||
},
|
||||
'admin.domain': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Domain'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'quota': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'admin.domainalias': {
|
||||
'Meta': {'object_name': 'DomainAlias'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"})
|
||||
},
|
||||
'admin.mailbox': {
|
||||
'Meta': {'object_name': 'Mailbox'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'quota': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'quota_value': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Quota']"}),
|
||||
'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
'admin.mailboxoperation': {
|
||||
'Meta': {'object_name': 'MailboxOperation'},
|
||||
'argument': ('django.db.models.fields.TextField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Mailbox']", 'null': 'True', 'blank': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||
},
|
||||
'admin.objectdates': {
|
||||
'Meta': {'object_name': 'ObjectDates'},
|
||||
'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
'admin.quota': {
|
||||
'Meta': {'object_name': 'Quota'},
|
||||
'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'})
|
||||
},
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'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'})
|
||||
},
|
||||
u'core.objectaccess': {
|
||||
'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
u'core.user': {
|
||||
'Meta': {'ordering': "['username']", 'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'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': '256'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['admin']
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Changing field 'Mailbox.quota_value'
|
||||
db.alter_column(u'admin_mailbox', 'quota_value_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['admin.Quota'], unique=True))
|
||||
# Adding unique constraint on 'Mailbox', fields ['quota_value']
|
||||
db.create_unique(u'admin_mailbox', ['quota_value_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'Mailbox', fields ['quota_value']
|
||||
db.delete_unique(u'admin_mailbox', ['quota_value_id'])
|
||||
|
||||
|
||||
# Changing field 'Mailbox.quota_value'
|
||||
db.alter_column(u'admin_mailbox', 'quota_value_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.Quota']))
|
||||
|
||||
models = {
|
||||
'admin.alias': {
|
||||
'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Alias']", 'symmetrical': 'False'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'})
|
||||
},
|
||||
'admin.domain': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Domain'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'quota': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'admin.domainalias': {
|
||||
'Meta': {'object_name': 'DomainAlias'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"})
|
||||
},
|
||||
'admin.mailbox': {
|
||||
'Meta': {'object_name': 'Mailbox'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'quota': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'quota_value': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['admin.Quota']", 'unique': 'True'}),
|
||||
'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
'admin.mailboxoperation': {
|
||||
'Meta': {'object_name': 'MailboxOperation'},
|
||||
'argument': ('django.db.models.fields.TextField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Mailbox']", 'null': 'True', 'blank': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||
},
|
||||
'admin.objectdates': {
|
||||
'Meta': {'object_name': 'ObjectDates'},
|
||||
'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
'admin.quota': {
|
||||
'Meta': {'object_name': 'Quota'},
|
||||
'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'})
|
||||
},
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'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'})
|
||||
},
|
||||
u'core.objectaccess': {
|
||||
'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.User']"})
|
||||
},
|
||||
u'core.user': {
|
||||
'Meta': {'ordering': "['username']", 'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'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': '256'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['admin']
|
||||
@@ -16,6 +16,17 @@ from .base import AdminObject
|
||||
from .domain import Domain
|
||||
|
||||
|
||||
class Quota(models.Model):
|
||||
"""Mailbox current quota usage.
|
||||
"""
|
||||
username = models.EmailField(primary_key=True, max_length=254)
|
||||
bytes = models.BigIntegerField(default=0)
|
||||
messages = models.IntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
app_label = 'admin'
|
||||
|
||||
|
||||
class MailboxManager(Manager):
|
||||
|
||||
def get_for_admin(self, admin, squery=None):
|
||||
@@ -43,7 +54,7 @@ class MailboxManager(Manager):
|
||||
qf = Q(pk__in=ids) & qf
|
||||
else:
|
||||
qf = Q(pk__in=ids)
|
||||
return self.get_query_set().filter(qf)
|
||||
return self.get_query_set().select_related().filter(qf)
|
||||
|
||||
|
||||
class Mailbox(AdminObject):
|
||||
@@ -53,6 +64,7 @@ class Mailbox(AdminObject):
|
||||
)
|
||||
quota = models.PositiveIntegerField()
|
||||
use_domain_quota = models.BooleanField(default=False)
|
||||
quota_value = models.OneToOneField(Quota, to_field="username")
|
||||
domain = models.ForeignKey(Domain)
|
||||
user = models.ForeignKey(User)
|
||||
|
||||
@@ -95,7 +107,7 @@ class Mailbox(AdminObject):
|
||||
|
||||
We ask dovecot to give us this information because there are
|
||||
several patterns to understand and we don't want to implement
|
||||
them.
|
||||
them.
|
||||
"""
|
||||
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
|
||||
if hm is None or hm == "no":
|
||||
@@ -134,16 +146,25 @@ class Mailbox(AdminObject):
|
||||
)
|
||||
|
||||
def rename(self, address, domain):
|
||||
"""Rename the mailbox
|
||||
"""Rename the mailbox.
|
||||
|
||||
To update the associated Quota record, we must create a new
|
||||
one first, update the foreign key and then we can delete the
|
||||
original record!
|
||||
|
||||
:param string address: the new mailbox's address (local part)
|
||||
:param Domain domain: the new mailbox's domain
|
||||
|
||||
"""
|
||||
old_mail_home = self.mail_home
|
||||
qs = Quota.objects.filter(username=self.full_address)
|
||||
self.address = address
|
||||
self.domain = domain
|
||||
qs.update(username=self.full_address)
|
||||
old_qvalue = self.quota_value
|
||||
self.quota_value = Quota.objects.create(
|
||||
username=self.full_address, bytes=old_qvalue.bytes,
|
||||
messages=old_qvalue.messages
|
||||
)
|
||||
old_qvalue.delete()
|
||||
self.rename_dir(old_mail_home)
|
||||
|
||||
def delete_dir(self):
|
||||
@@ -179,11 +200,10 @@ class Mailbox(AdminObject):
|
||||
|
||||
def get_quota(self):
|
||||
"""Get quota limit.
|
||||
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
q = Quota.objects.get(username=self.full_address)
|
||||
return int(q.bytes / 1048576)
|
||||
return int(self.quota_value.bytes / 1048576)
|
||||
|
||||
def get_quota_in_percent(self):
|
||||
"""Get current quota usage.
|
||||
@@ -192,8 +212,9 @@ class Mailbox(AdminObject):
|
||||
"""
|
||||
if not self.quota:
|
||||
return 0
|
||||
q = Quota.objects.get(username=self.full_address)
|
||||
return int(q.bytes / float(self.quota * 1048576) * 100)
|
||||
return int(
|
||||
self.quota_value.bytes / float(self.quota * 1048576) * 100
|
||||
)
|
||||
|
||||
def post_create(self, creator):
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
@@ -209,11 +230,16 @@ class Mailbox(AdminObject):
|
||||
grant_access_to_object(admin, self.user)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(Mailbox, self).save(*args, **kwargs)
|
||||
"""Custom save.
|
||||
|
||||
We just make sure a quota record is defined for this mailbox.
|
||||
"""
|
||||
try:
|
||||
q = self.quota_value
|
||||
except Quota.DoesNotExist:
|
||||
Quota.objects.create(mbox=self, username=self.full_address)
|
||||
self.quota_value, created = Quota.objects.get_or_create(
|
||||
username=self.full_address)
|
||||
super(Mailbox, self).save(*args, **kwargs)
|
||||
|
||||
def delete(self, keepdir=False):
|
||||
"""Custom delete method
|
||||
@@ -257,17 +283,6 @@ def mailbox_deleted_handler(sender, **kwargs):
|
||||
alias.delete()
|
||||
|
||||
|
||||
class Quota(models.Model):
|
||||
username = models.EmailField(primary_key=True, max_length=254)
|
||||
bytes = models.BigIntegerField(default=0)
|
||||
messages = models.IntegerField(default=0)
|
||||
|
||||
mbox = models.OneToOneField(Mailbox, related_name="quota_value", null=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'admin'
|
||||
|
||||
|
||||
class MailboxOperation(models.Model):
|
||||
mailbox = models.ForeignKey(Mailbox, blank=True, null=True)
|
||||
type = models.CharField(
|
||||
|
||||
@@ -46,6 +46,7 @@ class AccountTestCase(ModoTestCase):
|
||||
)
|
||||
mb = Mailbox.objects.get(pk=mb.id)
|
||||
self.assertEqual(mb.full_address, "pouet@test.com")
|
||||
self.assertEqual(mb.quota_value.username, "pouet@test.com")
|
||||
self.ajax_post(
|
||||
reverse("modoboa.extensions.admin.views.identity.delaccount",
|
||||
args=[account.id]),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# coding: utf-8
|
||||
import datetime
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.utils import timezone
|
||||
@@ -42,20 +41,25 @@ class ARmessageForm(forms.ModelForm):
|
||||
"""Custom fields validaton.
|
||||
|
||||
We want to be sure that fromdate < untildate and that they are
|
||||
both in the future.
|
||||
both in the future ONLY IF the autoreply is beeing activated.
|
||||
|
||||
"""
|
||||
super(ARmessageForm, self).clean()
|
||||
if self._errors:
|
||||
raise forms.ValidationError(self._errors)
|
||||
if not self.cleaned_data["enabled"]:
|
||||
return self.cleaned_data
|
||||
if self.cleaned_data["fromdate"] is not None:
|
||||
if self.cleaned_data["fromdate"] < timezone.now():
|
||||
self._errors["fromdate"] = self.error_class([_("This date is over")])
|
||||
self._errors["fromdate"] = self.error_class(
|
||||
[_("This date is over")])
|
||||
del self.cleaned_data['fromdate']
|
||||
else:
|
||||
self.cleaned_data['fromdate'] = timezone.now()
|
||||
if self.cleaned_data["untildate"] is not None:
|
||||
if self.cleaned_data["untildate"] < timezone.now():
|
||||
self._errors["untildate"] = self.error_class([_("This date is over")])
|
||||
self._errors["untildate"] = self.error_class(
|
||||
[_("This date is over")])
|
||||
del self.cleaned_data['untildate']
|
||||
elif 'fromdate' in self.cleaned_data and \
|
||||
self.cleaned_data['untildate'] < self.cleaned_data['fromdate']:
|
||||
|
||||
@@ -20,7 +20,7 @@ function removefilter(evt) {
|
||||
url: $this.attr("href"),
|
||||
dataType: 'json'
|
||||
}).done(function(response) {
|
||||
history.update(true);
|
||||
histomanager.update(true);
|
||||
$("body").notify('success', response, 2000);
|
||||
});
|
||||
}
|
||||
@@ -30,7 +30,7 @@ function removefilter(evt) {
|
||||
*/
|
||||
function changefs(evt) {
|
||||
evt.preventDefault();
|
||||
history.baseurl($(this).val()).update();
|
||||
histomanager.baseurl($(this).val()).update();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -48,7 +48,7 @@ function init_filters_list() {
|
||||
* It updates the middle DIV and initializes the user interface.
|
||||
*/
|
||||
function loadfs(response) {
|
||||
curscript = history.getbaseurl();
|
||||
curscript = histomanager.getbaseurl();
|
||||
$("#curfset").val(curscript);
|
||||
$("#set_content").html(response.content);
|
||||
|
||||
@@ -78,7 +78,7 @@ function send_command(cmd, extracb) {
|
||||
extracb(response);
|
||||
}
|
||||
if (!response.norefresh) {
|
||||
history.update(true);
|
||||
histomanager.update(true);
|
||||
}
|
||||
$("body").notify('success', response.respmsg, 2000);
|
||||
});
|
||||
@@ -133,7 +133,7 @@ function removefs(evt) {
|
||||
var $curfset = $("#curfset");
|
||||
|
||||
$curfset.find("option[value='" + curscript + "']").remove();
|
||||
history.baseurl(response.newfs, 1);
|
||||
histomanager.baseurl(response.newfs, 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ function filterset_created(data) {
|
||||
}
|
||||
});
|
||||
}
|
||||
history.baseurl(data.url, 1).update(1);
|
||||
histomanager.baseurl(data.url, 1).update(1);
|
||||
}
|
||||
|
||||
function filtersetform_cb() {
|
||||
@@ -240,4 +240,4 @@ function fetch_templates(url, container) {
|
||||
result = data;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/dynamic_input.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}sievefilters/js/jquery.dynfields.js"></script>
|
||||
<script type="text/javascript">
|
||||
var history = new History({
|
||||
var histomanager = new History({
|
||||
deflocation: "{{ default_script }}",
|
||||
defcallback: loadfs
|
||||
});
|
||||
|
||||
@@ -95,8 +95,7 @@ class Graphic(object):
|
||||
class AverageTraffic(Graphic):
|
||||
"""Average traffic.
|
||||
"""
|
||||
title = ugettext_lazy('Average traffic')
|
||||
vertlabel = ugettext_lazy('msgs/min')
|
||||
title = ugettext_lazy('Average traffic (msgs/min)')
|
||||
|
||||
# Curve definitions
|
||||
sent = Curve("sent", "lawngreen", ugettext_lazy("sent messages"))
|
||||
@@ -110,8 +109,7 @@ class AverageTraffic(Graphic):
|
||||
class AverageTrafficSize(Graphic):
|
||||
"""Average traffic size.
|
||||
"""
|
||||
title = ugettext_lazy('Average normal traffic size')
|
||||
vertlabel = ugettext_lazy('bytes/min')
|
||||
title = ugettext_lazy('Average normal traffic size (bytes/min)')
|
||||
|
||||
# Curve definitions
|
||||
size_recv = Curve("size_recv", "orange", ugettext_lazy("received size"))
|
||||
|
||||
@@ -218,6 +218,11 @@ class Modifier(ImapEmail):
|
||||
def _modify_html(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def subject(self):
|
||||
"""Just a shortcut to return a subject in any case."""
|
||||
return self.Subject if hasattr(self, "Subject") else ""
|
||||
|
||||
|
||||
class ReplyModifier(Modifier):
|
||||
headernames = ImapEmail.headernames + \
|
||||
@@ -246,11 +251,11 @@ class ReplyModifier(Modifier):
|
||||
if self.form.fields["cc"].initial != "":
|
||||
self.form.fields["cc"].initial += ", "
|
||||
self.form.fields["cc"].initial += tmp.fulladdress
|
||||
m = re.match(r"re\s*:\s*.+", self.Subject.lower())
|
||||
m = re.match(r"re\s*:\s*.+", self.subject.lower())
|
||||
if m:
|
||||
self.form.fields["subject"].initial = self.Subject
|
||||
self.form.fields["subject"].initial = self.subject
|
||||
else:
|
||||
self.form.fields["subject"].initial = "Re: %s" % self.Subject
|
||||
self.form.fields["subject"].initial = "Re: %s" % self.subject
|
||||
|
||||
def _modify_plain(self):
|
||||
super(ReplyModifier, self)._modify_plain()
|
||||
@@ -264,10 +269,15 @@ class ReplyModifier(Modifier):
|
||||
|
||||
|
||||
class ForwardModifier(Modifier):
|
||||
|
||||
"""
|
||||
Modify a message so it can be forwarded.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ForwardModifier, self).__init__(*args, **kwargs)
|
||||
self._header()
|
||||
self.form.fields["subject"].initial = "Fwd: %s" % self.Subject
|
||||
self.form.fields["subject"].initial = "Fwd: %s" % self.subject
|
||||
|
||||
def __getfunc(self, name):
|
||||
return getattr(self, "%s_%s" % (name, self.dformat))
|
||||
@@ -275,7 +285,7 @@ class ForwardModifier(Modifier):
|
||||
def _header(self):
|
||||
self.textheader = self.__getfunc("_header_begin")() + "\n"
|
||||
self.textheader += \
|
||||
self.__getfunc("_header_line")(_("Subject"), self.Subject)
|
||||
self.__getfunc("_header_line")(_("Subject"), self.subject)
|
||||
self.textheader += \
|
||||
self.__getfunc("_header_line")(_("Date"), self.Date)
|
||||
for hdr in ["From", "To", "Reply-To"]:
|
||||
|
||||
@@ -85,9 +85,9 @@ def parse_date(value, **kwargs):
|
||||
tmp = email.utils.parsedate_tz(value)
|
||||
if not tmp:
|
||||
return value
|
||||
ndate = datetime.datetime(*(tmp)[:7])
|
||||
now = datetime.datetime.now()
|
||||
try:
|
||||
ndate = datetime.datetime(*(tmp)[:7])
|
||||
now = datetime.datetime.now()
|
||||
if now - ndate > datetime.timedelta(7):
|
||||
return ndate.strftime("%d.%m.%Y %H:%M")
|
||||
return ndate.strftime("%a %H:%M")
|
||||
|
||||
@@ -8,22 +8,22 @@ class EmailSignature(object):
|
||||
:param user: User object
|
||||
"""
|
||||
def __init__(self, user):
|
||||
self._sig = ""
|
||||
self._sig = u""
|
||||
dformat = parameters.get_user(user, "EDITOR")
|
||||
content = parameters.get_user(user, "SIGNATURE")
|
||||
if len(content):
|
||||
getattr(self, "_format_sig_%s" % dformat)(content)
|
||||
|
||||
def _format_sig_plain(self, content):
|
||||
self._sig = """
|
||||
self._sig = u"""
|
||||
---
|
||||
%s""" % content
|
||||
|
||||
def _format_sig_html(self, content):
|
||||
content = re.sub("\n", "<br/>", content)
|
||||
self._sig = """<br/>
|
||||
self._sig = u"""<br/>
|
||||
---<br/>
|
||||
%s""" % content
|
||||
|
||||
def __repr__(self):
|
||||
def __unicode__(self):
|
||||
return self._sig
|
||||
|
||||
@@ -37,6 +37,7 @@ $(document).ready(function() {
|
||||
<div id="listing"></div>
|
||||
{% endblock %}
|
||||
{% block footerleft %}
|
||||
{% if quota != -1 %}
|
||||
<div id="quotabox">
|
||||
<label class="pull-left navbar-text">{% trans "Mailbox quota" %}</label>
|
||||
<div id="quotabar" class="pull-left progress {% progress_color quota %}">
|
||||
@@ -44,5 +45,6 @@ $(document).ready(function() {
|
||||
</div>
|
||||
<label id="quotaraw" class="pull-left navbar-text">{{ quota }}%</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -344,14 +344,14 @@ def listmailbox(request, defmailbox="INBOX", update_session=True):
|
||||
def render_compose(request, form, posturl, email=None, insert_signature=False):
|
||||
editor = parameters.get_user(request.user, "EDITOR")
|
||||
if email is None:
|
||||
body = ""
|
||||
textheader = ""
|
||||
body = u""
|
||||
textheader = u""
|
||||
else:
|
||||
body = email.body
|
||||
textheader = email.textheader
|
||||
if insert_signature:
|
||||
signature = EmailSignature(request.user)
|
||||
body += str(signature)
|
||||
body += unicode(signature)
|
||||
randid = None
|
||||
if not "id" in request.GET:
|
||||
if "compose_mail" in request.session:
|
||||
|
||||
@@ -177,7 +177,7 @@ function simple_ajax_form_post(e, options) {
|
||||
if (opts.reload_mode == 'full') {
|
||||
window.location.reload();
|
||||
} else {
|
||||
history.update(true);
|
||||
histomanager.update(true);
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
id: bid,
|
||||
click: $.proxy(this.destroy_box, this)
|
||||
}).css({
|
||||
position: "absolute"
|
||||
position: "fixed"
|
||||
});
|
||||
|
||||
return div;
|
||||
@@ -101,4 +101,4 @@
|
||||
top_position: 50
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
})(jQuery);
|
||||
|
||||
Reference in New Issue
Block a user