VirtualMailManager/Account.py
branchv0.6.x
changeset 245 f9a6b6701cf9
parent 236 084331dd1e4c
child 246 481280686789
equal deleted inserted replaced
244:698ba4208ddc 245:f9a6b6701cf9
     1 # -*- coding: UTF-8 -*-
     1 # -*- coding: UTF-8 -*-
     2 # Copyright (c) 2007 - 2010, Pascal Volk
     2 # Copyright (c) 2007 - 2010, Pascal Volk
     3 # See COPYING for distribution information.
     3 # See COPYING for distribution information.
     4 
     4 
     5 """Virtual Mail Manager's Account class to manage e-mail accounts."""
     5 """
     6 
     6     VirtualMailManager.Account
     7 import VirtualMailManager.constants.ERROR as ERR
     7 
       
     8     Virtual Mail Manager's Account class to manage e-mail accounts.
       
     9 """
       
    10 
     8 from VirtualMailManager.Domain import Domain
    11 from VirtualMailManager.Domain import Domain
     9 from VirtualMailManager.EmailAddress import EmailAddress
    12 from VirtualMailManager.EmailAddress import EmailAddress
    10 from VirtualMailManager.errors import AccountError as AccE
    13 from VirtualMailManager.Transport import Transport
       
    14 from VirtualMailManager.constants.ERROR import \
       
    15      ACCOUNT_EXISTS, ACCOUNT_MISSING_PASSWORD, ALIAS_EXISTS, ALIAS_PRESENT, \
       
    16      INVALID_AGUMENT, NO_SUCH_ACCOUNT, NO_SUCH_DOMAIN, RELOCATED_EXISTS, \
       
    17      UNKNOWN_MAILLOCATION_NAME, UNKNOWN_SERVICE
       
    18 from VirtualMailManager.errors import AccountError as AErr
    11 from VirtualMailManager.maillocation import MailLocation, known_format
    19 from VirtualMailManager.maillocation import MailLocation, known_format
    12 from VirtualMailManager.Transport import Transport
    20 from VirtualMailManager.pycompat import all
    13 
    21 
    14 
    22 
    15 _ = lambda msg: msg
    23 _ = lambda msg: msg
    16 
    24 
    17 
    25 
    18 class Account(object):
    26 class Account(object):
    19     """Class to manage e-mail accounts."""
    27     """Class to manage e-mail accounts."""
    20     __slots__ = ('_addr', '_base', '_gid', '_mid', '_passwd', '_tid', '_uid',
    28     __slots__ = ('_addr', '_domain', '_mid', '_new', '_passwd', '_tid', '_uid',
    21                  '_dbh')
    29                  '_dbh')
    22 
    30 
    23     def __init__(self, dbh, address, password=None):
    31     def __init__(self, dbh, address):
       
    32         """Creates a new Account instance.
       
    33 
       
    34         When an account with the given *address* could be found in the
       
    35         database all relevant data will be loaded.
       
    36 
       
    37         Arguments:
       
    38 
       
    39         `dbh` : pyPgSQL.PgSQL.Connection
       
    40           A database connection for the database access.
       
    41         `address` : basestring
       
    42           The e-mail address of the (new) Account.
       
    43         """
       
    44         if not isinstance(address, EmailAddress):
       
    45             raise TypeError("Argument 'address' is not an EmailAddress")
       
    46         self._addr = address
    24         self._dbh = dbh
    47         self._dbh = dbh
    25         self._base = None
    48         self._domain = Domain(self._dbh, self._addr.domainname)
    26         if isinstance(address, EmailAddress):
    49         if not self._domain.gid:
    27             self._addr = address
    50             raise AErr(_(u"The domain '%s' doesn't exist.") %
    28         else:
    51                        self._addr.domainname, NO_SUCH_DOMAIN)
    29             raise TypeError("Argument 'address' is not an EmailAddress")
       
    30         self._uid = 0
    52         self._uid = 0
    31         self._gid = 0
       
    32         self._mid = 0
    53         self._mid = 0
    33         self._tid = 0
    54         self._tid = 0
    34         self._passwd = password
    55         self._passwd = None
    35         self._setAddr()
    56         self._new = True
    36         self._exists()
    57         self._load()
    37         from VirtualMailManager.Handler import Handler
    58 
    38         if self._uid < 1 and Handler.aliasExists(self._dbh, self._addr):
    59     def _load(self):
    39             # TP: Hm, what quotation marks should be used?
    60         """Load 'uid', 'mid' and 'tid' from the database and set _new to
    40             # If you are unsure have a look at:
    61         `False` - if the user could be found. """
    41             # http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage
       
    42             raise AccE(_(u"There is already an alias with the address “%s”.") %
       
    43                        self._addr, ERR.ALIAS_EXISTS)
       
    44         if self._uid < 1 and Handler.relocatedExists(self._dbh, self._addr):
       
    45             raise AccE(
       
    46               _(u"There is already a relocated user with the address “%s”.") %
       
    47                        self._addr, ERR.RELOCATED_EXISTS)
       
    48 
       
    49     def _exists(self):
       
    50         dbc = self._dbh.cursor()
    62         dbc = self._dbh.cursor()
    51         dbc.execute(
    63         dbc.execute(
    52             "SELECT uid, mid, tid FROM users WHERE gid=%s AND local_part=%s",
    64             "SELECT uid, mid, tid FROM users WHERE gid=%s AND local_part=%s",
    53                     self._gid, self._addr.localpart)
    65                     self._domain.gid, self._addr.localpart)
    54         result = dbc.fetchone()
    66         result = dbc.fetchone()
    55         dbc.close()
    67         dbc.close()
    56         if result is not None:
    68         if result:
    57             self._uid, self._mid, self._tid = result
    69             self._uid, self._mid, self._tid = result
    58             return True
    70             self._new = False
    59         else:
    71 
    60             return False
    72     def _set_uid(self):
    61 
    73         """Set the unique ID for the new Account."""
    62     def _setAddr(self):
    74         assert self._uid == 0
    63         dom = Domain(self._dbh, self._addr.domainname)
       
    64         self._gid = dom.gid
       
    65         if self._gid == 0:
       
    66             raise AccE(_(u"The domain “%s” doesn't exist.") %
       
    67                        self._addr.domainname, ERR.NO_SUCH_DOMAIN)
       
    68         self._base = dom.directory
       
    69         self._tid = dom.transport.tid
       
    70 
       
    71     def _setID(self):
       
    72         dbc = self._dbh.cursor()
    75         dbc = self._dbh.cursor()
    73         dbc.execute("SELECT nextval('users_uid')")
    76         dbc.execute("SELECT nextval('users_uid')")
    74         self._uid = dbc.fetchone()[0]
    77         self._uid = dbc.fetchone()[0]
    75         dbc.close()
    78         dbc.close()
    76 
    79 
    77     def _prepare(self, maillocation):
    80     def _prepare(self, maillocation):
    78         if not known_format(maillocation):                                  
    81         """Check and set different attributes - before we store the
    79             raise AccE(_(u'Unknown mail_location mailbox format: %r') %
    82         information in the database."""
    80                        maillocation, ERR.UNKNOWN_MAILLOCATION_NAME)
    83         if not known_format(maillocation):
    81         self._setID()
    84             raise AErr(_(u'Unknown mail_location mailbox format: %r') %
       
    85                        maillocation, UNKNOWN_MAILLOCATION_NAME)
    82         self._mid = MailLocation(format=maillocation).mid
    86         self._mid = MailLocation(format=maillocation).mid
    83 
    87         if not self._tid:
    84     def _switchState(self, state, dcvers, service):
    88             self._tid = self._domain.tid
    85         if not isinstance(state, bool):
    89         self._set_uid()
    86             return False
    90 
    87         if not service in (None, 'all', 'imap', 'pop3', 'sieve', 'smtp'):
    91     def _switch_state(self, state, dcvers, service):
    88             raise AccE(_(u"Unknown service “%s”.") % service,
    92         """Switch the state of the Account's services on or off. See
    89                     ERR.UNKNOWN_SERVICE)
    93         Account.enable()/Account.disable() for more information."""
    90         if self._uid < 1:
    94         self._chk_state()
    91             raise AccE(_(u"The account “%s” doesn't exist.") % self._addr,
    95         if service not in (None, 'all', 'imap', 'pop3', 'sieve', 'smtp'):
    92                     ERR.NO_SUCH_ACCOUNT)
    96             raise AErr(_(u"Unknown service: '%s'.") % service, UNKNOWN_SERVICE)
    93         if dcvers > 11:
    97         if dcvers > 11:
    94             sieve_col = 'sieve'
    98             sieve_col = 'sieve'
    95         else:
    99         else:
    96             sieve_col = 'managesieve'
   100             sieve_col = 'managesieve'
    97         if service in ('smtp', 'pop3', 'imap'):
   101         if service in ('smtp', 'pop3', 'imap'):
    98             sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (service, state,
   102             sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (service, state,
    99                     self._uid)
   103                                                                self._uid)
   100         elif service == 'sieve':
   104         elif service == 'sieve':
   101             sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (sieve_col,
   105             sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (sieve_col,
   102                     state, self._uid)
   106                                                                state,
       
   107                                                                self._uid)
   103         else:
   108         else:
   104             sql = 'UPDATE users SET smtp = %(s)s, pop3 = %(s)s, imap = %(s)s,\
   109             sql = 'UPDATE users SET smtp = %(s)s, pop3 = %(s)s, imap = %(s)s,\
   105  %(col)s = %(s)s WHERE uid = %(uid)d' % {
   110  %(col)s = %(s)s WHERE uid = %(uid)d' % \
   106                 's': state, 'col': sieve_col, 'uid': self._uid}
   111                 {'s': state, 'col': sieve_col, 'uid': self._uid}
   107         dbc = self._dbh.cursor()
   112         dbc = self._dbh.cursor()
   108         dbc.execute(sql)
   113         dbc.execute(sql)
   109         if dbc.rowcount > 0:
   114         if dbc.rowcount > 0:
   110             self._dbh.commit()
   115             self._dbh.commit()
   111         dbc.close()
   116         dbc.close()
   112 
   117 
   113     def __aliaseCount(self):
   118     def _count_aliases(self):
   114         dbc = self._dbh.cursor()
   119         """Count all alias addresses where the destination address is the
   115         q = "SELECT COUNT(destination) FROM alias WHERE destination = '%s'"\
   120         address of the Account."""
   116             % self._addr
   121         dbc = self._dbh.cursor()
   117         dbc.execute(q)
   122         sql = "SELECT COUNT(destination) FROM alias WHERE destination = '%s'"\
       
   123                 % self._addr
       
   124         dbc.execute(sql)
   118         a_count = dbc.fetchone()[0]
   125         a_count = dbc.fetchone()[0]
   119         dbc.close()
   126         dbc.close()
   120         return a_count
   127         return a_count
   121 
   128 
   122     def setPassword(self, password):
   129     def _chk_state(self):
       
   130         """Raise an AccountError if the Account is new - not yet saved in the
       
   131         database."""
       
   132         if self._new:
       
   133             raise AErr(_(u"The account '%s' doesn't exist.") % self._addr,
       
   134                        NO_SUCH_ACCOUNT)
       
   135 
       
   136     @property
       
   137     def domain_directory(self):
       
   138         """The directory of the domain the Account belongs to."""
       
   139         return self._domain.directory
       
   140 
       
   141     @property
       
   142     def gid(self):
       
   143         """The Account's group ID."""
       
   144         return self._domain.gid
       
   145 
       
   146     @property
       
   147     def home(self):
       
   148         """The Account's home directory."""
       
   149         return '%s/%s' % (self._domain.directory, self._uid)
       
   150 
       
   151     @property
       
   152     def uid(self):
       
   153         """The Account's unique ID."""
       
   154         return self._uid
       
   155 
       
   156     def set_password(self, password):
       
   157         """Set a password for the new Account.
       
   158 
       
   159         If you want to update the password of an existing Account use
       
   160         Account.modify().
       
   161 
       
   162         Argument:
       
   163 
       
   164         `password` : basestring
       
   165           The hashed password for the new Account."""
   123         self._passwd = password
   166         self._passwd = password
   124 
   167 
   125     def getUID(self):
   168     def set_transport(self, transport):
   126         return self._uid
   169         """Set the transport for the new Account.
   127 
   170 
   128     def getGID(self):
   171         If you want to update the transport of an existing Account use
   129         return self._gid
   172         Account.modify().
   130 
   173 
   131     def getDir(self, directory):
   174         Argument:
   132         if directory == 'domain':
   175 
   133             return '%s' % self._base
   176         `transport` : basestring
   134         elif directory == 'home':
   177           The string representation of the transport, e.g.: 'dovecot:'
   135             return '%s/%i' % (self._base, self._uid)
   178         """
       
   179         self._tid = Transport(self._dbh, transport=transport).tid
   136 
   180 
   137     def enable(self, dcvers, service=None):
   181     def enable(self, dcvers, service=None):
   138         self._switchState(True, dcvers, service)
   182         """Enable a/all service/s for the Account.
       
   183 
       
   184         Possible values for the *service* are: 'imap', 'pop3', 'sieve' and
       
   185         'smtp'. When all services should be enabled, use 'all' or the
       
   186         default value `None`.
       
   187 
       
   188         Arguments:
       
   189 
       
   190         `dcvers` : int
       
   191           The concatenated major and minor version number from
       
   192           `dovecot --version`.
       
   193         `service` : basestring
       
   194           The name of a service ('imap', 'pop3', 'smtp', 'sieve'), 'all'
       
   195           or `None`.
       
   196         """
       
   197         self._switch_state(True, dcvers, service)
   139 
   198 
   140     def disable(self, dcvers, service=None):
   199     def disable(self, dcvers, service=None):
   141         self._switchState(False, dcvers, service)
   200         """Disable a/all service/s for the Account.
       
   201 
       
   202         For more information see: Account.enable()."""
       
   203         self._switch_state(False, dcvers, service)
   142 
   204 
   143     def save(self, maillocation, dcvers, smtp, pop3, imap, sieve):
   205     def save(self, maillocation, dcvers, smtp, pop3, imap, sieve):
   144         if self._uid < 1:
   206         """Save the new Account in the database.
   145             if dcvers > 11:
   207 
   146                 sieve_col = 'sieve'
   208         Arguments:
   147             else:
   209 
   148                 sieve_col = 'managesieve'
   210         `maillocation` : basestring
   149             self._prepare(maillocation)
   211           The mailbox format of the mail_location: 'maildir', 'mbox',
   150             sql = "INSERT INTO users (local_part, passwd, uid, gid, mid, tid,\
   212           'dbox' or 'mdbox'.
       
   213         `dcvers` : int
       
   214           The concatenated major and minor version number from
       
   215           `dovecot --version`.
       
   216         `smtp, pop3, imap, sieve` : bool
       
   217           Indicates if the user of the Account should be able to use this
       
   218           services.
       
   219         """
       
   220         if not self._new:
       
   221             raise AErr(_(u"The account '%s' already exists.") % self._addr,
       
   222                        ACCOUNT_EXISTS)
       
   223         if not self._passwd:
       
   224             raise AErr(_(u"No password set for '%s'.") % self._addr,
       
   225                        ACCOUNT_MISSING_PASSWORD)
       
   226         assert all(isinstance(service, bool) for service in (smtp, pop3, imap,
       
   227                                                              sieve))
       
   228         if dcvers > 11:
       
   229             sieve_col = 'sieve'
       
   230         else:
       
   231             sieve_col = 'managesieve'
       
   232         self._prepare(maillocation)
       
   233         sql = "INSERT INTO users (local_part, passwd, uid, gid, mid, tid,\
   151  smtp, pop3, imap, %s) VALUES ('%s', '%s', %d, %d, %d, %d, %s, %s, %s, %s)" % (
   234  smtp, pop3, imap, %s) VALUES ('%s', '%s', %d, %d, %d, %d, %s, %s, %s, %s)" % (
   152                 sieve_col, self._addr.localpart, self._passwd, self._uid,
   235             sieve_col, self._addr.localpart, self._passwd, self._uid,
   153                 self._gid, self._mid, self._tid, smtp, pop3, imap, sieve)
   236             self._domain.gid, self._mid, self._tid, smtp, pop3, imap, sieve)
   154             dbc = self._dbh.cursor()
   237         dbc = self._dbh.cursor()
   155             dbc.execute(sql)
   238         dbc.execute(sql)
   156             self._dbh.commit()
   239         self._dbh.commit()
   157             dbc.close()
   240         dbc.close()
   158         else:
   241         self._new = False
   159             raise AccE(_(u'The account “%s” already exists.') % self._addr,
   242 
   160                     ERR.ACCOUNT_EXISTS)
   243     def modify(self, field, value):
   161 
   244         """Update the Account's *field* to the new *value*.
   162     def modify(self, what, value):
   245 
   163         if self._uid == 0:
   246         Possible values for *filed* are: 'name', 'password' and
   164             raise AccE(_(u"The account “%s” doesn't exist.") % self._addr,
   247         'transport'.  *value* is the *field*'s new value.
   165                     ERR.NO_SUCH_ACCOUNT)
   248 
   166         if what not in ['name', 'password', 'transport']:
   249         Arguments:
   167             return False
   250 
   168         dbc = self._dbh.cursor()
   251         `field` : basestring
   169         if what == 'password':
   252           The attribute name: 'name', 'password' or 'transport'
       
   253         `value` : basestring
       
   254           The new value of the attribute. The password is expected as a
       
   255           hashed password string.
       
   256         """
       
   257         if field not in ('name', 'password', 'transport'):
       
   258             raise AErr(_(u"Unknown field: '%s'") % field, INVALID_AGUMENT)
       
   259         self._chk_state()
       
   260         dbc = self._dbh.cursor()
       
   261         if field == 'password':
   170             dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s',
   262             dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s',
   171                     value, self._uid)
   263                         value, self._uid)
   172         elif what == 'transport':
   264         elif field == 'transport':
   173             self._tid = Transport(self._dbh, transport=value).tid
   265             self._tid = Transport(self._dbh, transport=value).tid
   174             dbc.execute('UPDATE users SET tid = %s WHERE uid = %s',
   266             dbc.execute('UPDATE users SET tid = %s WHERE uid = %s',
   175                     self._tid, self._uid)
   267                         self._tid, self._uid)
   176         else:
   268         else:
   177             dbc.execute('UPDATE users SET name = %s WHERE uid = %s',
   269             dbc.execute('UPDATE users SET name = %s WHERE uid = %s',
   178                     value, self._uid)
   270                         value, self._uid)
   179         if dbc.rowcount > 0:
   271         if dbc.rowcount > 0:
   180             self._dbh.commit()
   272             self._dbh.commit()
   181         dbc.close()
   273         dbc.close()
   182 
   274 
   183     def getInfo(self, dcvers):
   275     def get_info(self, dcvers):
       
   276         """Returns a dict with some information about the Account.
       
   277 
       
   278         The keys of the dict are: 'address', 'gid', 'home', 'imap'
       
   279         'mail_location', 'name', 'pop3', 'sieve', 'smtp', transport' and
       
   280         'uid'.
       
   281 
       
   282         Argument:
       
   283 
       
   284         `dcvers` : int
       
   285           The concatenated major and minor version number from
       
   286           `dovecot --version`.
       
   287         """
       
   288         self._chk_state()
   184         if dcvers > 11:
   289         if dcvers > 11:
   185             sieve_col = 'sieve'
   290             sieve_col = 'sieve'
   186         else:
   291         else:
   187             sieve_col = 'managesieve'
   292             sieve_col = 'managesieve'
   188         sql = 'SELECT name, uid, gid, mid, tid, smtp, pop3, imap, %s\
   293         sql = 'SELECT name, uid, gid, mid, tid, smtp, pop3, imap, %s\
   189  FROM users WHERE uid = %d' % (sieve_col, self._uid)
   294  FROM users WHERE uid = %d' % (sieve_col, self._uid)
   190         dbc = self._dbh.cursor()
   295         dbc = self._dbh.cursor()
   191         dbc.execute(sql)
   296         dbc.execute(sql)
   192         info = dbc.fetchone()
   297         info = dbc.fetchone()
   193         dbc.close()
   298         dbc.close()
   194         if info is None:
   299         if info:
   195             raise AccE(_(u"The account “%s” doesn't exist.") % self._addr,
   300             keys = ('name', 'uid', 'gid', 'mid', 'transport', 'smtp',
   196                     ERR.NO_SUCH_ACCOUNT)
   301                     'pop3', 'imap', sieve_col)
   197         else:
       
   198             keys = ['name', 'uid', 'gid', 'mid', 'transport', 'smtp',
       
   199                     'pop3', 'imap', sieve_col]
       
   200             info = dict(zip(keys, info))
   302             info = dict(zip(keys, info))
   201             for service in ('smtp', 'pop3', 'imap', sieve_col):
   303             for service in ('smtp', 'pop3', 'imap', sieve_col):
   202                 if bool(info[service]):
   304                 if info[service]:
   203                     # TP: A service (pop3/imap/…) is enabled/usable for a user
   305                     # TP: A service (pop3/imap) is enabled/usable for a user
   204                     info[service] = _('enabled')
   306                     info[service] = _('enabled')
   205                 else:
   307                 else:
   206                     # TP: A service (pop3/imap) isn't enabled/usable for a user
   308                     # TP: A service (pop3/imap) isn't enabled/usable for a user
   207                     info[service] = _('disabled')
   309                     info[service] = _('disabled')
   208             info['address'] = self._addr
   310             info['address'] = self._addr
   209             info['home'] = '%s/%s' % (self._base, info['uid'])
   311             info['home'] = '%s/%s' % (self._domain.directory, info['uid'])
   210             info['mail_location'] = MailLocation(mid=info['mid']).mail_location
   312             info['mail_location'] = MailLocation(mid=info['mid']).mail_location
   211             info['transport'] = Transport(self._dbh,
   313             info['transport'] = Transport(self._dbh,
   212                                           tid=info['transport']).transport
   314                                           tid=info['transport']).transport
       
   315             del info['mid']
   213             return info
   316             return info
   214 
   317         # nearly impossible‽
   215     def getAliases(self):
   318         raise AErr(_(u"Couldn't fetch information for account: '%s'") \
       
   319                    % self._addr, NO_SUCH_ACCOUNT)
       
   320 
       
   321     def get_aliases(self):
       
   322         """Return a list with all alias e-mail addresses, whose destination
       
   323         is the address of the Account."""
       
   324         self._chk_state()
   216         dbc = self._dbh.cursor()
   325         dbc = self._dbh.cursor()
   217         dbc.execute("SELECT address ||'@'|| domainname FROM alias, domain_name\
   326         dbc.execute("SELECT address ||'@'|| domainname FROM alias, domain_name\
   218  WHERE destination = %s AND domain_name.gid = alias.gid\
   327  WHERE destination = %s AND domain_name.gid = alias.gid\
   219  AND domain_name.is_primary ORDER BY address", str(self._addr))
   328  AND domain_name.is_primary ORDER BY address", str(self._addr))
   220         addresses = dbc.fetchall()
   329         addresses = dbc.fetchall()
   221         dbc.close()
   330         dbc.close()
   222         aliases = []
   331         aliases = []
   223         if len(addresses) > 0:
   332         if addresses:
   224             aliases = [alias[0] for alias in addresses]
   333             aliases = [alias[0] for alias in addresses]
   225         return aliases
   334         return aliases
   226 
   335 
   227     def delete(self, delalias):
   336     def delete(self, delalias):
   228         if self._uid < 1:
   337         """Delete the Account from the database.
   229             raise AccE(_(u"The account “%s” doesn't exist.") % self._addr,
   338 
   230                     ERR.NO_SUCH_ACCOUNT)
   339         Argument:
       
   340 
       
   341         `delalias` : basestring
       
   342           if the values of delalias is 'delalias', all aliases, which
       
   343           points to the Account, will be also deleted."""
       
   344         self._chk_state()
   231         dbc = self._dbh.cursor()
   345         dbc = self._dbh.cursor()
   232         if delalias == 'delalias':
   346         if delalias == 'delalias':
   233             dbc.execute('DELETE FROM users WHERE uid= %s', self._uid)
   347             dbc.execute('DELETE FROM users WHERE uid= %s', self._uid)
   234             u_rc = dbc.rowcount
       
   235             # delete also all aliases where the destination address is the same
   348             # delete also all aliases where the destination address is the same
   236             # as for this account.
   349             # as for this account.
   237             dbc.execute("DELETE FROM alias WHERE destination = %s",
   350             dbc.execute("DELETE FROM alias WHERE destination = %s",
   238                     str(self._addr))
   351                         str(self._addr))
   239             if u_rc > 0 or dbc.rowcount > 0:
   352             self._dbh.commit()
   240                 self._dbh.commit()
   353         else:  # check first for aliases
   241         else: # check first for aliases
   354             a_count = self._count_aliases()
   242             a_count = self.__aliaseCount()
       
   243             if a_count == 0:
   355             if a_count == 0:
   244                 dbc.execute('DELETE FROM users WHERE uid = %s', self._uid)
   356                 dbc.execute('DELETE FROM users WHERE uid = %s', self._uid)
   245                 if dbc.rowcount > 0:
   357                 self._dbh.commit()
   246                     self._dbh.commit()
       
   247             else:
   358             else:
   248                 dbc.close()
   359                 dbc.close()
   249                 raise AccE(
   360                 raise AErr(_(u"There are %(count)d aliases with the \
   250                   _(u"There are %(count)d aliases with the destination address\
   361 destination address '%(address)s'.") % \
   251  “%(address)s”.") % {'count': a_count, 'address': self._addr},
   362                            {'count': a_count, 'address': self._addr},
   252                   ERR.ALIAS_PRESENT)
   363                            ALIAS_PRESENT)
   253         dbc.close()
   364         dbc.close()
   254 
   365 
   255 
   366 
   256 def getAccountByID(uid, dbh):
   367 def getAccountByID(uid, dbh):
       
   368     """Search an Account by its UID.
       
   369 
       
   370     Argument:
       
   371 
       
   372     `uid` : long
       
   373       The Account unique ID.
       
   374     `dbh` : pyPgSQL.PgSQL.Connection
       
   375       a database connection for the database access.
       
   376     """
   257     try:
   377     try:
   258         uid = long(uid)
   378         uid = long(uid)
   259     except ValueError:
   379     except ValueError:
   260         raise AccE(_(u'uid must be an int/long.'), ERR.INVALID_AGUMENT)
   380         raise AErr(_(u'UID must be an int/long.'), INVALID_AGUMENT)
   261     if uid < 1:
   381     if uid < 1:
   262         raise AccE(_(u'uid must be greater than 0.'), ERR.INVALID_AGUMENT)
   382         raise AErr(_(u'UID must be greater than 0.'), INVALID_AGUMENT)
   263     dbc = dbh.cursor()
   383     dbc = dbh.cursor()
   264     dbc.execute("SELECT local_part||'@'|| domain_name.domainname AS address,\
   384     dbc.execute("SELECT local_part||'@'|| domain_name.domainname AS address,\
   265  uid, users.gid FROM users LEFT JOIN domain_name ON (domain_name.gid \
   385  uid, users.gid FROM users LEFT JOIN domain_name ON (domain_name.gid \
   266  = users.gid AND is_primary) WHERE uid = %s;", uid)
   386  = users.gid AND is_primary) WHERE uid = %s;", uid)
   267     info = dbc.fetchone()
   387     info = dbc.fetchone()
   268     dbc.close()
   388     dbc.close()
   269     if info is None:
   389     if not info:
   270         raise AccE(_(u"There is no account with the UID “%d”.") % uid,
   390         raise AErr(_(u"There is no account with the UID '%d'.") % uid,
   271                 ERR.NO_SUCH_ACCOUNT)
   391                    NO_SUCH_ACCOUNT)
   272     keys = ['address', 'uid', 'gid']
   392     info = dict(zip(('address', 'uid', 'gid'), info))
   273     info = dict(zip(keys, info))
       
   274     return info
   393     return info
   275 
   394 
   276 
   395 
   277 del _
   396 del _