diff --git a/assets/monitoring/components/EditMonitoringProfile.jsx b/assets/monitoring/components/EditMonitoringProfile.jsx index 44430b243..584983011 100644 --- a/assets/monitoring/components/EditMonitoringProfile.jsx +++ b/assets/monitoring/components/EditMonitoringProfile.jsx @@ -179,7 +179,8 @@ class EditMonitoringProfile extends React.Component { value={item.format_type || 'monitoring_pdf'} options={[ {value: 'monitoring_pdf', text: 'PDF'}, - {value: 'monitoring_rtf', text: 'RTF'} + {value: 'monitoring_rtf', text: 'RTF'}, + {value: 'monitoring_email', text: 'Email'} ]} onChange={onChange} error={getError('format_type')} /> diff --git a/newsroom/email.py b/newsroom/email.py index ce81dc18d..ff46ba7ce 100644 --- a/newsroom/email.py +++ b/newsroom/email.py @@ -25,7 +25,7 @@ def _send_email(self, to, subject, text_body, html_body=None, sender=None, attac try: content = base64.b64decode(a['file']) decoded_attachments.append(Attachment(a['file_name'], - a['content_type'], data=content)) + a['content_type'], data=content, headers=a.get('headers'))) except Exception as e: logger.error('Error attaching {} file to mail. Receipient(s): {}. Error: {}'.format( a['file_desc'], to, e)) diff --git a/newsroom/monitoring/email_alerts.py b/newsroom/monitoring/email_alerts.py index 2873c40f8..2e406431b 100644 --- a/newsroom/monitoring/email_alerts.py +++ b/newsroom/monitoring/email_alerts.py @@ -21,8 +21,9 @@ import logging from bson import ObjectId from eve.utils import ParsedRequest -from .utils import get_monitoring_file, truncate_article_body +from .utils import get_monitoring_file, truncate_article_body, get_date_items_dict import base64 +import os try: from urllib.parse import urlparse @@ -181,6 +182,48 @@ def add_to_send_list(self, alert_monitoring, profile, now, one_hour_ago, two_hou alert_monitoring['four']['w_lists'].append(profile) return + def send_email_alert(self, items, subject, m): + """ + Send an email alert with the details in the body of the email. If a logo image is set in the + monitoring_report_logo_path settings it will be attached to the email and can be referenced in the + monitoring_export.html template as + :param items: + :param subject: + :param m: + :return: + """ + from newsroom.email import send_email + + general_settings = get_settings_collection().find_one(GENERAL_SETTINGS_LOOKUP) + + data = { + 'date_items_dict': get_date_items_dict(items), + 'monitoring_profile': m, + 'current_date': utc_to_local(app.config['DEFAULT_TIMEZONE'], utcnow()).strftime( + '%d/%m/%Y'), + 'monitoring_report_name': app.config.get('MONITORING_REPORT_NAME', 'Newsroom') + } + + # Attach logo to email if defined + logo = None + if general_settings and general_settings['values'].get('monitoring_report_logo_path'): + image_filename = general_settings['values'].get('monitoring_report_logo_path') + if os.path.exists(image_filename): + with open(image_filename, 'rb') as img: + bts = base64.b64encode(img.read()) + logo = [{'file': bts, + 'file_name': 'logo{}'.format(os.path.splitext(image_filename)[1]), + 'content_type': 'image/{}'.format( + os.path.splitext(image_filename)[1].replace('.', '')), + 'headers': [('Content-ID', 'logo')]}] + + send_email( + [u['email'] for u in get_items_by_id([ObjectId(u) for u in m['users']], 'users')], + subject, + text_body=render_template('monitoring_export.txt', **data), + html_body=render_template('monitoring_export.html', **data), + attachments_info=logo) + def send_alerts(self, monitoring_list, created_from, created_from_time, now): general_settings = get_settings_collection().find_one(GENERAL_SETTINGS_LOOKUP) error_recipients = [] @@ -207,9 +250,6 @@ def send_alerts(self, monitoring_list, created_from, created_from_time, now): 'section': 'wire', }) truncate_article_body(items, m) - _file = get_monitoring_file(m, items) - attachment = base64.b64encode(_file.read()) - formatter = app.download_formatters[m['format_type']]['formatter'] # If there is only one story to send and the headline is to be used as the subject if m.get('headline_subject', False) and len(items) == 1: @@ -217,19 +257,27 @@ def send_alerts(self, monitoring_list, created_from, created_from_time, now): else: subject = m.get('subject') or m['name'] - send_email( - [u['email'] for u in get_items_by_id([ObjectId(u) for u in m['users']], 'users')], - subject, - text_body=render_template('monitoring_email.txt', **template_kwargs), - html_body=render_template('monitoring_email.html', **template_kwargs), - attachments_info=[{ - 'file': attachment, - 'file_name': formatter.format_filename(None), - 'content_type': 'application/{}'.format(formatter.FILE_EXTENSION), - 'file_desc': 'Monitoring Report for Celery monitoring alerts for profile: {}'.format( - m['name']) - }] - ) + if m.get('format_type') == 'monitoring_email': + self.send_email_alert(items, subject, m) + else: + _file = get_monitoring_file(m, items) + attachment = base64.b64encode(_file.read()) + formatter = app.download_formatters[m['format_type']]['formatter'] + + send_email( + [u['email'] for u in get_items_by_id([ObjectId(u) for u in m['users']], 'users')], + subject, + text_body=render_template('monitoring_email.txt', **template_kwargs), + html_body=render_template('monitoring_email.html', **template_kwargs), + attachments_info=[{ + 'file': attachment, + 'file_name': formatter.format_filename(None), + 'content_type': 'application/{}'.format(formatter.FILE_EXTENSION), + 'file_desc': + 'Monitoring Report for Celery monitoring alerts for profile: {}'.format( + m['name']) + }] + ) except Exception: logger.exception('{0} Error processing monitoring profile {1} for company {2}.'.format( self.log_msg, m['name'], company['name'])) diff --git a/newsroom/monitoring/forms.py b/newsroom/monitoring/forms.py index 6a912db57..a807e8a5a 100644 --- a/newsroom/monitoring/forms.py +++ b/newsroom/monitoring/forms.py @@ -5,7 +5,8 @@ from wtforms.validators import DataRequired alert_types = [('full_text', gettext('Full text')), ('linked_text', gettext('Linked extract(s)'))] -format_types = [('monitoring_pdf', gettext('PDF')), ('monitoring_rtf', gettext('RTF'))] +format_types = [('monitoring_pdf', gettext('PDF')), ('monitoring_rtf', gettext('RTF')), + ('monitoring_email', gettext('Email'))] class MonitoringForm(FlaskForm): diff --git a/newsroom/templates/monitoring_export.txt b/newsroom/templates/monitoring_export.txt new file mode 100644 index 000000000..209abaeaf --- /dev/null +++ b/newsroom/templates/monitoring_export.txt @@ -0,0 +1,17 @@ +{{ monitoring_report_name }} Monitoring: {{ monitoring_profile.name }} {% if current_date %}({{ current_date }}){% endif %} + {% for d in date_items_dict.keys() %} + {{ d.strftime('%d/%m/%Y') }} + {% for item in date_items_dict[d] %} + Headline: {{ item.get('headline', '') }} + Source: {{ item.get('source', '') }} + Keywords: {{ get_keywords_in_text(item.get('body_str', ''), monitoring_profile.keywords)|join(',') }} + {% if item.byline %} + By {{ item.get('byline', '') }} + {% endif %} + {{ item.get('body_str', '') | safe }} + {% if monitoring_profile.alert_type == 'linked_text' and not print%} + {{ url_for('monitoring.index', item=item._id, _external=True) }} + {% endif %} + + {% endfor %} + {% endfor %} diff --git a/tests/test_monitoring.py b/tests/test_monitoring.py index f7b60b624..3a9ef817e 100644 --- a/tests/test_monitoring.py +++ b/tests/test_monitoring.py @@ -820,3 +820,32 @@ def test_send_immediate_headline_subject_alerts(client, app): assert outbox[0].sender == 'newsroom@localhost' assert outbox[0].subject == 'Article headline about product' assert 'Newsroom Monitoring: W1' in outbox[0].body + + +@mock.patch('newsroom.monitoring.email_alerts.utcnow', mock_utcnow) +@mock.patch('newsroom.email.send_email', mock_send_email) +def test_send_immediate_email_alerts(client, app): + test_login_succeeds_for_admin(client) + post_json(client, '/settings/general_settings', + {"monitoring_report_logo_path": get_fixture_path('thumbnail.jpg')}) + app.data.insert('items', [{ + '_id': 'foo', + 'headline': 'product immediate', + 'products': [{'code': '12345'}], + "versioncreated": utcnow(), + 'byline': 'Testy McTestface', + 'body_html': '
line 1 of the article text\nline 2 of the story\nand a bit more.
', + 'source': 'AAAA' + }]) + w = app.data.find_one('monitoring', None, _id='5db11ec55f627d8aa0b545fb') + assert w is not None + app.data.update('monitoring', ObjectId('5db11ec55f627d8aa0b545fb'), + {"format_type": "monitoring_email", "alert_type": "linked_text", + 'keywords': ['text']}, w) + with app.mail.record_messages() as outbox: + MonitoringEmailAlerts().run(immediate=True) + assert len(outbox) == 1 + assert outbox[0].recipients == ['foo_user@bar.com', 'foo_user2@bar.com'] + assert outbox[0].sender == 'newsroom@localhost' + assert outbox[0].subject == 'Monitoring Subject' + assert 'Newsroom Monitoring: W1' in outbox[0].body