mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-30 11:38:36 -07:00
Add email subject line and sending newsletters
This commit is contained in:
parent
d104ec216c
commit
5ac5b3cd29
6 changed files with 94 additions and 59 deletions
|
@ -133,7 +133,7 @@
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<select class="form-control" id="email_notifier" name="email_notifier">
|
<select class="form-control" id="email_notifier" name="email_notifier">
|
||||||
% for notifier in email_notifiers:
|
% for notifier in email_notifiers:
|
||||||
<% selected = 'selected' if notifier['id'] == newsletter['email_notifier'] else '' %>
|
<% selected = 'selected' if notifier['id'] == newsletter['email_config']['notifier'] else '' %>
|
||||||
% if notifier['friendly_name']:
|
% if notifier['friendly_name']:
|
||||||
<option value="${notifier['id']}" ${selected}>${notifier['agent_label']} (${notifier['id']} - ${notifier['friendly_name']})</option>
|
<option value="${notifier['id']}" ${selected}>${notifier['agent_label']} (${notifier['id']} - ${notifier['friendly_name']})</option>
|
||||||
% elif notifier['id']:
|
% elif notifier['id']:
|
||||||
|
@ -147,8 +147,21 @@
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Use an exisiting Email notification agent or enter a new configuration below.</p>
|
<p class="help-block">Use an exisiting Email notification agent or enter a new configuration below.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email_subject">Email Subject</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<input type="text" class="form-control" id="email_subject" name="email_subject" value="${newsletter['email_config']['subject']}" size="30">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help-block">
|
||||||
|
Optional: Enter a subject line for the email. Leave blank for default.
|
||||||
|
<br>
|
||||||
|
Note: You may include <span class="inline-pre">{start_date}</span> and <span class="inline-pre">{end_date}</span> as parameters. The global date format under Settings > General will be used.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="newsletter-email-config" class="col-md-12" style="padding-top: 10px; border-top: 1px solid #444; ${'display: none;' if newsletter['email_notifier'] else ''}">
|
<div id="newsletter-email-config" class="col-md-12" style="padding-top: 10px; border-top: 1px solid #444; ${'display: none;' if newsletter['email_config']['notifier'] else ''}">
|
||||||
% for item in newsletter['email_config_options']:
|
% for item in newsletter['email_config_options']:
|
||||||
% if item['input_type'] == 'help':
|
% if item['input_type'] == 'help':
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -733,7 +733,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="wrapper newsletter-header">
|
<td class="wrapper newsletter-header">
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<div class="dates">${start_date} - ${end_date}</div>
|
<div class="dates">${parameters['start_date']} - ${parameters['end_date']}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
% if recently_added.get('movie'):
|
% if recently_added.get('movie'):
|
||||||
|
|
|
@ -624,7 +624,7 @@ def dbcheck():
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'CREATE TABLE IF NOT EXISTS newsletters (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
'CREATE TABLE IF NOT EXISTS newsletters (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
||||||
'agent_id INTEGER, agent_name TEXT, agent_label TEXT, '
|
'agent_id INTEGER, agent_name TEXT, agent_label TEXT, '
|
||||||
'friendly_name TEXT, newsletter_config TEXT, email_config TEXT, email_notifier INTEGER DEFAULT 0, '
|
'friendly_name TEXT, newsletter_config TEXT, email_config TEXT, '
|
||||||
'cron TEXT NOT NULL DEFAULT "0 0 * * 0", active INTEGER DEFAULT 0)'
|
'cron TEXT NOT NULL DEFAULT "0 0 * * 0", active INTEGER DEFAULT 0)'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,10 @@
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import json
|
import json
|
||||||
from email.mime.multipart import MIMEMultipart
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
import email.utils
|
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from mako.lookup import TemplateLookup
|
from mako.lookup import TemplateLookup
|
||||||
from mako import exceptions
|
from mako import exceptions
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import plexpy
|
import plexpy
|
||||||
|
@ -32,8 +28,7 @@ import libraries
|
||||||
import logger
|
import logger
|
||||||
import notification_handler
|
import notification_handler
|
||||||
import pmsconnect
|
import pmsconnect
|
||||||
import request
|
from notifiers import send_notification, EMAIL
|
||||||
from notifiers import EMAIL
|
|
||||||
|
|
||||||
|
|
||||||
AGENT_IDS = {
|
AGENT_IDS = {
|
||||||
|
@ -114,8 +109,8 @@ def get_newsletter_config(newsletter_id=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config = json.loads(result.pop('newsletter_config') or '{}')
|
config = json.loads(result.pop('newsletter_config', '{}'))
|
||||||
email_config = json.loads(result.pop('email_config') or '{}')
|
email_config = json.loads(result.pop('email_config', '{}'))
|
||||||
newsletter_agent = get_agent_class(agent_id=result['agent_id'], config=config, email_config=email_config)
|
newsletter_agent = get_agent_class(agent_id=result['agent_id'], config=config, email_config=email_config)
|
||||||
newsletter_config = newsletter_agent.return_config_options()
|
newsletter_config = newsletter_agent.return_config_options()
|
||||||
newsletter_email_config = newsletter_agent.return_email_config_options()
|
newsletter_email_config = newsletter_agent.return_email_config_options()
|
||||||
|
@ -124,6 +119,7 @@ def get_newsletter_config(newsletter_id=None):
|
||||||
return
|
return
|
||||||
|
|
||||||
result['config'] = config
|
result['config'] = config
|
||||||
|
result['email_config'] = email_config
|
||||||
result['config_options'] = newsletter_config
|
result['config_options'] = newsletter_config
|
||||||
result['email_config_options'] = newsletter_email_config
|
result['email_config_options'] = newsletter_email_config
|
||||||
|
|
||||||
|
@ -188,8 +184,6 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
|
||||||
|
|
||||||
newsletter_config = {k[len(config_prefix):]: kwargs.pop(k)
|
newsletter_config = {k[len(config_prefix):]: kwargs.pop(k)
|
||||||
for k in kwargs.keys() if k.startswith(config_prefix)}
|
for k in kwargs.keys() if k.startswith(config_prefix)}
|
||||||
|
|
||||||
email_notifier = kwargs.pop('email_notifier', 0)
|
|
||||||
email_config = {k[len(email_config_prefix):]: kwargs.pop(k)
|
email_config = {k[len(email_config_prefix):]: kwargs.pop(k)
|
||||||
for k in kwargs.keys() if k.startswith(email_config_prefix)}
|
for k in kwargs.keys() if k.startswith(email_config_prefix)}
|
||||||
|
|
||||||
|
@ -202,7 +196,6 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
|
||||||
'friendly_name': kwargs.get('friendly_name', ''),
|
'friendly_name': kwargs.get('friendly_name', ''),
|
||||||
'newsletter_config': json.dumps(agent_class.config),
|
'newsletter_config': json.dumps(agent_class.config),
|
||||||
'email_config': json.dumps(agent_class.email_config),
|
'email_config': json.dumps(agent_class.email_config),
|
||||||
'email_notifier': email_notifier,
|
|
||||||
'cron': kwargs.get('cron'),
|
'cron': kwargs.get('cron'),
|
||||||
'active': kwargs.get('active')
|
'active': kwargs.get('active')
|
||||||
}
|
}
|
||||||
|
@ -245,11 +238,17 @@ def serve_template(templatename, **kwargs):
|
||||||
class Newsletter(object):
|
class Newsletter(object):
|
||||||
NAME = ''
|
NAME = ''
|
||||||
_DEFAULT_CONFIG = {}
|
_DEFAULT_CONFIG = {}
|
||||||
_DEFAULT_EMAIL_CONFIG = EMAIL._DEFAULT_CONFIG
|
|
||||||
|
|
||||||
def __init__(self, config=None, email_config=None):
|
def __init__(self, config=None, email_config=None):
|
||||||
|
self._default_email_config = EMAIL().return_default_config()
|
||||||
|
self._default_email_config['from_name'] = 'Tautulli Newsletter'
|
||||||
|
self._default_email_config['notifier'] = 0
|
||||||
|
self._default_email_config['subject'] = 'Tautulli Newsletter'
|
||||||
|
|
||||||
self.config = self.set_config(config=config, default=self._DEFAULT_CONFIG)
|
self.config = self.set_config(config=config, default=self._DEFAULT_CONFIG)
|
||||||
self.email_config = self.set_config(config=email_config, default=self._DEFAULT_EMAIL_CONFIG)
|
self.email_config = self.set_config(config=email_config, default=self._default_email_config)
|
||||||
|
|
||||||
|
self.parameters = {}
|
||||||
|
|
||||||
def set_config(self, config=None, default=None):
|
def set_config(self, config=None, default=None):
|
||||||
return self._validate_config(config=config, default=default)
|
return self._validate_config(config=config, default=default)
|
||||||
|
@ -267,33 +266,59 @@ class Newsletter(object):
|
||||||
|
|
||||||
return new_config
|
return new_config
|
||||||
|
|
||||||
def preview(self, **kwargs):
|
def _render_template(self, **kwargs):
|
||||||
|
return serve_template(
|
||||||
|
templatename=self._TEMPLATE,
|
||||||
|
title=self.NAME,
|
||||||
|
parameters=self.parameters,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def _format_subject(self, subject):
|
||||||
|
subject = subject or self._default_email_config['subject']
|
||||||
|
|
||||||
|
try:
|
||||||
|
subject = unicode(subject).format(**self.parameters)
|
||||||
|
except LookupError as e:
|
||||||
|
logger.error(
|
||||||
|
u"Tautulli Newsletter :: Unable to parse parameter %s in newsletter subject. Using fallback." % e)
|
||||||
|
subject = unicode(self._default_email_config['subject']).format(**self.parameters)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(
|
||||||
|
u"Tautulli Newsletter :: Unable to parse custom newsletter subject: %s. Using fallback." % e)
|
||||||
|
subject = unicode(self._default_email_config['subject']).format(**self.parameters)
|
||||||
|
|
||||||
|
return subject
|
||||||
|
|
||||||
|
def retrieve_data(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def generate_newsletter(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def preview(self):
|
||||||
|
self.retrieve_data()
|
||||||
|
return self.generate_newsletter()
|
||||||
|
|
||||||
def send(self, **kwargs):
|
def send(self, **kwargs):
|
||||||
pass
|
self.retrieve_data()
|
||||||
|
|
||||||
def make_request(self, url, method='POST', **kwargs):
|
subject = self._format_subject(self.email_config['subject'])
|
||||||
response, err_msg, req_msg = request.request_response2(url, method, **kwargs)
|
newsletter = self.generate_newsletter()
|
||||||
|
|
||||||
if response and not err_msg:
|
if self.email_config['notifier']:
|
||||||
logger.info(u"Tautulli Newsletters :: {name} notification sent.".format(name=self.NAME))
|
return send_notification(
|
||||||
return True
|
notifier_id=self.email_config['notifier'],
|
||||||
|
subject=subject,
|
||||||
|
body=newsletter
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
verify_msg = ""
|
email = EMAIL(config=self.email_config)
|
||||||
if response is not None and response.status_code >= 400 and response.status_code < 500:
|
return email.notify(
|
||||||
verify_msg = " Verify you notification newsletter agent settings are correct."
|
subject=subject,
|
||||||
|
body=newsletter
|
||||||
logger.error(u"Tautulli Newsletters :: {name} notification failed.{}".format(verify_msg, name=self.NAME))
|
)
|
||||||
|
|
||||||
if err_msg:
|
|
||||||
logger.error(u"Tautulli Newsletters :: {}".format(err_msg))
|
|
||||||
|
|
||||||
if req_msg:
|
|
||||||
logger.debug(u"Tautulli Newsletters :: Request response: {}".format(req_msg))
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
config_options = []
|
config_options = []
|
||||||
|
@ -321,6 +346,8 @@ class RecentlyAdded(Newsletter):
|
||||||
elif not isinstance(self.config['incl_libraries'], list):
|
elif not isinstance(self.config['incl_libraries'], list):
|
||||||
self.config['incl_libraries'] = [self.config['incl_libraries']]
|
self.config['incl_libraries'] = [self.config['incl_libraries']]
|
||||||
|
|
||||||
|
self._default_email_config['subject'] = 'Recently Added to Plex! ({end_date})'
|
||||||
|
|
||||||
date_format = helpers.momentjs_to_arrow(plexpy.CONFIG.DATE_FORMAT)
|
date_format = helpers.momentjs_to_arrow(plexpy.CONFIG.DATE_FORMAT)
|
||||||
|
|
||||||
self.end_time = int(time.time())
|
self.end_time = int(time.time())
|
||||||
|
@ -328,6 +355,9 @@ class RecentlyAdded(Newsletter):
|
||||||
self.end_date = arrow.get(self.end_time).format(date_format)
|
self.end_date = arrow.get(self.end_time).format(date_format)
|
||||||
self.start_date = arrow.get(self.start_time).format(date_format)
|
self.start_date = arrow.get(self.start_time).format(date_format)
|
||||||
|
|
||||||
|
self.parameters = {'start_date': self.start_date,
|
||||||
|
'end_date': self.end_date}
|
||||||
|
|
||||||
self.plexpy_config = {
|
self.plexpy_config = {
|
||||||
'pms_identifier': plexpy.CONFIG.PMS_IDENTIFIER,
|
'pms_identifier': plexpy.CONFIG.PMS_IDENTIFIER,
|
||||||
'pms_web_url': plexpy.CONFIG.PMS_WEB_URL
|
'pms_web_url': plexpy.CONFIG.PMS_WEB_URL
|
||||||
|
@ -451,32 +481,22 @@ class RecentlyAdded(Newsletter):
|
||||||
|
|
||||||
return recently_added
|
return recently_added
|
||||||
|
|
||||||
def get_recently_added(self):
|
def retrieve_data(self):
|
||||||
media_types = {s['section_type'] for s in self._get_sections()
|
media_types = {s['section_type'] for s in self._get_sections()
|
||||||
if str(s['section_id']) in self.config['incl_libraries']}
|
if str(s['section_id']) in self.config['incl_libraries']}
|
||||||
|
|
||||||
for media_type in media_types:
|
for media_type in media_types:
|
||||||
self.recently_added[media_type] = self._get_recently_added(media_type)
|
if media_type not in self.recently_added:
|
||||||
|
self.recently_added[media_type] = self._get_recently_added(media_type)
|
||||||
|
|
||||||
return self.recently_added
|
return self.recently_added
|
||||||
|
|
||||||
def preview(self, **kwargs):
|
def generate_newsletter(self):
|
||||||
self.get_recently_added()
|
return self._render_template(
|
||||||
|
|
||||||
return serve_template(
|
|
||||||
templatename=self._TEMPLATE,
|
|
||||||
title=self.NAME,
|
|
||||||
recently_added=self.recently_added,
|
recently_added=self.recently_added,
|
||||||
start_date=self.start_date,
|
|
||||||
end_date=self.end_date,
|
|
||||||
plexpy_config=self.plexpy_config
|
plexpy_config=self.plexpy_config
|
||||||
)
|
)
|
||||||
|
|
||||||
def send(self, **kwargs):
|
|
||||||
self.get_recently_added()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _get_sections(self):
|
def _get_sections(self):
|
||||||
return libraries.Libraries().get_sections()
|
return libraries.Libraries().get_sections()
|
||||||
|
|
||||||
|
|
|
@ -454,7 +454,7 @@ def get_notifier_config(notifier_id=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config = json.loads(result.pop('notifier_config') or '{}')
|
config = json.loads(result.pop('notifier_config', '{}'))
|
||||||
notifier_agent = get_agent_class(agent_id=result['agent_id'], config=config)
|
notifier_agent = get_agent_class(agent_id=result['agent_id'], config=config)
|
||||||
notifier_config = notifier_agent.return_config_options()
|
notifier_config = notifier_agent.return_config_options()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -772,6 +772,9 @@ class Notifier(object):
|
||||||
|
|
||||||
return new_config
|
return new_config
|
||||||
|
|
||||||
|
def return_default_config(self):
|
||||||
|
return self._DEFAULT_CONFIG
|
||||||
|
|
||||||
def notify(self, subject='', body='', action='', **kwargs):
|
def notify(self, subject='', body='', action='', **kwargs):
|
||||||
if self.NAME != 'Script':
|
if self.NAME != 'Script':
|
||||||
if not subject and self.config.get('incl_subject', True):
|
if not subject and self.config.get('incl_subject', True):
|
||||||
|
@ -1271,7 +1274,7 @@ class EMAIL(Notifier):
|
||||||
Email notifications
|
Email notifications
|
||||||
"""
|
"""
|
||||||
NAME = 'Email'
|
NAME = 'Email'
|
||||||
_DEFAULT_CONFIG = {'from_name': '',
|
_DEFAULT_CONFIG = {'from_name': 'Tautulli',
|
||||||
'from': '',
|
'from': '',
|
||||||
'to': '',
|
'to': '',
|
||||||
'cc': '',
|
'cc': '',
|
||||||
|
|
|
@ -3157,7 +3157,7 @@ class WebInterface(object):
|
||||||
notifier = notifiers.get_notifier_config(notifier_id=notifier_id)
|
notifier = notifiers.get_notifier_config(notifier_id=notifier_id)
|
||||||
|
|
||||||
if notifier:
|
if notifier:
|
||||||
logger.debug(u"Sending %s%s notification." % (test, notifier['agent_name']))
|
logger.debug(u"Sending %s%s notification." % (test, notifier['agent_label']))
|
||||||
if notification_handler.notify(notifier_id=notifier_id,
|
if notification_handler.notify(notifier_id=notifier_id,
|
||||||
notify_action=notify_action,
|
notify_action=notify_action,
|
||||||
subject=subject,
|
subject=subject,
|
||||||
|
@ -5500,9 +5500,8 @@ class WebInterface(object):
|
||||||
newsletter = newsletters.get_newsletter_config(newsletter_id=newsletter_id)
|
newsletter = newsletters.get_newsletter_config(newsletter_id=newsletter_id)
|
||||||
|
|
||||||
if newsletter:
|
if newsletter:
|
||||||
logger.debug(u"Sending %s%s newsletter." % (test, newsletter['agent_name']))
|
logger.debug(u"Sending %s%s newsletter." % (test, newsletter['agent_label']))
|
||||||
if newsletter_handler.send(newsletter_id=newsletter_id,
|
if newsletters.send_newsletter(newsletter_id=newsletter_id):
|
||||||
**kwargs):
|
|
||||||
return "Newsletter sent."
|
return "Newsletter sent."
|
||||||
else:
|
else:
|
||||||
return "Newsletter failed."
|
return "Newsletter failed."
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue