Skip to content

Commit

Permalink
SDAN-710 Send monitoring alerts with articles in body (#1153)
Browse files Browse the repository at this point in the history
  • Loading branch information
marwoodandrew authored Jan 12, 2022
1 parent 3e2463c commit 5d01305
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 20 deletions.
3 changes: 2 additions & 1 deletion assets/monitoring/components/EditMonitoringProfile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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')} />
Expand Down
2 changes: 1 addition & 1 deletion newsroom/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
82 changes: 65 additions & 17 deletions newsroom/monitoring/email_alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <img src="CID:logo" />
: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 = []
Expand All @@ -207,29 +250,34 @@ 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:
subject = items[0].get('headline', m.get('subject') or m['name'])
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']))
Expand Down
3 changes: 2 additions & 1 deletion newsroom/monitoring/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
17 changes: 17 additions & 0 deletions newsroom/templates/monitoring_export.txt
Original file line number Diff line number Diff line change
@@ -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 %}
29 changes: 29 additions & 0 deletions tests/test_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': '<p>line 1 of the article text\nline 2 of the story\nand a bit more.</p>',
'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 == ['[email protected]', '[email protected]']
assert outbox[0].sender == 'newsroom@localhost'
assert outbox[0].subject == 'Monitoring Subject'
assert 'Newsroom Monitoring: W1' in outbox[0].body

0 comments on commit 5d01305

Please sign in to comment.