mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-15 09:42:57 -07:00
Add users page
Set 10 results per page as default on Datatables Fix missing metadata bug
This commit is contained in:
parent
fa696adc79
commit
650e0963e2
5 changed files with 241 additions and 7 deletions
|
@ -56,6 +56,11 @@
|
||||||
% else:
|
% else:
|
||||||
<li><a href="history"><i class="fa fa-history fa-2x" data-toggle="tooltip" data-placement="bottom" title="History" id="history"></i></a></li>
|
<li><a href="history"><i class="fa fa-history fa-2x" data-toggle="tooltip" data-placement="bottom" title="History" id="history"></i></a></li>
|
||||||
% endif
|
% endif
|
||||||
|
% if title=="Users":
|
||||||
|
<li class="active"><a href="users"><i class="fa fa-users fa-2x" data-toggle="tooltip" data-placement="bottom" title="Users" id="users"></i></a></li>
|
||||||
|
% else:
|
||||||
|
<li><a href="users"><i class="fa fa-users fa-2x" data-toggle="tooltip" data-placement="bottom" title="Users" id="users"></i></a></li>
|
||||||
|
% endif
|
||||||
% if title=="Log":
|
% if title=="Log":
|
||||||
<li class="active"><a href="logs"><i class="fa fa-book fa-2x" data-toggle="tooltip" data-placement="bottom" title="Logs" id="logs"></i></a></li>
|
<li class="active"><a href="logs"><i class="fa fa-book fa-2x" data-toggle="tooltip" data-placement="bottom" title="Logs" id="logs"></i></a></li>
|
||||||
% else:
|
% else:
|
||||||
|
@ -83,6 +88,9 @@
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#history').tooltip();
|
$('#history').tooltip();
|
||||||
});
|
});
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#users').tooltip();
|
||||||
|
});
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#logs').tooltip();
|
$('#logs').tooltip();
|
||||||
});
|
});
|
||||||
|
|
|
@ -125,7 +125,7 @@
|
||||||
"sPaginationType": "bootstrap",
|
"sPaginationType": "bootstrap",
|
||||||
"processing": false,
|
"processing": false,
|
||||||
"serverSide": true,
|
"serverSide": true,
|
||||||
"pageLength": 25,
|
"pageLength": 10,
|
||||||
"order": [ 1, 'desc'],
|
"order": [ 1, 'desc'],
|
||||||
"ajax": {
|
"ajax": {
|
||||||
"url": "getHistory.json"
|
"url": "getHistory.json"
|
||||||
|
|
|
@ -152,6 +152,7 @@
|
||||||
|
|
||||||
<%def name="javascriptIncludes()">
|
<%def name="javascriptIncludes()">
|
||||||
<script src="interfaces/default/js/jquery.rateit.min.js"></script>
|
<script src="interfaces/default/js/jquery.rateit.min.js"></script>
|
||||||
|
% if metadata:
|
||||||
% if metadata['type'] == 'movie':
|
% if metadata['type'] == 'movie':
|
||||||
<script>
|
<script>
|
||||||
// Convert rating to 5 star rating type
|
// Convert rating to 5 star rating type
|
||||||
|
@ -159,4 +160,5 @@
|
||||||
$('#stars').attr('data-rateit-value', starRating)
|
$('#stars').attr('data-rateit-value', starRating)
|
||||||
</script>
|
</script>
|
||||||
% endif
|
% endif
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
125
data/interfaces/default/users.html
Normal file
125
data/interfaces/default/users.html
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<%inherit file="base.html"/>
|
||||||
|
<%!
|
||||||
|
from plexpy import helpers
|
||||||
|
%>
|
||||||
|
|
||||||
|
<%def name="headIncludes()">
|
||||||
|
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="body()">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
<div class="wellheader-bg">
|
||||||
|
<div class="dashboard-wellheader-no-chevron">
|
||||||
|
<h2><i class="fa fa-group"></i> Users</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='container-fluid'>
|
||||||
|
<div class='row-fluid'>
|
||||||
|
<div class='span12'>
|
||||||
|
<div class='wellbg'>
|
||||||
|
<table id="usersTable" class="display" width="100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th align="right" id="avatar"></th>
|
||||||
|
<th align="left" id="username"><i class='fa fa-sort'></i> User </th>
|
||||||
|
<th align="left" id="last_seen"><i class='fa fa-sort'></i> Last Seen </th>
|
||||||
|
<th align="left" id="last_known_ip"><i class='fa fa-sort'></i> Last Known IP </th>
|
||||||
|
<th align="left" id="total_plays"><i class='fa fa-sort'></i> Total Plays</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer></footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="javascriptIncludes()">
|
||||||
|
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
|
||||||
|
<script src="interfaces/default/js/moment-with-locale.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
var oTable = $('#usersTable').dataTable({
|
||||||
|
"language": {
|
||||||
|
"search": "Search: ",
|
||||||
|
"lengthMenu":"Show _MENU_ entries per page",
|
||||||
|
"info":"Showing _START_ to _END_ of _TOTAL_ entries",
|
||||||
|
"infoEmpty":"Showing 0 to 0 of 0 entries",
|
||||||
|
"infoFiltered":"(filtered from _MAX_ total entries)",
|
||||||
|
"emptyTable": "No data in table",
|
||||||
|
},
|
||||||
|
"destroy": true,
|
||||||
|
"processing": false,
|
||||||
|
"serverSide": true,
|
||||||
|
"pageLength": 10,
|
||||||
|
"order": [ 0, 'asc'],
|
||||||
|
"ajax": {
|
||||||
|
"url": "get_user_list"
|
||||||
|
},
|
||||||
|
"bLengthChange": true,
|
||||||
|
"bInfo": true,
|
||||||
|
"bAutoWidth": true,
|
||||||
|
"aaSorting": [[ 0, "asc" ]],
|
||||||
|
"bStateSave": true,
|
||||||
|
"bSortClasses": true,
|
||||||
|
"sPaginationType": "bootstrap",
|
||||||
|
"columnDefs": [
|
||||||
|
{
|
||||||
|
"targets": [0],
|
||||||
|
"data": null,
|
||||||
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
|
if (rowData['user_thumb'] === '') {
|
||||||
|
$(td).html('<img src="interfaces/default/images/gravatar-default-80x80.png" alt="User Logo"/>');
|
||||||
|
} else {
|
||||||
|
$(td).html('<img src="' + rowData['user_thumb'] + '" alt="User Logo"/>');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"orderable": false,
|
||||||
|
"className": "users-poster-face",
|
||||||
|
"width": "40px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"targets": [1],
|
||||||
|
"data": "user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"targets": [2],
|
||||||
|
"data": "time",
|
||||||
|
"render": function ( data, type, full ) {
|
||||||
|
return moment(data, "X").fromNow();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"targets": [3],
|
||||||
|
"data": "ip_address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"targets": [4],
|
||||||
|
"data": "plays"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"drawCallback": function (settings) {
|
||||||
|
// Jump to top of page
|
||||||
|
$('html,body').scrollTop(0);
|
||||||
|
$('#ajaxMsg').addClass('success').fadeOut();
|
||||||
|
},
|
||||||
|
"preDrawCallback": function(settings) {
|
||||||
|
$('#ajaxMsg').html("<div class='msg'><span class='ui-icon ui-icon-check'></span>Fetching rows...</div>");
|
||||||
|
$('#ajaxMsg').addClass('success').fadeIn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</%def>
|
|
@ -80,6 +80,105 @@ class WebInterface(object):
|
||||||
return serve_template(templatename="history.html", title="History", date_format=date_format,
|
return serve_template(templatename="history.html", title="History", date_format=date_format,
|
||||||
time_format=time_format)
|
time_format=time_format)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def users(self):
|
||||||
|
return serve_template(templatename="users.html", title="Users")
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def get_user_list(self, start=0, length=100, **kwargs):
|
||||||
|
start = int(start)
|
||||||
|
length = int(length)
|
||||||
|
filtered = []
|
||||||
|
totalcount = 0
|
||||||
|
search_value = ""
|
||||||
|
search_regex = ""
|
||||||
|
order_column = 1
|
||||||
|
order_dir = "desc"
|
||||||
|
|
||||||
|
if 'order[0][dir]' in kwargs:
|
||||||
|
order_dir = kwargs.get('order[0][dir]', "desc")
|
||||||
|
|
||||||
|
if 'order[0][column]' in kwargs:
|
||||||
|
order_column = kwargs.get('order[0][column]', "1")
|
||||||
|
|
||||||
|
if 'search[value]' in kwargs:
|
||||||
|
search_value = kwargs.get('search[value]', "")
|
||||||
|
|
||||||
|
if 'search[regex]' in kwargs:
|
||||||
|
search_regex = kwargs.get('search[regex]', "")
|
||||||
|
|
||||||
|
sortcolumn = 'user'
|
||||||
|
if order_column == '2':
|
||||||
|
sortcolumn = 'time'
|
||||||
|
elif order_column == '3':
|
||||||
|
sortcolumn = 'ip_address'
|
||||||
|
elif order_column == '4':
|
||||||
|
sortcolumn = 'plays'
|
||||||
|
|
||||||
|
myDB = db.DBConnection()
|
||||||
|
db_table = db.DBConnection().get_history_table_name()
|
||||||
|
|
||||||
|
if search_value == "":
|
||||||
|
query = 'SELECT COUNT(title) as plays, user, time, \
|
||||||
|
SUM(time) as timeTotal, SUM(stopped) as stoppedTotal, \
|
||||||
|
SUM(paused_counter) as paused_counterTotal, platform, \
|
||||||
|
ip_address, xml \
|
||||||
|
from %s GROUP by user ORDER by %s COLLATE NOCASE %s' % (db_table, sortcolumn, order_dir)
|
||||||
|
filtered = myDB.select(query)
|
||||||
|
totalcount = len(filtered)
|
||||||
|
else:
|
||||||
|
query = 'SELECT COUNT(title) as plays, user, time, \
|
||||||
|
SUM(time) as timeTotal, SUM(stopped) as stoppedTotal, \
|
||||||
|
SUM(paused_counter) as paused_counterTotal, platform, \
|
||||||
|
ip_address, xml \
|
||||||
|
from ' + db_table + ' WHERE user LIKE "%' + search_value + '%" \
|
||||||
|
GROUP by user' + ' ORDER by %s COLLATE NOCASE %s' % (sortcolumn, order_dir)
|
||||||
|
filtered = myDB.select(query)
|
||||||
|
totalcount = myDB.select('SELECT COUNT(*) from %s' % db_table)[0][0]
|
||||||
|
|
||||||
|
users = filtered[start:(start + length)]
|
||||||
|
rows = []
|
||||||
|
for item in users:
|
||||||
|
row = {"plays": item['plays'],
|
||||||
|
"time": item['time'],
|
||||||
|
"user": item["user"],
|
||||||
|
"timeTotal": item["timeTotal"],
|
||||||
|
"ip_address": item["ip_address"],
|
||||||
|
"stoppedTotal": item["stoppedTotal"],
|
||||||
|
"paused_counterTotal": item["paused_counterTotal"],
|
||||||
|
"platform": item["platform"]
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
xml_parse = minidom.parseString(helpers.latinToAscii(item['xml']))
|
||||||
|
except IOError, e:
|
||||||
|
logger.warn("Error parsing XML in PlexWatch db: %s" % e)
|
||||||
|
|
||||||
|
xml_head = xml_parse.getElementsByTagName('User')
|
||||||
|
if not xml_head:
|
||||||
|
logger.warn("Error parsing XML in PlexWatch db: %s" % e)
|
||||||
|
|
||||||
|
for s in xml_head:
|
||||||
|
if s.getAttribute('thumb'):
|
||||||
|
row['user_thumb'] = s.getAttribute('thumb')
|
||||||
|
else:
|
||||||
|
row['user_thumb'] = ""
|
||||||
|
if s.getAttribute('id'):
|
||||||
|
row['user_id'] = s.getAttribute('id')
|
||||||
|
else:
|
||||||
|
row['user_id'] = ""
|
||||||
|
|
||||||
|
rows.append(row)
|
||||||
|
|
||||||
|
dict = {'recordsFiltered': len(filtered),
|
||||||
|
'recordsTotal': totalcount,
|
||||||
|
'data': rows,
|
||||||
|
}
|
||||||
|
s = json.dumps(dict)
|
||||||
|
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return s
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def checkGithub(self):
|
def checkGithub(self):
|
||||||
from plexpy import versioncheck
|
from plexpy import versioncheck
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue