# Copyright (C) 2009-2017 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 . """Handle subscriptions.""" from mailman.database.transaction import flush from mailman.email.message import UserNotification from mailman.interfaces.listmanager import ListDeletingEvent from mailman.interfaces.pending import IPendings from mailman.interfaces.subscriptions import ( ISubscriptionManager, ISubscriptionService, SubscriptionConfirmationNeededEvent, UnsubscriptionConfirmationNeededEvent) from mailman.interfaces.template import ITemplateLoader from mailman.interfaces.workflows import IWorkflowStateManager from mailman.utilities.string import expand from mailman.workflows.builtin import (PendableSubscription, PendableUnsubscription, SubscriptionWorkflow, UnSubscriptionWorkflow) from public import public from zope.component import getUtility from zope.interface import implementer @public @implementer(ISubscriptionManager) class SubscriptionManager: def __init__(self, mlist): self._mlist = mlist def register(self, subscriber=None, *, pre_verified=False, pre_confirmed=False, pre_approved=False): """See `ISubscriptionManager`.""" workflow = SubscriptionWorkflow( self._mlist, subscriber, pre_verified=pre_verified, pre_confirmed=pre_confirmed, pre_approved=pre_approved) list(workflow) return workflow.token, workflow.token_owner, workflow.member def unregister(self, subscriber=None, *, pre_confirmed=False, pre_approved=False): workflow = UnSubscriptionWorkflow( self._mlist, subscriber, pre_confirmed=pre_confirmed, pre_approved=pre_approved) list(workflow) return workflow.token, workflow.token_owner, workflow.member def confirm(self, token): if token is None: raise LookupError pendable = getUtility(IPendings).confirm(token, expunge=False) if pendable is None: raise LookupError workflow_type = pendable.get('type') assert workflow_type in (PendableSubscription.PEND_TYPE, PendableUnsubscription.PEND_TYPE) workflow = (SubscriptionWorkflow if workflow_type == PendableSubscription.PEND_TYPE else UnSubscriptionWorkflow)(self._mlist) workflow.token = token workflow.restore() # In order to just run the whole workflow, all we need to do # is iterate over the workflow object. On calling the __next__ # over the workflow iterator it automatically executes the steps # that needs to be done. list(workflow) return workflow.token, workflow.token_owner, workflow.member def discard(self, token): with flush(): getUtility(IPendings).confirm(token) getUtility(IWorkflowStateManager).discard(token) def _handle_confirmation_needed_events(event, template_name): subject = 'confirm {}'.format(event.token) confirm_address = event.mlist.confirm_address(event.token) email_address = event.email # Send a verification email to the address. template = getUtility(ITemplateLoader).get(template_name, event.mlist) text = expand(template, event.mlist, dict( token=event.token, subject=subject, confirm_email=confirm_address, user_email=email_address, # For backward compatibility. confirm_address=confirm_address, email_address=email_address, domain_name=event.mlist.domain.mail_host, contact_address=event.mlist.owner_address, )) msg = UserNotification(email_address, confirm_address, subject, text) msg.send(event.mlist, add_precedence=False) @public def handle_SubscriptionConfirmationNeededEvent(event): if not isinstance(event, SubscriptionConfirmationNeededEvent): return _handle_confirmation_needed_events(event, 'list:user:action:subscribe') @public def handle_UnsubscriptionConfirmationNeededEvent(event): if not isinstance(event, UnsubscriptionConfirmationNeededEvent): return _handle_confirmation_needed_events(event, 'list:user:action:unsubscribe') @public def handle_ListDeletingEvent(event): """Delete a mailing list's members when the list is being deleted.""" if not isinstance(event, ListDeletingEvent): return # Find all the members still associated with the mailing list. members = getUtility(ISubscriptionService).find_members( list_id=event.mailing_list.list_id) for member in members: member.unsubscribe()