def reset_send_status(event):
    if not INewsletterIssue.providedBy(event.object):
        return
    if event.new_state.id in ['master']:
        status_adapter = ISendStatus(event.object)
        if not status_adapter:
            return
        status_adapter.clear()
    return
    def filter(self, receivers):
        status_adapter = ISendStatus(self.context)
        if not status_adapter:
            return receivers
        successful = status_adapter.get_keys(successful=True)

        return [
            receiver for receiver in receivers
            if receiver.get('email') not in successful
        ]
Esempio n. 3
0
 def receivers(self):
     status_adapter = ISendStatus(self.context)
     if not status_adapter:
         return
     now = datetime.now()
     records = status_adapter.get_records()
     records = sorted(records, key=lambda x: x.get('status', {}).get('datetime', now))
     self.failed = len(status_adapter.get_keys(successful=False))
     self.successful = len(status_adapter.get_keys(successful=True))
     self.total = len(records)
     return records
Esempio n. 4
0
 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__()
Esempio n. 5
0
 def test_get_keys(self):
     """Validate the 'get_keys' method."""
     status_adapter = ISendStatus(self.issue)
     status_adapter.add_records(self.receivers)
     self.assertEquals(len(status_adapter.get_keys()), 3)
     self.assertEquals(len(status_adapter.get_keys(successful=True)), 1)
     self.assertEquals(len(status_adapter.get_keys(successful=False)), 1)
    def test_filter(self):
        """Validate already sent emails are filtered out."""

        receivers = [
            {
                'email': '*****@*****.**',
                'fullname': 'John Doe',
                'firstname': 'John',
                'lastname': 'Doe',
                'salutation': 'Dear Mr.',
            },
            {
                'email': '*****@*****.**',
                'fullname': 'Mary Doe',
                'firstname': 'Mary',
                'lastname': 'Doe',
                'salutation': 'Dear Mrs.',
            },
        ]

        successful_receivers = [{
            'email': '*****@*****.**',
            'fullname': 'John Doe',
            'firstname': 'John',
            'lastname': 'Doe',
            'salutation': 'Dear Mr.',
            'status': {
                'successful': True,
                'error': None,
                'datetime': datetime.now(),
            },
        }]

        already_sent = FilterAlreadySentReceivers(self.issue)
        final_receivers = already_sent.filter(receivers)
        self.assertEquals(len(final_receivers), 2)

        status_adapter = ISendStatus(self.issue)
        status_adapter.add_records(successful_receivers)

        final_receivers = already_sent.filter(receivers)
        self.assertEquals(len(final_receivers), 1)
Esempio n. 7
0
    def test_filter(self):
        """Validate already sent emails are filtered out."""

        receivers = [
            {
                "email": "*****@*****.**",
                "fullname": "John Doe",
                "firstname": "John",
                "lastname": "Doe",
                "salutation": "Dear Mr.",
            },
            {
                "email": "*****@*****.**",
                "fullname": "Mary Doe",
                "firstname": "Mary",
                "lastname": "Doe",
                "salutation": "Dear Mrs.",
            },
        ]

        successful_receivers = [{
            "email": "*****@*****.**",
            "fullname": "John Doe",
            "firstname": "John",
            "lastname": "Doe",
            "salutation": "Dear Mr.",
            "status": {
                "successful": True,
                "error": None,
                "datetime": datetime.now(),
            },
        }]

        already_sent = FilterAlreadySentReceivers(self.issue)
        final_receivers = already_sent.filter(receivers)
        self.assertEquals(len(final_receivers), 2)

        status_adapter = ISendStatus(self.issue)
        status_adapter.add_records(successful_receivers)

        final_receivers = already_sent.filter(receivers)
        self.assertEquals(len(final_receivers), 1)
Esempio n. 8
0
 def test_reset_statistics_making_master(self):
     """Validate statistics are reset when issue is made as master."""
     status_adapter = ISendStatus(self.issue)
     status_adapter.add_records(self.receivers)
     self.assertEquals(len(status_adapter.get_keys()), 3)
     request = self.issue.REQUEST
     request["enlwf_guard"] = True
     api.content.transition(obj=self.issue, transition="make_master")
     self.assertEquals(len(status_adapter.get_keys()), 0)
     request["enlwf_guard"] = False
Esempio n. 9
0
    def send(self):
        """Sends the newsletter, sending might be queued for async send out."""

        # check for workflow
        current_state = api.content.get_state(obj=self.context)
        if not self.is_test and current_state != "sending":
            raise ValueError("Executed send in wrong review state!")

        # get hold of the parent Newsletter object#
        enl = self.context.get_newsletter()
        sender_name = self.request.get("sender_name") or enl.sender_name
        sender_email = self.request.get("sender_email") or enl.sender_email
        # get Plone email_charset
        # charset = get_email_charset()
        receivers = self._get_recipients()

        # determine MailHost first (build-in vs. external)
        delivery_service_name = "mailhost"  # XXX enl.delivery_dervice
        if delivery_service_name == "mailhost":
            self.mail_host = api.portal.get_tool("MailHost")
        else:
            self.mail_host = getUtility(IMailHost, name=delivery_service_name)
        log.info('Using mail delivery service "%r"' % self.mail_host)

        send_counter = 0
        send_error_counter = 0

        issue_data_fetcher = IIssueDataFetcher(self.context)
        # get issue subject an rendered output data
        issue_data = issue_data_fetcher()
        # import pdb; pdb.set_trace()  # NOQA: E702
        for receiver in receivers:
            personalized_html = issue_data_fetcher.personalize(
                receiver, issue_data["body_html"])
            # get plain text version
            personalized_plaintext = issue_data_fetcher.create_plaintext_message(
                personalized_html)

            m = Message(
                html=personalized_html,
                text=personalized_plaintext,
                subject=issue_data["subject"],
                mail_from=(sender_name, sender_email),
                mail_to=(receiver["fullname"], receiver["email"]),
            )
            m.transformer.local_loader = LocalLoader()
            m.transform(
                images_inline=True,
                load_images=True,
                base_url=self.context.absolute_url(),
                cssutils_logging_level=logging.ERROR,
            )

            send_status = {
                "successful": None,
                "error": None,
                "datetime": datetime.now(),
            }

            msg_string = ""
            try:
                msg_string = m.as_string()
            except Exception as e:  # noqa
                send_status["successful"] = False
                send_status["error"] = e
                log.exception(
                    'Building newsletter email for "%s" failed, with error "%s"!'
                    % (receiver["email"], e))
                send_error_counter += 1
                continue

            if "HTTPLoaderError" in msg_string:
                log.exception("Transform message failed: {0}".format(
                    m.as_string()))

            try:
                self.mail_host.send(msg_string, immediate=True)
                send_status["successful"] = True
                log.info('Send newsletter to "%s"' % receiver["email"])
                send_counter += 1
            except Exception as e:  # noqa
                send_status["successful"] = False
                send_status["error"] = e
                log.exception(
                    'Sending newsletter to "%s" failed, with error "%s"!' %
                    (receiver["email"], e))
                send_error_counter += 1
            finally:
                receiver["status"] = send_status
        # Add information to annotations
        status_adapter = ISendStatus(self.context)
        if status_adapter:
            status_adapter.add_records(receivers)
        log.info(
            "Newsletter was sent to (%s) receivers. (%s) errors occurred!" %
            (send_counter, send_error_counter))

        # change status only for a 'regular' send operation (not 'is_test')
        if not self.is_test:
            self.request["enlwf_guard"] = True
            api.content.transition(obj=self.context,
                                   transition="sending_completed")
            self.request["enlwf_guard"] = False
            self.context.setEffectiveDate(datetime.now())
            self.context.reindexObject(idxs=["effective"])
            msg_type = "info"
            additional_warning = ""
            if send_error_counter:
                msg_type = "warn"
                additional_warning = _(
                    "\nPlease check the log files, for more details!")
            api.portal.show_message(
                message=_(
                    "Newsletter was sent to ({0}) receivers. ({1}) errors occurred!{2}"
                    .format(send_counter, send_error_counter,
                            additional_warning)),
                request=self.request,
                type=msg_type,
            )
    def send(self):
        """Sends the newsletter, sending might be queued for async send out.
        """

        # check for workflow
        current_state = api.content.get_state(obj=self.context)
        if not self.is_test and current_state != 'sending':
            raise ValueError('Executed send in wrong review state!')

        # get hold of the parent Newsletter object#
        enl = self.context.get_newsletter()
        sender_name = self.request.get('sender_name') or enl.sender_name
        sender_email = self.request.get('sender_email') or enl.sender_email
        # get Plone email_charset
        # charset = get_email_charset()
        receivers = self._get_recipients()

        # determine MailHost first (build-in vs. external)
        delivery_service_name = 'mailhost'  # XXX enl.delivery_dervice
        if delivery_service_name == 'mailhost':
            self.mail_host = api.portal.get_tool('MailHost')
        else:
            self.mail_host = getUtility(IMailHost, name=delivery_service_name)
        log.info('Using mail delivery service "%r"' % self.mail_host)

        send_counter = 0
        send_error_counter = 0

        issue_data_fetcher = IIssueDataFetcher(self.context)
        # get issue data
        issue_data = issue_data_fetcher()
        for receiver in receivers:
            send_status = {
                'successful': None,
                'error': None,
                'datetime': datetime.now(),
            }
            try:
                personalized_html = issue_data_fetcher.personalize(
                    receiver, issue_data['body_html']
                )
                # get plain text version
                personalized_plaintext = issue_data_fetcher.create_plaintext_message(
                    personalized_html
                )

                m = emails.Message(
                    html=personalized_html,
                    text=personalized_plaintext,
                    subject=issue_data['subject'],
                    mail_from=(sender_name, sender_email),
                    mail_to=(receiver['fullname'], receiver['email']),
                )
                m.transform(
                    images_inline=True,
                    base_url=self.context.absolute_url(),
                    cssutils_logging_level=logging.ERROR,
                )
                message_string = m.as_string()
                if 'HTTPLoaderError' in message_string:
                    log.exception(u"Transform message failed: {0}".format(message_string))
                try:
                    self.mail_host.send(message_string, immediate=True)
                    send_status['successful'] = True
                    log.info('Send newsletter to "%s"' % receiver['email'])
                    send_counter += 1
                except Exception as e:  # noqa
                    send_status['successful'] = False
                    send_status['error'] = e
                    log.exception(
                        'Sending newsletter to "%s" failed, with error "%s"!'
                        % (receiver['email'], e)
                    )
                    send_error_counter += 1
            except Exception as e:
                send_status['successful'] = False
                send_status['error'] = e
                log.exception(
                    'Sending newsletter failed, with error "{0}"!'.format(e)
                )
                send_error_counter += 1
            finally:
                receiver['status'] = send_status

        if not self.is_test:
            # Add information to annotations
            status_adapter = ISendStatus(self.context)
            if status_adapter:
                status_adapter.add_records(receivers)
        log.info(
            'Newsletter was sent to (%s) receivers. (%s) errors occurred!'
            % (send_counter, send_error_counter)
        )

        # change status only for a 'regular' send operation (not 'is_test')
        if not self.is_test:
            self.request['enlwf_guard'] = True
            api.content.transition(obj=self.context, transition='sending_completed')
            self.request['enlwf_guard'] = False
            self.context.setEffectiveDate(DateTime())
            self.context.reindexObject(idxs=['effective'])
            msg_type = "info"
            additional_warning = ""
            if send_error_counter:
                msg_type = "warn"
                additional_warning = _(
                    "\nPlease check the log files, for more details!"
                )
            api.portal.show_message(
                message=_(
                    'Newsletter was sent to ({0}) receivers. ({1}) errors occurred!{2}'.format(
                        send_counter, send_error_counter, additional_warning
                    )
                ),
                request=self.request,
                type=msg_type,
            )
Esempio n. 11
0
    def test_add_records(self):
        """Validate the 'add_records' method."""
        status_adapter = ISendStatus(self.issue)
        status_adapter.add_records(self.receivers)
        self.assertEquals(len(status_adapter.get_keys()), 3)

        # Adding the same records will not give more items.
        status_adapter.add_records(self.receivers)
        self.assertEquals(len(status_adapter.get_keys()), 3)

        # Adding a new record will reurn more items.
        status_adapter.add_records([{"email": "*****@*****.**"}])
        self.assertEquals(len(status_adapter.get_keys()), 4)