Merge branch 'release-1.36' of github.com:ZoneMinder/zoneminder into release-1.36

This commit is contained in:
Isaac Connor 2021-11-16 15:00:34 -05:00
commit b7d8add5ad
12 changed files with 159 additions and 126 deletions

View File

@ -93,7 +93,7 @@ if ( canView('Events') or canView('Snapshots') ) {
$exportFormat, $exportFormat,
$exportCompress, $exportCompress,
$exportStructure, $exportStructure,
(!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport'), (!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport')
)) { )) {
ajaxResponse(array('exportFile'=>$exportFile)); ajaxResponse(array('exportFile'=>$exportFile));
} else { } else {

View File

@ -1,5 +1,4 @@
<?php <?php
if (empty($_REQUEST['eid'])) ajaxError('Event Id Not Provided'); if (empty($_REQUEST['eid'])) ajaxError('Event Id Not Provided');
if (empty($_REQUEST['fid'])) ajaxError('Frame Id Not Provided'); if (empty($_REQUEST['fid'])) ajaxError('Frame Id Not Provided');
@ -9,32 +8,26 @@ $row = ( isset($_REQUEST['row']) ) ? $_REQUEST['row'] : '';
$raw = isset($_REQUEST['raw']); $raw = isset($_REQUEST['raw']);
$data = array(); $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;
}
}
if ($raw) { if ($raw) {
$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'; $sql = 'SELECT S.*,E.*,Z.Name AS ZoneName,Z.Units,Z.Area,M.Name AS MonitorName
$stat = dbFetchOne( $sql, NULL, array( $eid, $fid ) ); 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
if ( $stat ) { WHERE S.EventId = ? AND S.FrameId = ? ORDER BY S.ZoneId';
$stats = dbFetchAll($sql, NULL, array($eid, $fid));
foreach ($stats as $stat) {
$stat['ZoneName'] = validHtmlStr($stat['ZoneName']); $stat['ZoneName'] = validHtmlStr($stat['ZoneName']);
$stat['PixelDiff'] = validHtmlStr($stat['PixelDiff']); $stat['PixelDiff'] = validHtmlStr($stat['PixelDiff']);
$stat['AlarmPixels'] = sprintf( "%d (%d%%)", $stat['AlarmPixels'], (100*$stat['AlarmPixels']/$stat['Area']) ); $stat['AlarmPixels'] = sprintf('%d (%d%%)', $stat['AlarmPixels'], (100*$stat['AlarmPixels']/$stat['Area']));
$stat['FilterPixels'] = sprintf( "%d (%d%%)", $stat['FilterPixels'], (100*$stat['FilterPixels']/$stat['Area']) ); $stat['FilterPixels'] = sprintf('%d (%d%%)', $stat['FilterPixels'], (100*$stat['FilterPixels']/$stat['Area']));
$stat['BlobPixels'] = sprintf( "%d (%d%%)", $stat['BlobPixels'], (100*$stat['BlobPixels']/$stat['Area']) ); $stat['BlobPixels'] = sprintf('%d (%d%%)', $stat['BlobPixels'], (100*$stat['BlobPixels']/$stat['Area']));
$stat['Blobs'] = validHtmlStr($stat['Blobs']); $stat['Blobs'] = validHtmlStr($stat['Blobs']);
if ($stat['Blobs'] > 1) { if ($stat['Blobs'] > 1) {
$stat['BlobSizes'] = sprintf( "%d-%d (%d%%-%d%%)", $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area']) ); $stat['BlobSizes'] = sprintf('%d-%d (%d%%-%d%%)', $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area']));
} else { } else {
$stat['BlobSizes'] = sprintf( "%d (%d%%)", $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area'] ); $stat['BlobSizes'] = sprintf('%d (%d%%)', $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area']);
} }
$stat['AlarmLimits'] = validHtmlStr($stat['MinX'].",".$stat['MinY']."-".$stat['MaxX'].",".$stat['MaxY']); $stat['AlarmLimits'] = validHtmlStr($stat['MinX'].','.$stat['MinY'].'-'.$stat['MaxX'].','.$stat['MaxY']);
} $data['raw'][] = $stat;
$data['raw'] = $stat; } # end foreach stat/zone
} else { } else {
$data['html'] = getStatsTableHTML($eid, $fid, $row); $data['html'] = getStatsTableHTML($eid, $fid, $row);
$data['id'] = '#contentStatsTable' .$row; $data['id'] = '#contentStatsTable' .$row;

View File

@ -650,6 +650,23 @@ class Event extends ZM_Object {
} }
return false; return false;
} }
function canEdit($u=null) {
global $user;
if (!$u) $u=$user;
if (!$u) {
# auth turned on and not logged in
return false;
}
if (!empty($u['MonitorIds']) ) {
if (!in_array($this->{'MonitorId'}, explode(',', $u['MonitorIds']))) {
return false;
}
}
if ($u['Events'] != 'Edit') {
return false;
}
return true;
}
} # end class } # end class
?> ?>

View File

@ -495,6 +495,10 @@ class Monitor extends ZM_Object {
return $this->Server()->UrlToIndex($port); return $this->Server()->UrlToIndex($port);
} }
public function UrlToZMS($port=null) {
return $this->Server()->UrlToZMS($port).'?mid='.$this->Id();
}
public function sendControlCommand($command) { public function sendControlCommand($command) {
// command is generally a command option list like --command=blah but might be just the word quit // command is generally a command option list like --command=blah but might be just the word quit

View File

@ -205,7 +205,7 @@ if ( $action == 'save' ) {
} // end if changes in width or height } // end if changes in width or height
} else { } else {
global $error_message; global $error_message;
$error_message = dbError(); $error_message = dbError('unknown');
} // end if successful save } // end if successful save
$restart = true; $restart = true;
} else { // new monitor } else { // new monitor

View File

@ -45,5 +45,7 @@ if ( $action == 'settings' ) {
dbQuery( dbQuery(
'UPDATE Monitors SET Brightness = ?, Contrast = ?, Hue = ?, Colour = ? WHERE Id = ?', 'UPDATE Monitors SET Brightness = ?, Contrast = ?, Hue = ?, Colour = ? WHERE Id = ?',
array($brightness, $contrast, $hue, $colour, $mid)); array($brightness, $contrast, $hue, $colour, $mid));
global $redirect;
$redirect = '?view=watch&mid='.$mid;
} }
?> ?>

View File

@ -150,6 +150,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
<button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Edit') ?>" disabled><i class="fa fa-pencil"></i></button> <button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Edit') ?>" disabled><i class="fa fa-pencil"></i></button>
<button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>"><i class="fa fa-external-link"></i></button> <button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>"><i class="fa fa-external-link"></i></button>
<a id="downloadBtn" class="btn btn-normal" href="<?php echo $Event->getStreamSrc(array('mode'=>'mp4'),'&amp;')?>" <a id="downloadBtn" class="btn btn-normal" href="<?php echo $Event->getStreamSrc(array('mode'=>'mp4'),'&amp;')?>"
title="<?php echo translate('Download'). ' ' . $Event->DefaultVideo() ?>"
download download
<?php echo $Event->DefaultVideo() ? '' : 'style="display:none;"' ?> <?php echo $Event->DefaultVideo() ? '' : 'style="display:none;"' ?>
><i class="fa fa-download"></i></a> ><i class="fa fa-download"></i></a>

View File

@ -18,17 +18,16 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
if ( !canView('Events') ) {
$view = 'error';
return;
}
require_once('includes/Frame.php'); require_once('includes/Frame.php');
$eid = validInt($_REQUEST['eid']); $eid = validInt($_REQUEST['eid']);
$fid = empty($_REQUEST['fid']) ? 0 : validInt($_REQUEST['fid']); $fid = empty($_REQUEST['fid']) ? 0 : validInt($_REQUEST['fid']);
$Event = new ZM\Event($eid); $Event = new ZM\Event($eid);
if (!$Event->canView()) {
$view = 'error';
return;
}
$Monitor = $Event->Monitor(); $Monitor = $Event->Monitor();
# This is kinda weird.. so if we pass fid=0 or some other non-integer, then it loads max score # This is kinda weird.. so if we pass fid=0 or some other non-integer, then it loads max score
@ -41,7 +40,6 @@ if ( !empty($fid) ) {
$frame = dbFetchOne('SELECT * FROM Frames WHERE EventId=? AND Score=?', NULL, array($eid, $Event->MaxScore())); $frame = dbFetchOne('SELECT * FROM Frames WHERE EventId=? AND Score=?', NULL, array($eid, $Event->MaxScore()));
} }
$Frame = new ZM\Frame($frame); $Frame = new ZM\Frame($frame);
$maxFid = $Event->Frames(); $maxFid = $Event->Frames();
$firstFid = 1; $firstFid = 1;
@ -92,33 +90,35 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id().' - '.$Frame->Frame
<div id="page p-0"> <div id="page p-0">
<div class="d-flex flex-row justify-content-between px-3 pt-1"> <div class="d-flex flex-row justify-content-between px-3 pt-1">
<div id="toolbar" > <div id="toolbar" >
<button id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button> <button type="button" id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
<button id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button> <button type="button" id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
<button id="statsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats') ?>" ><i class="fa fa-info"></i></button> <button type="button" id="statsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats') ?>" ><i class="fa fa-info"></i></button>
<button id="statsViewBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats').' '.translate('View') ?>" ><i class="fa fa-table"></i></button> <button type="button" id="statsViewBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats').' '.translate('View') ?>" ><i class="fa fa-table"></i></button>
</div> </div>
<h2><?php echo translate('Frame') ?> <?php echo $Event->Id().'-'.$Frame->FrameId().' ('.$Frame->Score().')' ?></h2> <h2><?php echo translate('Frame') ?> <?php echo $Event->Id().'-'.$Frame->FrameId().' ('.$Frame->Score().')' ?></h2>
<form> <form>
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo htmlSelect('scale', $scales, $scale, array('data-on-change'=>'changeScale','id'=>'scale')); ?></div> <div id="scaleControl">
<label for="scale"><?php echo translate('Scale') ?></label>
<?php echo htmlSelect('scale', $scales, $scale, array('data-on-change'=>'changeScale','id'=>'scale')); ?>
</div>
<input type="hidden" name="base_width" id="base_width" value="<?php echo $Event->Width(); ?>"/> <input type="hidden" name="base_width" id="base_width" value="<?php echo $Event->Width(); ?>"/>
<input type="hidden" name="base_height" id="base_height" value="<?php echo $Event->Height(); ?>"/> <input type="hidden" name="base_height" id="base_height" value="<?php echo $Event->Height(); ?>"/>
</form> </form>
</div> </div>
<div id="content" class="d-flex flex-row justify-content-center"> <div id="content" class="d-flex flex-row justify-content-center">
<table id="frameStatsTable" class="table-sm table-borderless pr-3"> <table id="frameStatsTable" class="table-sm table-borderless pr-3">
<!-- FRAME STATISTICS POPULATED BY AJAX --> <!-- FRAME STATISTICS POPULATED BY AJAX -->
</table> </table>
<div> <div>
<p id="image"> <p id="image">
<?php if ( $imageData['hasAnalImage'] ) { <?php
if ( $imageData['hasAnalImage'] ) {
echo sprintf('<a href="?view=frame&amp;eid=%d&amp;fid=%d&scale=%d&amp;show=%s">', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) ); echo sprintf('<a href="?view=frame&amp;eid=%d&amp;fid=%d&scale=%d&amp;show=%s">', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) );
} ?> }
?>
<img id="frameImg" <img id="frameImg"
src="<?php echo validHtmlStr($Frame->getImageSrc($show=='anal'?'analyse':'capture')) ?>" src="<?php echo validHtmlStr($Frame->getImageSrc($show=='anal'?'analyse':'capture')) ?>"
width="<?php echo reScale($Event->Width(), $Monitor->DefaultScale(), $scale) ?>" width="<?php echo reScale($Event->Width(), $Monitor->DefaultScale(), $scale) ?>"
@ -126,8 +126,8 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id().' - '.$Frame->Frame
alt="<?php echo $Frame->EventId().'-'.$Frame->FrameId() ?>" alt="<?php echo $Frame->EventId().'-'.$Frame->FrameId() ?>"
class="<?php echo $imageData['imageClass'] ?>" class="<?php echo $imageData['imageClass'] ?>"
/> />
<?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?> <?php
if ($imageData['hasAnalImage']) { ?></a><?php } ?>
</p> </p>
<?php <?php
$frame_url_base = '?view=frame&amp;eid='.$Event->Id().'&amp;scale='.$scale.'&amp;show='.$show.'&amp;fid='; $frame_url_base = '?view=frame&amp;eid='.$Event->Id().'&amp;scale='.$scale.'&amp;show='.$show.'&amp;fid=';

View File

@ -34,7 +34,7 @@ function streamReq(data) {
data.view = 'request'; data.view = 'request';
data.request = 'stream'; data.request = 'stream';
$j.getJSON(thisUrl, data) $j.getJSON(monitorUrl, data)
.done(getCmdResponse) .done(getCmdResponse)
.fail(logAjaxFail); .fail(logAjaxFail);
} }
@ -300,7 +300,7 @@ function getCmdResponse(respObj, respText) {
if (streamStatus.auth) { if (streamStatus.auth) {
// Try to reload the image stream. // Try to reload the image stream.
var streamImg = $j('#evtStream'); var streamImg = document.getElementById('evtStream');
if (streamImg) { if (streamImg) {
streamImg.src = streamImg.src.replace(/auth=\w+/i, 'auth='+streamStatus.auth); streamImg.src = streamImg.src.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
} }
@ -657,6 +657,7 @@ function getFrameResponse(respObj, respText) {
function frameQuery(eventId, frameId, loadImage) { function frameQuery(eventId, frameId, loadImage) {
var data = {}; var data = {};
if (auth_hash) data.auth = auth_hash;
data.loopback = loadImage; data.loopback = loadImage;
data.id = {eventId, frameId}; data.id = {eventId, frameId};

View File

@ -39,7 +39,7 @@ function changeScale() {
onStatsResize(newWidth); onStatsResize(newWidth);
} }
function getFrmStatsCookie() { function getFrameStatsCookie() {
var cookie = 'zmFrameStats'; var cookie = 'zmFrameStats';
var stats = getCookie(cookie); var stats = getCookie(cookie);
@ -53,16 +53,19 @@ function getFrmStatsCookie() {
function getStat(params) { function getStat(params) {
$j.getJSON(thisUrl + '?view=request&request=stats&raw=true', params) $j.getJSON(thisUrl + '?view=request&request=stats&raw=true', params)
.done(function(data) { .done(function(data) {
var stat = data.raw; var stats = data.raw;
$j('#frameStatsTable').empty().append('<tbody>'); $j('#frameStatsTable').empty().append('<tbody>');
for (const stat of stats) {
$j.each(statHeaderStrings, function(key) { $j.each(statHeaderStrings, function(key) {
var th = $j('<th>').addClass('text-right').text(statHeaderStrings[key]); var th = $j('<th>').addClass('text-right').text(statHeaderStrings[key]);
var tdString; var tdString;
switch (stat ? key : 'n/a') { switch (stat ? key : 'n/a') {
case 'FrameId': case 'FrameId':
tdString = '<a href="?view=stats&amp;eid=' + params.eid + '&amp;fid=' + params.fid + '">' + stat[key] + '</a>'; case 'EventId':
//tdString = '<a href="?view=stats&amp;eid=' + params.eid + '&amp;fid=' + params.fid + '">' + stat[key] + '</a>';
break; break;
case 'n/a': case 'n/a':
tdString = 'n/a'; tdString = 'n/a';
@ -76,6 +79,7 @@ function getStat(params) {
$j('#frameStatsTable tbody').append(row); $j('#frameStatsTable tbody').append(row);
}); });
} // end foreach stat
}) })
.fail(logAjaxFail); .fail(logAjaxFail);
} }
@ -143,7 +147,7 @@ function initPage() {
// Load the frame stats // Load the frame stats
getStat({eid: eid, fid: fid}); getStat({eid: eid, fid: fid});
if ( getFrmStatsCookie() != 'on' ) { if (getFrameStatsCookie() != 'on') {
table.toggle(false); table.toggle(false);
} else { } else {
onStatsResize($j('#base_width').val() * scale / SCALE_BASE); onStatsResize($j('#base_width').val() * scale / SCALE_BASE);

View File

@ -16,6 +16,9 @@ function generateVideoResponse( data, responseText ) {
} }
function generateVideo() { function generateVideo() {
$j.ajaxSetup({
timeout: 0
});
var form = $j('#videoForm').serialize(); var form = $j('#videoForm').serialize();
$j.getJSON(thisUrl + '?view=request&request=event&action=video', form) $j.getJSON(thisUrl + '?view=request&request=event&action=video', form)
.done(generateVideoResponse) .done(generateVideoResponse)

View File

@ -44,6 +44,7 @@ $tabs['medband'] = translate('MediumBW');
$tabs['lowband'] = translate('LowBW'); $tabs['lowband'] = translate('LowBW');
$tabs['users'] = translate('Users'); $tabs['users'] = translate('Users');
$tabs['control'] = translate('Control'); $tabs['control'] = translate('Control');
$tabs['privacy'] = translate('Privacy');
if (isset($_REQUEST['tab'])) if (isset($_REQUEST['tab']))
$tab = validHtmlStr($_REQUEST['tab']); $tab = validHtmlStr($_REQUEST['tab']);
@ -53,7 +54,6 @@ else
$focusWindow = true; $focusWindow = true;
xhtmlHeaders(__FILE__, translate('Options')); xhtmlHeaders(__FILE__, translate('Options'));
?> ?>
<body> <body>
<?php echo getNavBarHTML(); ?> <?php echo getNavBarHTML(); ?>
@ -194,6 +194,14 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as
} }
// Have to do this // Have to do this
header('Location: '.$redirect); header('Location: '.$redirect);
} else if ($tab == 'privacy') {
if (canView('System')) {
$redirect = '?view=privacy';
} else {
$redirect = '?view=error';
}
// Have to do this
header('Location: '.$redirect);
} else if ( $tab == 'servers' ) { } else if ( $tab == 'servers' ) {
?> ?>
<form name="serversForm" method="post" action="?"> <form name="serversForm" method="post" action="?">