mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-13 18:16:57 -07:00
Add selectize for email input
This commit is contained in:
parent
a3e6e76158
commit
5089ede207
4 changed files with 153 additions and 22 deletions
|
@ -79,6 +79,13 @@ select.form-control {
|
|||
padding: 1px 2px;
|
||||
transition: background-color .3s;
|
||||
}
|
||||
.selectize-control.form-control .selectize-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 4px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.react-selectize.root-node .react-selectize-control .react-selectize-placeholder {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
@ -95,7 +102,7 @@ select.form-control {
|
|||
.react-selectize.root-node .simple-value span {
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
.react-selectize.root-node .react-selectize-control .react-selectize-search-field-and-selected-values .resizable-input{
|
||||
.react-selectize.root-node .react-selectize-control .react-selectize-search-field-and-selected-values .resizable-input {
|
||||
padding-top: 3px !important;
|
||||
padding-bottom: 3px !important;
|
||||
}
|
||||
|
@ -110,7 +117,7 @@ select.form-control:focus,
|
|||
}
|
||||
.react-selectize.root-node.open .simple-value,
|
||||
.selectize-control.multi .selectize-input.focus > div,
|
||||
.selectize-control.multi .selectize-input > div.active{
|
||||
.selectize-control.multi .selectize-input > div.active {
|
||||
background: #efefef !important;
|
||||
color: #333333 !important;
|
||||
transition: background-color .3s;
|
||||
|
@ -118,6 +125,28 @@ select.form-control:focus,
|
|||
.react-selectize.root-node.open .react-selectize-control .react-selectize-toggle-button path {
|
||||
fill: #999 !important;
|
||||
}
|
||||
.selectize-control .selectize-input > div .email {
|
||||
opacity: 0.8;
|
||||
font-size: 12px;
|
||||
}
|
||||
.selectize-control .selectize-input > div .user + .email {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.selectize-control .selectize-input > div .email:before {
|
||||
content: '<';
|
||||
opacity: 0.8;
|
||||
font-size: 12px;
|
||||
}
|
||||
.selectize-control .selectize-input > div .email:after {
|
||||
content: '>';
|
||||
opacity: 0.8;
|
||||
font-size: 12px;
|
||||
}
|
||||
.selectize-control .selectize-dropdown .caption {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
color: #a0a0a0;
|
||||
}
|
||||
select.form-control option {
|
||||
color: #555;
|
||||
background-color: #fff;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<%!
|
||||
from plexpy import helpers, notifiers
|
||||
import json
|
||||
from plexpy import helpers, notifiers, users
|
||||
available_notification_actions = notifiers.available_notification_actions()
|
||||
|
||||
user_emails = [{'user': u['friendly_name'] or u['username'], 'email': u['email']} for u in users.Users().get_users() if u['email']]
|
||||
sorted(user_emails, key=lambda u: u['user'])
|
||||
%>
|
||||
% if notifier:
|
||||
<link href="${http_root}css/selectize.bootstrap3.css" rel="stylesheet" />
|
||||
|
@ -39,7 +43,7 @@
|
|||
<div class="form-group">
|
||||
<label for="${item['name']}">${item['label']}</label>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<input type="${item['input_type']}" class="form-control" id="${item['name']}" name="${item['name']}" value="${item['value']}" size="30" ${'readonly' if item.get('readonly') else ''}>
|
||||
% if item['name'] == 'osx_notify_app':
|
||||
<a href="javascript:void(0)" id="osxnotifyregister">Register</a>
|
||||
|
@ -62,7 +66,7 @@
|
|||
<div class="form-group">
|
||||
<label for="${item['name']}">${item['label']}</label>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<input type="button" class="btn btn-bright" id="${item['name']}" name="${item['name']}" value="${item['value']}">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,7 +84,7 @@
|
|||
<div class="form-group">
|
||||
<label for="${item['name']}">${item['label']}</label>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="${item['name']}" name="${item['name']}">
|
||||
% for key, value in sorted(item['select_options'].iteritems()):
|
||||
% if key == item['value']:
|
||||
|
@ -101,7 +105,7 @@
|
|||
<div class="form-group">
|
||||
<label for="friendly_name">Description</label>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${notifier['friendly_name']}" size="30">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -185,7 +189,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<input type="button" class="btn btn-bright notifier-text-preview" data-action="${action['name']}" value="Preview Arguments">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -212,7 +216,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<input type="button" class="btn btn-bright notifier-text-preview" data-action="${action['name']}" value="Preview Text">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -278,7 +282,7 @@
|
|||
% endif
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<input type="button" class="btn btn-bright" id="test_notifier" name="test_notifier" value="Test ${notifier['agent_label']}">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -465,6 +469,70 @@
|
|||
var osx_notify_app = $('#osx_notify_app').val();
|
||||
$.get('osxnotifyregister', { 'app': osx_notify_app }, function (data) { showMsg('<i class="fa fa-check"></i> ' + data, false, true, 3000); });
|
||||
})
|
||||
|
||||
% elif notifier['agent_name'] == 'email':
|
||||
var REGEX_EMAIL = '([a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@' +
|
||||
'(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)';
|
||||
var $email_selectors = $('#email_to, #email_cc, #email_bcc').selectize({
|
||||
plugins: ['remove_button'],
|
||||
persist: false,
|
||||
maxItems: null,
|
||||
valueField: 'email',
|
||||
labelField: 'user',
|
||||
searchField: ['user', 'email'],
|
||||
options: ${json.dumps(user_emails) | n},
|
||||
render: {
|
||||
item: function(item, escape) {
|
||||
return '<div>' +
|
||||
(item.user ? '<span class="user">' + escape(item.user) + '</span>' : '') +
|
||||
(item.email ? '<span class="email">' + escape(item.email) + '</span>' : '') +
|
||||
'</div>';
|
||||
},
|
||||
option: function(item, escape) {
|
||||
var label = item.user || item.email;
|
||||
var caption = item.user ? item.email : null;
|
||||
return '<div>' +
|
||||
escape(label) +
|
||||
(caption ? '<span class="caption">' + escape(caption) + '</span>' : '') +
|
||||
'</div>';
|
||||
}
|
||||
},
|
||||
createFilter: function(input) {
|
||||
var match, regex;
|
||||
|
||||
// email@address.com
|
||||
regex = new RegExp('^' + REGEX_EMAIL + '$', 'i');
|
||||
match = input.match(regex);
|
||||
if (match) return !this.options.hasOwnProperty(match[0]);
|
||||
|
||||
// user <email@address.com>
|
||||
regex = new RegExp('^([^<]*)\<' + REGEX_EMAIL + '\>$', 'i');
|
||||
match = input.match(regex);
|
||||
if (match) return !this.options.hasOwnProperty(match[2]);
|
||||
|
||||
return false;
|
||||
},
|
||||
create: function(input) {
|
||||
if ((new RegExp('^' + REGEX_EMAIL + '$', 'i')).test(input)) {
|
||||
return {email: input};
|
||||
}
|
||||
var match = input.match(new RegExp('^([^<]*)\<' + REGEX_EMAIL + '\>$', 'i'));
|
||||
if (match) {
|
||||
return {
|
||||
email : match[2],
|
||||
user : $.trim(match[1])
|
||||
};
|
||||
}
|
||||
alert('Invalid email address.');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
var email_to = $email_selectors[0].selectize;
|
||||
var email_cc = $email_selectors[1].selectize;
|
||||
var email_bcc = $email_selectors[2].selectize;
|
||||
email_to.setValue(${json.dumps(next((c['value'] for c in notifier['config_options'] if c['name'] == 'email_to'), [])) | n});
|
||||
email_cc.setValue(${json.dumps(next((c['value'] for c in notifier['config_options'] if c['name'] == 'email_cc'), [])) | n});
|
||||
email_bcc.setValue(${json.dumps(next((c['value'] for c in notifier['config_options'] if c['name'] == 'email_bcc'), [])) | n});
|
||||
% endif
|
||||
|
||||
function validateLogic() {
|
||||
|
|
|
@ -60,6 +60,7 @@ import logger
|
|||
import mobile_app
|
||||
import pmsconnect
|
||||
import request
|
||||
import users
|
||||
from plexpy.config import _BLACKLIST_KEYS, _WHITELIST_KEYS
|
||||
|
||||
|
||||
|
@ -1245,6 +1246,16 @@ class EMAIL(Notifier):
|
|||
'html_support': 1
|
||||
}
|
||||
|
||||
def __init__(self, config=None):
|
||||
super(EMAIL, self).__init__(config=config)
|
||||
|
||||
if not isinstance(self.config['to'], list):
|
||||
self.config['to'] = [x.strip() for x in self.config['to'].split(';')]
|
||||
if not isinstance(self.config['cc'], list):
|
||||
self.config['cc'] = [x.strip() for x in self.config['cc'].split(';')]
|
||||
if not isinstance(self.config['bcc'], list):
|
||||
self.config['bcc'] = [x.strip() for x in self.config['bcc'].split(';')]
|
||||
|
||||
def notify(self, subject='', body='', action='', **kwargs):
|
||||
if not subject or not body:
|
||||
return
|
||||
|
@ -1259,13 +1270,10 @@ class EMAIL(Notifier):
|
|||
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = email.utils.formataddr((self.config['from_name'], self.config['from']))
|
||||
msg['To'] = self.config['to']
|
||||
msg['CC'] = self.config['cc']
|
||||
msg['To'] = ','.join(self.config['to'])
|
||||
msg['CC'] = ','.join(self.config['cc'])
|
||||
|
||||
recipients = [x.strip() for x in self.config['to'].split(';')] \
|
||||
+ [x.strip() for x in self.config['cc'].split(';')] \
|
||||
+ [x.strip() for x in self.config['bcc'].split(';')]
|
||||
recipients = filter(None, recipients)
|
||||
recipients = self.config['to'] + self.config['cc'] + self.config['bcc']
|
||||
|
||||
try:
|
||||
mailserver = smtplib.SMTP(self.config['smtp_server'], self.config['smtp_port'])
|
||||
|
@ -1289,6 +1297,8 @@ class EMAIL(Notifier):
|
|||
return False
|
||||
|
||||
def return_config_options(self):
|
||||
user_emails = {} # User selection set with selectize options
|
||||
|
||||
config_option = [{'label': 'From Name',
|
||||
'value': self.config['from_name'],
|
||||
'name': 'email_from_name',
|
||||
|
@ -1304,20 +1314,23 @@ class EMAIL(Notifier):
|
|||
{'label': 'To',
|
||||
'value': self.config['to'],
|
||||
'name': 'email_to',
|
||||
'description': 'The email address(es) of the recipients, separated by semicolons (;).',
|
||||
'input_type': 'text'
|
||||
'description': 'The email address(es) of the recipients.',
|
||||
'input_type': 'select',
|
||||
'select_options': user_emails
|
||||
},
|
||||
{'label': 'CC',
|
||||
'value': self.config['cc'],
|
||||
'name': 'email_cc',
|
||||
'description': 'The email address(es) to CC, separated by semicolons (;).',
|
||||
'input_type': 'text'
|
||||
'description': 'The email address(es) to CC.',
|
||||
'input_type': 'select',
|
||||
'select_options': user_emails
|
||||
},
|
||||
{'label': 'BCC',
|
||||
'value': self.config['bcc'],
|
||||
'name': 'email_bcc',
|
||||
'description': 'The email address(es) to BCC, separated by semicolons (;).',
|
||||
'input_type': 'text'
|
||||
'description': 'The email address(es) to BCC.',
|
||||
'input_type': 'select',
|
||||
'select_options': user_emails
|
||||
},
|
||||
{'label': 'SMTP Server',
|
||||
'value': self.config['smtp_server'],
|
||||
|
|
|
@ -580,6 +580,27 @@ class Users(object):
|
|||
|
||||
return recently_watched
|
||||
|
||||
def get_users(self):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
||||
try:
|
||||
query = 'SELECT user_id, username, friendly_name, email FROM users WHERE deleted_user = 0'
|
||||
result = monitor_db.select(query=query)
|
||||
except Exception as e:
|
||||
logger.warn(u"Tautulli Users :: Unable to execute database query for get_users: %s." % e)
|
||||
return None
|
||||
|
||||
users = []
|
||||
for item in result:
|
||||
user = {'user_id': item['user_id'],
|
||||
'username': item['username'],
|
||||
'friendly_name': item['friendly_name'],
|
||||
'email': item['email']
|
||||
}
|
||||
users.append(user)
|
||||
|
||||
return users
|
||||
|
||||
def delete_all_history(self, user_id=None):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue