VMM/account: Integrated class ServiceSet in class Account. v0.6.x
authorPascal Volk <neverseen@users.sourceforge.net>
Wed, 02 Nov 2011 03:29:51 +0000
branchv0.6.x
changeset 444 95275b61ff8a
parent 443 e2b9e3de2b51
child 445 b8c94e06cd46
VMM/account: Integrated class ServiceSet in class Account. Replaced methods Account.enable() and Account.disable() by Account.update_serviceset(). VMM/handler: Replaced methods Handler.user_disable() and Handler.user_enable() by Handler.user_services()
VirtualMailManager/account.py
VirtualMailManager/handler.py
--- a/VirtualMailManager/account.py	Tue Nov 01 23:37:06 2011 +0000
+++ b/VirtualMailManager/account.py	Wed Nov 02 03:29:51 2011 +0000
@@ -20,10 +20,9 @@
 from VirtualMailManager.password import pwhash
 from VirtualMailManager.quotalimit import QuotaLimit
 from VirtualMailManager.transport import Transport
+from VirtualMailManager.serviceset import ServiceSet
 
-__all__ = ('SERVICES', 'Account', 'get_account_by_uid')
-
-SERVICES = ('imap', 'pop3', 'smtp', 'sieve')
+__all__ = ('Account', 'get_account_by_uid')
 
 _ = lambda msg: msg
 cfg_dget = lambda option: None
@@ -32,7 +31,7 @@
 class Account(object):
     """Class to manage e-mail accounts."""
     __slots__ = ('_addr', '_dbh', '_domain', '_mail', '_new', '_passwd',
-                 '_qlimit', '_transport', '_uid')
+                 '_qlimit', '_services', '_transport', '_uid')
 
     def __init__(self, dbh, address):
         """Creates a new Account instance.
@@ -61,6 +60,7 @@
         self._uid = 0
         self._mail = None
         self._qlimit = self._domain.quotalimit
+        self._services = self._domain.serviceset
         self._transport = self._domain.transport
         self._passwd = None
         self._new = True
@@ -71,17 +71,20 @@
         return not self._new
 
     def _load(self):
-        """Load 'uid', 'mid', 'qid' and 'tid' from the database and set
-        _new to `False` - if the user could be found. """
+        """Load 'uid', 'mid', 'qid', 'ssid'  and 'tid' from the database and
+        set _new to `False` - if the user could be found. """
         dbc = self._dbh.cursor()
-        dbc.execute('SELECT uid, mid, qid, tid FROM users WHERE gid = %s AND '
-                    'local_part=%s', (self._domain.gid, self._addr.localpart))
+        dbc.execute('SELECT uid, mid, qid, ssid, tid FROM users WHERE gid = '
+                    '%s AND local_part = %s', (self._domain.gid,
+                                               self._addr.localpart))
         result = dbc.fetchone()
         dbc.close()
         if result:
-            self._uid, _mid, _qid, _tid = result
+            self._uid, _mid, _qid, _ssid, _tid = result
             if _qid != self._qlimit.qid:
                 self._qlimit = QuotaLimit(self._dbh, qid=_qid)
+            if _ssid != self._services.ssid:
+                self._services = ServiceSet(self._dbh, ssid=_ssid)
             if _tid != self._transport.tid:
                 self._transport = Transport(self._dbh, tid=_tid)
             self._mail = MailLocation(self._dbh, mid=_mid)
@@ -114,50 +117,17 @@
         self._mail = maillocation
         self._set_uid()
 
-    def _update_services(self, activate, *services):
-        """Activate or deactivate the Account's services.
-
-        Arguments:
-
-        `activate`: bool
-          When `True` the Account's user will be able to login to the
-          services, otherwise the login will fail.
-        `*services`
-          No or one or more of the services: imap, pop3, smtp and sieve
-        """
-        self._chk_state()
-        if services:
-            services = set(services)
-            for service in services:
-                if service not in SERVICES:
-                    raise AErr(_(u"Unknown service: '%s'") % service,
-                               UNKNOWN_SERVICE)
-        else:
-            services = SERVICES
-        state = ('FALSE', 'TRUE')[activate]
-        sql = 'UPDATE users SET %s WHERE uid = %u' % (
-                    (' = %(s)s, '.join(services) + ' = %(s)s') % {'s': state},
-                    self._uid)
-        if 'sieve' in services and \
-           cfg_dget('misc.dovecot_version') < 0x10200b02:
-            sql = sql.replace('sieve', 'managesieve')
-        dbc = self._dbh.cursor()
-        dbc.execute(sql)
-        if dbc.rowcount > 0:
-            self._dbh.commit()
-        dbc.close()
-
     def _update_tables(self, column, value):
         """Update various columns in the users table.
 
         Arguments:
 
         `column` : basestring
-          Name of the table column. Currently: qid and tid
+          Name of the table column. Currently: qid, ssid and tid
         `value` : long
           The referenced key
         """
-        if column not in ('qid', 'tid'):
+        if column not in ('qid', 'ssid', 'tid'):
             raise ValueError('Unknown column: %r' % column)
         dbc = self._dbh.cursor()
         dbc.execute('UPDATE users SET %s = %%s WHERE uid = %%s' % column,
@@ -238,26 +208,6 @@
                        ACCOUNT_MISSING_PASSWORD)
         self._passwd = password
 
-    def enable(self, *services):
-        """Enable all or the given service/s for the Account.
-
-        Possible *services* are: 'imap', 'pop3', 'sieve' and 'smtp'.
-        When all services should be enabled, give no service name.
-
-        Arguments:
-
-        `*services` : basestring
-          No or one or more of the services 'imap', 'pop3', 'smtp', and
-          'sieve'.
-        """
-        self._update_services(True, *services)
-
-    def disable(self, *services):
-        """Disable all or the given service/s for the Account.
-
-        For more information see: Account.enable()."""
-        self._update_services(False, *services)
-
     def save(self):
         """Save the new Account in the database."""
         if not self._new:
@@ -266,22 +216,15 @@
         if not self._passwd:
             raise AErr(_(u"No password set for account: '%s'") % self._addr,
                        ACCOUNT_MISSING_PASSWORD)
-        if cfg_dget('misc.dovecot_version') >= 0x10200b02:
-            sieve_col = 'sieve'
-        else:
-            sieve_col = 'managesieve'
         self._prepare(MailLocation(self._dbh, mbfmt=cfg_dget('mailbox.format'),
                                    directory=cfg_dget('mailbox.root')))
         dbc = self._dbh.cursor()
         dbc.execute('INSERT INTO users (local_part, passwd, uid, gid, mid, '
-                    'qid, tid, smtp, pop3, imap, %s) VALUES' % (sieve_col,) + \
-                    '(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)',
+                    'qid, ssid, tid) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)',
                     (self._addr.localpart,
                      pwhash(self._passwd, user=self._addr), self._uid,
                      self._domain.gid, self._mail.mid, self._qlimit.qid,
-                     self._transport.tid, cfg_dget('account.smtp'),
-                     cfg_dget('account.pop3'), cfg_dget('account.imap'),
-                     cfg_dget('account.sieve')))
+                     self._services.ssid, self._transport.tid))
         self._dbh.commit()
         dbc.close()
         self._new = False
@@ -330,6 +273,21 @@
         self._update_tables('qid', quotalimit.qid)
         self._qlimit = quotalimit
 
+    def update_serviceset(self, serviceset):
+        """Assign a different set of services to the Account.
+
+        Argument:
+
+        `serviceset` : VirtualMailManager.serviceset.ServiceSet
+          the new service set.
+        """
+        self._chk_state()
+        assert isinstance(serviceset, ServiceSet)
+        if serviceset == self._services:
+            return
+        self._update_tables('ssid', serviceset.ssid)
+        self._services = serviceset
+
     def update_transport(self, transport):
         """Sets a new transport for the Account.
 
@@ -359,29 +317,19 @@
         'uq_bytes', 'uq_messages', 'ql_bytes', and 'ql_messages'.
         """
         self._chk_state()
-        if cfg_dget('misc.dovecot_version') >= 0x10200b02:
-            sieve_col = 'sieve'
-        else:
-            sieve_col = 'managesieve'
         dbc = self._dbh.cursor()
-        dbc.execute('SELECT name, smtp, pop3, imap, %s, CASE WHEN bytes IS '
-                    'NULL THEN 0 ELSE bytes END, CASE WHEN messages IS NULL '
-                    'THEN 0 ELSE messages END FROM users LEFT JOIN userquota '
-                    'USING (uid) WHERE users.uid = %u' % (sieve_col,
-                        self._uid))
+        dbc.execute('SELECT name, CASE WHEN bytes IS NULL THEN 0 ELSE bytes '
+                    'END, CASE WHEN messages IS NULL THEN 0 ELSE messages END '
+                    'FROM users LEFT JOIN userquota USING (uid) WHERE '
+                    'users.uid = %s', (self._uid,))
         info = dbc.fetchone()
         dbc.close()
         if info:
-            keys = ('name', 'smtp', 'pop3', 'imap', sieve_col, 'uq_bytes',
-                    'uq_messages')
-            info = dict(zip(keys, info))
-            for service in keys[1:5]:
-                if info[service]:
-                    # TP: A service (pop3/imap) is enabled/usable for a user
-                    info[service] = _('enabled')
-                else:
-                    # TP: A service (pop3/imap) isn't enabled/usable for a user
-                    info[service] = _('disabled')
+            info = dict(zip(('name', 'uq_bytes', 'uq_messages'), info))
+            for service, state in self._services.services.iteritems():
+                # TP: A service (e.g. pop3 or imap) may be enabled/usable or
+                # disabled/unusable for a user.
+                info[service] = (_('disabled'), _('enabled'))[state]
             info['address'] = self._addr
             info['gid'] = self._domain.gid
             info['home'] = '%s/%s' % (self._domain.directory, self._uid)
@@ -446,7 +394,7 @@
         self._new = True
         self._uid = 0
         self._addr = self._dbh = self._domain = self._passwd = None
-        self._mail = self._qlimit = self._transport = None
+        self._mail = self._qlimit = self._services = self._transport = None
 
 
 def get_account_by_uid(uid, dbh):
--- a/VirtualMailManager/handler.py	Tue Nov 01 23:37:06 2011 +0000
+++ b/VirtualMailManager/handler.py	Wed Nov 02 03:29:51 2011 +0000
@@ -740,29 +740,20 @@
                            acc.address, NO_SUCH_ACCOUNT)
         acc.update_transport(Transport(self._dbh, transport=transport))
 
-    def user_disable(self, emailaddress, services=None):
-        """Wrapper for Account.disable(*services)"""
-        if services is None:
-            services = []
-        else:
-            assert isinstance(services, list)
+    def user_services(self, emailaddress, *services):
+        """Wrapper around Account.update_serviceset()."""
+        kwargs = dict.fromkeys(SERVICES, False)
+        for service in set(services):
+            if service not in SERVICES:
+                raise VMMError(_(u"Unknown service: '%s'") % service,
+                               UNKNOWN_SERVICE)
+            kwargs[service] = True
         acc = self._get_account(emailaddress)
         if not acc:
             raise VMMError(_(u"The account '%s' does not exist.") %
                            acc.address, NO_SUCH_ACCOUNT)
-        acc.disable(*services)
-
-    def user_enable(self, emailaddress, services=None):
-        """Wrapper for Account.enable(*services)"""
-        if services is None:
-            services = []
-        else:
-            assert isinstance(services, list)
-        acc = self._get_account(emailaddress)
-        if not acc:
-            raise VMMError(_(u"The account '%s' does not exist.") %
-                           acc.address, NO_SUCH_ACCOUNT)
-        acc.enable(*services)
+        serviceset = ServiceSet(self._dbh, **kwargs)
+        acc.update_serviceset(serviceset)
 
     def relocated_add(self, emailaddress, targetaddress):
         """Creates a new `Relocated` entry in the database. If there is