1 # Copyright (C) 2008-2019 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)
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
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/>.
20 from mailman
.database
.model
import Model
21 from mailman
.database
.transaction
import dbconnection
22 from mailman
.database
.types
import SAUnicode
23 from mailman
.interfaces
.domain
import (
24 BadDomainSpecificationError
, DomainCreatedEvent
, DomainCreatingEvent
,
25 DomainDeletedEvent
, DomainDeletingEvent
, IDomain
, IDomainManager
)
26 from mailman
.interfaces
.user
import IUser
27 from mailman
.interfaces
.usermanager
import IUserManager
28 from mailman
.model
.mailinglist
import MailingList
29 from public
import public
30 from sqlalchemy
import Column
, Integer
31 from sqlalchemy
.orm
import relationship
32 from zope
.component
import getUtility
33 from zope
.event
import notify
34 from zope
.interface
import implementer
42 __tablename__
= 'domain'
44 id = Column(Integer
, primary_key
=True)
46 mail_host
= Column(SAUnicode
)
47 description
= Column(SAUnicode
)
48 owners
= relationship('User',
49 secondary
='domain_owner',
51 alias_domain
= Column(SAUnicode
)
53 def __init__(self
, mail_host
,
57 """Create and register a domain.
59 :param mail_host: The host name for the email interface.
60 :type mail_host: string
61 :param description: An optional description of the domain.
62 :type description: string
63 :param owners: Optional owners of this domain.
64 :type owners: sequence of `IUser` or string emails.
65 :param alias_domain: Alternate domain for Postfix
66 :type alias_domain: string
68 self
.mail_host
= mail_host
69 self
.description
= description
70 if owners
is not None:
71 self
.add_owners(owners
)
72 self
.alias_domain
= alias_domain
76 def mailing_lists(self
, store
):
78 yield from store
.query(MailingList
).filter(
79 MailingList
.mail_host
== self
.mail_host
80 ).order_by(MailingList
._list
_id
)
84 if self
.description
is None and self
.alias_domain
is None:
85 return ('<Domain {0.mail_host}>').format(self
)
86 elif self
.alias_domain
is None:
87 return ('<Domain {0.mail_host}, {0.description}>').format(self
)
88 elif self
.description
is None:
89 return ('<Domain {0.mail_host}, '
90 'alias: {0.alias_domain}>').format(self
)
92 return ('<Domain {0.mail_host}, '
94 'alias: {0.alias_domain}>').format(self
)
96 def add_owner(self
, owner
):
98 user_manager
= getUtility(IUserManager
)
99 if IUser
.providedBy(owner
):
102 user
= user_manager
.get_user(owner
)
103 # BAW 2015-04-06: Make sure this path is tested.
105 user
= user_manager
.create_user(owner
)
106 self
.owners
.append(user
)
108 def add_owners(self
, owners
):
110 # BAW 2015-04-06: This should probably be more efficient by inlining
113 self
.add_owner(owner
)
115 def remove_owner(self
, owner
):
117 user_manager
= getUtility(IUserManager
)
118 self
.owners
.remove(user_manager
.get_user(owner
))
122 @implementer(IDomainManager
)
124 """Domain manager."""
132 """See `IDomainManager`."""
133 # Be sure the mail_host is not already registered. This is probably
134 # a constraint that should (also) be maintained in the database.
135 if self
.get(mail_host
) is not None:
136 raise BadDomainSpecificationError(
137 'Duplicate email host: {}'.format(mail_host
))
138 notify(DomainCreatingEvent(mail_host
))
139 domain
= Domain(mail_host
, description
, owners
, alias_domain
)
141 notify(DomainCreatedEvent(domain
))
145 def remove(self
, store
, mail_host
):
146 domain
= self
[mail_host
]
147 notify(DomainDeletingEvent(domain
))
149 notify(DomainDeletedEvent(mail_host
))
153 def get(self
, store
, mail_host
, default
=None):
154 """See `IDomainManager`."""
155 domains
= store
.query(Domain
).filter_by(mail_host
=mail_host
)
156 if domains
.count() < 1:
158 assert domains
.count() == 1, (
159 'Too many matching domains: %s' % mail_host
)
162 def __getitem__(self
, mail_host
):
163 """See `IDomainManager`."""
165 domain
= self
.get(mail_host
, missing
)
166 if domain
is missing
:
167 raise KeyError(mail_host
)
171 def __len__(self
, store
):
172 return store
.query(Domain
).count()
175 def __iter__(self
, store
):
176 """See `IDomainManager`."""
177 yield from store
.query(Domain
).order_by(Domain
.mail_host
).all()
180 def __contains__(self
, store
, mail_host
):
181 """See `IDomainManager`."""
182 return store
.query(Domain
).filter_by(mail_host
=mail_host
).count() > 0