<NME> handle_mailbox_operations.py
<BEF> """A management command to apply mailbox operations."""

from optparse import make_option
from django.core.management.base import BaseCommand
from modoboa.lib import parameters
from modoboa.admin.models import MailboxOperation


from modoboa.parameters import tools as param_tools
from ...app_settings import load_admin_settings
from ...models import MailboxOperation


class OperationError(Exception):
    """Custom exception."""

    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)
        self.logger = logging.getLogger('modoboa.cron')

    def rename_mailbox(self, operation):
        if not os.path.exists(operation.argument):
            return
        new_mail_home = operation.mailbox.mail_home.strip(os.sep)
        self.logger.info("Renaming %s to %s", operation.argument, new_mail_home)
        curpath = '/'
        for part in new_mail_home.split(os.sep)[:-1]:
            if not part:
                continue
            curpath = os.path.join(curpath, part)
            if not os.path.exists(curpath):
                os.mkdir(curpath)
        code, output = exec_cmd(
            "mv %s %s" % (old_mail_home, new_mail_home)
        )
        if code:
            raise OperationError(output)
        )
    def delete_mailbox(self, operation):
        if not os.path.exists(operation.argument):
            return
        self.logger.info("Deleting %s", operation.argument)
        code, output = exec_cmd(
            "rm -r %s" % operation.argument
        )
        if code:
            raise OperationError(output)

    def handle(self):
        if parameters.get_admin("HANDLE_MAILBOXES") == 'no':
            return
        for ope in MailboxOperation.objects.all():
            try:
                f = getattr(self, '%s_mailbox' % ope.optype)
            except AttributeError:
                continue
            try:
                f(ope)
            except OperationError as e:
                self.logger.critical('Operation failed: %s', str(e))
            else:
                ope.delete()
                "delete failed (reason: {})".format(excinfo))

        shutil.rmtree(operation.argument, False, onerror)

    def check_pidfile(self, path):
        """Check if this command is already running

        :param str path: path to the file containing the PID
        :return: a boolean, True means we can go further
        """
        if os.path.exists(path):
            with open(path) as fp:
                pid = fp.read().strip()
            code, output = exec_cmd(
                "grep handle_mailbox_operations /proc/%s/cmdline" % pid
            )
            if not code:
                return False
        with open(path, "w") as fp:
            print(os.getpid(), file=fp)
        return True

    def handle(self, *args, **options):
        """Command entry point."""
        load_admin_settings()
        if not param_tools.get_global_parameter("handle_mailboxes"):
            return
        if not self.check_pidfile(options["pidfile"]):
            return
        for ope in MailboxOperation.objects.all():
            try:
                f = getattr(self, "%s_mailbox" % ope.type)
            except AttributeError:
                continue
            try:
                f(ope)
            except (OperationError, InternalError) as e:
                self.logger.critical(
                    "%s failed (reason: %s)", ope, str(e).decode("utf-8"))
            else:
                self.logger.info("%s succeed", ope)
                ope.delete()
        os.unlink(options["pidfile"])

<MSG> Log results into the database.

see #482

<DFF> @@ -3,6 +3,8 @@ import logging
 from optparse import make_option
 from django.core.management.base import BaseCommand
 from modoboa.lib import parameters
+from modoboa.lib.sysutils import exec_cmd
+from modoboa.admin import AdminConsole
 from modoboa.admin.models import MailboxOperation
 
 
@@ -16,22 +18,18 @@ class Command(BaseCommand):
 
     def __init__(self, *args, **kwargs):
         super(Command, self).__init__(*args, **kwargs)
-        self.logger = logging.getLogger('modoboa.cron')
+        self.logger = logging.getLogger('modoboa.admin')
 
     def rename_mailbox(self, operation):
         if not os.path.exists(operation.argument):
             return
-        new_mail_home = operation.mailbox.mail_home.strip(os.sep)
-        self.logger.info("Renaming %s to %s", operation.argument, new_mail_home)
-        curpath = '/'
-        for part in new_mail_home.split(os.sep)[:-1]:
-            if not part:
-                continue
-            curpath = os.path.join(curpath, part)
-            if not os.path.exists(curpath):
-                os.mkdir(curpath)
+        new_mail_home = operation.mailbox.mail_home
+        try:
+            os.makedirs(os.path.dirname(new_mail_home))
+        except os.error as e:
+            raise OperationError(str(e))
         code, output = exec_cmd(
-            "mv %s %s" % (old_mail_home, new_mail_home)
+            "mv %s %s" % (ope.argument, new_mail_home)
         )
         if code:
             raise OperationError(output)
@@ -39,24 +37,25 @@ class Command(BaseCommand):
     def delete_mailbox(self, operation):
         if not os.path.exists(operation.argument):
             return
-        self.logger.info("Deleting %s", operation.argument)
         code, output = exec_cmd(
             "rm -r %s" % operation.argument
         )
         if code:
             raise OperationError(output)
 
-    def handle(self):
+    def handle(self, *args, **options):
+        AdminConsole().load()
         if parameters.get_admin("HANDLE_MAILBOXES") == 'no':
             return
         for ope in MailboxOperation.objects.all():
             try:
-                f = getattr(self, '%s_mailbox' % ope.optype)
+                f = getattr(self, '%s_mailbox' % ope.type)
             except AttributeError:
                 continue
             try:
                 f(ope)
             except OperationError as e:
-                self.logger.critical('Operation failed: %s', str(e))
+                self.logger.critical('Operation failed: %s. Reason: %s', ope, str(e))
             else:
+                self.logger.info('Operation succeed: %s', ope)
                 ope.delete()

Log results into the database.