mirror of https://github.com/dani/vroom.git
Basic audit viewer
This commit is contained in:
parent
90df86724f
commit
6662c0a9e8
|
@ -97,6 +97,7 @@ use constant MOH => {
|
|||
use constant API_ACTIONS => {
|
||||
admin => {
|
||||
get_room_list => 1,
|
||||
get_event_list => 1,
|
||||
set_persistent => 1
|
||||
},
|
||||
owner => {
|
||||
|
|
|
@ -720,6 +720,136 @@ function initAdminRooms(){
|
|||
});
|
||||
}
|
||||
|
||||
// Audit page
|
||||
function initAdminAudit(){
|
||||
var eventList = {};
|
||||
var matches = 0;
|
||||
|
||||
// Update display of event list
|
||||
function updateEventList(filter, min, max){
|
||||
$('#loading-icon').show();
|
||||
$('#eventList').html('');
|
||||
var filterRe = new RegExp(filter, "gi");
|
||||
var i = 0;
|
||||
matches = 0;
|
||||
$.each(eventList, function (index, obj){
|
||||
if (filter === '' ||
|
||||
( obj.event.match(filterRe) ||
|
||||
obj.from_ip.match(filterRe) ||
|
||||
obj.user.match(filterRe) ||
|
||||
obj.message.match(filterRe))
|
||||
){
|
||||
matches ++;
|
||||
if (i >= min && i < max){
|
||||
var t = obj.date.split(/[- :]/);
|
||||
var date = utc2Local(new Date(t[0], t[1]-1, t[2], t[3], t[4], t[5])).toLocaleString();
|
||||
$('#eventList').append($('<tr>')
|
||||
.append($('<td>').html(stringEscape(obj.id)).addClass('hidden-xs'))
|
||||
.append($('<td>').html(stringEscape(date)))
|
||||
.append($('<td>').html(stringEscape(obj.from_ip)))
|
||||
.append($('<td>').html(stringEscape(obj.event)))
|
||||
.append($('<td>').html(stringEscape(obj.user)).addClass('hidden-xs'))
|
||||
.append($('<td>').html(stringEscape(obj.message)))
|
||||
);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
});
|
||||
$('#loadingIcon').hide();
|
||||
$('.tablesorter').trigger('update');
|
||||
}
|
||||
|
||||
function updatePagination(){
|
||||
if (matches <= itemPerPage){
|
||||
$('#pagination').hide(200);
|
||||
return;
|
||||
}
|
||||
var total = Math.ceil(matches / itemPerPage);
|
||||
if (total === 0){
|
||||
total = 1;
|
||||
}
|
||||
$('#pagination').bootpag({
|
||||
total: total,
|
||||
maxVisible: 10,
|
||||
page: 1
|
||||
}).on('page', function(e, page){
|
||||
var min = itemPerPage * (page - 1);
|
||||
var max = min + itemPerPage;
|
||||
updateEventList($('#searchEvent').val(), min, max);
|
||||
});
|
||||
$('#pagination').show(200);
|
||||
}
|
||||
|
||||
function reloadEvents(start,end){
|
||||
$.ajax({
|
||||
data: {
|
||||
req: JSON.stringify({
|
||||
action: 'get_event_list',
|
||||
param: {
|
||||
start: start,
|
||||
end: end
|
||||
}
|
||||
})
|
||||
},
|
||||
error: function(data) {
|
||||
showApiError(data);
|
||||
},
|
||||
success: function(data){
|
||||
eventList = data.events;
|
||||
matches = Object.keys(eventList).length;
|
||||
updateEventList($('#eventSearch').val(), 0, itemPerPage);
|
||||
updatePagination();
|
||||
//$('.tablesorter').tablesorter({textSorter: $.tablesorter.sortText});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Intercept form submission
|
||||
$('#eventSearch').submit(function(e){
|
||||
e.preventDefault();
|
||||
var startObj = new Date($('#dateStart').val());
|
||||
var endObj = new Date($('#dateEnd').val());
|
||||
if (!$('#dateStart').val().match(dateRe)){
|
||||
$('#dateStart').notify(localize('ERROR_DATE_INVALID'), {
|
||||
class: 'error',
|
||||
position: 'bottom center'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
else if (!$('#dateEnd').val().match(dateRe)){
|
||||
$('#dateEnd').notify(localize('ERROR_DATE_INVALID'), {
|
||||
class: 'error',
|
||||
position: 'bottom center'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
else if (startObj > endObj){
|
||||
$('#dateEnd').notify(localize('ERROR_END_MUST_BE_AFTER_START'), {
|
||||
class: 'error',
|
||||
position: 'bottom center'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
reloadEvents($('#dateStart').val(),$('#dateEnd').val());
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
$('#searchEvent').on('input', function(){
|
||||
var lastInput = +new Date;
|
||||
setTimeout(function(){
|
||||
if (lastInput + 500 < +new Date){
|
||||
$('#loading-icon').show();
|
||||
$('#pagination').html('');
|
||||
updateEventList($('#searchEvent').val(), 0, itemPerPage);
|
||||
updatePagination();
|
||||
}
|
||||
}, 600);
|
||||
});
|
||||
|
||||
reloadEvents($('#dateStart').val(),$('#dateEnd').val());
|
||||
}
|
||||
// Started when entering a room
|
||||
function initJoin(room){
|
||||
// Auth input if access is protected
|
||||
|
|
77
vroom.pl
77
vroom.pl
|
@ -125,6 +125,18 @@ helper valid_email => sub {
|
|||
return Email::Valid->address($email);
|
||||
};
|
||||
|
||||
# Validate a date in YYYY-MM-DD format
|
||||
# Also accept YYYY-MM-DD hh:mm:ss
|
||||
helper valid_date => sub {
|
||||
my $self = shift;
|
||||
my ($date) = @_;
|
||||
if ($date =~ m/^\d{4}\-\d{1,2}\-\d{1,2}(\s+\d{1,2}:\d{1,2}:\d{1,2})?$/){
|
||||
return 1;
|
||||
}
|
||||
$self->app->log->debug("$date is not a valid date");
|
||||
return 0;
|
||||
};
|
||||
|
||||
##########################
|
||||
# Various helpers #
|
||||
##########################
|
||||
|
@ -167,6 +179,36 @@ helper log_event => sub {
|
|||
return 1;
|
||||
};
|
||||
|
||||
# Return a list of event between 2 dates
|
||||
helper get_event_list => sub {
|
||||
my $self = shift;
|
||||
my ($start,$end) = @_;
|
||||
# Check both start and end dates seems valid
|
||||
if (!$self->valid_date($start) || !$self->valid_date($end)){
|
||||
$self->app->log->debug("Invalid date submitted while looking for events");
|
||||
return 0;
|
||||
}
|
||||
my $sth;
|
||||
$sth = eval {
|
||||
$self->db->prepare('SELECT * FROM `audit`
|
||||
WHERE `date`>=?
|
||||
AND `date`<=?');
|
||||
};
|
||||
if ($@){
|
||||
$self->app->log->debug("DB error: $@");
|
||||
return 0;
|
||||
}
|
||||
# We want both dates to be inclusive, as the default time is 00:00:00
|
||||
# if not given, append 23:59:59 to the end date
|
||||
$sth->execute($start,$end . ' 23:59:59');
|
||||
if ($sth->err){
|
||||
$self->app->log->debug("DB error: " . $sth->errstr . " (code " . $sth->err . ")");
|
||||
return 0;
|
||||
}
|
||||
# Everything went fine, return the list of event as a hashref
|
||||
return $sth->fetchall_hashref('id');
|
||||
};
|
||||
|
||||
# Generate and manage rotation of session keys
|
||||
# used to sign cookies
|
||||
helper update_session_keys => sub {
|
||||
|
@ -1570,6 +1612,41 @@ any '/api' => sub {
|
|||
}
|
||||
);
|
||||
}
|
||||
elsif ($req->{action} eq 'get_event_list'){
|
||||
my $start = $req->{param}->{start};
|
||||
my $end = $req->{param}->{end};
|
||||
if ($start eq ''){
|
||||
$start = DateTime->now->ymd;
|
||||
}
|
||||
if ($end eq ''){
|
||||
$end = DateTime->now->ymd;
|
||||
}
|
||||
# Validate input
|
||||
if (!$self->valid_date($start) || !$self->valid_date($end)){
|
||||
return $self->render(
|
||||
json => {
|
||||
err => 'ERROR_INPUT_INVALID',
|
||||
msg => $self->l('ERROR_INPUT_INVALID'),
|
||||
status => 'error'
|
||||
},
|
||||
);
|
||||
}
|
||||
my $events = $self->get_event_list($start,$end);
|
||||
foreach my $event (keys %{$events}){
|
||||
# Init NULL values to empty strings
|
||||
foreach (qw(date from_ip event user message)){
|
||||
if (!$events->{$event}->{$_}){
|
||||
$events->{$event}->{$_} = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
# And send the list of event as a json object
|
||||
return $self->render(
|
||||
json => {
|
||||
events => $events
|
||||
}
|
||||
);
|
||||
}
|
||||
# And here anonymous method, which do not require an API Key
|
||||
elsif ($req->{action} eq 'create_room'){
|
||||
$req->{param}->{room} ||= $self->get_random_name();
|
||||
|
|
Loading…
Reference in New Issue