VMM: {alias,catchall}delete: Accept multiple destinations.
--- a/VirtualMailManager/alias.py Mon Sep 24 19:13:51 2012 +0000
+++ b/VirtualMailManager/alias.py Thu Sep 27 19:15:09 2012 +0000
@@ -73,20 +73,21 @@
'limit': limit, 'count_new': count_new},
ALIAS_EXCEEDS_EXPANSION_LIMIT)
- def _delete(self, destination=None):
- """Deletes a destination from the alias, if ``destination`` is
- not ``None``. If ``destination`` is None, the alias with all
+ def _delete(self, destinations=None):
+ """Deletes the *destinations* from the alias, if ``destinations``
+ is not ``None``. If ``destinations`` is None, the alias with all
its destination addresses will be deleted.
"""
dbc = self._dbh.cursor()
- if not destination:
+ if not destinations:
dbc.execute('DELETE FROM alias WHERE gid = %s AND address = %s',
(self._gid, self._addr.localpart))
else:
- dbc.execute('DELETE FROM alias WHERE gid = %s AND address = %s '
- 'AND destination = %s',
- (self._gid, self._addr.localpart, str(destination)))
+ dbc.executemany("DELETE FROM alias WHERE gid = %d AND address = "
+ "'%s' AND destination = %%s" % (self._gid,
+ self._addr.localpart),
+ ((str(dest),) for dest in destinations))
if dbc.rowcount > 0:
self._dbh.commit()
dbc.close()
@@ -135,18 +136,34 @@
self._dests.extend(destinations)
return destinations
- def del_destination(self, destination):
- """Deletes the specified ``destination`` address from the alias."""
- assert isinstance(destination, EmailAddress)
+ def del_destinations(self, destinations, warnings=None):
+ """Delete the specified `EmailAddress`es of *destinations* from
+ the alias's destinations.
+
+ """
+ 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)
if not self._dests:
raise AErr(_(u"The alias '%s' does not exist.") % self._addr,
NO_SUCH_ALIAS)
- if not destination in self._dests:
- raise AErr(_(u"The address '%(addr)s' is not a destination of "
- u"the alias '%(alias)s'.") % {'addr': destination,
- 'alias': self._addr}, NO_SUCH_ALIAS)
- self._delete(destination)
- self._dests.remove(destination)
+ unknown = destinations.difference(set(self._dests))
+ if unknown:
+ destinations.intersection_update(set(self._dests))
+ if not warnings is None:
+ warnings.extend(unknown)
+ if not destinations:
+ raise AErr(_(u"No suitable destinations left to remove from alias "
+ u"'%s'.") % self._addr, NO_SUCH_ALIAS)
+ self._delete(destinations)
+ for destination in destinations:
+ self._dests.remove(destination)
def get_destinations(self):
"""Returns an iterator for all destinations of the alias."""
--- a/VirtualMailManager/catchall.py Mon Sep 24 19:13:51 2012 +0000
+++ b/VirtualMailManager/catchall.py Thu Sep 27 19:15:09 2012 +0000
@@ -84,18 +84,19 @@
'limit': limit, 'count_new': count_new},
ALIAS_EXCEEDS_EXPANSION_LIMIT)
- def _delete(self, destination=None):
- """Deletes a destination from the catchall alias, if ``destination``
- is not ``None``. If ``destination`` is None, the catchall alias with
- all its destination addresses will be deleted.
+ def _delete(self, destinations=None):
+ """Delete one ore multiple destinations from the catchall alias, if
+ ``destinations`` is not ``None``. If ``destinations`` is None, the
+ catchall alias with all its destination addresses will be deleted.
"""
dbc = self._dbh.cursor()
- if not destination:
+ if not destinations:
dbc.execute('DELETE FROM catchall WHERE gid = %s', (self._gid,))
else:
- dbc.execute('DELETE FROM catchall WHERE gid = %s '
- 'AND destination = %s', (self._gid, str(destination)))
+ dbc.executemany('DELETE FROM catchall WHERE gid = %d AND '
+ 'destination = %%s' % self._gid,
+ ((str(dest),) for dest in destinations))
if dbc.rowcount > 0:
self._dbh.commit()
dbc.close()
@@ -139,20 +140,28 @@
self._dests.extend(destinations)
return destinations
- def del_destination(self, destination):
- """Deletes the specified ``destination`` address from the catchall
- alias."""
- assert isinstance(destination, EmailAddress)
+ def del_destinations(self, destinations, warnings=None):
+ """Deletes the specified ``destinations`` from the catchall alias."""
+ destinations = set(destinations)
+ assert destinations and \
+ all(isinstance(dest, EmailAddress) for dest in destinations)
+ if not warnings is None:
+ assert isinstance(warnings, list)
if not self._dests:
raise AErr(_(u"There are no catch-all aliases defined for "
u"domain '%s'.") % self._domain, NO_SUCH_ALIAS)
- if not destination in self._dests:
- raise AErr(_(u"The address '%(addr)s' is not a destination of "
- u"the catch-all alias for domain '%(domain)s'.")
- % {'addr': destination, 'domain': self._domain},
+ unknown = destinations.difference(set(self._dests))
+ if unknown:
+ destinations.intersection_update(set(self._dests))
+ if not warnings is None:
+ warnings.extend(unknown)
+ if not destinations:
+ raise AErr(_(u"No suitable destinations left to remove from the "
+ u"catch-all alias of domain '%s'.") % self._domain,
NO_SUCH_ALIAS)
- self._delete(destination)
- self._dests.remove(destination)
+ self._delete(destinations)
+ for destination in destinations:
+ self._dests.remove(destination)
def get_destinations(self):
"""Returns an iterator for all destinations of the catchall alias."""
--- a/VirtualMailManager/cli/clihelp.py Mon Sep 24 19:13:51 2012 +0000
+++ b/VirtualMailManager/cli/clihelp.py Thu Sep 27 19:15:09 2012 +0000
@@ -193,6 +193,11 @@
will be replaced by the local part, the domain, or the email address with '@'
replaced by '=' respectively. In combination with alias domains, this enables
domain-specific destinations."""),),
+ # TP: description of subcommand aliasdelete
+ 'aliasdelete': (_(u"""This subcommand is used to delete one or multiple
+<destination>s from the alias with the given <address>."""),
+_(u"""When no <destination> address was specified the alias with all its
+destinations will be deleted."""),),
# TP: description of subcommand aliasinfo
'aliasinfo': (_(u"""Information about the alias with the given <address>
can be displayed with this subcommand."""),),
@@ -222,8 +227,8 @@
aliases defined for the domain <fqdn>."""),),
# TP: description of subcommand catchalldelete
'catchalldelete': (_(u"""With this subcommand, catch-all aliases defined
-for a domain can be removed, either all of them, or a single one if specified
-explicitly."""),),
+for a domain can be removed, either all of them, or those <destination>s which
+were specified explicitly."""),),
}
del _
--- a/VirtualMailManager/cli/subcommands.py Mon Sep 24 19:13:51 2012 +0000
+++ b/VirtualMailManager/cli/subcommands.py Thu Sep 27 19:15:09 2012 +0000
@@ -133,7 +133,7 @@
elif ctx.argc < 4:
ctx.hdlr.alias_delete(ctx.args[2].lower())
else:
- ctx.hdlr.alias_delete(ctx.args[2].lower(), ctx.args[3])
+ ctx.hdlr.alias_delete(ctx.args[2].lower(), ctx.args[3:])
def alias_info(ctx):
@@ -220,7 +220,7 @@
elif ctx.argc < 4:
ctx.hdlr.catchall_delete(ctx.args[2].lower())
else:
- ctx.hdlr.catchall_delete(ctx.args[2].lower(), ctx.args[3])
+ ctx.hdlr.catchall_delete(ctx.args[2].lower(), ctx.args[3:])
def catchall_info(ctx):
@@ -826,7 +826,7 @@
_(u'create a new alias e-mail address with one or more '
u'destinations')),
'aliasdelete': cmd('aliasdelete', 'ad', alias_delete,
- 'address [destination]',
+ 'address [destination ...]',
_(u'delete the specified alias e-mail address or one '
u'of its destinations')),
'aliasinfo': cmd('aliasinfo', 'ai', alias_info, 'address',
@@ -848,7 +848,7 @@
_(u'add one or more catch-all destinations for a '
u'domain')),
'catchalldelete': cmd('catchalldelete', 'cad', catchall_delete,
- 'fqdn [destination]',
+ 'fqdn [destination ...]',
_(u'delete the specified catch-all destination or all '
u'of a domain\'s destinations')),
'catchallinfo': cmd('catchallinfo', 'cai', catchall_info, 'fqdn',
--- a/VirtualMailManager/handler.py Mon Sep 24 19:13:51 2012 +0000
+++ b/VirtualMailManager/handler.py Thu Sep 27 19:15:09 2012 +0000
@@ -711,16 +711,27 @@
raise VMMError(_(u"The alias '%s' does not exist.") %
alias.address, NO_SUCH_ALIAS)
- def alias_delete(self, aliasaddress, targetaddress=None):
+ def alias_delete(self, aliasaddress, targetaddresses=None):
"""Deletes the `Alias` *aliasaddress* with all its destinations from
- the database. If *targetaddress* is not ``None``, only this
- destination will be removed from the alias."""
+ the database. If *targetaddresses* is not ``None``, only the given
+ destinations will be removed from the alias."""
alias = self._get_alias(aliasaddress)
- if targetaddress is None:
+ error = None
+ if targetaddresses is None:
alias.delete()
else:
- alias.del_destination(DestinationEmailAddress(targetaddress,
- self._dbh))
+ destinations = [DestinationEmailAddress(addr, self._dbh)
+ for addr in targetaddresses]
+ warnings = []
+ try:
+ alias.del_destinations(destinations, warnings)
+ except VMMError, err:
+ error = err
+ if warnings:
+ self._warnings.append(_('Ignored destination addresses:'))
+ self._warnings.extend((' * %s' % w for w in warnings))
+ if error:
+ raise error
def catchall_add(self, domain, *targetaddresses):
"""Creates a new `CatchallAlias` entry for the given *domain* with
@@ -744,16 +755,27 @@
instances) for the `CatchallAlias` with the given *domain*."""
return self._get_catchall(domain).get_destinations()
- def catchall_delete(self, domain, targetaddress=None):
+ def catchall_delete(self, domain, targetaddresses=None):
"""Deletes the `CatchallAlias` for domain *domain* with all its
- destinations from the database. If *targetaddress* is not ``None``,
- only this destination will be removed from the alias."""
+ destinations from the database. If *targetaddresses* is not
+ ``None``, only those destinations will be removed from the alias."""
catchall = self._get_catchall(domain)
- if targetaddress is None:
+ error = None
+ if targetaddresses is None:
catchall.delete()
else:
- catchall.del_destination(DestinationEmailAddress(targetaddress,
- self._dbh))
+ destinations = [DestinationEmailAddress(addr, self._dbh)
+ for addr in targetaddresses]
+ warnings = []
+ try:
+ catchall.del_destinations(destinations, warnings)
+ except VMMError, err:
+ error = err
+ if warnings:
+ self._warnings.append(_('Ignored destination addresses:'))
+ self._warnings.extend((' * %s' % w for w in warnings))
+ if error:
+ raise error
def user_info(self, emailaddress, details=None):
"""Wrapper around Account.get_info(...)"""
--- a/man/de/man1/vmm.1 Mon Sep 24 19:13:51 2012 +0000
+++ b/man/de/man1/vmm.1 Thu Sep 27 19:15:09 2012 +0000
@@ -1,4 +1,4 @@
-.TH "VMM" "1" "2012-08-12" "vmm 0.6" "vmm"
+.TH "VMM" "1" "2012-09-27" "vmm 0.6" "vmm"
.SH NAME
vmm \- Kommandozeilenprogramm zur Verwaltung von E\-Mail\-Domains/\-Konten
und \-Aliase.
@@ -853,15 +853,15 @@
.\" ------------------------------------
.SS aliasdelete (ad)
.BI "vmm aliasdelete" " address"
-.RI [ destination ]
+.RI [ destination " ...]"
.PP
Verwenden Sie diesen Unterbefehl um den Alias mit der angegebenen Adresse
zu löschen.
.PP
-Wurde eine optionale
+Wurden eine oder mehrere optionale
.I destination
-angegeben, so wird nur diese
-.I destination
+Adressen angegeben, so werden nur diese
+.IR destination s
vom angegebenen Alias entfernt.
.PP
Beispiel:
@@ -972,11 +972,13 @@
.\" ------------------------------------
.SS catchalldelete (cad)
.BI "vmm catchalldelete " fqdn
-.RI [ destination ]
+.RI [ destination " ...]"
.PP
Mit diesem Unterbefehl werden Catch\-all Aliase einer Domain wieder
-gelöscht, entweder nur das angegebene Alias, oder alle, wenn keines
-angegeben wurde.
+gelöscht,
+entweder nur das/die angegebene(n) Alias(e), oder alle, wenn keine
+.I destination
+Adresse angegeben wurde.
.PP
Beispiel:
.PP
--- a/man/man1/vmm.1 Mon Sep 24 19:13:51 2012 +0000
+++ b/man/man1/vmm.1 Thu Sep 27 19:15:09 2012 +0000
@@ -1,4 +1,4 @@
-.TH "VMM" "1" "2012-09-02" "vmm 0.6" "vmm"
+.TH "VMM" "1" "2012-09-27" "vmm 0.6" "vmm"
.SH NAME
vmm \- command line tool to manage email domains/accounts/aliases
.\" -----------------------------------------------------------------------
@@ -821,15 +821,16 @@
.\" ------------------------------------
.SS aliasdelete (ad)
.BI "vmm aliasdelete" " address"
-.RI [ destination ]
+.RI [ destination " ...]"
.PP
-Use this subcommand to delete the alias with the given
+This subcommand is used to delete one or multiple
+.IR destination s
+from the alias with the given
.IR address .
.PP
-If the optional
+When no
.I destination
-address is given, only this
-destination will be removed from the alias.
+address was specified the alias with all its destinations will be deleted.
.PP
Example:
.PP
@@ -935,10 +936,12 @@
.\" ------------------------------------
.SS catchalldelete (cad)
.BI "vmm catchalldelete " fqdn
-.RI [ destination ]
+.RI [ destination " ...]"
.PP
With this subcommand, catch\-all aliases defined for a domain can be
-removed, either all of them, or a single one if specified explicitly.
+removed, either all of them, or those
+.IR destination s
+which were specified explicitly.
.PP
Example:
.PP