VirtualMailManager/serviceset.py
branchv0.6.x
changeset 438 e35efe931af3
child 439 39036f5e6387
equal deleted inserted replaced
437:9823548b2717 438:e35efe931af3
       
     1 # coding: utf-8
       
     2 # Copyright (c) 2011, Pascal Volk
       
     3 # See COPYING for distribution information.
       
     4 """
       
     5     VirtualMailManager.serviceset
       
     6     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
     7 
       
     8     Virtual Mail Manager's ServiceSet class for simplified database access
       
     9     to the service_set table.
       
    10 """
       
    11 
       
    12 cfg_dget = lambda option: None
       
    13 
       
    14 
       
    15 class ServiceSet(object):
       
    16     """A wrapper class that provides access to the service_set table.
       
    17 
       
    18     Each ServiceSet object provides following - read only - attributes:
       
    19 
       
    20     `ssid` : long
       
    21       The id of the service set
       
    22     `smtp` : bool
       
    23       Boolean flag for service smtp
       
    24     `pop3` : bool
       
    25       Boolean flag for service pop3
       
    26     `imap` : bool
       
    27       Boolean flag for service imap
       
    28     `sieve` : bool
       
    29       Boolean flag for service sieve
       
    30     """
       
    31     __slots__ = ('_ssid', '_services', '_sieve_col', '_dbh')
       
    32     _kwargs = ('ssid', 'smtp', 'pop3', 'imap', 'sieve')
       
    33 
       
    34     def __init__(self, dbh, **kwargs):
       
    35         """Creates a new ServiceSet instance.
       
    36 
       
    37         Either the 'ssid' keyword argument or one or more of the service
       
    38         arguments ('smtp', 'pop3',  'imap', 'sieve') must be provided.
       
    39 
       
    40         Arguments:
       
    41         `dbh` : pyPgSQL.PgSQL.Connection or psycopg2.extensions.connection
       
    42           A database connection for the database access.
       
    43 
       
    44         Keyword arguments:
       
    45         `ssid` : int
       
    46           The id of the service set (>0)
       
    47         `smtp` : bool
       
    48           Boolean flag for service smtp - default `True`
       
    49         `pop3` : bool
       
    50           Boolean flag for service pop3 - default `True`
       
    51         `imap` : bool
       
    52           Boolean flag for service imap - default `True`
       
    53         `sieve` : bool
       
    54           Boolean flag for service sieve - default `True`
       
    55         """
       
    56         self._dbh = dbh
       
    57         self._ssid = 0
       
    58         self._services = dict.fromkeys(self.__class__._kwargs[1:], True)
       
    59         if cfg_dget('misc.dovecot_version') < 0x10200b02:
       
    60             self._sieve_col = 'managesieve'
       
    61         else:
       
    62             self._sieve_col = 'sieve'
       
    63 
       
    64         for key in kwargs.iterkeys():
       
    65             if key not in self.__class__._kwargs:
       
    66                 raise ValueError('unrecognized keyword: %r' % key)
       
    67             if key == 'ssid':
       
    68                 assert not isinstance(kwargs[key], bool) and \
       
    69                        isinstance(kwargs[key], (int, long)) and kwargs[key] > 0
       
    70                 self._load_by_ssid(kwargs[key])
       
    71                 break
       
    72             else:
       
    73                 assert isinstance(kwargs[key], bool)
       
    74                 if not kwargs[key]:
       
    75                     self._services[key] = kwargs[key]
       
    76         if not self._ssid:
       
    77             self._load_by_services()
       
    78 
       
    79     def __eq__(self, other):
       
    80         if isinstance(other, self.__class__):
       
    81             return self._ssid == other._ssid
       
    82         return NotImplemented
       
    83 
       
    84     def __ne__(self, other):
       
    85         if isinstance(other, self.__class__):
       
    86             return self._ssid != other._ssid
       
    87         return NotImplemented
       
    88 
       
    89     def __getattr__(self, name):
       
    90         if name not in self.__class__._kwargs:
       
    91             raise AttributeError('%r object has no attribute %r' % (
       
    92                                  self.__class__.__name__, name))
       
    93         if name == 'ssid':
       
    94             return self._ssid
       
    95         else:
       
    96             return self._services[name]
       
    97 
       
    98     def __repr__(self):
       
    99         return '%s(%s, %s)' % (self.__class__.__name__, self._dbh,
       
   100                   ', '.join('%s=%r' % s for s in self._services.iteritems()))
       
   101 
       
   102     def _load_by_services(self):
       
   103         """Try to load the service_set by it's service combination."""
       
   104         sql = ('SELECT ssid FROM service_set WHERE %s' %
       
   105                ' AND '.join('%s = %s' %
       
   106                (k, str(v).upper()) for k, v in self._services.iteritems()))
       
   107         if self._sieve_col == 'managesieve':
       
   108             sql.replace('sieve', self._sieve_col)
       
   109         dbc = self._dbh.cursor()
       
   110         dbc.execute(sql)
       
   111         result = dbc.fetchone()
       
   112         dbc.close()
       
   113         if result:
       
   114             self._ssid = result[0]
       
   115         else:
       
   116             self._save()
       
   117 
       
   118     def _load_by_ssid(self, ssid):
       
   119         """Try to load the service_set by it's primary key."""
       
   120         dbc = self._dbh.cursor()
       
   121         dbc.execute('SELECT ssid, smtp, pop3, imap, %s' % (self._sieve_col,) +
       
   122                     ' FROM service_set WHERE ssid = %s', (ssid,))
       
   123         result = dbc.fetchone()
       
   124         dbc.close()
       
   125         if not result:
       
   126             raise ValueError('Unknown service_set id specified: %r' % ssid)
       
   127         self._ssid = result[0]
       
   128         self._services.update(zip(self.__class__._kwargs[1:], result[1:]))
       
   129 
       
   130     def _save(self):
       
   131         """Store a new service_set in the database."""
       
   132         sql = ('INSERT INTO service_set (ssid, smtp, pop3, imap, %s) ' %
       
   133                (self._sieve_col,) +
       
   134                'VALUES (%(ssid)s, %(smtp)s, %(pop3)s, %(imap)s, %(sieve)s)')
       
   135         if self._sieve_col == 'managesieve':
       
   136             sql.replace('sieve', self._sieve_col)
       
   137         self._set_ssid()
       
   138         values = {'ssid': self._ssid}
       
   139         values.update(self._services)
       
   140         dbc = self._dbh.cursor()
       
   141         dbc.execute(sql, values)
       
   142         self._dbh.commit()
       
   143         dbc.close()
       
   144 
       
   145     def _set_ssid(self):
       
   146         """Set the unique ID for the new service_set."""
       
   147         assert self._ssid == 0
       
   148         dbc = self._dbh.cursor()
       
   149         dbc.execute("SELECT nextval('service_set_id')")
       
   150         self._ssid = dbc.fetchone()[0]
       
   151         dbc.close()
       
   152 
       
   153 del cfg_dget