def unsubscribe(self): """ """ if protect is not None: alsoProvides(self.request, protect.interfaces.IDisableCSRFProtection) putils = getToolByName(self.context, "plone_utils") uid = self.request.get("subscriber") newsletter = self.context if not INewsletter.providedBy(newsletter): putils.addPortalMessage( _("Please use the correct unsubscribe url!"), "error") return self.request.response.redirect( api.portal.get_navigation_root(self).absolute_url()) # We do the deletion as the owner of the newsletter object # so that this is possible without login. owner = newsletter.getWrappedOwner() newSecurityManager(newsletter, owner) subscriber = api.content.get(UID=uid) if subscriber is None or not INewsletterSubscriber.providedBy( subscriber): putils.addPortalMessage(_("An error occured"), "error") else: del newsletter[subscriber.id] putils.addPortalMessage(_("You have been unsubscribed.")) return self.request.response.redirect( api.portal.get_navigation_root(self).absolute_url())
def send_issue(self): """ sets workflow state to sending and then redirects to step2 with UID as parameter as simple safety belt. """ PostOnly(self.request) if 'test' in self.request.form: # test must not modify the state self.context.send() api.portal.show_message( message=_('The issue test sending has been initiated.'), request=self.request, ) return self.request.response.redirect(self.context.absolute_url()) if self.context.issue_queue is not None: self._send_issue_prepare() self.context.queue_issue_for_sendout() api.portal.show_message( message=_( 'The issue sending has been initiated in the background.' ), request=self.request, ) return self.request.response.redirect(self.context.absolute_url()) # No queuing but direct send self.send_issue_immediately() api.portal.show_message( message=_( 'The issue has been generated and sent to the mail server.' ), request=self.request, ) return self.request.response.redirect(self.context.absolute_url())
def confirm_subscriber(self): hashkey = self.request.get('hkey') enl_registration_tool = queryUtility(IENLRegistrationTool, 'enl_registration_tool') regdataobj = enl_registration_tool.get(hashkey) messages = IStatusMessage(self.request) if regdataobj: easynewsletter = self.portal.unrestrictedTraverse( regdataobj.path_to_easynewsletter) valid_email, error_code = easynewsletter.addSubscriber( regdataobj.subscriber, regdataobj.firstname, regdataobj.lastname, regdataobj.name_prefix, regdataobj.nl_language, regdataobj.organization, regdataobj.salutation) if valid_email: # now delete the regobj del enl_registration_tool[hashkey] messages.addStatusMessage( _("Your subscription was successfully confirmed."), "info") else: messages.addStatusMessage(MESSAGE_CODE[error_code], "error") self._msg_redirect(easynewsletter) else: messages.addStatusMessage(_("Please enter a valid email address."), "error") return self.request.response.redirect(self.context.absolute_url())
def confirm_subscriber(self): hashkey = self.request.get('hkey') enl_registration_tool = queryUtility( IENLRegistrationTool, 'enl_registration_tool') regdataobj = enl_registration_tool.get(hashkey) messages = IStatusMessage(self.request) if regdataobj: easynewsletter = self.portal.unrestrictedTraverse( regdataobj.path_to_easynewsletter) valid_email, error_code = easynewsletter.addSubscriber( regdataobj.subscriber, regdataobj.firstname, regdataobj.lastname, regdataobj.name_prefix, regdataobj.nl_language, regdataobj.organization, regdataobj.salutation ) if valid_email: # now delete the regobj del enl_registration_tool[hashkey] messages.addStatusMessage( _("Your subscription was successfully confirmed."), "info") else: messages.addStatusMessage(MESSAGE_CODE[error_code], "error") self._msg_redirect(easynewsletter) else: messages.addStatusMessage( _("Please enter a valid email address."), "error") return self.request.response.redirect(self.context.absolute_url())
def send_unsubscribe_email(self, subscriber): newsletter = self.context catalog = getToolByName(self.context, "portal_catalog") query = {} query["portal_type"] = "ENLSubscriber" query["email"] = subscriber results = catalog.unrestrictedSearchResults(query) messages = IStatusMessage(self.request) if results: subscriber_brain = results[0] unsubscribe_url = self.newsletter_url +\ '/unsubscribe?subscriber=' + subscriber_brain.UID msg_text = """%s: %s""" % ( newsletter.getUnsubscribe_string(), unsubscribe_url) api.portal.send_email( recipient=subscriber, sender=self.context.email_from_address, subject=_(u"confirm newsletter unsubscription"), body=msg_text, ) messages.addStatusMessage( _("We send you an email, please confirm this unsubscription."), "info") else: # todo: write an extra error msg if a plone user wants to # unsubscribe himself messages.addStatusMessage( _("Your email address could not be found in subscribers."), "error")
def __call__(self): """ sets workflow state to sending and then redirects to step2 with UID as parameter as simple safety belt. """ PostOnly(self.request) if self.is_test: # test must not modify the state self.send() api.portal.show_message( message=_("The issue test sending has been initiated."), request=self.request, ) return self.request.response.redirect(self.context.absolute_url()) # XXX implement this: # if self.context.issue_queue is not None: # self._send_issue_prepare() # self.context.queue_issue_for_sendout() # api.portal.show_message( # message=_("The issue sending has been initiated in the background."), # request=self.request, # ) # return self.request.response.redirect(self.context.absolute_url()) # No queuing but direct send # self._send_issue_prepare() self.send_issue_immediately() api.portal.show_message( message=_( "The issue has been generated and sent to the mail server."), request=self.request, ) return self.request.response.redirect(self.context.absolute_url())
def send_unsubscribe_email(self, subscriber): newsletter = self.context catalog = getToolByName(self.context, "portal_catalog") query = {} query["portal_type"] = "ENLSubscriber" query["email"] = subscriber results = catalog.unrestrictedSearchResults(query) messages = IStatusMessage(self.request) if results: subscriber_brain = results[0] unsubscribe_url = self.newsletter_url +\ '/unsubscribe?subscriber=' + subscriber_brain.UID msg_text = """%s: %s""" % (newsletter.getUnsubscribe_string(), unsubscribe_url) settings = get_portal_mail_settings() api.portal.send_email( recipient=subscriber, sender=settings.email_from_address, subject=_(u"confirm newsletter unsubscription"), body=msg_text, ) messages.addStatusMessage( _("We send you an email, please confirm this unsubscription."), "info") else: # todo: write an extra error msg if a plone user wants to # unsubscribe himself messages.addStatusMessage( _("Your email address could not be found in subscribers."), "error")
def register_subscriber(self): """ """ subscriber = self.request.get("subscriber") fullname = self.request.get("fullname", "") salutation = self.request.get("salutation", "") organization = self.request.get("organization", "") path_to_easynewsletter = self.request.get("newsletter") # remove leading slash from paths like: /mynewsletter path_to_easynewsletter = path_to_easynewsletter.strip('/') newsletter_container = self.portal.restrictedTraverse(path_to_easynewsletter) messages = IStatusMessage(self.request) if not salutation: messages.addStatusMessage(_("Please choose a salutation."), "error") return self.request.response.redirect(newsletter_container.absolute_url()) if not subscriber: messages.addStatusMessage(_("Please enter a valid email address."), "error") return self.request.response.redirect(newsletter_container.absolute_url()) from Products.validation.validators.BaseValidators import EMAIL_RE EMAIL_RE = "^" + EMAIL_RE mo = re.search(EMAIL_RE, subscriber) if not mo: messages.addStatusMessage(_("Please enter a valid email address."), "error") return self.request.response.redirect(newsletter_container.absolute_url()) if subscriber in newsletter_container.objectIds(): messages.addStatusMessage(_("Your email address is already registered."), "error") return self.request.response.redirect(newsletter_container.absolute_url()) subscriber_data = {} subscriber_data["subscriber"] = subscriber subscriber_data["fullname"] = fullname subscriber_data["salutation"] = salutation subscriber_data["organization"] = organization subscriber_data["path_to_easynewsletter"] = path_to_easynewsletter # use password reset tool to create a hash pwr_data = self._requestReset(subscriber) hashkey = pwr_data['randomstring'] enl_registration_tool = queryUtility(IENLRegistrationTool, 'enl_registration_tool') if hashkey not in enl_registration_tool.objectIds(): enl_registration_tool[hashkey] = RegistrationData(hashkey, **subscriber_data) msg_subject = newsletter_container.getRawSubscriber_confirmation_mail_subject().replace( "${portal_url}", self.portal_url.strip('http://')) confirmation_url = self.portal_url + '/confirm-subscriber?hkey=' + str(hashkey) msg_text = newsletter_container.getRawSubscriber_confirmation_mail_text().replace("${newsletter_title}", newsletter_container.Title()) msg_text = msg_text.replace("${subscriber_email}", subscriber) msg_text = msg_text.replace("${confirmation_url}", confirmation_url) msg_sender = self.portal.getProperty('email_from_address') msg_receiver = subscriber msg = MIMEText(msg_text) msg['To']= msg_receiver msg['From'] = msg_sender msg['Subject'] = msg_subject #msg.epilogue = '' self.portal.MailHost.send(msg.as_string()) messages.addStatusMessage(_("Your email has been registered. \ A confirmation email was sent to your address. Please check \ your inbox and click on the link in the email in order to \ confirm your subscription."), "info") self.request.response.redirect(newsletter_container.absolute_url())
class IENLSettings(Interface): """ """ allowed_content_aggregation_types = schema.List( required=False, title=_(u'Allowed content aggregation types'), description=_(u'Content types which will be visbile in the Content' u' aggregation sources reference field.'), value_type=schema.TextLine(title=_('Content type')), )
class EditForm(base.EditForm): """ """ if IS_PLONE_5: schema = INewsletterSubscriberPortlet else: # BBB form_fields = form.Fields(INewsletterSubscriberPortlet) label = _(u"Edit Newsletter portlet") description = _( u"This portlet displays the subscriber add form of a newsletter.")
def delete(self): """delete all the selected subscribers""" ids = self.request.get("subscriber_ids", []) if not ids: msg = _("No subscriber selected!") api.portal.show_message(msg, request=self.request, type="error") return False existing = self.context.objectIds() # avoid wrong id to be submitted to_remove = [i for i in ids if i in existing] self.context.manage_delObjects(to_remove) msg = _("subscriber/s deleted successfully") api.portal.show_message(msg, request=self.request, type="info") return True
class INewsletterSubscriber(model.Schema): """Marker interface and Dexterity Python Schema for NewsletterSubscriber""" salutation = schema.Choice( title=_("EasyNewsletter_label_salutation", default="Salutation"), description=_("EasyNewsletter_help_salutation", default=""), vocabulary="Products.EasyNewsletter.Salutations", required=False, ) name_prefix = schema.TextLine( title=_("EasyNewsletter_label_name_prefix", default="Name Prefix"), description=_("EasyNewsletter_help_name_prefix", default=""), default="", required=False, ) firstname = schema.TextLine( title=_("EasyNewsletter_label_firstname", default="First Name"), required=False, ) lastname = schema.TextLine(title=_("EasyNewsletter_label_lastname", default="Last Name"), required=False) organization = schema.TextLine( title=_("EasyNewsletter_label_organization", default="Organization"), required=False, ) email = schema.TextLine(title=_("EasyNewsletter_label_email", default="Email"), required=True)
def send_issue(self): """ """ putils = getToolByName(self.context, "plone_utils") self.context.send() putils.addPortalMessage(_("The issue has been send.")) return self.request.response.redirect(self.context.absolute_url())
def __call__(self, context): items = [] registry = getUtility(IRegistry) output_templates = registry.get( "Products.EasyNewsletter.output_templates") for key, value in output_templates.items(): items.append(VocabItem(key, value)) if not len(items): items.append( VocabItem( "output_default", _("enl_label_default_output_template", "Default output template"), )) # Fix context if you are using the vocabulary in DataGridField. # See https://github.com/collective/collective.z3cform.datagridfield/issues/31: # NOQA: 501 if not IDexterityContent.providedBy(context): req = getRequest() context = req.PARENTS[0] # create a list of SimpleTerm items: terms = [] for item in items: terms.append( SimpleTerm(value=item.token, token=str(item.token), title=item.value)) # Create a SimpleVocabulary from the terms list and return it: return SimpleVocabulary(terms)
def delete(self): """ delete all the selected subscribers """ msg_manager = IStatusMessage(self.request) ids = self.request.get('subscriber_ids', []) if not ids: msg = _(u"No subscriber selected!") msg_manager.addStatusMessage(msg, type='error') return False existing = self.context.objectIds() # avoid wrong id to be submitted to_remove = [i for i in ids if i in existing] self.context.manage_delObjects(to_remove) msg = _(u"subscriber/s deleted successfully") msg_manager.addStatusMessage(msg, type="info") return True
def get_delivery_services(self): result = atapi.DisplayList() result.add(u'mailhost', _(u'EasyNewsletter_label_PloneMailHost', u'Default Plone Mailhost')) for utility in getUtilitiesFor(IMailHost): if utility[0]: result.add(utility[0], utility[0]) return result
def __call__(self, value=None, *args, **kwargs): instance = kwargs.get('instance') if instance is not None: folder = instance.aq_parent identifier = getToolByName(instance, 'plone_utils').normalizeString(value).lower() if folder._getOb(identifier, instance) != instance: return _(u"Duplicate registration.") return 1
def get_subscriber_sources(self): result = atapi.DisplayList() result.add(u'default', _( u'EasyNewsletter_label_noSource', u'no external subscriber source')) for utility in getUtilitiesFor(ISubscriberSource): result.add(utility[0], utility[0]) return result
def get_delivery_services(self): result = atapi.DisplayList() result.add(u'mailhost', _( u'EasyNewsletter_label_PloneMailHost', u'Default Plone Mailhost')) for utility in getUtilitiesFor(IMailHost): if utility[0]: result.add(utility[0], utility[0]) return result
class ICollectionAsNewsletterAggregationSource(model.Schema): """ """ model.fieldset( "settings", label=_("Settings"), fields=["aggregation_template"], ) aggregation_template = schema.Choice( title=_("Newsletter aggregation template"), description= _('The <a href="https://productseasynewsletter.readthedocs.io/en/latest/#aggregation-templates">aggregation template</a> used by the Newsletter to render Collection items for the Newsletter.' ), vocabulary="Products.EasyNewsletter.AggregationTemplates", # defaultFactory=get_default_aggregation_template, required=True, )
def send_unsubscribe_email(self, subscriber): newsletter = self.context catalog = api.portal.get_tool(name="portal_catalog") query = {} query["portal_type"] = "Newsletter Subscriber" query["email"] = subscriber results = catalog.unrestrictedSearchResults(query) if results: subscriber_brain = results[0] unsubscribe_url = ( self.newsletter_url + "/unsubscribe?subscriber=" + subscriber_brain.UID ) unsubscribe_header_msgid = _( "you_requested_to_unsubscribe", default="You requested to unsubscribe from the following newsletter: ${title}", mapping={"title": newsletter.title}, ) msg_text = "{0}\n{1}: {2}".format( translate(unsubscribe_header_msgid), newsletter.unsubscribe_string, unsubscribe_url, ) settings = get_portal_mail_settings() api.portal.send_email( recipient=subscriber, sender=settings.email_from_address, subject="{0}: {1}".format( newsletter.title, _("confirm newsletter unsubscription") ), body=msg_text, ) api.portal.show_message( message=_("We send you an email, please confirm this unsubscription."), request=self.request, type="info", ) else: # todo: write an extra error msg if a plone user wants to # unsubscribe himself api.portal.show_message( message=_("Your email address could not be found in subscribers."), request=self.request, type="error", )
def subscribers(self): query = dict( portal_type="Newsletter Subscriber", context=self.context, sort_on="email", ) form = self.request.form for k in self.searchable_params: if form.get(k): if k == "SearchableText": searchterm = form.get(k) if not searchterm.endswith("*"): searchterm += "*" query[k] = searchterm else: query[k] = form.get(k) subscribers = list() # Plone subscribers for brain in api.content.find(**query): if brain.salutation: salutation = config.SALUTATION.get(brain.salutation, "") else: salutation = "" subscribers.append( dict( id=brain.getId, source="plone", deletable=True, email=brain.email, getURL=brain.getURL(), salutation=salutation, name_prefix=brain.name_prefix, firstname=brain.firstname, lastname=brain.lastname, nl_language=brain.nl_language, organization=brain.organization, ) ) # External subscribers ext_subcriber_source = self.context.get('subscriber_source') if ext_subcriber_source: if ext_subcriber_source != "default": try: external_source = getUtility( ISubscriberSource, name=ext_subcriber_source ) except ComponentLookupError: log.warn(_(u'label_ext_subcriber_source_failed', default=u"External subscriber lookup failed")) else: for subscriber in external_source.getSubscribers(self.context): subscriber["source"] = ext_subcriber_source subscribers.append(subscriber) return subscribers
def confirm_subscriber(self): hashkey = self.request.get("hkey") enl_registration_tool = queryUtility(IENLRegistrationTool, "enl_registration_tool") regdataobj = enl_registration_tool.get(hashkey) messages = IStatusMessage(self.request) if regdataobj: portal = api.portal.get() easynewsletter = portal.unrestrictedTraverse( regdataobj.path_to_easynewsletter) email = regdataobj.subscriber plone_utils = api.portal.get_tool(name="plone_utils") subscriber_id = plone_utils.normalizeString(email) try: execute_under_special_role( portal, "Contributor", api.content.create, type="Newsletter Subscriber", id=subscriber_id, language=self.context.language, email=email, firstname=regdataobj.firstname, lastname=regdataobj.lastname, name_prefix=regdataobj.name_prefix, # nl_language=regdataobj.nl_language, organization=regdataobj.organization, salutation=regdataobj.salutation, container=easynewsletter, ) except BadRequest: error_code = "email_exists" messages.addStatusMessage(MESSAGE_CODE[error_code], "error") else: # now delete the regobj del enl_registration_tool[hashkey] messages.addStatusMessage( _("Your subscription was successfully confirmed."), "info") return self._msg_redirect(easynewsletter) else: messages.addStatusMessage(_("Please enter a valid email address."), "error") return self.request.response.redirect(self.context.absolute_url())
def test_vocab_plone_users(self): vocab_name = "Products.EasyNewsletter.PloneUsers" factory = getUtility(IVocabularyFactory, vocab_name) self.assertTrue(IVocabularyFactory.providedBy(factory)) vocabulary = factory(self.portal) self.assertTrue(IVocabularyTokenized.providedBy(vocabulary)) self.assertEqual( vocabulary.getTerm(self.jane.getId()).title, _("Jane Doe - [email protected]") )
class IPloneUserGroupRecipients(model.Schema): """ """ model.fieldset( "recipients", label=_("Recipients"), fields=["plone_receiver_members", "plone_receiver_groups"], ) plone_receiver_members = schema.Set( title=_( "EasyNewsletter_label_ploneReceiverMembers", default="Plone Members to receive the newsletter", ), description=_( "EasyNewsletter_help_ploneReceiverMembers", default="Choose Plone Members which should receive \ the newsletter. Changing this setting does not affect \ already existing issues.", ), value_type=schema.Choice( vocabulary="Products.EasyNewsletter.PloneUsers"), required=False, defaultFactory=get_default_plone_receiver_members, ) plone_receiver_groups = schema.Set( title=_( "EasyNewsletter_label_ploneReceiverGroups", default="Plone Groups to receive the newsletter", ), description=_( "EasyNewsletter_help_ploneReceiverGroups", default="Choose Plone Groups which should receive \ the newsletter. Changing this setting does not affect \ already existing issues.", ), value_type=schema.Choice( vocabulary="Products.EasyNewsletter.PloneGroups"), required=False, defaultFactory=get_default_plone_receiver_groups, )
def test_vocab_salutations(self): vocab_name = 'Products.EasyNewsletter.Salutations' factory = getUtility(IVocabularyFactory, vocab_name) self.assertTrue(IVocabularyFactory.providedBy(factory)) vocabulary = factory(self.portal) self.assertTrue(IVocabularyTokenized.providedBy(vocabulary)) self.assertEqual( vocabulary.getTerm('ms').title, _(u'Ms'), )
def __call__(self): if 'reset_statistics' in self.request.form: status_adapter = ISendStatus(self.context) if status_adapter: status_adapter.clear() api.portal.show_message( message=_('Newsletter issue statistics have been reset.'), request=self.request, type='info', ) return super(NewsletterIssueStatistics, self).__call__()
def test_vocab_aggregation_templates(self): vocab_name = "Products.EasyNewsletter.AggregationTemplates" factory = getUtility(IVocabularyFactory, vocab_name) self.assertTrue(IVocabularyFactory.providedBy(factory)) vocabulary = factory(self.portal) self.assertTrue(IVocabularyTokenized.providedBy(vocabulary)) self.assertEqual( vocabulary.getTerm("aggregation_generic_listing").title, _("Generic Listing"), )
def test_vocab_output_templates(self): vocab_name = "Products.EasyNewsletter.OutputTemplates" factory = getUtility(IVocabularyFactory, vocab_name) self.assertTrue(IVocabularyFactory.providedBy(factory)) vocabulary = factory(self.portal) self.assertTrue(IVocabularyTokenized.providedBy(vocabulary)) self.assertEqual( vocabulary.getTerm("output_default").title, _("Default output template"), )
def get_aggregation_templates(self): """ Return registered aggregation templates as DisplayList """ result = atapi.DisplayList() registry = getUtility(IRegistry) aggregation_templates = registry.get( 'Products.EasyNewsletter.content_aggregation_templates') for key, value in aggregation_templates.items(): result.add(key, value) result.add(u'custom', _(u'enl_label_custom_template', u'Custom template field')) return result
def unsubscribe(self): """ """ putils = getToolByName(self.context, "plone_utils") catalog = getToolByName(self.context, "reference_catalog") uid = self.request.get("subscriber") subscriber = catalog.lookupObject(uid) if subscriber is None: putils.addPortalMessage(_("An error occured"), "error") else: newsletter = self.context # We do the deletion as the owner of the newsletter object # so that this is possible without login. owner = newsletter.getWrappedOwner() newSecurityManager(newsletter, owner) del newsletter[subscriber.id] putils.addPortalMessage(_("You have been unsubscribed.")) return self.request.response.redirect(self.context.absolute_url())
def test_vocab_plone_groups(self): vocab_name = 'Products.EasyNewsletter.PloneGroups' factory = getUtility(IVocabularyFactory, vocab_name) self.assertTrue(IVocabularyFactory.providedBy(factory)) vocabulary = factory(self.portal) self.assertTrue(IVocabularyTokenized.providedBy(vocabulary)) self.assertEqual( vocabulary.getTerm(self.vip.getId()).title, _(u'VIP'), )
def __call__(self): """ """ alsoProvides(self.request, protect.interfaces.IDisableCSRFProtection) uid = self.request.get("subscriber") newsletter = self.context if not INewsletter.providedBy(newsletter): api.portal.show_message( message=_("Please use the correct unsubscribe url!"), request=self.request, type="error", ) return self.request.response.redirect( api.portal.get_navigation_root(self).absolute_url() ) # We do the deletion as the owner of the newsletter object # so that this is possible without login. owner = newsletter.getWrappedOwner() newSecurityManager(newsletter, owner) subscriber = api.content.get(UID=uid) if subscriber is None or not INewsletterSubscriber.providedBy(subscriber): api.portal.show_message( message=_("An error occured"), request=self.request, type="error", ) else: del newsletter[subscriber.id] api.portal.show_message( message=_("You have been unsubscribed."), request=self.request, type="info", ) return self.request.response.redirect( api.portal.get_navigation_root(self).absolute_url() )
def __call__(self, context): items = [ VocabItem("ms", _("Ms")), VocabItem("mr", _("Mr")), ] # Fix context if you are using the vocabulary in DataGridField. # See https://github.com/collective/collective.z3cform.datagridfield/issues/31: # NOQA: 501 if not IDexterityContent.providedBy(context): req = getRequest() context = req.PARENTS[0] # create a list of SimpleTerm items: terms = [] for item in items: terms.append( SimpleTerm( value=item.token, token=str(item.token), title=item.value, )) # Create a SimpleVocabulary from the terms list and return it: return SimpleVocabulary(terms)
def __call__(self): text = self.render_aggregation_sources() self.context.text = RichTextValue( raw=text, mimeType="text/html", outputMimeType="text/html", ) api.portal.show_message( message=_("Newsletter content successfully aggregated."), request=self.request, type="info", ) self.request.response.setHeader("Pragma", "no-cache") self.request.response.setHeader("Cache-Control", "no-cache") return self.request.response.redirect(self.context.absolute_url(), status=301)
def get_output_templates(self): """ Return registered output templates as DisplayList """ result = atapi.DisplayList() registry = getUtility(IRegistry) output_templates = registry.get( 'Products.EasyNewsletter.output_templates') if not output_templates: return result for key, value in output_templates.items(): result.add(key, value) if not len(result): result.add(u'output_default', _( u'enl_label_default_output_template', u'Default output template')) return result
def __call__(self): """Returns a CSV file with all newsletter subscribers. """ context = aq_inner(self.context) ctool = getToolByName(context, 'portal_catalog') # Create CSV file filename = tempfile.mktemp() file = open(filename, 'wb') csvWriter = UnicodeWriter(file, {'delimiter': ',', 'quotechar': '"', 'quoting': csv.QUOTE_MINIMAL}) CSV_HEADER_I18N = [self.context.translate(_(x)) for x in CSV_HEADER] csvWriter.writerow(CSV_HEADER_I18N) for subscriber in ctool(portal_type='ENLSubscriber', path='/'.join(self.context.getPhysicalPath()), sort_on='email'): obj = subscriber.getObject() csvWriter.writerow([obj.salutation, obj.name_prefix, obj.firstname, obj.lastname, obj.nl_language, obj.email, obj.organization]) file.close() data = open(filename, "r").read() # Create response response = context.REQUEST.response response.addHeader( 'Content-Disposition', "attachment; filename=easynewsletter-subscribers.csv") response.addHeader('Content-Type', 'text/csv') response.addHeader('Content-Length', "%d" % len(data)) response.addHeader('Pragma', "no-cache") response.addHeader( 'Cache-Control', "must-revalidate, post-check=0, pre-check=0, public") response.addHeader('Expires', "0") # Return CSV data return data
from AccessControl import ClassSecurityInfo from Products.Archetypes import atapi from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ from Products.EasyNewsletter import config from Products.EasyNewsletter.interfaces import IENLSubscriber from zope.interface import implementer schema = atapi.BaseSchema + atapi.Schema( ( atapi.StringField( "title", required=False, widget=atapi.StringWidget( visible={"edit": "invisible", "view": "invisible"}, label=_(u"EasyNewsletter_label_title", default=u"Title"), i18n_domain="EasyNewsletter", ), ), atapi.StringField( "salutation", required=False, vocabulary=config.SALUTATION, widget=atapi.SelectionWidget( label=_(u"EasyNewsletter_label_salutation", default="Salutation"), description=_("EasyNewsletter_help_salutation", default=u""), i18n_domain="EasyNewsletter", format="select", ), ), atapi.StringField(
def create_subscribers(self, csv_data=None): """Create newsletter subscribers from uploaded CSV file. """ # Do nothing if no submit button was hit if 'form.button.Import' not in self.request.form: return context = aq_inner(self.context) lang = context.Language() # plone_utils = getToolByName(self.context, 'plone_utils') # encoding = plone_utils.getSiteEncoding() existing = self.context.objectIds() # messages = IStatusMessage(self.request) success = [] fail = [] # Show error if no file was specified filename = self.request.form.get('csv_upload', None) if not filename: msg = _('No file specified.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.response.redirect( context.absolute_url() + '/@@upload_csv') # Show error if no data has been provided in the file reader = UnicodeReader(filename) header = reader.next() CSV_HEADER_I18N = [self.context.translate(_(x)) for x in CSV_HEADER] if header != CSV_HEADER_I18N: logger.info("Got header %s\n Expected:%s" % ( header, CSV_HEADER_I18N)) msg = _( 'Wrong specification of the CSV file. ' + 'Please correct it and retry.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.response.redirect( context.absolute_url() + '/@@upload_csv') for subscriber in reader: # Check the length of the line if len(subscriber) != 7: msg = _('The number of items in the line is not correct. \ It should be 7. Check your CSV file.') fail.append( {'failure': msg}) else: salutation = subscriber[0] name_prefix = subscriber[1] firstname = subscriber[2] lastname = subscriber[3] nl_language = subscriber[4] email = subscriber[5] organization = subscriber[6] id = normalize_id(email) if id in existing: msg = _('This email address is already registered.') fail.append( {'salutation': salutation, 'name_prefix': name_prefix, 'firstname': firstname, 'lastname': lastname, 'nl_language': nl_language, 'email': email, 'organization': organization, 'failure': msg}) else: title = email + " - " + ' '.join([lastname, firstname]) try: self.context.invokeFactory( 'ENLSubscriber', id=id, title=title, description="", language=lang) sub = context[id] sub.email = email sub.name_prefix = name_prefix sub.firstname = firstname sub.lastname = lastname sub.nl_language = nl_language sub.organization = organization sub.salutation = salutation obj = self.context.get(id, None) obj.reindexObject() # update existing existing.append(id) success.append({ 'salutation': salutation, 'name_prefix': name_prefix, 'firstname': firstname, 'lastname': lastname, 'nl_language': nl_language, 'email': email, 'organization': organization }) except Exception, e: fail.append({ 'salutation': salutation, 'name_prefix': name_prefix, 'firstname': firstname, 'lastname': lastname, 'nl_language': nl_language, 'email': email, 'organization': organization, 'failure': ( 'An error occured while creating ' + 'this subscriber: %s') % str(e)})
from Products.Archetypes import atapi from Products.CMFCore.utils import getToolByName from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ from Products.EasyNewsletter import config from Products.EasyNewsletter.interfaces import IENLTemplate from Products.TemplateFields import ZPTField from zope.interface import implementer schema = atapi.BaseSchema + atapi.Schema(( ZPTField( 'body', validators=('zptvalidator', ), widget=atapi.TextAreaWidget( label=_(u'label_body_zpt', default=u'Newsletter Template'), description=_( 'help_body_zpt', default=u'This is a Zope Page Template file that is used for \ rendering the newsletter mail.'), i18n_domain="plone", rows=30, ), ), atapi.TextField( 'description', accessor="Description", widget=atapi.TextAreaWidget( label=_(u"label_description", default=u'Description'), description=_(
# write to the target stream self.stream.write(data) # empty queue self.queue.truncate(0) def writerows(self, rows): for row in rows: self.writerow(row) def normalize_id(astring): return getUtility(IIDNormalizer).normalize(astring) CSV_HEADER = [ _(u"salutation"), _(u"name_prefix"), _(u"firstname"), _(u"lastname"), _(u"nl_language"), _(u"email"), _(u"organization") ] class IEnl_Subscribers_View(Interface): """ Enl_Subscribers_View interface """
else: from Products.Archetypes.atapi import RichWidget as RichTextWidget log = logging.getLogger("Products.EasyNewsletter") schema = atapi.Schema(( # TODO: provide a default value here from portals email_from_address atapi.StringField( 'senderEmail', required=True, validators=('isEmail', ), widget=atapi.StringWidget( label=_( u"EasyNewsletter_label_senderEmail", default=u"Sender email"), description=_( u"EasyNewsletter_help_senderEmail", default=u"Default for the sender address of the newsletters."), i18n_domain='EasyNewsletter', ), ), atapi.StringField( 'senderName', widget=atapi.StringWidget( label=_( u"EasyNewsletter_label_senderName", default=u"Sender name"), description=_(
def title(self): """ """ return _(u"Newsletter subscriber portlet")
from Products.EasyNewsletter.interfaces import IReceiversMemberFilter, IReceiversGroupFilter from Products.EasyNewsletter.interfaces import IEasyNewsletter from Products.EasyNewsletter.interfaces import ISubscriberSource from Products.EasyNewsletter import config from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ import logging log = logging.getLogger("Products.EasyNewsletter") schema = atapi.Schema(( atapi.StringField('senderEmail', required = True, validators = ('isEmail', ), widget = atapi.StringWidget( label = _(u"EasyNewsletter_label_senderEmail", default=u"Sender email"), description = _(u"EasyNewsletter_help_senderEmail", default=u"Default for the sender address of the newsletters."), i18n_domain = 'EasyNewsletter', ), ), atapi.StringField('senderName', widget = atapi.StringWidget( label = _(u"EasyNewsletter_label_senderName", default=u"Sender name"), description = _(u"EasyNewsletter_help_senderName", default=u"Default for the sender name of the newsletters."), i18n_domain = 'EasyNewsletter', ) ),
import re from Products.Archetypes.atapi import DisplayList from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ PROJECTNAME = "EasyNewsletter" PLACEHOLDERS = ["UNSUBSCRIBE", "SUBSCRIBER_SALUTATION"] SALUTATION = DisplayList( ( ("", _(u"label_choose_saluation", "Choose salutation...")), ("ms", _(u"label_salutation_ms", "Ms.")), ("mr", _(u"label_salutation_mr", "Mr.")), ) ) MESSAGE_CODE = { "email_added": "Your email has been registered. A confirmation email was \ sent to your address. Please check your inbox and click on the link in \ the email in order to confirm your subscription.", "invalid_email": "Please enter a valid email address.", "email_exists": "Your email address is already registered.", "invalid_hashkey": "Please enter a valid email address.", "subscription_confirmed": "Your subscription was successfully confirmed.", }
from Products.EasyNewsletter.zamqp.handler import zamqp_queue_issue has_zamqp = True log = logging.getLogger("Products.EasyNewsletter") schema = atapi.Schema(( atapi.TextField( 'text', allowable_content_types=( 'text/plain', 'text/structured', 'text/html', 'application/msword'), default_output_type='text/html', widget=atapi.RichWidget( rows=30, label=_('EasyNewsletter_label_text', default=u'Text'), description=_( u'description_text_issue', default=u'The main content of the mailing. You can use \ the topic criteria to collect content or put manual \ content in. This will included in outgoing mails.'), i18n_domain='EasyNewsletter', ), ), atapi.BooleanField( 'excludeAllSubscribers', default_method="get_excludeAllSubscribers_defaults", widget=atapi.BooleanWidget( label=_( u'label_excludeAllExternalSubscribers',
from plone.i18n.normalizer.interfaces import IIDNormalizer from Products.CMFCore.utils import getToolByName from Products.Five import BrowserView from Products.statusmessages.interfaces import IStatusMessage from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ from Products.EasyNewsletter.config import SALUTATION from Products.EasyNewsletter.interfaces import ISubscriberSource def normalize_id(astring): return getUtility(IIDNormalizer).normalize(astring) CSV_HEADER = [_(u"salutation"), _(u"fullname"), _(u"email"), _(u"organization"), ] class IEnl_Subscribers_View(Interface): """ Enl_Subscribers_View interface """ class Enl_Subscribers_View(BrowserView): """ Enl_Subscribers_View browser view """ implements(IEnl_Subscribers_View) # TODO: we should move these indexes from FieldIndex to ZCTextIndex
folder = instance.aq_parent identifier = getToolByName(instance, 'plone_utils').normalizeString(value).lower() if folder._getOb(identifier, instance) != instance: return _(u"Duplicate registration.") return 1 validation.register(NoDuplicateValidator()) schema = atapi.BaseSchema + atapi.Schema(( atapi.StringField('title', required = False, widget = atapi.StringWidget( visible = {'edit': 'invisible', 'view': 'invisible'}, label = _(u'EasyNewsletter_label_title', default=u'Title'), description = _(u'EasyNewsletter_help_title', default=u''), i18n_domain = 'EasyNewsletter', ), ), atapi.StringField('salutation', required = False, vocabulary = config.SALUTATION, widget = atapi.SelectionWidget( label = _(u'EasyNewsletter_label_salutation', default='Salutation'), description = _('EasyNewsletter_help_salutation', default=u''), i18n_domain = 'EasyNewsletter', format = 'select', ),
# flake8: noqa # from zope.i18n import translate from Products.Archetypes.atapi import DisplayList from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ import re PROJECTNAME = "EasyNewsletter" ENL_ISSUE_TYPES = ['ENLIssue'] ENL_EDITHELPER_TYPES =['EasyNewsletter', 'ENLIssue'] PLACEHOLDERS = ["UNSUBSCRIBE", "SUBSCRIBER_SALUTATION"] SALUTATION = DisplayList(( ('', _(u"label_choose_saluation", "Choose salutation...")), ("ms", _(u"label_salutation_ms", "Ms.")), ("mr", _(u"label_salutation_mr", "Mr.")), )) NL_LANGUAGE = DisplayList(( ('', _(u"label_choose_nl_language", "Choose language...")), ("de", _(u"label_salutation_de", "DE")), ("en", _(u"label_salutation_en", "EN")), ("fr", _(u"label_salutation_fr", "FR")), )) MESSAGE_CODE = { "email_added": _( u"email_added", default=u"Your email has been registered. A confirmation email was"
def register_subscriber(self): """ """ props = getToolByName(self, "portal_properties").site_properties charset = props.getProperty("default_charset") subscriber = self.request.get("subscriber") lastname = self.request.get("name", "") firstname = self.request.get("firstname", "") name_prefix = self.request.get("name_prefix", "") portal_state = getMultiAdapter( (self.context.aq_inner, self.request), name=u'plone_portal_state' ) current_language = portal_state.language() nl_language = self.request.get("nl_language", current_language) salutation = self.request.get("salutation", "") organization = self.request.get("organization", "") path_to_easynewsletter = self.request.get("newsletter") # remove leading slash from paths like: /mynewsletter path_to_easynewsletter = path_to_easynewsletter.strip('/') newsletter_container = self.portal.unrestrictedTraverse( path_to_easynewsletter) messages = IStatusMessage(self.request) if not subscriber: messages.addStatusMessage( _("Please enter a valid email address."), "error") return self._msg_redirect(newsletter_container) mo = re.search(EMAIL_RE, subscriber) if not mo: messages.addStatusMessage( _("Please enter a valid email address."), "error") return self._msg_redirect(newsletter_container) norm = queryUtility(IIDNormalizer) normalized_subscriber = norm.normalize(subscriber) if normalized_subscriber in newsletter_container.objectIds(): messages.addStatusMessage( _("Your email address is already registered."), "error") return self._msg_redirect(newsletter_container) subscriber_data = {} subscriber_data["subscriber"] = subscriber subscriber_data["lastname"] = lastname subscriber_data["firstname"] = firstname subscriber_data["name_prefix"] = name_prefix subscriber_data["nl_language"] = nl_language subscriber_data["salutation"] = salutation subscriber_data["organization"] = organization subscriber_data["path_to_easynewsletter"] = path_to_easynewsletter # use password reset tool to create a hash pwr_data = self._requestReset(subscriber) hashkey = pwr_data['randomstring'] enl_registration_tool = queryUtility( IENLRegistrationTool, 'enl_registration_tool') if hashkey not in enl_registration_tool.objectIds(): enl_registration_tool[hashkey] = RegistrationData( hashkey, **subscriber_data) msg_subject = newsletter_container\ .getRawSubscriber_confirmation_mail_subject().replace( "${portal_url}", self.portal_url.strip('http://')) confirmation_url = self.portal_url + '/confirm-subscriber?hkey=' +\ str(hashkey) msg_text = newsletter_container\ .getRawSubscriber_confirmation_mail_text().replace( "${newsletter_title}", newsletter_container.Title()) msg_text = msg_text.replace("${subscriber_email}", subscriber) msg_text = msg_text.replace( "${confirmation_url}", confirmation_url) msg_sender = self.portal.getProperty('email_from_address') msg_receiver = subscriber msg = MIMEText(msg_text, "plain", charset) msg['To'] = msg_receiver msg['From'] = msg_sender msg['Subject'] = msg_subject # msg.epilogue = '' self.portal.MailHost.send(msg.as_string()) messages.addStatusMessage(_("Your email has been registered. \ A confirmation email was sent to your address. Please check \ your inbox and click on the link in the email in order to \ confirm your subscription."), "info") return self._msg_redirect(newsletter_container)
def create_subscribers(self, csv_data=None): """Create newsletter subscribers from uploaded CSV file. """ # Do nothing if no submit button was hit if 'form.button.Import' not in self.request.form: return context = aq_inner(self.context) plone_utils = getToolByName(self.context, 'plone_utils') encoding = plone_utils.getSiteEncoding() existing = self.context.objectIds() messages = IStatusMessage(self.request) success = [] fail = [] data = [] # Show error if no file was specified filename = self.request.form.get('csv_upload', None) if not filename: msg = _('No file specified.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.response.redirect(context.absolute_url() + '/@@upload_csv') # Show error if no data has been provided in the file reader = csv.reader(filename) header = reader.next() if header != CSV_HEADER: msg = _('Wrong specification of the CSV file. Please correct it and retry.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.response.redirect(context.absolute_url() + '/@@upload_csv') for subscriber in reader: # Check the length of the line if len(subscriber) != 4: msg = _('The number of items in the line is not correct. \ It should be 4. Check your CSV file.') fail.append( {'failure': msg}) else: salutation = subscriber[0] fullname = subscriber[1] email = subscriber[2] organization = subscriber[3] id = plone_utils.normalizeString(email) if id in existing: msg = _('This email address is already registered.') fail.append( {'salutation': salutation, 'fullname': fullname, 'email': email, 'organization': organization, 'failure': msg}) else: title = email + " - " + fullname try: self.context.invokeFactory('ENLSubscriber', id=id, title=title, description="") sub = context[id] sub.email = email sub.fullname = fullname.decode(encoding) sub.organization = organization.decode(encoding) sub.salutation = salutation.decode(encoding) obj = self.context.get(id, None) obj.reindexObject() success.append( {'salutation': salutation, 'fullname': fullname, 'email': email, 'organization': organization}) except Exception, e: fail.append( {'salutation': salutation, 'fullname': fullname, 'email': email, 'organization': organization, 'failure': 'An error occured while creating this subscriber: %s' % str(e)})
from Products.EasyNewsletter.utils.ENLHTMLParser import ENLHTMLParser #from Products.EasyNewsletter.utils.mail import create_html_mail from Products.EasyNewsletter.utils import safe_portal_encoding from Products.CMFPlone.utils import safe_unicode import logging log = logging.getLogger("Products.EasyNewsletter") schema = atapi.Schema(( atapi.TextField('text', allowable_content_types = ('text/plain', 'text/structured', 'text/html', 'application/msword'), default_output_type = 'text/html', widget = atapi.RichWidget( rows = 30, label = _('EasyNewsletter_label_text', default=u'Text'), description = _(u'description_text_issue', default=u'The main content of the mailing. You can use the topic \ criteria to collect content or put manual content in. \ This will included in outgoing mails.'), i18n_domain = 'EasyNewsletter', ), ), atapi.BooleanField('sendToAllPloneMembers', default_method = "get_sendToAllPloneMembers_defaults", widget = atapi.BooleanWidget( label = _(u'label_sendToAllPloneMembers', default=u'Send to all Plone members'), description = _(u'help_sendToAllPloneMembers', default=u'If checked, the newsletter/mailing is send to all \
from Products.TemplateFields import ZPTField from Products.CMFCore.utils import getToolByName from zope.interface import implements from Products.EasyNewsletter import config from Products.EasyNewsletter.interfaces import IENLTemplate from Products.EasyNewsletter import EasyNewsletterMessageFactory as _ schema = atapi.BaseSchema + atapi.Schema( ( ZPTField( "body", validators=("zptvalidator",), widget=atapi.TextAreaWidget( label=_(u"label_body_zpt", default=u"Newsletter Template"), description=_( "help_body_zpt", default=u"This is a Zope Page Template file that is used for \ rendering the newsletter mail.", ), i18n_domain="plone", rows=30, ), ), atapi.TextField( "description", accessor="Description", widget=atapi.TextAreaWidget( label=_(u"label_description", default=u"Description"), description=_(u"help_description", default=u"Enter a value for description."),
else: from Products.Archetypes.atapi import RichWidget as RichTextWidget log = logging.getLogger('Products.EasyNewsletter') schema = atapi.Schema(( atapi.TextField( 'text', allowable_content_types=( 'text/html', 'text/x-plone-outputfilters-html'), default_output_type='text/x-plone-outputfilters-html', widget=RichTextWidget( rows=30, label=_('EasyNewsletter_label_text', default=u'Text'), description=_( u'description_text_issue', default=u'The main content of the mailing. You can use \ the Collections to collect content or put manual \ content in. This will included in outgoing mails.'), i18n_domain='EasyNewsletter', ), ), atapi.BooleanField( 'excludeAllSubscribers', default_method='get_excludeAllSubscribers_defaults', widget=atapi.BooleanWidget( label=_( u'label_excludeAllExternalSubscribers',
from Products.CMFPlone.utils import safe_unicode import logging log = logging.getLogger("Products.EasyNewsletter") schema = atapi.Schema( ( atapi.TextField( "text", allowable_content_types=("text/plain", "text/structured", "text/html", "application/msword"), default_output_type="text/html", widget=atapi.RichWidget( rows=30, label=_("EasyNewsletter_label_text", default=u"Text"), description=_( u"description_text_issue", default=u"The main content of the mailing. You can use the topic \ criteria to collect content or put manual content in. \ This will included in outgoing mails.", ), i18n_domain="EasyNewsletter", ), ), atapi.BooleanField( "sendToAllPloneMembers", default_method="get_sendToAllPloneMembers_defaults", widget=atapi.BooleanWidget( label=_(u"label_sendToAllPloneMembers", default=u"Send to all Plone members"), description=_(