mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 15:56:07 -07:00
Add "delete mode" on history table allows individual rows to be deleted permanently.
Add user history purge option in edit user screen. Will remove all history for selected user.
This commit is contained in:
parent
8e57df53fd
commit
6b1a57e650
8 changed files with 165 additions and 21 deletions
|
@ -58,6 +58,12 @@ DOCUMENTATION :: END
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Uncheck this if you do not want this keep any history on this user's activity.</p>
|
<p class="help-block">Uncheck this if you do not want this keep any history on this user's activity.</p>
|
||||||
</div>
|
</div>
|
||||||
|
% if data['user_id']:
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-danger" id="delete-all-history">Purge</button>
|
||||||
|
<p class="help-block">DANGER ZONE! Click the purge button to remote all history logged for this user. This is permanent!</p>
|
||||||
|
</div>
|
||||||
|
% endif
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
@ -112,6 +118,21 @@ DOCUMENTATION :: END
|
||||||
});
|
});
|
||||||
% endif
|
% endif
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#delete-all-history").click(function() {
|
||||||
|
var r = confirm("Are you REALLY REALLY REALLY sure you want to delete all history for this user?");
|
||||||
|
if (r == true) {
|
||||||
|
$.ajax({
|
||||||
|
url: 'delete_all_user_history',
|
||||||
|
data: {user_id: '${data['user_id']}'},
|
||||||
|
cache: false,
|
||||||
|
async: true,
|
||||||
|
success: function(data) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
% endif
|
% endif
|
|
@ -13,13 +13,16 @@
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<span><i class="fa fa-history"></i> History</span>
|
<span><i class="fa fa-history"></i> History</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="colvis-button-bar hidden-xs">
|
<div class="button-bar">
|
||||||
|
<button class="btn btn-danger" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode"><i class="fa fa-trash-o"></i> Delete Mode</button> 
|
||||||
|
<div class="colvis-button-bar hidden-xs"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='table-card-back'>
|
<div class='table-card-back'>
|
||||||
<table class="display" id="history_table" width="100%">
|
<table class="display" id="history_table" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th align='left' id="delete_row">Delete</th>
|
||||||
<th align='left' id="time">Time</th>
|
<th align='left' id="time">Time</th>
|
||||||
<th align='left' id="friendly_name">User</th>
|
<th align='left' id="friendly_name">User</th>
|
||||||
<th align='left' id="platform">Platform</th>
|
<th align='left' id="platform">Platform</th>
|
||||||
|
@ -60,8 +63,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table').DataTable(history_table_options);
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: 'Select columns', buttonClass: 'btn btn-dark' });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"> Select columns</i>', buttonClass: 'btn btn-dark' });
|
||||||
$(colvis.button()).appendTo('div.colvis-button-bar');
|
$(colvis.button()).appendTo('div.colvis-button-bar');
|
||||||
|
|
||||||
|
$('#row-edit-mode').click(function() {
|
||||||
|
if ($(this).hasClass('active')) {
|
||||||
|
$('.delete-control').each(function() {
|
||||||
|
$(this).addClass('hidden');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('.delete-control').each(function() {
|
||||||
|
$(this).removeClass('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -256,7 +256,7 @@ DOCUMENTATION :: END
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table').DataTable(history_table_options);
|
||||||
history_table.column(4).visible(false);
|
history_table.column(4).visible(false);
|
||||||
|
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: 'Select columns', buttonClass: 'btn btn-dark' });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"> Select columns</i>', buttonClass: 'btn btn-dark' });
|
||||||
$(colvis.button()).appendTo('div.colvis-button-bar');
|
$(colvis.button()).appendTo('div.colvis-button-bar');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -274,7 +274,7 @@ DOCUMENTATION :: END
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table').DataTable(history_table_options);
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: 'Select columns', buttonClass: 'btn btn-dark' });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"> Select columns</i>', buttonClass: 'btn btn-dark' });
|
||||||
$(colvis.button()).appendTo('div.colvis-button-bar');
|
$(colvis.button()).appendTo('div.colvis-button-bar');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -25,10 +25,11 @@ history_table_options = {
|
||||||
"processing": false,
|
"processing": false,
|
||||||
"serverSide": true,
|
"serverSide": true,
|
||||||
"pageLength": 25,
|
"pageLength": 25,
|
||||||
"order": [ 0, 'desc'],
|
"order": [ 1, 'desc'],
|
||||||
|
"autoWidth": false,
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{
|
{
|
||||||
"targets": [0],
|
"targets": [1],
|
||||||
"data":"date",
|
"data":"date",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (rowData['stopped'] === null) {
|
if (rowData['stopped'] === null) {
|
||||||
|
@ -41,7 +42,7 @@ history_table_options = {
|
||||||
"className": "no-wrap"
|
"className": "no-wrap"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [1],
|
"targets": [2],
|
||||||
"data":"friendly_name",
|
"data":"friendly_name",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
|
@ -57,7 +58,7 @@ history_table_options = {
|
||||||
"className": "no-wrap hidden-xs"
|
"className": "no-wrap hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [2],
|
"targets": [3],
|
||||||
"data":"player",
|
"data":"player",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
|
@ -67,7 +68,7 @@ history_table_options = {
|
||||||
"className": "modal-control no-wrap hidden-sm hidden-xs"
|
"className": "modal-control no-wrap hidden-sm hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [3],
|
"targets": [4],
|
||||||
"data":"ip_address",
|
"data":"ip_address",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData) {
|
if (cellData) {
|
||||||
|
@ -87,7 +88,7 @@ history_table_options = {
|
||||||
"className": "no-wrap hidden-xs modal-control-ip"
|
"className": "no-wrap hidden-xs modal-control-ip"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [4],
|
"targets": [5],
|
||||||
"data":"full_title",
|
"data":"full_title",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
|
@ -106,7 +107,7 @@ history_table_options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [5],
|
"targets": [6],
|
||||||
"data":"started",
|
"data":"started",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData === null) {
|
if (cellData === null) {
|
||||||
|
@ -119,7 +120,7 @@ history_table_options = {
|
||||||
"className": "no-wrap hidden-sm hidden-xs"
|
"className": "no-wrap hidden-sm hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [6],
|
"targets": [7],
|
||||||
"data":"paused_counter",
|
"data":"paused_counter",
|
||||||
"render": function ( data, type, full ) {
|
"render": function ( data, type, full ) {
|
||||||
if (data !== null) {
|
if (data !== null) {
|
||||||
|
@ -132,7 +133,7 @@ history_table_options = {
|
||||||
"className": "no-wrap hidden-xs"
|
"className": "no-wrap hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [7],
|
"targets": [8],
|
||||||
"data":"stopped",
|
"data":"stopped",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData === null) {
|
if (cellData === null) {
|
||||||
|
@ -145,7 +146,7 @@ history_table_options = {
|
||||||
"className": "no-wrap hidden-md hidden-xs"
|
"className": "no-wrap hidden-md hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [8],
|
"targets": [9],
|
||||||
"data":"duration",
|
"data":"duration",
|
||||||
"render": function ( data, type, full ) {
|
"render": function ( data, type, full ) {
|
||||||
if (data !== null) {
|
if (data !== null) {
|
||||||
|
@ -158,7 +159,7 @@ history_table_options = {
|
||||||
"className": "no-wrap hidden-xs"
|
"className": "no-wrap hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [9],
|
"targets": [10],
|
||||||
"data":"percent_complete",
|
"data":"percent_complete",
|
||||||
"render": function ( data, type, full ) {
|
"render": function ( data, type, full ) {
|
||||||
if (data > 80) {
|
if (data > 80) {
|
||||||
|
@ -173,7 +174,17 @@ history_table_options = {
|
||||||
"orderable": false,
|
"orderable": false,
|
||||||
"className": "no-wrap hidden-md hidden-xs",
|
"className": "no-wrap hidden-md hidden-xs",
|
||||||
"width": "10px"
|
"width": "10px"
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"targets": [0],
|
||||||
|
"data": null,
|
||||||
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
|
$(td).html('<button class="btn btn-xs btn-danger" data-id="' + rowData['id'] + '"><i class="fa fa-trash-o"></i> Delete</button>');
|
||||||
|
},
|
||||||
|
"className": "delete-control no-wrap hidden",
|
||||||
|
"searchable": false,
|
||||||
|
"orderable": false
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"drawCallback": function (settings) {
|
"drawCallback": function (settings) {
|
||||||
// Jump to top of page
|
// Jump to top of page
|
||||||
|
@ -183,6 +194,11 @@ history_table_options = {
|
||||||
$('.info-modal').each(function() {
|
$('.info-modal').each(function() {
|
||||||
$(this).tooltip();
|
$(this).tooltip();
|
||||||
});
|
});
|
||||||
|
if ($('#row-edit-mode').hasClass('active')) {
|
||||||
|
$('.delete-control').each(function() {
|
||||||
|
$(this).removeClass('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"preDrawCallback": function(settings) {
|
"preDrawCallback": function(settings) {
|
||||||
var msg = "<div class='msg'><i class='fa fa-refresh fa-spin'></i> Fetching rows...</div>";
|
var msg = "<div class='msg'><i class='fa fa-refresh fa-spin'></i> Fetching rows...</div>";
|
||||||
|
@ -228,6 +244,24 @@ $('#history_table').on('click', 'td.modal-control-ip', function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserLocation(rowData['ip_address']);
|
getUserLocation(rowData['ip_address']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#history_table').on('click', 'td.delete-control', function () {
|
||||||
|
var tr = $(this).parents('tr');
|
||||||
|
var row = history_table.row( tr );
|
||||||
|
var rowData = row.data();
|
||||||
|
|
||||||
|
$(this).children("button").prop('disabled', true);
|
||||||
|
$(this).children("button").html('<i class="fa fa-spin fa-refresh"></i> Delete');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'delete_history_rows',
|
||||||
|
data: {row_id: rowData['id']},
|
||||||
|
async: true,
|
||||||
|
success: function(data) {
|
||||||
|
history_table.ajax.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -58,7 +58,7 @@
|
||||||
}
|
}
|
||||||
sync_table = $('#sync_table').DataTable(sync_table_options);
|
sync_table = $('#sync_table').DataTable(sync_table_options);
|
||||||
|
|
||||||
var colvis = new $.fn.dataTable.ColVis( sync_table, { buttonText: 'Select columns', buttonClass: 'btn btn-dark' } );
|
var colvis = new $.fn.dataTable.ColVis( sync_table, { buttonText: '<i class="fa fa-columns"> Select columns</i>', buttonClass: 'btn btn-dark' } );
|
||||||
$( colvis.button() ).appendTo('div.colvis-button-bar');
|
$( colvis.button() ).appendTo('div.colvis-button-bar');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -291,7 +291,7 @@ from plexpy import helpers
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table').DataTable(history_table_options);
|
||||||
history_table.column(1).visible(false);
|
history_table.column(1).visible(false);
|
||||||
|
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: 'Select columns', buttonClass: 'btn btn-dark' });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"> Select columns</i>', buttonClass: 'btn btn-dark' });
|
||||||
$(colvis.button()).appendTo('#button-bar-history');
|
$(colvis.button()).appendTo('#button-bar-history');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ from plexpy import helpers
|
||||||
sync_table = $('#sync_table').DataTable(sync_table_options);
|
sync_table = $('#sync_table').DataTable(sync_table_options);
|
||||||
history_table.column(1).visible(false);
|
history_table.column(1).visible(false);
|
||||||
|
|
||||||
var colvis_sync = new $.fn.dataTable.ColVis( sync_table, { buttonText: 'Select columns', buttonClass: 'btn btn-dark' } );
|
var colvis_sync = new $.fn.dataTable.ColVis( sync_table, { buttonText: '<i class="fa fa-columns"> Select columns</i>', buttonClass: 'btn btn-dark' } );
|
||||||
$( colvis_sync.button() ).appendTo('#button-bar-sync');
|
$( colvis_sync.button() ).appendTo('#button-bar-sync');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -475,3 +475,47 @@ class DataFactory(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
|
def delete_session_history_rows(self, row_id=None):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
if row_id.isdigit():
|
||||||
|
logger.info(u"PlexPy DataFactory :: Deleting row id %s from the session history database." % row_id)
|
||||||
|
session_history_del = \
|
||||||
|
monitor_db.action('DELETE FROM session_history WHERE id = ?', [row_id])
|
||||||
|
session_history_media_info_del = \
|
||||||
|
monitor_db.action('DELETE FROM session_history_media_info WHERE id = ?', [row_id])
|
||||||
|
session_history_metadata_del = \
|
||||||
|
monitor_db.action('DELETE FROM session_history_metadata WHERE id = ?', [row_id])
|
||||||
|
|
||||||
|
return 'Deleted rows %s.' % row_id
|
||||||
|
else:
|
||||||
|
return 'Unable to delete rows. Input row not valid.'
|
||||||
|
|
||||||
|
def delete_all_user_history(self, user_id=None):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
if user_id.isdigit():
|
||||||
|
logger.info(u"PlexPy DataFactory :: Deleting all history for user id %s from database." % user_id)
|
||||||
|
session_history_media_info_del = \
|
||||||
|
monitor_db.action('DELETE FROM '
|
||||||
|
'session_history_media_info '
|
||||||
|
'WHERE session_history_media_info.id IN (SELECT session_history_media_info.id '
|
||||||
|
'FROM session_history_media_info '
|
||||||
|
'JOIN session_history ON session_history_media_info.id = session_history.id '
|
||||||
|
'WHERE session_history.user_id = ?)', [user_id])
|
||||||
|
session_history_metadata_del = \
|
||||||
|
monitor_db.action('DELETE FROM '
|
||||||
|
'session_history_metadata '
|
||||||
|
'WHERE session_history_metadata.id IN (SELECT session_history_metadata.id '
|
||||||
|
'FROM session_history_metadata '
|
||||||
|
'JOIN session_history ON session_history_metadata.id = session_history.id '
|
||||||
|
'WHERE session_history.user_id = ?)', [user_id])
|
||||||
|
session_history_del = \
|
||||||
|
monitor_db.action('DELETE FROM '
|
||||||
|
'session_history '
|
||||||
|
'WHERE session_history.user_id = ?', [user_id])
|
||||||
|
|
||||||
|
return 'Deleted all items for user_id %s.' % user_id
|
||||||
|
else:
|
||||||
|
return 'Unable to delete items. Input user_id not valid.'
|
||||||
|
|
|
@ -1256,3 +1256,32 @@ class WebInterface(object):
|
||||||
|
|
||||||
return serve_template(templatename="notification_triggers_modal.html", title="Notification Triggers",
|
return serve_template(templatename="notification_triggers_modal.html", title="Notification Triggers",
|
||||||
data=this_agent)
|
data=this_agent)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def delete_history_rows(self, row_id, **kwargs):
|
||||||
|
data_factory = datafactory.DataFactory()
|
||||||
|
|
||||||
|
if row_id:
|
||||||
|
delete_row = data_factory.delete_session_history_rows(row_id=row_id)
|
||||||
|
|
||||||
|
if delete_row:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': delete_row})
|
||||||
|
else:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': 'no data received'})
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def delete_all_user_history(self, user_id, **kwargs):
|
||||||
|
data_factory = datafactory.DataFactory()
|
||||||
|
|
||||||
|
if user_id:
|
||||||
|
delete_row = data_factory.delete_all_user_history(user_id=user_id)
|
||||||
|
|
||||||
|
if delete_row:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': delete_row})
|
||||||
|
else:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': 'no data received'})
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue