From c05de846f30d6c98f7feeee8a7803234ef7d381c Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Feb 2015 10:36:12 +0100 Subject: [PATCH 01/17] Make sure to load the imap_utf7 codec. --- modoboa/extensions/webmail/lib/imaputils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/extensions/webmail/lib/imaputils.py b/modoboa/extensions/webmail/lib/imaputils.py index 7d34a75c8..f3572dea9 100644 --- a/modoboa/extensions/webmail/lib/imaputils.py +++ b/modoboa/extensions/webmail/lib/imaputils.py @@ -14,7 +14,7 @@ from django.utils.translation import ugettext as _ from ..exceptions import ImapError, WebmailInternalError from .fetch_parser import parse_fetch_response -from modoboa.lib import parameters +from modoboa.lib import parameters, imap_utf7 from modoboa.lib.connections import ConnectionsManager from modoboa.lib.exceptions import InternalError From d3a5c235dd72f8bec4556089faa34e6754737a7d Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Feb 2015 14:00:33 +0100 Subject: [PATCH 02/17] Oups... --- modoboa/extensions/sievefilters/test.py | 43 ------------------------- 1 file changed, 43 deletions(-) delete mode 100644 modoboa/extensions/sievefilters/test.py diff --git a/modoboa/extensions/sievefilters/test.py b/modoboa/extensions/sievefilters/test.py deleted file mode 100644 index 2555f22bc..000000000 --- a/modoboa/extensions/sievefilters/test.py +++ /dev/null @@ -1,43 +0,0 @@ -if __name__ == "__main__": - clt = ManageSieveClient("mail.koalabs.org", 2000) - if clt.connect("tonio@ngyn.org", "aka/12;c", starttls=True): - print clt.get_sasl_mechanisms() - print clt.get_sieve_capabilities() - print clt.havespace("test", 45) - - if not clt.putscript("myscript", """require ["fileinto", "envelope"]; - -if envelope :contains "to" "tmartin+sent" { - fileinto "INBOX.sent"; -} -"""): - print clt.errmsg - - if not clt.putscript("test", """#comment -InvalidSieveCommand -"""): - print clt.errmsg - - clt.deletescript("thescript") - - if not clt.setactive("myscript"): - print clt.errmsg - print clt.listscripts() - - sc = clt.getscript("myscript") - if sc is None: - print clt.errmsg - else: - print sc - - if not clt.renamescript("myscript", "thescript"): - print clt.errmsg - - clt.setactive("") - - if not clt.deletescript("thescript"): - print clt.errmsg - else: - print clt.errmsg - clt.logout() - From 768aa7990be111471022f9b3da084627b96f4829 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 18 Feb 2015 10:30:51 +0100 Subject: [PATCH 03/17] This event can raise a list of alias too... see #693 --- modoboa/extensions/amavis/general_callbacks.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modoboa/extensions/amavis/general_callbacks.py b/modoboa/extensions/amavis/general_callbacks.py index c98c5fb24..2f64fcc54 100644 --- a/modoboa/extensions/amavis/general_callbacks.py +++ b/modoboa/extensions/amavis/general_callbacks.py @@ -103,12 +103,14 @@ def on_mailboxalias_created(user, alias): @events.observe("MailboxAliasDeleted") -def on_mailboxalias_deleted(alias): +def on_mailboxalias_deleted(aliases): """Clean amavis database when an alias is removed.""" if parameters.get_admin("MANUAL_LEARNING") == "no": return - if Users.objects.filter(email=alias.full_address).exists(): - Users.objects.delete(email=alias.full_address) + if isinstance(aliases, Alias): + aliases = [aliases] + aliases = [alias.full_address for alias in aliases] + Users.objects.filter(email__in=aliases).delete() @events.observe("GetStaticContent") From 2e99cf7690c2fa759ffbe0781c0b8cbc3448f810 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 18 Feb 2015 10:34:40 +0100 Subject: [PATCH 04/17] Import Alias model. see #693 --- modoboa/extensions/amavis/general_callbacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/extensions/amavis/general_callbacks.py b/modoboa/extensions/amavis/general_callbacks.py index 2f64fcc54..76b994e16 100644 --- a/modoboa/extensions/amavis/general_callbacks.py +++ b/modoboa/extensions/amavis/general_callbacks.py @@ -3,7 +3,7 @@ from django.utils.translation import ugettext as _ from django.template import Template, Context from modoboa.lib import events, parameters -from modoboa.extensions.admin.models import DomainAlias +from modoboa.extensions.admin.models import DomainAlias, Alias from modoboa.extensions.amavis.lib import ( create_user_and_policy, update_user_and_policy, delete_user_and_policy, create_user_and_use_policy, delete_user From c4e693afebcaacfe6940e2c74d9df00c1084d8ff Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 19 Feb 2015 13:21:32 +0100 Subject: [PATCH 05/17] Fix attempt for #695. --- modoboa/lib/formutils.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modoboa/lib/formutils.py b/modoboa/lib/formutils.py index 9c75761b2..4b1922ba5 100644 --- a/modoboa/lib/formutils.py +++ b/modoboa/lib/formutils.py @@ -333,17 +333,19 @@ class TabForms(object): # -def is_valid_host(host): - """IDN compatible domain validator - """ - host = host.encode('idna').lower() - if not hasattr(is_valid_host, '_re'): - is_valid_host._re = re.compile(r'^([0-9a-z][-\w]*[0-9a-z]\.)+[a-z0-9\-]{2,15}$') - return bool(is_valid_host._re.match(host)) +def is_valid_hostname(hostname): + """Domain name validaton.""" + if len(hostname) > 255: + return False + if hostname[-1] == ".": + hostname = hostname[:-1] # strip exactly one dot from the + # right, if present + allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(? Date: Thu, 19 Feb 2015 13:51:29 +0100 Subject: [PATCH 06/17] Fix unit test. --- modoboa/extensions/postfix_relay_domains/tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modoboa/extensions/postfix_relay_domains/tests.py b/modoboa/extensions/postfix_relay_domains/tests.py index f1d28a001..107c501d1 100644 --- a/modoboa/extensions/postfix_relay_domains/tests.py +++ b/modoboa/extensions/postfix_relay_domains/tests.py @@ -195,18 +195,18 @@ class LimitsTestCase(ExtTestCase, Operations): def test_relay_domain_aliases_limit(self): self._create_relay_domain('relaydomain1.tld') self._relay_domain_alias_operation( - 'add', 'relaydomain1.tld', 'relay_domain_alias1.tld' + 'add', 'relaydomain1.tld', 'relay-domain-alias1.tld' ) self._check_limit('relay_domain_aliases', 1, 2) self._relay_domain_alias_operation( - 'add', 'relaydomain1.tld', 'relay_domain_alias2.tld' + 'add', 'relaydomain1.tld', 'relay-domain-alias2.tld' ) self._check_limit('relay_domain_aliases', 2, 2) self._relay_domain_alias_operation( - 'add', 'relaydomain1.tld', 'relay_domain_alias3.tld', 403 + 'add', 'relaydomain1.tld', 'relay-domain-alias3.tld', 403 ) self._check_limit('relay_domain_aliases', 2, 2) self._relay_domain_alias_operation( - 'delete', 'relaydomain1.tld', 'relay_domain_alias2.tld' + 'delete', 'relaydomain1.tld', 'relay-domain-alias2.tld' ) self._check_limit('relay_domain_aliases', 1, 2) From c34601e40ebf865b08cc9aab4fa38fc0dd2c5aae Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 19 Feb 2015 14:11:54 +0100 Subject: [PATCH 07/17] Fix unit tests. --- modoboa/extensions/limits/tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modoboa/extensions/limits/tests.py b/modoboa/extensions/limits/tests.py index 4db5078df..f13477bc6 100644 --- a/modoboa/extensions/limits/tests.py +++ b/modoboa/extensions/limits/tests.py @@ -189,15 +189,15 @@ class ResellerTestCase(ResourceTestCase): def test_domain_aliases_limit(self): self._create_domain('pouet.com') - self._domain_alias_operation('add', 'pouet.com', 'domain_alias1.tld') + self._domain_alias_operation('add', 'pouet.com', 'domain-alias1.tld') self._check_limit('domain_aliases', 1, 2) - self._domain_alias_operation('add', 'pouet.com', 'domain_alias2.tld') + self._domain_alias_operation('add', 'pouet.com', 'domain-alias2.tld') self._check_limit('domain_aliases', 2, 2) resp = self._domain_alias_operation( - 'add', 'pouet.com', 'domain_alias3.tld', 403 + 'add', 'pouet.com', 'domain-alias3.tld', 403 ) self._check_limit('domain_aliases', 2, 2) - self._domain_alias_operation('delete', 'pouet.com', 'domain_alias2.tld') + self._domain_alias_operation('delete', 'pouet.com', 'domain-alias2.tld') self._check_limit('domain_aliases', 1, 2) def test_domain_admins_limit(self): From 24bac0e4dda48de1ccae2435ba49a27083d19d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20G=C3=A9nieux?= Date: Sat, 28 Feb 2015 17:32:19 +0100 Subject: [PATCH 08/17] issue #413 Added: email checking for to/cc/cci in webmail --- modoboa/extensions/webmail/forms.py | 8 +++++--- .../webmail/templates/webmail/compose.html | 2 +- modoboa/extensions/webmail/validators.py | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 modoboa/extensions/webmail/validators.py diff --git a/modoboa/extensions/webmail/forms.py b/modoboa/extensions/webmail/forms.py index c377fc91b..2ff9d3ff0 100644 --- a/modoboa/extensions/webmail/forms.py +++ b/modoboa/extensions/webmail/forms.py @@ -14,6 +14,7 @@ from .lib import ( ImapEmail, create_mail_attachment ) +from validators import validate_email_list def html2plaintext(content): """HTML to plain text translation. @@ -76,13 +77,14 @@ def make_body_images_inline(body): return lxml.html.tostring(html), parts + class ComposeMailForm(forms.Form): """Compose mail form.""" - to = forms.CharField(label=_("To")) - cc = forms.CharField(label=_("Cc"), required=False) - cci = forms.CharField(label=_("Cci"), required=False) + to = forms.CharField(label=_("To"), validators=[validate_email_list]) + cc = forms.CharField(label=_("Cc"), required=False, validators=[validate_email_list]) + cci = forms.CharField(label=_("Cci"), required=False, validators=[validate_email_list]) subject = forms.CharField( label=_("Subject"), max_length=255, diff --git a/modoboa/extensions/webmail/templates/webmail/compose.html b/modoboa/extensions/webmail/templates/webmail/compose.html index 4fb607529..06db8600f 100644 --- a/modoboa/extensions/webmail/templates/webmail/compose.html +++ b/modoboa/extensions/webmail/templates/webmail/compose.html @@ -8,7 +8,7 @@
- +
{% if not form.cc.value %}
diff --git a/modoboa/extensions/webmail/validators.py b/modoboa/extensions/webmail/validators.py new file mode 100644 index 000000000..8c6c25dc1 --- /dev/null +++ b/modoboa/extensions/webmail/validators.py @@ -0,0 +1,17 @@ +from django.utils.encoding import force_text +from django.utils.deconstruct import deconstructible +from django.core.validators import validate_email +from email.utils import getaddresses + +class EmailListValidator(object): + """ + Validate a comma separated list of email + """ + def __call__(self, value): + value = force_text(value) + emails = map(unicode.strip, value.split(',')) + addresses = getaddresses(emails) + [ validate_email(e) for r, e in addresses ] + +validate_email_list = EmailListValidator() + From 4e305ed00338fc93e8e9bfd9759dc7aa1bc061b4 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Mar 2015 10:21:04 +0100 Subject: [PATCH 09/17] Coding style fixes. --- modoboa/extensions/webmail/forms.py | 3 ++- modoboa/extensions/webmail/validators.py | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/modoboa/extensions/webmail/forms.py b/modoboa/extensions/webmail/forms.py index 2ff9d3ff0..ac4468553 100644 --- a/modoboa/extensions/webmail/forms.py +++ b/modoboa/extensions/webmail/forms.py @@ -14,7 +14,8 @@ from .lib import ( ImapEmail, create_mail_attachment ) -from validators import validate_email_list +from .validators import validate_email_list + def html2plaintext(content): """HTML to plain text translation. diff --git a/modoboa/extensions/webmail/validators.py b/modoboa/extensions/webmail/validators.py index 8c6c25dc1..fab794a43 100644 --- a/modoboa/extensions/webmail/validators.py +++ b/modoboa/extensions/webmail/validators.py @@ -1,17 +1,20 @@ -from django.utils.encoding import force_text -from django.utils.deconstruct import deconstructible -from django.core.validators import validate_email +"""Custom form validators.""" + from email.utils import getaddresses +from django.utils.encoding import force_text +from django.core.validators import validate_email + + class EmailListValidator(object): - """ - Validate a comma separated list of email - """ + + """Validate a comma separated list of email.""" + def __call__(self, value): value = force_text(value) - emails = map(unicode.strip, value.split(',')) + emails = [unicode.strip(email) for email in value.split(",")] addresses = getaddresses(emails) - [ validate_email(e) for r, e in addresses ] + [validate_email(e) for r, e in addresses.values] validate_email_list = EmailListValidator() From df16a3296d5ca4c976b80b7b87a341ae6b4f8aec Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Mar 2015 10:25:27 +0100 Subject: [PATCH 10/17] PEP8 fixes --- modoboa/extensions/webmail/forms.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modoboa/extensions/webmail/forms.py b/modoboa/extensions/webmail/forms.py index ac4468553..95c6e565c 100644 --- a/modoboa/extensions/webmail/forms.py +++ b/modoboa/extensions/webmail/forms.py @@ -83,9 +83,12 @@ class ComposeMailForm(forms.Form): """Compose mail form.""" - to = forms.CharField(label=_("To"), validators=[validate_email_list]) - cc = forms.CharField(label=_("Cc"), required=False, validators=[validate_email_list]) - cci = forms.CharField(label=_("Cci"), required=False, validators=[validate_email_list]) + to = forms.CharField( + label=_("To"), validators=[validate_email_list]) + cc = forms.CharField( + label=_("Cc"), required=False, validators=[validate_email_list]) + cci = forms.CharField( + label=_("Cci"), required=False, validators=[validate_email_list]) subject = forms.CharField( label=_("Subject"), max_length=255, From 5a5cf25f6c803ee9d9031166ffebf47f52e3acae Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Mar 2015 10:35:21 +0100 Subject: [PATCH 11/17] Set viewport on the login page. fix #690 --- modoboa/templates/registration/login.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modoboa/templates/registration/login.html b/modoboa/templates/registration/login.html index d01a6781b..838588b14 100644 --- a/modoboa/templates/registration/login.html +++ b/modoboa/templates/registration/login.html @@ -5,6 +5,8 @@ + + {% trans "Welcome to Modoboa" %} From 9947c21571c814d4f23d68bc86f85e5cb4245e66 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Mar 2015 13:26:32 +0100 Subject: [PATCH 12/17] Be carefull with ownership. fix #689 --- modoboa/core/models.py | 1 + modoboa/extensions/admin/tests/alias.py | 10 +++++-- .../extensions/admin/tests/domain_alias.py | 1 + modoboa/extensions/limits/tests.py | 21 ++++++++++++++ modoboa/lib/permissions.py | 29 +++++++------------ 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/modoboa/core/models.py b/modoboa/core/models.py index 57faece90..66805169e 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -88,6 +88,7 @@ class User(PermissionsMixin): for ooentry in self.objectaccess_set.filter(is_owner=True): if ooentry.content_object is not None: grant_access_to_object(owner, ooentry.content_object, True) + ungrant_access_to_object(ooentry.content_object, self) events.raiseEvent("AccountDeleted", self, fromuser, **kwargs) ungrant_access_to_object(self) diff --git a/modoboa/extensions/admin/tests/alias.py b/modoboa/extensions/admin/tests/alias.py index 69702f50c..e2ad06dac 100644 --- a/modoboa/extensions/admin/tests/alias.py +++ b/modoboa/extensions/admin/tests/alias.py @@ -48,15 +48,19 @@ class AliasTestCase(ModoTestCase): ) self.assertEqual(user.mailbox_set.first().alias_set.count(), 1) self.assertEqual( - user.mailbox_set.first().alias_set.first(), "toto@test.com") + user.mailbox_set.first().alias_set.first().full_address, + "toto@test.com" + ) values = { - "email": "Titi@test.com", "recipient": "user@test.com", + "email": "Titi@test.com", "recipients": "user@test.com", "enabled": True } self.ajax_post(reverse("admin:alias_add"), values) self.assertEqual( - user.mailbox_set.first().alias_set.first(), "titi@test.com") + user.mailbox_set.first().alias_set.first().full_address, + "titi@test.com" + ) def test_dlist(self): values = dict(email="all@test.com", diff --git a/modoboa/extensions/admin/tests/domain_alias.py b/modoboa/extensions/admin/tests/domain_alias.py index a13abc915..c4a1e5538 100644 --- a/modoboa/extensions/admin/tests/domain_alias.py +++ b/modoboa/extensions/admin/tests/domain_alias.py @@ -19,6 +19,7 @@ class DomainAliasTestCase(ModoTestCase): domal = DomainAlias() domal.name = "domalias.net" domal.target = dom + domal.enabled = True domal.save() self.assertEqual(dom.domainalias_count, 1) diff --git a/modoboa/extensions/limits/tests.py b/modoboa/extensions/limits/tests.py index f13477bc6..7a9f0927e 100644 --- a/modoboa/extensions/limits/tests.py +++ b/modoboa/extensions/limits/tests.py @@ -39,6 +39,27 @@ class PermissionsTestCase(ExtTestCase): self.assertEqual(resp, "Permission denied") + def test_delete_forward(self): + """Delete a forward created by a user. + + This test was added to help fixing #689. + """ + self.clt.logout() + self.clt.login(username="user@test2.com", password="toto") + + values = { + "dest": "rcpt@dest.com", + "keepcopies": True + } + self.ajax_post(reverse("user_forward"), values) + + user = User.objects.get(username="user@test2.com") + + self.clt.logout() + self.clt.login(username="admin", password="password") + self.ajax_post(reverse("admin:account_delete", args=[user.pk])) + + class ResourceTestCase(ExtTestCase): fixtures = ["initial_users.json"] diff --git a/modoboa/lib/permissions.py b/modoboa/lib/permissions.py index a4b3487d3..abca0a6b8 100644 --- a/modoboa/lib/permissions.py +++ b/modoboa/lib/permissions.py @@ -45,22 +45,15 @@ def grant_access_to_object(user, obj, is_owner=False): :param obj: an admin. object (Domain, Mailbox, ...) :param is_owner: the user is the unique object's owner """ - ct = ContentType.objects.get_for_model(obj) - try: - entry = user.objectaccess_set.get(content_type=ct, object_id=obj.id) - entry.is_owner = is_owner - entry.save() - except ObjectAccess.DoesNotExist: - pass - else: - return - - ObjectAccess.objects.create( - user=user, content_type=ct, object_id=obj.id, is_owner=is_owner - ) - if not is_owner: - return from modoboa.core.models import User + + ct = ContentType.objects.get_for_model(obj) + entry, created = ObjectAccess.objects.get_or_create( + user=user, content_type=ct, object_id=obj.id) + entry.is_owner = is_owner + entry.save() + if not created or not is_owner: + return for su in User.objects.filter(is_superuser=True): if su == user: continue @@ -80,10 +73,8 @@ def grant_access_to_objects(user, objects, ct): :param ct: the content type """ for obj in objects: - try: - ObjectAccess.objects.create(user=user, content_type=ct, object_id=obj.id) - except IntegrityError: - pass + ObjectAccess.objects.get_or_create( + user=user, content_type=ct, object_id=obj.id) def ungrant_access_to_object(obj, user=None): From 3090dfb7666e5034c9513f22bbb4c1fd4fd941f8 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Mar 2015 13:42:04 +0100 Subject: [PATCH 13/17] 1.2.1. --- doc/conf.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index b337042cc..44f06ec80 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -50,7 +50,7 @@ copyright = u'2014, Antoine Nguyen' # The short X.Y version. version = '1.2' # The full version, including alpha/beta/rc tags. -release = '1.2.0' +release = '1.2.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index d1726d0a4..9e950373e 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def read(fname): setup( name="modoboa", - version='1.2.0', + version='1.2.1', url='http://modoboa.org/', license='MIT', description="Mail hosting made simple", From 00488261d544aa5a27283edc40432e0eb2e935a5 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 12 Mar 2015 16:26:40 +0100 Subject: [PATCH 14/17] Raise event once the alias is fully created. see #698 --- modoboa/extensions/admin/models/alias.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modoboa/extensions/admin/models/alias.py b/modoboa/extensions/admin/models/alias.py index 4ced8b994..289521b81 100644 --- a/modoboa/extensions/admin/models/alias.py +++ b/modoboa/extensions/admin/models/alias.py @@ -194,7 +194,8 @@ class Alias(AdminObject): except Mailbox.DoesNotExist: raise BadRequest(_("Local recipient %s not found" % rcpt)) int_rcpts += [target] - self.save(int_rcpts=int_rcpts, ext_rcpts=ext_rcpts, creator=user) + self.save(int_rcpts=int_rcpts, ext_rcpts=ext_rcpts) + self.post_create(user) def to_csv(self, csvwriter): row = [self.type, self.full_address.encode("utf-8"), self.enabled] From 4064a006492d92738d52bc8577147ea8564c15c2 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 25 Mar 2015 15:14:56 +0100 Subject: [PATCH 15/17] Manually load extensions inside management commands. --- modoboa/extensions/amavis/management/commands/amnotify.py | 7 ++++++- modoboa/extensions/amavis/management/commands/qcleanup.py | 2 ++ .../postfix_autoreply/management/commands/autoreply.py | 4 +++- .../radicale/management/commands/generate_rights.py | 4 +++- modoboa/extensions/stats/management/commands/logparser.py | 2 ++ modoboa/extensions/stats/modo_extension.py | 1 - 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/modoboa/extensions/amavis/management/commands/amnotify.py b/modoboa/extensions/amavis/management/commands/amnotify.py index 209350da3..d9962b93f 100644 --- a/modoboa/extensions/amavis/management/commands/amnotify.py +++ b/modoboa/extensions/amavis/management/commands/amnotify.py @@ -16,10 +16,14 @@ from modoboa.extensions.admin.models import Domain from modoboa.extensions.amavis.models import ( Msgrcpt ) -from modoboa.extensions.amavis.sql_connector import get_connector +from ...modo_extension import Amavis +from ...sql_connector import get_connector class Command(BaseCommand, CloseConnectionMixin): + + """A management command to notify admins about pending release requests.""" + help = 'Amavis notification tool' sender = None @@ -40,6 +44,7 @@ class Command(BaseCommand, CloseConnectionMixin): def handle(self, *args, **options): if options["baseurl"] is None: raise CommandError("You must provide the --baseurl option") + Amavis.load() self.options = options self.notify_admins_pending_requests() diff --git a/modoboa/extensions/amavis/management/commands/qcleanup.py b/modoboa/extensions/amavis/management/commands/qcleanup.py index 47e2d6dce..34dcdc060 100644 --- a/modoboa/extensions/amavis/management/commands/qcleanup.py +++ b/modoboa/extensions/amavis/management/commands/qcleanup.py @@ -11,6 +11,7 @@ from modoboa.extensions.amavis.models import ( Msgrcpt, Msgs, Maddr ) from modoboa.lib import parameters +from ...modo_extension import Amavis class Command(BaseCommand, CloseConnectionMixin): @@ -34,6 +35,7 @@ class Command(BaseCommand, CloseConnectionMixin): print msg def handle(self, *args, **options): + Amavis.load() if options["debug"]: import logging l = logging.getLogger("django.db.backends") diff --git a/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py b/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py index 09482185c..44d2ed172 100644 --- a/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py +++ b/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py @@ -10,7 +10,8 @@ from modoboa.core.management.commands import CloseConnectionMixin from modoboa.lib import parameters from modoboa.lib.email_utils import split_mailbox, sendmail_simple from modoboa.extensions.admin.models import Mailbox -from modoboa.extensions.postfix_autoreply.models import ARmessage, ARhistoric +from ...models import ARmessage, ARhistoric +from ...modo_extension import PostfixAutoreply def send_autoreply(sender, mailbox, armessage): @@ -52,6 +53,7 @@ class Command(BaseCommand, CloseConnectionMixin): raise CommandError( "usage: ./manage.py autoreply ") + PostfixAutoreply.load() sender = args[0] for fulladdress in args[1:]: address, domain = split_mailbox(fulladdress) diff --git a/modoboa/extensions/radicale/management/commands/generate_rights.py b/modoboa/extensions/radicale/management/commands/generate_rights.py index 3dd857c97..25365c514 100644 --- a/modoboa/extensions/radicale/management/commands/generate_rights.py +++ b/modoboa/extensions/radicale/management/commands/generate_rights.py @@ -8,9 +8,10 @@ from modoboa.core.management.commands import CloseConnectionMixin from modoboa.core.models import User from modoboa.lib import parameters from modoboa.extensions.admin.models import Domain -from modoboa.extensions.radicale.models import ( +from ...models import ( AccessRule ) +from ...modo_extension import Radicale class Command(BaseCommand, CloseConnectionMixin): @@ -102,6 +103,7 @@ permission = %s def handle(self, *args, **options): """Command entry point.""" + Radicale.load() path = parameters.get_admin("RIGHTS_FILE_PATH", app="radicale") if not options["force"]: try: diff --git a/modoboa/extensions/stats/management/commands/logparser.py b/modoboa/extensions/stats/management/commands/logparser.py index 1f38ff6fa..089c374ab 100644 --- a/modoboa/extensions/stats/management/commands/logparser.py +++ b/modoboa/extensions/stats/management/commands/logparser.py @@ -33,6 +33,7 @@ from modoboa.core.management.commands import CloseConnectionMixin from modoboa.extensions.admin.models import Domain from modoboa.extensions.stats.lib import date_to_timestamp from modoboa.lib import parameters +from ...modo_extension import Stats rrdstep = 60 xpoints = 540 @@ -372,6 +373,7 @@ class Command(BaseCommand, CloseConnectionMixin): ) def handle(self, *args, **options): + Stats.load() if options["logfile"] is None: options["logfile"] = parameters.get_admin("LOGFILE", app="stats") p = LogParser(options, parameters.get_admin("RRD_ROOTDIR", app="stats")) diff --git a/modoboa/extensions/stats/modo_extension.py b/modoboa/extensions/stats/modo_extension.py index 926063168..8711a60e0 100644 --- a/modoboa/extensions/stats/modo_extension.py +++ b/modoboa/extensions/stats/modo_extension.py @@ -7,7 +7,6 @@ This module provides support to retrieve statistics from postfix log : sent, received, bounced, rejected """ -import sys from django.utils.translation import ugettext_lazy From 9b80cf2a2c140e84e9b982011b0c649ffee74398 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 25 Mar 2015 15:25:32 +0100 Subject: [PATCH 16/17] select_related is a method! fix #701 --- modoboa/extensions/amavis/general_callbacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/extensions/amavis/general_callbacks.py b/modoboa/extensions/amavis/general_callbacks.py index 76b994e16..f08c9fa4e 100644 --- a/modoboa/extensions/amavis/general_callbacks.py +++ b/modoboa/extensions/amavis/general_callbacks.py @@ -64,7 +64,7 @@ def on_mailbox_modified(mailbox): not hasattr(mailbox, "old_full_address") or \ mailbox.full_address == mailbox.old_full_address: return - user = Users.objects.select_related.get(email=mailbox.old_full_address) + user = Users.objects.select_related().get(email=mailbox.old_full_address) full_address = mailbox.full_address user.email = full_address user.policy.policy_name = full_address[:32] From e436bdda210e952f5416765e90d6802be9855a28 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 25 Mar 2015 15:43:15 +0100 Subject: [PATCH 17/17] Instantiate extensions... --- modoboa/extensions/amavis/management/commands/amnotify.py | 2 +- modoboa/extensions/amavis/management/commands/qcleanup.py | 2 +- .../postfix_autoreply/management/commands/autoreply.py | 2 +- .../extensions/radicale/management/commands/generate_rights.py | 2 +- modoboa/extensions/stats/management/commands/logparser.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modoboa/extensions/amavis/management/commands/amnotify.py b/modoboa/extensions/amavis/management/commands/amnotify.py index d9962b93f..577a81308 100644 --- a/modoboa/extensions/amavis/management/commands/amnotify.py +++ b/modoboa/extensions/amavis/management/commands/amnotify.py @@ -44,7 +44,7 @@ class Command(BaseCommand, CloseConnectionMixin): def handle(self, *args, **options): if options["baseurl"] is None: raise CommandError("You must provide the --baseurl option") - Amavis.load() + Amavis().load() self.options = options self.notify_admins_pending_requests() diff --git a/modoboa/extensions/amavis/management/commands/qcleanup.py b/modoboa/extensions/amavis/management/commands/qcleanup.py index 34dcdc060..eaf1ed283 100644 --- a/modoboa/extensions/amavis/management/commands/qcleanup.py +++ b/modoboa/extensions/amavis/management/commands/qcleanup.py @@ -35,7 +35,7 @@ class Command(BaseCommand, CloseConnectionMixin): print msg def handle(self, *args, **options): - Amavis.load() + Amavis().load() if options["debug"]: import logging l = logging.getLogger("django.db.backends") diff --git a/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py b/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py index 44d2ed172..0dd3ecd23 100644 --- a/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py +++ b/modoboa/extensions/postfix_autoreply/management/commands/autoreply.py @@ -53,7 +53,7 @@ class Command(BaseCommand, CloseConnectionMixin): raise CommandError( "usage: ./manage.py autoreply ") - PostfixAutoreply.load() + PostfixAutoreply().load() sender = args[0] for fulladdress in args[1:]: address, domain = split_mailbox(fulladdress) diff --git a/modoboa/extensions/radicale/management/commands/generate_rights.py b/modoboa/extensions/radicale/management/commands/generate_rights.py index 25365c514..58663a855 100644 --- a/modoboa/extensions/radicale/management/commands/generate_rights.py +++ b/modoboa/extensions/radicale/management/commands/generate_rights.py @@ -103,7 +103,7 @@ permission = %s def handle(self, *args, **options): """Command entry point.""" - Radicale.load() + Radicale().load() path = parameters.get_admin("RIGHTS_FILE_PATH", app="radicale") if not options["force"]: try: diff --git a/modoboa/extensions/stats/management/commands/logparser.py b/modoboa/extensions/stats/management/commands/logparser.py index 089c374ab..e898d338c 100644 --- a/modoboa/extensions/stats/management/commands/logparser.py +++ b/modoboa/extensions/stats/management/commands/logparser.py @@ -373,7 +373,7 @@ class Command(BaseCommand, CloseConnectionMixin): ) def handle(self, *args, **options): - Stats.load() + Stats().load() if options["logfile"] is None: options["logfile"] = parameters.get_admin("LOGFILE", app="stats") p = LogParser(options, parameters.get_admin("RRD_ROOTDIR", app="stats"))