VMM/Alias: renamed Alias.add_destination() to add_destinations(). v0.6.x
authorPascal Volk <neverseen@users.sourceforge.net>
Sat, 27 Feb 2010 21:36:55 +0000
branchv0.6.x
changeset 221 371ae0b4443d
parent 220 8b8d632f0ef3
child 222 d0c16e70a9fb
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.
VirtualMailManager/Alias.py
VirtualMailManager/Handler.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)
--- 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']: