def handle_migrate_action(self, action, data): # permission checking needed since setting the permission # in zcml doesn't seem to work mtool = getToolByName(self.context, 'portal_membership') if not mtool.checkPermission('Manage Portal', self.context): return _(u'permission denied') ll = getUtility(IListLookup) mappings = ll.showAddressMapping() self.nlists = len(mappings) self.results = [] for mapping in mappings: path = mapping['path'] try: ml = self.context.unrestrictedTraverse(path) migrator = IMigrateList(ml) return_msg = migrator.migrate() absolute_url = ml.absolute_url() except AttributeError: return_msg = _(u'Error: List not found') absolute_url = '' self.results.append({ 'url': absolute_url, 'title': path, 'msg': return_msg }) return self.result_template.render()
def chooseName(self, name, object): if not name: title = getattr(object, 'title', '') name = self.getIdFromTitle(title) if not name: name = object.__class__.__name__ try: name = name.encode('ascii') except UnicodeDecodeError: raise UserError, _("Id must contain only ASCII characters.") dot = name.rfind('.') if dot >= 0: suffix = name[dot:] name = name[:dot] else: suffix = '' n = name + suffix i = 0 while True: i += 1 try: self.context._getOb(n) except AttributeError: break n = name + '-' + str(i) + suffix # Make sure the name is valid. We may have started with # something bad. self.checkName(n, object) return n
def checkName(self, name, object): # ObjectManager can only deal with ASCII names. Specially # ObjectManager._checkId can only deal with strings. try: name = name.encode('ascii') except UnicodeDecodeError: raise UserError, _("Id must contain only ASCII characters.") context = self.context # XXX: Try Plone check_id script this should become a view/adapter try: check_id = getattr(object.__of__(context), 'check_id', None) except AttributeError: # We may not have acquisition available check_id = None if check_id is not None: invalid = check_id(name, required=1) if invalid: raise UserError, invalid # Otherwise fallback on _checkId else: try: self.context._checkId(name, allow_dup=False) except BadRequest, e: msg = ' '.join(e.args) or _("Id is in use or invalid") raise UserError, msg
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
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 ""
def _searchArchive(self, text=None): messages = [] batch = self.request.get('batch', True) batch_size = int(self.request.get('b_size', 25)) batch_start = int(self.request.get('b_start', 0)) text = text or decode(self.request.get('search_text'), '') context = self.context subscription = IMembershipList(self.getMailingList()) if text: text = text.strip() try: messages = self.search.search(text) except ParseTree.ParseError, inst: if "Token 'ATOM' required, 'EOF' found" in str(inst) or "Token 'EOF' required" in str(inst): self.request.set('portal_status_message', _(u'Invalid Search: Search phrase cannot end with \'and\', \'or\', or \'not\'')) elif "Token 'ATOM' required" in str(inst): self.request.set('portal_status_message', _(u'Invalid Search: Search phrase cannot begin with \'and\', \'or\', or \'not\'')) elif "a term must have at least one positive word" in str(inst): self.request.set('portal_status_message', _(u'Invalid Search: Search phrase cannot begin with \'not\'')) elif "Query contains only common words" in str(inst): self.request.set('portal_status_message', _(u'Invalid Search: Search phrase must contain words other than \'and\', \'or\', and \'not\'')) else: messages = catalogMessageIterator(messages, sub_mgr=subscription) if len(messages) == 0: self.request.set('portal_status_message', _(u'There were no messages found'))
def manage_afterAdd(self, item, container, **kw): """Setup properties and sub-objects""" # Only run on add, not rename, etc. if not base_hasattr(self, 'mqueue'): setMailBoxerProperties(self, self.REQUEST, kw) # Setup the default checkMail validator chain setDefaultValidatorChain(self) # Add Archive archive = zapi.createObject('listen.ArchiveFactory', self.storage, title=_(u'List Archive')) item._setObject(self.storage, archive) # Add moderation queue mqueue = zapi.createObject('listen.QueueFactory', self.mailqueue, title=_(u'Moderation queue')) item._setObject(self.mailqueue, mqueue) ttool = getToolByName(self, 'portal_types', None) if ttool is not None: # If the archive/queue are CMF types then we must finish # constructing them. fti = ttool.getTypeInfo(mqueue) if fti is not None: fti._finishConstruction(mqueue) fti = ttool.getTypeInfo(archive) if fti is not None: fti._finishConstruction(archive) MailBoxer.manage_afterAdd(self, self.REQUEST, kw)
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 __call__(self): # Make sure that the current user is allowed to reply: if not self.canReply(): raise Unauthorized, \ _(u"You do not have permission to respond to this message.") # Save the referring URL, either from the template form, or the # HTTP_REFERER, otherwise just use the message url. referring_url = (self.request.get('referring_url', None) or self.request.get('HTTP_REFERER', None) or self.context.absolute_url()) self.referring_url = urllib.splitquery(referring_url)[0] submitted = self.request.get('submit', None) cancelled = self.request.get('cancel', None) if cancelled: portal_status_msg = _(u"Reply Cancelled") return self.request.response.redirect(self.referring_url + '?portal_status_message=%s' % (portal_status_msg)) if submitted: self.errors = {} ml = self.getMailingList() body = decode(self.request.get('body', None), ml) subject = decode(self.request.get('subject', None), ml) if not body or body == self.reply_body(use_empty=True): self.errors['body'] = _(u'You must enter a message') if not subject: self.errors['subject'] = _( u'You must enter a subject for your message.') if not self.member_address(): self.errors['subject'] = _(u'The current user has no address.') if not self.errors: message = self.createReply() self.request.set('Mail', message) result = ml.processMail(self.request) if result == POST_ALLOWED: portal_status_msg = _(u"Post Sent") return self.request.response.redirect( self.referring_url + '?portal_status_message=%s' % (portal_status_msg)) elif result == POST_DEFERRED: portal_status_msg = _(u"Post Pending Moderation") return self.request.response.redirect( self.referring_url + '?portal_status_message=%s' % (portal_status_msg)) elif result == POST_DENIED: portal_status_msg = _( u"Post Rejected: You already have a post pending moderation." ) return self.request.response.redirect( self.referring_url + '?portal_status_message=%s' % (portal_status_msg)) else: portal_status_msg = _(u"Post Error") return self.request.response.redirect( self.referring_url + '?portal_status_message=%s' % (portal_status_msg)) return self.index()
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()
class IListTypeDefinition(Interface): """used for indicating the type of mailing list""" title = Attribute("displayable title of list type") description = Attribute("displayable description of list type") list_marker = InterfaceField(title=_(u'list marker'), description=_(u'marked interface used to indicate the list type'), constraint=IListType.providedBy) index = Int(title=_(u'sort index'))
def __call__(self): ll = getUtility(IListLookup, context=self.context) try: return ll.deliverMessage(self.request) except ListDoesNotExist: raise NotFound, _( "The message address does not correspond to a known mailing list" ) except: message = str(self.request.get(MAIL_PARAMETER_NAME, None)) logger.error("Listen delivery failed for message: \n%s" % message) raise
def addMail(self, mailString, force_id=False): """ Store mail in date based folder archive. Returns created mail. See IMailingList interface. """ archive = aq_get(self, self.getValueFor('storage'), None) # no archive available? then return immediately if archive is None: return None (header, body) = splitMail(mailString) # if 'keepdate' is set, get date from mail, if self.getValueFor('keepdate'): assert header.get("date") is not None time = DateTime(header.get("date")) # ... take our own date, clients are always lying! else: time = DateTime() # now let's create the date-path (yyyy/mm) year = str(time.year()) # yyyy month = str(time.mm()) # mm title = "%s %s"%(time.Month(), year) # do we have a year folder already? if not base_hasattr(archive, year): self.addMailBoxerFolder(archive, year, year, btree=False) yearFolder=getattr(archive, year) # do we have a month folder already? if not base_hasattr(yearFolder, month): self.addMailBoxerFolder(yearFolder, month, title) mailFolder=getattr(yearFolder, month) subject = header.get('subject', _('No Subject')) sender = header.get('from',_('Unknown')) # search a free id for the mailobject id = time.millis() while base_hasattr(mailFolder, str(id)): if force_id: raise AssertionError("ID %s already exists on folder %s" % (id, mailFolder)) id = id + 1 id = str(id) self.addMailBoxerMail(mailFolder, id, sender, subject, time, mailString) mailObject = getattr(mailFolder, id) return mailObject
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 ""
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 __call__(self): # Make sure that the current user is allowed to reply: if not self.canReply(): raise Unauthorized, \ "You do not have permission to respond to this message." # Save the referring URL, either from the template form, or the # HTTP_REFERER, otherwise just use the message url. referring_url = (self.request.get('referring_url', None) or self.request.get('HTTP_REFERER', None) or self.context.absolute_url()) self.referring_url = urllib.splitquery(referring_url)[0] submitted = self.request.get('submit', None) cancelled = self.request.get('cancel', None) if cancelled: return self.request.response.redirect(self.referring_url+ '?portal_status_message=Reply%20Cancelled') if submitted: self.errors = {} ml = self.getMailingList() body = decode(self.request.get('body', None), ml) subject = decode(self.request.get('subject', None), ml) if not body or body == self.reply_body(use_empty=True): self.errors['body'] = _(u'You must enter a message') if not subject: self.errors['subject'] = _( u'You must enter a subject for your message.') if not self.member_address(): self.errors['subject'] = _(u'The current user has no address.') if not self.errors: message = self.createReply() self.request.set('Mail', message) result = ml.processMail(self.request) if result == POST_ALLOWED: return self.request.response.redirect(self.referring_url+ '?portal_status_message=Post%20Sent') elif result == POST_DEFERRED: return self.request.response.redirect(self.referring_url+ '?portal_status_message=Post%20Pending%20Moderation') elif result == POST_DENIED: return self.request.response.redirect(self.referring_url+ '?portal_status_message=Post%20Rejected:%20You%20already%20have%20a%20post%20pending%20moderation.') else: return self.request.response.redirect(self.referring_url+ '?portal_status_message=Post%20Error') return self.index()
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 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 user_mem_mod_already_pending(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("Membership approval already pending") body = default_email_text.user_mem_mod_already_pending mapping = { 'fullname': user_name, 'listname': self.context.title, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
def user_unsubscribe_confirm(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("Unsubscription confirmed") body = default_email_text.user_unsubscribe_confirm mapping = { 'fullname': user_name, 'listname': self.context.title, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
def user_denied(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("Membership denied") body = default_email_text.user_denied mapping = { 'fullname': user_name, 'listname': self.context.title, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
def manager_mod(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("Membership awaiting approval") body = default_email_text.manager_mod mapping = { 'fullname': user_name, 'listname': self.context.title, 'mod_url': self.context.absolute_url() + '/moderation',} body = Message(body, mapping=mapping) self.send_to_managers(translate(subject), translate(body))
def Title(self): title = _('label_archive_list_archive_view', u'${list} archive for ${date}') title = Message(title, mapping={ u'list': self.listTitle(), u'date': self.context.title, }) return title
def user_post_mod_notification(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("Message pending moderation") body = default_email_text.user_post_mod_notification mapping = { 'fullname': user_name, 'listname': self.context.title, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
def user_welcome(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("welcome_to_list", "Welcome to ${title}", mapping={'title' : self.context.title}) body = default_email_text.user_welcome mapping = { 'fullname': user_name, 'listname': self.context.title, 'listaddress': self.context.mailto, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
def user_sub_rejected(self, user_email, user_name, reject_reason): user_name = nonascii_username(user_email, user_name) subject = _("Subscription request rejected") body = default_email_text.user_sub_rejected mapping = { 'fullname': user_name, 'listname': self.context.title, 'reject_reason': reject_reason, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
class MigrationView(Form): """view to migrate mailing lists""" form_fields = Fields() result_template = ZopeTwoPageTemplateFile('browser/migration.pt') @action(_('label_migrate', _(u'Migrate'))) def handle_migrate_action(self, action, data): # permission checking needed since setting the permission # in zcml doesn't seem to work mtool = getToolByName(self.context, 'portal_membership') if not mtool.checkPermission('Manage Portal', self.context): return _(u'permission denied') ll = getUtility(IListLookup) mappings = ll.showAddressMapping() self.nlists = len(mappings) self.results = [] for mapping in mappings: path = mapping['path'] try: ml = self.context.unrestrictedTraverse(path) migrator = IMigrateList(ml) return_msg = migrator.migrate() absolute_url = ml.absolute_url() except AttributeError: return_msg = _(u'Error: List not found') absolute_url = '' self.results.append({ 'url': absolute_url, 'title': path, 'msg': return_msg }) return self.result_template.render() def results(self): return self.results def num_lists(self): return self.nlists
def manager_mod(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("Membership awaiting approval") body = default_email_text.manager_mod mapping = { 'fullname': user_name, 'listname': self.context.title, 'mod_url': self.context.absolute_url() + '/moderation', } body = Message(body, mapping=mapping) self.send_to_managers(translate(subject), translate(body))
def registerList(self, ml): """See IListLookup interface documentation""" address = ml.mailto # normalize case if not address: # Our list does not have an address yet, this only happens when # the add form wasn't used. return address = address.lower() path = '/'.join(ml.getPhysicalPath()) current_addr = self._reverse.get(path, None) current_path = self._mapping.get(address, None) if current_addr is not None: raise UserError, _("This list is already registered, use "\ "updateList to change the address.") if current_path is not None: raise UserError, _("A list is already registered for this address,"\ " you must unregister it first.") self._mapping[address] = path self._reverse[path] = address
def _searchArchive(self, text=None): messages = [] batch = self.request.get('batch', True) batch_size = int(self.request.get('b_size', 25)) batch_start = int(self.request.get('b_start', 0)) text = text or decode(self.request.get('search_text'), '') context = self.context subscription = IMembershipList(self.getMailingList()) if text: text = text.strip() try: messages = self.search.search(text) except ParseTree.ParseError, inst: if "Token 'ATOM' required, 'EOF' found" in str( inst) or "Token 'EOF' required" in str(inst): self.request.set( 'portal_status_message', _(u'Invalid Search: Search phrase cannot end with \'and\', \'or\', or \'not\'' )) elif "Token 'ATOM' required" in str(inst): self.request.set( 'portal_status_message', _(u'Invalid Search: Search phrase cannot begin with \'and\', \'or\', or \'not\'' )) elif "a term must have at least one positive word" in str( inst): self.request.set( 'portal_status_message', _(u'Invalid Search: Search phrase cannot begin with \'not\'' )) elif "Query contains only common words" in str(inst): self.request.set( 'portal_status_message', _(u'Invalid Search: Search phrase must contain words other than \'and\', \'or\', and \'not\'' )) else: messages = catalogMessageIterator(messages, sub_mgr=subscription) if len(messages) == 0: self.request.set('portal_status_message', _(u'There were no messages found'))
def user_welcome(self, user_email, user_name): user_name = nonascii_username(user_email, user_name) subject = _("welcome_to_list", "Welcome to ${title}", mapping={'title': self.context.title}) body = default_email_text.user_welcome mapping = { 'fullname': user_name, 'listname': self.context.title, 'listaddress': self.context.mailto, 'listmanager': self.context.manager_email, } body = Message(body, mapping=mapping) self.context.sendCommandRequestMail(user_email, translate(subject), translate(body))
def updateList(self, ml): """See IListLookup interface documentation""" address = ml.mailto or '' # normalize case address = address.lower() path = '/'.join(ml.getPhysicalPath()) current_addr = self._reverse.get(path, None) current_path = self._mapping.get(address, None) if (current_path is None and current_addr is not None and current_addr != address): # The mailing list address has changed to one which is unknown del self._mapping[current_addr] self._reverse[path] = address self._mapping[address] = path elif current_addr == address and current_path == path: # Nothing has changed, do nothing pass elif current_addr is None and current_path is None: # The list is not registered at all, this happens when the addform # was not used, stupid CMF self.registerList(ml) else: # The new address is already registered raise UserError, _("A list is already registered for this address")
def reply_body(self, use_empty=False): """Add quote characters and attribution to original body.""" req_body = self.request.get('body', None) if req_body and not use_empty: return req_body # Remove message signature stripped_body = stripSignature(self.context.body) quoted_body = rewrapMessage(stripped_body, add_quote=True) attribution = _("reply-attribution", u"On ${date}, ${author} wrote:") attribution = Message(attribution, mapping={ u'date': self.date(), u'author': self.mail_from_name(do_encode=False)}) return translate(attribution) + '\r\n' + quoted_body + '\r\n'
def manager_mod_post_request(self, user_email, user_name, post): user_name = nonascii_username(user_email, user_name) subject = _(u"Post requiring moderation") body = default_email_text.manager_mod_post_request boundary = u'Boundary-%s-%s' % (random(), random()) post_msg = create_request_from(post)['Mail'].decode('utf-8', 'replace') mapping = { 'fullname': user_name, 'mod_url': self.context.absolute_url() + '/moderation', 'listname': self.context.title, 'post': post_msg, 'boundary': boundary,} body = Message(body, mapping=mapping) extra_headers = {'Content-Type': u'multipart/mixed; boundary=%s' % boundary, 'Mime-Version': u'1.0',} self.send_to_managers(translate(subject), translate(body), extra_headers)
def reply_body(self, use_empty=False): """Add quote characters and attribution to original body.""" req_body = self.request.get('body', None) if req_body and not use_empty: return req_body # Remove message signature stripped_body = stripSignature(self.context.body) quoted_body = rewrapMessage(stripped_body, add_quote=True) attribution = _("reply-attribution", u"On ${date}, ${author} wrote:") attribution = Message(attribution, mapping={ u'date': self.date(), u'author': self.mail_from_name(do_encode=False) }) return translate(attribution) + '\r\n' + quoted_body + '\r\n'
def manager_mod_post_request(self, user_email, user_name, post): user_name = nonascii_username(user_email, user_name) subject = _(u"Post requiring moderation") body = default_email_text.manager_mod_post_request boundary = u'Boundary-%s-%s' % (random(), random()) post_msg = create_request_from(post)['Mail'].decode('utf-8', 'replace') mapping = { 'fullname': user_name, 'mod_url': self.context.absolute_url() + '/moderation', 'listname': self.context.title, 'post': post_msg, 'boundary': boundary, } body = Message(body, mapping=mapping) extra_headers = { 'Content-Type': u'multipart/mixed; boundary=%s' % boundary, 'Mime-Version': u'1.0', } self.send_to_managers(translate(subject), translate(body), extra_headers)
def deliverMessage(self, request): """See IListLookup interface documentation""" # XXX raising NotFound annoyingly hides the real problem so # I've added a bunch of logging. I propose in the future we # change NotFound to something that actually gets logged. But # I'm afraid to do that now because I don't know if we somehow # depend on getting a 404 here. message = str(request.get(MAIL_PARAMETER_NAME, None)) if message is not None: message = message_from_string(message) else: logger.error("request.get(%s) returned None" % MAIL_PARAMETER_NAME) raise NotFound, _("The message destination cannot be deterimined.") # preferentially use the x-original-to header (is this postfix only?), # so that mails to multiple lists are handled properly address = message.get('x-original-to', None) if not address: address = message['to'] cc = message['cc'] if address and cc: address = address + ', ' + cc elif cc: address = cc # normalize case if not address: import pprint logger.warn("No destination found in headers:\n%s" % pprint.pformat(message)) raise NotFound, _("The message destination cannot be deterimined.") address = address.lower() if '-manager@' in address: address = address.replace('-manager@', '@') address_list = AddressList(address) for ml_address in address_list: ml = self.getListForAddress(ml_address[1]) if ml is not None: break else: # raise an error on bad requests, so that the SMTP server can # send a proper failure message. logger.warn("no list found for any of %r" % str(address_list)) raise ListDoesNotExist, _("The message address does not correspond to a "\ "known mailing list.") setSite(ml) return ml.manage_mailboxer(request)
def Title(self): title = _('label_archive_views_forum', u'Forum view for ${list}') title = Message(title, mapping={ u'list': self.listTitle(), }) return title
from Products.listen.i18n import _ user_pin_mismatch = _(u'user_pin_mismatch_body',u''' Hello ${fullname}, Your request to join the ${listname} mailing list has been denied because the pin you provided does not match the one initially sent. Any questions regarding this should be sent to ${listmanager}. Yours, List Manager ''') user_denied = _(u'user_denied_body',u''' Hello ${fullname}, Your request to join the ${listname} mailing list has been denied because there was no record of a request. Any questions regarding this should be sent to ${listmanager}. Yours, List Manager ''') user_mod = _(u'user_mod_body',u''' Hello ${fullname}, We have received a message from you to the ${listname} mailing list. Permission for you to post messages to this list is
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 handle_cancel_action(self, action, data): self.status = _(u"Edit cancelled.") return ""
def Description(self): return _(u'Manage Allowed Senders')
def Title(self): return _(u'Manage Allowed Senders')
def listAddress(self): """The list address""" ml = self.getMailingList() if ml is not None: return obfct_de(encode(ml.mailto, ml)) return _(u'No address')
def Title(self): title = _('label_archive_views_date', u'Archive by date for ${title}') title = Message(title, mapping={ u'title': self.listTitle(), }) return title
def Title(self): title = _('label_archive_search', u'Search messages in ${title}') title = Message(title, mapping={ u'title': self.listTitle(), }) return title
def listTitle(self): """The title of the list""" ml = self.getMailingList() if ml is not None: return ml.Title().decode('utf8') return _(u'No Title')
def __call__(self): d = self.request.form post = email = None action = '' postid = None reject_reason = '' plone_utils = getToolByName(self.context, 'plone_utils') # first check if mass moderating all posts if d.get('discard_all_posts', False): action = 'discard' policy = getAdapter(self.context, IEmailPostPolicy) for post in self.get_pending_lists(): postid = post['postid'] email = post['user'] req = dict(action=action, email=email, postid=postid) policy_result = policy.enforce(req) if policy_result == MODERATION_FAILED: plone_utils.addPortalMessage(_(u'Could not moderate!'), type='error') break else: plone_utils.addPortalMessage(_(u'All posts discarded.'), type='info') self.request.response.redirect(self.nextURL()) return for name, value in d.items(): if name.endswith('_approve') or \ name.endswith('_discard') or \ name.endswith('_reject'): action = name.split('_')[-1] elif name == 'postid': postid = int(value) elif name == 'email': email = value elif name == 'reject_reason': reject_reason = value # we only need to check moderation if we have an action specified if action: # having a post id specified means that we need to moderate posts if postid is not None: # using email post policy # may have to try enforcing the ITTWPostPolicy as well on failure policy = getAdapter(self.context, IEmailPostPolicy) req = dict(action=action, email=email, postid=postid, reject_reason=reject_reason) policy_result = policy.enforce(req) if policy_result == MODERATION_FAILED: plone_utils.addPortalMessage(_(u'Could not moderate!'), type='error') else: plone_utils.addPortalMessage(_(u'Post moderated.'), type='info') else: # same idea between membership policy # may have to try the IUserTTWMembershipPolicy if the email policy fails policy = getAdapter(self.context, IUserEmailMembershipPolicy) req = dict(action=action, email=email, reject_reason=reject_reason) policy_result = policy.enforce(req) if policy_result == MODERATION_FAILED: plone_utils.addPortalMessage(_(u'Could not moderate!'), type='error') else: plone_utils.addPortalMessage(_(u'Member moderated.'), type='info') self.request.response.redirect(self.nextURL()) return return self.index()
description=_(u'marked interface used to indicate the list type'), constraint=IListType.providedBy) index = Int(title=_(u'sort index')) class ListDefinitionFactory(object): implements(IListTypeDefinition) def __init__(self, title, description, list_marker, index=100): self.title = title self.description = description self.list_marker = list_marker self.index = index PublicListTypeDefinition = ListDefinitionFactory( title=_(u'Public List'), description=_(u'Anyone who confirms their email address is valid can post and receive messages.'), list_marker=IPublicList, index=100) MembershipModeratedListTypeDefinition = ListDefinitionFactory( title=_(u'Members List'), description=_(u'Only those approved by the list managers can post and receive messages.'), list_marker=IMembershipModeratedList, index=300) PostModeratedListTypeDefinition = ListDefinitionFactory( title=_(u'Announce List'), description=_(u'Anyone can receive messages, but each posted message has to be approved by the list managers first.'), list_marker=IPostModeratedList, index=200)
def __call__(self): plone_utils = getToolByName(self.context, 'plone_utils') # handle export actions export_messages = self.request.form.get('export_messages') export_addresses = self.request.form.get('export_addresses') if export_messages or export_addresses: filename = file_data = "" if export_addresses: if not self.can(ExportMailingListSubscribers): raise Unauthorized(_(u'Cannot export mailing list subscribers')) filename = "%s-subscribers.csv" % self.context.getId() es = getAdapter(self.context, IMailingListSubscriberExport, name='csv') file_data = es.export_subscribers() elif export_messages: if not self.can(ExportMailingListArchives): raise Unauthorized(_(u'Cannot export mailing list archives')) filename = "%s.mbox" % self.context.getId() em = getAdapter(self.context, IMailingListMessageExport, name='mbox') file_data = em.export_messages() # both export actions result in a file to download self.request.response.setHeader("Content-type", "text/plain") self.request.response.setHeader("Content-disposition", "attachment; filename=%s" % filename) # XXX don't know why i have to do this import transaction transaction.abort() return file_data # import actions psm_text = psm_type = None # This should be moved elsewhere self.UNDO_SUBMIT = UNDO_SUBMIT = "undu_" for key in self.request.form: if key.startswith(UNDO_SUBMIT): # reuse the import permission here if not self.can(ImportMailingListArchives): raise Unauthorized(_(u'Cannot import mailing list archives')) key = key[len(UNDO_SUBMIT):] msg_count = self.undo_import(key) if msg_count: txt = (_(u"Removed %s message%s from the list archive.") % (msg_count, self._plural(msg_count))) plone_utils.addPortalMessage(txt, type='info') self.request.response.redirect(self.nextURL()) return if self.request.form.get("import_messages"): if not self.can(ImportMailingListArchives): raise Unauthorized(_(u'Cannot import mailing list archives')) file = self.request.form.get("import_file") if file: im = getAdapter(self.context, IMailingListMessageImport, name='mbox') self.msgids = im.import_messages(file) self.filename = file.filename self.save_import_history() msg_count = len(self.msgids) psm_text = (_(u'Imported %s message%s from \'%s\'') % (msg_count, self._plural(msg_count), file.filename)) psm_type = 'info' else: psm_text = _(u"No file selected. Please select an mbox file before importing.") psm_type = 'error' plone_utils.addPortalMessage(psm_text, type=psm_type) self.request.response.redirect(self.nextURL()) return if self.request.form.get('import_subscribers'): if not self.can(ImportMailingListSubscribers): raise Unauthorized(_(u'Cannot import mailing list subscribers')) file = self.request.form.get("import_subscribers_file") if file: emails = [s.strip().split(',')[-2:] for s in file] # quick sanity check emails = [e for e in emails if '@' in e[0] and e[1].strip() in ("subscribed", "allowed")] subscriber_importer = IMailingListSubscriberImport(self.context) if emails: subscriber_importer.import_subscribers(emails) n_emails = len(emails) if n_emails != 1: psm_text = _(u'%s email addresses imported') % n_emails else: psm_text = _(u'1 email address imported') psm_type = 'info' else: psm_text = _(u'No emails found') psm_type = 'error' else: psm_text = _(u"No file selected. Please select a csv file before importing.") psm_type = 'error' plone_utils.addPortalMessage(psm_text, type=psm_type) self.request.response.redirect(self.nextURL()) return return self.index()