diff options
| author | Abhilash Raj | 2015-03-21 00:32:10 +0530 |
|---|---|---|
| committer | Abhilash Raj | 2015-03-21 00:32:10 +0530 |
| commit | ae2a7c9a22f5b6eeed1a6884c6dcd87ed9ba673d (patch) | |
| tree | 270cef8ecb93fba8eaee33381f1415c54fd7af60 /src | |
| parent | 6280c5ffcd2fdebf80f170f7c9a4e47adf0c6c4a (diff) | |
| download | mailman-ae2a7c9a22f5b6eeed1a6884c6dcd87ed9ba673d.tar.gz mailman-ae2a7c9a22f5b6eeed1a6884c6dcd87ed9ba673d.tar.zst mailman-ae2a7c9a22f5b6eeed1a6884c6dcd87ed9ba673d.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/app/registrar.py | 2 | ||||
| -rw-r--r-- | src/mailman/database/alembic/versions/46e92facee7_add_serverowner_domainowner.py | 45 | ||||
| -rw-r--r-- | src/mailman/model/domain.py | 39 | ||||
| -rw-r--r-- | src/mailman/model/user.py | 11 | ||||
| -rw-r--r-- | src/mailman/rest/domains.py | 21 | ||||
| -rw-r--r-- | src/mailman/rest/users.py | 36 |
6 files changed, 128 insertions, 26 deletions
diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py index 252a7eb9b..f601b645a 100644 --- a/src/mailman/app/registrar.py +++ b/src/mailman/app/registrar.py @@ -161,8 +161,6 @@ def handle_ConfirmationNeededEvent(event): # For i18n interpolation. confirm_url = mlist.domain.confirm_url(event.token) email_address = event.pendable['email'] - domain_name = mlist.domain.mail_host - contact_address = mlist.domain.contact_address # Send a verification email to the address. template = getUtility(ITemplateLoader).get( 'mailman:///{0}/{1}/confirm.txt'.format( diff --git a/src/mailman/database/alembic/versions/46e92facee7_add_serverowner_domainowner.py b/src/mailman/database/alembic/versions/46e92facee7_add_serverowner_domainowner.py new file mode 100644 index 000000000..bf42e2232 --- /dev/null +++ b/src/mailman/database/alembic/versions/46e92facee7_add_serverowner_domainowner.py @@ -0,0 +1,45 @@ +"""add_serverowner_domainowner + +Revision ID: 46e92facee7 +Revises: 33e1f5f6fa8 +Create Date: 2015-03-20 16:01:25.007242 + +""" + +# revision identifiers, used by Alembic. +revision = '46e92facee7' +down_revision = '33e1f5f6fa8' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_table('owner', + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('domain_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['domain_id'], ['domain.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('user_id', 'domain_id') + ) + op.add_column('user', sa.Column('is_serverowner', sa.Boolean(), + nullable=True)) + if op.get_bind().dialect.name != 'sqlite': + op.drop_column('domain', 'contact_address') + # The migration below may be because the first migration was created + # before we changed this attribute to a primary_key + op.create_foreign_key('_preferred_address', 'user', 'address', + ['_preferred_address_id'], ['id']) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_column('user', 'is_serverowner') + if op.get_bind().dialect.name != 'sqlite': + op.add_column('domain', sa.Column('contact_address', sa.VARCHAR(), + nullable=True)) + op.drop_constraint('_preferred_address', 'user', type_='foreignkey') + op.drop_table('owner') + ### end Alembic commands ### diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py index 9e627c119..b6705a619 100644 --- a/src/mailman/model/domain.py +++ b/src/mailman/model/domain.py @@ -29,8 +29,10 @@ from mailman.interfaces.domain import ( BadDomainSpecificationError, DomainCreatedEvent, DomainCreatingEvent, DomainDeletedEvent, DomainDeletingEvent, IDomain, IDomainManager) from mailman.model.mailinglist import MailingList +from mailman.model.user import User from urllib.parse import urljoin, urlparse from sqlalchemy import Column, Integer, Unicode +from sqlalchemy.orm import relationship, backref from zope.event import notify from zope.interface import implementer @@ -47,12 +49,14 @@ class Domain(Model): mail_host = Column(Unicode) # TODO: add index? base_url = Column(Unicode) description = Column(Unicode) - contact_address = Column(Unicode) + owners = relationship("User", + secondary="owner", + backref="domains") def __init__(self, mail_host, description=None, base_url=None, - contact_address=None): + owner=None): """Create and register a domain. :param mail_host: The host name for the email interface. @@ -63,18 +67,16 @@ class Domain(Model): scheme. If not given, it will be constructed from the `mail_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@`mail_host` will be used. - :type contact_address: string + :param owner: The `User` who is the owner of this domain + :type owner: mailman.models.user.User """ self.mail_host = mail_host self.base_url = (base_url if base_url is not None else 'http://' + mail_host) self.description = description - self.contact_address = (contact_address - if contact_address is not None - else 'postmaster@' + mail_host) + if owner is not None: + self.owners.append(owner) @property def url_host(self): @@ -103,14 +105,14 @@ class Domain(Model): def __repr__(self): """repr(a_domain)""" if self.description is None: - return ('<Domain {0.mail_host}, base_url: {0.base_url}, ' - 'contact_address: {0.contact_address}>').format(self) + return ('<Domain {0.mail_host}, base_url: {0.base_url}').format(self) else: return ('<Domain {0.mail_host}, {0.description}, ' - 'base_url: {0.base_url}, ' - 'contact_address: {0.contact_address}>').format(self) - + 'base_url: {0.base_url}, ').format(self) + def add_owner(self, owner): + """ Add an owner to a domain""" + self.owners.append(owner) @implementer(IDomainManager) class DomainManager: @@ -121,15 +123,22 @@ class DomainManager: mail_host, description=None, base_url=None, - contact_address=None): + owner_id=None): """See `IDomainManager`.""" # Be sure the mail_host is not already registered. This is probably # a constraint that should (also) be maintained in the database. if self.get(mail_host) is not None: raise BadDomainSpecificationError( 'Duplicate email host: %s' % mail_host) + # Be sure that the owner exists + owner = None + if owner_id is not None: + owner = store.query(User).filter(id==owner_id).first() + if owner is None: + raise BadDomainSpecificationError( + 'Owner does not exist') notify(DomainCreatingEvent(mail_host)) - domain = Domain(mail_host, description, base_url, contact_address) + domain = Domain(mail_host, description, base_url, owner) store.add(domain) notify(DomainCreatedEvent(domain)) return domain diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py index b74ea6d06..5ebe69a37 100644 --- a/src/mailman/model/user.py +++ b/src/mailman/model/user.py @@ -34,7 +34,7 @@ from mailman.model.preferences import Preferences from mailman.model.roster import Memberships from mailman.utilities.datetime import factory as date_factory from mailman.utilities.uid import UniqueIDFactory -from sqlalchemy import Column, DateTime, ForeignKey, Integer, Unicode +from sqlalchemy import Column, DateTime, ForeignKey, Integer, Unicode, Boolean from sqlalchemy.orm import relationship, backref from zope.event import notify from zope.interface import implementer @@ -55,6 +55,7 @@ class User(Model): _password = Column('password', Unicode) _user_id = Column(UUID, index=True) _created_on = Column(DateTime) + is_serverowner = Column(Boolean, default=False) addresses = relationship( 'Address', backref='user', @@ -174,3 +175,11 @@ class User(Model): @property def memberships(self): return Memberships(self) + + +class Owner(Model): + """Doomain to owners(user) association class""" + + __tablename__ = 'owner' + user_id = Column(Integer, ForeignKey('user.id'), primary_key=True) + domain_id = Column(Integer, ForeignKey('domain.id'), primary_key=True) diff --git a/src/mailman/rest/domains.py b/src/mailman/rest/domains.py index 345e8327d..d312737df 100644 --- a/src/mailman/rest/domains.py +++ b/src/mailman/rest/domains.py @@ -29,6 +29,7 @@ from mailman.rest.helpers import ( BadRequest, CollectionMixin, NotFound, bad_request, child, created, etag, no_content, not_found, okay, path_to) from mailman.rest.lists import ListsForDomain +from mailman.rest.users import OwnersForDomain from mailman.rest.validator import Validator from zope.component import getUtility @@ -41,7 +42,6 @@ class _DomainBase(CollectionMixin): """See `CollectionMixin`.""" return dict( base_url=domain.base_url, - contact_address=domain.contact_address, description=domain.description, mail_host=domain.mail_host, self_link=path_to('domains/{0}'.format(domain.mail_host)), @@ -88,6 +88,17 @@ class ADomain(_DomainBase): else: return BadRequest(), [] + @child() + def owners(self, request, segments): + """/domains/<domain>/owners""" + if len(segments) == 0: + domain = getUtility(IDomainManager).get(self._domain) + if domain is None: + return NotFound() + return OwnersForDomain(domain) + else: + return BadRequest(), [] + class AllDomains(_DomainBase): """The domains.""" @@ -99,12 +110,12 @@ class AllDomains(_DomainBase): validator = Validator(mail_host=str, description=str, base_url=str, - contact_address=str, + owner_id=int, _optional=('description', 'base_url', - 'contact_address')) + 'owner_id')) domain = domain_manager.add(**validator(request)) - except BadDomainSpecificationError: - bad_request(response, b'Domain exists') + except BadDomainSpecificationError as error: + bad_request(response, str(error)) except ValueError as error: bad_request(response, str(error)) else: diff --git a/src/mailman/rest/users.py b/src/mailman/rest/users.py index 018c8441d..b1aca9678 100644 --- a/src/mailman/rest/users.py +++ b/src/mailman/rest/users.py @@ -67,8 +67,9 @@ CREATION_FIELDS = dict( email=str, display_name=str, password=str, - _optional=('display_name', 'password'), - ) + is_serverowner=bool, + _optional=('display_name', 'password', 'is_serverowner'), +) @@ -108,7 +109,8 @@ class _UserBase(CollectionMixin): user_id=user_id, created_on=user.created_on, self_link=path_to('users/{}'.format(user_id)), - ) + is_serverowner=user.is_serverowner, + ) # Add the password attribute, only if the user has a password. Same # with the real name. These could be None or the empty string. if user.password: @@ -377,3 +379,31 @@ class Login: no_content(response) else: forbidden(response) + +class OwnersForDomain(_UserBase): + """Owners for a particular domain.""" + + def __init__(self, domain): + self._domain = domain + + def on_get(self, request, response): + """/domains/<domain>/owners""" + resource = self._make_collection(request) + okay(response, etag(resource)) + + def on_post(self, request, response): + """POST to /domains/<domain>/owners """ + validator = Validator(owner_id=GetterSetter(int)) + try: + values = validator(request) + except ValueError as error: + bad_request(response, str(error)) + return + owner = getUtility(IUserManager).get_user_by_id(values['owner_id']) + self._domain.add_owner(owner) + return no_content(response) + + @paginate + def _get_collection(self, request): + """See `CollectionMixin`.""" + return list(self._domain.owners) |
