Example #1
0
 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.")
Example #3
0
    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.")
Example #4
0
    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.")
Example #5
0
 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'))
Example #6
0
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))
Example #7
0
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)
Example #8
0
    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.")
Example #9
0
    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))
Example #10
0
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)
Example #11
0
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 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))
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))
Example #16
0
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)
Example #17
0
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()
Example #18
0
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.")
Example #19
0
 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.")
Example #20
0
 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.")
Example #21
0
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')
Example #22
0
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)()
Example #23
0
 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'))
Example #24
0
 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()
Example #25
0
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')
Example #26
0
    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
Example #27
0
 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))
Example #28
0
 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))
Example #29
0
    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)
Example #30
0
    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)
Example #31
0
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
Example #32
0
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
Example #33
0
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
Example #34
0
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
        })
Example #35
0
    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)
Example #36
0
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()
Example #37
0
    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)
Example #38
0
 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]
Example #39
0
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), []
Example #40
0
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)
Example #42
0
 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.")
Example #43
0
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()
Example #44
0
    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)
Example #45
0
    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))
Example #46
0
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)
Example #48
0
    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)
Example #49
0
    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()
Example #50
0
 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")
Example #51
0
 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.")
Example #52
0
 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"))
Example #54
0
    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)
Example #55
0
    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))
Example #57
0
    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)
Example #58
0
 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