def handle_clear(self, action): self.status = _(u"Please select items to remove.") selected = self.selected_items() if selected: self.status = _(u"Successfully removed old messages from mailing-lists.") for id, stats in selected: stats.channel.queue.clear()
def handle_send(self, action): context = self.context.context data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return channel = data["channel"] channel_paths = ["/".join(channel.getPhysicalPath())] newsletter_path = "/".join(context.getPhysicalPath()) newsletter_uid = IUUID(context) include_collector_items = data["include_collector_items"] override_vars = self.get_override_vars() job = collective.singing.async.Job( _assemble_messages, channel_paths, newsletter_uid, newsletter_path, include_collector_items, override_vars ) title = _( u"Send '${context}' through ${channel}.", mapping=dict( context=context.Title().decode(context.plone_utils.getSiteEncoding()), channel=u'"%s"' % channel.title ), ) job.title = title utils.get_queue().pending.append(job) self.status = _(u"Messages queued for delivery.")
def handle_schedule(self, action): data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return try: path, section = data["channel_and_collector"] except KeyError: return site = getSite() channel = site.unrestrictedTraverse(path) if not isinstance(channel.scheduler, collective.singing.scheduler.TimedScheduler): self.status = _("${name} does not support scheduling.", mapping=dict(name=channel.title)) return if not data.get('datetime'): self.status = _("Please fill in a date.") return # XXX: We want to get the UIDResolver through an adapter # in the future channel.scheduler.items.append( (data['datetime'], UIDResolver(self.context.context.UID()), self.get_override_vars())) self.status = _("Successfully scheduled distribution.")
def add_subscription(self, context, secret, comp_data, coll_data, metadata, secret_provided): try: self.added = self.context.subscriptions.add_subscription( self.context, secret, comp_data, coll_data, metadata) if secret and not self.added.metadata.get('pending', False): #in this case the user subscribed himself in my-subscriptions.html #panel and he doesn't need to confirm his subscription notify(ConfirmSubscriptionEvent(context, self.added)) except ValueError: self.added = None self.status = self.status_already_subscribed return self.status = _(u"You subscribed successfully.") if not secret_provided: composer = self.context.composers[self.format] msg = composer.render_confirmation(self.added) status, status_msg = collective.singing.message.dispatch(msg) if status == u'sent': self.status = _(u"Information on how to confirm your " "subscription has been sent to you.") else: # This implicitely rolls back our transaction. raise RuntimeError( "There was an error with sending your e-mail. Please try " "again later.")
def handle_clearnew(self, action): self.status = _(u"Please select items with new messages to clear.") selected = self.selected_items() if selected: self.status = _(u"Successfully cleared queued messages in mailing-lists.") for id, stats in selected: stats.channel.queue.clear(queue_names=('new','retry'))
def _assemble_messages(channel_paths, newsletter_uid, newsletter_path, include_collector_items, override_vars=None): if override_vars is None: override_vars = {} queued = 0 site = getSite() request = site.REQUEST uid_catalog = getToolByName(site, 'uid_catalog', None) newsletter_item = uid_catalog(UID=newsletter_uid) if not newsletter_item: message = "There was a problem in dispatching newsletters. %s was not found and this queue will be deleted." % newsletter_path logger.warning(message) IStatusMessage(site.REQUEST).add(message, "warning") return _(u"0 messages queued for delivery. Item '${newsletter_path}' not found.", mapping=dict(newsletter_path=newsletter_path)) # raise KeyError('Newsletter not found') context = newsletter_item[0].getObject() for path in channel_paths: channel = site.restrictedTraverse(path) assembler = collective.singing.interfaces.IMessageAssemble(channel) queued += assembler( request, (FullFormatWrapper(context),), include_collector_items, override_vars) if channel.scheduler is not None and include_collector_items: channel.scheduler.triggered_last = datetime.datetime.now() return _(u"${queued} message(s) queued for delivery.", mapping=dict(queued=queued))
class EditTimedSchedulerForm(form.EditForm): template = viewpagetemplatefile.ViewPageTemplateFile( 'form-with-subforms.pt') @property def fields(self): return field.Fields( collective.singing.interfaces.IScheduler).select('active') def update(self): self.subforms = [] for index, entry in enumerate(self.context.items): sub = EditTimedSchedulerEntryForm(entry, self.request) sub.prefix = '%s.' % index sub.update() self.subforms.append(sub) super(EditTimedSchedulerForm, self).update() @button.buttonAndHandler(_('Apply'), name='apply') def handle_apply(self, action): return super(EditTimedSchedulerForm, self).handleApply.func(self, action) @button.buttonAndHandler(_('Remove entries'), name='remove') def handle_remove(self, action): for subform in tuple(self.subforms): data, errors = subform.extractData() if data.get('selected'): self.context.items.remove(subform.context) self.subforms.remove(subform)
def handle_send(self, action): context = self.context.context data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return channel = data['channel'] channel_paths = ['/'.join(channel.getPhysicalPath())] newsletter_path = "/".join(context.getPhysicalPath()) newsletter_uid = IUUID(context) include_collector_items = data['include_collector_items'] override_vars = self.get_override_vars() job = collective.singing.async.Job(_assemble_messages, channel_paths, newsletter_uid, newsletter_path, include_collector_items, override_vars) title = _(u"Send '${context}' through ${channel}.", mapping=dict( context=context.Title().decode(context.plone_utils.getSiteEncoding()), channel=u'"%s"' % channel.title)) job.title = title utils.get_queue().pending.append(job) self.status = _(u"Messages queued for delivery.")
def handle_preview(self, action): data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return channel = data['channel'] include_collector_items = data['include_collector_items'] address = data['address'] if not address: self.status = _(u"The address to send the preview to is missing.") return queued = 0 assembler = collective.singing.interfaces.IMessageAssemble(channel) assembler.update_cue = False subs = channel.subscriptions.query(key=address) for sub in subs: msg = assembler.render_message( self.request, sub, (FullFormatWrapper(self.context.context),), include_collector_items, self.get_override_vars()) if msg is not None: queued += 1 self.status = _( u"${num} message(s) queued.", mapping=dict(num=queued))
class ISendAndPreviewFormWithCustomSubject(ISendAndPreviewForm): subject = schema.TextLine( title=_(u"Custom Subject"), description=_(u"Enter a custom subject line for your newsletter here. " "Leave blank to use the default subject for the chosen " "content and mailing-list."), required=False)
class PortletSubscribeLinkForm(z3c.form.form.Form): """ """ template = viewpagetemplatefile.ViewPageTemplateFile('titlelessform.pt') ignoreContext = True formErrorsMessage = _('There were some errors.') def __init__(self, context, request): super(PortletSubscribeLinkForm, self).__init__(context, request) @property def fields(self): return z3c.form.field.Fields(self.context.composers[self.format].schema) @z3c.form.button.buttonAndHandler(_('Proceed'), name='preceed') def handleAdd(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return params = urlencode(dict([('composer.widgets.%s'%key, value) for key, value in data.items()])) subscribe_url = '%s/subscribe.html?%s' % (self.context.absolute_url(), params) self.request.response.redirect(subscribe_url) return
def handle_schedule(self, action): data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return try: path, section = data["channel_and_collector"] except KeyError: return site = getSite() channel = site.unrestrictedTraverse(path) if not isinstance(channel.scheduler, collective.singing.scheduler.TimedScheduler): self.status = _("${name} does not support scheduling.", mapping=dict(name=channel.title)) return if not data.get('datetime'): self.status = _("Please fill in a date.") return # XXX: We want to get the UIDResolver through an adapter # in the future channel.scheduler.items.append(( data['datetime'], UIDResolver(self.context.context.UID()), self.get_override_vars())) self.status = _("Successfully scheduled distribution.")
def handle_send(self, action): context = self.context.context data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return path = data["channel_and_collector"][0] channel_paths = [path] newsletter_path = "/".join(context.getPhysicalPath()) if HAS_UUID: newsletter_uid = IUUID(context) else: newsletter_uid = context.UID() include_collector_items = data['include_collector_items'] override_vars = self.get_override_vars() job = collective.singing.async.Job(_assemble_messages, channel_paths, newsletter_uid, newsletter_path, include_collector_items, override_vars) site = getSite() channel = site.unrestrictedTraverse(path) title = _(u"Send '${context}' through ${channel}.", mapping=dict( context=context.Title().decode(context.plone_utils.getSiteEncoding()), channel=u'"%s"' % channel.title)) job.title = title utils.get_queue().pending.append(job) self.status = _(u"Messages queued for delivery.")
def _assemble_messages(channel_paths, newsletter_uid, newsletter_path, include_collector_items, override_vars=None, use_full_format=True): if override_vars is None: override_vars = {} queued = 0 site = getSite() request = site.REQUEST uid_catalog = getToolByName(site, 'uid_catalog', None) newsletter_item = uid_catalog(UID=newsletter_uid) if not newsletter_item: message = "There was a problem in dispatching newsletters. %s was not found and this queue will be deleted." % newsletter_path logger.warning(message) IStatusMessage(site.REQUEST).add(message, "warning") return _(u"0 messages queued for delivery. Item '${newsletter_path}' not found.", mapping=dict(newsletter_path=newsletter_path)) # raise KeyError('Newsletter not found') context = newsletter_item[0].getObject() for path in channel_paths: channel = site.restrictedTraverse(path) assembler = collective.singing.interfaces.IMessageAssemble(channel) wrapped_context = FullFormatWrapper(context) if use_full_format else context queued += assembler( request, (wrapped_context,), include_collector_items, override_vars) if channel.scheduler is not None and include_collector_items: channel.scheduler.triggered_last = datetime.datetime.now() return _(u"${queued} message(s) queued for delivery.", mapping=dict(queued=queued))
class ChannelPreviewForm(z3c.form.form.Form): """Channel preview form. Currently only allows an in-browser preview. """ interface.implements(ISendAndPreviewForm) template = viewpagetemplatefile.ViewPageTemplateFile('form.pt') description = _(u"See an in-browser preview of the newsletter.") fields = z3c.form.field.Fields(ISendAndPreviewForm).select( 'include_collector_items') include_collector_items = True def getContent(self): return self @z3c.form.button.buttonAndHandler(_(u"Generate"), name='preview') def handle_preview(self, action): data, errors = self.extractData() if errors: self.status = form.EditForm.formErrorsMessage return collector_items = int(bool(data['include_collector_items'])) return self.request.response.redirect( self.context.absolute_url()+\ '/preview-newsletter.html?include_collector_items=%d' % \ collector_items)
class Confirm(BrowserView): template = ViewPageTemplateFile('skeleton.pt') contents = ViewPageTemplateFile('status.pt') label = _(u"Confirming your subscription") successMessage = _(u"You confirmed your subscription successfully.") notKnownMessage = _(u"Your subscription isn't known to us.") def __call__(self): secret = self.request.form['secret'] if secret: for channel in channel_lookup(only_subscribeable=True): subscriptions = channel.subscriptions.query(secret=secret) if len(subscriptions): for sub in subscriptions: if sub.metadata.get('pending', False): sub.metadata['pending'] = False notify_subscription_confirmed(sub) self.status = self.successMessage break else: self.status = self.notKnownMessage else: self.status = _(u"Can't identify your subscription. " u"Please check your URL.") return self.template()
class SubscriptionEditForm(IncludeHiddenSecret, form.EditForm): template = viewpagetemplatefile.ViewPageTemplateFile('form.pt') successMessage = _('Your subscription was updated.') removed = False handlers = form.EditForm.handlers @property def description(self): return self.context.channel.description @property def prefix(self): return '%s.%s.' % (self.context.channel.name, self.context.metadata['format']) @property def label(self): subscription = self.context value = subscription.channel.title if len(subscription.channel.composers) > 1: format = subscription.metadata['format'] value = u"%s (%s)" % (value, subscription.channel.composers[format].title) return value @property def fields(self): if self.context.channel.collector is None: return field.Fields() return field.Fields(self.context.channel.collector.schema) def update(self): if len(self.fields) == 0: self.buttons = self.buttons.omit('apply') super(SubscriptionEditForm, self).update() @button.buttonAndHandler(_('Apply changes'), name='apply') def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return changes = self.applyChanges(data) if changes: self.status = self.successMessage else: self.status = self.noChangesMessage @button.buttonAndHandler(_('Unsubscribe from newsletter'), name='unsubscribe') def handle_unsubscribe(self, action): secret = self.secret subs = self.context.channel.subscriptions for subscription in subs.query(secret=secret): subs.remove_subscription(subscription) self.removed = self.context self.status = _(u"You unsubscribed successfully.")
def handle_trigger(self, action): queued = self.context.trigger(self.context.aq_inner.aq_parent, self.request) if queued: self.status = _(u"${number} messages queued.", mapping=dict(number=queued)) else: self.status = _(u"No messages queued.")
def handle_trigger(self, action): queued = self.context.trigger( self.context.aq_inner.aq_parent, self.request) if queued: self.status = _(u"${number} messages queued.", mapping=dict(number=queued)) else: self.status = _(u"No messages queued.")
class CollectorEditForm(EditForm): """An edit form for Collector conditions """ form_fields = form.FormFields(ICollectorCondition) label = _(u'Edit S&D Collector Condition') description = _( u'A S&D Collector condition filters to only items in a collector.') form_name = _(u'Configure element')
class ChannelSubscribePortletAddView(ChannelSubscribePortletView): label = _(u"Add Mailing-list Subscribe Portlet") description = _(u"This portlet allows a visitor to subscribe to a specific newsletter.") def contents(self): switch_on(self) return ChannelSubscribePortletAddForm(self.context, self.request)()
def handle_clearnew(self, action): self.status = _(u"Please select items with new messages to clear.") selected = self.selected_items() if selected: self.status = _( u"Successfully cleared queued messages in mailing-lists.") for id, stats in selected: stats.channel.queue.clear(queue_names=('new', 'retry'))
def handle_clear(self, action): self.status = _(u"Please select items to remove.") selected = self.selected_items() if selected: self.status = _( u"Successfully removed old messages from mailing-lists.") for id, stats in selected: stats.channel.queue.clear()
class ChannelEditForm(EditForm): """ An edit form for the mail action """ form_fields = form.FormFields(IChannelAction) label = _(u'Edit S&D Newsletter Action') description = _( u'A S&D Newsletter action can send an item as a newsletter') form_name = _(u'Configure element')
def _addItem(self, data): """imports csv and returns message @param data: the form data @return status as i18n aware unicode if a subscription with same email is found, we delete this first but keep selection of options. if remove-non-existing in the form was found, all existing subscriptions not found in the CSV file are removed. """ metadata = dict(format=self.context.format, date=datetime.datetime.now()) subscriberdata = data.get("subscriberdata", None) onlyremove = data.get("onlyremove", False) remove = data.get("removenonexisting", False) header_row_present = data.get("header_row_present", False) delimiter = data.get("csv_delimiter", csv_delimiter) if subscriberdata is None: return _(u"File was not given.") subscribers, errorcandidates = parseSubscriberCSVFile( subscriberdata, self.context.composer, header_row_present=header_row_present, delimiter=delimiter ) if not type(subscribers) == type([]): return _(u"File has incorrect format.") added = 0 new_and_updated = [] notadded = len(errorcandidates) current = self.mychannel.subscriptions if onlyremove: new_and_updated = [s["email"] for s in subscribers] if onlyremove or remove: old = sets.Set([sub.composer_data["email"] for sub in current.values()]) # maybe add subscribvers or just registered subscribers email list if not onlyremove: for subscriber_data in subscribers: secret = collective.singing.subscribe.secret( self.mychannel, self.context.composer, subscriber_data, self.context.request ) try: old_subscription = self._removeSubscription(secret) item = current.add_subscription(self.mychannel, secret, subscriber_data, [], metadata) new_and_updated.append(subscriber_data["email"]) # restore section selection if old_subscription is not None: old_collector_data = old_subscription[0].collector_data if "selected_collectors" in old_collector_data and old_collector_data["selected_collectors"]: item.collector_data = old_collector_data added += 1 except Exception, e: # XXX refine which exceptions we want to catch # TODO; put some information about error e into the message errorcandidates.append(subscriber_data.get("email", _(u"Unknown"))) notadded += 1
def handle_send(self, action): self.status = _(u"Please select which mailing-list's queued e-mails" " you'd like to send.") selected = self.selected_items() if selected: sent, failed = 0, 0 for id, stats in selected: s, f = stats.channel.queue.dispatch() sent += s failed += f self.status = _(u"${sent} message(s) sent, ${failed} failure(s).", mapping=dict(sent=sent, failed=failed))
def fields(self): factory = schema.Choice( __name__='factory', title=_(u"Type"), vocabulary=zope.schema.vocabulary.SimpleVocabulary([ zope.schema.vocabulary.SimpleTerm(value=f, title=f.title) for f in collector.collectors ])) title = schema.TextLine(__name__='title', title=_(u"Title")) return z3c.form.field.Fields(factory, title)
def fields(self): factory = schema.Choice( __name__="factory", title=_(u"Type"), vocabulary=zope.schema.vocabulary.SimpleVocabulary( [zope.schema.vocabulary.SimpleTerm(value=f, title=f.title) for f in collector.collectors] ), ) title = schema.TextLine(__name__="title", title=_(u"Title")) return z3c.form.field.Fields(factory, title)
class SubscriptionsSearchForm(z3c.form.form.Form): prefix = 'search.' ignoreContext = True fields = field.Fields( schema.TextLine( __name__='fulltext', title=_(u"Search subscribers"), )) @z3c.form.button.buttonAndHandler(_('Search'), name='search') def handle_search(self, action): pass
class CollectorAddForm(AddForm): """An add form for Collector conditions. """ form_fields = form.FormFields(ICollectorCondition) label = _(u'Add S&D Collector Condition') description = _( u'A S&D Collector condition filters to only items in a collector.') form_name = _(u'Configure element') def create(self, data): c = CollectorCondition() form.applyChanges(c, self.form_fields, data) return c
class ChannelAddForm(AddForm): """ An add form for the mail action """ form_fields = form.FormFields(IChannelAction) label = _(u'Add S&D Newsletter Action') description = _( u'A S&D Newsletter action can send an item as a newsletter') form_name = _(u'Configure element') def create(self, data): a = ChannelAction() form.applyChanges(a, self.form_fields, data) return a
def status_already_subscribed(self): channel_url = "" for item in self.context.aq_inner.aq_chain: if not channel_url: if IDanceFloorParty.providedBy(item): channel_url = "%s/portal_newsletters" % item.absolute_url() else: plone_view = getMultiAdapter((aq_inner(item), self.request), name='plone') if plone_view.isDefaultPageInFolder(): right_context = plone_view.getParentObject() if IDanceFloorParty.providedBy(right_context): channel_url = "%s/portal_newsletters" % right_context.absolute_url( ) if not channel_url: channel_url = self.newslettertool.absolute_url() link_start = '<a href="%s/sendsecret.html">' % (channel_url) link_end = '</a>' # The link_start plus link_end construction is not very # pretty, but it is needed to avoid syntax errors in the # generated po files. return _( u'You are already subscribed to this newsletter. Click here to ' '${link_start}edit your subscriptions${link_end}.', mapping={ 'link_start': link_start, 'link_end': link_end })
def render_confirmation(self, subscription): vars = self._vars(subscription) subscription_vars = self._subscription_vars(subscription) if 'confirmation_subject' not in vars: vars['confirmation_subject'] = zope.i18n.translate( _(u"Confirm your subscription with ${channel-title}", mapping={'channel-title': subscription.channel.title}), target_language=self.language) html = self.confirm_template(**vars) html = utils.compactify(html) html = string.Template(html).safe_substitute(subscription_vars) message = collective.singing.mail.create_html_mail( vars['confirmation_subject'], html, from_addr=vars['from_addr'], to_addr=subscription_vars[template_var('to_addr')], headers=vars.get('more_headers'), encoding=self.encoding) # status=None prevents message from ending up in any queue return collective.singing.message.Message(message, subscription, status=None)
class ReferenceCollector(OFS.SimpleItem.SimpleItem): interface.implements(IReferenceCollector) title = _(u'Content selection') items = () def __init__(self, id, title): self.id = id self.title = title def get_items(self, cue=None, subscription=None): items = self._rebuild_items() return tuple(items), None def _rebuild_items(self): catalog = Products.CMFCore.utils.getToolByName(self, 'portal_catalog') for ref in self.items: if not isinstance(ref, persistent.wref.WeakRef): raise ValueError(_(u"Must be a weak reference (got ${title})", mapping={'title': repr(ref)})) item = ref() if item is not None: uid = item.UID() try: brain = catalog(UID=uid)[0] except IndexError: continue yield brain.getObject()
def render_forgot_secret(self, subscription): vars = self._vars(subscription) subscription_vars = self._subscription_vars(subscription) if 'forgot_secret_subject' not in vars: # XXX Since this is not working #vars['forgot_secret_subject'] = zope.i18n.translate( # _(u"Change your subscriptions with ${site_title}", # mapping={'site_title': vars['site_title']}), # target_language=self.language) vars['forgot_secret_subject'] = self.portal_url.translate( _(u"Change your subscriptions with ${site_title}", mapping={'site_title': vars['site_title']})) html = self.forgot_template(**vars) html = utils.compactify(html) html = string.Template(html).safe_substitute(subscription_vars) message = collective.singing.mail.create_html_mail( vars['forgot_secret_subject'], html, from_addr=vars['from_addr'], to_addr=subscription_vars[template_var('to_addr')], headers=vars.get('more_headers'), encoding=self.encoding) # status=None prevents message from ending up in any queue return collective.singing.message.Message( message, subscription, status=None)
def add_topic(self): name = self.get_next_id() title = self.translate(_(u'Collection for ${title}', mapping={'title': self.title})) Products.CMFPlone.utils._createObjectByType( 'Topic', self, id=name, title=title) self[name].unmarkCreationFlag() return self[name]
def parseSubscriberCSVFile(subscriberdata, composer, header_row_present=False, delimiter=csv_delimiter): """parses file containing subscriber data returns list of dictionaries with subscriber data according to composer""" properties = component.getUtility(IPropertiesTool) charset = properties.site_properties.getProperty("default_charset", "utf-8").upper() try: data = cStringIO.StringIO(subscriberdata) reader = csv.reader(data, delimiter=str(delimiter)) subscriberslist = [] errorcandidates = [] for index, parsedline in enumerate(reader): if index == 0: if header_row_present: fields = parsedline continue else: fields = field.Fields(composer.schema).keys() if len(parsedline) < len(fields): pass else: try: subscriber = dict(zip(fields, map(lambda x: x.decode(charset), parsedline))) subscriber["email"] = subscriber["email"].lower() check_email(subscriber["email"]) except: errorcandidates.append(subscriber["email"]) else: subscriberslist.append(subscriber) return subscriberslist, errorcandidates except Exception, e: return _(u"Error importing subscriber file. %s" % e), []
class EditTopicForm(subform.EditSubForm): """Edit a single collector. """ component.adapts(Products.ATContentTypes.content.topic.ATTopic, None, z3c.form.interfaces.IEditForm) template = viewpagetemplatefile.ViewPageTemplateFile('subform.pt') fields = field.Fields(schema.TextLine(__name__='title', title=_(u"Title"))) @property def css_class(self): return "subform subform-level-%s" % self.level @property def label(self): return _(u"Collection: ${title}", mapping={'title': self.context.title}) prefix = property(prefix) def contents_bottom(self): return u'<a href="%s/criterion_edit_form">%s</a>' % ( self.context.absolute_url(), self.context.translate(_(u"Edit the Smart Folder"))) heading = heading
def render_confirmation(self, subscription): """ Custom render_confirmation method. If there is a registered template with id "confirm_newsletter_subscription" use it. If there isn't, use the default template. """ vars = self._vars(subscription) subscription_vars = self._subscription_vars(subscription) if 'confirmation_subject' not in vars: vars['confirmation_subject'] = translate( _(u"Confirm your subscription with ${channel-title}", mapping={'channel-title': subscription.channel.title}), target_language=self.language) to_addr = subscription_vars[template_var('to_addr')] vars['to_addr'] = to_addr portal = getSite() confirm_template = portal.restrictedTraverse('confirm_newsletter_subscription', self.confirm_template) html = confirm_template(**vars) html = utils.compactify(html) html = string.Template(html).safe_substitute(subscription_vars) message = create_html_mail( vars['confirmation_subject'], html, from_addr=vars['from_addr'], to_addr=to_addr, headers=vars.get('more_headers'), encoding=self.encoding) # status=None prevents message from ending up in any queue return Message( message, subscription, status=None)
def handle_unsubscribe(self, action): secret = self.secret subs = self.context.channel.subscriptions for subscription in subs.query(secret=secret): subs.remove_subscription(subscription) self.removed = self.context self.status = _(u"You unsubscribed successfully.")
class Unsubscribe(BrowserView): template = ViewPageTemplateFile('skeleton.pt') contents = ViewPageTemplateFile('status.pt') label = _(u"Unsubscribe") def __call__(self): secret = self.request.form['secret'] if secret: subs = self.context.aq_inner.subscriptions subscriptions = subs.query(secret=secret) if len(subscriptions): for sub in subscriptions: subs.remove_subscription(sub) self.status = _(u"You unsubscribed successfully.") else: self.status = _(u"You aren't subscribed to this mailing-list.") else: self.status = _(u"Can't identify your subscription. " u"Please check your URL.") return self.template()
def render_confirmation(self, subscription): vars = self._vars(subscription) subscription_vars = self._subscription_vars(subscription) if 'confirmation_subject' not in vars: vars['confirmation_subject'] = zope.i18n.translate( _(u"Confirm your subscription with ${channel-title}", mapping={'channel-title': subscription.channel.title}), target_language=self.language) html = self.confirm_template(**vars) html = utils.compactify(html) html = string.Template(html).safe_substitute(subscription_vars) message = collective.singing.mail.create_html_mail( vars['confirmation_subject'], html, from_addr=vars['from_addr'], to_addr=subscription_vars[template_var('to_addr')], headers=vars.get('more_headers'), encoding=self.encoding) # status=None prevents message from ending up in any queue return collective.singing.message.Message( message, subscription, status=None)
def schema(self): fields = [] optional_collectors = self.get_optional_collectors() if optional_collectors: vocabulary = zope.schema.vocabulary.SimpleVocabulary( [zope.schema.vocabulary.SimpleTerm( value=collector, token='/'.join(collector.getPhysicalPath()), title=collector.title) for collector in optional_collectors]) name = 'selected_collectors' fields.append( (name, zope.schema.Set( __name__=name, title=_(u"Sections"), value_type=zope.schema.Choice(vocabulary=vocabulary)) )) interface.directlyProvides(fields[0][1], collective.singing.interfaces.IDynamicVocabularyCollection) return zope.interface.interface.InterfaceClass( 'Schema', bases=(collective.singing.interfaces.ICollectorSchema,), attrs=dict(fields))
class EditChannelForm(z3c.form.form.EditForm): """Channel edit form. As opposed to the crud form, this allows editing of all channel settings. Actions are also provided to preview and send the newsletter. """ template = viewpagetemplatefile.ViewPageTemplateFile('form.pt') description = _(u"Edit the properties of the mailing-list.") @property def fields(self): fields = z3c.form.field.Fields(IChannel).select('title') collector = schema.Choice(__name__='collector', title=IChannel['collector'].title, required=False, vocabulary='Collector Vocabulary') scheduler = FactoryChoice(__name__='scheduler', title=IChannel['scheduler'].title, required=False, vocabulary='Scheduler Vocabulary') fields += field.Fields(collector, scheduler) fields += field.Fields(IChannel).select('description', 'subscribeable', 'keep_sent_messages') fields['description'].widgetFactory[ z3c.form.interfaces.INPUT_MODE] = wysiwyg.WysiwygFieldWidget return fields
def render_forgot_secret(self, subscription): """ Custom render_forgot method. If there is a registered template with id "forgot_newsletter_subscription" use it. If there isn't, use the default template. """ vars = self._vars(subscription) subscription_vars = self._subscription_vars(subscription) portal = getSite() if 'forgot_secret_subject' not in vars: vars['forgot_secret_subject'] = translate( _(u"Change your subscriptions with ${site_title}", mapping={'site_title': vars['channel_title']}), target_language=self.language) forgot_template = portal.restrictedTraverse('forgot_newsletter_subscription', self.forgot_template) html = forgot_template(**vars) html = utils.compactify(html) html = string.Template(html).safe_substitute(subscription_vars) message = create_html_mail( vars['forgot_secret_subject'], html, from_addr=vars['from_addr'], to_addr=subscription_vars[template_var('to_addr')], headers=vars.get('more_headers'), encoding=self.encoding) # status=None prevents message from ending up in any queue return Message( message, subscription, status=None)
def render_forgot_secret(self, subscription): vars = self._vars(subscription) subscription_vars = self._subscription_vars(subscription) if 'forgot_secret_subject' not in vars: # XXX Since this is not working #vars['forgot_secret_subject'] = zope.i18n.translate( # _(u"Change your subscriptions with ${site_title}", # mapping={'site_title': vars['site_title']}), # target_language=self.language) vars['forgot_secret_subject'] = self.portal_url.translate( _(u"Change your subscriptions with ${site_title}", mapping={'site_title': vars['site_title']})) html = self.forgot_template(**vars) html = utils.compactify(html) html = string.Template(html).safe_substitute(subscription_vars) message = collective.singing.mail.create_html_mail( vars['forgot_secret_subject'], html, from_addr=vars['from_addr'], to_addr=subscription_vars[template_var('to_addr')], headers=vars.get('more_headers'), encoding=self.encoding) # status=None prevents message from ending up in any queue return collective.singing.message.Message(message, subscription, status=None)
def __call__(self): secret = self.request.form['secret'] if secret: subs = self.context.aq_inner.subscriptions subscriptions = subs.query(secret=secret) if len(subscriptions): for sub in subscriptions: subs.remove_subscription(sub) self.status = _(u"You unsubscribed successfully.") else: self.status = _(u"You aren't subscribed to this mailing-list.") else: self.status = _(u"Can't identify your subscription. " u"Please check your URL.") return self.template()
def handle_process_jobs(self, action): queue = utils.get_queue() num = queue.process() finished = queue.finished[-num:] if len(finished) == 1: self.status = finished[0].value else: self.status = _(u"All pending jobs processed")
def handle_add(self, action): data, errors = self.extractData() if errors: self.status = z3c.form.form.EditForm.formErrorsMessage return obj = data["factory"](self.context.get_next_id(), data["title"]) self.context[obj.id] = obj self.status = _(u"Item added successfully.")
def add_schema(self): return self.update_schema + field.Fields( schema.Choice( __name__='factory', title=_(u"Type"), vocabulary=zope.schema.vocabulary.SimpleVocabulary( [zope.schema.vocabulary.SimpleTerm(value=f, title=f.title) for f in collector.standalone_collectors]) ))
def back_link(self): url = self.request.form.get('referer') if not url: addview = aq_parent(aq_inner(self.context)) context = aq_parent(aq_inner(addview)) url = str(component.getMultiAdapter((context, self.request), name=u"absolute_url")) + '/@@manage-portlets' return dict(url=url, label=_(u"Back to portlets"))
def __call__(self, name=None, include_collector_items=False, override_vars=None): # deactivate diazo - we style our newsletters without it self.request.response.setHeader('X-Theme-Disabled', 'True') if override_vars is None: override_vars = '{}' try: include_collector_items = int(include_collector_items) except ValueError: include_collector_items = False if IChannel.providedBy(self.context): channel = self.context items = () else: assert name is not None channel = lookup(name) items = (FullFormatWrapper(self.context),) sub = PreviewSubscription(channel) # We don't want to commit a transaction just for the preview; # this would happen if we were to simply add and remove from # the queue. sp = transaction.savepoint() message = IMessageAssemble(channel).render_message( self.request, sub, items, bool(include_collector_items), eval(override_vars)) if message is None: IStatusMessage(self.request).addStatusMessage( _(u"No items found.")) return self.request.response.redirect(self.context.absolute_url()) # pull message out of hat channel.queue[message.status].pull(-1) # rollback savepoint sp.rollback() # walk message, decoding HTML payload for part in message.payload.walk(): if part.get_content_type() == 'text/html': html = part.get_payload(decode=True) break else: raise ValueError("Message does not contain a 'text/html' part.") return self.template(content=html, title=channel.title)
def update(self): super(PrettySubscriptionsForm, self).update() # Let's set convert any 'pending' subscriptions to non-pending: for sub in self.subs: if sub.metadata.get('pending'): sub.metadata['pending'] = False # Assemble the list of edit forms self.subscription_editforms = [ SubscriptionEditSubForm(s, self.request, self) for s in self.subs] # Assemble the list of add forms self.subscription_addforms = [] for format, channel in self.channels: addform = SubscriptionAddSubForm(channel, self.request, self) addform.format = format self.subscription_addforms.append(addform) # The edit forms might have deleted a subscription. We'll # take care of this while updating them: for form in self.subscription_editforms: form.update() if form.removed: subscription = form.context addform = SubscriptionAddSubForm( subscription.channel, self.request, self) addform.format = subscription.metadata['format'] addform.ignoreRequest = True addform.update() self.subscription_addforms.append(addform) addform.status = form.status #elif form.status != form.noChangesMessage: # self.status = form.status # Let's update the add forms now. One of them may have added # a subscription: for form in self.subscription_addforms: form.update() subscription = form.added if subscription is not None: editform = SubscriptionEditSubForm( subscription, self.request, self) editform.update() self.subscription_editforms.append(editform) #_(u"You subscribed successfully.") editform.status = form.status # check if all subscriptions are now cancelled if not sum([len(c.subscriptions.query(secret=self.secret)) \ for c in channel_lookup(only_subscribeable=True)]): self.unsubscribed_all = True self.status_message = _(u"You were unsubscribed completely.") # update after setting unsubscribed_all self.updateWidgets() del self.request.form['secret']
def summary(self): site = getSite() channel_path, collector = self.channel_and_collector try: channel = site.unrestrictedTraverse(channel_path).name title = '%s (section: %s)' % (channel, collector) except: title = channel_path + ' (WARNING: not found)' return _(u'Send to channel: ${channel}', mapping=dict(channel=title))
def fields(self): subscriberdata = schema.Bytes( __name__="subscriberdata", title=_(u"Subscribers"), description=_( u"Upload a CSV file with a list of subscribers here. " u"Subscribers already present in the database will " u"be overwritten. Each line should contain: " u"${columns}.", mapping=dict(columns=";".join(field.Fields(self.context.composer.schema).keys())), ), ) onlyremove = schema.Bool( __name__="onlyremove", title=_(u"Remove subscribers in list."), description=_(u"Only purge subscribers present in this list."), default=False, ) remove = schema.Bool( __name__="removenonexisting", title=_(u"Purge list."), description=_(u"Purge list before import."), default=False, ) header_row_present = schema.Bool( __name__="header_row_present", title=_(u"CSV contains a header row"), description=_( u"Select this if you want to use the csv " u"header row to designate document variables." u"The header row must contain one 'email' field." ), default=False, ) csv_delimiter = schema.TextLine( __name__="csv_delimiter", title=_(u"CSV delimiter"), description=_(u"The delimiter in your CSV file. " u"(Usually ',' or ';', but no quotes are necessary.)"), default=u",", ) return field.Fields(subscriberdata, remove, onlyremove, header_row_present, csv_delimiter)
def add_schema(self): if len(channel.channels) > 1: return self.update_schema + field.Fields( schema.Choice( __name__='factory', title=_(u"Type"), vocabulary=zope.schema.vocabulary.SimpleVocabulary( [zope.schema.vocabulary.SimpleTerm(value=c, title=c.type_name) for c in channel.channels]) )) return self.update_schema