class ModerationPortletAssignment(base.Assignment): implements(IModerationPortlet) heading = _(u"Feed moderation") description = _(u"Use this form to moderate content.") title = _(u"Moderation portlet")
class RegistryEditForm(form.EditForm): control_panel_view = "plone_control_panel" def getContent(self): return annotation_proxy(self.context, self.schema) @button.buttonAndHandler(_(u"Save"), name='save') def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return self.applyChanges(data) IStatusMessage(self.request).addStatusMessage( _(u"Changes saved."), "info" ) self._redirect() @button.buttonAndHandler(_(u"Cancel"), name='cancel') def handleCancel(self, action): IStatusMessage(self.request).addStatusMessage( _(u"Edit cancelled."), "info" ) self._redirect() def _redirect(self): self.request.response.redirect( "%s/%s" % (self.context.absolute_url(), self.control_panel_view) )
class CampaignPortletAssignment(base.Assignment): implements(ICampaignPortlet) heading = _(u"Campaign scheduling") description = _(u"Send or schedule a newsletter campaign.") title = _(u"Campaign portlet") start = None section = u"std_content00" def __init__(self, **kwargs): for name, value in kwargs.items(): self.__dict__[name] = value
class ISubscriptionPortlet(IPortletDataProvider, ISubscriptionFormSettings): heading = schema.TextLine( title=_(u"Title"), description=_(u"Provide a title for the portlet."), required=True, default=u"Sign up", ) description = schema.Text( title=_(u"Description"), description=_(u"Enter a description of your newsletter."), required=False, default=u"Join our newsletter and stay updated!", )
class IFeedControl(Interface): """Feed control settings.""" feeds = schema.Set( title=_(u"Feeds"), description=_(u"Select one or more items from this list " u"to include in the corresponding feed."), required=False, value_type=schema.Choice( vocabulary="collective.chimpfeed.vocabularies.Feeds", ) ) feedCategory = schema.Choice( title=_(u"Feed category"), description=_(u"Please select a category for this item."), required=False, default=None, vocabulary="collective.chimpfeed.vocabularies.Categories", ) feedSchedule = schema.Date( title=_(u'Feed date'), description=_(u'If this date is set, the content will only be ' u'included in Mailchimp-based feeds from this date on. ' u'Otherwise, the "Publishing date" is used.'), required=False, ) feedModerate = schema.Bool( title=_(u'Feed moderation'), description=_(u'Select this option to approve item.'), required=False, )
def update(self): super(CampaignForm, self).update() today = datetime.date.today() date = self.context.start if date is None: date = today start = self.widgets['start'] start.value = (date.year, date.month, date.day) subject = self.widgets['subject'] if not subject.value: value = self.context.subject or \ self.context.Title().decode('utf-8') subject.value = _( u"${subject} ${date}", mapping={ 'subject': value, 'date': ulocalized_time( DateTime(), context=self.context, request=self.request ).lstrip('0')} )
def update(self): super(CampaignForm, self).update() today = datetime.date.today() date = self.context.start if date is None: date = today start = self.widgets['start'] start.value = (date.year, date.month, date.day) subject = self.widgets['subject'] if not subject.value: value = self.context.subject or \ self.context.Title().decode('utf-8') subject.value = _(u"${subject} ${date}", mapping={ 'subject': value, 'date': ulocalized_time( DateTime(), context=self.context, request=self.request).lstrip('0') })
def update(self): super(NewsletterForm, self).update() today = datetime.date.today() subject = self.widgets['subject'] if type(subject.value) == type(''): subject.value = subject.value.decode('utf-8') if not subject.value: value = self.context.subject or \ self.context.Title().decode('utf-8') subject.value = _(u"${subject} ${date}", mapping={ 'subject': value, 'date': ulocalized_time( DateTime(), context=self.context, request=self.request).lstrip('0') }) if not self.context.select_interest_groups: self.widgets['interests'].mode = HIDDEN_MODE
def get_name(self): api = getUtility(IApiUtility, context=self) for list_id, name in api.get_lists(): if list_id == self.mailinglist: return name return _(u"Untitled")
def groups(self): last = None groups = [] entries = [] today = DateTime() for entry in self.entries: date = entry['feedSchedule'] days = int(math.floor(date - today)) if days != last: entries = [] # To-Do: Use Plone's date formatters if days == -1: name = _(u"Today") elif days < 7: abbr = date.strftime("%a") name = translate( 'weekday_%s' % abbr.lower(), domain="plonelocales", context=self.request ) else: name = self._localize_time(date, False) groups.append({ 'date': name, 'entries': entries, }) entries.append(entry) return groups
class SubscriptionPortletForm(FormBase): name = "Subscribe" form_fields = form.Fields(ISubscriptionPortlet) description = _(u"This portlet shows a subscription form.") def setUpWidgets(self, **kwargs): super(SubscriptionPortletForm, self).setUpWidgets(**kwargs) widget = self.widgets['mailinglist'] if len(widget.vocabulary): mailinglist = ISubscriptionPortlet.providedBy(self.context) and \ self.context.mailinglist or widget.hasInput() \ and widget.getInputValue() if mailinglist: pass else: # Make a default choice token = tuple(widget.vocabulary)[-1].token widget.setRenderedValue(token) else: self.widgets['interest_groups'].hidden = True self.widgets['interest_groupings'].hidden = True
def get_terms(self): groupings = self.get_groupings() for grouping in groupings: value = token = grouping['id'] groups = grouping['groups'] name = grouping['name'] if groups: names = [group['name'] for group in groups] if len(names) > 4: del names[4:] name = _( u"${name} (${groups} and ${count} more)", mapping={ 'name': name, 'groups': ", ".join(names), 'count': len(groups) - len(names), } ) else: name += u" (%s)" % ", ".join(names) yield SimpleTerm(value, token, name)
def handleRepair(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return query = Indexed('chimpfeeds') brains = self.context.portal_catalog.evalAdvancedQuery(query) context = self.getContent() vocabulary = feeds_factory(context) all_feeds = set(term.value for term in vocabulary) count = 0 bad = set() changed = [] for i, brain in enumerate(brains): try: feeds = set(brain.chimpfeeds) except TypeError: continue missing = feeds - all_feeds bad |= missing if missing: count += 1 obj = brain.getObject() try: field = obj.getField('feeds') except AttributeError: feeds = obj.feeds field = None else: feeds = set(field.get(obj)) fixed = feeds - missing if field is None: obj.feeds = fixed else: field.set(obj, fixed) changed.append(obj) for obj in changed: modified(obj) obj.reindexObject() logger.info("Repair complete; %d items updated." % count) if bad: logger.info("Feeds removed: %s." % (", ".join(bad).encode('utf-8'))) IStatusMessage(self.request).addStatusMessage( _(u"Repaired ${count} items.", mapping={'count': count}), "info" )
class ICampaign(ICampaignPortlet): """Note that most fields are inherited from the portlet.""" limit = schema.Bool( title=_(u"Limit"), description=_(u"Include scheduled items up until today's date only."), default=True, required=False, ) filtering = schema.Bool( title=_(u"Apply filtering markup"), description=_(u"Select this option to apply the markup " u"required for automatic interest group " u"filtering."), default=True, required=False, ) create_draft = schema.Bool(title=_(u"Create new campaigns as drafts"), required=False, default=True) schedule = schema.Datetime( title=_(u"Schedule date"), description=_(u"If provided, item will be scheduled to be sent " u"at this time."), required=False, default=None, )
def description(self): context = self.context.aq_base if self.request.get('success'): return u'' elif not IPloneSiteRoot.providedBy(context) \ and context.Description(): return context.Description() else: return _(u"Select subscription options and submit form.")
def handleRepair(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return query = Indexed('chimpfeeds') brains = self.context.portal_catalog.evalAdvancedQuery(query) context = self.getContent() vocabulary = feeds_factory(context) all_feeds = set(term.value for term in vocabulary) count = 0 bad = set() changed = [] for i, brain in enumerate(brains): try: feeds = set(brain.chimpfeeds) except TypeError: continue missing = feeds - all_feeds bad |= missing if missing: count += 1 obj = brain.getObject() try: field = obj.getField('feeds') except AttributeError: feeds = obj.feeds field = None else: feeds = set(field.get(obj)) fixed = feeds - missing if field is None: obj.feeds = fixed else: field.set(obj, fixed) changed.append(obj) for obj in changed: modified(obj) obj.reindexObject() logger.info("Repair complete; %d items updated." % count) if bad: logger.info("Feeds removed: %s." % (", ".join(bad).encode('utf-8'))) IStatusMessage(self.request).addStatusMessage( _(u"Repaired ${count} items.", mapping={'count': count}), "info")
class CampaignPortletAddForm(base.AddForm): label = _(u"Add campaign portlet") form_fields = form.Fields(ICampaignPortlet) # Let's not ask the user to name a start date on adding the # portlet. form_fields = form_fields.omit('start') def create(self, data): return CampaignPortletAssignment(**data)
class IControlPanel(IFeedSettings): urls = schema.Tuple( title=_(u"RSS"), description=_(u"This field lists an RSS-feed for each of " u"the available feed strings (including " u"those that are automatically pulled from " u"interest groups."), required=False, value_type=schema.ASCIILine(), ) lists = schema.Tuple( title=_(u"Lists"), description=_(u"This listing shows a link to a " u"subscription form for each of the defined " u"lists in your account."), required=False, value_type=schema.ASCIILine(), )
class NewsletterPortletAssignment(base.Assignment): implements(INewsletterPortlet) heading = _(u"Static campaign scheduling") description = _( u"Send or schedule a newsletter campaign based on the current context." ) title = _(u"Newsletter portlet") maillinglist = '' interest_groups = tuple() select_interest_groups = False template = '' section = u"std_content00" subject = '' def __init__(self, **kwargs): for name, value in kwargs.items(): self.__dict__[name] = value
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return self.applyChanges(data) IStatusMessage(self.request).addStatusMessage( _(u"Changes saved."), "info" ) self._redirect()
class ISubscription(Interface): email = schema.TextLine( title=_(u"E-mail"), required=True, constraint=is_email, ) interests = schema.Tuple( value_type=schema.Choice( vocabulary="collective.chimpfeed.vocabularies.InterestGroups", ), required=False, constraint=interests_required, )
def groups(self): last = None groups = [] entries = [] today = DateTime() today = DateTime(today.year(), today.month(), today.day()) for entry in self.entries: date = entry['feedSchedule'] days = int(math.floor(date - today)) if days != last: entries = [] # To-Do: Use Plone's date formatters if days == -1: name = _(u"Today") else: abbr = date.strftime("%a") name = translate( 'weekday_%s' % abbr.lower(), domain="plonelocales", context=self.request ).capitalize() if days < 0 or days >= 7: name = _(u"${subject} ${date}", mapping={ 'subject': name, 'date': self._localize_time(date, False), }) groups.append({ 'date': name, 'entries': entries, }) last = days entries.append(entry) return groups
def fields(self): fields = field.Fields() settings = IFeedSettings(self.context) if settings.show_name: fields += field.Fields( schema.TextLine( __name__="name", title=_(u"Name"), required=False, )) fields += field.Fields(ISubscription) fields['interests'].widgetFactory = InterestsWidget.factory return fields
def groups(self): last = None groups = [] entries = [] today = DateTime() today = DateTime(today.year(), today.month(), today.day()) for entry in self.entries: date = entry['feedSchedule'] days = int(math.floor(date - today)) if days != last: entries = [] # To-Do: Use Plone's date formatters if days == -1: name = _(u"Today") else: abbr = date.strftime("%a") name = translate('weekday_%s' % abbr.lower(), domain="plonelocales", context=self.request).capitalize() if days < 0 or days >= 7: name = _(u"${subject} ${date}", mapping={ 'subject': name, 'date': self._localize_time(date, False), }) groups.append({ 'date': name, 'entries': entries, }) last = days entries.append(entry) return groups
def fields(self): fields = field.Fields() settings = IFeedSettings(self.context) if settings.show_name: fields += field.Fields( schema.TextLine( __name__="name", title=_(u"Name"), required=False, ) ) fields += field.Fields(ISubscription) fields['interests'].widgetFactory = InterestsWidget.factory return fields
def handleCreate(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return success = self.process("campaignCreate", **data) if success: IStatusMessage(self.request).addStatusMessage( _(u"Campaign created."), "info") # Set date to tomorrow's date. self.context.start = datetime.date.today() + \ datetime.timedelta(days=1)
class INewsletter(INewsletterPortlet): """Note that most fields are inherited from the portlet.""" interests = schema.Tuple( title=_(u"Select interest groups"), description=_(u"If no interest groups are selected the predefined " u"groups will be used, which were specified during the " u"creation of the portlet"), value_type=schema.Choice( vocabulary="collective.chimpfeed.vocabularies.InterestGroups", ), required=False, ) create_draft = schema.Bool(title=_(u"Create new campaigns as drafts"), required=False, default=True) schedule = schema.Datetime( title=_(u"Schedule date"), description=_(u"If provided, item will be scheduled to be sent " u"at this time."), required=False, default=None, )
def handleCreate(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return success = self.process("campaignCreate", **data) if success: IStatusMessage(self.request).addStatusMessage( _(u"Campaign created."), "info" ) # Set date to tomorrow's date. self.context.start = datetime.date.today() + \ datetime.timedelta(days=1)
def handleCreate(self, action): if self.context.REQUEST.get('restricted_traverse', False): return subj = self.context.REQUEST.get('chimpXYZ.widgets.subject') if type(subj) == type(''): self.context.REQUEST.set('chimpXYZ.widgets.subject', subj.decode('utf-8')) data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return if not self.context.select_interest_groups: data.update(dict(interests=self.context.interest_groups)) success = self.process("campaignCreate", **data) if success: IStatusMessage(self.request).addStatusMessage( _(u"Campaign created."), "info")
def template(self): site = getToolByName(self.context, "portal_url").getPortalObject() settings = IFeedSettings(site) api_key = settings.mailchimp_api_key if not api_key: return try: api = greatape.MailChimp(api_key, debug=False) cid = self.request.get('cid', '') content = api(method="campaignContent", cid=cid) except greatape.MailChimpError: IStatusMessage(self.request).addStatusMessage( _(u"Unable to show content."), "error" ) return return content['html']
def handleCreate(self, action): if self.context.REQUEST.get('restricted_traverse', False): return subj = self.context.REQUEST.get('chimpXYZ.widgets.subject') if type(subj) == type(''): self.context.REQUEST.set('chimpXYZ.widgets.subject', subj.decode('utf-8')) data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return if not self.context.select_interest_groups: data.update(dict(interests=self.context.interest_groups)) success = self.process("campaignCreate", **data) if success: IStatusMessage(self.request).addStatusMessage( _(u"Campaign created."), "info" )
class ISubscriptionFormSettings(Interface): mailinglist = schema.Choice( title=_(u"Mailinglist"), description=_(u"Select a mailinglist for this portlet."), vocabulary="collective.chimpfeed.vocabularies.Lists", required=True, ) interest_groupings = schema.Tuple( title=_(u"Interest groups"), description=_(u"Select interest groups. " u"Note that all interests within the selected " u"groups will appear in the portlet."), value_type=schema.Choice( vocabulary="collective.chimpfeed.vocabularies.InterestGroupings", ), required=False, ) interest_groups = schema.Tuple( title=_(u"Interests"), description=_(u"Select interests."), value_type=schema.Choice( vocabulary="collective.chimpfeed.vocabularies.InterestGroups", ), required=False, ) preselected_interest_groups = schema.Tuple( title=_(u"Preselected interests."), description=_(u"If interests is selected here, the interests groups will be preselected, " u"and the user will not be able to select these."), value_type=schema.Choice( vocabulary="collective.chimpfeed.vocabularies.InterestGroups", ), required=False, )
def process(self, method, subject=None, create_draft=False, schedule=None, **data): settings = IFeedSettings(self.context) api_key = settings.mailchimp_api_key view = getMultiAdapter((self.context.aq_parent, self.request), name="chimpfeed-campaign") params = self.makeParams(**data) rendered = view.template(**params).encode('utf-8') next_url = self.request.get('HTTP_REFERER') or self.action segments = view.getSegments(**params).items() if segments: segment_opts = { 'match': 'all', 'conditions': [{ 'field': 'interests-%s' % groupingid, 'op': 'one', 'value': groupids } for groupingid, groupids in segments[:10]] } if len(segments) > 10: count = len(segments) - 10 IStatusMessage(self.request).addStatusMessage( _(u"%d segments were ignored " u"(Mailchimp limits this to 10)." % count), "warning") else: segment_opts = {} return self.createCampaign(api_key, method, subject, create_draft, schedule, rendered, next_url, segment_opts)
def renderInterestGroupings(self): filtered = ( grouping for grouping in self.groupings if grouping['id'] in self.context.interest_groupings ) rendered = [] for grouping in filtered: terms = tuple(interest_groups_factory.get_terms_for_grouping( grouping, count=False )) # Create label from the grouping name; we simply lowercase # it. label = _(u"Choose ${name}:", mapping={ 'name': cgi.escape(grouping['name'].lower()) }) result = self.renderChoices(terms, label) rendered.append(result) return u"\n".join(rendered)
def update(self): super(NewsletterForm, self).update() today = datetime.date.today() subject = self.widgets['subject'] if type(subject.value) == type(''): subject.value = subject.value.decode('utf-8') if not subject.value: value = self.context.subject or \ self.context.Title().decode('utf-8') subject.value = _( u"${subject} ${date}", mapping={ 'subject': value, 'date': ulocalized_time( DateTime(), context=self.context, request=self.request ).lstrip('0')} ) if not self.context.select_interest_groups: self.widgets['interests'].mode = HIDDEN_MODE
def get_terms(self): groupings = self.get_groupings() for grouping in groupings: value = token = grouping['id'] groups = grouping['groups'] name = grouping['name'] if groups: names = [group['name'] for group in groups] if len(names) > 4: del names[4:] name = _(u"${name} (${groups} and ${count} more)", mapping={ 'name': name, 'groups': ", ".join(names), 'count': len(groups) - len(names), }) else: name += u" (%s)" % ", ".join(names) yield SimpleTerm(value, token, name)
def process(self, method, subject=None, create_draft=False, schedule=None, **data): settings = IFeedSettings(self.context) api_key = settings.mailchimp_api_key view = getMultiAdapter( (self.context.aq_parent, self.request), name="chimpfeed-campaign" ) params = self.makeParams(**data) rendered = view.template(**params).encode('utf-8') next_url = self.request.get('HTTP_REFERER') or self.action segments = view.getSegments(**params).items() if segments: segment_opts = { 'match': 'all', 'conditions': [{'field': 'interests-%s' % groupingid, 'op':'one', 'value': groupids} for groupingid, groupids in segments[:10] ]} if len(segments) > 10: count = len(segments) - 10 IStatusMessage(self.request).addStatusMessage( _(u"%d segments were ignored " u"(Mailchimp limits this to 10)." % count), "warning" ) else: segment_opts = {} return self.createCampaign(api_key, method, subject, create_draft, schedule, rendered, next_url, segment_opts)
class CampaignView(BrowserView): template = ViewPageTemplateFile('campaign.pt') title = _(u"Preview") def results(self, start, until=None): today = DateTime() today = DateTime(today.year(), today.month(), today.day()) start = DateTime(start) start = DateTime(start.year(), start.month(), start.day()) query = Indexed('chimpfeeds') & \ In('review_state', ('published', )) & \ Ge('feedSchedule', start) if until: try: until = DateTime(until) except DateTime.SyntaxError: pass else: query = query & Le('feedSchedule', until) site = getToolByName(self.context, "portal_url").getPortalObject() settings = IFeedSettings(site) if settings.use_moderation: query = query & Eq('feedModerate', True) catalog = getToolByName(self.context, "portal_catalog") extras = [] utilities = getUtilitiesFor(IGroupExtras) groups = InterestGroupVocabulary()(self.context) for name, util in utilities: for group in groups: extras.extend(util.items(group.title, start, until)) return list(catalog.evalAdvancedQuery( query, (('feedSchedule', 'desc'), ))) + extras def getGroupings(self, start, until=None): groupings = {} for brain in self.results(start, until=until): # Note that an item can appear in more than one group. categories = [name.rsplit(':', 1)[0] for name in brain.chimpfeeds] for category in set(categories): items = groupings.setdefault(category, []) items.append(brain) sorting = queryUtility(IGroupSorter) if sorting is None: key = lambda name, items: name else: key = sorting.key return sorted(groupings.items(), key=lambda item: key(*item)) def getSegments(self, start, until=None, **kwargs): chimpfeeds = set() for brain in self.results(start, until=until): chimpfeeds.update( (feed.replace(' ', '') for feed in brain.chimpfeeds) ) segments = {} for term in InterestGroupVocabulary()(self.context): if term.title.replace(' ', '') in chimpfeeds: groupingid, grouptitle, groupid = term.value items = segments.setdefault(groupingid, []) items.append(groupid) return segments
def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return settings = IFeedSettings(self.context) api_key = settings.mailchimp_api_key next_url = self.nextURL() try: list_id = (data.pop('list_id', None) or self.getContent().mailinglist) try: name = data.pop('name') except KeyError: name = '' email = data.pop('email') interests = data.pop('interests') content = self.getContent() preselected = getattr(content, 'preselected_interest_groups', None) if preselected: if not interests: interests = preselected else: interests = interests + preselected if api_key: api = greatape.MailChimp(api_key, debug=False) # Negotiate language language = negotiate(self.request) # Split full name into first (given) and last name. try: fname, lname = queryUtility( INameSplitter, name=language, default=GenericNameSplitter).split_name(name) except AttributeError: fname, lname = u'', u'' # Log subscription attempt. logger.info(("listSubscribe(%r, %r, %r, %r)" % (list_id, email, fname, lname)).encode('utf-8')) merge_vars = { 'FNAME': fname.encode('utf-8'), 'LNAME': lname.encode('utf-8'), 'GROUPINGS': [ dict( id=grouping_id, groups=",".join( group.encode('utf-8').replace(',', '\\,') for group in group_names), ) for (grouping_id, group_names ) in create_groupings(interests).items() ] } for name, value in data.items(): if value is not None: merge_vars[name.upper()] = value.encode('utf-8') try: result = api(method="listSubscribe", id=list_id, email_address=email, update_existing=True, replace_interests=False, merge_vars=merge_vars) except greatape.MailChimpError, exc: logger.warn(exc.msg) # ... is not a valid interest grouping id for the list if exc.code == 270: return IStatusMessage(self.request).addStatusMessage( _(u"There was a problem signing you up for " u"the selected interest groups. This could " u"mean that the subscription service is " u"configured incorrectly. Please contact " u"the webmaster."), "error", ) else: if result: next_url += ('?' in next_url and '&' or '?') + 'success=yes' return IStatusMessage(self.request).addStatusMessage( _(u"Thank you for signing up. We'll send you a " u"confirmation message by e-mail shortly."), "info") IStatusMessage(self.request).addStatusMessage( _( u"An error occurred while processing your " u"request to sign up for ${email}. " u"Please try again!", mapping={'email': email}), "error")
def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return settings = IFeedSettings(self.context) api_key = settings.mailchimp_api_key try: list_id = self.context.mailinglist email = data['email'] name = data['name'] interests = data['interests'] if api_key: api = greatape.MailChimp(api_key, debug=False) # Negotiate language language = negotiate(self.request) # Split full name into first (given) and last name. fname, lname = queryUtility( INameSplitter, name=language, default=GenericNameSplitter ).split_name(name) try: result = api( method="listSubscribe", id=list_id, email_address=email, update_existing=True, replace_interests=False, merge_vars={ 'FNAME': fname.encode('utf-8'), 'LNAME': lname.encode('utf-8'), 'GROUPINGS': [ dict( id=grouping_id, groups=",".join( group.\ encode('utf-8').\ replace(',', '\\,') for group in group_names ), ) for (grouping_id, group_names) in create_groupings(interests).items() ] }, ) except greatape.MailChimpError, exc: logger.warn(exc.msg) else: if result: return IStatusMessage(self.request).addStatusMessage( _(u"Thank you for signing up. We'll send you a " u"confirmation message by e-mail shortly."), "info" ) IStatusMessage(self.request).addStatusMessage( _(u"An error occurred while processing your " u"request to sign up for ${email}. " u"Please try again!", mapping={'email': email}), "error")
def get_terms(self): yield SimpleTerm(u"", "", _(u"Empty")) for value, name in self.get_templates(): yield SimpleTerm(value, value, name)
def handleApprove(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return catalog = self.context.portal_catalog bumped = [] today = datetime.date.today() uids = [] for rid in data['items'] or (): metadata = catalog.getMetadataForRID(rid) uids.append(metadata['UID']) settings = IFeedSettings(self.context) brains = catalog.unrestrictedSearchResults(UID=uids) for brain in brains: obj = brain.getObject() # Bump the scheduled date to today's date. This ensures that # the item will be shown on the moderation portlet. try: date = obj.getField('feedSchedule').get(obj) if date is not None: date = date.asdatetime().date() except AttributeError: date = obj.feedSchedule if settings.bump_date_on_moderation and (date is None or date < today): try: field = obj.getField('feedSchedule') except AttributeError: obj.feedSchedule = today else: field.set(obj, DateTime( today.year, today.month, today.day )) bumped.append(obj) try: field = obj.getField('feedModerate') except AttributeError: obj.feedModerate = True else: field.set(obj, True) # Reindex entire object (to make sure the metadata is # updated, too). obj.reindexObject() if data['items']: self.widgets['items'].update() if bumped: IStatusMessage(self.request).addStatusMessage( _(u"The scheduled date has been set to today's date " u"for the following items that were scheduled to " u"a date in the past: ${titles}.", mapping={'titles': u', '.join( [obj.Title().decode('utf-8') for obj in bumped])}), "info", )
def render(self): return _(self.error.__doc__)
return not settings.use_moderation moderation_enabled = moderation_enabled() class settings_available: def __nonzero__(self): context = getSite() return IFeedSettings(context, None) is None settings_available = settings_available() IFeedControl.setTaggedValue(WRITE_PERMISSIONS_KEY, {"feedModerate": MODERATE_PERMISSION}) IFeedControl.setTaggedValue( OMITTED_KEY, ( (IAutoExtensibleForm, "feeds", settings_available), (IAutoExtensibleForm, "feedModerate", settings_available), (IAutoExtensibleForm, "feedSchedule", settings_available), (IAutoExtensibleForm, "feedModerate", moderation_enabled), ), ) IFeedControl.setTaggedValue( FIELDSETS_KEY, [ Fieldset("dates", fields=["feedSchedule", "feedModerate"], label=_(u"Dates")), Fieldset("categorization", fields=["feeds"], label=_(u"Categorization")), ], )
def fields(self): fields = field.Fields() settings = IFeedSettings(self.context) # Javascript-widget if settings.enable_select_all: fields += field.Fields(SelectAllGroupsJavascript(schema.Field( __name__="js", required=False), mode="hidden")) # Include form fields, but change the order around. fields += field.Fields(ISubscription).select('interests') fields['interests'].widgetFactory = InterestsWidget.factory if settings.show_name: fields += field.Fields( schema.TextLine( __name__="name", title=_(u"Name"), required=False, ) ) fields += field.Fields(ISubscription).select('email') # Add mailinglist as hidden field fields += field.Fields(schema.ASCII( __name__="list_id", required=True), mode="hidden" ) context = self.getContent() api = getUtility(IApiUtility, context=self.context) result = api.list_merge_vars(context.mailinglist) for entry in result: name = entry['tag'].lower() if name in fields: continue if not entry['show']: continue # Skip all-uppercase: if entry['name'] == entry['name'].upper(): continue field_type = entry['field_type'] required = entry['req'] if field_type == 'text': factory = schema.TextLine options = {} elif field_type == 'dropdown': factory = schema.Choice choices = list(entry['choices']) if not required: choices.append(u"") required = True options = { 'vocabulary': SimpleVocabulary([ SimpleTerm(value=value, token=value.encode( 'ascii', 'xmlcharrefreplace'), title=value or _(u"None")) for value in choices]) } else: continue fields += field.Fields(factory( __name__=name.encode('utf-8'), default=entry['default'], required=required, title=_(entry['name']), **options )) return fields
class ControlPanelEditForm(controlpanel.RegistryEditForm): schema = IFeedSettings fields = field.Fields(IControlPanel) label = _(u"MailChimp settings") description = _(u"Please configure an API-key and define one or more " u"feeds.") fields['urls'].mode = "display" fields['urls'].widgetFactory = UrlsWidget.factory fields['lists'].mode = "display" fields['lists'].widgetFactory = UrlsWidget.factory if textlines is not None: fields['feeds'].widgetFactory = textlines.TextLinesFieldWidget buttons = button.Buttons() buttons += controlpanel.RegistryEditForm.buttons handlers = controlpanel.RegistryEditForm.handlers.copy() def updateActions(self): # This prevents a redirect to the main control panel page self.request.response.setStatus(200, lock=True) super(ControlPanelEditForm, self).updateActions() def render(self): if switch_on is not None: switch_on(self) urls = self.widgets['urls'] urls.update() if not urls.value: del self.widgets['urls'] return super(ControlPanelEditForm, self).render() def getContent(self): content = super(ControlPanelEditForm, self).getContent() return ImplicitAcquisitionWrapper(content, self.context) @button.buttonAndHandler(_(u"Repair"), name='repair') def handleRepair(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return query = Indexed('chimpfeeds') brains = self.context.portal_catalog.evalAdvancedQuery(query) context = self.getContent() vocabulary = feeds_factory(context) all_feeds = set(term.value for term in vocabulary) count = 0 bad = set() changed = [] for i, brain in enumerate(brains): try: feeds = set(brain.chimpfeeds) except TypeError: continue missing = feeds - all_feeds bad |= missing if missing: count += 1 obj = brain.getObject() try: field = obj.getField('feeds') except AttributeError: feeds = obj.feeds field = None else: feeds = set(field.get(obj)) fixed = feeds - missing if field is None: obj.feeds = fixed else: field.set(obj, fixed) changed.append(obj) for obj in changed: modified(obj) obj.reindexObject() logger.info("Repair complete; %d items updated." % count) if bad: logger.info("Feeds removed: %s." % (", ".join(bad).encode('utf-8'))) IStatusMessage(self.request).addStatusMessage( _(u"Repaired ${count} items.", mapping={'count': count}), "info")
def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return settings = IFeedSettings(self.context) api_key = settings.mailchimp_api_key next_url = self.nextURL() try: list_id = ( data.pop('list_id', None) or self.getContent().mailinglist ) try: name = data.pop('name') except KeyError: name = '' email = data.pop('email') interests = data.pop('interests') content = self.getContent() preselected = getattr(content, 'preselected_interest_groups', None) if preselected: if not interests: interests = preselected else: interests = interests + preselected if api_key: api = greatape.MailChimp(api_key, debug=False) # Negotiate language language = negotiate(self.request) # Split full name into first (given) and last name. try: fname, lname = queryUtility( INameSplitter, name=language, default=GenericNameSplitter ).split_name(name) except AttributeError: fname, lname = u'', u'' # Log subscription attempt. logger.info(("listSubscribe(%r, %r, %r, %r)" % ( list_id, email, fname, lname)).encode('utf-8')) merge_vars = { 'FNAME': fname.encode('utf-8'), 'LNAME': lname.encode('utf-8'), 'GROUPINGS': [ dict( id=grouping_id, groups=",".join( group. encode('utf-8'). replace(',', '\\,') for group in group_names ), ) for (grouping_id, group_names) in create_groupings(interests).items() ] } for name, value in data.items(): if value is not None: merge_vars[name.upper()] = value.encode('utf-8') try: result = api( method="listSubscribe", id=list_id, email_address=email, update_existing=True, replace_interests=False, merge_vars=merge_vars ) except greatape.MailChimpError, exc: logger.warn(exc.msg) # ... is not a valid interest grouping id for the list if exc.code == 270: return IStatusMessage(self.request).addStatusMessage( _(u"There was a problem signing you up for " u"the selected interest groups. This could " u"mean that the subscription service is " u"configured incorrectly. Please contact " u"the webmaster."), "error", ) else: if result: next_url += ('?' in next_url and '&' or '?') + 'success=yes' return IStatusMessage(self.request).addStatusMessage( _(u"Thank you for signing up. We'll send you a " u"confirmation message by e-mail shortly."), "info" ) IStatusMessage(self.request).addStatusMessage( _(u"An error occurred while processing your " u"request to sign up for ${email}. " u"Please try again!", mapping={'email': email}), "error")
def title(self): return _("Subscribe: ${title}", mapping={'title': self.heading})
IFeedControl.setTaggedValue( OMITTED_KEY, ( (IAutoExtensibleForm, 'feeds', settings_available), (IAutoExtensibleForm, 'feedModerate', settings_available), (IAutoExtensibleForm, 'feedSchedule', settings_available), (IAutoExtensibleForm, 'feedModerate', moderation_enabled), ) ) IFeedControl.setTaggedValue( FIELDSETS_KEY, [Fieldset( 'dates', fields=['feedSchedule', 'feedModerate'], label=_(u"Dates")), Fieldset( 'categorization', fields=['feeds'], label=_(u"Categorization")), ] ) IFeedControl.setTaggedValue( WIDGETS_KEY, {'feeds': 'z3c.form.browser.checkbox.CheckBoxFieldWidget'} ) class IGroupExtras(Interface):
def createCampaign(self, api_key, method, subject, create_draft, schedule, rendered, next_url, segment_opts={}): try: if not rendered.strip(): IStatusMessage(self.request).addStatusMessage( _(u"No content found; newsletter not created."), "info" ) return if api_key: api = greatape.MailChimp(api_key, debug=False) try: for entry in api(method="lists"): if entry['id'] == self.context.mailinglist: break else: IStatusMessage(self.request).addStatusMessage( _(u"Mailinglist not found."), "error" ) return if self.context.template: section = 'html_%s' % self.context.section else: section = 'html' args = {} args['method'] = method args['type'] = 'regular' args['content'] = {section: rendered} if segment_opts: args['segment_opts'] = segment_opts options = {} options['subject'] = subject.encode("utf-8") or \ entry['default_subject'] options['from_email'] = entry['default_from_email'] options['from_name'] = \ entry['default_from_name'].encode("utf-8") options['to_email'] = 0 options['list_id'] = self.context.mailinglist options['template_id'] = self.context.template or None options['generate_text'] = True args['options'] = options result = api(**args) if result: if not create_draft: if schedule: # Apply local time zone to get GMT schedule = schedule + datetime.timedelta( seconds=time.timezone ) # Format time schedule_time = time.strftime( "%Y-%m-%d %H:%M:%S", schedule.utctimetuple() ) schedule = api( method="campaignSchedule", cid=result, schedule_time=schedule_time, ) if not schedule: IStatusMessage(self.request).addStatusMessage( _(u"Campaign created, but not scheduled."), "error" ) return else: api(method="campaignSendNow", cid=result) next_url = self.context.portal_url() + \ "/@@chimpfeed-content?cid=%s" % result except greatape.MailChimpError, exc: IStatusMessage(self.request).addStatusMessage( _(u"Unable to process request: ${message}", mapping={'message': exc.msg}), "error" ) logger.warn(exc.msg) logger.warn(pprint.pformat(args)) return return bool(result) finally: self.request.response.redirect(next_url)
def handleCancel(self, action): IStatusMessage(self.request).addStatusMessage( _(u"Edit cancelled."), "info" ) self._redirect()
def label(self): if self.request.get('success'): return _(u"Request processed") name = self.getContent().name return _(u"Subscribe to: ${name}", mapping={'name': name})