# Copyright (C) 2008-2011 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 . """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.config import config from mailman.database.model import Model from mailman.interfaces.domain import ( BadDomainSpecificationError, 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): """See `IDomain`.""" # pylint: disable-msg=E1101 # no netloc member; yes it does return urlparse(self.base_url).netloc @property def scheme(self): """See `IDomain`.""" return urlparse(self.base_url).scheme 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 ('').format(self) else: return ('').format(self) class DomainManager: """Domain manager.""" implements(IDomainManager) 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) config.db.store.add(domain) return domain def remove(self, email_host): domain = self[email_host] config.db.store.remove(domain) return domain def get(self, email_host, default=None): """See `IDomainManager`.""" domains = config.db.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 config.db.store.find(Domain).count() def __iter__(self): """See `IDomainManager`.""" for domain in config.db.store.find(Domain): yield domain def __contains__(self, email_host): """See `IDomainManager`.""" return config.db.store.find(Domain, email_host=email_host).count() > 0