Add setting to specify newsletter ID name for static URLs

This commit is contained in:
JonnyWong16 2018-05-08 10:54:07 -07:00
parent 8e3fe7bfa2
commit 7778d84728
7 changed files with 61 additions and 31 deletions

View file

@ -166,6 +166,15 @@
% endfor % endfor
</div> </div>
<div class="col-md-12" style="margin-top: 10px; padding-top: 10px; border-top: 1px solid #444;"> <div class="col-md-12" style="margin-top: 10px; padding-top: 10px; border-top: 1px solid #444;">
<div class="form-group">
<label for="id_name">Unique ID Name</label>
<div class="row">
<div class="col-md-12">
<input type="text" class="form-control" id="id_name" name="id_name" value="${newsletter['id_name']}" size="30">
</div>
</div>
<p class="help-block">Enter a unique ID name to create a static URL to the last sent scheduled newsletter at <span class="inline-pre">/newsletter/id/&lt;id_name&gt;</span>. Only letters (a-z), numbers (0-9), underscores (_) and hyphens (-) are allowed. Leave blank to disable.</p>
</div>
<div class="form-group"> <div class="form-group">
<label for="newsletter_config_filename">Filename</label> <label for="newsletter_config_filename">Filename</label>
<div class="row"> <div class="row">
@ -483,6 +492,17 @@
return true; return true;
} }
} }
function validateIDName() {
var id_name = $('#id_name').val();
if (/^[a-zA-Z0-9_-]*$/.test(id_name)) {
return true;
} else {
showMsg('<i class="fa fa-times"></i> Failed to save newsletter. Invalid unique ID name.', false, true, 5000, true);
return false;
}
}
var $incl_libraries = $('#newsletter_config_incl_libraries').selectize({ var $incl_libraries = $('#newsletter_config_incl_libraries').selectize({
plugins: ['remove_button'], plugins: ['remove_button'],
maxItems: null, maxItems: null,
@ -668,7 +688,7 @@
if ($('#custom_cron').val() === '0'){ if ($('#custom_cron').val() === '0'){
$("#cron_value").val(cron_widget.cron('value')); $("#cron_value").val(cron_widget.cron('value'));
} }
if (validateFilename()){ if (validateFilename() && validateIDName()){
doAjaxCall('set_newsletter_config', $(this), 'tabs', true, true, saveCallback); doAjaxCall('set_newsletter_config', $(this), 'tabs', true, true, saveCallback);
} }
} }

View file

@ -969,13 +969,6 @@
Note: The <span class="inline-pre">${http_root}newsletter</span> endpoint on your domain must be publicly accessible from the internet. Note: The <span class="inline-pre">${http_root}newsletter</span> endpoint on your domain must be publicly accessible from the internet.
</p> </p>
<p class="help-block settings-warning base-url-warning">Warning: Public Tautulli domain not set under <a data-tab-destination="tabs-web_interface" data-target="#http_base_url">Web Interface</a>.</p> <p class="help-block settings-warning base-url-warning">Warning: Public Tautulli domain not set under <a data-tab-destination="tabs-web_interface" data-target="#http_base_url">Web Interface</a>.</p>
<div class="checkbox">
<label>
<input type="checkbox" id="newsletter_static_url" name="newsletter_static_url" value="1" ${config['newsletter_static_url']}> Enable Static Newsletter URL
</label>
<p class="help-block">Enable static newsletter URLs to the last sent scheduled newsletter at <span class="inline-pre">${http_root}newsletter/id/&lt;newsletter_id&gt;</span>.</p>
</div>
</div> </div>
<div class="form-group advanced-setting"> <div class="form-group advanced-setting">

View file

@ -637,7 +637,7 @@ def dbcheck():
# 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, '
'agent_id INTEGER, agent_name TEXT, agent_label TEXT, ' 'agent_id INTEGER, agent_name TEXT, agent_label TEXT, id_name TEXT NOT NULL DEFAULT "", '
'friendly_name TEXT, newsletter_config TEXT, email_config TEXT, ' 'friendly_name TEXT, newsletter_config TEXT, email_config TEXT, '
'subject TEXT, body TEXT, message TEXT, ' 'subject TEXT, body TEXT, message 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)'
@ -1504,6 +1504,15 @@ def dbcheck():
'ALTER TABLE newsletter_log ADD COLUMN filename TEXT' 'ALTER TABLE newsletter_log ADD COLUMN filename TEXT'
) )
# Upgrade newsletters table from earlier versions
try:
c_db.execute('SELECT id_name FROM newsletters')
except sqlite3.OperationalError:
logger.debug(u"Altering database. Updating database table newsletters.")
c_db.execute(
'ALTER TABLE newsletters ADD COLUMN id_name TEXT NOT NULL DEFAULT ""'
)
# Upgrade library_sections table from earlier versions (remove UNIQUE constraint on section_id) # Upgrade library_sections table from earlier versions (remove UNIQUE constraint on section_id)
try: try:
result = c_db.execute('SELECT SQL FROM sqlite_master WHERE type="table" AND name="library_sections"').fetchone() result = c_db.execute('SELECT SQL FROM sqlite_master WHERE type="table" AND name="library_sections"').fetchone()

View file

@ -527,7 +527,8 @@ NEWSLETTER_PARAMETERS = [
{'name': 'Newsletter URL', 'type': 'str', 'value': 'newsletter_url', 'description': 'The self-hosted URL to the newsletter.'}, {'name': 'Newsletter URL', 'type': 'str', 'value': 'newsletter_url', 'description': 'The self-hosted URL to the newsletter.'},
{'name': 'Newsletter Static URL', 'type': 'str', 'value': 'newsletter_static_url', 'description': 'The static self-hosted URL to the latest scheduled newsletter for the agent.'}, {'name': 'Newsletter Static URL', 'type': 'str', 'value': 'newsletter_static_url', 'description': 'The static self-hosted URL to the latest scheduled newsletter for the agent.'},
{'name': 'Newsletter UUID', 'type': 'str', 'value': 'newsletter_uuid', 'description': 'The unique identifier for the newsletter.'}, {'name': 'Newsletter UUID', 'type': 'str', 'value': 'newsletter_uuid', 'description': 'The unique identifier for the newsletter.'},
{'name': 'Newsletter ID', 'type': 'int', 'value': 'newsletter_id', 'description': 'The ID number for the newsletter agent.'}, {'name': 'Newsletter ID', 'type': 'int', 'value': 'newsletter_id', 'description': 'The unique ID number for the newsletter agent.'},
{'name': 'Newsletter ID Name', 'type': 'int', 'value': 'newsletter_id_name', 'description': 'The unique ID name for the newsletter agent.'},
] ]
}, },
{ {

View file

@ -87,6 +87,7 @@ def notify(newsletter_id=None, notify_action=None, **kwargs):
message = newsletter_config['message'] message = newsletter_config['message']
newsletter_agent = newsletters.get_agent_class(newsletter_id=newsletter_id, newsletter_agent = newsletters.get_agent_class(newsletter_id=newsletter_id,
newsletter_id_name=newsletter_config['id_name'],
agent_id=newsletter_config['agent_id'], 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'],
@ -152,21 +153,21 @@ def set_notify_success(newsletter_log_id):
db.upsert(table_name='newsletter_log', key_dict=keys, value_dict=values) db.upsert(table_name='newsletter_log', key_dict=keys, value_dict=values)
def get_newsletter(newsletter_uuid=None, newsletter_id=None): def get_newsletter(newsletter_uuid=None, newsletter_id_name=None):
db = database.MonitorDatabase() db = database.MonitorDatabase()
if newsletter_uuid: if newsletter_uuid:
result = db.select_single('SELECT newsletter_id, start_date, end_date, uuid, filename FROM newsletter_log ' result = db.select_single('SELECT start_date, end_date, uuid, filename FROM newsletter_log '
'WHERE uuid = ?', [newsletter_uuid]) 'WHERE uuid = ?', [newsletter_uuid])
elif newsletter_id: elif newsletter_id_name:
result = db.select_single('SELECT newsletter_id, start_date, end_date, uuid, filename FROM newsletter_log ' result = db.select_single('SELECT start_date, end_date, uuid, filename FROM newsletter_log '
'WHERE newsletter_id = ? AND notify_action != "test" ' 'JOIN newsletters ON newsletters.id = newsletter_log.newsletter_id '
'ORDER BY timestamp DESC LIMIT 1', [newsletter_id]) 'WHERE id_name = ? AND notify_action != "test" '
'ORDER BY timestamp DESC LIMIT 1', [newsletter_id_name])
else: else:
result = None result = None
if result: if result:
newsletter_id = result['newsletter_id']
newsletter_uuid = result['uuid'] newsletter_uuid = result['uuid']
start_date = result['start_date'] start_date = result['start_date']
end_date = result['end_date'] end_date = result['end_date']

View file

@ -63,12 +63,13 @@ def available_notification_actions():
return actions return actions
def get_agent_class(newsletter_id=None, agent_id=None, config=None, email_config=None, start_date=None, end_date=None, def get_agent_class(newsletter_id=None, newsletter_id_name=None, agent_id=None, config=None, email_config=None,
subject=None, body=None, message=None): start_date=None, end_date=None, subject=None, body=None, message=None):
if str(agent_id).isdigit(): if str(agent_id).isdigit():
agent_id = int(agent_id) agent_id = int(agent_id)
kwargs = {'newsletter_id': newsletter_id, kwargs = {'newsletter_id': newsletter_id,
'newsletter_id_name': newsletter_id_name,
'config': config, 'config': config,
'email_config': email_config, 'email_config': email_config,
'start_date': start_date, 'start_date': start_date,
@ -139,7 +140,8 @@ def get_newsletter_config(newsletter_id=None):
subject = result.pop('subject') subject = result.pop('subject')
body = result.pop('body') body = result.pop('body')
message = result.pop('message') message = result.pop('message')
newsletter_agent = get_agent_class(newsletter_id=newsletter_id, agent_id=result['agent_id'], newsletter_agent = get_agent_class(newsletter_id=newsletter_id, newsletter_id_name=result['id_name'],
agent_id=result['agent_id'],
config=config, email_config=email_config, config=config, email_config=email_config,
subject=subject, body=body, message=message) subject=subject, body=body, message=message)
except Exception as e: except Exception as e:
@ -178,6 +180,7 @@ def add_newsletter_config(agent_id=None, **kwargs):
values = {'agent_id': agent['id'], values = {'agent_id': agent['id'],
'agent_name': agent['name'], 'agent_name': agent['name'],
'agent_label': agent['label'], 'agent_label': agent['label'],
'id_name': '',
'friendly_name': '', '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),
@ -225,7 +228,7 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
body = kwargs.pop('body') body = kwargs.pop('body')
message = kwargs.pop('message') message = kwargs.pop('message')
agent_class = get_agent_class(newsletter_id=newsletter_id, agent_id=agent['id'], agent_class = get_agent_class(agent_id=agent['id'],
config=newsletter_config, email_config=email_config, config=newsletter_config, email_config=email_config,
subject=subject, body=body, message=message) subject=subject, body=body, message=message)
@ -233,6 +236,7 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
values = {'agent_id': agent['id'], values = {'agent_id': agent['id'],
'agent_name': agent['name'], 'agent_name': agent['name'],
'agent_label': agent['label'], 'agent_label': agent['label'],
'id_name': kwargs.get('id_name', ''),
'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),
@ -318,13 +322,14 @@ class Newsletter(object):
_TEMPLATE_MASTER = '' _TEMPLATE_MASTER = ''
_TEMPLATE = '' _TEMPLATE = ''
def __init__(self, newsletter_id=None, config=None, email_config=None, start_date=None, end_date=None, def __init__(self, newsletter_id=None, newsletter_id_name=None, config=None, email_config=None,
subject=None, body=None, message=None): start_date=None, end_date=None, subject=None, body=None, message=None):
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.uuid = generate_newsletter_uuid() self.uuid = generate_newsletter_uuid()
self.newsletter_id = newsletter_id self.newsletter_id = newsletter_id
self.newsletter_id_name = newsletter_id_name
self.start_date = None self.start_date = None
self.end_date = None self.end_date = None
@ -506,9 +511,10 @@ class Newsletter(object):
'newsletter_time_frame': self.config['time_frame'], 'newsletter_time_frame': self.config['time_frame'],
'newsletter_time_frame_units': self.config['time_frame_units'], 'newsletter_time_frame_units': self.config['time_frame_units'],
'newsletter_url': base_url + self.uuid, 'newsletter_url': base_url + self.uuid,
'newsletter_static_url': base_url + 'id/' + str(self.newsletter_id), 'newsletter_static_url': base_url + 'id/' + self.newsletter_id_name,
'newsletter_uuid': self.uuid, 'newsletter_uuid': self.uuid,
'newsletter_id': self.newsletter_id 'newsletter_id': self.newsletter_id,
'newsletter_id_name': self.newsletter_id_name
} }
return parameters return parameters

View file

@ -2756,7 +2756,6 @@ class WebInterface(object):
"show_advanced_settings": plexpy.CONFIG.SHOW_ADVANCED_SETTINGS, "show_advanced_settings": plexpy.CONFIG.SHOW_ADVANCED_SETTINGS,
"newsletter_dir": plexpy.CONFIG.NEWSLETTER_DIR, "newsletter_dir": plexpy.CONFIG.NEWSLETTER_DIR,
"newsletter_self_hosted": checked(plexpy.CONFIG.NEWSLETTER_SELF_HOSTED), "newsletter_self_hosted": checked(plexpy.CONFIG.NEWSLETTER_SELF_HOSTED),
"newsletter_static_url": checked(plexpy.CONFIG.NEWSLETTER_STATIC_URL),
"newsletter_custom_dir": plexpy.CONFIG.NEWSLETTER_CUSTOM_DIR "newsletter_custom_dir": plexpy.CONFIG.NEWSLETTER_CUSTOM_DIR
} }
@ -2779,7 +2778,7 @@ class WebInterface(object):
"allow_guest_access", "cache_images", "http_proxy", "http_basic_auth", "notify_concurrent_by_ip", "allow_guest_access", "cache_images", "http_proxy", "http_basic_auth", "notify_concurrent_by_ip",
"history_table_activity", "plexpy_auto_update", "history_table_activity", "plexpy_auto_update",
"themoviedb_lookup", "tvmaze_lookup", "http_plex_admin", "themoviedb_lookup", "tvmaze_lookup", "http_plex_admin",
"newsletter_self_hosted", "newsletter_static_url" "newsletter_self_hosted"
] ]
for checked_config in checked_configs: for checked_config in checked_configs:
if checked_config not in kwargs: if checked_config not in kwargs:
@ -5666,15 +5665,15 @@ class WebInterface(object):
cherrypy.response.headers['Cache-Control'] = 'max-age=2592000' # 30 days cherrypy.response.headers['Cache-Control'] = 'max-age=2592000' # 30 days
return self.image(args[1], refresh=True) return self.image(args[1], refresh=True)
if plexpy.CONFIG.NEWSLETTER_STATIC_URL and len(args) >= 2 and args[0] == 'id': if len(args) >= 2 and args[0] == 'id':
newsletter_id = args[1] newsletter_id_name = args[1]
newsletter_uuid = None newsletter_uuid = None
else: else:
newsletter_id = None newsletter_id_name = None
newsletter_uuid = args[0] newsletter_uuid = args[0]
newsletter = newsletter_handler.get_newsletter(newsletter_uuid=newsletter_uuid, newsletter = newsletter_handler.get_newsletter(newsletter_uuid=newsletter_uuid,
newsletter_id=newsletter_id) newsletter_id_name=newsletter_id_name)
return newsletter return newsletter
@cherrypy.expose @cherrypy.expose
@ -5694,6 +5693,7 @@ class WebInterface(object):
if newsletter: if newsletter:
newsletter_agent = newsletters.get_agent_class(newsletter_id=newsletter_id, newsletter_agent = newsletters.get_agent_class(newsletter_id=newsletter_id,
newsletter_id_name=newsletter['id_name'],
agent_id=newsletter['agent_id'], agent_id=newsletter['agent_id'],
config=newsletter['config'], config=newsletter['config'],
start_date=start_date, start_date=start_date,