import zope
from zope.event import notify
from zope.interface.common import idatetime
from BTrees.OOBTree import OOBTree
from Acquisition import aq_inner
from AccessControl.interfaces import IRoleManager
from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
from Products.SecureMailHost.SecureMailHost import EMAIL_RE
from Products.CMFCore.utils import _checkPermission
from Products.CMFCore.utils import getToolByName
from Products.statusmessages.interfaces import IStatusMessage
from Products.listen.interfaces import IMailingList
from Products.listen.interfaces import IWriteMembershipList
from Products.listen.interfaces import IMembershipList
from Products.listen.interfaces import IMembershipPolicy
from Products.listen.interfaces import IMembershipPendingList
from Products.listen.interfaces import IUserTTWMembershipPolicy
from Products.listen.interfaces import IUserEmailMembershipPolicy
from Products.listen.content import archiveOptionsVocabulary
from Products.listen.lib.browser_utils import encode, obfct_de
from Products.listen.lib.common import assign_local_role
from Products.listen.permissions import SubscribeSelf
from Products.listen.i18n import _
from Products.listen.lib.common import is_email
from Products.listen.lib.common import lookup_email
from Products.listen.config import PROJECTNAME
from Products.listen.config import MEMBERSHIP_ALLOWED
from Products.listen.config import MEMBERSHIP_DEFERRED
from Products.listen.content import ListTypeChanged
from zope.component import getAdapter
from zope.app.annotation.interfaces import IAnnotations
from Products.listen.i18n import _
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)
class MailingListArchiveView(BrowserView):
"""A basic view for the mailing list archive.
"""
def name(self):
return encode(self.context.title, self.context)
def archive(self):
return self.context.archive
from zope.formlib import form
from base import EditForm
from zope.app.form.browser import TextAreaWidget
from zope.app.form.browser import ASCIIWidget
from zope.app.form.browser import RadioWidget
from Products.listen.browser.listwidget.widget import DynamicListWidget
class DescriptionWidget(TextAreaWidget):
width = 40
height = 3
def create_radio_widget(field, request):
return RadioWidget(field, field.vocabulary, request)
listen_form_fields = form.FormFields(IMailingList)
listen_form_fields['description'].custom_widget = DescriptionWidget
listen_form_fields['mailto'].custom_widget = ASCIIWidget
listen_form_fields['archived'].custom_widget = create_radio_widget
listen_form_fields['list_type'].custom_widget = create_radio_widget
listen_form_fields['managers'].custom_widget = DynamicListWidget
class MailingListAddForm(form.AddForm):
"""A form for adding MailingList objects.
"""
form_fields = listen_form_fields
portal_type = 'MailingList'
label = _(u"Add Mailing List")
def _assign_local_roles_to_managers(self, ml):
assign_local_role('Owner', ml.managers, IRoleManager(ml))
def createAndAdd(self, data):
# use aq_inner, or else the obj will be wrapped in this view,
# will screw up acquired security settings (esp. local roles)
context = aq_inner(self.context)
plone_utils = getToolByName(context, 'plone_utils')
list_id = plone_utils.normalizeString(data['title'])
context.invokeFactory(self.portal_type, list_id)
list_ob = context._getOb(list_id)
old_list_type = list_ob.list_type.list_marker
new_list_type = data.get('list_type').list_marker
form.applyChanges(list_ob, self.form_fields, data)
# ensure correct role is set for users
self._assign_local_roles_to_managers(list_ob)
# XXX this ObjectCreatedEvent event would normally come before
# the ObjectAddedEvent
notify(zope.app.event.objectevent.ObjectCreatedEvent(list_ob))
notify(ListTypeChanged(list_ob, old_list_type, new_list_type))
self._finished_add = True
status = IStatusMessage(self.request)
status.addStatusMessage(_('Mailing list added.'), type=u'info')
self._next_url = list_ob.absolute_url()
return list_ob
def nextURL(self):
return self._next_url
class MailingListEditForm(EditForm):
"""A form for editing MailingList objects.
"""
form_fields = listen_form_fields
label = _(u"Edit Mailing List")
def _assign_local_roles_to_managers(self):
ml = self.context
assign_local_role('Owner', ml.managers, IRoleManager(ml))
@form.action(_('label_save', u'Save'), condition=form.haveInputWidgets)
def handle_save_action(self, action, data):
old_list_type = self.context.list_type.list_marker
new_list_type = data.get('list_type').list_marker
if form.applyChanges(self.context, self.form_fields, data,
self.adapters):
# ensure correct role is set for users
self._assign_local_roles_to_managers()
notify(zope.app.event.objectevent.ObjectModifiedEvent(self.context))
notify(ListTypeChanged(self.context, old_list_type, new_list_type))
self.status = _(u"Your changes have been saved.")
else:
self.status = _(u"No changes need to be saved.")
return ""
@form.action(_('label_cancel', u'Cancel'), validator=lambda *a: ())
def handle_cancel_action(self, action, data):
self.status = _(u"Edit cancelled.")
return ""