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

This commit is contained in:
Isaac Connor 2020-10-31 10:47:25 -04:00
commit a04f6df06a
28 changed files with 299 additions and 485 deletions

View File

@ -303,6 +303,7 @@ CREATE TABLE `Filters` (
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
`Background` tinyint(1) unsigned NOT NULL default '0',
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
`LockRows` tinyint(1) unsigned NOT NULL default '0',
PRIMARY KEY (`Id`),
KEY `Name` (`Name`)
) ENGINE=@ZM_MYSQL_ENGINE@;
@ -315,6 +316,7 @@ DROP TABLE IF EXISTS `Frames`;
CREATE TABLE `Frames` (
`Id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`EventId` BIGINT UNSIGNED NOT NULL default '0',
FOREIGN KEY (`EventId`) REFERENCES `Events` (`Id`) ON DELETE CASCADE,
`FrameId` int(10) unsigned NOT NULL default '0',
`Type` enum('Normal','Bulk','Alarm') NOT NULL default 'Normal',
`TimeStamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
@ -608,8 +610,11 @@ DROP TABLE IF EXISTS `Stats`;
CREATE TABLE `Stats` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`MonitorId` int(10) unsigned NOT NULL default '0',
FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE,
`ZoneId` int(10) unsigned NOT NULL default '0',
FOREIGN KEY (`ZoneId`) REFERENCES `Zones` (`Id`) ON DELETE CASCADE,
`EventId` BIGINT UNSIGNED NOT NULL,
FOREIGN KEY (`EventId`) REFERENCES `Events` (`Id`) ON DELETE CASCADE,
`FrameId` int(10) unsigned NOT NULL default '0',
`PixelDiff` tinyint(3) unsigned NOT NULL default '0',
`AlarmPixels` int(10) unsigned NOT NULL default '0',
@ -704,6 +709,7 @@ DROP TABLE IF EXISTS `Zones`;
CREATE TABLE `Zones` (
`Id` int(10) unsigned NOT NULL auto_increment,
`MonitorId` int(10) unsigned NOT NULL default '0',
FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE,
`Name` varchar(64) NOT NULL default '',
`Type` enum('Active','Inclusive','Exclusive','Preclusive','Inactive','Privacy') NOT NULL default 'Active',
`Units` enum('Pixels','Percent') NOT NULL default 'Pixels',

83
db/zm_update-1.35.11.sql Normal file
View File

@ -0,0 +1,83 @@
/* Change Id type to BIGINT. */
set @exist := (SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'Events' AND COLUMN_NAME = 'Id' and DATA_TYPE='bigint');
set @sqlstmt := if( @exist = 0, "ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment", "SELECT 'Ok'");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
/* Add FOREIGN KEYS After deleting lost records */
set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Frames' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id');
set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'");
set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY EventId in Frames already exists'", @sqlstmt);
set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for EventId to Frames'", @sqlstmt);
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist != 0, "SELECT '.'", "SELECT 'Deleting unlinked Frames'");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist != 0, "SELECT '.'", "DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist != 0, "SELECT 'Ok'", "ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
SELECT 'Adding foreign key for EventId to Stats';
set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id');
set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'");
set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY already EventId in Stats already exists'", @sqlstmt);
set @sqlstmt := if( @exist = 0, "SELECT 'Adding FOREIGN KEY for EventId to Stats'", @sqlstmt);
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for EventId in Stats already exists'", "DELETE FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events);");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
SELECT 'Adding foreign key for MonitorId to Stats';
set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='MonitorId' and referenced_table_name='Monitors' and referenced_column_name='Id');
set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for MonitorId in Stats already exists'", "DELETE FROM Stats WHERE MonitorId NOT IN (SELECT Id FROM Monitors);");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id) ON DELETE CASCADE");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
SELECT 'Adding foreign key for ZoneId to Stats';
set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='ZoneId' and referenced_table_name='Zones' and referenced_column_name='Id');
set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for ZoneId in Stats already exists'", "DELETE FROM Stats WHERE ZoneId NOT IN (SELECT Id FROM Zones);");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (ZoneId) REFERENCES Zones (Id) ON DELETE CASCADE");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
SELECT 'Adding foreign key for MonitorId to Zones';
set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Zones' and column_name='MonitorId' and referenced_table_name='Monitors' and referenced_column_name='Id');
set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for MonitorId in Zones already exists'", "SELECT 'FOREIGN KEY for MonitorId in Zones does not already exist'");
set @badzones := (select count(*) FROM Zones WHERE MonitorId NOT IN (SELECT Id FROM Monitors));
set @sqlstmt := if ( @badzones > 0, "SELECT 'You have Zones with no Monitor record in the Monitors table. Please delete them manually'", "ALTER TABLE Zones ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id)");
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;

18
db/zm_update-1.35.12.sql Normal file
View File

@ -0,0 +1,18 @@
--
-- Update Filters table to have a LockRows Column
--
SELECT 'Checking for LockRows in Filters';
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Filters'
AND table_schema = DATABASE()
AND column_name = 'LockRows'
) > 0,
"SELECT 'Column LockRows already exists in Filters'",
"ALTER TABLE Filters ADD COLUMN `LockRows` tinyint(1) unsigned NOT NULL default '0' AFTER `Concurrent`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -39,9 +39,9 @@ if [ "$1" = "configure" ]; then
exit 1;
fi
# This creates the user.
echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute, REFERENCES on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute, REFERENCES on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
zmupdate.pl --nointeractive

View File

@ -28,7 +28,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.35.10
Version: 1.35.12
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons

View File

@ -67,8 +67,8 @@ if [ "$1" = "configure" ]; then
# This creates the user.
echo "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
echo "Updating permissions"
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
echo "Updating permissions for user ${ZM_DB_USER}@localhost"
echo "GRANT LOCK TABLES,ALTER,DROP,SELECT,INSERT,UPDATE,DELETE,CREATE,INDEX,ALTER ROUTINE,CREATE ROUTINE, TRIGGER,EXECUTE,REFERENCES ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f

View File

@ -25,8 +25,8 @@ create_update_user () {
# This creates the user.
echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
echo "Updating permissions"
echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
echo "Updating permissions for user ${ZM_DB_USER}@${ZM_DB_HOST}"
echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute,REFERENCES ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
}
update_db () {

View File

@ -349,6 +349,10 @@ sub GenerateVideo {
return;
} # end sub GenerateVideo
# Note about transactions, this function may be called with rows locked and hence in a transaction.
# So we will detect if we are in a transaction, and if not, start one. We will NOT do rollback or
# commits unless we started the transaction.
sub delete {
my $event = $_[0];
@ -378,23 +382,25 @@ sub delete {
Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from ".$event->Path());
$ZoneMinder::Database::dbh->ping();
$ZoneMinder::Database::dbh->begin_work();
#$event->lock_and_load();
my $in_transaction = $ZoneMinder::Database::dbh->{AutoCommit} ? 0 : 1;
ZoneMinder::Database::zmDbDo('DELETE FROM Frames WHERE EventId=?', $$event{Id});
if ( $ZoneMinder::Database::dbh->errstr() ) {
$ZoneMinder::Database::dbh->commit();
return;
}
$ZoneMinder::Database::dbh->begin_work() if ! $in_transaction;
# Going to delete in order of least value to greatest value. Stats is least and references Frames
ZoneMinder::Database::zmDbDo('DELETE FROM Stats WHERE EventId=?', $$event{Id});
if ( $ZoneMinder::Database::dbh->errstr() ) {
$ZoneMinder::Database::dbh->commit();
$ZoneMinder::Database::dbh->commit() if ! $in_transaction;
return;
}
ZoneMinder::Database::zmDbDo('DELETE FROM Frames WHERE EventId=?', $$event{Id});
if ( $ZoneMinder::Database::dbh->errstr() ) {
$ZoneMinder::Database::dbh->commit() if ! $in_transaction;
return;
}
# Do it individually to avoid locking up the table for new events
ZoneMinder::Database::zmDbDo('DELETE FROM Events WHERE Id=?', $$event{Id});
$ZoneMinder::Database::dbh->commit();
$ZoneMinder::Database::dbh->commit() if ! $in_transaction;
}
if ( ( $in_zmaudit or (!$Config{ZM_OPT_FAST_DELETE})) and $event->Storage()->DoDelete() ) {

View File

@ -77,6 +77,7 @@ UpdateDiskSpace
UserId
Background
Concurrent
LockRows
);
sub Execute {
@ -103,6 +104,8 @@ sub Execute {
$sql =~ s/zmSystemLoad/$load/g;
}
$sql .= ' FOR UPDATE' if $$self{LockRows};
Debug("Filter::Execute SQL ($sql)");
my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());

View File

@ -504,9 +504,9 @@ sub openFile {
$LOGFILE->autoflush() if $this->{autoFlush};
my $webUid = (getpwnam($ZoneMinder::Config::Config{ZM_WEB_USER}))[2];
Error("Can't get uid for $ZoneMinder::Config::Config{ZM_WEB_USER}") if ! defined $webUid;
Error('Can\'t get uid for '.$ZoneMinder::Config::Config{ZM_WEB_USER}) if ! defined $webUid;
my $webGid = (getgrnam($ZoneMinder::Config::Config{ZM_WEB_GROUP}))[2];
Error("Can't get gid for $ZoneMinder::Config::Config{ZM_WEB_USER}") if ! defined $webGid;
Error('Can\'t get gid for '.$ZoneMinder::Config::Config{ZM_WEB_USER}) if ! defined $webGid;
if ( $> == 0 ) {
# If we are root, we want to make sure that www-data or whatever owns the file
chown($webUid, $webGid, $this->{logFile} ) or
@ -610,6 +610,7 @@ sub logInit( ;@ ) {
my %options = @_ ? @_ : ();
$logger = ZoneMinder::Logger->new() if !$logger;
$logger->initialise(%options);
logSetSignal();
}
sub logReinit {
@ -626,12 +627,26 @@ sub logHupHandler {
$do_log_rotate = 1;
}
sub logUSR1Handler {
$logger->level($logger->level()+1);
Info('Logger - Level changed to '. $logger->level() . '=>'.$codes{$logger->level()});
}
sub logUSR2Handler {
$logger->level($logger->level()-1);
Info('Logger - Level changed to '. $logger->level() . '=>'.$codes{$logger->level()});
}
sub logSetSignal {
$SIG{HUP} = \&logHupHandler;
$SIG{USR1} = \&logUSR1Handler;
$SIG{USR2} = \&logUSR2Handler;
}
sub logClearSignal {
$SIG{HUP} = 'DEFAULT';
$SIG{USR1} = 'DEFAULT';
$SIG{USR2} = 'DEFAULT';
}
sub logLevel {

View File

@ -277,6 +277,7 @@ FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
sub checkFilter {
my $filter = shift;
my $in_transaction = ZoneMinder::Database::start_transaction($dbh) if $$filter{LockRows};
my @Events = $filter->Execute();
Debug(
join(' ',
@ -396,6 +397,7 @@ sub checkFilter {
$ZoneMinder::Database::dbh->commit();
} # end if UpdateDiskSpace
} # end foreach event
ZoneMinder::Database::end_transaction($dbh, $in_transaction) if $$filter{LockRows};
} # end sub checkFilter
sub generateVideo {

View File

@ -664,7 +664,6 @@ int FfmpegCamera::OpenFfmpeg() {
} // int FfmpegCamera::OpenFfmpeg()
int FfmpegCamera::Close() {
Debug(2, "CloseFfmpeg called.");
mCanCapture = false;

View File

@ -29,15 +29,13 @@
bool zm_reload = false;
bool zm_terminate = false;
RETSIGTYPE zm_hup_handler(int signal)
{
RETSIGTYPE zm_hup_handler(int signal) {
// Shouldn't do complex things in signal handlers, logging is complex and can block due to mutexes.
//Info("Got signal %d (%s), reloading", signal, strsignal(signal));
zm_reload = true;
}
RETSIGTYPE zm_term_handler(int signal)
{
RETSIGTYPE zm_term_handler(int signal) {
// Shouldn't do complex things in signal handlers, logging is complex and can block due to mutexes.
//Info("Got signal %d (%s), exiting", signal, strsignal(signal));
zm_terminate = true;
@ -55,8 +53,7 @@ RETSIGTYPE zm_die_handler(int signal)
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
void *ip = nullptr;
void *cr2 = nullptr;
if (info && context) {
if ( info && context ) {
Debug(1,
"Signal information: number %d code %d errno %d pid %d uid %d status %d",
signal, info->si_code, info->si_errno, info->si_pid,
@ -79,7 +76,7 @@ RETSIGTYPE zm_die_handler(int signal)
#endif // defined(__x86_64__)
// Print the signal address and instruction pointer if available
if (ip) {
if ( ip ) {
Error("Signal address is %p, from %p", cr2, ip);
} else {
Error("Signal address is %p, no instruction pointer", cr2);
@ -115,8 +112,7 @@ RETSIGTYPE zm_die_handler(int signal)
exit(signal);
}
void zmSetHupHandler(SigHandler * handler)
{
void zmSetHupHandler(SigHandler * handler) {
sigset_t block_set;
sigemptyset(&block_set);
struct sigaction action, old_action;
@ -127,8 +123,7 @@ void zmSetHupHandler(SigHandler * handler)
sigaction(SIGHUP, &action, &old_action);
}
void zmSetTermHandler(SigHandler * handler)
{
void zmSetTermHandler(SigHandler * handler) {
sigset_t block_set;
sigemptyset(&block_set);
struct sigaction action, old_action;
@ -141,8 +136,7 @@ void zmSetTermHandler(SigHandler * handler)
sigaction(SIGQUIT, &action, &old_action);
}
void zmSetDieHandler(SigHandler * handler)
{
void zmSetDieHandler(SigHandler * handler) {
sigset_t block_set;
sigemptyset(&block_set);
struct sigaction action, old_action;
@ -163,19 +157,16 @@ void zmSetDieHandler(SigHandler * handler)
sigaction(SIGFPE, &action, &old_action);
}
void zmSetDefaultHupHandler()
{
void zmSetDefaultHupHandler() {
zmSetHupHandler((SigHandler *) zm_hup_handler);
}
void zmSetDefaultTermHandler()
{
void zmSetDefaultTermHandler() {
zmSetTermHandler((SigHandler *) zm_term_handler);
}
void zmSetDefaultDieHandler()
{
if (config.dump_cores) {
void zmSetDefaultDieHandler() {
if ( config.dump_cores ) {
// Do nothing
} else {
zmSetDieHandler((SigHandler *) zm_die_handler);

View File

@ -1 +1 @@
1.35.10
1.35.12

View File

@ -115,6 +115,19 @@ function deleteRequest($eid) {
}
function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) {
$data = array(
'total' => 0,
'totalNotFiltered' => 0,
'rows' => array(),
'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG)
);
$failed = !$filter->test_pre_sql_conditions();
if ( $failed ) {
ZM\Debug('Pre conditions failed, not doing sql');
return $data;
}
// Put server pagination code here
// The table we want our data from
$table = 'Events';
@ -126,7 +139,8 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
$col_alt = array('Monitor', 'Storage');
if ( !in_array($sort, array_merge($columns, $col_alt)) ) {
ZM\Fatal('Invalid sort field: ' . $sort);
ZM\Error('Invalid sort field: ' . $sort);
$sort = 'Id';
}
$data = array();
@ -140,44 +154,39 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
if ( count($advsearch) ) {
foreach ( $advsearch as $col=>$text ) {
if ( !in_array($col, array_merge($columns, $col_alt)) ) {
if ( in_array($col, $columns) ) {
array_push($likes, 'E.'.$col.' LIKE ?');
array_push($query['values'], $text);
} else if ( in_array($col, $col_alt) ) {
array_push($likes, 'M.'.$col.' LIKE ?');
array_push($query['values'], $text);
} else {
ZM\Error("'$col' is not a sortable column name");
continue;
}
$text = '%' .$text. '%';
array_push($likes, $col.' LIKE ?');
array_push($query['values'], $text);
}
} # end foreach col in advsearch
$wherevalues = $query['values'];
$where = ' AND (' .implode(' OR ', $likes). ')';
$where .= ($where != '') ? ' AND (' .implode(' OR ', $likes). ')' : implode(' OR ', $likes);
} else if ( $search != '' ) {
$search = '%' .$search. '%';
foreach ( $columns as $col ) {
array_push($likes, $col.' LIKE ?');
array_push($likes, 'E.'.$col.' LIKE ?');
array_push($query['values'], $search);
}
$wherevalues = $query['values'];
$where = ' AND (' .implode(' OR ', $likes). ')';
$where .= ( $where != '') ? ' AND (' .implode(' OR ', $likes). ')' : implode(' OR ', $likes);
}
if ( $where )
$where = ' WHERE '.$where;
$sort = $sort == "Monitor" ? 'M.Name' : 'E.'.$sort;
$sort = $sort == 'Monitor' ? 'M.Name' : 'E.'.$sort;
$col_str = 'E.*, M.Name AS Monitor';
//$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY LENGTH(' .$sort. '), ' .$sort. ' ' .$order. ' LIMIT ?, ?';
$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?';
array_push($query['values'], $offset, $limit);
ZM\Warning('Calling the following sql query: ' .$query['sql']);
$data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table . ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total');
if ( $search != '' || count($advsearch) ) {
$data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table . ' AS E'.$where , 'Total', $wherevalues);
} else {
$data['total'] = $data['totalNotFiltered'];
}
//ZM\Debug('Calling the following sql query: ' .$query['sql']);
$storage_areas = ZM\Storage::find();
$StorageById = array();
@ -187,12 +196,15 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
$rows = array();
foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) {
ZM\Debug("row".print_r($row,true));
$event = new ZM\Event($row);
if ( !$filter->test_post_sql_conditions($event) ) {
$event->remove_from_cache();
continue;
}
$scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width());
$imgSrc = $event->getThumbnailSrc(array(),'&');
$streamSrc = $event->getStreamSrc(array(
'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&');
'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&');
// Modify the row data as needed
$row['imgHtml'] = '<img id="thumbnail' .$event->Id(). '" src="' .$imgSrc. '" alt="' .validHtmlStr('Event ' .$event->Id()). '" style="width:' .validInt($event->ThumbnailWidth()). 'px;height:' .validInt($event->ThumbnailHeight()).'px;" stream_src="' .$streamSrc. '" still_src="' .$imgSrc. '"/>';
@ -201,16 +213,18 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
$row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No');
$row['Cause'] = validHtmlStr($row['Cause']);
$row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime']));
$row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime']));
$row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndTime']));
$row['Length'] = gmdate('H:i:s', $row['Length'] );
$row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default';
$row['Notes'] = htmlspecialchars($row['Notes']);
$row['Notes'] = nl2br(htmlspecialchars($row['Notes']));
$row['DiskSpace'] = human_filesize($event->DiskSpace());
$rows[] = $row;
}
$data['rows'] = $rows;
$data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG);
# total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet.
$data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total');
#$data['total'] = count($rows);
return $data;
}
?>

View File

@ -66,7 +66,7 @@ if ( isset($_REQUEST['limit']) ) {
switch ( $task ) {
case 'create' :
createRequest($task, $eid);
createRequest();
break;
case 'query' :
$data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit);
@ -82,27 +82,27 @@ ajaxResponse($data);
//
function createRequest() {
if ( !empty($_POST['level']) && !empty($_POST['message']) ) {
ZM\logInit(array('id'=>'web_js'));
if ( !empty($_POST['level']) && !empty($_POST['message']) ) {
ZM\logInit(array('id'=>'web_js'));
$string = $_POST['message'];
$string = $_POST['message'];
$file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : '';
if ( !empty($_POST['line']) ) {
$line = validInt($_POST['line']);
} else {
$line = NULL;
}
$levels = array_flip(ZM\Logger::$codes);
if ( !isset($levels[$_POST['level']]) ) {
ZM\Panic('Unexpected logger level '.$_POST['level']);
}
$level = $levels[$_POST['level']];
ZM\Logger::fetch()->logPrint($level, $string, $file, $line);
$file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : '';
if ( !empty($_POST['line']) ) {
$line = validInt($_POST['line']);
} else {
ZM\Error('Invalid log create: '.print_r($_POST, true));
$line = NULL;
}
$levels = array_flip(ZM\Logger::$codes);
if ( !isset($levels[$_POST['level']]) ) {
ZM\Panic('Unexpected logger level '.$_POST['level']);
}
$level = $levels[$_POST['level']];
ZM\Logger::fetch()->logPrint($level, $string, $file, $line);
} else {
ZM\Error('Invalid log create: '.print_r($_POST, true));
}
}
function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) {

View File

@ -6,6 +6,7 @@ if ( $_REQUEST['entity'] == 'navBar' ) {
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) {
$data['auth'] = $auth_hash;
$data['auth_relay'] = get_auth_relay();
}
}
// Each widget on the navbar has its own function

View File

@ -29,6 +29,7 @@ class Filter extends ZM_Object {
'Background' => 0,
'Concurrent' => 0,
'Query_json' => '',
'LockRows' => 0,
);
protected $_querystring;

View File

@ -408,10 +408,10 @@ class Logger {
}
}
$message = $code.' ['.$string.']';
if ( $level <= $this->syslogLevel )
syslog( self::$syslogPriorities[$level], $message );
syslog(self::$syslogPriorities[$level], $message);
$message = $code.' ['.$string.']';
if ( $level <= $this->databaseLevel ) {
try {
global $dbConn;

View File

@ -371,6 +371,7 @@ $SLANG = array(
'FilterUpdateDiskSpace' => 'Update used disk space',
'FilterDeleteEvents' => 'Delete all matches',
'FilterCopyEvents' => 'Copy all matches',
'FilterLockRows' => 'Lock Rows',
'FilterMoveEvents' => 'Move all matches',
'FilterEmailEvents' => 'Email details of all matches',
'FilterEmailTo' => 'Email To',

View File

@ -351,6 +351,11 @@ if ( currentView != 'none' && currentView != 'login' ) {
.done(setNavBar)
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
if ( ! jqxhr.responseText ) {
console.log("No responseText in jqxhr");
console.log(jqxhr);
return;
}
console.log("Response Text: " + jqxhr.responseText.replace(/(<([^>]+)>)/gi, ''));
if ( textStatus != "timeout" ) {
// The idea is that this should only fail due to auth, so reload the page
@ -367,10 +372,14 @@ if ( currentView != 'none' && currentView != 'login' ) {
}
if ( data.auth ) {
if ( data.auth != auth_hash ) {
console.log("Update auth_hash to "+data.auth);
// Update authentication token.
auth_hash = data.auth;
}
}
if ( data.auth_relay ) {
auth_relay = data.auth_relay;
}
// iterate through all the keys then update each element id with the same name
for (var key of Object.keys(data)) {
if ( key == "auth" ) continue;

View File

@ -42,73 +42,6 @@ if ( isset($_REQUEST['filter'])) {
parseSort();
$filterQuery = $filter->querystring();
ZM\Debug('Filter '.print_r($filter, true));
if ( $filter->sql() ) {
$eventsSql .= ' AND ('.$filter->sql().')';
} else {
ZM\Warning('No filters');
exit;
}
$eventsSql .= ' ORDER BY '.$sortColumn.' '.$sortOrder;
if ( $sortColumn != 'E.Id' ) $eventsSql .= ',E.Id '.$sortOrder;
$page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 0;
$limit = isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : $filter['limit'];
if ( $_POST ) {
// I think this is basically so that a refresh doesn't repost
ZM\Debug('Redirecting to ' . $_SERVER['REQUEST_URI']);
header('Location: ?view=' . $view.htmlspecialchars_decode($filterQuery).htmlspecialchars_decode($sortQuery).$limitQuery.'&page='.$page);
exit();
}
$failed = !$filter->test_pre_sql_conditions();
if ( $failed ) {
ZM\Debug('Pre conditions failed, not doing sql');
}
$results = $failed ? null : dbQuery($eventsSql);
$nEvents = $results ? $results->rowCount() : 0;
if ( ! $results ) {
global $error_message;
$error_message = dbError($eventsSql);
}
ZM\Debug("Pre conditions succeeded sql return $nEvents events");
if ( !empty($limit) && ($nEvents > $limit) ) {
$nEvents = $limit;
}
$pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE);
#Debug("Page $page Limit $limit #vents: $nEvents pages: $pages ");
if ( !empty($page) ) {
if ( $page < 0 )
$page = 1;
else if ( $pages and ( $page > $pages ) )
$page = $pages;
$limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE);
if ( empty($limit) ) {
$limitAmount = ZM_WEB_EVENTS_PER_PAGE;
} else {
$limitLeft = $limit - $limitStart;
$limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft;
}
$eventsSql .= ' LIMIT '.$limitStart.', '.$limitAmount;
} else if ( !empty($limit) ) {
$eventsSql .= ' LIMIT 0, '.$limit;
}
$maxShortcuts = 5;
$focusWindow = true;
$storage_areas = ZM\Storage::find();
$StorageById = array();
foreach ( $storage_areas as $S ) {
$StorageById[$S->Id()] = $S;
}
xhtmlHeaders(__FILE__, translate('Events'));
getBodyTopHTML();
@ -136,6 +69,8 @@ getBodyTopHTML();
<table
id="eventTable"
data-locale="<?php echo i18n() ?>"
data-side-pagination="server"
data-ajax="ajaxRequest"
data-pagination="true"
data-show-pagination-switch="true"
data-page-list="[10, 25, 50, 100, 200, All]"
@ -155,6 +90,7 @@ getBodyTopHTML();
data-mobile-responsive="true"
data-buttons-class="btn btn-normal"
data-show-jump-to="true"
data-show-refresh="true"
class="table-sm table-borderless"
style="display:none;"
>
@ -168,163 +104,24 @@ getBodyTopHTML();
<th data-sortable="true" data-field="Emailed"><?php echo translate('Emailed') ?></th>
<th data-sortable="true" data-field="Monitor"><?php echo translate('Monitor') ?></th>
<th data-sortable="true" data-field="Cause"><?php echo translate('Cause') ?></th>
<th data-sortable="true" data-field="AttrStartTime"><?php echo translate('AttrStartTime') ?></th>
<th data-sortable="true" data-field="AttrEndTime"><?php echo translate('AttrEndTime') ?></th>
<th data-sortable="true" data-field="Duration"><?php echo translate('Duration') ?></th>
<th data-sortable="true" data-field="StartTime"><?php echo translate('AttrStartTime') ?></th>
<th data-sortable="true" data-field="EndTime"><?php echo translate('AttrEndTime') ?></th>
<th data-sortable="true" data-field="Length"><?php echo translate('Duration') ?></th>
<th data-sortable="true" data-field="Frames"><?php echo translate('Frames') ?></th>
<th data-sortable="true" data-field="AlarmBrFrames"><?php echo translate('AlarmBrFrames') ?></th>
<th data-sortable="true" data-field="TotalBrScore"><?php echo translate('TotalBrScore') ?></th>
<th data-sortable="true" data-field="AvgBrScore"><?php echo translate('AvgBrScore') ?></th>
<th data-sortable="true" data-field="MaxBrScore"><?php echo translate('MaxBrScore') ?></th>
<?php
if ( count($storage_areas) > 1 ) {
?>
<th data-sortable="true" data-field="Storage"><?php echo translate('Storage') ?></th>
<?php
}
if ( ZM_WEB_EVENT_DISK_SPACE ) {
?>
<th data-sortable="true" data-field="AlarmFrames"><?php echo translate('AlarmBrFrames') ?></th>
<th data-sortable="true" data-field="TotScore"><?php echo translate('TotalBrScore') ?></th>
<th data-sortable="true" data-field="AvgScore"><?php echo translate('AvgBrScore') ?></th>
<th data-sortable="true" data-field="MaxScore"><?php echo translate('MaxBrScore') ?></th>
<th data-sortable="false" data-field="Storage"><?php echo translate('Storage') ?></th>
<th data-sortable="true" data-field="DiskSpace"><?php echo translate('DiskSpace') ?></th>
<?php
}
if ( ZM_WEB_LIST_THUMBS ) {
?>
<th data-sortable="false" data-field="Thumbnail"><?php echo translate('Thumbnail') ?></th>
<?php
}
?>
</tr>
</thead>
<tbody>
<?php
$count = 0;
$disk_space_total = 0;
if ( $results ) {
$events = array();
</thead>
while ( $event_row = dbFetchNext($results) ) {
$event = new ZM\Event($event_row);
if ( !$filter->test_post_sql_conditions($event) ) {
$event->remove_from_cache();
continue;
}
$events[] = $event;
if ( $limit and (count($events) >= $limit) ) {
break;
}
ZM\Debug("Have " . count($events) . " events, limit $limit");
}
foreach ( $events as $event ) {
$scale = max(reScale(SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE);
?>
<tr<?php echo $event->Archived() ? ' class="archived"' : '' ?>>
<td data-checkbox="true"></td>
<td><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.$event->Id() ?></a></td>
<td><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.validHtmlStr($event->Name())?></a>
<?php
$archived = $event->Archived() ? translate('Archived') : '';
$emailed = $event->Emailed() ? ' '.translate('Emailed') : '';
echo '<br/><div class="small text-nowrap text-muted">'.$archived.$emailed.'</div>';
?>
</td>
<td class="text-center"><?php echo ( $event->Archived() ) ? 'Yes' : 'No' ?></td>
<td class="text-center"><?php echo ( $event->Emailed() ) ? 'Yes' : 'No' ?></td>
<td><?php echo makeLink( '?view=monitor&amp;mid='.$event->MonitorId(), $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td><?php echo makeLink( '#', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="' .htmlspecialchars($event->Notes()). '" class="eDetailLink" data-eid=' .$event->Id(). '"') ?>
<?php
# display notes as small text
if ( $event->Notes() ) {
# if notes include detection objects, then link it to objdetect.jpg
if ( strpos($event->Notes(), 'detected:') !== false ) {
# make a link
echo makeLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', '<div class="small text-nowrap text-muted"><u>'.$event->Notes().'</u></div>');
} else if ( $event->Notes() != 'Forced Web: ' ) {
echo '<br/><div class="small text-nowrap text-muted">'.$event->Notes().'</div>';
}
}
?>
</td>
<td><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime())) ?></td>
<td><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime())) ?></td>
<td><?php echo gmdate('H:i:s', $event->Length() ) ?></td>
<td><a href="?view=frames&amp;eid=<?php echo $event->Id() ?>"><?php echo $event->Frames() ?></a></td>
<td><a href="?view=frames&amp;eid=<?php echo $event->Id() ?>"><?php echo $event->AlarmFrames() ?></a></td>
<td><?php echo $event->TotScore() ?></td>
<td><?php echo $event->AvgScore() ?></td>
<td><?php echo makeLink('?view=frame&amp;eid='.$event->Id().'&amp;fid=0', $event->MaxScore()); ?></td>
<?php
if ( count($storage_areas) > 1 ) {
?>
<td>
<?php
if ( $event->StorageId() ) {
echo isset($StorageById[$event->StorageId()]) ? $StorageById[$event->StorageId()]->Name() : 'Unknown Storage Id: '.$event->StorageId();
} else {
echo 'Default';
}
if ( $event->SecondaryStorageId() ) {
echo '<br/>'.(isset($StorageById[$event->SecondaryStorageId()]) ? $StorageById[$event->SecondaryStorageId()]->Name() : 'Unknown Storage Id '.$event->SecondaryStorageId());
}
?>
</td>
<?php
}
if ( ZM_WEB_EVENT_DISK_SPACE ) {
$disk_space_total += $event->DiskSpace();
?>
<td class="colDiskSpace"><?php echo human_filesize($event->DiskSpace()) ?></td>
<?php
}
if ( ZM_WEB_LIST_THUMBS ) {
echo '<td class="colThumbnail zoom">';
$imgSrc = $event->getThumbnailSrc(array(),'&amp;');
$streamSrc = $event->getStreamSrc(array(
'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&amp;');
$imgHtml = '<img id="thumbnail'.$event->Id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($event->ThumbnailWidth()) .'px;height:'. validInt($event->ThumbnailHeight()).'px;" stream_src="'.$streamSrc.'" still_src="'.$imgSrc.'"/>';
echo '<a href="?view=event&amp;eid='. $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.$imgHtml.'</a>';
echo '</td>';
} // end if ZM_WEB_LIST_THUMBS
?>
</tr>
<?php
} # end foreach row
?>
<tbody>
<!-- Row data populated via Ajax -->
</tbody>
<?php
} # end if $results
if ( ZM_WEB_EVENT_DISK_SPACE ) {
?>
<tfoot>
<tr>
<td colspan="11">Totals:</td>
<?php
if ( count($storage_areas)>1 ) {
?>
<td class="colStorage"></td>
<?php
}
?>
<td class="colDiskSpace"><?php echo human_filesize($disk_space_total) ?></td>
<?php
if ( ZM_WEB_LIST_THUMBS ) {
?>
<td></td>
<?php
}
?>
<td></td>
</tr>
</tfoot>
<?php
}
?>
</table>
</div>
</div>

View File

@ -485,6 +485,10 @@ if ( ZM_OPT_MESSAGE ) {
<label for="Concurrent"><?php echo translate('ConcurrentFilter') ?></label>
<input type="checkbox" id="filter[Concurrent]" name="filter[Concurrent]" value="1"<?php if ( $filter->Concurrent() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
</p>
<p>
<label for="LockRows"><?php echo translate('FilterLockRows') ?></label>
<input type="checkbox" id="filter[LockRows]" name="filter[LockRows]" value="1"<?php if ( $filter->LockRows() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
</p>
</div>
<hr/>
<div id="contentButtons">

View File

@ -61,7 +61,7 @@ function processRows(rows) {
if ( canEditMonitors ) row.Monitor = '<a href="?view=monitor&amp;mid=' + mid + '">' + row.Monitor + '</a>';
if ( canEditEvents ) row.Cause = '<a href="#" title="' + row.Notes + '" class="eDetailLink" data-eid="' + eid + '">' + row.Cause + '</a>';
if ( row.Notes.indexOf('detected:') >= 0 ) {
row.Cause = row.Cause + '<a href="#?view=image&amp;eid=' + eid + '&amp;fid=objdetect"><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></a>';
row.Cause = row.Cause + '<a href="?view=image&amp;eid=' + eid + '&amp;fid=objdetect"><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></a>';
} else if ( row.Notes != 'Forced Web: ' ) {
row.Cause = row.Cause + '<br/><div class="small text-nowrap text-muted">' + row.Notes + '</div>';
}
@ -135,7 +135,7 @@ function manageDelConfirmModalBtns() {
$j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+selections.join('&eids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
window.location.reload(true);
$j('#deleteConfirm').modal('hide');
})
.fail(logAjaxFail);
});
@ -238,7 +238,6 @@ function initPage() {
$j.getJSON(thisUrl + '?request=events&task=archive&eids[]='+selections.join('&eids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
window.location.reload(true);
})
.fail(logAjaxFail);
});
@ -257,11 +256,8 @@ function initPage() {
$j.getJSON(thisUrl + '?request=events&task=unarchive&eids[]='+selections.join('&eids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
window.location.reload(true);
})
.fail(logAjaxFail);
//window.location.reload(true);
});
// Manage the EDIT button
@ -321,13 +317,6 @@ function initPage() {
$j('#deleteConfirm').modal('show');
});
// Manage the eventdetail links in the events list
$j(".eDetailLink").click(function(evt) {
evt.preventDefault();
var eid = $j(this).data('eid');
getEventDetailModal(eid);
});
// Update table links each time after new data is loaded
table.on('post-body.bs.table', function(data) {
// Manage the eventdetail links in the events list
@ -343,6 +332,7 @@ function initPage() {
table.find("tr td:nth-child(" + (thumb_ndx+1) + ")").addClass('colThumbnail zoom');
});
table.bootstrapTable('resetSearch');
// The table is initially given a hidden style, so now that we are done rendering, show it
table.show();
}

View File

@ -74,35 +74,32 @@ function validateForm(form) {
function updateButtons(element) {
var form = element.form;
if ( element.type == 'checkbox' && element.checked ) {
form.elements['executeButton'].disabled = false;
} else {
var canExecute = false;
if ( form.elements['filter[AutoArchive]'] && form.elements['filter[AutoArchive]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoUnarchive]'] && form.elements['filter[AutoUnarchive]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoCopy]'] && form.elements['filter[AutoCopy]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoMove]'] && form.elements['filter[AutoMove]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoVideo]'] && form.elements['filter[AutoVideo]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoUpload]'] && form.elements['filter[AutoUpload]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoExecute]'].checked && form.elements['filter[AutoExecuteCmd]'].value != '' ) {
canExecute = true;
} else if ( form.elements['filter[AutoDelete]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[UpdateDiskSpace]'].checked ) {
canExecute = true;
}
form.elements['executeButton'].disabled = !canExecute;
var canExecute = false;
if ( form.elements['filter[AutoArchive]'] && form.elements['filter[AutoArchive]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoUnarchive]'] && form.elements['filter[AutoUnarchive]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoCopy]'] && form.elements['filter[AutoCopy]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoMove]'] && form.elements['filter[AutoMove]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoVideo]'] && form.elements['filter[AutoVideo]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoUpload]'] && form.elements['filter[AutoUpload]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoExecute]'].checked && form.elements['filter[AutoExecuteCmd]'].value != '' ) {
canExecute = true;
} else if ( form.elements['filter[AutoDelete]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[UpdateDiskSpace]'].checked ) {
canExecute = true;
}
form.elements['executeButton'].disabled = !canExecute;
if ( form.elements['filter[Name]'].value ) {
form.elements['Save'].disabled = false;
form.elements['SaveAs'].disabled = false;

View File

@ -1,4 +1,4 @@
var ZM_OPT_USE_GEOLOCATION = '<?php echo ZM_OPT_USE_GEOLOCATION ?>';
var ZM_OPT_USE_GEOLOCATION = '<?php echo ZM_OPT_USE_GEOLOCATION ?>' == '1' ? true : false;
<?php
if ( ZM_OPT_USE_GEOLOCATION ) {
echo 'var ZM_OPT_GEOLOCATION_TILE_PROVIDER=\''.ZM_OPT_GEOLOCATION_TILE_PROVIDER.'\''.PHP_EOL;

View File

@ -1,128 +0,0 @@
<?php
//
// ZoneMinder web events 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') || (!empty($_REQUEST['execute']) && !canEdit('Events')) ) {
$view = 'error';
return;
}
require_once('includes/Event.php');
require_once('includes/Filter.php');
$eventsSql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultScale FROM Monitors AS M INNER JOIN Events AS E on (M.Id = E.MonitorId) WHERE';
if ( $user['MonitorIds'] ) {
$user_monitor_ids = ' M.Id in ('.$user['MonitorIds'].')';
$eventsSql .= $user_monitor_ids;
} else {
$eventsSql .= ' 1';
}
$filter = isset($_REQUEST['filter_id']) ? new ZM\Filter($_REQUEST['filter_id']) : new ZM\Filter();
if ( isset($_REQUEST['filter'])) {
$filter->set($_REQUEST['filter']);
}
parseSort();
$filterQuery = $filter->querystring();
xhtmlHeaders(__FILE__, translate('Events'));
getBodyTopHTML();
?>
<?php echo getNavBarHTML() ?>
<div id="page" class="container-fluid p-3">
<!-- Toolbar button placement and styling handled by bootstrap-tables -->
<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 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="tlineBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('ShowTimeline') ?>" ><i class="fa fa-history"></i></button>
<button id="filterBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Filter') ?>"><i class="fa fa-filter"></i></button>
<button id="viewBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('View') ?>" disabled><i class="fa fa-binoculars"></i></button>
<button id="archiveBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Archive') ?>" disabled><i class="fa fa-archive"></i></button>
<button id="unarchiveBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Unarchive') ?>" disabled><i class="fa fa-file-archive-o"></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') ?>" disabled><i class="fa fa-external-link"></i></button>
<button id="downloadBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('DownloadVideo') ?>" disabled><i class="fa fa-download"></i></button>
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>" disabled><i class="fa fa-trash"></i></button>
</div>
<!-- Table styling handled by bootstrap-tables -->
<div class="row justify-content-center">
<table
id="eventTable"
data-locale="<?php echo i18n() ?>"
data-side-pagination="server"
data-ajax="ajaxRequest"
data-pagination="true"
data-show-pagination-switch="true"
data-page-list="[10, 25, 50, 100, 200, All]"
data-search="true"
data-cookie="true"
data-cookie-id-table="zmEventsTable"
data-cookie-expire="2y"
data-click-to-select="true"
data-remember-order="true"
data-show-columns="true"
data-show-export="true"
data-uncheckAll="true"
data-toolbar="#toolbar"
data-show-fullscreen="true"
data-click-to-select="true"
data-maintain-meta-data="true"
data-mobile-responsive="true"
data-buttons-class="btn btn-normal"
data-show-jump-to="true"
data-show-refresh="true"
class="table-sm table-borderless"
style="display:none;"
>
<thead>
<!-- Row styling is handled by bootstrap-tables -->
<tr>
<th data-sortable="false" data-field="toggleCheck" data-checkbox="true"></th>
<th data-sortable="true" data-field="Id"><?php echo translate('Id') ?></th>
<th data-sortable="true" data-field="Name"><?php echo translate('Name') ?></th>
<th data-sortable="true" data-field="Archived"><?php echo translate('Archived') ?></th>
<th data-sortable="true" data-field="Emailed"><?php echo translate('Emailed') ?></th>
<th data-sortable="true" data-field="Monitor"><?php echo translate('Monitor') ?></th>
<th data-sortable="true" data-field="Cause"><?php echo translate('Cause') ?></th>
<th data-sortable="true" data-field="StartTime"><?php echo translate('AttrStartTime') ?></th>
<th data-sortable="true" data-field="EndTime"><?php echo translate('AttrEndTime') ?></th>
<th data-sortable="true" data-field="Length"><?php echo translate('Duration') ?></th>
<th data-sortable="true" data-field="Frames"><?php echo translate('Frames') ?></th>
<th data-sortable="true" data-field="AlarmFrames"><?php echo translate('AlarmBrFrames') ?></th>
<th data-sortable="true" data-field="TotScore"><?php echo translate('TotalBrScore') ?></th>
<th data-sortable="true" data-field="AvgScore"><?php echo translate('AvgBrScore') ?></th>
<th data-sortable="true" data-field="MaxScore"><?php echo translate('MaxBrScore') ?></th>
<th data-sortable="false" data-field="Storage"><?php echo translate('Storage') ?></th>
<th data-sortable="true" data-field="DiskSpace"><?php echo translate('DiskSpace') ?></th>
<th data-sortable="false" data-field="Thumbnail"><?php echo translate('Thumbnail') ?></th>
</tr>
</thead>
<tbody>
<!-- Row data populated via Ajax -->
</tbody>
</table>
</div>
</div>
<?php xhtmlFooter() ?>

View File

@ -279,17 +279,23 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as
<tbody>
<?php
foreach( ZM\Storage::find( null, array('order'=>'lower(Name)') ) as $Storage ) {
$filter = new ZM\Filter();
$filter->addTerm(array('attr'=>'StorageId','op'=>'=','val'=>$Storage->Id()));
if ( $user['MonitorIds'] ) {
$filter = $filter->addTerm(array('cnj'=>'and', 'attr'=>'MonitorId', 'op'=>'IN', 'val'=>$user['MonitorIds']));
}
$str_opt = 'class="storageCol" data-sid="'.$Storage->Id().'"';
?>
<tr>
<td class="colId"><?php echo makeLink('#', validHtmlStr($Storage->Id()), $canEdit, $str_opt ) ?></td>
<td class="colName"><?php echo makeLink('#', validHtmlStr($Storage->Name()), $canEdit, $str_opt ) ?></td>
<td class="colPath"><?php echo makeLink('#', validHtmlStr($Storage->Path()), $canEdit, $str_opt ) ?></td>
<td class="colType"><?php echo makeLink('#', validHtmlStr($Storage->Type()), $canEdit, $str_opt ) ?></td>
<td class="colScheme"><?php echo makeLink('#', validHtmlStr($Storage->Scheme()), $canEdit, $str_opt ) ?></td>
<td class="colServer"><?php echo makeLink('#', validHtmlStr($Storage->Server()->Name()), $canEdit, $str_opt ) ?></td>
<td class="colId"><?php echo makeLink('#', validHtmlStr($Storage->Id()), $canEdit, $str_opt) ?></td>
<td class="colName"><?php echo makeLink('#', validHtmlStr($Storage->Name()), $canEdit, $str_opt) ?></td>
<td class="colPath"><?php echo makeLink('#', validHtmlStr($Storage->Path()), $canEdit, $str_opt) ?></td>
<td class="colType"><?php echo makeLink('#', validHtmlStr($Storage->Type()), $canEdit, $str_opt) ?></td>
<td class="colScheme"><?php echo makeLink('#', validHtmlStr($Storage->Scheme()), $canEdit, $str_opt) ?></td>
<td class="colServer"><?php echo makeLink('#', validHtmlStr($Storage->Server()->Name()), $canEdit, $str_opt) ?></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="ColEvents"><?php echo makeLink('?view=events'.$filter->querystring(), $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>
</tr>
<?php } #end foreach Server ?>
@ -302,13 +308,12 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as
</form>
<?php
} else if ($tab == 'API') {
} else if ( $tab == 'API' ) {
$apiEnabled = dbFetchOne("SELECT Value FROM Config WHERE Name='ZM_OPT_USE_API'");
if ($apiEnabled['Value']!='1') {
echo "<div class='errorText'>APIs are disabled. To enable, please turn on OPT_USE_API in Options->System</div>";
}
else {
$apiEnabled = dbFetchOne('SELECT Value FROM Config WHERE Name=\'ZM_OPT_USE_API\'');
if ( $apiEnabled['Value'] != '1' ) {
echo '<div class="errorText">APIs are disabled. To enable, please turn on OPT_USE_API in Options->System</div>';
} else {
?>
<form name="userForm" method="post" action="?">