summaryrefslogtreecommitdiff
path: root/src/mailman/database
diff options
context:
space:
mode:
authorBarry Warsaw2009-07-16 22:36:06 -0400
committerBarry Warsaw2009-07-16 22:36:06 -0400
commit1bfc7f302f2730a679b2a4a103c2978d8e7c70ae (patch)
tree3d69d43841dcf838e9778d2e83cc3e58a7b9ed20 /src/mailman/database
parentac3af23142c9b2417759f90837d68e15866b6793 (diff)
downloadmailman-1bfc7f302f2730a679b2a4a103c2978d8e7c70ae.tar.gz
mailman-1bfc7f302f2730a679b2a4a103c2978d8e7c70ae.tar.zst
mailman-1bfc7f302f2730a679b2a4a103c2978d8e7c70ae.zip
Wow. Put domains into the database.
Add an IDomainManager and a global domain manager which can be gotten by adapting the global config object. Add an IDomainCollection interface for exposing the domain manager onto the API.
Diffstat (limited to 'src/mailman/database')
-rw-r--r--src/mailman/database/domain.py163
-rw-r--r--src/mailman/database/mailinglist.py5
-rw-r--r--src/mailman/database/mailman.sql20
-rw-r--r--src/mailman/database/member.py4
4 files changed, 183 insertions, 9 deletions
diff --git a/src/mailman/database/domain.py b/src/mailman/database/domain.py
new file mode 100644
index 000000000..a729cb8e2
--- /dev/null
+++ b/src/mailman/database/domain.py
@@ -0,0 +1,163 @@
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Domains."""
+
+from __future__ import unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'Domain',
+ 'DomainManager',
+ ]
+
+from urlparse import urljoin, urlparse
+from storm.locals import Int, Unicode
+from zope.interface import implements
+
+from mailman.core.errors import BadDomainSpecificationError
+from mailman.database.model import Model
+from mailman.interfaces.domain import IDomain, IDomainManager
+
+
+
+class Domain(Model):
+ """Domains."""
+
+ implements(IDomain)
+
+ id = Int(primary=True)
+
+ email_host = Unicode()
+ base_url = Unicode()
+ description = Unicode()
+ contact_address = Unicode()
+
+ def __init__(self, email_host,
+ description=None,
+ base_url=None,
+ contact_address=None):
+ """Create and register a domain.
+
+ :param email_host: The host name for the email interface.
+ :type email_host: string
+ :param description: An optional description of the domain.
+ :type description: string
+ :param base_url: The optional base url for the domain, including
+ scheme. If not given, it will be constructed from the
+ `email_host` using the http protocol.
+ :type base_url: string
+ :param contact_address: The email address to contact a human for this
+ domain. If not given, postmaster@`email_host` will be used.
+ :type contact_address: string
+ """
+ self.email_host = email_host
+ self.base_url = (base_url
+ if base_url is not None
+ else 'http://' + email_host)
+ self.description = description
+ self.contact_address = (contact_address
+ if contact_address is not None
+ else 'postmaster@' + email_host)
+
+ @property
+ def url_host(self):
+ # pylint: disable-msg=E1101
+ # no netloc member; yes it does
+ return urlparse(self.base_url).netloc
+
+ def confirm_address(self, token=''):
+ """See `IDomain`."""
+ return 'confirm-{0}@{1}'.format(token, self.email_host)
+
+ def confirm_url(self, token=''):
+ """See `IDomain`."""
+ return urljoin(self.base_url, 'confirm/' + token)
+
+ def __repr__(self):
+ """repr(a_domain)"""
+ if self.description is None:
+ return ('<Domain {0.email_host}, base_url: {0.base_url}, '
+ 'contact_address: {0.contact_address}>').format(self)
+ else:
+ return ('<Domain {0.email_host}, {0.description}, '
+ 'base_url: {0.base_url}, '
+ 'contact_address: {0.contact_address}>').format(self)
+
+
+
+class DomainManager:
+ """Domain manager."""
+
+ implements(IDomainManager)
+
+ def __init__(self, config):
+ """Create a domain manager.
+
+ :param config: The configuration object.
+ :type config: `IConfiguration`
+ """
+ self.config = config
+ self.store = config.db.store
+
+ def add(self, email_host,
+ description=None,
+ base_url=None,
+ contact_address=None):
+ """See `IDomainManager`."""
+ # Be sure the email_host is not already registered. This is probably
+ # a constraint that should (also) be maintained in the database.
+ if self.get(email_host) is not None:
+ raise BadDomainSpecificationError(
+ 'Duplicate email host: %s' % email_host)
+ domain = Domain(email_host, description, base_url, contact_address)
+ self.store.add(domain)
+ return domain
+
+ def remove(self, email_host):
+ domain = self[email_host]
+ self.store.remove(domain)
+ return domain
+
+ def get(self, email_host, default=None):
+ """See `IDomainManager`."""
+ domains = self.store.find(Domain, email_host=email_host)
+ if domains.count() < 1:
+ return default
+ assert domains.count() == 1, (
+ 'Too many matching domains: %s' % email_host)
+ return domains.one()
+
+ def __getitem__(self, email_host):
+ """See `IDomainManager`."""
+ missing = object()
+ domain = self.get(email_host, missing)
+ if domain is missing:
+ raise KeyError(email_host)
+ return domain
+
+ def __len__(self):
+ return self.store.find(Domain).count()
+
+ def __iter__(self):
+ """See `IDomainManager`."""
+ for domain in self.store.find(Domain):
+ yield domain
+
+ def __contains__(self, email_host):
+ """See `IDomainManager`."""
+ return self.store.find(Domain, email_host=email_host).count() > 0
diff --git a/src/mailman/database/mailinglist.py b/src/mailman/database/mailinglist.py
index f08adfd8b..5384e9895 100644
--- a/src/mailman/database/mailinglist.py
+++ b/src/mailman/database/mailinglist.py
@@ -40,6 +40,7 @@ from mailman.database.digests import OneLastDigest
from mailman.database.mime import ContentFilter
from mailman.database.model import Model
from mailman.database.types import Enum
+from mailman.interfaces.domain import IDomainManager
from mailman.interfaces.mailinglist import (
IAcceptableAlias, IAcceptableAliasSet, IMailingList, Personalization)
from mailman.interfaces.mime import FilterType
@@ -210,12 +211,12 @@ class MailingList(Model):
@property
def web_host(self):
"""See `IMailingList`."""
- return config.domains[self.host_name]
+ return IDomainManager(config)[self.host_name]
def script_url(self, target, context=None):
"""See `IMailingList`."""
# Find the domain for this mailing list.
- domain = config.domains[self.host_name]
+ domain = IDomainManager(config)[self.host_name]
# XXX Handle the case for when context is not None; those would be
# relative URLs.
return urljoin(domain.base_url, target + '/' + self.fqdn_listname)
diff --git a/src/mailman/database/mailman.sql b/src/mailman/database/mailman.sql
index fa772416f..84a906fb1 100644
--- a/src/mailman/database/mailman.sql
+++ b/src/mailman/database/mailman.sql
@@ -67,11 +67,21 @@ CREATE TABLE contentfilter (
CREATE INDEX ix_contentfilter_mailing_list_id
ON contentfilter (mailing_list_id);
+CREATE TABLE domain (
+ id INTEGER NOT NULL,
+ email_host TEXT,
+ base_url TEXT,
+ description TEXT,
+ contact_address TEXT,
+ PRIMARY KEY (id)
+ );
+
CREATE TABLE language (
- id INTEGER NOT NULL,
- code TEXT,
- PRIMARY KEY (id)
-);
+ id INTEGER NOT NULL,
+ code TEXT,
+ PRIMARY KEY (id)
+ );
+
CREATE TABLE mailinglist (
id INTEGER NOT NULL,
-- List identity
@@ -80,7 +90,7 @@ CREATE TABLE mailinglist (
list_id TEXT,
include_list_post_header BOOLEAN,
include_rfc2369_headers BOOLEAN,
- -- Attributes not directly modifiable via the web u/i
+ -- Attributes not directly modifiable via the web u/i
created_at TIMESTAMP,
admin_member_chunksize INTEGER,
next_request_id INTEGER,
diff --git a/src/mailman/database/member.py b/src/mailman/database/member.py
index 22bf042f6..4a158a11e 100644
--- a/src/mailman/database/member.py
+++ b/src/mailman/database/member.py
@@ -28,7 +28,7 @@ from storm.locals import *
from zope.interface import implements
from mailman.config import config
-from mailman.constants import SystemDefaultPreferences
+from mailman.constants import system_preferences
from mailman.database.model import Model
from mailman.database.types import Enum
from mailman.interfaces.member import IMember
@@ -69,7 +69,7 @@ class Member(Model):
pref = getattr(self.address.user.preferences, preference)
if pref is not None:
return pref
- return getattr(SystemDefaultPreferences, preference)
+ return getattr(system_preferences, preference)
@property
def acknowledge_posts(self):