Merge branch 'master' of github.com:ZoneMinder/zoneminder

pull/3047/head
Isaac Connor 2020-09-14 14:05:02 -04:00
commit ab8e2d2e6c
18 changed files with 440 additions and 283 deletions

View File

@ -19,7 +19,7 @@ if ( canEdit('Events') ) {
$archiveVal = ($_REQUEST['action'] == 'archive') ? 1 : 0;
dbQuery(
'UPDATE Events SET Archived = ? WHERE Id = ?',
array($archiveVal, $_REQUEST['id'])
array($archiveVal, $eid)
);
break;
case 'delete' :

View File

@ -25,6 +25,16 @@ switch ( $modal ) {
if ( empty($_REQUEST['ohndx']) ) ajaxError('Option Help Index Not Provided');
$data['html'] = getOptionHelpHTML($_REQUEST['ohndx'], $OLANG);
break;
case 'enoperm' :
$data['html'] = getENoPermHTML();
break;
case 'delconfirm' :
$data['html'] = getDelConfirmHTML();
break;
case 'storage' :
if ( !isset($_REQUEST['id']) ) ajaxError('Storage Id Not Provided');
$data['html'] = getStorageModalHTML($_REQUEST['id']);
break;
default :
// Maybe don't need both
ZM\Warning('Unknown modal '.$modal);

24
web/ajax/stats.php Normal file
View File

@ -0,0 +1,24 @@
<?php
if ( empty($_REQUEST['eid']) ) ajaxError('Event Id Not Provided');
if ( empty($_REQUEST['fid']) ) ajaxError('Frame Id Not Provided');
$eid = $_REQUEST['eid'];
$fid = $_REQUEST['fid'];
$row = ( isset($_REQUEST['row']) ) ? $_REQUEST['row'] : '';
$data = array();
// Not sure if this is required
if ( ZM_OPT_USE_AUTH && (ZM_AUTH_RELAY == 'hashed') ) {
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) {
$data['auth'] = $auth_hash;
}
}
$data['html'] = getStatsTableHTML($eid, $fid, $row);
$data['id'] = '#contentStatsTable' .$row;
ajaxResponse($data);
return;
?>

View File

@ -24,7 +24,7 @@ if ( !canEdit('System') ) {
return;
}
if ( $action == 'Save' ) {
if ( $action == 'save' ) {
$storage = new ZM\Storage($_REQUEST['id']);
$changes = $storage->changes($_REQUEST['newStorage']);
@ -33,7 +33,7 @@ if ( $action == 'Save' ) {
$storage->save($changes);
$refreshParent = true;
}
$view = 'none';
$redirect = '?view=options&tab=storage';
} else {
ZM\Error("Unknown action $action in saving Storage");
}

View File

@ -790,6 +790,232 @@ function getOptionHelpHTML($optionHelpIndex, $OLANG) {
return $result;
}
// Return an Error No Permissions Modal
function getENoPermHTML() {
$result = '';
$result .= '<div id="ENoPerm" class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">'.PHP_EOL;
$result .= '<div class="modal-dialog">'.PHP_EOL;
$result .= '<div class="modal-content">'.PHP_EOL;
$result .= '<div class="modal-header">'.PHP_EOL;
$result .= '<h5 class="modal-title" id="staticBackdropLabel">ZoneMinder ' .translate('Error'). '</h5>'.PHP_EOL;
$result .= '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'.PHP_EOL;
$result .= '<span aria-hidden="true">&times;</span>'.PHP_EOL;
$result .= '</button>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '<div class="modal-body">'.PHP_EOL;
$result .= '<p>' .translate('YouNoPerms'). '</p>'.PHP_EOL;
$result .= '<p>' .translate('ContactAdmin'). '</p>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '<div class="modal-footer">'.PHP_EOL;
$result .= '<button type="button" id="enpCloseBtn" class="btn btn-secondary" data-dismiss="modal">Close</button>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
return $result;
}
function getStatsTableHTML($eid, $fid, $row='') {
if ( !canView('Events') ) return;
$result = '';
$sql = 'SELECT S.*,E.*,Z.Name AS ZoneName,Z.Units,Z.Area,M.Name AS MonitorName FROM Stats AS S LEFT JOIN Events AS E ON S.EventId = E.Id LEFT JOIN Zones AS Z ON S.ZoneId = Z.Id LEFT JOIN Monitors AS M ON E.MonitorId = M.Id WHERE S.EventId = ? AND S.FrameId = ? ORDER BY S.ZoneId';
$stats = dbFetchAll( $sql, NULL, array( $eid, $fid ) );
$result .= '<table id="contentStatsTable' .$row. '"'.PHP_EOL;
$result .= 'data-toggle="table"'.PHP_EOL;
$result .= 'data-toolbar="#toolbar"'.PHP_EOL;
$result .= 'class="table-sm table-borderless contentStatsTable"'.PHP_EOL;
$result .= 'cellspacing="0">'.PHP_EOL;
$result .= '<caption>' .translate('Stats'). ' - ' .$eid. ' - ' .$fid. '</caption>'.PHP_EOL;
$result .= '<thead>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="colZone font-weight-bold" data-align="center">' .translate('Zone'). '</th>'.PHP_EOL;
$result .= '<th class="colPixelDiff font-weight-bold" data-align="center">' .translate('PixelDiff'). '</th>'.PHP_EOL;
$result .= '<th class="colAlarmPx font-weight-bold" data-align="center">' .translate('AlarmPx'). '</th>'.PHP_EOL;
$result .= '<th class="colFilterPx font-weight-bold" data-align="center">' .translate('FilterPx'). '</th>'.PHP_EOL;
$result .= '<th class="colBlobPx font-weight-bold" data-align="center">' .translate('BlobPx'). '</th>'.PHP_EOL;
$result .= '<th class="colBlobs font-weight-bold" data-align="center">' .translate('Blobs'). '</th>'.PHP_EOL;
$result .= '<th class="colBlobSizes font-weight-bold" data-align="center">' .translate('BlobSizes'). '</th>'.PHP_EOL;
$result .= '<th class="colAlarmLimits font-weight-bold" data-align="center">' .translate('AlarmLimits'). '</th>'.PHP_EOL;
$result .= '<th class="colScore font-weight-bold" data-align="center">' .translate('Score'). '</th>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '</thead>'.PHP_EOL;
$result .= '<tbody>'.PHP_EOL;
if ( count($stats) ) {
foreach ( $stats as $stat ) {
$result .= '<tr>'.PHP_EOL;
$result .= '<td class="colZone">' .validHtmlStr($stat['ZoneName']). '</td>'.PHP_EOL;
$result .= '<td class="colPixelDiff">' .validHtmlStr($stat['PixelDiff']). '</td>'.PHP_EOL;
$result .= '<td class="colAlarmPx">' .sprintf( "%d (%d%%)", $stat['AlarmPixels'], (100*$stat['AlarmPixels']/$stat['Area']) ). '</td>'.PHP_EOL;
$result .= '<td class="colFilterPx">' .sprintf( "%d (%d%%)", $stat['FilterPixels'], (100*$stat['FilterPixels']/$stat['Area']) ).'</td>'.PHP_EOL;
$result .= '<td class="colBlobPx">' .sprintf( "%d (%d%%)", $stat['BlobPixels'], (100*$stat['BlobPixels']/$stat['Area']) ). '</td>'.PHP_EOL;
$result .= '<td class="colBlobs">' .validHtmlStr($stat['Blobs']). '</td>'.PHP_EOL;
if ( $stat['Blobs'] > 1 ) {
$result .= '<td class="colBlobSizes">' .sprintf( "%d-%d (%d%%-%d%%)", $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area']) ). '</td>'.PHP_EOL;
} else {
$result .= '<td class="colBlobSizes">' .sprintf( "%d (%d%%)", $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area'] ). '</td>'.PHP_EOL;
}
$result .= '<td class="colAlarmLimits">' .validHtmlStr($stat['MinX'].",".$stat['MinY']."-".$stat['MaxX'].",".$stat['MaxY']). '</td>'.PHP_EOL;
$result .= '<td class="colScore">' .$stat['Score']. '</td>'.PHP_EOL;
}
} else {
$result .= '<tr>'.PHP_EOL;
$result .= '<td class="rowNoStats" colspan="9">' .translate('NoStatisticsRecorded'). '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
}
$result .= '</tbody>'.PHP_EOL;
$result .= '</table>'.PHP_EOL;
return $result;
}
// This is the HTML representing the Delete confirmation modal on the Events page
function getDelConfirmHTML() {
$result = '';
$result .= '<div id="deleteConfirm" class="modal fade" class="modal" tabindex="-1">'.PHP_EOL;
$result .= '<div class="modal-dialog">'.PHP_EOL;
$result .= '<div class="modal-content">'.PHP_EOL;
$result .= '<div class="modal-header">'.PHP_EOL;
$result .= '<h5 class="modal-title">Delete Confirmation</h5>'.PHP_EOL;
$result .= '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'.PHP_EOL;
$result .= '<span aria-hidden="true">&times;</span>'.PHP_EOL;
$result .= '</button>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '<div class="modal-body">'.PHP_EOL;
$result .= '<p>' .translate('ConfirmDeleteEvents'). '</p>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '<div class="modal-footer">'.PHP_EOL;
$result .= '<button id="delCancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal">' .translate('Cancel'). '</button>'.PHP_EOL;
$result .= '<button id ="delConfirmBtn" type="button" class="btn btn-danger">' .translate('Delete'). '</button>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
return $result;
}
function getStorageModalHTML($sid) {
$result = '';
$null = '';
$checked = 'checked="checked"';
if ( !canEdit('System') ) return;
require_once('includes/Server.php');
require_once('includes/Storage.php');
if ( $_REQUEST['id'] ) {
if ( !($newStorage = ZM\Storage::find_one(array('Id'=>$sid)) ) ) {
// Perhaps do something different here, rather than return nothing
return;
}
} else {
$newStorage = new ZM\Storage();
$newStorage->Name(translate('NewStorage'));
}
$type_options = array( 'local' => translate('Local'), 's3fs' => translate('s3fs') );
$scheme_options = array(
'Deep' => translate('Deep'),
'Medium' => translate('Medium'),
'Shallow' => translate('Shallow'),
);
$servers = ZM\Server::find( null, array('order'=>'lower(Name)') );
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
if ( isset($GLOBALS['csrf']['key']) ) {
$csrf_input = '<input type="hidden" name="__csrf_magic" value="key:' .csrf_hash($GLOBALS['csrf']['key']). '" />'.PHP_EOL;
} else {
$csrf_input = '';
}
$result .= '<div class="modal fade" id="storageModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">'.PHP_EOL;
$result .= '<div class="modal-dialog">'.PHP_EOL;
$result .= '<div class="modal-content">'.PHP_EOL;
$result .= '<div class="modal-header">'.PHP_EOL;
$result .= '<h5 class="modal-title" id="staticBackdropLabel">' .translate('Storage').' - '.$newStorage->Name(). '</h5>'.PHP_EOL;
$result .= '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'.PHP_EOL;
$result .= '<span aria-hidden="true">&times;</span>'.PHP_EOL;
$result .= '</button>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '<div class="modal-body">'.PHP_EOL;
$result .= '<form id="storageModalForm" name="contentForm" method="post" action="?view=storage&action=save" class="validateFormOnSubmit">'.PHP_EOL;
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
$result .= $csrf_input;
$result .= '<input type="hidden" name="view" value="storage"/>'.PHP_EOL;
$result .= '<input type="hidden" name="object" value="storage"/>'.PHP_EOL;
$result .= '<input type="hidden" name="id" value="' .validHtmlStr($sid). '"/>'.PHP_EOL;
$result .= '<table id="contentTable" class="major">'.PHP_EOL;
$result .= '<tbody>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('Name'). '</th>'.PHP_EOL;
$result .= '<td><input type="text" name="newStorage[Name]" value="' .$newStorage->Name(). '"/></td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('Path'). '</th>'.PHP_EOL;
$result .= '<td><input type="text" name="newStorage[Path]" value="' .$newStorage->Path(). '"/></td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('Url'). '</th>'.PHP_EOL;
$result .= '<td><input type="text" name="newStorage[Url]" value="' .$newStorage->Url(). '"/></td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('Server'). '</th>'.PHP_EOL;
$result .= '<td>' .htmlSelect('newStorage[ServerId]', array(''=>'Remote / No Specific Server') + $ServersById, $newStorage->ServerId()). '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('Type'). '</th>'.PHP_EOL;
$result .= '<td>' .htmlSelect('newStorage[Type]', $type_options, $newStorage->Type()). '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('StorageScheme'). '</th>'.PHP_EOL;
$result .= '<td>' .htmlSelect('newStorage[Scheme]', $scheme_options, $newStorage->Scheme()). '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('StorageDoDelete'). '</th>'.PHP_EOL;
$result .= '<td>'.PHP_EOL;
$result .= '<input type="radio" name="newStorage[DoDelete]" value="1" ' .($newStorage->DoDelete() ? $checked : $null). '>Yes'.PHP_EOL;
$result .= '<input type="radio" name="newStorage[DoDelete]" value="0" ' .($newStorage->DoDelete() ? $null : $checked). '>No'.PHP_EOL;
$result .= '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="text-right pr-3" scope="row">' .translate('Enabled'). '</th>'.PHP_EOL;
$result .= '<td>'.PHP_EOL;
$result .= '<input type="radio" name="newStorage[Enabled]" value="1" ' .($newStorage->Enabled() ? $checked : $null). '>Yes'.PHP_EOL;
$result .= '<input type="radio" name="newStorage[Enabled]" value="0" ' .($newStorage->Enabled() ? $null : $checked). '>No'.PHP_EOL;
$result .= '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '</tbody>'.PHP_EOL;
$result .= '</table>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '<div class="modal-footer">'.PHP_EOL;
$result .= '<button name="action" id="storageSubmitBtn" type="submit" class="btn btn-primary" value="Save">' .translate('Save'). '</button>'.PHP_EOL;
$result .= '<button type="button" class="btn btn-secondary" data-dismiss="modal">' .translate('Cancel'). '</button>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</form>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
$result .= '</div>'.PHP_EOL;
return $result;
}
function xhtmlFooter() {
global $css;
global $cspNonce;

View File

@ -416,6 +416,7 @@ if ( currentView != 'none' && currentView != 'login' ) {
.done(setNavBar)
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
if ( textStatus != "timeout" ) {
// The idea is that this should only fail due to auth, so reload the page
// which should go to login if it can't stay logged in.
@ -711,7 +712,33 @@ function bwClickFunction() {
function reminderClickFunction() {
$j("#dropdown_reminder a").click(function() {
var option = $j(this).data('pdsa-dropdown-val');
$j.getJSON(thisUrl + '?view=version&action=version&option=' + option);
window.location.reload(true); //Do a full refresh to update ZM_DYN_LAST_VERSION
$j.getJSON(thisUrl + '?view=version&action=version&option=' + option)
.done(window.location.reload(true)) //Do a full refresh to update ZM_DYN_LAST_VERSION
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
});
}
// Load then show the "You No Permission" error modal
function enoperm() {
$j.getJSON(thisUrl + '?request=modal&modal=enoperm')
.done(function(data) {
if ( $j('#ENoPerm').length ) {
$j('#ENoPerm').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
$j('#ENoPerm').modal('show');
// Manage the CLOSE optionhelp modal button
document.getElementById("enpCloseBtn").addEventListener("click", function onENPCloseClick(evt) {
$j('#ENoPerm').modal('hide');
});
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
}

View File

@ -1,90 +0,0 @@
<?php
//
// ZoneMinder web stats view file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView('Events') ) {
$view = 'error';
return;
}
if ( !isset($row) ) $row = '';
$sql = 'SELECT S.*,E.*,Z.Name AS ZoneName,Z.Units,Z.Area,M.Name AS MonitorName FROM Stats AS S LEFT JOIN Events AS E ON S.EventId = E.Id LEFT JOIN Zones AS Z ON S.ZoneId = Z.Id LEFT JOIN Monitors AS M ON E.MonitorId = M.Id WHERE S.EventId = ? AND S.FrameId = ? ORDER BY S.ZoneId';
$stats = dbFetchAll($sql, NULL, array($eid, $fid));
?>
<table id="contentStatsTable<?php echo $row ?>"
data-toggle="table"
data-toolbar="#toolbar"
class="table-sm table-borderless contentStatsTable"
>
<caption><?php echo translate('Stats') ?> - <?php echo $eid ?> - <?php echo $fid ?></caption>
<thead>
<tr>
<th class="colZone font-weight-bold" data-align="center"><?php echo translate('Zone') ?></th>
<th class="colPixelDiff font-weight-bold" data-align="center"><?php echo translate('PixelDiff') ?></th>
<th class="colAlarmPx font-weight-bold" data-align="center"><?php echo translate('AlarmPx') ?></th>
<th class="colFilterPx font-weight-bold" data-align="center"><?php echo translate('FilterPx') ?></th>
<th class="colBlobPx font-weight-bold" data-align="center"><?php echo translate('BlobPx') ?></th>
<th class="colBlobs font-weight-bold" data-align="center"><?php echo translate('Blobs') ?></th>
<th class="colBlobSizes font-weight-bold" data-align="center"><?php echo translate('BlobSizes') ?></th>
<th class="colAlarmLimits font-weight-bold" data-align="center"><?php echo translate('AlarmLimits') ?></th>
<th class="colScore font-weight-bold" data-align="center"><?php echo translate('Score') ?></th>
</tr>
</thead>
<tbody>
<?php
if ( count($stats) ) {
foreach ( $stats as $stat ) {
?>
<tr>
<td class="colZone"><?php echo validHtmlStr($stat['ZoneName']) ?></td>
<td class="colPixelDiff"><?php echo validHtmlStr($stat['PixelDiff']) ?></td>
<td class="colAlarmPx"><?php echo sprintf( "%d (%d%%)", $stat['AlarmPixels'], (100*$stat['AlarmPixels']/$stat['Area']) ) ?></td>
<td class="colFilterPx"><?php echo sprintf( "%d (%d%%)", $stat['FilterPixels'], (100*$stat['FilterPixels']/$stat['Area']) ) ?></td>
<td class="colBlobPx"><?php echo sprintf( "%d (%d%%)", $stat['BlobPixels'], (100*$stat['BlobPixels']/$stat['Area']) ) ?></td>
<td class="colBlobs"><?php echo validHtmlStr($stat['Blobs']) ?></td>
<?php
if ( $stat['Blobs'] > 1 ) {
?>
<td class="colBlobSizes"><?php echo sprintf( "%d-%d (%d%%-%d%%)", $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area']) ) ?></td>
<?php
} else {
?>
<td class="colBlobSizes"><?php echo sprintf( "%d (%d%%)", $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area'] ) ?></td>
<?php
}
?>
<td class="colAlarmLimits"><?php echo validHtmlStr($stat['MinX'].",".$stat['MinY']."-".$stat['MaxX'].",".$stat['MaxY']) ?></td>
<td class="colScore"><?php echo $stat['Score'] ?></td>
</tr>
<?php
}
} else {
?>
<tr>
<td class="rowNoStats" colspan="9"><?php echo translate('NoStatisticsRecorded') ?></td>
</tr>
<?php
}
?>
</tbody>
</table>

View File

@ -322,25 +322,4 @@ if ( $results ) {
</table>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div id="deleteConfirm" class="modal fade" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p><?php echo translate('ConfirmDeleteEvents') ?></p>
</div>
<div class="modal-footer">
<button id="delCancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
<button id ="delConfirmBtn" type="button" class="btn btn-danger"><?php echo translate('Delete') ?></button>
</div>
</div>
</div>
</div>
<?php xhtmlFooter() ?>

View File

@ -206,15 +206,4 @@ if ( count($frames) ) {
</table>
</div>
</div>
<!-- Load the statistics for each frame -->
<!-- This content gets hidden on init and only revailed on detail view -->
<?php
$row = 0;
if ( count($frames) ) foreach ( $frames as $frame ) {
$eid = $frame['EventId'];
$fid = $frame['FrameId'];
include('_stats_table.php');
$row++;
}
?>
<?php xhtmlFooter() ?>

View File

@ -151,7 +151,7 @@ function initPage() {
$j('.functionLnk').click(function(evt) {
evt.preventDefault();
if ( !canEditEvents ) {
alert('You do not have permission to change monitor function.');
enoperm();
return;
}
var mid = evt.currentTarget.getAttribute('data-mid');
@ -186,8 +186,11 @@ function initPage() {
var mid = form.elements['mid'].value;
var newFunc = $j('#newFunction').val();
var newEnabled = $j('#newEnabled').is(':checked') ? 1 : 0;
$j.getJSON(thisUrl + '?view=function&action=function&mid='+mid+'&newFunction='+newFunc+'&newEnabled='+newEnabled, function() {
window.location.reload(true);
$j.getJSON(thisUrl + '?view=function&action=function&mid='+mid+'&newFunction='+newFunc+'&newEnabled='+newEnabled)
.done(window.location.reload(true))
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
});
}

View File

@ -49,7 +49,11 @@ $j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON.
var cueFrames = null; //make cueFrames available even if we don't send another ajax query
function initialAlarmCues(eventId) {
$j.getJSON(thisUrl + '?view=request&request=status&entity=frames&id=' + eventId, setAlarmCues); //get frames data for alarmCues and inserts into html
$j.getJSON(thisUrl + '?view=request&request=status&entity=frames&id=' + eventId, setAlarmCues) //get frames data for alarmCues and inserts into html
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
}
function setAlarmCues(data) {

View File

@ -35,6 +35,50 @@ function getArchivedSelections() {
return selection.includes("Yes");
}
// Load the Delete Confirmation Modal HTML via Ajax call
function getDelConfirmModal() {
$j.getJSON(thisUrl + '?request=modal&modal=delconfirm')
.done(function(data) {
if ( $j('#deleteConfirm').length ) {
$j('#deleteConfirm').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
manageDelConfirmModalBtns();
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
}
function manageDelConfirmModalBtns() {
// Manage the DELETE CONFIRMATION modal button
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEditEvents ) {
enoperm();
return;
}
var selections = getIdSelections();
evt.preventDefault();
$j.getJSON(thisUrl + '?request=events&action=delete&eids[]='+selections.join('&eids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
});
// Manage the CANCEL modal button
document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) {
$j('#deleteConfirm').modal('hide');
});
}
function initPage() {
var backBtn = $j('#backBtn');
var viewBtn = $j('#viewBtn');
@ -46,6 +90,9 @@ function initPage() {
var deleteBtn = $j('#deleteBtn');
var table = $j('#eventTable');
// Load the delete confirmation modal into the DOM
getDelConfirmModal();
// Define the icons used in the bootstrap-table top-right toolbar
var icons = {
paginationSwitchDown: 'fa-caret-square-o-down',
@ -125,14 +172,21 @@ function initPage() {
var selections = getIdSelections();
evt.preventDefault();
$j.getJSON(thisUrl + '?view=events&action=archive&eids[]='+selections.join('&eids[]='));
$j.getJSON(thisUrl + '?request=events&action=archive&eids[]='+selections.join('&eids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
window.location.reload(true);
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
});
// Manage the UNARCHIVE button
document.getElementById("unarchiveBtn").addEventListener("click", function onUnarchiveClick(evt) {
if ( ! canEditEvents ) {
alert("You do not have permission to Unarchive events.");
enoperm();
return;
}
@ -140,7 +194,15 @@ function initPage() {
console.log(selections);
evt.preventDefault();
$j.getJSON(thisUrl + '?view=events&action=unarchive&eids[]='+selections.join('&eids[]='));
$j.getJSON(thisUrl + '?request=events&action=unarchive&eids[]='+selections.join('&eids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
window.location.reload(true);
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
if ( openFilterWindow ) {
//opener.location.reload(true);
@ -154,7 +216,7 @@ function initPage() {
// Manage the EDIT button
document.getElementById("editBtn").addEventListener("click", function onEditClick(evt) {
if ( ! canEditEvents ) {
alert("You do not have permission to edit events.");
enoperm();
return;
}
@ -183,7 +245,7 @@ function initPage() {
// Manage the DELETE button
document.getElementById("deleteBtn").addEventListener("click", function onDeleteClick(evt) {
if ( ! canEditEvents ) {
alert("You do not have permission to delete events.");
enoperm();
return;
}
@ -191,25 +253,6 @@ function initPage() {
$j('#deleteConfirm').modal('show');
});
// Manage the DELETE CONFIRMATION modal button
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEditEvents ) {
alert("You do not have permission to delete events.");
return;
}
var selections = getIdSelections();
evt.preventDefault();
$j.getJSON(thisUrl + '?request=events&action=delete&eids[]='+selections.join('&eids[]='));
window.location.reload(true);
});
// Manage the CANCEL modal button
document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) {
$j('#deleteConfirm').modal('hide');
});
// The table is initially given a hidden style, so now that we are done rendering, show it
table.show();
}

View File

@ -25,10 +25,18 @@ function processClicks(event, field, value, row, $element) {
}
}
function detailFormatter(index, row, element) {
return $j(element).html($j('#contentStatsTable'+index).clone(true).show());
// This function handles when the user clicks a "+" link to retrieve stats for a frame
function detailFormatter(index, row, $detail) {
$detail.html('Please wait. Loading from ajax request...');
$j.get(thisUrl + '?request=stats&eid=' + row.EventId + '&fid=' + row.FrameId + '&row=' + index)
.done(function(data) {
$detail.html(data.html);
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
}
function initPage() {
var backBtn = $j('#backBtn');
var table = $j('#framesTable');

View File

@ -0,0 +1,45 @@
// Load the Storage Modal HTML via Ajax call
function getStorageModal(sid) {
$j.getJSON(thisUrl + '?request=modal&modal=storage&id=' + sid)
.done(function(data) {
if ( $j('#storageModal').length ) {
$j('#storageModal').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
$j('#storageModal').modal('show');
// Manage the Save button
$j('#storageSubmitBtn').click(function(evt) {
evt.preventDefault();
$j('#storageModalForm').submit();
});
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText);
});
}
function enableStorageModal() {
$j(".storageCol").click(function(evt) {
evt.preventDefault();
var sid = $j(this).data('sid');
getStorageModal(sid);
});
$j('#NewStorageBtn').click(function(evt) {
evt.preventDefault();
getStorageModal(0);
});
}
function initPage() {
var NewStorageBtn = $j('#NewStorageBtn');
if ( canEditSystem ) enableStorageModal();
NewStorageBtn.prop('disabled', !canEditSystem);
}
$j(document).ready(function() {
initPage();
});

View File

@ -3,3 +3,5 @@ var restartWarning = <?php echo empty($restartWarning)?'false':'true' ?>;
if ( restartWarning ) {
alert( "<?php echo translate('OptionRestartWarning') ?>" );
}
var canEditSystem = <?php echo canEdit('System') ? 'true' : 'false' ?>;

View File

@ -272,12 +272,12 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as
<tbody>
<?php foreach( ZM\Storage::find( null, array('order'=>'lower(Name)') ) as $Storage ) { ?>
<tr>
<td class="colId"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Id()), $canEdit ) ?></td>
<td class="colName"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?></td>
<td class="colPath"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Path()), $canEdit ) ?></td>
<td class="colType"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Type()), $canEdit ) ?></td>
<td class="colScheme"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Scheme()), $canEdit ) ?></td>
<td class="colServer"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Server()->Name()), $canEdit ) ?></td>
<td class="colId"><?php echo makeLink('#', validHtmlStr($Storage->Id()), $canEdit, 'class="storageCol" data-sid="'.$Storage->Id().'"' ) ?></td>
<td class="colName"><?php echo makeLink('#', validHtmlStr($Storage->Name()), $canEdit, 'class="storageCol" data-sid="'.$Storage->Id().'"' ) ?></td>
<td class="colPath"><?php echo makeLink('#', validHtmlStr($Storage->Path()), $canEdit, 'class="storageCol" data-sid="'.$Storage->Id().'"' ) ?></td>
<td class="colType"><?php echo makeLink('#', validHtmlStr($Storage->Type()), $canEdit, 'class="storageCol" data-sid="'.$Storage->Id().'"' ) ?></td>
<td class="colScheme"><?php echo makeLink('#', validHtmlStr($Storage->Scheme()), $canEdit, 'class="storageCol" data-sid="'.$Storage->Id().'"' ) ?></td>
<td class="colServer"><?php echo makeLink('#', validHtmlStr($Storage->Server()->Name()), $canEdit, 'class="storageCol" data-sid="'.$Storage->Id().'"' ) ?></td>
<td class="colDiskSpace"><?php echo human_filesize($Storage->disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?></td>
<td class="ColEvents"><?php echo $Storage->EventCount().' using '.human_filesize($Storage->event_disk_space()) ?></td>
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $Storage->Id() ?>" data-on-click-this="configureDeleteButton"<?php if ( $Storage->EventCount() or !$canEdit ) { ?> disabled="disabled"<?php } ?><?php echo $Storage->EventCount() ? ' title="Can\'t delete as long as there are events stored here."' : ''?>/></td>
@ -286,7 +286,7 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as
</tbody>
</table>
<div id="contentButtons">
<?php echo makePopupButton('?view=storage&id=0', 'zmStorage', 'storage', translate('AddNewStorage'), canEdit('System')); ?>
<button type="button" id="NewStorageBtn" value="<?php echo translate('AddNewStorage') ?>" disabled="disabled"><?php echo translate('AddNewStorage') ?></button>
<button type="submit" class="btn-danger" name="deleteBtn" value="Delete" disabled="disabled"><?php echo translate('Delete') ?></button>
</div>
</form>

View File

@ -44,9 +44,10 @@ xhtmlHeaders(__FILE__, translate('Stats')." - ".$eid." - ".$fid );
<div id="content" class="row justify-content-center">
<form name="contentForm" id="contentForm" method="get" action="?">
<input type="hidden" name="view" value="none"/>
<?php include('_stats_table.php'); ?>
<?php echo getStatsTableHTML($eid, $fid) ?>
</form>
</div>
</div>
</body>
</html>
<?php xhtmlFooter() ?>

View File

@ -1,114 +0,0 @@
<?php
//
// ZoneMinder web user view file
// Copyright (C) 2020 ZoneMinder LLC
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit('System') ) {
$view = 'error';
return;
}
require_once('includes/Server.php');
require_once('includes/Storage.php');
if ( $_REQUEST['id'] ) {
if ( !($newStorage = ZM\Storage::find_one(array('Id'=>$_REQUEST['id'])) ) ) {
$view = 'error';
return;
}
} else {
$newStorage = new ZM\Storage();
$newStorage->Name(translate('NewStorage'));
}
$type_options = array( 'local' => translate('Local'), 's3fs' => translate('s3fs') );
$scheme_options = array(
'Deep' => translate('Deep'),
'Medium' => translate('Medium'),
'Shallow' => translate('Shallow'),
);
$servers = ZM\Server::find( null, array('order'=>'lower(Name)') );
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Storage').' - '.$newStorage->Name());
?>
<body>
<div id="page">
<div id="header">
<h2><?php echo translate('Storage').' - '.$newStorage->Name() ?></h2>
</div>
<div id="content">
<form name="contentForm" method="post" action="?" class="validateFormOnSubmit">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="object" value="storage"/>
<input type="hidden" name="id" value="<?php echo validHtmlStr($_REQUEST['id']) ?>"/>
<table id="contentTable" class="major">
<tbody>
<tr>
<th scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newStorage[Name]" value="<?php echo $newStorage->Name() ?>"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Path') ?></th>
<td><input type="text" name="newStorage[Path]" value="<?php echo $newStorage->Path() ?>"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Url') ?></th>
<td><input type="text" name="newStorage[Url]" value="<?php echo $newStorage->Url() ?>"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Server') ?></th>
<td><?php echo htmlSelect('newStorage[ServerId]', array(''=>'Remote / No Specific Server') + $ServersById, $newStorage->ServerId()); ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Type') ?></th>
<td><?php echo htmlSelect('newStorage[Type]', $type_options, $newStorage->Type()); ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('StorageScheme') ?></th>
<td><?php echo htmlSelect('newStorage[Scheme]', $scheme_options, $newStorage->Scheme()); ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('StorageDoDelete') ?></th>
<td>
<input type="radio" name="newStorage[DoDelete]" value="1"<?php echo $newStorage->DoDelete() ? 'checked="checked"' : '' ?>/>Yes
<input type="radio" name="newStorage[DoDelete]" value="0"<?php echo $newStorage->DoDelete() ? '' : 'checked="checked"' ?>/>No
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('Enabled') ?></th>
<td>
<input type="radio" name="newStorage[Enabled]" value="1"<?php echo $newStorage->Enabled() ? 'checked="checked"' : '' ?>/>Yes
<input type="radio" name="newStorage[Enabled]" value="0"<?php echo $newStorage->Enabled() ? '' : 'checked="checked"' ?>/>No
</td>
</tr>
</tbody>
</table>
<div id="contentButtons">
<button name="action" type="submit" value="Save"><?php echo translate('Save') ?></button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
<?php xhtmlFooter() ?>