Example #1
0
def add_or_remove_membership(mship, remove=False):

    mem_id = mship.getId()
    team = mship.aq_inner.aq_parent
    proj_id = team.getId()
    portal = getToolByName(mship, 'portal_url').getPortalObject()
    listencontainer = portal.projects[proj_id].lists

    mlists = []

    for mlist in listencontainer.objectValues(spec='OpenMailingList'):
        if ISyncWithProjectMembership.providedBy(mlist):
            mlists.append(mlist)
           
    if not mlists:
        # no autosync mailing lists; silently fail
        return

    for ml in mlists:
        memlist = IWriteMembershipList(ml)

        if remove:
            memlist.unsubscribe(mem_id)
        else:
            memlist.subscribe(mem_id)
    def migrate(self):
        if self.is_updated(): 
            return 'already migrated'
        
        # set the appropriate list type based on the previous settings
        # this may need to mark the appropriate interface on the mailing
        # list as well
        if self.context.moderated:
            self.context.list_type = PostModeratedListTypeDefinition
        elif self.context.closed:
            self.context.list_type = MembershipModeratedListTypeDefinition
        else:
            self.context.list_type = PublicListTypeDefinition

        # copy over the membership stuff
        annot = IAnnotations(self.context)
        listen_annot = annot.get('listen', {})
        old_subscribers = listen_annot.get('subscribers', [])

        # create the new annotations by using current adapters
        mem_list = IWriteMembershipList(self.context)
        for subscriber in old_subscribers:
            mem_list.subscribe(subscriber)

        # unsubscribe (but leave as allowed senders) those who don't 
        # receive mail
        nomail = listen_annot.get('norecvmail', [])
        for allowed_sender in nomail:
            mem_list.unsubscribe(allowed_sender)

        # copy over the moderation messages
        self.mod_post_pending_list = getAdapter(self.context, IPostPendingList, 'pending_pmod_post')
        for i in self.context.mqueue.objectIds():
            (header, body) = splitMail(self.context.mqueue[i])
            post = {'header':header, 'body':body}
            (user_name, user_email) = parseaddr(header.get('from', ''))
            self.mod_post_pending_list.add(user_email, user_name=user_name, post=post)

        # creates list managers from moderators and list owner
        managers = []
        managers.append(self.context.list_owner)
        for moderator in self.context.moderators:
            managers.append(moderator)
        self.context.managers = tuple(managers)
        convert_manager_emails_to_memberids(self.context)

        # translate archived vocabulary
        if self.context.archived == 'not archived':
            self.context.archived = 2
        elif self.context.archived == 'plain text':
            self.context.archived = 1
        elif self.context.archived == 'with attachments':
            self.context.archived = 0
        else:
            return 'error translating archive option'

        # annotate the list to say the migration completed
        self.migration_annot.append('policy_migration')

        return 'successfully migrated'
 def import_subscribers(self, subscribers):
     """ Imports the list of subscriber email addresses """
     slist = IWriteMembershipList(self.context)
     for subscriber, status in subscribers:
         if status == "subscribed":
             slist.subscribe(subscriber, send_notify=False)
         elif status == "allowed":
             slist.add_allowed_sender(subscriber, send_notify=False)
Example #4
0
def listen_featurelet_installed(proj, event):
    """need to create a default discussion mailing list
       and subscribe all project members to the list"""
    proj_id = proj.getId()
    proj_title = proj.Title().decode('utf-8')
    ml_id = '%s-discussion' % proj_id
    address = '%s%s' % (ml_id, getSuffix())

    # need to verify that a mailing list with this name isn't already created
    portal = getToolByName(proj, 'portal_url').getPortalObject()
    ll = getUtility(IListLookup, context=portal)
    if ll.getListForAddress(address) is not None:
        # XXX we'll just silently fail for now, not sure what else we can do
        # psm maybe?
        return

    # XXX we need a request utility
    request = proj.REQUEST
    # invokeFactory depends on the title being set in the request
    ml_title = u'%s discussion' % (proj_title)
    request.set('title', ml_title)
    lists_folder = proj.lists.aq_inner
    lists_folder.invokeFactory(OpenMailingList.portal_type, ml_id)
    ml = lists_folder[ml_id]
    ml.mailto = ml_id
    ms_tool = getToolByName(proj, 'portal_membership')
    cur_mem_id = unicode(ms_tool.getAuthenticatedMember().getId())
    ml.managers = (cur_mem_id,)
    ml.setDescription(translate(_(u'discussion_list_desc',
                                  u'Discussion list for this ${project_noun}, consisting of all ${project_noun} members.',
                                  mapping={'project_noun':project_noun()}),
                                            context=request))


    # http://www.openplans.org/projects/opencore/lists/opencore-dev/archive/2009/04/1239543233615/forum_view
    from zope.interface import alsoProvides
    alsoProvides(ml, ISyncWithProjectMembership)

    notify(ObjectCreatedEvent(ml))

    memlist = IWriteMembershipList(ml)

    cat = getToolByName(portal, 'portal_catalog')
    teams = getToolByName(portal, 'portal_teams')
    try:
        team = teams[proj_id]
    except KeyError:
        # if the team doesn't exist
        # then nobody is on the project yet
        # so we only need to subscribe the current user
        memlist.subscribe(cur_mem_id)
        return
    active_states = teams.getDefaultActiveStates()
    team_path = '/'.join(team.getPhysicalPath())
    mships = cat(portal_type='OpenMembership', review_state=active_states, path=team_path)
    for mship in mships:
        memlist.subscribe(mship.getId)
Example #5
0
    def handle_request(self, target=None, fields=None):
        # Get the tool used to normalize strings
        putils = getToolByName(self.context, 'plone_utils')

        result = self.validate_form(creation=True)
        if not result:
            return

        title, workflow, archive, mailto, managers = result
        private_archives = "private_list" in self.request.form
        sync_project_membership = "sync_project_membership" in self.request.form

        # Try to create a mailing list using the mailto address to see if it's going to be valid
        lists_folder = self.context
        try:
            lists_folder.invokeFactory(OpenMailingList.portal_type, mailto)
        except BadRequest:
            self.errors['mailto'] = _(u'list_create_duplicate_error', u'The requested list prefix is already taken.')
            self.add_status_message(_(u'psm_correct_errors_below', u'Please correct the errors indicated below.'))
            return

        list = lists_folder._getOb(mailto)

        list.managers = tuple(managers)
        self._assign_local_roles_to_managers(list)
        list.setDescription(unicode(self.request.form.get('description',''), 'utf-8'))

        old_workflow_type = list.list_type
        new_workflow_type = workflow_to_mlist_type(workflow)
            
        notify(ListTypeChanged(list,
                               old_workflow_type.list_marker,
                               new_workflow_type.list_marker))

        list.archived = archive
        list.private_archives = private_archives
        if sync_project_membership:
            alsoProvides(list, ISyncWithProjectMembership)

        self.template = None

        #subscribe user to list
        sub_list = IWriteMembershipList(list)
        current_user = unicode(self.loggedinmember.getId())        
        sub_list.subscribe(current_user)

        s_message_mapping = {'title': title}
        s_message = _(u'list_created',
                      u'"${title}" has been created.',
                      mapping=s_message_mapping)
        
        self.add_status_message(s_message)

        list.reindexObject()
        self.redirect(list.absolute_url())
 def __init__(self, context, request):
     super(ModerationView, self).__init__(context, request)
     self.mem_list = IWriteMembershipList(context)
     annot = IAnnotations(self.context)
     self.listen_annot = annot.setdefault(PROJECTNAME, OOBTree())
     self.mod_post_pending_list = getAdapter(context, IPostPendingList, 'pending_mod_post')
     self.pmod_post_pending_list = getAdapter(context, IPostPendingList, 'pending_pmod_post')
     self.sub_pending_list = getAdapter(context, IMembershipPendingList, 'pending_sub_mod_email')
    def __call__(self):
        sub_action = self.request.get('subscribe_member', None)
        unsub_action = self.request.get('unsubscribe_member', None)
        email_action = self.request.get('subscribe_email', None)
        self.request.set('enable_border', True)
        self.errors = errors = {}

        logged_in_mem = self._get_logged_in_user()
        self.user_logged_in = False
        if logged_in_mem:
            self.user_email = lookup_email(logged_in_mem.getId(), self.context)
            self.user_logged_in = True
        else:
            #XXX what should this be?
            self.user_email = ''

        self.mem_list = IWriteMembershipList(self.context)

        # the appropriate sub_policy needs to be instantiated
        # depending on list type
        self.sub_policy = getAdapter(self.context, IUserTTWMembershipPolicy)

        if sub_action:
            self.subscribe()
        elif unsub_action:
            self.unsubscribe()
        elif email_action:
            address = self.request.get('email_address', None)
            if not address:
                errors['email_address'] = _('An email address is required')
            elif EMAIL_RE.match(address) is None:
                errors['email_address'] = _('This email address is invalid')
            elif self.mem_list.is_subscribed(address):
                errors['email_address'] = \
                                 _('This email address is already subscribed')
            else:
                # everything is OK, send a request mail the
                # appropriate sub_policy needs to be instantiated
                # depending on list type
                sub_policy_for_email = getAdapter(self.context, IUserEmailMembershipPolicy)

                ret = sub_policy_for_email.enforce({'email':address,
                                                    'subject':'subscribe'})
                if ret == MEMBERSHIP_ALLOWED:
                    # make user a subscriber
                    self.mem_list.subscribe(address)
                    self.request.set('portal_status_message', 'Email subscribed')
                elif ret == MEMBERSHIP_DEFERRED:
                    self.request.set('portal_status_message',
                                     'Subscription request sent')
                else:
                    self.request.set('portal_status_message', 'Bad email address')
                    
                # Blank the email field to avoid the postback
                self.request.set('email_address', '')
                self.request.set('subscribe_email', '')

        return self.index()
Example #8
0
 def add_allowed_sender(self, email):
     IWriteMembershipList(self.context).add_allowed_sender(email)
Example #9
0
class MailingListView(BrowserView):
    """A basic view of a mailing list"""

    def __call__(self):
        sub_action = self.request.get('subscribe_member', None)
        unsub_action = self.request.get('unsubscribe_member', None)
        email_action = self.request.get('subscribe_email', None)
        self.request.set('enable_border', True)
        self.errors = errors = {}

        logged_in_mem = self._get_logged_in_user()
        self.user_logged_in = False
        if logged_in_mem:
            self.user_email = lookup_email(logged_in_mem.getId(), self.context)
            self.user_logged_in = True
        else:
            #XXX what should this be?
            self.user_email = ''

        self.mem_list = IWriteMembershipList(self.context)

        # the appropriate sub_policy needs to be instantiated
        # depending on list type
        self.sub_policy = getAdapter(self.context, IUserTTWMembershipPolicy)

        if sub_action:
            self.subscribe()
        elif unsub_action:
            self.unsubscribe()
        elif email_action:
            address = self.request.get('email_address', None)
            if not address:
                errors['email_address'] = _('An email address is required')
            elif EMAIL_RE.match(address) is None:
                errors['email_address'] = _('This email address is invalid')
            elif self.mem_list.is_subscribed(address):
                errors['email_address'] = \
                                 _('This email address is already subscribed')
            else:
                # everything is OK, send a request mail the
                # appropriate sub_policy needs to be instantiated
                # depending on list type
                sub_policy_for_email = getAdapter(self.context, IUserEmailMembershipPolicy)

                ret = sub_policy_for_email.enforce({'email':address,
                                                    'subject':'subscribe'})
                if ret == MEMBERSHIP_ALLOWED:
                    # make user a subscriber
                    self.mem_list.subscribe(address)
                    self.request.set('portal_status_message', _(u'list_email_subscribed_status_msg',
                                                                u'Email subscribed'))
                elif ret == MEMBERSHIP_DEFERRED:
                    self.request.set('portal_status_message',
                                     _(u'list_subscription_request_sent_status_msg',
                                       u'Subscription request sent'))
                else:
                    self.request.set('portal_status_message', _(u'list_bad_email_address_status_msg',
                                                                u'Bad email address'))
                    
                # Blank the email field to avoid the postback
                self.request.set('email_address', '')
                self.request.set('subscribe_email', '')

        return self.index()

    def Title(self):
        return encode(self.context.title, self.context)

    def Description(self):
        return encode(self.context.description, self.context)

    def address(self):
        if not self.context.mailto:
            return u''
        return obfct_de(encode(self.context.mailto, self.context))

    def archived(self):
        archived = self.context.archived
        vocab = archiveOptionsVocabulary(self.context)
        return vocab.getTerm(archived).token + '. '
    
    def is_archived(self):
        return self.context._is_archived()

    def list_managers(self):
        managers = []
        creator = self.context.Creator()
        for manager in self.context.managers:
            if manager == creator:
                managers.append('%s (creator)' % manager)
            else:
                managers.append(manager)
        return managers

    def list_title(self):
        return self.context.Title()

    def list_type(self):
        list_type = self.context.list_type
        if list_type is None:
            return _(u'list_type_not_set', u'List Type not set')
        return '%s. %s' % (list_type.title, list_type.description)

    def subscribe_keyword(self):
        # Mailboxer stores the subject line keyword used for subscribing as
        # a property
        return self.context.getValueFor('subscribe')

    def unsubscribe_keyword(self):
        # Mailboxer stores the subject line keyword used for unsubscribing as
        # a property
        return self.context.getValueFor('unsubscribe')

    def subscribe(self):
        req = {'action':'subscribe', 'email':self.user_email}
        if self.user_logged_in:
            req['use_logged_in_user'] = True
        ret = self.sub_policy.enforce(req)
                                       
        if ret == MEMBERSHIP_ALLOWED:
            self.mem_list.subscribe(self.user_email)
            self.request.set('portal_status_message',
                             _(u'list_have_been_subscribed_status_msg',
                               u'You have been subscribed'))
            pass
        elif ret == MEMBERSHIP_DEFERRED:
            self.request.set('portal_status_message',
                             _(u'list_subscription_pending_moderation_status_msg',
                               u"Your subscription request is pending moderation by the list manager."))

    def unsubscribe(self):
        self.mem_list.unsubscribe(self.user_email)
        self.request.set('portal_status_message', _(u'list_have_been_unsubscribed_status_msg',
                                                    u"You have been unsubscribed"))

    def _get_logged_in_user(self):
        mtool = getToolByName(self.context, 'portal_membership')
        return mtool.getAuthenticatedMember()

    def isSubscribed(self):
        if self.user_email:
            return self.mem_list.is_subscribed(self.user_email)
        else:
            return False

    def isPending(self):
        annot = IAnnotations(self.context)
        sub_mod_pending_list = getAdapter(self.context,
                                          IMembershipPendingList,
                                          'pending_sub_mod_email')

        return sub_mod_pending_list.is_pending(self.user_email)

    def canSubscribe(self):
        return _checkPermission(SubscribeSelf, self.context)

    def manager_email(self):
        if not self.context.manager_email:
            return u''
        return obfct_de(self.context.manager_email)
 def __init__(self, context, request):
     super(ManageMembersView, self).__init__(context, request)
     self.policy = getAdapter(context, IManagerTTWMembershipPolicy)
     self.mem_list = IWriteMembershipList(context)
class ManageMembersView(BrowserView):
    """A basic view of displaying subscribed members and allowed senders """

    def __init__(self, context, request):
        super(ManageMembersView, self).__init__(context, request)
        self.policy = getAdapter(context, IManagerTTWMembershipPolicy)
        self.mem_list = IWriteMembershipList(context)
    
    def __call__(self):
        if not self.request.get('save', None): return self.index()
        d = self.request.form
        self.errors = ''
        to_remove = []
        subscribed_list = set()
        wassubscribed_list = set()
        for name, value in d.items():
            if name.lower() == 'save' and value.lower() == 'save changes': continue
            valuetype, name = name.split('_', 1)
            if valuetype == 'remove':
                to_remove.append(name.decode('utf-8'))
            elif valuetype == 'subscribed':
                subscribed_list.add(name.decode('utf-8'))
            elif valuetype == 'wassubscribed':
                wassubscribed_list.add(name.decode('utf-8'))
        
        to_subscribe = subscribed_list - wassubscribed_list
        to_unsubscribe = wassubscribed_list - subscribed_list

        self._remove(to_remove)
        self._subscribe(to_subscribe)
        self._unsubscribe(to_unsubscribe)

        psm = ""
        to_add = d.get('add_email', None).strip()
        if to_add:
            subscribed = d.get('add_subscribed', None)
            if self._add(to_add, subscribed):
                psm += 'Added: %s.  ' % to_add
            else:
                psm += 'Bad user or email address: %s.  ' % to_add
            
        if to_remove:
            psm += _(u'Removed: %s.  ') % ', '.join(to_remove)
        if to_subscribe:
            psm += _(u'Subscribed: %s.  ') % ', '.join(to_subscribe)
        if to_unsubscribe:
            psm += 'Unsubscribed: %s.  ' % ', '.join(to_unsubscribe)


        if psm:
            context = aq_inner(self.context)
            plone_utils = getToolByName(context, 'plone_utils')
            plone_utils.addPortalMessage(psm)

        # since this means that we've been posted to
        # we should redirect
        self.request.response.redirect(self.nextURL())

    def nextURL(self):
        return '%s/%s' % (self.context.absolute_url(), self.__name__)

    def can_subscribe_others(self):
        return False

    def _add(self, user, subscribed, subscribe_directly=False):
        request = {'action': 'add_allowed_sender', 'email': user}
        policy_result = self.policy.enforce(request)
        if policy_result == MEMBERSHIP_ALLOWED:
            self.mem_list.add_allowed_sender(user)
        elif policy_result == MEMBERSHIP_DENIED:
            return False

        if subscribed:
            request = {'action': 'subscribe', 'email': user}

            if subscribe_directly and self.can_subscribe_others():
                self.mem_list.subscribe(user)
            else:
                result = self.policy.enforce(request)
                if result == MEMBERSHIP_ALLOWED:
                    self.mem_list.subscribe(user)
        return True

    def _remove(self, remove_list):
        for user in remove_list:
            if self.mem_list.is_subscribed(user):
                request = {'action': 'unsubscribe', 'email':user}
            else:
                request = {'action': 'remove_allowed_sender', 'email':user}
                
            if self.policy.enforce(request) == MEMBERSHIP_ALLOWED:
                self.mem_list.remove_allowed_sender(user)


    def _subscribe_user_directly(self, user):
        return False

    def _subscribe(self, add_list):
        can_subscribe_others = self.can_subscribe_others()
        for user in add_list:
            if can_subscribe_others and self._subscribe_user_directly(user):
                self.mem_list.subscribe(user)
                continue
            request = {'action': 'subscribe', 'email': user}
            policy_result = self.policy.enforce(request)
            if policy_result == MEMBERSHIP_ALLOWED:
                self.mem_list.subscribe(user)


    def _unsubscribe(self, remove_list):
        for user in remove_list:
            request = {'action': 'unsubscribe', 'email': user}
            if self.policy.enforce(request) == MEMBERSHIP_ALLOWED:
                self.mem_list.unsubscribe(user)


    def Title(self):
        return _(u'Manage Allowed Senders')

    def Description(self):
        return _(u'Manage Allowed Senders')

    def allowed_senders_data(self):
        return self.mem_list.allowed_senders_data

    def is_subscribed(self, user):
        return self.mem_list.is_subscribed(user)

    def pending_status(self, user):
        annot = IAnnotations(self.context)
        listen_annot = annot.setdefault(PROJECTNAME, OOBTree())

        subscribe_pending_list = getAdapter(self.context, IMembershipPendingList, 'pending_sub_email')
        unsubscribe_pending_list = getAdapter(self.context, IMembershipPendingList, 'pending_unsub_email')
        sub_mod_pending_list = getAdapter(self.context, IMembershipPendingList, 'pending_sub_mod_email')

        email_address = is_email(user) and user or lookup_email(user, self.context)

        inlist = lambda lst: lst.is_pending(email_address)
        status = lambda msg, lst: msg + lst.get_pending_time(email_address)

        status_msg = ''
        if inlist(subscribe_pending_list):
            status_msg += status('subscription pending user confirmation: ', subscribe_pending_list)
        if inlist(unsubscribe_pending_list):
            status_msg += status('unsubscription pending user confirmation: ', unsubscribe_pending_list)
        if inlist(sub_mod_pending_list):
            status_msg += status('subscription pending manager moderation: ', sub_mod_pending_list)

        return status_msg
    def migrate(self):
        if self.is_updated():
            return _(u'already migrated')

        # set the appropriate list type based on the previous settings
        # this may need to mark the appropriate interface on the mailing
        # list as well
        if self.context.moderated:
            self.context.list_type = PostModeratedListTypeDefinition
        elif self.context.closed:
            self.context.list_type = MembershipModeratedListTypeDefinition
        else:
            self.context.list_type = PublicListTypeDefinition

        # copy over the membership stuff
        annot = IAnnotations(self.context)
        listen_annot = annot.get('listen', {})
        old_subscribers = listen_annot.get('subscribers', [])

        # create the new annotations by using current adapters
        mem_list = IWriteMembershipList(self.context)
        for subscriber in old_subscribers:
            mem_list.subscribe(subscriber)

        # unsubscribe (but leave as allowed senders) those who don't
        # receive mail
        nomail = listen_annot.get('norecvmail', [])
        for allowed_sender in nomail:
            mem_list.unsubscribe(allowed_sender)

        # copy over the moderation messages
        self.mod_post_pending_list = getAdapter(self.context, IPostPendingList,
                                                'pending_pmod_post')
        for i in self.context.mqueue.objectIds():
            (header, body) = splitMail(self.context.mqueue[i])
            post = {'header': header, 'body': body}
            (user_name, user_email) = parseaddr(header.get('from', ''))
            self.mod_post_pending_list.add(user_email,
                                           user_name=user_name,
                                           post=post)

        # creates list managers from moderators and list owner
        managers = []
        managers.append(self.context.list_owner)
        for moderator in self.context.moderators:
            managers.append(moderator)
        self.context.managers = tuple(managers)
        convert_manager_emails_to_memberids(self.context)

        # translate archived vocabulary
        if self.context.archived == 'not archived':
            self.context.archived = 2
        elif self.context.archived == 'plain text':
            self.context.archived = 1
        elif self.context.archived == 'with attachments':
            self.context.archived = 0
        else:
            return _(u'error translating archive option')

        # annotate the list to say the migration completed
        self.migration_annot.append('policy_migration')

        return _(u'successfully migrated')
 def __init__(self, context):
     BaseImportExport.__init__(self, context)
     self.mem_list = IWriteMembershipList(context)
Example #14
0
 def __init__(self, context):
     self.context = context
     annot = IAnnotations(context)
     self.listen_annot = annot.setdefault(PROJECTNAME, OOBTree())
     self.mail_sender = ISendMail(context)
     self.mem_list = IWriteMembershipList(context)
def became_allowed_sender(event):
    """
    This function should ensure that all other pending allowed sender
    lists that the other policy adapters depend on are in sync.

    set up the phony mailing list and policies
    >>> from Products.listen.content.tests import DummyAnnotableList
    >>> from Products.listen.content.tests import DummyMembershipTool
    >>> from Products.listen.extras.tests import TestMailingList
    >>> from Products.listen.content.tests import DummyMember
    >>> from Products.listen.config import POST_DEFERRED, MEMBERSHIP_DEFERRED
    >>> ml = TestMailingList()
    >>> from zope.interface import alsoProvides
    >>> from Products.listen.interfaces import IPublicList
    >>> alsoProvides(ml, IPublicList)
    >>> mails_to_list = []
    >>> def listMail(post):
    ...     mails_to_list.append(post)
    >>> ml.listMail = listMail
    >>> from Products.listen.interfaces import IMailingList
    >>> dtool = DummyMembershipTool('foo')
    >>> dtool.result = None
    >>> ml.portal_membership = dtool
    >>> from Products.listen.content import WriteMembershipList
    >>> mlist = WriteMembershipList(ml)
    >>> from zope.component import getAdapter
    >>> from zope.component import provideAdapter
    >>> from Products.listen.interfaces import IEmailPostPolicy
    >>> from Products.listen.interfaces import IUserEmailMembershipPolicy
    >>> from Products.listen.content import PublicEmailPostPolicy
    >>> from Products.listen.content import UserMembershipPolicy
    >>> postpolicy = getAdapter(ml, IEmailPostPolicy)
    >>> mempolicy = getAdapter(ml, IUserEmailMembershipPolicy)

    send a subscribe email to get on the pending list
    >>> request = dict(email='*****@*****.**',
    ...                subject='subscribe')
    >>> mempolicy.enforce(request) == MEMBERSHIP_DEFERRED
    True

    now submit a post to get on that pending list
    >>> request = dict(email='*****@*****.**',
    ...                post=dict(header={}, body='there is only zul!'))
    >>> postpolicy.enforce(request) == POST_DEFERRED
    True

    now add the email as an allowed sender
    >>> mlist.add_allowed_sender('*****@*****.**')

    make sure he's not on the allowed sender pending list
    >>> from zope.annotation.interfaces import IAnnotations
    >>> annot = IAnnotations(ml)
    >>> listen_annot = annot['listen']
    >>> a_s_list = listen_annot['a_s_pending_sub_email']
    >>> '*****@*****.**' in a_s_list
    False

    verify that the post is no longer pending and has been sent out
    >>> post_list = listen_annot['pending_mod_post']
    >>> '*****@*****.**' in post_list
    False
    >>> 'there is only zul!' in mails_to_list[0]['Mail']
    True

    try with a mem-moderated list policy
    >>> from zope.interface import directlyProvides
    >>> from Products.listen.interfaces import IMembershipModeratedList
    >>> directlyProvides(ml, IMembershipModeratedList)
    >>> postpolicy = getAdapter(ml, IEmailPostPolicy)
    >>> request = dict(email='*****@*****.**',
    ...                post=dict(header={}, body='there is only zui!'))
    >>> postpolicy.enforce(request) == POST_DEFERRED
    True
    >>> mlist.add_allowed_sender('*****@*****.**')
    >>> '*****@*****.**' in post_list
    False
    >>> 'there is only zui!' in mails_to_list[1]['Mail']
    True

    make someone who is pending subscription moderation an allowed sender
    and make sure they get automatically subscribed
    >>> from Products.listen.interfaces import IMembershipPendingList
    >>> sub_mod_pending_list = getAdapter(ml, IMembershipPendingList, 'pending_sub_mod_email')
    >>> sub_mod_pending_list.add('*****@*****.**')
    >>> mlist.add_allowed_sender('*****@*****.**')
    >>> mlist.is_subscribed('*****@*****.**')
    True

    now try subscribing a member who is pending subscription moderation
    >>> sub_mod_pending_list.add('*****@*****.**')
    >>> mlist.subscribe('*****@*****.**')
    >>> mlist.is_subscribed('*****@*****.**')
    True

    """
    
    email = event.email
    context = event.context

    # clean up pending subscription
    pend_list = getAdapter(context, IPostPendingList, 'a_s_pending_sub_email')
    pend_list.remove(email)

    # if member is waiting for moderation to become a subscriber
    # then subscribe member
    sub_pending_list = getAdapter(context, IMembershipPendingList, 'pending_sub_mod_email')
    if sub_pending_list.is_pending(email):
        mlist = IWriteMembershipList(context)
        mail_sender = ISendMail(context)
        sub_pending_list.remove(email)
        mlist.subscribe(email)
        mail_sender.user_welcome(email, email)

    # clean up pending posts
    post_mod_list = getAdapter(context, IPostPendingList, 'pending_mod_post')
    # XXX currently expecting one post,
    # this is not the case for Post Moderated Lists
    # send the post for the user to the list
    posts = post_mod_list.get_posts(email)
    # uniquify posts
    post_dict = {}
    for p in posts:
        post_dict[p['body']] = p['header']
    posts = [dict(header=v, body=k) for k,v in post_dict.iteritems()]
    send_pending_posts(context, posts)
    post_mod_list.remove(email)
class MailingListView(BrowserView):
    """A basic view of a mailing list"""

    def __call__(self):
        sub_action = self.request.get('subscribe_member', None)
        unsub_action = self.request.get('unsubscribe_member', None)
        email_action = self.request.get('subscribe_email', None)
        self.request.set('enable_border', True)
        self.errors = errors = {}

        logged_in_mem = self._get_logged_in_user()
        self.user_logged_in = False
        if logged_in_mem:
            self.user_email = lookup_email(logged_in_mem.getId(), self.context)
            self.user_logged_in = True
        else:
            #XXX what should this be?
            self.user_email = ''

        self.mem_list = IWriteMembershipList(self.context)

        # the appropriate sub_policy needs to be instantiated
        # depending on list type
        self.sub_policy = getAdapter(self.context, IUserTTWMembershipPolicy)

        if sub_action:
            self.subscribe()
        elif unsub_action:
            self.unsubscribe()
        elif email_action:
            address = self.request.get('email_address', None)
            if not address:
                errors['email_address'] = _('An email address is required')
            elif EMAIL_RE.match(address) is None:
                errors['email_address'] = _('This email address is invalid')
            elif self.mem_list.is_subscribed(address):
                errors['email_address'] = \
                                 _('This email address is already subscribed')
            else:
                # everything is OK, send a request mail the
                # appropriate sub_policy needs to be instantiated
                # depending on list type
                sub_policy_for_email = getAdapter(self.context, IUserEmailMembershipPolicy)

                ret = sub_policy_for_email.enforce({'email':address,
                                                    'subject':'subscribe'})
                if ret == MEMBERSHIP_ALLOWED:
                    # make user a subscriber
                    self.mem_list.subscribe(address)
                    self.request.set('portal_status_message', 'Email subscribed')
                elif ret == MEMBERSHIP_DEFERRED:
                    self.request.set('portal_status_message',
                                     'Subscription request sent')
                else:
                    self.request.set('portal_status_message', 'Bad email address')
                    
                # Blank the email field to avoid the postback
                self.request.set('email_address', '')
                self.request.set('subscribe_email', '')

        return self.index()

    def Title(self):
        return encode(self.context.title, self.context)

    def Description(self):
        return encode(self.context.description, self.context)

    def address(self):
        if not self.context.mailto:
            return u''
        return obfct_de(encode(self.context.mailto, self.context))

    def archived(self):
        archived = self.context.archived
        vocab = archiveOptionsVocabulary(self.context)
        return vocab.getTerm(archived).token + '. '
    
    def is_archived(self):
        return self.context._is_archived()

    def list_managers(self):
        managers = []
        creator = self.context.Creator()
        for manager in self.context.managers:
            if manager == creator:
                managers.append('%s (creator)' % manager)
            else:
                managers.append(manager)
        return managers

    def list_title(self):
        return self.context.Title()

    def list_type(self):
        list_type = self.context.list_type
        if list_type is None:
            return _(u'List Type not set')
        return '%s. %s' % (list_type.title, list_type.description)

    def subscribe_keyword(self):
        # Mailboxer stores the subject line keyword used for subscribing as
        # a property
        return self.context.getValueFor('subscribe')

    def unsubscribe_keyword(self):
        # Mailboxer stores the subject line keyword used for unsubscribing as
        # a property
        return self.context.getValueFor('unsubscribe')

    def subscribe(self):
        req = {'action':'subscribe', 'email':self.user_email}
        if self.user_logged_in:
            req['use_logged_in_user'] = True
        ret = self.sub_policy.enforce(req)
                                       
        if ret == MEMBERSHIP_ALLOWED:
            self.mem_list.subscribe(self.user_email)
            self.request.set('portal_status_message',
                             'You have been subscribed')
            pass
        elif ret == MEMBERSHIP_DEFERRED:
            self.request.set('portal_status_message',
                             'Your subscription request is pending moderation '
                             'by the list manager.')       

    def unsubscribe(self):
        self.mem_list.unsubscribe(self.user_email)
        self.request.set('portal_status_message', 'You have been unsubscribed')

    def _get_logged_in_user(self):
        mtool = getToolByName(self.context, 'portal_membership')
        return mtool.getAuthenticatedMember()

    def isSubscribed(self):
        if self.user_email:
            return self.mem_list.is_subscribed(self.user_email)
        else:
            return False

    def isPending(self):
        annot = IAnnotations(self.context)
        sub_mod_pending_list = getAdapter(self.context,
                                          IMembershipPendingList,
                                          'pending_sub_mod_email')

        return sub_mod_pending_list.is_pending(self.user_email)

    def canSubscribe(self):
        return _checkPermission(SubscribeSelf, self.context)

    def manager_email(self):
        if not self.context.manager_email:
            return u''
        return obfct_de(self.context.manager_email)
Example #17
0
    def __call__(self):
        sub_action = self.request.get('subscribe_member', None)
        unsub_action = self.request.get('unsubscribe_member', None)
        email_action = self.request.get('subscribe_email', None)
        self.request.set('enable_border', True)
        self.errors = errors = {}

        logged_in_mem = self._get_logged_in_user()
        self.user_logged_in = False
        if logged_in_mem:
            self.user_email = lookup_email(logged_in_mem.getId(), self.context)
            self.user_logged_in = True
        else:
            #XXX what should this be?
            self.user_email = ''

        self.mem_list = IWriteMembershipList(self.context)

        # the appropriate sub_policy needs to be instantiated
        # depending on list type
        self.sub_policy = getAdapter(self.context, IUserTTWMembershipPolicy)

        if sub_action:
            self.subscribe()
        elif unsub_action:
            self.unsubscribe()
        elif email_action:
            address = self.request.get('email_address', None)
            if not address:
                errors['email_address'] = _('An email address is required')
            elif EMAIL_RE.match(address) is None:
                errors['email_address'] = _('This email address is invalid')
            elif self.mem_list.is_subscribed(address):
                errors['email_address'] = \
                                 _('This email address is already subscribed')
            else:
                # everything is OK, send a request mail the
                # appropriate sub_policy needs to be instantiated
                # depending on list type
                sub_policy_for_email = getAdapter(self.context, IUserEmailMembershipPolicy)

                ret = sub_policy_for_email.enforce({'email':address,
                                                    'subject':'subscribe'})
                if ret == MEMBERSHIP_ALLOWED:
                    # make user a subscriber
                    self.mem_list.subscribe(address)
                    self.request.set('portal_status_message', _(u'list_email_subscribed_status_msg',
                                                                u'Email subscribed'))
                elif ret == MEMBERSHIP_DEFERRED:
                    self.request.set('portal_status_message',
                                     _(u'list_subscription_request_sent_status_msg',
                                       u'Subscription request sent'))
                else:
                    self.request.set('portal_status_message', _(u'list_bad_email_address_status_msg',
                                                                u'Bad email address'))
                    
                # Blank the email field to avoid the postback
                self.request.set('email_address', '')
                self.request.set('subscribe_email', '')

        return self.index()
Example #18
0
 def __init__(self, context, request):
     super(ManageMembersView, self).__init__(context, request)
     self.policy = getAdapter(context, IManagerTTWMembershipPolicy)
     self.mem_list = IWriteMembershipList(context)
Example #19
0
class ManageMembersView(BrowserView):
    """A basic view of displaying subscribed members and allowed senders """
    def __init__(self, context, request):
        super(ManageMembersView, self).__init__(context, request)
        self.policy = getAdapter(context, IManagerTTWMembershipPolicy)
        self.mem_list = IWriteMembershipList(context)

    def __call__(self):
        if not self.request.get('save', None): return self.index()
        d = self.request.form
        self.errors = ''
        to_remove = []
        subscribed_list = set()
        wassubscribed_list = set()
        for name, value in d.items():
            if name.lower() == 'save' and value.lower() == 'save changes':
                continue
            valuetype, name = name.split('_', 1)
            if valuetype == 'remove':
                to_remove.append(name.decode('utf-8'))
            elif valuetype == 'subscribed':
                subscribed_list.add(name.decode('utf-8'))
            elif valuetype == 'wassubscribed':
                wassubscribed_list.add(name.decode('utf-8'))

        to_subscribe = subscribed_list - wassubscribed_list
        to_unsubscribe = wassubscribed_list - subscribed_list

        self._remove(to_remove)
        self._subscribe(to_subscribe)
        self._unsubscribe(to_unsubscribe)

        psm = ""
        to_add = d.get('add_email', None).strip()
        if to_add:
            subscribed = d.get('add_subscribed', None)
            if self._add(to_add, subscribed):
                psm += _(u'add_subscribed_portal_msg',
                         u'Added: ${to_add}.  ',
                         mapping={'to_add': to_add})
            else:
                psm += _(u'bad_user_email_portal_msg',
                         u'Bad user or email address: ${to_add}.  ',
                         mapping={'to_add': to_add})

        if to_remove:
            psm += _(u'removed_portal_msg',
                     u'Removed: ${to_remove}.  ',
                     mapping={'to_remove': to_remove})
        if to_subscribe:
            psm += _(u'subscribed_portal_msg',
                     u'Subscribed: ${to_subscribe}.  ',
                     mapping={'to_subscribe': to_subscribe})
        if to_unsubscribe:
            psm += _(u'unsubscribed_portal_msg',
                     u'Unsubscribed: ${to_unsubscribe}.  ',
                     mapping={'to_unsubscribe': to_unsubscribe})

        if psm:
            context = aq_inner(self.context)
            plone_utils = getToolByName(context, 'plone_utils')
            plone_utils.addPortalMessage(psm)

        # since this means that we've been posted to
        # we should redirect
        self.request.response.redirect(self.nextURL())

    def nextURL(self):
        return '%s/%s' % (self.context.absolute_url(), self.__name__)

    def can_subscribe_others(self):
        return False

    def _add(self, user, subscribed, subscribe_directly=False):
        request = {'action': 'add_allowed_sender', 'email': user}
        policy_result = self.policy.enforce(request)
        if policy_result == MEMBERSHIP_ALLOWED:
            self.mem_list.add_allowed_sender(user)
        elif policy_result == MEMBERSHIP_DENIED:
            return False

        if subscribed:
            request = {'action': 'subscribe', 'email': user}

            if subscribe_directly and self.can_subscribe_others():
                self.mem_list.subscribe(user)
            else:
                result = self.policy.enforce(request)
                if result == MEMBERSHIP_ALLOWED:
                    self.mem_list.subscribe(user)
        return True

    def _remove(self, remove_list):
        for user in remove_list:
            if self.mem_list.is_subscribed(user):
                request = {'action': 'unsubscribe', 'email': user}
            else:
                request = {'action': 'remove_allowed_sender', 'email': user}

            if self.policy.enforce(request) == MEMBERSHIP_ALLOWED:
                self.mem_list.remove_allowed_sender(user)

    def _subscribe_user_directly(self, user):
        return False

    def _subscribe(self, add_list):
        can_subscribe_others = self.can_subscribe_others()
        for user in add_list:
            if can_subscribe_others and self._subscribe_user_directly(user):
                self.mem_list.subscribe(user)
                continue
            request = {'action': 'subscribe', 'email': user}
            policy_result = self.policy.enforce(request)
            if policy_result == MEMBERSHIP_ALLOWED:
                self.mem_list.subscribe(user)

    def _unsubscribe(self, remove_list):
        for user in remove_list:
            request = {'action': 'unsubscribe', 'email': user}
            if self.policy.enforce(request) == MEMBERSHIP_ALLOWED:
                self.mem_list.unsubscribe(user)

    def Title(self):
        return _(u'Manage Allowed Senders')

    def Description(self):
        return _(u'Manage Allowed Senders')

    def allowed_senders_data(self):
        return self.mem_list.allowed_senders_data

    def is_subscribed(self, user):
        return self.mem_list.is_subscribed(user)

    def pending_status(self, user):
        annot = IAnnotations(self.context)
        listen_annot = annot.setdefault(PROJECTNAME, OOBTree())

        subscribe_pending_list = getAdapter(self.context,
                                            IMembershipPendingList,
                                            'pending_sub_email')
        unsubscribe_pending_list = getAdapter(self.context,
                                              IMembershipPendingList,
                                              'pending_unsub_email')
        sub_mod_pending_list = getAdapter(self.context, IMembershipPendingList,
                                          'pending_sub_mod_email')

        email_address = is_email(user) and user or lookup_email(
            user, self.context)

        inlist = lambda lst: lst.is_pending(email_address)
        status = lambda msg, lst: msg + lst.get_pending_time(email_address)

        status_msg = ''
        if inlist(subscribe_pending_list):
            status_msg += status(
                _(u'subscription pending user confirmation: '),
                subscribe_pending_list)
        if inlist(unsubscribe_pending_list):
            status_msg += status(
                _(u'unsubscription pending user confirmation: '),
                unsubscribe_pending_list)
        if inlist(sub_mod_pending_list):
            status_msg += status(
                _(u'subscription pending manager moderation: '),
                sub_mod_pending_list)

        return status_msg