Add newsletter handler

This commit is contained in:
JonnyWong16 2018-01-11 20:16:03 -08:00
parent 33c2315384
commit d4d5ff9de7
6 changed files with 155 additions and 23 deletions

View file

@ -439,7 +439,7 @@
}); });
function previewNewsletter() { function previewNewsletter() {
window.open('preview_newsletter?newsletter_id=${newsletter["id"]}'); window.open('preview_newsletter?newsletter_id=' + $('#newsletter_id').val());
} }
function sendTestNewsletter() { function sendTestNewsletter() {
@ -447,8 +447,9 @@
$.ajax({ $.ajax({
url: 'send_newsletter', url: 'send_newsletter',
data: { data: {
newsletter_id: '${newsletter["id"]}', newsletter_id: $('#newsletter_id').val(),
test: true subject: $('#email_subject').val(),
notify_action: 'test'
}, },
cache: false, cache: false,
async: true, async: true,

View file

@ -755,7 +755,7 @@
$.ajax({ $.ajax({
url: 'send_notification', url: 'send_notification',
data: { data: {
notifier_id: '${notifier["id"]}', notifier_id: $('#notifier_id').val(),
subject: $('#test_subject').val(), subject: $('#test_subject').val(),
body: $('#test_body').val(), body: $('#test_body').val(),
script: $('#test_script').val(), script: $('#test_script').val(),

View file

@ -426,7 +426,7 @@ def initialize_scheduler():
logger.error(e) logger.error(e)
def schedule_job(function, name, hours=0, minutes=0, seconds=0, args=None): def schedule_job(func, name, hours=0, minutes=0, seconds=0, args=None):
""" """
Start scheduled job if starting or restarting plexpy. Start scheduled job if starting or restarting plexpy.
Reschedule job if Interval Settings have changed. Reschedule job if Interval Settings have changed.
@ -444,7 +444,7 @@ def schedule_job(function, name, hours=0, minutes=0, seconds=0, args=None):
hours=hours, minutes=minutes, seconds=seconds), args=args) hours=hours, minutes=minutes, seconds=seconds), args=args)
logger.info(u"Re-scheduled background task: %s", name) logger.info(u"Re-scheduled background task: %s", name)
elif hours > 0 or minutes > 0 or seconds > 0: elif hours > 0 or minutes > 0 or seconds > 0:
SCHED.add_job(function, id=name, trigger=IntervalTrigger( SCHED.add_job(func, id=name, trigger=IntervalTrigger(
hours=hours, minutes=minutes, seconds=seconds), args=args) hours=hours, minutes=minutes, seconds=seconds), args=args)
logger.info(u"Scheduled background task: %s", name) logger.info(u"Scheduled background task: %s", name)
@ -574,14 +574,6 @@ def dbcheck():
'filter_music TEXT, filter_photos TEXT)' 'filter_music TEXT, filter_photos TEXT)'
) )
# notify_log table :: This is a table which logs notifications sent
c_db.execute(
'CREATE TABLE IF NOT EXISTS notify_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, '
'session_key INTEGER, rating_key INTEGER, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
'user_id INTEGER, user TEXT, notifier_id INTEGER, agent_id INTEGER, agent_name TEXT, notify_action TEXT, '
'subject_text TEXT, body_text TEXT, script_args TEXT, success INTEGER DEFAULT 0)'
)
# library_sections table :: This table keeps record of the servers library sections # library_sections table :: This table keeps record of the servers library sections
c_db.execute( c_db.execute(
'CREATE TABLE IF NOT EXISTS library_sections (id INTEGER PRIMARY KEY AUTOINCREMENT, ' 'CREATE TABLE IF NOT EXISTS library_sections (id INTEGER PRIMARY KEY AUTOINCREMENT, '
@ -620,6 +612,14 @@ def dbcheck():
'custom_conditions TEXT, custom_conditions_logic TEXT)' 'custom_conditions TEXT, custom_conditions_logic TEXT)'
) )
# notify_log table :: This is a table which logs notifications sent
c_db.execute(
'CREATE TABLE IF NOT EXISTS notify_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, '
'session_key INTEGER, rating_key INTEGER, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
'user_id INTEGER, user TEXT, notifier_id INTEGER, agent_id INTEGER, agent_name TEXT, notify_action TEXT, '
'subject_text TEXT, body_text TEXT, script_args TEXT, success INTEGER DEFAULT 0)'
)
# newsletters table :: This table keeps record of the newsletter settings # newsletters table :: This table keeps record of the newsletter settings
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, '
@ -628,6 +628,13 @@ def dbcheck():
'cron TEXT NOT NULL DEFAULT "0 0 * * 0", active INTEGER DEFAULT 0)' 'cron TEXT NOT NULL DEFAULT "0 0 * * 0", active INTEGER DEFAULT 0)'
) )
# newsletter_log table :: This is a table which logs newsletters sent
c_db.execute(
'CREATE TABLE IF NOT EXISTS newsletter_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, '
'newsletter_id INTEGER, agent_id INTEGER, agent_name TEXT, notify_action TEXT, '
'subject_text TEXT, success INTEGER DEFAULT 0)'
)
# poster_urls table :: This table keeps record of the notification poster urls # poster_urls table :: This table keeps record of the notification poster urls
c_db.execute( c_db.execute(
'CREATE TABLE IF NOT EXISTS poster_urls (id INTEGER PRIMARY KEY AUTOINCREMENT, ' 'CREATE TABLE IF NOT EXISTS poster_urls (id INTEGER PRIMARY KEY AUTOINCREMENT, '

View file

@ -0,0 +1,102 @@
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Tautulli is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
import time
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
import plexpy
import database
import logger
import newsletters
NEWSLETTER_SCHED = BackgroundScheduler()
def schedule_newsletter(newsletter_id, func=None, remove_job=False, args=None, **kwargs):
if NEWSLETTER_SCHED.get_job(newsletter_id):
if remove_job:
NEWSLETTER_SCHED.remove_job(newsletter_id)
else:
NEWSLETTER_SCHED.reschedule_job(
newsletter_id, args=args, trigger=CronTrigger(**kwargs))
elif not remove_job:
NEWSLETTER_SCHED.add_job(
func, args=args, id=newsletter_id, trigger=CronTrigger(**kwargs))
def notify(newsletter_id=None, notify_action=None, **kwargs):
logger.info(u"Tautulli NewsletterHandler :: Preparing newsletter for newsletter_id %s." % newsletter_id)
newsletter_config = newsletters.get_newsletter_config(newsletter_id=newsletter_id)
if not newsletter_config:
return
if notify_action in ('test', 'api'):
subject_string = kwargs.pop('subject', 'Tautulli Newsletter')
else:
# Get the subject string
subject_string = newsletter_config['subject']
newsletter_agent = newsletters.get_agent_class(agent_id=newsletter_config['agent_id'],
config=newsletter_config['config'],
email_config=newsletter_config['email_config'])
subject = newsletter_agent.format_subject(subject_string)
# Set the newsletter state in the db
newsletter_log_id = set_notify_state(newsletter=newsletter_config,
notify_action=notify_action,
subject=subject)
# Send the notification
success = newsletters.send_newsletter(newsletter_id=newsletter_config['id'],
subject=subject,
notify_action=notify_action,
newsletter_log_id=newsletter_log_id,
**kwargs)
if success:
set_notify_success(newsletter_log_id)
return True
def set_notify_state(newsletter, notify_action, subject):
if newsletter and notify_action:
monitor_db = database.MonitorDatabase()
keys = {'timestamp': int(time.time()),
'newsletter_id': newsletter['id'],
'agent_id': newsletter['agent_id'],
'notify_action': notify_action}
values = {'agent_name': newsletter['agent_name'],
'subject_text': subject}
monitor_db.upsert(table_name='newsletter_log', key_dict=keys, value_dict=values)
return monitor_db.last_insert_id()
else:
logger.error(u"Tautulli NewsletterHandler :: Unable to set notify state.")
def set_notify_success(newsletter_log_id):
keys = {'id': newsletter_log_id}
values = {'success': 1}
monitor_db = database.MonitorDatabase()
monitor_db.upsert(table_name='newsletter_log', key_dict=keys, value_dict=values)

View file

@ -50,6 +50,19 @@ def available_newsletter_agents():
return agents return agents
def available_notification_actions():
actions = [{'label': 'Schedule',
'name': 'on_cron',
'description': 'Trigger a notification on a certain schedule.',
'subject': 'Tautulli Newsletter',
'icon': 'fa-calendar',
'media_types': ('newsletter',)
}
]
return actions
def get_agent_class(agent_id=None, config=None, email_config=None): def get_agent_class(agent_id=None, config=None, email_config=None):
if str(agent_id).isdigit(): if str(agent_id).isdigit():
agent_id = int(agent_id) agent_id = int(agent_id)
@ -213,13 +226,15 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
return False return False
def send_newsletter(newsletter_id=None, newsletter_log_id=None, **kwargs): def send_newsletter(newsletter_id=None, subject=None, notify_action='', newsletter_log_id=None, **kwargs):
newsletter_config = get_newsletter_config(newsletter_id=newsletter_id) newsletter_config = get_newsletter_config(newsletter_id=newsletter_id)
if newsletter_config: if newsletter_config:
agent = get_agent_class(agent_id=newsletter_config['agent_id'], agent = get_agent_class(agent_id=newsletter_config['agent_id'],
config=newsletter_config['config'], config=newsletter_config['config'],
email_config=newsletter_config['email_config']) email_config=newsletter_config['email_config'])
return agent.send(newsletter_log_id=newsletter_log_id, **kwargs) return agent.send(subject=subject,
action=notify_action.split('on_')[-1],
newsletter_log_id=newsletter_log_id, **kwargs)
else: else:
logger.debug(u"Tautulli Newsletters :: Notification requested but no newsletter_id received.") logger.debug(u"Tautulli Newsletters :: Notification requested but no newsletter_id received.")
@ -284,7 +299,7 @@ class Newsletter(object):
**kwargs **kwargs
) )
def _format_subject(self, subject): def format_subject(self, subject):
subject = subject or self._DEFAULT_EMAIL_CONFIG['subject'] subject = subject or self._DEFAULT_EMAIL_CONFIG['subject']
try: try:
@ -313,10 +328,10 @@ class Newsletter(object):
self.retrieve_data() self.retrieve_data()
return self.generate_newsletter() return self.generate_newsletter()
def send(self, **kwargs): def send(self, subject='', **kwargs):
self.retrieve_data() self.retrieve_data()
subject = self._format_subject(self.email_config['subject']) subject = self.format_subject(subject or self.email_config['subject'])
newsletter = self.generate_newsletter() newsletter = self.generate_newsletter()
if self.email_config['notifier']: if self.email_config['notifier']:

View file

@ -39,6 +39,7 @@ import http_handler
import libraries import libraries
import log_reader import log_reader
import logger import logger
import newsletter_handler
import newsletters import newsletters
import mobile_app import mobile_app
import notification_handler import notification_handler
@ -5478,7 +5479,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi("notify_newsletter") @addtoapi("notify_newsletter")
def send_newsletter(self, newsletter_id=None, test=False, **kwargs): def send_newsletter(self, newsletter_id=None, subject='Tautulli Newsletter', notify_action='', **kwargs):
""" Send a newsletter using Tautulli. """ Send a newsletter using Tautulli.
``` ```
@ -5494,14 +5495,17 @@ class WebInterface(object):
""" """
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
test = 'test ' if test else '' test = 'test ' if notify_action == 'test' else ''
if newsletter_id: if newsletter_id:
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_label'])) logger.debug(u"Sending %s%s newsletter." % (test, newsletter['agent_label']))
if newsletters.send_newsletter(newsletter_id=newsletter_id): if newsletter_handler.notify(newsletter_id=newsletter_id,
notify_action=notify_action,
subject=subject,
**kwargs):
return "Newsletter sent." return "Newsletter sent."
else: else:
return "Newsletter failed." return "Newsletter failed."
@ -5518,7 +5522,10 @@ class WebInterface(object):
if newsletter_id: if newsletter_id:
newsletter = newsletters.get_newsletter_config(newsletter_id=newsletter_id) newsletter = newsletters.get_newsletter_config(newsletter_id=newsletter_id)
newsletter_agent = newsletters.get_agent_class(agent_id=newsletter['agent_id'], config=newsletter['config']) newsletter_agent = newsletters.get_agent_class(agent_id=newsletter['agent_id'], config=newsletter['config'])
if newsletter_agent: if newsletter_agent:
return newsletter_agent.preview(master=master) return newsletter_agent.preview(master=master)
return return "Invalid newsletter id %s" % newsletter_id
return "Missing newsletter_id parameter"