mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 13:11:15 -07:00
Save newsletters to html file
This commit is contained in:
parent
b6bd305694
commit
b9b82b23f7
11 changed files with 111 additions and 41 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -15,7 +15,9 @@
|
|||
release.lock
|
||||
version.lock
|
||||
logs/*
|
||||
backups/*
|
||||
cache/*
|
||||
newsletters/*
|
||||
*.mmdb
|
||||
|
||||
# HTTPS Cert/Key #
|
||||
|
|
|
@ -49,6 +49,10 @@ DOCUMENTATION :: END
|
|||
<td>Cache Directory:</td>
|
||||
<td>${plexpy.CONFIG.CACHE_DIR}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Newsletter Directory:</td>
|
||||
<td>${plexpy.CONFIG.NEWSLETTER_DIR}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GeoLite2 Database:</td>
|
||||
% if plexpy.CONFIG.GEOIP_DB:
|
||||
|
|
|
@ -1043,6 +1043,17 @@
|
|||
<h3>Directories</h3>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="log_dir">Log Directory</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control directory-settings" id="log_dir" name="log_dir" value="${config['log_dir']}">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-form" type="button" id="clear_logs">Clear Logs</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="backup_dir">Backup Directory</label>
|
||||
<div class="row">
|
||||
|
@ -1068,13 +1079,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="log_dir">Log Directory</label>
|
||||
<label for="newsletter_dir">Newsletter Directory</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control directory-settings" id="log_dir" name="log_dir" value="${config['log_dir']}">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-form" type="button" id="clear_logs">Clear Logs</button>
|
||||
</div>
|
||||
<input type="text" class="form-control directory-settings" id="newsletter_dir" name="newsletter_dir" value="${config['newsletter_dir']}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>Tautulli ${title} Newsletter</title>
|
||||
<title>Tautulli Newsletter - ${title}</title>
|
||||
<style>
|
||||
/* -------------------------------------
|
||||
GLOBAL RESETS
|
||||
|
@ -567,7 +567,7 @@
|
|||
<div class="content" style="box-sizing: border-box;display: block;margin: 0 auto;max-width: 1042px;padding: 10px;">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<span class="preheader" style="color: transparent;display: none;height: 0;max-height: 0;max-width: 0;opacity: 0;overflow: hidden;mso-hide: all;visibility: hidden;width: 0;">Tautulli ${title} Newsletter (${parameters['start_date']} - ${parameters['end_date']})</span>
|
||||
<span class="preheader">Tautulli Newsletter - ${title}</span>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="main" style="border-collapse: separate;mso-table-lspace: 0pt;mso-table-rspace: 0pt;width: 100%;background: #282A2D;border-radius: 3px;color: #ffffff;">
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<head>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<title>Tautulli ${title} Newsletter</title>
|
||||
<title>Tautulli Newsletter - ${title}</title>
|
||||
<style>
|
||||
/* -------------------------------------
|
||||
GLOBAL RESETS
|
||||
|
@ -567,7 +567,7 @@
|
|||
<div class="content">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<span class="preheader">Tautulli ${title} Newsletter (${parameters['start_date']} - ${parameters['end_date']})</span>
|
||||
<span class="preheader">Tautulli Newsletter - ${title}</span>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="main">
|
||||
|
||||
|
|
|
@ -167,6 +167,14 @@ def initialize(config_file):
|
|||
except OSError as e:
|
||||
logger.error(u"Could not create cache dir '%s': %s" % (CONFIG.CACHE_DIR, e))
|
||||
|
||||
if not CONFIG.NEWSLETTER_DIR:
|
||||
CONFIG.NEWSLETTER_DIR = os.path.join(DATA_DIR, 'newsletters')
|
||||
if not os.path.exists(CONFIG.NEWSLETTER_DIR):
|
||||
try:
|
||||
os.makedirs(CONFIG.NEWSLETTER_DIR)
|
||||
except OSError as e:
|
||||
logger.error(u"Could not create newsletter dir '%s': %s" % (CONFIG.NEWSLETTER_DIR, e))
|
||||
|
||||
# Initialize the database
|
||||
logger.info(u"Checking if the database upgrades are required...")
|
||||
try:
|
||||
|
|
|
@ -308,6 +308,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'MONITOR_REMOTE_ACCESS': (int, 'Monitoring', 0),
|
||||
'MONITORING_INTERVAL': (int, 'Monitoring', 60),
|
||||
'MONITORING_USE_WEBSOCKET': (int, 'Monitoring', 0),
|
||||
'NEWSLETTER_DIR': (str, 'General', ''),
|
||||
'NMA_APIKEY': (str, 'NMA', ''),
|
||||
'NMA_ENABLED': (int, 'NMA', 0),
|
||||
'NMA_PRIORITY': (int, 'NMA', 0),
|
||||
|
@ -656,7 +657,7 @@ def make_backup(cleanup=False, scheduler=False):
|
|||
logger.debug(u"Tautulli Config :: Successfully backed up %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
||||
return True
|
||||
else:
|
||||
logger.warn(u"Tautulli Config :: Failed to backup %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
||||
logger.error(u"Tautulli Config :: Failed to backup %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ def make_backup(cleanup=False, scheduler=False):
|
|||
logger.debug(u"Tautulli Database :: Successfully backed up %s to %s" % (db_filename(), backup_file))
|
||||
return True
|
||||
else:
|
||||
logger.warn(u"Tautulli Database :: Failed to backup %s to %s" % (db_filename(), backup_file))
|
||||
logger.error(u"Tautulli Database :: Failed to backup %s to %s" % (db_filename(), backup_file))
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
@ -78,7 +79,8 @@ def notify(newsletter_id=None, notify_action=None, **kwargs):
|
|||
notify_action=notify_action,
|
||||
subject=newsletter_agent.subject,
|
||||
start_date=newsletter_agent.start_date.format('YYYY-MM-DD'),
|
||||
end_date=newsletter_agent.end_date.format('YYYY-MM-DD'))
|
||||
end_date=newsletter_agent.end_date.format('YYYY-MM-DD'),
|
||||
newsletter_uuid=newsletter_agent.uuid)
|
||||
|
||||
# Send the notification
|
||||
success = newsletter_agent.send()
|
||||
|
@ -88,13 +90,13 @@ def notify(newsletter_id=None, notify_action=None, **kwargs):
|
|||
return True
|
||||
|
||||
|
||||
def set_notify_state(newsletter, notify_action, subject, start_date, end_date):
|
||||
def set_notify_state(newsletter, notify_action, subject, start_date, end_date, newsletter_uuid):
|
||||
|
||||
if newsletter and notify_action:
|
||||
db = database.MonitorDatabase()
|
||||
|
||||
keys = {'timestamp': int(time.time()),
|
||||
'uuid': generate_newsletter_uuid()}
|
||||
'uuid': newsletter_uuid}
|
||||
|
||||
values = {'newsletter_id': newsletter['id'],
|
||||
'agent_id': newsletter['agent_id'],
|
||||
|
@ -118,22 +120,32 @@ def set_notify_success(newsletter_log_id):
|
|||
db.upsert(table_name='newsletter_log', key_dict=keys, value_dict=values)
|
||||
|
||||
|
||||
def generate_newsletter_uuid():
|
||||
uuid = ''
|
||||
uuid_exists = 0
|
||||
db = database.MonitorDatabase()
|
||||
|
||||
while not uuid or uuid_exists:
|
||||
uuid = plexpy.generate_uuid()[:8]
|
||||
result = db.select_single(
|
||||
'SELECT EXISTS(SELECT uuid FROM newsletter_log WHERE uuid = ?) as uuid_exists', [uuid])
|
||||
uuid_exists = result['uuid_exists']
|
||||
|
||||
return uuid
|
||||
|
||||
|
||||
def get_newsletter(newsletter_uuid):
|
||||
db = database.MonitorDatabase()
|
||||
result = db.select_single('SELECT newsletter_id, start_date, end_date FROM newsletter_log '
|
||||
'WHERE uuid = ?', [newsletter_uuid])
|
||||
return result
|
||||
|
||||
if result:
|
||||
newsletter_id = result['newsletter_id']
|
||||
start_date = result['start_date']
|
||||
end_date = result['end_date']
|
||||
|
||||
newsletter_file = 'newsletter_%s-%s_%s.html' % (start_date.replace('-', ''),
|
||||
end_date.replace('-', ''),
|
||||
newsletter_uuid)
|
||||
newsletter_folder = plexpy.CONFIG.NEWSLETTER_DIR
|
||||
newsletter_file_fp = os.path.join(newsletter_folder, newsletter_file)
|
||||
|
||||
if newsletter_file in os.listdir(newsletter_folder):
|
||||
try:
|
||||
with open(newsletter_file_fp, 'r') as n_file:
|
||||
newsletter = n_file.read()
|
||||
return newsletter
|
||||
except OSError as e:
|
||||
logger.error(u"Tautulli NewsletterHandler :: Failed to retrieve newsletter '%s': %s" % (newsletter_uuid, e))
|
||||
return "Failed to retrieve newsletter"
|
||||
else:
|
||||
logger.warn(u"Tautulli NewsletterHandler :: Newsletter '%s' file is missing." % newsletter_uuid)
|
||||
return "Newsletter no longer exists"
|
||||
else:
|
||||
return "Newsletter does not exist"
|
||||
|
|
|
@ -259,6 +259,20 @@ def serve_template(templatename, **kwargs):
|
|||
return exceptions.html_error_template().render()
|
||||
|
||||
|
||||
def generate_newsletter_uuid():
|
||||
uuid = ''
|
||||
uuid_exists = 0
|
||||
db = database.MonitorDatabase()
|
||||
|
||||
while not uuid or uuid_exists:
|
||||
uuid = plexpy.generate_uuid()[:8]
|
||||
result = db.select_single(
|
||||
'SELECT EXISTS(SELECT uuid FROM newsletter_log WHERE uuid = ?) as uuid_exists', [uuid])
|
||||
uuid_exists = result['uuid_exists']
|
||||
|
||||
return uuid
|
||||
|
||||
|
||||
class Newsletter(object):
|
||||
NAME = ''
|
||||
_DEFAULT_CONFIG = {'last_days': 7}
|
||||
|
@ -307,6 +321,8 @@ class Newsletter(object):
|
|||
|
||||
self.subject = self.format_subject(self.email_config['subject'])
|
||||
|
||||
self.uuid = generate_newsletter_uuid()
|
||||
|
||||
self.is_preview = False
|
||||
|
||||
self.data = {}
|
||||
|
@ -355,7 +371,7 @@ class Newsletter(object):
|
|||
|
||||
return serve_template(
|
||||
templatename=template,
|
||||
title=self.NAME,
|
||||
title=self.subject,
|
||||
parameters=self.parameters,
|
||||
data=self.data,
|
||||
preview=self.is_preview
|
||||
|
@ -364,6 +380,30 @@ class Newsletter(object):
|
|||
def send(self):
|
||||
newsletter = self.generate_newsletter()
|
||||
|
||||
self._save(newsletter)
|
||||
return self._send(newsletter)
|
||||
|
||||
def _save(self, newsletter):
|
||||
newsletter_file = 'newsletter_%s-%s_%s.html' % (self.start_date.format('YYYYMMDD'),
|
||||
self.end_date.format('YYYYMMDD'),
|
||||
self.uuid)
|
||||
newsletter_folder = plexpy.CONFIG.NEWSLETTER_DIR
|
||||
newsletter_file_fp = os.path.join(newsletter_folder, newsletter_file)
|
||||
|
||||
# In case the user has deleted it manually
|
||||
if not os.path.exists(newsletter_folder):
|
||||
os.makedirs(newsletter_folder)
|
||||
|
||||
try:
|
||||
with open(newsletter_file_fp, 'w') as n_file:
|
||||
n_file.write(newsletter)
|
||||
|
||||
logger.info(u"Tautulli Newsletters :: %s newsletter saved to %s" % (self.NAME, newsletter_file))
|
||||
except OSError as e:
|
||||
logger.error(u"Tautulli Newsletters :: Failed to save %s newsletter to %s: %s"
|
||||
% (self.NAME, newsletter_file, e))
|
||||
|
||||
def _send(self, newsletter):
|
||||
if not self._has_data():
|
||||
logger.warn(u"Tautulli Newsletters :: %s newsletter has no data. Newsletter not sent." % self.NAME)
|
||||
return False
|
||||
|
|
|
@ -2658,7 +2658,8 @@ class WebInterface(object):
|
|||
"music_watched_percent": plexpy.CONFIG.MUSIC_WATCHED_PERCENT,
|
||||
"themoviedb_lookup": checked(plexpy.CONFIG.THEMOVIEDB_LOOKUP),
|
||||
"tvmaze_lookup": checked(plexpy.CONFIG.TVMAZE_LOOKUP),
|
||||
"show_advanced_settings": plexpy.CONFIG.SHOW_ADVANCED_SETTINGS
|
||||
"show_advanced_settings": plexpy.CONFIG.SHOW_ADVANCED_SETTINGS,
|
||||
"newsletter_dir": plexpy.CONFIG.NEWSLETTER_DIR
|
||||
}
|
||||
|
||||
return serve_template(templatename="settings.html", title="Settings", config=config, kwargs=kwargs)
|
||||
|
@ -5474,7 +5475,7 @@ class WebInterface(object):
|
|||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@addtoapi("notify_newsletter")
|
||||
def send_newsletter(self, newsletter_id=None, subject='Tautulli Newsletter', notify_action='', **kwargs):
|
||||
def send_newsletter(self, newsletter_id=None, subject='', notify_action='', **kwargs):
|
||||
""" Send a newsletter using Tautulli.
|
||||
|
||||
```
|
||||
|
@ -5527,15 +5528,9 @@ class WebInterface(object):
|
|||
preview=False, master=False, raw=False, **kwargs):
|
||||
if newsletter_uuid:
|
||||
newsletter = newsletter_handler.get_newsletter(newsletter_uuid=newsletter_uuid)
|
||||
return newsletter
|
||||
|
||||
if newsletter:
|
||||
newsletter_id = newsletter['newsletter_id']
|
||||
start_date = newsletter['start_date']
|
||||
end_date = newsletter['end_date']
|
||||
else:
|
||||
return "This newsletter does not exist"
|
||||
|
||||
if newsletter_id:
|
||||
if newsletter_id and newsletter_id != 'None':
|
||||
newsletter = newsletters.get_newsletter_config(newsletter_id=newsletter_id)
|
||||
|
||||
if newsletter:
|
||||
|
@ -5553,7 +5548,7 @@ class WebInterface(object):
|
|||
|
||||
return newsletter_agent.generate_newsletter(preview=preview, master=master)
|
||||
|
||||
logger.error(u"Failed to retrieve newsletter: Invalid newsletter_id #%s" % newsletter_id)
|
||||
logger.error(u"Failed to retrieve newsletter: Invalid newsletter_id %s" % newsletter_id)
|
||||
return "Failed to retrieve newsletter"
|
||||
|
||||
logger.error(u"Failed to retrieve newsletter: Missing newsletter_id parameter.")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue