mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-13 18:16:57 -07:00
Filter History and Graphs in the WebUI
* Still need to prevent manually accessing endpoints with other user_ids
This commit is contained in:
parent
b45df26fdc
commit
4f8a5211f8
6 changed files with 53 additions and 46 deletions
|
@ -210,9 +210,10 @@ from plexpy.helpers import anon_url
|
|||
% else:
|
||||
<li class="dropdown">
|
||||
% endif
|
||||
<a href="#" class="dropdown-toggle" aria-haspopup="true" data-toggle="dropdown" data-hover="dropdown" data-href="settings"><i class="fa fa-lg fa-cogs"></i> <span class="caret"></span></a>
|
||||
<% href = 'settings' if _session['user_group'] == 'admin' else '#' %>
|
||||
<a href="#" class="dropdown-toggle" aria-haspopup="true" data-toggle="dropdown" data-hover="dropdown" data-href="${href}"><i class="fa fa-lg fa-cogs"></i> <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" id="settings-dropdown-menu">
|
||||
% if user_group == 'admin':
|
||||
% if _session['user_group'] == 'admin':
|
||||
<li><a href="settings"><i class="fa fa-fw fa-cogs"></i> Settings</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="logs"><i class="fa fa-fw fa-list-alt"></i> View Logs</a></li>
|
||||
|
@ -229,7 +230,7 @@ from plexpy.helpers import anon_url
|
|||
<li><a href="${http_root}auth/login"><i class="fa fa-fw fa-lock"></i> Admin Login</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
% endif
|
||||
% if expiry:
|
||||
% if _session['expiry']:
|
||||
<li><a href="${http_root}auth/logout"><i class="fa fa-fw fa-sign-out"></i> Logout</a></li>
|
||||
% endif
|
||||
</ul>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<span><i class="fa fa-bar-chart"></i> Graphs</span>
|
||||
</div>
|
||||
<div class="button-bar hidden-xs">
|
||||
% if _session['user_group'] == 'admin':
|
||||
<div class="btn-group" id="user-selection">
|
||||
<label>
|
||||
<select name="graph-user" id="graph-user" class="btn" style="color: inherit;">
|
||||
|
@ -20,6 +21,7 @@
|
|||
</select>
|
||||
</label>
|
||||
</div>
|
||||
% endif
|
||||
<div class="btn-group" data-toggle="buttons" id="yaxis-selection">
|
||||
% if config['graph_type'] == 'duration':
|
||||
<label class="btn btn-dark">
|
||||
|
@ -256,6 +258,8 @@
|
|||
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
||||
|
||||
<script>
|
||||
var selected_user_id = "${_session['user_id']}" == "None" ? null : "${_session['user_id']}"
|
||||
|
||||
// Modal popup dialog
|
||||
function selectHandler(selectedDate, selectedSeries) {
|
||||
|
||||
|
@ -282,6 +286,7 @@
|
|||
url: "history_table_modal",
|
||||
type: 'post',
|
||||
data: {
|
||||
user_id: selected_user_id,
|
||||
start_date: dateString,
|
||||
media_type: media_type,
|
||||
transcode_decision: transcode_decision
|
||||
|
@ -289,10 +294,6 @@
|
|||
complete: function(xhr, status) {
|
||||
$('#history-modal').modal('show');
|
||||
$("#history-modal").html(xhr.responseText);
|
||||
var opt = $('#graph-user :selected');
|
||||
if (opt.prev().length) {
|
||||
$('#history_table_modal_filter input[type=search]').val(opt.text()).trigger("input");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -320,7 +321,6 @@
|
|||
var yaxis = "${config['graph_type']}";
|
||||
var current_range = ${config['graph_days']};
|
||||
var current_tab = "${'#' + config['graph_tab']}";
|
||||
var selected_user_id = undefined;
|
||||
|
||||
$('.days').html(current_range);
|
||||
|
||||
|
@ -589,7 +589,7 @@
|
|||
|
||||
// User changed
|
||||
$('#graph-user').on('change', function() {
|
||||
selected_user_id = $(this).val() || undefined;
|
||||
selected_user_id = $(this).val() || null;
|
||||
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
|
||||
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
|
||||
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); }
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
</div>
|
||||
<div class="button-bar">
|
||||
<div class="colvis-button-bar hidden-xs"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-trash-o"></i> Delete mode
|
||||
</button>
|
||||
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select rows to delete. Data is deleted upon exiting delete mode.</div>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-card-back'>
|
||||
|
@ -84,7 +86,8 @@
|
|||
data: function (d) {
|
||||
return {
|
||||
json_data: JSON.stringify(d),
|
||||
media_type: media_type
|
||||
media_type: media_type,
|
||||
user_id: "${_session['user_id']}" == "None" ? null : "${_session['user_id']}"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
return {
|
||||
json_data: JSON.stringify(d),
|
||||
grouping: false,
|
||||
user_id: "${data['user_id']}",
|
||||
start_date: "${data['start_date']}",
|
||||
media_type: "${data.get('media_type')}",
|
||||
transcode_decision: "${data.get('transcode_decision')}"
|
||||
|
|
|
@ -25,7 +25,7 @@ from datetime import datetime, timedelta
|
|||
|
||||
import plexpy
|
||||
from plexpy import logger
|
||||
from plexpy.users import user_login
|
||||
from plexpy.users import Users, user_login
|
||||
|
||||
|
||||
SESSION_KEY = '_cp_username'
|
||||
|
@ -44,21 +44,14 @@ def check_credentials(username, password):
|
|||
else:
|
||||
return False, None
|
||||
|
||||
# An example implementation which uses an ORM could be:
|
||||
# u = User.get(username)
|
||||
# if u is None:
|
||||
# return u"Username %s is unknown to me." % username
|
||||
# if u.password != md5.new(password).hexdigest():
|
||||
# return u"Incorrect password"
|
||||
|
||||
def check_auth(*args, **kwargs):
|
||||
"""A tool that looks in config for 'auth.require'. If found and it
|
||||
is not None, a login is required and the entry is evaluated as a list of
|
||||
conditions that the user must fulfill"""
|
||||
conditions = cherrypy.request.config.get('auth.require', None)
|
||||
if conditions is not None:
|
||||
session = cherrypy.session.get(SESSION_KEY)
|
||||
username, user_group, expiry = session if session else (None, None, None)
|
||||
cp_sesssion = cherrypy.session.get(SESSION_KEY)
|
||||
username, user_id, user_group, expiry = cp_sesssion if cp_sesssion else (None, None, None, None)
|
||||
|
||||
if (username and expiry) and expiry > datetime.now():
|
||||
cherrypy.request.login = username
|
||||
|
@ -152,10 +145,17 @@ class AuthController(object):
|
|||
(vaild_login, user_group) = check_credentials(username, password)
|
||||
|
||||
if vaild_login:
|
||||
if user_group == 'guest':
|
||||
user_details = Users().get_details(user=username)
|
||||
user_id = user_details['user_id']
|
||||
else:
|
||||
user_id = None
|
||||
|
||||
expiry = datetime.now() + (timedelta(days=30) if remember_me == '1' else timedelta(minutes=60))
|
||||
|
||||
cherrypy.session.regenerate()
|
||||
cherrypy.request.login = username
|
||||
expiry = datetime.now() + (timedelta(days=30) if remember_me == '1' else timedelta(minutes=60))
|
||||
cherrypy.session[SESSION_KEY] = (username, user_group, expiry)
|
||||
cherrypy.session[SESSION_KEY] = (username, user_id, user_group, expiry)
|
||||
|
||||
self.on_login(username)
|
||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||
|
@ -169,10 +169,9 @@ class AuthController(object):
|
|||
if not plexpy.CONFIG.HTTP_PASSWORD:
|
||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||
|
||||
cp_sess = cherrypy.session
|
||||
session = cp_sess.get(SESSION_KEY)
|
||||
username, user_group, expiry = session if session else (None, None, None)
|
||||
cp_sess[SESSION_KEY] = None
|
||||
cp_sesssion = cherrypy.session.get(SESSION_KEY)
|
||||
username, user_id, user_group, expiry = cp_sesssion if cp_sesssion else (None, None, None, None)
|
||||
cherrypy.session[SESSION_KEY] = None
|
||||
|
||||
if username:
|
||||
cherrypy.request.login = None
|
||||
|
|
|
@ -49,13 +49,15 @@ def serve_template(templatename, **kwargs):
|
|||
|
||||
server_name = plexpy.CONFIG.PMS_NAME
|
||||
|
||||
session = cherrypy.session.get(SESSION_KEY)
|
||||
user, user_group, expiry = session if session else (None, None, None)
|
||||
_cp_session = cherrypy.session.get(SESSION_KEY)
|
||||
_session = {}
|
||||
_session['username'], _session['user_id'], _session['user_group'], _session['expiry'] = \
|
||||
_cp_session if _cp_session else (None, None, None, None)
|
||||
|
||||
try:
|
||||
template = _hplookup.get_template(templatename)
|
||||
return template.render(http_root=plexpy.HTTP_ROOT, server_name=server_name,
|
||||
user=user, user_group=user_group, expiry=expiry, **kwargs)
|
||||
_session=_session, **kwargs)
|
||||
except:
|
||||
return exceptions.html_error_template().render()
|
||||
|
||||
|
@ -797,12 +799,12 @@ class WebInterface(object):
|
|||
##### History #####
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
def history(self):
|
||||
return serve_template(templatename="history.html", title="History")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
def get_history(self, user=None, user_id=None, grouping=0, **kwargs):
|
||||
|
||||
if grouping == 'false':
|
||||
|
@ -851,7 +853,7 @@ class WebInterface(object):
|
|||
return json.dumps(history)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
def get_stream_data(self, row_id=None, user=None, **kwargs):
|
||||
|
||||
data_factory = datafactory.DataFactory()
|
||||
|
@ -860,7 +862,7 @@ class WebInterface(object):
|
|||
return serve_template(templatename="stream_data.html", title="Stream Data", data=stream_data, user=user)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
def get_ip_address_details(self, ip_address=None, **kwargs):
|
||||
import socket
|
||||
|
||||
|
@ -890,7 +892,7 @@ class WebInterface(object):
|
|||
##### Graphs #####
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
def graphs(self):
|
||||
|
||||
config = {
|
||||
|
@ -918,6 +920,7 @@ class WebInterface(object):
|
|||
return "Updated graphs config values."
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@addtoapi()
|
||||
def get_user_names(self, **kwargs):
|
||||
|
||||
|
@ -928,7 +931,7 @@ class WebInterface(object):
|
|||
return json.dumps(user_names)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_date(self, time_range='30', user_id=None, y_axis='plays', **kwargs):
|
||||
|
||||
|
@ -942,7 +945,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_date.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_dayofweek(self, time_range='30', user_id=None, y_axis='plays', **kwargs):
|
||||
|
||||
|
@ -956,7 +959,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_dayofweek.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_hourofday(self, time_range='30', user_id=None, y_axis='plays', **kwargs):
|
||||
|
||||
|
@ -970,7 +973,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_hourofday.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_per_month(self, y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -984,7 +987,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_per_month.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_top_10_platforms(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -998,7 +1001,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_top_10_platforms.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_top_10_users(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -1012,7 +1015,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_top_10_users.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_stream_type(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -1026,7 +1029,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_stream_type.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_source_resolution(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -1040,7 +1043,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_source_resolution.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_plays_by_stream_resolution(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -1054,7 +1057,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_plays_by_stream_resolution.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_stream_type_by_top_10_users(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -1068,7 +1071,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_stream_type_by_top_10_users.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_stream_type_by_top_10_platforms(self, time_range='30', y_axis='plays', user_id=None, **kwargs):
|
||||
|
||||
|
@ -1082,7 +1085,7 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_stream_type_by_top_10_platforms.")
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
def history_table_modal(self, **kwargs):
|
||||
|
||||
return serve_template(templatename="history_table_modal.html", title="History Data", data=kwargs)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue