OMGW00T: After over a decade, the MailList mixin class is gone! Well,
[mailman.git] / Mailman / database / model / mailinglist.py
blob7fa9aca381fa4a67ee16a8608b4bec4e56ba8ea0
1 # Copyright (C) 2006-2007 by the Free Software Foundation, Inc.
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
16 # USA.
18 import os
19 import string
21 from elixir import *
22 from zope.interface import implements
24 from Mailman.Utils import fqdn_listname, makedirs, split_listname
25 from Mailman.configuration import config
26 from Mailman.interfaces import *
27 from Mailman.database.types import EnumType, TimeDeltaType
29 SPACE = ' '
30 UNDERSCORE = '_'
34 class MailingList(Entity):
35 implements(
36 IMailingList,
37 IMailingListAddresses,
38 IMailingListIdentity,
39 IMailingListRosters,
40 IMailingListWeb,
43 # List identity
44 has_field('list_name', Unicode),
45 has_field('host_name', Unicode),
46 # Attributes not directly modifiable via the web u/i
47 has_field('created_at', DateTime),
48 has_field('web_page_url', Unicode),
49 has_field('admin_member_chunksize', Integer),
50 has_field('hold_and_cmd_autoresponses', PickleType),
51 # Attributes which are directly modifiable via the web u/i. The more
52 # complicated attributes are currently stored as pickles, though that
53 # will change as the schema and implementation is developed.
54 has_field('next_request_id', Integer),
55 has_field('next_digest_number', Integer),
56 has_field('admin_responses', PickleType),
57 has_field('postings_responses', PickleType),
58 has_field('request_responses', PickleType),
59 has_field('digest_last_sent_at', Float),
60 has_field('one_last_digest', PickleType),
61 has_field('volume', Integer),
62 has_field('last_post_time', DateTime),
63 # Attributes which are directly modifiable via the web u/i. The more
64 # complicated attributes are currently stored as pickles, though that
65 # will change as the schema and implementation is developed.
66 has_field('accept_these_nonmembers', PickleType),
67 has_field('acceptable_aliases', PickleType),
68 has_field('admin_immed_notify', Boolean),
69 has_field('admin_notify_mchanges', Boolean),
70 has_field('administrivia', Boolean),
71 has_field('advertised', Boolean),
72 has_field('anonymous_list', Boolean),
73 has_field('archive', Boolean),
74 has_field('archive_private', Boolean),
75 has_field('archive_volume_frequency', Integer),
76 has_field('autorespond_admin', Boolean),
77 has_field('autorespond_postings', Boolean),
78 has_field('autorespond_requests', Integer),
79 has_field('autoresponse_admin_text', Unicode),
80 has_field('autoresponse_graceperiod', TimeDeltaType),
81 has_field('autoresponse_postings_text', Unicode),
82 has_field('autoresponse_request_text', Unicode),
83 has_field('ban_list', PickleType),
84 has_field('bounce_info_stale_after', TimeDeltaType),
85 has_field('bounce_matching_headers', Unicode),
86 has_field('bounce_notify_owner_on_disable', Boolean),
87 has_field('bounce_notify_owner_on_removal', Boolean),
88 has_field('bounce_processing', Boolean),
89 has_field('bounce_score_threshold', Integer),
90 has_field('bounce_unrecognized_goes_to_list_owner', Boolean),
91 has_field('bounce_you_are_disabled_warnings', Integer),
92 has_field('bounce_you_are_disabled_warnings_interval', TimeDeltaType),
93 has_field('collapse_alternatives', Boolean),
94 has_field('convert_html_to_plaintext', Boolean),
95 has_field('default_member_moderation', Boolean),
96 has_field('description', Unicode),
97 has_field('digest_footer', Unicode),
98 has_field('digest_header', Unicode),
99 has_field('digest_is_default', Boolean),
100 has_field('digest_send_periodic', Boolean),
101 has_field('digest_size_threshold', Integer),
102 has_field('digest_volume_frequency', Integer),
103 has_field('digestable', Boolean),
104 has_field('discard_these_nonmembers', PickleType),
105 has_field('emergency', Boolean),
106 has_field('encode_ascii_prefixes', Boolean),
107 has_field('filter_action', Integer),
108 has_field('filter_content', Boolean),
109 has_field('filter_filename_extensions', PickleType),
110 has_field('filter_mime_types', PickleType),
111 has_field('first_strip_reply_to', Boolean),
112 has_field('forward_auto_discards', Boolean),
113 has_field('gateway_to_mail', Boolean),
114 has_field('gateway_to_news', Boolean),
115 has_field('generic_nonmember_action', Integer),
116 has_field('goodbye_msg', Unicode),
117 has_field('header_filter_rules', PickleType),
118 has_field('hold_these_nonmembers', PickleType),
119 has_field('include_list_post_header', Boolean),
120 has_field('include_rfc2369_headers', Boolean),
121 has_field('info', Unicode),
122 has_field('linked_newsgroup', Unicode),
123 has_field('max_days_to_hold', Integer),
124 has_field('max_message_size', Integer),
125 has_field('max_num_recipients', Integer),
126 has_field('member_moderation_action', Boolean),
127 has_field('member_moderation_notice', Unicode),
128 has_field('mime_is_default_digest', Boolean),
129 has_field('mod_password', Unicode),
130 has_field('msg_footer', Unicode),
131 has_field('msg_header', Unicode),
132 has_field('new_member_options', Integer),
133 has_field('news_moderation', Boolean),
134 has_field('news_prefix_subject_too', Boolean),
135 has_field('nntp_host', Unicode),
136 has_field('nondigestable', Boolean),
137 has_field('nonmember_rejection_notice', Unicode),
138 has_field('obscure_addresses', Boolean),
139 has_field('pass_filename_extensions', PickleType),
140 has_field('pass_mime_types', PickleType),
141 has_field('password', Unicode),
142 has_field('personalize', Integer),
143 has_field('post_id', Integer),
144 has_field('preferred_language', Unicode),
145 has_field('private_roster', Boolean),
146 has_field('real_name', Unicode),
147 has_field('reject_these_nonmembers', PickleType),
148 has_field('reply_goes_to_list', EnumType),
149 has_field('reply_to_address', Unicode),
150 has_field('require_explicit_destination', Boolean),
151 has_field('respond_to_post_requests', Boolean),
152 has_field('scrub_nondigest', Boolean),
153 has_field('send_goodbye_msg', Boolean),
154 has_field('send_reminders', Boolean),
155 has_field('send_welcome_msg', Boolean),
156 has_field('subject_prefix', Unicode),
157 has_field('subscribe_auto_approval', PickleType),
158 has_field('subscribe_policy', Integer),
159 has_field('topics', PickleType),
160 has_field('topics_bodylines_limit', Integer),
161 has_field('topics_enabled', Boolean),
162 has_field('unsubscribe_policy', Integer),
163 has_field('welcome_msg', Unicode),
164 # Relationships
165 ## has_and_belongs_to_many(
166 ## 'available_languages',
167 ## of_kind='Mailman.database.model.languages.Language')
168 # Options
169 using_options(shortnames=True)
171 def __init__(self, fqdn_listname):
172 super(MailingList, self).__init__()
173 listname, hostname = split_listname(fqdn_listname)
174 self.list_name = listname
175 self.host_name = hostname
176 # For the pending database
177 self.next_request_id = 1
178 self._restore()
179 # Max autoresponses per day. A mapping between addresses and a
180 # 2-tuple of the date of the last autoresponse and the number of
181 # autoresponses sent on that date.
182 self.hold_and_cmd_autoresponses = {}
183 self.full_path = os.path.join(config.LIST_DATA_DIR, fqdn_listname)
184 self.real_name = string.capwords(SPACE.join(listname.split(UNDERSCORE)))
185 makedirs(self.full_path)
187 # XXX FIXME
188 def _restore(self):
189 # Avoid circular imports.
190 from Mailman.database.model import roster
191 self.owners = roster.OwnerRoster(self)
192 self.moderators = roster.ModeratorRoster(self)
193 self.administrators = roster.AdministratorRoster(self)
194 self.members = roster.MemberRoster(self)
195 self.regular_members = roster.RegularMemberRoster(self)
196 self.digest_members = roster.DigestMemberRoster(self)
197 self.subscribers = roster.Subscribers(self)
199 @property
200 def fqdn_listname(self):
201 """See IMailingListIdentity."""
202 return fqdn_listname(self.list_name, self.host_name)
204 @property
205 def web_host(self):
206 """See IMailingListWeb."""
207 return config.domains[self.host_name]
209 def script_url(self, target, context=None):
210 """See IMailingListWeb."""
211 # XXX Handle the case for when context is not None; those would be
212 # relative URLs.
213 return self.web_page_url + target + '/' + self.fqdn_listname
215 # IMailingListAddresses
217 @property
218 def posting_address(self):
219 return self.fqdn_listname
221 @property
222 def noreply_address(self):
223 return '%s@%s' % (config.NO_REPLY_ADDRESS, self.host_name)
225 @property
226 def owner_address(self):
227 return '%s-owner@%s' % (self.list_name, self.host_name)
229 @property
230 def request_address(self):
231 return '%s-request@%s' % (self.list_name, self.host_name)
233 @property
234 def bounces_address(self):
235 return '%s-bounces@%s' % (self.list_name, self.host_name)
237 @property
238 def join_address(self):
239 return '%s-join@%s' % (self.list_name, self.host_name)
241 @property
242 def leave_address(self):
243 return '%s-leave@%s' % (self.list_name, self.host_name)
245 @property
246 def subscribe_address(self):
247 return '%s-subscribe@%s' % (self.list_name, self.host_name)
249 @property
250 def unsubscribe_address(self):
251 return '%s-unsubscribe@%s' % (self.list_name, self.host_name)
253 def confirm_address(self, cookie):
254 template = string.Template(config.VERP_CONFIRM_FORMAT)
255 local_part = template.safe_substitute(
256 address = '%s-confirm' % self.list_name,
257 cookie = cookie)
258 return '%s@%s' % (local_part, self.host_name)
260 def __repr__(self):
261 return '<mailing list "%s" at %#x>' % (self.fqdn_listname, id(self))