# HG changeset patch # User Pascal Volk # Date 1267306615 0 # Node ID 371ae0b4443d319d3eade4fa7c5982dcf193feff # Parent 8b8d632f0ef3f4315601d00b5195cbad3e4b5782 VMM/Alias: renamed Alias.add_destination() to add_destinations(). Now it's possible to add one ore more destinations to the alias with a single method call. VMM/Handler: adjusted Handler.aliasAdd() to the API changes of the Alias class. Also use get_gid from the Domain module to get the gid of a domain. We don't need complete Domain object, only the gid. Handler.getWarnings(): no longer return the __warnings list. Return a copy instead and empty the Handler.__warnings list. diff -r 8b8d632f0ef3 -r 371ae0b4443d VirtualMailManager/Alias.py --- a/VirtualMailManager/Alias.py Sat Feb 27 20:58:49 2010 +0000 +++ b/VirtualMailManager/Alias.py Sat Feb 27 21:36:55 2010 +0000 @@ -11,6 +11,7 @@ from VirtualMailManager.Domain import get_gid from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.errors import AliasError as AErr +from VirtualMailManager.pycompat import all from VirtualMailManager.constants.ERROR import ALIAS_ADDR_DEST_IDENTICAL, \ ALIAS_EXCEEDS_EXPANSION_LIMIT, ALIAS_EXISTS, NO_SUCH_ALIAS @@ -44,27 +45,27 @@ dest_add(EmailAddress(dest[0])) dbc.close() - def __check_expansion(self, limit): + def __check_expansion(self, count_new, limit): """Checks the current expansion limit of the alias.""" dcount = len(self._dests) failed = False - if dcount == limit: + if dcount == limit or dcount + count_new > limit: failed = True errmsg = _( -u"""Can't add new destination to alias %(address)r. +u"""Can't add %(count_new)i new destination(s) to alias %(address)r. Currently this alias expands into %(count)i/%(limit)i recipients. -One more destination will render this alias unusable. +%(count_new)i additional destination(s) will render this alias unusable. Hint: Increase Postfix' virtual_alias_expansion_limit""") elif dcount > limit: failed = True errmsg = _( -u"""Can't add new destination to alias %(address)r. +u"""Can't add %(count_new)i new destination(s) to alias %(address)r. This alias already exceeds it's expansion limit (%(count)i/%(limit)i). So its unusable, all messages addressed to this alias will be bounced. Hint: Delete some destination addresses.""") if failed: raise AErr(errmsg % {'address': str(self._addr), 'count': dcount, - 'limit': limit}, + 'limit': limit, 'count_new': count_new}, ALIAS_EXCEEDS_EXPANSION_LIMIT) def __delete(self, destination=None): @@ -89,25 +90,39 @@ """Returns the number of destinations of the alias.""" return len(self._dests) - def add_destination(self, destination, expansion_limit): - """Adds the ``destination`` `EmailAddress` to the alias.""" - assert isinstance(destination, EmailAddress) - if self._addr == destination: - raise AErr(_(u"Address and destination are identical."), - ALIAS_ADDR_DEST_IDENTICAL) - if destination in self._dests: - raise AErr(_( - u'The alias %(a)r has already the destination %(d)r.') % - {'a': str(self._addr), 'd': str(destination)}, - ALIAS_EXISTS) - self.__check_expansion(expansion_limit) + def add_destinations(self, destinations, expansion_limit, warnings=None): + """Adds the `EmailAddress`es from *destinations* list to the + destinations of the alias. + + Destinations, that are already assigned to the alias, will be + removed from *destinations*. When done, this method will return + a set with all destinations, that was saved in the database. + """ + destinations = set(destinations) + assert destinations and \ + all(isinstance(dest, EmailAddress) for dest in destinations) + if not warnings is None: + assert isinstance(warnings, list) + if self._addr in destinations: + destinations.remove(self._addr) + if not warnings is None: + warnings.append(self._addr) + duplicates = destinations.intersection(set(self._dests)) + if duplicates: + destinations.difference_update(set(self._dests)) + if not warnings is None: + warnings.extend(duplicates) + if not destinations: + return destinations + self.__check_expansion(len(destinations), expansion_limit) dbc = self._dbh.cursor() - dbc.execute('INSERT INTO alias (gid, address, destination) \ -VALUES (%s, %s, %s)', - self._gid, self._addr.localpart, str(destination)) + dbc.executemany("INSERT INTO alias VALUES (%d, '%s', %%s)" % + (self._gid, self._addr.localpart), + (str(destination) for destination in destinations)) self._dbh.commit() dbc.close() - self._dests.append(destination) + self._dests.extend(destinations) + return destinations def del_destination(self, destination): """Deletes the specified ``destination`` address from the alias.""" @@ -131,7 +146,7 @@ return iter(self._dests) def delete(self): - """Deletes the alias with all it's destinations.""" + """Deletes the alias with all its destinations.""" if not self._dests: raise AErr(_(u"The alias %r doesn't exist.") % str(self._addr), NO_SUCH_ALIAS) diff -r 8b8d632f0ef3 -r 371ae0b4443d VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Sat Feb 27 20:58:49 2010 +0000 +++ b/VirtualMailManager/Handler.py Sat Feb 27 21:36:55 2010 +0000 @@ -26,9 +26,9 @@ from VirtualMailManager.Alias import Alias from VirtualMailManager.AliasDomain import AliasDomain from VirtualMailManager.Config import Config as Cfg -from VirtualMailManager.Domain import Domain +from VirtualMailManager.Domain import Domain, get_gid from VirtualMailManager.EmailAddress import EmailAddress -from VirtualMailManager.errors import VMMError, AliasError +from VirtualMailManager.errors import VMMError, AliasError, DomainError from VirtualMailManager.Relocated import Relocated from VirtualMailManager.ext.Postconf import Postconf @@ -394,8 +394,13 @@ return bool(len(self.__warnings)) def getWarnings(self): - """Returns a list with all available warnings.""" - return self.__warnings + """Returns a list with all available warnings and resets all + warnings. + + """ + ret_val = self.__warnings[:] + del self.__warnings[:] + return ret_val def cfgDget(self, option): return self._Cfg.dget(option) @@ -529,19 +534,32 @@ self._Cfg.dget('account.sieve')) self.__mailDirMake(acc.getDir('domain'), acc.getUID(), acc.getGID()) - def aliasAdd(self, aliasaddress, targetaddress): + def aliasAdd(self, aliasaddress, *targetaddresses): """Creates a new `Alias` entry for the given *aliasaddress* with - the given *targetaddress*.""" + the given *targetaddresses*.""" alias = self.__getAlias(aliasaddress) - destination = EmailAddress(targetaddress) - alias.add_destination(destination, - long(self._postconf.read('virtual_alias_expansion_limit'))) - gid = self.__getDomain(destination.domainname).getID() - if gid > 0 and (not Handler.accountExists(self._dbh, destination) and - not Handler.aliasExists(self._dbh, destination)): - self.__warnings.append( - _(u"The destination account/alias ā€œ%sā€ doesn't exist.") % - destination) + destinations = [EmailAddress(address) for address in targetaddresses] + warnings = [] + destinations = alias.add_destinations(destinations, + long(self._postconf.read('virtual_alias_expansion_limit')), + warnings) + if warnings: + self.__warnings.append(_('Ignored destination addresses:')) + self.__warnings.extend((' * %s' % w for w in warnings)) + for destination in destinations: + try: + gid = get_gid(self._dbh, destination.domainname) + except DomainError, e: + if e.code == ERR.NO_SUCH_DOMAIN: + continue + else: + raise + if gid > 0 and \ + (not Handler.accountExists(self._dbh, destination) and + not Handler.aliasExists(self._dbh, destination)): + self.__warnings.append( + _(u"The destination account/alias %r doesn't exist.") % + str(destination)) def userDelete(self, emailaddress, force=None): if force not in [None, 'delalias']: