The SubscriptionWorkflow class doesn't need to include the expiry date in its
[mailman.git] / src / mailman / app / lifecycle.py
blob140ccab211b366db4a2117d856f6c22a5e7095d2
1 # Copyright (C) 2007-2015 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
8 # any later version.
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 # more details.
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
18 """Application level list creation."""
20 __all__ = [
21 'create_list',
22 'remove_list',
26 import os
27 import errno
28 import shutil
29 import logging
31 from mailman.config import config
32 from mailman.interfaces.address import IEmailValidator
33 from mailman.interfaces.domain import (
34 BadDomainSpecificationError, IDomainManager)
35 from mailman.interfaces.listmanager import IListManager
36 from mailman.interfaces.member import MemberRole
37 from mailman.interfaces.styles import IStyleManager
38 from mailman.interfaces.usermanager import IUserManager
39 from mailman.utilities.modules import call_name
40 from zope.component import getUtility
43 log = logging.getLogger('mailman.error')
47 def create_list(fqdn_listname, owners=None, style_name=None):
48 """Create the named list and apply styles.
50 The mailing may not exist yet, but the domain specified in `fqdn_listname`
51 must exist.
53 :param fqdn_listname: The fully qualified name for the new mailing list.
54 :type fqdn_listname: string
55 :param owners: The mailing list owners.
56 :type owners: list of string email addresses
57 :param style_name: The name of the style to apply to the newly created
58 list. If not given, the default is taken from the configuration file.
59 :type style_name: string
60 :return: The new mailing list.
61 :rtype: `IMailingList`
62 :raises BadDomainSpecificationError: when the hostname part of
63 `fqdn_listname` does not exist.
64 :raises ListAlreadyExistsError: when the mailing list already exists.
65 :raises InvalidEmailAddressError: when the fqdn email address is invalid.
66 """
67 if owners is None:
68 owners = []
69 # This raises InvalidEmailAddressError if the address is not a valid
70 # posting address. Let these percolate up.
71 getUtility(IEmailValidator).validate(fqdn_listname)
72 listname, domain = fqdn_listname.split('@', 1)
73 if domain not in getUtility(IDomainManager):
74 raise BadDomainSpecificationError(domain)
75 mlist = getUtility(IListManager).create(fqdn_listname)
76 style = getUtility(IStyleManager).get(
77 config.styles.default if style_name is None else style_name)
78 if style is not None:
79 style.apply(mlist)
80 # Coordinate with the MTA, as defined in the configuration file.
81 call_name(config.mta.incoming).create(mlist)
82 # Create any owners that don't yet exist, and subscribe all addresses as
83 # owners of the mailing list.
84 user_manager = getUtility(IUserManager)
85 for owner_address in owners:
86 address = user_manager.get_address(owner_address)
87 if address is None:
88 user = user_manager.create_user(owner_address)
89 address = list(user.addresses)[0]
90 mlist.subscribe(address, MemberRole.owner)
91 return mlist
95 def remove_list(mlist):
96 """Remove the list and all associated artifacts and subscriptions."""
97 fqdn_listname = mlist.fqdn_listname
98 # Delete the mailing list from the database.
99 getUtility(IListManager).delete(mlist)
100 # Do the MTA-specific list deletion tasks
101 call_name(config.mta.incoming).delete(mlist)
102 # Remove the list directory, if it exists.
103 try:
104 shutil.rmtree(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
105 except OSError as error:
106 if error.errno != errno.ENOENT:
107 raise