From 34b079fa9ef749e5b8050e1c2f233976fe753799 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Jul 2020 12:13:09 -0400 Subject: [PATCH 001/117] Start roughing in pre and post conditions --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 91b87e615..c0e05226e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -82,6 +82,13 @@ sub Execute { my $self = $_[0]; my $sql = $self->Sql(undef); + if ( @{$$self{PreConditions}} ) { + foreach my $term ( @{$$self{PreConditions}} ) { + if ( $$term{attr} eq 'DiskPercent' ) { + } + } + } + if ( $self->{HasDiskPercent} ) { my $disk_percent = getDiskPercent($$self{Storage} ? $$self{Storage}->Path() : ()); $sql =~ s/zmDiskPercent/$disk_percent/g; @@ -104,12 +111,13 @@ sub Execute { return; } my @results; - while ( my $event = $sth->fetchrow_hashref() ) { push @results, $event; } $sth->finish(); - Debug('Loaded ' . @results . " events for filter $_[0]{Name} using query ($sql)"); + Debug('Loaded ' . @results . ' events for filter '.$$self{Name}.' using query ('.$sql.')"'); + if ( $self->{HasNonSqlConditions} ) { + } return @results; } @@ -183,18 +191,23 @@ sub Sql { $self->{Sql} .= "weekday( E.EndTime )"; # + } elsif ( $term->{attr} eq 'EventExists' ) { + push @{$self->{PreConditions}}, $term; } elsif ( $term->{attr} eq 'DiskSpace' ) { $self->{Sql} .= 'E.DiskSpace'; - $self->{HasDiskPercent} = !undef; + push @{$self->{PostConditions}}, $term; } elsif ( $term->{attr} eq 'DiskPercent' ) { $self->{Sql} .= 'zmDiskPercent'; $self->{HasDiskPercent} = !undef; + $self->{HasPreCondition} = !undef; } elsif ( $term->{attr} eq 'DiskBlocks' ) { $self->{Sql} .= 'zmDiskBlocks'; $self->{HasDiskBlocks} = !undef; + $self->{HasPreCondition} = !undef; } elsif ( $term->{attr} eq 'SystemLoad' ) { $self->{Sql} .= 'zmSystemLoad'; $self->{HasSystemLoad} = !undef; + $self->{HasPreCondition} = !undef; } else { $self->{Sql} .= 'E.'.$term->{attr}; } From b8433373b53cc917af37c135b6a970b8f497d014 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 15 Aug 2020 17:49:11 -0400 Subject: [PATCH 002/117] Rough in Pre and Post SQL Conditions in execute. Rough in ExistsInFileSystem support. Needs more work. --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 22 ++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index c0e05226e..d18df337c 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -82,8 +82,8 @@ sub Execute { my $self = $_[0]; my $sql = $self->Sql(undef); - if ( @{$$self{PreConditions}} ) { - foreach my $term ( @{$$self{PreConditions}} ) { + if ( @{$$self{PreSQLConditions}} ) { + foreach my $term ( @{$$self{PreSQLConditions}} ) { if ( $$term{attr} eq 'DiskPercent' ) { } } @@ -116,10 +116,22 @@ sub Execute { } $sth->finish(); Debug('Loaded ' . @results . ' events for filter '.$$self{Name}.' using query ('.$sql.')"'); - if ( $self->{HasNonSqlConditions} ) { - } + if ( $self->{PostSQLConditions} ) { + my @filtered_events; + foreach my $term ( @{$$self{PostSQLConditions}} ) { + if ( $$term{attr} eq 'ExistsInFileSystem' ) { + foreach my $row ( @results ) { + my $event = new ZoneMinder::Event($row); + if ( -e $event->Path() ) { + push @filtered_events, $row; + } + } + } + } # end foreach term + @results = @filtered_events; + } # end if has PostSQLConditions return @results; -} +} # end sub Execute sub Sql { my $self = shift; From 8a170f2841a43f2ad6dd320b16c9b59ac3f232c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 15 Aug 2020 17:49:26 -0400 Subject: [PATCH 003/117] Remove Debug --- web/includes/Server.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/includes/Server.php b/web/includes/Server.php index d49a4e914..bf3dfeb51 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -106,7 +106,6 @@ class Server extends ZM_Object { if ( $this->Protocol() == 'https' and $port == 443 ) { } else if ( $this->Protocol() == 'http' and $port == 80 ) { } else { - Logger::Debug("Adding port $port for " . $this->Protocol()); $url .= ':'.$port; } return $url; From 82a1670d8002e0b0c185fe30b2456f3861cafacb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 15 Aug 2020 17:49:59 -0400 Subject: [PATCH 004/117] Rough in FilterTerm class, stealing code from functions.php and adapting it. --- web/includes/FilterTerm.php | 343 ++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 web/includes/FilterTerm.php diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php new file mode 100644 index 000000000..91a6aac50 --- /dev/null +++ b/web/includes/FilterTerm.php @@ -0,0 +1,343 @@ + translate('ConjAnd'), + 'or' => translate('ConjOr') + ); + } + return $validConjunctionTypes; +} + +class FilterTerm { + public $index; + public $attr; + public $op; + public $val; + public $values; + public $cnj; + public $obr; + public $cbr; + + + public function __construct($term = NULL, $index=0) { + $validConjunctionTypes = getFilterQueryConjunctionTypes(); + + $this->index = $index; + $this->attr = $term['attr']; + $this->op = $term['op']; + $this->val = $term['val']; + if ( isset($term['cnj']) ) { + if ( array_key_exists($term['cnj'], $validConjunctionTypes) ) { + $this->cnj = $term['cnj']; + } else { + Warning('Invalid cnj ' . $term['cnj'] . ' in ' . print_r($term, true)); + } + } + + if ( isset($term['obr']) ) { + if ( (string)(int)$term['obr'] == $term['obr'] ) { + $this->obr = $term['obr']; + } else { + Warning('Invalid obr ' . $term['obr'] . ' in ' . print_r($term, true)); + } + } + if ( isset($term['cbr']) ) { + if ( (string)(int)$term['cbr'] == $term['cbr'] ) { + $this->obr = $term['cbr']; + } else { + Warning('Invalid cbr ' . $term['cbr'] . ' in ' . print_r($term, true)); + } + } + } # end function __construct + + # Returns an array of values. AS term->value can be a list, we will break it apart, remove quotes etc + public function sql_values() { + $values = array(); + if ( !isset($this->val) ) { + Logger::Warning("No value in term "); + return $values; + } + + foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val)) as $value ) { + + switch ( $this->attr ) { + + case 'AlarmedZoneId': + $value = '(SELECT * FROM Stats WHERE EventId=E.Id AND ZoneId='.$value.')'; + break; + case 'ExistsInFileSystem': + break; + case 'MonitorName': + case 'Name': + case 'Cause': + case 'Notes': + if ( $this->op == 'LIKE' || $this->op == 'NOT LIKE' ) { + $value = '%'.$value.'%'; + } + $value = dbEscape($value); + break; + case 'MonitorServerId': + case 'FilterServerId': + case 'StorageServerId': + case 'ServerId': + if ( $value == 'ZM_SERVER_ID' ) { + $value = ZM_SERVER_ID; + } else if ( $value == 'NULL' ) { + + } else { + $value = dbEscape($value); + } + break; + case 'StorageId': + if ( $value != 'NULL' ) { + $value = dbEscape($value); + } + break; + case 'DateTime': + case 'StartDateTime': + case 'EndDateTime': + if ( $value != 'NULL' ) + $value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\''; + break; + case 'Date': + case 'StartDate': + case 'EndDate': + if ( $value == 'CURDATE()' or $value == 'NOW()' ) { + $value = 'to_days('.$value.')'; + } else if ( $value != 'NULL' ) { + $value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; + } + break; + case 'Time': + case 'StartTime': + case 'EndTime': + if ( $value != 'NULL' ) + $value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; + break; + default : + if ( $value == 'Odd' ) { + $value = 1; + } else if ( $value == 'Even' ) { + $value = 0; + } else if ( $value != 'NULL' ) + $value = dbEscape($value); + break; + } + $values[] = $value; + } // end foreach value + return $values; + } # end function sql_values + + public function sql_operator() { + if ( $this->attr == 'AlarmZoneId' ) { + return ' EXISTS '; + } + + switch ( $this->op ) { + case '=' : + case '!=' : + case '>=' : + case '>' : + case '<' : + case '<=' : + case 'LIKE' : + case 'NOT LIKE': + return ' '.$this->op.' '; + case '=~' : + return ' regexp '; + case '!~' : + return ' not regexp '; + case '=[]' : + case 'IN' : + return ' IN '; + case '![]' : + return ' NOT IN '; + case 'EXISTS' : + return ' EXISTS '; + case 'IS' : + # Odd will be replaced with 1 + # Even will be replaced with 0 + if ( $this->value == 'Odd' or $this->value == 'Even' ) { + return ' % 2 = '; + } else { + return ' IS '; + } + case 'IS NOT' : + if ( $this->value == 'Odd' or $this->value == 'Even' ) { + return ' % 2 = '; + } + return ' IS NOT '; + default: + ZM\Warning('Invalid operator in filter: ' . print_r($this->op, true)); + } // end switch op + } # end public function sql_operator + + /* Some terms don't have related SQL */ + public function sql() { + if ( $this->attr == 'ExistsInFileSystem' ) { + return ''; + } + + $sql = ''; + if ( isset($this->cnj) ) { + $sql .= ' '.$this->cnj.' '; + } + if ( isset($this->obr) ) { + $sql .= ' '.str_repeat('(', $this->obr).' '; + } + + switch ( $this->attr ) { + case 'MonitorName': + $sql .= 'M.Name'; + break; + case 'ServerId': + case 'MonitorServerId': + $sql .= 'M.ServerId'; + break; + case 'StorageServerId': + $sql .= 'S.ServerId'; + break; + case 'FilterServerId': + $sql .= ZM_SERVER_ID; + break; + # Unspecified start or end, so assume start, this is to support legacy filters + case 'DateTime': + $sql .= 'E.StartTime'; + break; + case 'Date': + $sql .= 'to_days(E.StartTime)'; + break; + case 'Time': + $sql .= 'extract(hour_second FROM E.StartTime)'; + break; + case 'Weekday': + $sql .= 'weekday(E.StartTime)'; + break; + # Starting Time + case 'StartDateTime': + $sql .= 'E.StartTime'; + break; + case 'FramesEventId': + $sql .= 'F.EventId'; + break; + case 'StartDate': + $sql .= 'to_days(E.StartTime)'; + break; + case 'StartTime': + $sql .= 'extract(hour_second FROM E.StartTime)'; + break; + case 'StartWeekday': + $sql .= 'weekday(E.StartTime)'; + break; + # Ending Time + case 'EndDateTime': + $sql .= 'E.EndTime'; + break; + case 'EndDate': + $sql .= 'to_days(E.EndTime)'; + break; + case 'EndTime': + $sql .= 'extract(hour_second FROM E.EndTime)'; + break; + case 'EndWeekday': + $sql .= 'weekday(E.EndTime)'; + break; + case 'Id': + case 'Name': + case 'DiskSpace': + case 'MonitorId': + case 'StorageId': + case 'SecondaryStorageId': + case 'Length': + case 'Frames': + case 'AlarmFrames': + case 'TotScore': + case 'AvgScore': + case 'MaxScore': + case 'Cause': + case 'Notes': + case 'StateId': + case 'Archived': + $sql .= 'E.'.$this->attr; + } + $sql .= $this->sql_operator(); + $values = $this->sql_values(); + if ( count($values) > 1 ) { + $sql .= '('.join(',', $values).')'; + } else { + $sql .= $values[0]; + } + + if ( isset($this->cbr) ) { + $sql .= ' '.str_repeat(')', $this->cbr).' '; + } + return $sql; + } # end public function sql + + public function querystring($querySep='&') { + # We don't validate the term parameters here + $query = ''; + if ( $this->cnj ) + $query .= $querySep.urlencode('filter[Query][terms]['.$this->index.'][cnj]').'='.$this->cnj; + if ( $this->obr ) + $query .= $querySep.urlencode('filter[Query][terms]['.$this->index.'][obr]').'='.$this->obr; + + $query .= $querySep.urlencode('filter[Query][terms]['.$this->index.'][attr]').'='.urlencode($this->attr); + $query .= $querySep.urlencode('filter[Query][terms]['.$this->index.'][op]').'='.urlencode($this->op); + $query .= $querySep.urlencode('filter[Query][terms]['.$this->index.'][val]').'='.urlencode($this->val); + if ( $this->cbr ) + $query .= $querySep.urlencode('filter[Query][terms]['.$this->index.'][cbr]').'='.$this->cbr; + return $query; + } # end public function querystring + + public function hidden_fields_string() { + $html =''; + if ( $this->cnj ) + $html .= ''.PHP_EOL; + + if ( $this->obr ) + $html .= ''.PHP_EOL; + + # attr should have been already validation, so shouldn't need htmlspecialchars + $html .= ''.PHP_EOL; + $html .= ''.PHP_EOL; + $html .= ''.PHP_EOL; + if ( $this->cbr ) + $html .= ''.PHP_EOL; + + return $html; + } # end public function hidden_field_string + + public function test($event) { + Logger::Debug("Testing PostSQLcondtion"); + if ( $this->attr == 'ExistsInFileSystem' ) { + Logger::Debug("file exists?! " . file_exists($event->Path()) ); + if ( + ($this->op == 'IS' and $this->val == 'True') + or + ($this->op == 'IS NOT' and $this->val == 'False') + ) { + return file_exists($event->Path()); + } else { + return !file_exists($event->Path()); + } + } + Error("testing not supported term"); + return false; + } + + public function is_post_sql() { + if ( $this->attr == 'ExistsInFileSystem' ) { + return true; + } + return false; + } + +} # end class FilterTerm + +?> From d1126b300708b6e317bac8ed139c7a3f88b2e6f1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 16 Aug 2020 13:02:34 -0400 Subject: [PATCH 005/117] Move term logic from parseFilter to FilterTerm class --- web/includes/functions.php | 262 +++++-------------------------------- 1 file changed, 33 insertions(+), 229 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index e50fd23c2..c72c10cbc 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -17,6 +17,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // +// +require_once('FilterTerm.php'); // Compatibility functions if ( version_compare(phpversion(), '4.3.0', '<') ) { @@ -1087,119 +1089,40 @@ function parseSort($saveToSession=false, $querySep='&') { } } -function getFilterQueryConjunctionTypes() { - return array( - 'and' => translate('ConjAnd'), - 'or' => translate('ConjOr') - ); -} - +# Historically this function has just modified the passed in filter array. +# This would normally be $_REQUEST['filter']; We don't like modifying +# request parameters. For now we will keep this behaviour, but note that we +# now return the resulting array and other code should by modified to use that. +# +# Please note that I will be removing the savetosession code as well. function parseFilter(&$filter, $saveToSession=false, $querySep='&') { $filter['query'] = ''; $filter['sql'] = ''; $filter['fields'] = ''; + $filter['PostSQLConditions'] = array(); - $validQueryConjunctionTypes = getFilterQueryConjunctionTypes(); $StorageArea = NULL; # It is not possible to pass an empty array in the url, so we have to deal with there not being a terms field. $terms = (isset($filter['Query']) and isset($filter['Query']['terms']) and is_array($filter['Query']['terms'])) ? $filter['Query']['terms'] : array(); - if ( count($terms) ) { - for ( $i = 0; $i < count($terms); $i++ ) { + if ( !count($terms) ) { + ZM\Logger::Warning('No terms'); + $filter['query'] = $querySep; + return; + } + for ( $i = 0; $i < count($terms); $i++ ) { + $term = new ZM\FilterTerm($terms[$i], $i); + if ( $term->is_post_sql() ) { + $filter['PostSQLConditions'][] = $term; + continue; + } - $term = $terms[$i]; + $filter['query'] .= $term->querystring($querySep); + $filter['sql'] .= $term->sql(); + $filter['fields'] .= $term->hidden_fields_string(); - if ( isset($term['cnj']) && array_key_exists($term['cnj'], $validQueryConjunctionTypes) ) { - $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cnj]").'='.urlencode($term['cnj']); - $filter['sql'] .= ' '.$term['cnj'].' '; - $filter['fields'] .= "\n"; - } - if ( isset($term['obr']) && (string)(int)$term['obr'] == $term['obr'] ) { - $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][obr]").'='.urlencode($term['obr']); - $filter['sql'] .= ' '.str_repeat('(', $term['obr']).' '; - $filter['fields'] .= "\n"; - } - if ( isset($term['attr']) ) { - $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][attr]").'='.urlencode($term['attr']); - $filter['fields'] .= "\n"; - switch ( $term['attr'] ) { - case 'AlarmedZoneId': - $term['op'] = 'EXISTS'; - break; - case 'MonitorName': - $filter['sql'] .= 'M.Name'; - break; - case 'ServerId': - case 'MonitorServerId': - $filter['sql'] .= 'M.ServerId'; - break; - case 'StorageServerId': - $filter['sql'] .= 'S.ServerId'; - break; - case 'FilterServerId': - $filter['sql'] .= ZM_SERVER_ID; - break; -# Unspecified start or end, so assume start, this is to support legacy filters - case 'DateTime': - $filter['sql'] .= 'E.StartTime'; - break; - case 'Date': - $filter['sql'] .= 'to_days(E.StartTime)'; - break; - case 'Time': - $filter['sql'] .= 'extract(hour_second FROM E.StartTime)'; - break; - case 'Weekday': - $filter['sql'] .= 'weekday(E.StartTime)'; - break; -# Starting Time - case 'StartDateTime': - $filter['sql'] .= 'E.StartTime'; - break; - case 'FramesEventId': - $filter['sql'] .= 'F.EventId'; - break; - case 'StartDate': - $filter['sql'] .= 'to_days(E.StartTime)'; - break; - case 'StartTime': - $filter['sql'] .= 'extract(hour_second FROM E.StartTime)'; - break; - case 'StartWeekday': - $filter['sql'] .= 'weekday(E.StartTime)'; - break; -# Ending Time - case 'EndDateTime': - $filter['sql'] .= 'E.EndTime'; - break; - case 'EndDate': - $filter['sql'] .= 'to_days(E.EndTime)'; - break; - case 'EndTime': - $filter['sql'] .= 'extract(hour_second FROM E.EndTime)'; - break; - case 'EndWeekday': - $filter['sql'] .= 'weekday(E.EndTime)'; - break; - case 'Id': - case 'Name': - case 'DiskSpace': - case 'MonitorId': - case 'StorageId': - case 'SecondaryStorageId': - case 'Length': - case 'Frames': - case 'AlarmFrames': - case 'TotScore': - case 'AvgScore': - case 'MaxScore': - case 'Cause': - case 'Notes': - case 'StateId': - case 'Archived': - $filter['sql'] .= 'E.'.$term['attr']; - break; + /* case 'DiskPercent': // Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH if ( ! $StorageArea ) { @@ -1240,135 +1163,15 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { case 'SystemLoad': $filter['sql'] .= getLoad(); break; - } - $valueList = array(); - if ( !isset($term['val']) ) $term['val'] = ''; - foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) { - switch ( $term['attr'] ) { + } # end switch attr + */ + } // end foreach term - case 'AlarmedZoneId': - $value = '(SELECT * FROM Stats WHERE EventId=E.Id AND ZoneId='.$value.')'; - break; - case 'MonitorName': - case 'Name': - case 'Cause': - case 'Notes': - if ( $term['op'] == 'LIKE' || $term['op'] == 'NOT LIKE' ) { - $value = '%'.$value.'%'; - } - $value = dbEscape($value); - break; - case 'MonitorServerId': - case 'FilterServerId': - case 'StorageServerId': - case 'ServerId': - if ( $value == 'ZM_SERVER_ID' ) { - $value = ZM_SERVER_ID; - } else if ( $value == 'NULL' ) { - - } else { - $value = dbEscape($value); - } - break; - case 'StorageId': - $StorageArea = ZM\Storage::find_one(array('Id'=>$value)); - if ( $value != 'NULL' ) - $value = dbEscape($value); - break; - case 'DateTime': - case 'StartDateTime': - case 'EndDateTime': - if ( $value != 'NULL' ) - $value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\''; - break; - case 'Date': - case 'StartDate': - case 'EndDate': - if ( $value == 'CURDATE()' or $value == 'NOW()' ) { - $value = 'to_days('.$value.')'; - } else if ( $value != 'NULL' ) { - $value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; - } - break; - case 'Time': - case 'StartTime': - case 'EndTime': - if ( $value != 'NULL' ) - $value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; - break; - default : - if ( $value != 'NULL' ) - $value = dbEscape($value); - break; - } - $valueList[] = $value; - } // end foreach value - - switch ( $term['op'] ) { - case '=' : - case '!=' : - case '>=' : - case '>' : - case '<' : - case '<=' : - case 'LIKE' : - case 'NOT LIKE': - $filter['sql'] .= ' '.$term['op'].' '. $value; - break; - case '=~' : - $filter['sql'] .= ' regexp '.$value; - break; - case '!~' : - $filter['sql'] .= ' not regexp '.$value; - break; - case '=[]' : - case 'IN' : - $filter['sql'] .= ' IN ('.join(',', $valueList).')'; - break; - case '![]' : - $filter['sql'] .= ' not in ('.join(',', $valueList).')'; - break; - case 'EXISTS' : - $filter['sql'] .= ' EXISTS ' .$value; - break; - case 'IS' : - if ( $value == 'Odd' ) { - $filter['sql'] .= ' % 2 = 1'; - } else if ( $value == 'Even' ) { - $filter['sql'] .= ' % 2 = 0'; - } else { - $filter['sql'] .= " IS $value"; - } - break; - case 'IS NOT' : - $filter['sql'] .= " IS NOT $value"; - break; - default: - ZM\Warning('Invalid operator in filter: ' . print_r($term['op'], true)); - } // end switch op - - $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($term['op']); - $filter['fields'] .= "\n"; - if ( isset($term['val']) ) { - $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][val]").'='.urlencode($term['val']); - $filter['fields'] .= "\n"; - } - } // end if isset($term['attr']) - if ( isset($term['cbr']) && (string)(int)$term['cbr'] == $term['cbr'] ) { - $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cbr]").'='.urlencode($term['cbr']); - $filter['sql'] .= ' '.str_repeat(')', $term['cbr']); - $filter['fields'] .= "\n"; - } - } // end foreach term - if ( $filter['sql'] ) - $filter['sql'] = ' AND ( '.$filter['sql'].' )'; - if ( $saveToSession ) { - $_SESSION['filter'] = $filter; - } - } else { - $filter['query'] = $querySep; - #.urlencode('filter[Query][terms]=[]'); - } // end if terms + if ( $filter['sql'] ) + $filter['sql'] = ' AND ( '.$filter['sql'].' )'; + if ( $saveToSession ) { + $_SESSION['filter'] = $filter; + } #if ( 0 ) { #// ICON I feel like these should be here, but not yet @@ -1380,6 +1183,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { #$filter['sql'] .= ' LIMIT ' . validInt($filter['Query']['limit']); #} #} + return $filter; } // end function parseFilter(&$filter, $saveToSession=false, $querySep='&') // Please note that the filter is passed in by copy, so you need to use the return value from this function. From 344f586f194b86f5cd1569fcdda38328e7f2c8e8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 16 Aug 2020 13:03:18 -0400 Subject: [PATCH 006/117] Add language entry for ExistsInFileSystem --- web/lang/en_gb.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index b3de1729d..fb730d86a 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -343,6 +343,7 @@ $SLANG = array( 'Export' => 'Export', 'DownloadVideo' => 'Download Video', 'GenerateDownload' => 'Generate Download', + 'ExistsInFileSystem' => 'Exists In File System', 'ExportFailed' => 'Export Failed', 'ExportFormat' => 'Export File Format', 'ExportFormatTar' => 'Tar', From d3cc4d589f3c0d5c1bae6efa345b861993bf5c58 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 16 Aug 2020 13:04:42 -0400 Subject: [PATCH 007/117] Remove the parseFilter etc calls from getNavBarHTML code which was used to populate the filter link with the currently viewed events list. I think we can do this better with saving it to the sesssion or similar. --- web/skins/classic/includes/functions.php | 27 +++++++----------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 7c101cabc..8e0bef643 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -223,24 +223,13 @@ function getNavBarHTML() { global $user; global $bandwidth_options; global $view; - global $filterQuery; - global $sortQuery; - global $limitQuery; - - if ( !$sortQuery ) { - parseSort(); - } - if ( (!$filterQuery) and isset($_REQUEST['filter']) ) { - parseFilter($_REQUEST['filter']); - $filterQuery = $_REQUEST['filter']['query']; - } ob_start(); if ( ZM_WEB_NAVBAR_TYPE == "normal" ) { - echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery); + echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view); } else { - echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery); + echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view); } return ob_get_clean(); @@ -249,7 +238,7 @@ function getNavBarHTML() { // // The legacy navigation bar that collapses into a pulldown menu on small screens. // -function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) { +function getNormalNavBarHTML($running, $user, $bandwidth_options, $view) { $status = runtimeStatus($running); @@ -280,7 +269,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filter echo getLogHTML(); echo getDevicesHTML(); echo getGroupsHTML($view); - echo getFilterHTML($view, $filterQuery, $sortQuery, $limitQuery); + echo getFilterHTML($view); echo getCycleHTML($view); echo getMontageHTML($view); echo getMontageReviewHTML($view); @@ -340,7 +329,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filter // // A new, slimmer navigation bar, permanently collapsed into a dropdown // -function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) { +function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view) { $status = runtimeStatus($running); @@ -409,7 +398,7 @@ function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $fil echo getLogHTML(); echo getDevicesHTML(); echo getGroupsHTML($view); - echo getFilterHTML($view,$filterQuery,$sortQuery,$limitQuery); + echo getFilterHTML($view); echo getCycleHTML($view); echo getMontageHTML($view); echo getMontageReviewHTML($view); @@ -698,11 +687,11 @@ function getGroupsHTML($view) { } // Returns the html representing the Filter menu item -function getFilterHTML($view, $filterQuery, $sortQuery, $limitQuery) { +function getFilterHTML($view) { $result = ''; $class = $view == 'filter' ? ' selected' : ''; - $result .= ''.PHP_EOL; + $result .= ''.PHP_EOL; return $result; } From 303154c69049d6d3937998fdee2d1cc6ce6ab437 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 16 Aug 2020 13:06:37 -0400 Subject: [PATCH 008/117] Remove countSQL code that ran the sql query once to get the # of entries returned to be used in pagination. Now that we support POSTSQL Conditions it is no longer useful. Pagination has to happen later. Implement POSTSQLConditions in filtering results. --- web/skins/classic/views/events.php | 44 ++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 9b6f4cb07..98613009e 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -25,31 +25,32 @@ if ( !canView('Events') || (!empty($_REQUEST['execute']) && !canEdit('Events')) require_once('includes/Event.php'); -$countSql = 'SELECT count(E.Id) AS EventCount FROM Monitors AS M INNER JOIN Events AS E ON (M.Id = E.MonitorId) WHERE'; $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'].')'; - $countSql .= $user_monitor_ids; $eventsSql .= $user_monitor_ids; } else { - $countSql .= ' 1'; $eventsSql .= ' 1'; } parseSort(); -parseFilter($_REQUEST['filter']); -$filterQuery = $_REQUEST['filter']['query']; -if ( $_REQUEST['filter']['sql'] ) { - $countSql .= $_REQUEST['filter']['sql']; - $eventsSql .= $_REQUEST['filter']['sql']; +$filter = parseFilter($_REQUEST['filter']); +$filterQuery = $filter['query']; +ZM\Logger::Debug("Filter ".print_r($filter, true)); + +if ( $filter['sql'] ) { + $eventsSql .= $filter['sql']; } -$eventsSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder"; +$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']) : 0; +$limit = 9; -$nEvents = dbFetchOne($countSql, 'EventCount'); +$results = dbQuery($eventsSql); +$nEvents = $results->rowCount(); if ( !empty($limit) && $nEvents > $limit ) { $nEvents = $limit; } @@ -62,14 +63,14 @@ if ( !empty($page) ) { $page = $pages; $limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE); - if ( empty( $limit ) ) { + 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"; -} elseif ( !empty($limit) ) { +} else if ( !empty($limit) ) { $eventsSql .= ' LIMIT 0, '.$limit; } @@ -134,7 +135,7 @@ if ( $pages > 1 ) { - + @@ -145,9 +146,24 @@ if ( $pages > 1 ) { $count = 0; $disk_space_total = 0; -$results = dbQuery($eventsSql); while ( $event_row = dbFetchNext($results) ) { $event = new ZM\Event($event_row); + + if ( count($filter['PostSQLConditions']) ) { + ZM\Logger::Debug("Has post conditions" . count($filter['PostSQLConditions'])); + $failed = false; + foreach ( $filter['PostSQLConditions'] as $term ) { + if ( !$term->test($event) ) { +ZM\Logger::Debug("failed"); + $failed = true; + break; + } + } + if ( $failed ) continue; + } else { + ZM\Logger::Debug("Has no post conditions"); + } # end if PostSQLConditions + if ( $event_row['Archived'] ) $archived = true; else From 77f9f4bffb03956871dbe9f7a0da66312cf763bf Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 16 Aug 2020 13:07:21 -0400 Subject: [PATCH 009/117] Add ExistsInFileSystem support in Filters. This also includes limiting operators to IS/IS NOT --- web/skins/classic/views/filter.php | 26 ++++++++++++--- web/skins/classic/views/js/filter.js | 49 ++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index f7fd5444d..5d18364f5 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -25,6 +25,7 @@ if ( !canView('Events') ) { require_once('includes/Object.php'); require_once('includes/Storage.php'); require_once('includes/Filter.php'); +require_once('includes/FilterTerm.php'); require_once('includes/Monitor.php'); require_once('includes/Zone.php'); require_once('includes/User.php'); @@ -53,7 +54,7 @@ if ( isset($_REQUEST['filter']) ) { #$filter->set($_REQUEST['filter']); } -$conjunctionTypes = getFilterQueryConjunctionTypes(); +$conjunctionTypes = ZM\getFilterQueryConjunctionTypes(); $obracketTypes = array(); $cbracketTypes = array(); @@ -83,6 +84,7 @@ $attrTypes = array( 'EndDate' => translate('AttrEndDate'), 'EndTime' => translate('AttrEndTime'), 'EndWeekday' => translate('AttrEndWeekday'), + 'ExistsInFileSystem' => translate('ExistsInFileSystem'), 'FilterServerId' => translate('AttrFilterServer'), 'Frames' => translate('AttrFrames'), 'Id' => translate('AttrId'), @@ -122,11 +124,20 @@ $opTypes = array( 'LIKE' => translate('OpLike'), 'NOT LIKE' => translate('OpNotLike'), ); +$is_isnot_opTypes = array( + 'IS' => translate('OpIs'), + 'IS NOT' => translate('OpIsNot'), +); $archiveTypes = array( - '0' => translate('ArchUnarchived'), - '1' => translate('ArchArchived') - ); + '0' => translate('ArchUnarchived'), + '1' => translate('ArchArchived') +); + +$booleanValues = array( + 'false' => translate('False'), + 'true' => translate('True') +); $focusWindow = true; @@ -275,6 +286,11 @@ for ( $i=0; $i < count($terms); $i++ ) { + + + @@ -459,7 +475,7 @@ if ( ZM_OPT_MESSAGE ) {
- + diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index bcf67c00b..b09e2233b 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -2,12 +2,12 @@ function selectFilter(element) { element.form.submit(); } -function validateForm( form ) { +function validateForm(form) { var rows = $j(form).find('tbody').eq(0).find('tr'); var obrCount = 0; var cbrCount = 0; for ( var i = 0; i < rows.length; i++ ) { - if (rows.length > 2) { + if ( rows.length > 2 ) { obrCount += parseInt(form.elements['filter[Query][terms][' + i + '][obr]'].value); cbrCount += parseInt(form.elements['filter[Query][terms][' + i + '][cbr]'].value); } @@ -108,10 +108,14 @@ function resetFilter( element ) { $j('#contentForm')[0].reset(); } -function submitToEvents( element ) { +function submitToEvents(element) { var form = element.form; - form.action = thisUrl + '?view=events'; - history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); + //form.action = '?view=events'; + //form.submit(); + //console.log(form); + //console.log($j(form).serialize()); + //history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); + window.location.assign('?view=events&'+$j(form).serialize()); } function submitToMontageReview(element) { @@ -254,6 +258,15 @@ function parseRows(rows) { } var monitorVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(monitorSelect).children().val(monitorVal); + } else if ( attr == 'ExistsInFileSystem' ) { + var select = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); + for ( var booleanVal in booleanValues ) { + select.append(''); + } + var val = inputTds.eq(4).children().val(); + if ( ! val ) val = 'false'; // default to the first option false + inputTds.eq(4).html(select).children().val(val); + } else { // Reset to regular text field and operator for everything that isn't special var textInput = $j('').attr('type', 'text').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); var textVal = inputTds.eq(4).children().val(); @@ -263,13 +276,23 @@ function parseRows(rows) { // Validate the operator var opSelect = $j('').attr('name', queryPrefix + rowNum + '][op]').attr('id', queryPrefix + rowNum + '][op]'); var opVal = inputTds.eq(3).children().val(); - if ( ! opVal ) { - // Default to equals so that something gets selected - console.log("No value for operator. Defaulting to ="); - opVal = '='; - } - for ( var key in opTypes ) { - opSelect.append(''); + if ( attr == 'ExistsInFileSystem' ) { + if ( ! opVal ) { + // Default to equals so that something gets selected + opVal = 'IS'; + } + for ( var key of ['IS', 'IS NOT'] ) { + opSelect.append(''); + } + } else { + if ( ! opVal ) { + // Default to equals so that something gets selected + console.log("No value for operator. Defaulting to ="); + opVal = '='; + } + for ( var key in opTypes ) { + opSelect.append(''); + } } inputTds.eq(3).html(opSelect).children().val(opVal).chosen({width: "101%"}); if ( attr.endsWith('DateTime') ) { //Start/End DateTime @@ -289,7 +312,7 @@ function parseRows(rows) { inputTds.eq(2).children().eq(0).attr('id', 'filter'+stringFilter(term)); } //End for each term/row history.replaceState(null, null, '?view=filter&' + $j('#contentForm').serialize()); -} +} // parseRows function stringFilter(term) { var termString = ''; From 77c391fcae9b84395ac3d26fb69672f9d005421b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 16 Aug 2020 13:07:42 -0400 Subject: [PATCH 010/117] Add booleanvalues for operators support --- web/skins/classic/views/js/filter.js.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/skins/classic/views/js/filter.js.php b/web/skins/classic/views/js/filter.js.php index 108dbddce..e01daf0da 100644 --- a/web/skins/classic/views/js/filter.js.php +++ b/web/skins/classic/views/js/filter.js.php @@ -10,6 +10,7 @@ global $storageareas; global $monitors; global $zones; + global $booleanValues; ?> var filterQuery = ''; var sortQuery = ''; @@ -24,6 +25,7 @@ var servers = ; var storageareas = ; var monitors = ; var zones = ; +var booleanValues = ; var errorBrackets = ''; var errorValue = ''; From ae91e9c58f2ed50e6a4ed819abbb37b04ed0c54e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 16:55:05 -0400 Subject: [PATCH 011/117] add functions to Filter class to build up the sql, hidden_fields and query_string from the list of terms --- web/includes/Filter.php | 96 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index ce9d11cd4..793f34cd8 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -30,9 +30,101 @@ class Filter extends ZM_Object { 'Query_json' => '', ); + protected $_querystring; + protected $_sql; + protected $_hidden_fields; + public $_pre_sql_conditions; + public $_post_sql_conditions; + protected $_Terms; + + public function sql() { + if ( ! isset($this->_sql) ) { + foreach ( $this->FilterTerms() as $term ) { + if ( ! ($term->is_pre_sql() or $term->is_post_sql()) ) + $this->_sql .= $term->sql(); + } # end foreach term + } + return $this->_sql; + } + + public function querystring() { + if ( ! isset($this->_querystring) ) { + foreach ( $this->FilterTerms() as $term ) { + $this->_querystring .= $term->querystring(); + } # end foreach term + } + return $this->_querystring; + } + + public function hidden_fields() { + if ( ! isset($this->_hidden_fields) ) { + foreach ( $this->FilterTerms() as $term ) { + $this->_hidden_fields .= $term->hidden_fields(); + } # end foreach term + } + return $this->_hidden_fields; + } + + public function pre_sql_conditions() { + if ( ! isset($this->_pre_sql_conditions) ) { + $this->_pre_sql_conditions = array(); + foreach ( $this->FilterTerms() as $term ) { + if ( $term->is_pre_sql() ) + $this->_pre_sql_conditions[] = $term; + } # end foreach term + } + return $this->_pre_sql_conditions; + } + + public function post_sql_conditions() { + + if ( ! isset($this->_post_sql_conditions) ) { + $this->_post_sql_conditions = array(); + foreach ( $this->FilterTerms() as $term ) { + if ( $term->is_post_sql() ) + $this->_post_sql_conditions[] = $term; + } # end foreach term + } + return $this->_post_sql_conditions; + } + + public function FilterTerms() { + if ( ! isset($this->Terms) ) { + $this->Terms = array(); + $_terms = $this->terms(); + for ( $i = 0; $i < count($_terms); $i++ ) { + $term = new FilterTerm($this, $_terms[$i], $i); + $this->Terms[] = $term; + } # end foreach term + } + return $this->Terms; + } + + public static function parse($new_filter, $querySep='&') { + $filter = new Filter(); + $filter->Query($new_filter['Query']); + return $filter; + } + + # If no storage areas are specified in the terms, then return all + public function get_StorageAreas() { + $storage_ids = array(); + foreach ( $this->Terms as $term ) { + if ( $term->attr == 'StorageId' ) { + # TODO handle other operators like != + $storage_ids[] = $term->value; + } + } + if ( count($storage_ids) ) { + return Storage::find(array('Id'=>$storage_ids)); + } else { + return Storage::find(); + } + } # end function get_StorageAreas + public function Query_json() { if ( func_num_args( ) ) { - $this->{'Query_json'} = func_get_arg(0);; + $this->{'Query_json'} = func_get_arg(0); $this->{'Query'} = jsonDecode($this->{'Query_json'}); } return $this->{'Query_json'}; @@ -40,7 +132,7 @@ class Filter extends ZM_Object { public function Query() { if ( func_num_args( ) ) { - $this->{'Query'} = func_get_arg(0);; + $this->{'Query'} = func_get_arg(0); $this->{'Query_json'} = jsonEncode($this->{'Query'}); } if ( !property_exists($this, 'Query') ) { From d2b7aa3e90da249929e7735df3eb23da632a26e3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 16:55:29 -0400 Subject: [PATCH 012/117] Populate Scheme of default Storage Area when event Storage is not valid --- web/includes/Event.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 2f9fa4d20..a9eb99d59 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -58,8 +58,10 @@ class Event extends ZM_Object { if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) { if ( isset($this->{'StorageId'}) and $this->{'StorageId'} ) $this->{'Storage'} = Storage::find_one(array('Id'=>$this->{'StorageId'})); - if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) + if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) { $this->{'Storage'} = new Storage(NULL); + $this->{'Storage'}->Scheme($this->{'Scheme'}); + } } return $this->{'Storage'}; } From e9b0c4fbf5ca84308e876dd06c68493b3bcbe257 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 16:56:54 -0400 Subject: [PATCH 013/117] add ->filter to FilterTerm so that we can access other terms in testing pre and post conditions. rename hidden_fields_string to hidden_fields. Add in DiskPercent DiskBlocks, SystemLoad Pre and Post conditions --- web/includes/FilterTerm.php | 95 +++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php index 73f5da94c..63eac2890 100644 --- a/web/includes/FilterTerm.php +++ b/web/includes/FilterTerm.php @@ -14,6 +14,7 @@ function getFilterQueryConjunctionTypes() { } class FilterTerm { + public $filter; public $index; public $attr; public $op; @@ -24,7 +25,8 @@ class FilterTerm { public $cbr; - public function __construct($term = NULL, $index=0) { + public function __construct($filter = null, $term = NULL, $index=0) { + $this->filter = $filter; $validConjunctionTypes = getFilterQueryConjunctionTypes(); $this->index = $index; @@ -35,7 +37,7 @@ class FilterTerm { if ( array_key_exists($term['cnj'], $validConjunctionTypes) ) { $this->cnj = $term['cnj']; } else { - Warning('Invalid cnj ' . $term['cnj'] . ' in ' . print_r($term, true)); + Warning('Invalid cnj ' . $term['cnj'].' in '.print_r($term, true)); } } @@ -295,7 +297,7 @@ class FilterTerm { return $query; } # end public function querystring - public function hidden_fields_string() { + public function hidden_fields() { $html =''; if ( $this->cnj ) $html .= ''.PHP_EOL; @@ -311,27 +313,92 @@ class FilterTerm { $html .= ''.PHP_EOL; return $html; - } # end public function hidden_field_string + } # end public function hiddens_fields - public function test($event) { - if ( $this->attr == 'ExistsInFileSystem' ) { - if ( - ($this->op == 'IS' and $this->val == 'True') - or - ($this->op == 'IS NOT' and $this->val == 'False') - ) { - return file_exists($event->Path()); + public function test($event=null) { + if ( !isset($event) ) { + # Is a Pre Condition + if ( $this->attr == 'DiskPercent' ) { + # The logic on this is really ugly. We are going to treat it as an OR + foreach ( $this->filter->get_StorageAreas() as $storage ) { + $string_to_eval = 'return $storage->disk_usage_percent() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Logger::Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } # end foreach Storage Area + } else if ( $this->attr == 'SystemLoad' ) { + $string_to_eval = 'return getLoad() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Logger::Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } } else { - return !file_exists($event->Path()); + Error('testing unsupported pre term ' . $this->attr); + } + } else { + # Is a Post Condition + if ( $this->attr == 'ExistsInFileSystem' ) { + if ( + ($this->op == 'IS' and $this->val == 'True') + or + ($this->op == 'IS NOT' and $this->val == 'False') + ) { + return file_exists($event->Path()); + } else { + return !file_exists($event->Path()); + } + } else if ( $this->attr == 'DiskPercent' ) { + $string_to_eval = 'return $event->Storage()->disk_usage_percent() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Logger::Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } else if ( $this->attr == 'DiskBlocks' ) { + $string_to_eval = 'return $event->Storage()->disk_usage_blocks() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Logger::Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } else { + Error('testing unsupported post term ' . $this->attr); } } - Error("testing not supported term"); return false; } + public function is_pre_sql() { + if ( $this->attr == 'DiskPercent' ) { + return true; + } + return false; + } + public function is_post_sql() { if ( $this->attr == 'ExistsInFileSystem' ) { return true; + } else if ( $this->attr == 'DiskPercent' ) { + return true; } return false; } From 72cad5f6d6f079d6b70a8f34306ffcf8bd40da6c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 16:57:14 -0400 Subject: [PATCH 014/117] Move more code from parseFilter to Filter object. --- web/includes/functions.php | 86 ++++---------------------------------- 1 file changed, 9 insertions(+), 77 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index c72c10cbc..4a5a4b848 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -18,6 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // +require_once('Filter.php'); require_once('FilterTerm.php'); // Compatibility functions @@ -1096,82 +1097,17 @@ function parseSort($saveToSession=false, $querySep='&') { # # Please note that I will be removing the savetosession code as well. function parseFilter(&$filter, $saveToSession=false, $querySep='&') { - $filter['query'] = ''; - $filter['sql'] = ''; - $filter['fields'] = ''; - $filter['PostSQLConditions'] = array(); - $StorageArea = NULL; + $Filter = ZM\Filter::parse($filter, $querySep); - # It is not possible to pass an empty array in the url, so we have to deal with there not being a terms field. - $terms = (isset($filter['Query']) and isset($filter['Query']['terms']) and is_array($filter['Query']['terms'])) ? $filter['Query']['terms'] : array(); - - if ( !count($terms) ) { - ZM\Logger::Warning('No terms'); - $filter['query'] = $querySep; - return; - } - for ( $i = 0; $i < count($terms); $i++ ) { - $term = new ZM\FilterTerm($terms[$i], $i); - if ( $term->is_post_sql() ) { - $filter['PostSQLConditions'][] = $term; - continue; - } - - $filter['query'] .= $term->querystring($querySep); - $filter['sql'] .= $term->sql(); - $filter['fields'] .= $term->hidden_fields_string(); - - /* - case 'DiskPercent': - // Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH - if ( ! $StorageArea ) { - for ( $j = 0; $j < count($terms); $j++ ) { - if ( - isset($terms[$j]['attr']) - and - ($terms[$j]['attr'] == 'StorageId') - and - isset($terms[$j]['val']) - ) { - $StorageArea = ZM\Storage::find_one(array('Id'=>$terms[$j]['val'])); - break; - } - } // end foreach remaining term - if ( ! $StorageArea ) $StorageArea = new ZM\Storage(); - } // end no StorageArea found yet - - $filter['sql'] .= getDiskPercent($StorageArea->Path()); - break; - case 'DiskBlocks': - // Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH - if ( ! $StorageArea ) { - for ( $j = $i; $j < count($terms); $j++ ) { - if ( - isset($terms[$j]['attr']) - and - ($terms[$j]['attr'] == 'StorageId') - and - isset($terms[$j]['val']) - ) { - $StorageArea = ZM\Storage::find_one(array('Id'=>$terms[$j]['val'])); - } - } // end foreach remaining term - } // end no StorageArea found yet - $filter['sql'] .= getDiskBlocks( $StorageArea ); - break; - case 'SystemLoad': - $filter['sql'] .= getLoad(); - break; - } # end switch attr - */ - } // end foreach term + $filter['sql'] = $Filter->sql(); + $filter['querystring'] = $Filter->querystring(); + $filter['hidden_fields'] = $Filter->hidden_fields(); + $filter['pre_sql_conditions'] = $Filter->pre_sql_conditions(); + $filter['post_sql_conditions'] = $Filter->post_sql_conditions(); if ( $filter['sql'] ) $filter['sql'] = ' AND ( '.$filter['sql'].' )'; - if ( $saveToSession ) { - $_SESSION['filter'] = $filter; - } #if ( 0 ) { #// ICON I feel like these should be here, but not yet @@ -1179,9 +1115,6 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { #$filter['sql'] .= ' ORDER BY ' . $filter['Query']['sort_field'] . ( #( $filter['Query']['sort_asc'] ? ' ASC' : ' DESC' ) ); #} - #if ( $filter['Query']['limit'] ) { - #$filter['sql'] .= ' LIMIT ' . validInt($filter['Query']['limit']); - #} #} return $filter; } // end function parseFilter(&$filter, $saveToSession=false, $querySep='&') @@ -1324,9 +1257,8 @@ function getDiskPercent($path = ZM_DIR_EVENTS) { return $space; } -function getDiskBlocks() { - if ( !$StorageArea ) $StorageArea = new ZM\Storage(); - $df = shell_exec('df '.escapeshellarg($StorageArea->Path())); +function getDiskBlocks($path = ZM_DIR_EVENTS) { + $df = shell_exec('df '.escapeshellarg($path)); $space = -1; if ( preg_match('/\s(\d+)\s+\d+\s+\d+%/ms', $df, $matches) ) $space = $matches[1]; From 479768a2a45156c4f9ebdb47bda049888ea3adbc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 16:57:53 -0400 Subject: [PATCH 015/117] implement disk_used_blocks in Storage. Also use Type() instead of ->{Type} to get default value. --- web/includes/Storage.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 099b98f4d..3a30606e6 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -69,6 +69,14 @@ class Storage extends ZM_Object { return $this->{'EventCount'}; } + public function disk_used_blocks() { + $df = shell_exec('df '.escapeshellarg($this->Path())); + $space = -1; + if ( preg_match('/\s(\d+)\s+\d+\s+\d+%/ms', $df, $matches) ) + $space = $matches[1]; + return $space; + } + public function disk_usage_percent() { $path = $this->Path(); if ( ! $path ) { @@ -106,7 +114,7 @@ class Storage extends ZM_Object { public function disk_used_space() { # This isn't a function like this in php, so we have to add up the space used in each event. if ( ( !property_exists($this, 'disk_used_space')) or !$this->{'disk_used_space'} ) { - if ( $this->{'Type'} == 's3fs' ) { + if ( $this->Type() == 's3fs' ) { $this->{'disk_used_space'} = $this->event_disk_space(); } else { $path = $this->Path(); From f4594f06d1a7343e698b31330cf691a57bcbfb12 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 16:58:37 -0400 Subject: [PATCH 016/117] Add in pre_condition checks. --- web/skins/classic/views/events.php | 67 +++++++++++++++++++----------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index f1177b491..93c37ddbb 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -36,7 +36,7 @@ if ( $user['MonitorIds'] ) { parseSort(); $filter = parseFilter($_REQUEST['filter']); -$filterQuery = $filter['query']; +$filterQuery = $filter['querystring']; ZM\Logger::Debug("Filter ".print_r($filter, true)); if ( $filter['sql'] ) { @@ -55,8 +55,24 @@ if ( $_POST ) { exit(); } -$results = dbQuery($eventsSql); -$nEvents = $results->rowCount(); +$failed = false; +if ( count($filter['pre_sql_conditions']) ) { + foreach ( $filter['pre_sql_conditions'] as $term ) { + if ( !$term->test() ) { + $failed = true; + break; + } + } +} # end if pre_sql_conditions +if ( $failed ) { + ZM\Logger::Debug("Pre conditions failed, not doing sql"); +} + +$results = $failed ? null : dbQuery($eventsSql); + +$nEvents = $results ? $results->rowCount() : 0; +ZM\Logger::Debug("Pre conditions succeeded sql return $nEvents events"); + if ( !empty($limit) && ($nEvents > $limit) ) { $nEvents = $limit; } @@ -135,26 +151,6 @@ xhtmlHeaders(__FILE__, translate('Events')); style="display:none;" > -test($event) ) { - $failed = true; - break; - } - } - if ( $failed ) continue; - } # end if PostSQLConditions - - if ( ($count++%ZM_WEB_EVENTS_PER_PAGE) == 0 ) { -?> @@ -193,8 +189,28 @@ while ( $event_row = dbFetchNext($results) ) { DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE); +$count = 0; +$disk_space_total = 0; +if ( $results ) { + + while ( $event_row = dbFetchNext($results) ) { + $event = new ZM\Event($event_row); + + if ( count($filter['post_sql_conditions']) ) { + $failed = false; + foreach ( $filter['post_sql_conditions'] as $term ) { + if ( !$term->test($event) ) { + $failed = true; + break; + } + } + if ( $failed ) { + ZM\Logger::Debug("Failed post conditions"); + continue; + } + } # end if PostSQLConditions + + $scale = max(reScale(SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE); ?> Archived() ? ' class="archived"' : '' ?>> @@ -285,6 +301,7 @@ while ( $event_row = dbFetchNext($results) ) { ?> From 5078a69c8122c83677a5ff83002ab826f3d363f0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 17:40:58 -0400 Subject: [PATCH 017/117] move pre and post condition testing into the Filter class so we can use it everywhere --- web/includes/Filter.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 793f34cd8..5a441b2ac 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -275,6 +275,37 @@ class Filter extends ZM_Object { return $status; } + public function test_pre_sql_conditions() { + if ( !count($this->pre_sql_conditions()) ) { + return true; + } # end if pre_sql_conditions + + $failed = false; + foreach ( $this->pre_sql_conditions() as $term ) { + if ( !$term->test() ) { + $failed = true; + break; + } + } + return $failed; + } + + public function test_post_sql_conditions($event) { + if ( !count($this->post_sql_conditions()) ) { + return true; + } # end if pre_sql_conditions + + $failed = true; + foreach ( $this->post_sql_conditions() as $term ) { + if ( !$term->test($event) ) { + $failed = false; + break; + } + } + return $failed; + } + + } # end class Filter ?> From 6649a30bbb608b7be9de6aa0e81d0298460a7754 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 17:41:13 -0400 Subject: [PATCH 018/117] Use querystring instead of query --- web/skins/classic/views/console.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index bbfc91ec1..a1b9b9cfe 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -333,7 +333,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { foreach ( array_keys($eventCounts) as $i ) { ?> - ' : '') . + ' : '') . $monitor[$i.'Events'] . '
' . human_filesize($monitor[$i.'EventDiskSpace']) ?>
' : '') . + (canView('Events') ? 'href="?view='.ZM_WEB_EVENTS_VIEW.'&page=1'.$filter['querystring'].'">' : '') . $eventCounts[$i]['totalevents'].'
'.human_filesize($eventCounts[$i]['totaldiskspace']) ?>
From 0f90b999c08130182189e63d782f085160c1a773 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 17:41:38 -0400 Subject: [PATCH 019/117] use filter class instead of parseFilter --- web/skins/classic/views/event.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index e5df8944f..80eb055d7 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -23,6 +23,9 @@ if ( !canView('Events') ) { return; } +require_once('includes/Event.php'); +require_once('includes/Filter.php'); + $eid = validInt($_REQUEST['eid']); $fid = !empty($_REQUEST['fid']) ? validInt($_REQUEST['fid']) : 1; @@ -115,8 +118,8 @@ if ( !isset($_REQUEST['filter']) ) { ); } parseSort(); -parseFilter($_REQUEST['filter']); -$filterQuery = $_REQUEST['filter']['query']; +$filter = ZM\Filter::parse($_REQUEST['filter']); +$filterQuery = $filter->querystring(); $connkey = generateConnKey(); From e5dd10fc04ea32571b7b4db89580a7aeefa8c931 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 17:41:50 -0400 Subject: [PATCH 020/117] use filter class instead of parseFilter --- web/skins/classic/views/events.php | 36 +++++++++--------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 93c37ddbb..cc88b003e 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -24,6 +24,7 @@ if ( !canView('Events') || (!empty($_REQUEST['execute']) && !canEdit('Events')) } 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'] ) { @@ -35,12 +36,12 @@ if ( $user['MonitorIds'] ) { parseSort(); -$filter = parseFilter($_REQUEST['filter']); -$filterQuery = $filter['querystring']; +$filter = ZM\Filter::parse($_REQUEST['filter']); +$filterQuery = $filter->querystring(); ZM\Logger::Debug("Filter ".print_r($filter, true)); -if ( $filter['sql'] ) { - $eventsSql .= $filter['sql']; +if ( $filter->sql() ) { + $eventsSql .= ' AND ('.$filter->sql().')'; } $eventsSql .= " ORDER BY $sortColumn $sortOrder"; if ( $sortColumn != 'E.Id' ) $eventsSql .= ',E.Id '.$sortOrder; @@ -55,15 +56,7 @@ if ( $_POST ) { exit(); } -$failed = false; -if ( count($filter['pre_sql_conditions']) ) { - foreach ( $filter['pre_sql_conditions'] as $term ) { - if ( !$term->test() ) { - $failed = true; - break; - } - } -} # end if pre_sql_conditions +$failed = !$filter->test_pre_sql_conditions(); if ( $failed ) { ZM\Logger::Debug("Pre conditions failed, not doing sql"); } @@ -196,19 +189,10 @@ if ( $results ) { while ( $event_row = dbFetchNext($results) ) { $event = new ZM\Event($event_row); - if ( count($filter['post_sql_conditions']) ) { - $failed = false; - foreach ( $filter['post_sql_conditions'] as $term ) { - if ( !$term->test($event) ) { - $failed = true; - break; - } - } - if ( $failed ) { - ZM\Logger::Debug("Failed post conditions"); - continue; - } - } # end if PostSQLConditions + if ( !$filter->test_post_sql_conditions($event) ) { + ZM\Logger::Debug("Failed post conditions"); + continue; + } $scale = max(reScale(SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE); ?> From e3fe75f21bae63d1b1ad87436a2d077fd19a13e9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 17:42:03 -0400 Subject: [PATCH 021/117] fix case on filterQuery --- web/skins/classic/views/js/event.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/event.js.php b/web/skins/classic/views/js/event.js.php index 70d7561a1..b3f746e07 100644 --- a/web/skins/classic/views/js/event.js.php +++ b/web/skins/classic/views/js/event.js.php @@ -2,7 +2,7 @@ global $connkey; global $Event; global $Monitor; - global $FilterQuery; + global $filterQuery; global $sortQuery; global $rates; global $rate; From dc451cbc859f6d42e0b684bacc7b5d15698491f9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 17 Aug 2020 17:42:22 -0400 Subject: [PATCH 022/117] Use filter class --- web/skins/classic/views/export.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 6abfd62bf..b1d43134b 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -85,20 +85,18 @@ if ( $user['MonitorIds'] ) { } if ( isset($_REQUEST['eid']) and $_REQUEST['eid'] ) { - ZM\Logger::Debug('Loading events by single eid'); $eventsSql .= ' AND E.Id=?'; $eventsValues[] = $_REQUEST['eid']; -} elseif ( isset($_REQUEST['eids']) and count($_REQUEST['eids']) > 0 ) { - ZM\Logger::Debug('Loading events by eids'); +} else if ( isset($_REQUEST['eids']) and count($_REQUEST['eids']) > 0 ) { $eventsSql .= ' AND E.Id IN ('.implode(',', array_map(function(){return '?';}, $_REQUEST['eids'])). ')'; $eventsValues += $_REQUEST['eids']; } else if ( isset($_REQUEST['filter']) ) { parseSort(); - parseFilter($_REQUEST['filter']); - $filterQuery = $_REQUEST['filter']['query']; + $filter = Filter::parse($_REQUEST['filter']); + $filterQuery = $filter->querystring(); - if ( $_REQUEST['filter']['sql'] ) { - $eventsSql .= $_REQUEST['filter']['sql']; + if ( $filter->sql() ) { + $eventsSql .= $filter->sql(); } $eventsSql .= " ORDER BY $sortColumn $sortOrder"; if ( isset($_REQUEST['filter']['Query']['limit']) ) From d366d4129754b60dfab1fbe5b2b2843ae8469512 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 19 Aug 2020 14:07:51 -0400 Subject: [PATCH 023/117] Update parseFilter to Filter::parse --- web/skins/classic/views/frames.php | 45 ++++++++++++++++++------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index 1f4abe240..703ffeb7c 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -24,12 +24,14 @@ if ( !canView('Events') ) { } require_once('includes/Frame.php'); +require_once('includes/Filter.php'); + $eid = validInt($_REQUEST['eid']); $Event = new ZM\Event($eid); $Monitor = $Event->Monitor(); $countSql = 'SELECT COUNT(*) AS FrameCount FROM Frames AS F WHERE 1 '; -$frameSql = 'SELECT *, unix_timestamp( TimeStamp ) AS UnixTimeStamp FROM Frames AS F WHERE 1 '; +$frameSql = 'SELECT *, unix_timestamp(TimeStamp) AS UnixTimeStamp FROM Frames AS F WHERE 1 '; // override the sort_field handling in parseSort for frames if ( empty($_REQUEST['sort_field']) ) @@ -38,7 +40,7 @@ if ( empty($_REQUEST['sort_field']) ) if ( !isset($_REQUEST['sort_asc']) ) $_REQUEST['sort_asc'] = true; -if ( ! isset($_REQUEST['filter'])){ +if ( !isset($_REQUEST['filter'])){ // generate a dummy filter from the eid for pagination $_REQUEST['filter'] = array('Query' => array( 'terms' => array( ) ) ); $_REQUEST['filter'] = addFilterTerm( @@ -49,12 +51,12 @@ if ( ! isset($_REQUEST['filter'])){ } parseSort(); -parseFilter($_REQUEST['filter']); -$filterQuery = $_REQUEST['filter']['query']; +$filter = ZM\Filter::parse($_REQUEST['filter']); +$filterQuery = $filter->querystring(); -if ( $_REQUEST['filter']['sql'] ) { - $countSql .= $_REQUEST['filter']['sql']; - $frameSql .= $_REQUEST['filter']['sql']; +if ( $filter->sql() ) { + $countSql .= ' AND ('.$filter->sql().')'; + $frameSql .= ' AND ('.$filter->sql().')'; } $frameSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder"; @@ -93,9 +95,9 @@ if ( !empty($page) ) { $limitLeft = $limit - $limitStart; $limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft; } - $frameSql .= " limit $limitStart, $limitAmount"; -} elseif ( !empty($limit) ) { - $frameSql .= ' limit 0, '.$limit; + $frameSql .= " LIMIT $limitStart, $limitAmount"; +} else if ( !empty($limit) ) { + $frameSql .= ' LIMIT 0, '.$limit; } $maxShortcuts = 5; @@ -143,7 +145,7 @@ if ( $pages > 1 ) { - + hidden_fields() ?> @@ -184,7 +186,7 @@ if ( count($frames) ) { ?> - + @@ -197,11 +199,19 @@ if ( count($frames) ) { } if ( ZM_WEB_LIST_THUMBS ) { ?> - Id().'&fid='.$frame['FrameId'], 'zmImage', array('image', $Event->Width(), $Event->Height()), ''.$frame['FrameId'].'' ) ?> + +Id().'&fid='.$frame['FrameId'], + 'zmImage', + array('image', $Event->Width(), $Event->Height()), + ''.$frame['FrameId'].'' +) ?> @@ -226,7 +236,6 @@ if ( $pagination ) { -
From 177df461132f752cb54e1e4c8e4144955d9e1a34 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 9 Aug 2020 22:20:06 -0400 Subject: [PATCH 024/117] Apply min=0 to filterX and Y so that we don't get negative values --- web/skins/classic/views/zone.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index 207bd64e5..0a2c9155b 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -217,8 +217,8 @@ xhtmlHeaders(__FILE__, translate('Zone')); - - + + From efec1e7d4f9c62183e0593a631893485d0c42bfb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 19 Aug 2020 14:13:48 -0400 Subject: [PATCH 025/117] remove debug --- web/skins/classic/views/js/zone.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index b8926d789..e5a3b14da 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -312,9 +312,7 @@ function updateActivePoint(index) { $('newZone[Points]['+index+'][y]').value = y; zone['Points'][index].x = x; zone['Points'][index].y = y; - console.log('hello'); var Point = $('zonePoly').points.getItem(index); - console.log('hello'); Point.x = x; Point.y = y; updateArea(); From d0c21995cd40386b2a688956523936f78ffe602c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 9 Aug 2020 22:19:43 -0400 Subject: [PATCH 026/117] Fixes to function converting from pixels to percent. Adjust to 100 if > 100. --- web/skins/classic/views/js/zone.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index e5a3b14da..605e0879d 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -178,14 +178,20 @@ function applyPreset() { function toPixels(field, maxValue) { if ( field.value != '' ) { field.value = Math.round((field.value*maxValue)/100); + if ( field.value > maxValue ) + field.value = maxValue; } field.setAttribute('step', 1); - field.setAttribute('max', monitorArea); + field.setAttribute('max', maxValue); } +// maxValue is the max Pixels value which is normally the max area function toPercent(field, maxValue) { if ( field.value != '' ) { field.value = Math.round((100*100*field.value)/maxValue)/100; + if ( field.value > 100 ) { + field.value = 100; + } } field.setAttribute('step', 0.01); field.setAttribute('max', 100); @@ -676,7 +682,6 @@ var watchdogFunctions = { //Make sure the various refreshes are still taking effect function watchdogCheck(type) { if ( watchdogInactive[type] ) { - console.log("Detected streamWatch of type: " + type + " stopped, restarting"); watchdogFunctions[type](); watchdogInactive[type] = false; } else { From c2d6b8f4934b65ffb197d20a66253d421d469b59 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 19 Aug 2020 14:39:15 -0400 Subject: [PATCH 027/117] revert code that passed the div hightlightOn/Off. Better to pass index. Fixes js errors. --- web/skins/classic/views/js/zone.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index 605e0879d..9071cfb24 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -250,14 +250,12 @@ function limitArea(field) { limitRange(field, minValue, maxValue); } -function highlightOn(point) { - var index = point.getAttribute('data-index'); +function highlightOn(index) { $('row'+index).addClass('highlight'); $('point'+index).addClass('highlight'); } -function highlightOff(point) { - var index = point.getAttribute('data-index'); +function highlightOff(index) { $('row'+index).removeClass('highlight'); $('point'+index).removeClass('highlight'); } @@ -329,17 +327,15 @@ function addPoint(index) { if ( index >= (zone['Points'].length-1) ) { nextIndex = 0; } + var newX = parseInt(Math.round((zone['Points'][index]['x']+zone['Points'][nextIndex]['x'])/2)); var newY = parseInt(Math.round((zone['Points'][index]['y']+zone['Points'][nextIndex]['y'])/2)); if ( nextIndex == 0 ) { zone['Points'][zone['Points'].length] = {'x': newX, 'y': newY}; } else { - zone['Points'].splice( nextIndex, 0, {'x': newX, 'y': newY} ); + zone['Points'].splice(nextIndex, 0, {'x': newX, 'y': newY}); } drawZonePoints(); - // drawZonePoints calls updateZoneImage - //updateZoneImage(); - //setActivePoint( nextIndex ); } function delPoint(index) { @@ -422,10 +418,9 @@ function drawZonePoints() { 'top': zone['Points'][i].y } }); - //div.addEvent('mouseover', highlightOn.pass(i)); - div.onmouseover = window['highlightOn'].bind(div, div); - div.onmouseout = window['highlightOff'].bind(div, div); + div.addEvent('mouseover', highlightOn.pass(i)); div.addEvent('mouseout', highlightOff.pass(i)); + div.inject($('imageFrame')); div.makeDraggable( { 'container': $('imageFrame'), @@ -494,7 +489,7 @@ function drawZonePoints() { cell.inject(row); row.inject(tables[i%tables.length].getElement('tbody')); - } + } // end foreach point // Sets up the SVG polygon updateZoneImage(); } From 46aaddeac545803de47db232b78021d82b1c45ee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 20 Aug 2020 20:44:28 -0400 Subject: [PATCH 028/117] Sort loading of conf.d config files. Also ignore db Config table entries that have already been defined in conf.d files so that they take precedence. --- .../ZoneMinder/lib/ZoneMinder/Config.pm.in | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index 10e4b4733..2cdd58add 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -76,39 +76,42 @@ BEGIN { require ZoneMinder::Database; # Process name, value pairs from the main config file first - my $config_file = ZM_CONFIG; - process_configfile($config_file); + process_configfile(ZM_CONFIG); # Search for user created config files. If one or more are found then # update the Config hash with those values if ( ZM_CONFIG_SUBDIR and -d ZM_CONFIG_SUBDIR ) { if ( -R ZM_CONFIG_SUBDIR ) { - foreach my $filename ( glob ZM_CONFIG_SUBDIR.'/*.conf' ) { + foreach my $filename ( sort { $a cmp $b } glob ZM_CONFIG_SUBDIR.'/*.conf' ) { process_configfile($filename); } } else { - print( STDERR 'WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on '.ZM_CONFIG_SUBDIR.".\n" ); + print(STDERR 'WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on '.ZM_CONFIG_SUBDIR.".\n"); } } my $dbh = ZoneMinder::Database::zmDbConnect(); + die "Unable to connect to DB. ZM Cannot continue.\n" if !$dbh; + my $sql = 'SELECT Name,Value FROM Config'; my $sth = $dbh->prepare_cached($sql) or croak("Can't prepare '$sql': ".$dbh->errstr()); my $res = $sth->execute() or croak("Can't execute: ".$sth->errstr()); - while( my $config = $sth->fetchrow_hashref() ) { + while ( my $config = $sth->fetchrow_hashref() ) { + # If already defined skip it because we want the values in /etc/zm.conf to override the values in Config Table + next if exists $Config{$config->{Name}}; $Config{$config->{Name}} = $config->{Value}; } $sth->finish(); - if ( ! $Config{ZM_SERVER_ID} ) { + if ( !$Config{ZM_SERVER_ID} ) { $Config{ZM_SERVER_ID} = undef; - $sth = $dbh->prepare_cached( 'SELECT * FROM Servers WHERE Name=?' ); + $sth = $dbh->prepare_cached('SELECT * FROM Servers WHERE Name=?'); if ( $Config{ZM_SERVER_NAME} ) { - $res = $sth->execute( $Config{ZM_SERVER_NAME} ); + $res = $sth->execute($Config{ZM_SERVER_NAME}); my $result = $sth->fetchrow_hashref(); $Config{ZM_SERVER_ID} = $$result{Id}; } elsif ( $Config{ZM_SERVER_HOST} ) { - $res = $sth->execute( $Config{ZM_SERVER_HOST} ); + $res = $sth->execute($Config{ZM_SERVER_HOST}); my $result = $sth->fetchrow_hashref(); $Config{ZM_SERVER_ID} = $$result{Id}; } @@ -126,20 +129,20 @@ require ZoneMinder::Database; open( my $CONFIG, '<', $config_file ) or croak("Can't open config file '$config_file': $!"); foreach my $str ( <$CONFIG> ) { - next if ( $str =~ /^\s*$/ ); + next if ( $str =~ /^\s*$/ ); next if ( $str =~ /^\s*#/ ); my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*[\'"]*(.*?)[\'"]*\s*$/; if ( !$name ) { print(STDERR "Warning, bad line in $config_file: $str\n"); next; } # end if - $name =~ tr/a-z/A-Z/; + $name = uc $name; #if ( !$ZoneMinder::ConfigData::options_hash{$name} ) { - #print(STDERR "Warning, unknown config option name $name in $config_file\n"); -#} else { - #print(STDERR "Warning, known config option name $name in $config_file\n"); - #} - $Config{$name} = $value; + #print(STDERR "Warning, unknown config option name $name in $config_file\n"); + #} else { + #print(STDERR "Warning, known config option name $name in $config_file\n"); + #} + $Config{$name} = $value; } # end foreach config line close($CONFIG); } # end sub process_configfile @@ -147,11 +150,11 @@ require ZoneMinder::Database; } # end BEGIN sub loadConfigFromDB { - print( 'Loading config from DB' ); + print('Loading config from DB'); my $dbh = ZoneMinder::Database::zmDbConnect(); if ( !$dbh ) { - print( "Error: unable to load options from database: $DBI::errstr\n" ); - return( 0 ); + print("Error: unable to load options from database: $DBI::errstr\n"); + return(0); } my $sql = "select * from Config"; my $sth = $dbh->prepare_cached( $sql ) @@ -161,13 +164,13 @@ sub loadConfigFromDB { my $option_count = 0; while( my $config = $sth->fetchrow_hashref() ) { my ( $name, $value ) = ( $config->{Name}, $config->{Value} ); -#print( "Name = '$name'\n" ); + #print( "Name = '$name'\n" ); my $option = $options_hash{$name}; if ( !$option ) { warn( "No option '$name' found, removing.\n" ); next; } -#next if ( $option->{category} eq 'hidden' ); + #next if ( $option->{category} eq 'hidden' ); if ( defined($value) ) { if ( $option->{type} == $types{boolean} ) { $option->{value} = $value?'yes':'no'; @@ -204,8 +207,8 @@ sub saveConfigToDB { my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); foreach my $option ( @options ) { -#next if ( $option->{category} eq 'hidden' ); -#print( $option->{name}."\n" ) if ( !$option->{category} ); + #next if ( $option->{category} eq 'hidden' ); + #print( $option->{name}."\n" ) if ( !$option->{category} ); $option->{db_type} = $option->{type}->{db_type}; $option->{db_hint} = $option->{type}->{hint}; $option->{db_pattern} = $option->{type}->{pattern}; From 9357017a398c273f46e8ab5b41290c0ddbf9e2ae Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 21 Aug 2020 07:11:57 -0500 Subject: [PATCH 029/117] add export fx to tables --- web/skins/classic/includes/functions.php | 4 +- .../classic/js/bootstrap-table-export.min.js | 10 ++ web/skins/classic/js/tableExport.min.js | 93 +++++++++++++++++++ web/skins/classic/views/events.php | 1 + web/skins/classic/views/frames.php | 1 + web/skins/classic/views/js/events.js | 1 + web/skins/classic/views/js/frames.js | 1 + 7 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 web/skins/classic/js/bootstrap-table-export.min.js create mode 100644 web/skins/classic/js/tableExport.min.js diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 2c420c4e8..00a25db07 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -132,7 +132,9 @@ if ( $css != 'base' ) - + + + diff --git a/web/skins/classic/js/bootstrap-table-export.min.js b/web/skins/classic/js/bootstrap-table-export.min.js new file mode 100644 index 000000000..44d05ba4c --- /dev/null +++ b/web/skins/classic/js/bootstrap-table-export.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.17.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):e((t=t||self).jQuery)}(this,(function(t){"use strict";t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function n(t,e){return t(e={exports:{}},e.exports),e.exports}var r=function(t){return t&&t.Math==Math&&t},o=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof e&&e)||Function("return this")(),i=function(t){try{return!!t()}catch(t){return!0}},a=!i((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})),c={}.propertyIsEnumerable,u=Object.getOwnPropertyDescriptor,l={f:u&&!c.call({1:2},1)?function(t){var e=u(this,t);return!!e&&e.enumerable}:c},s=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},f={}.toString,p=function(t){return f.call(t).slice(8,-1)},d="".split,h=i((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==p(t)?d.call(t,""):Object(t)}:Object,g=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},y=function(t){return h(g(t))},v=function(t){return"object"==typeof t?null!==t:"function"==typeof t},b=function(t,e){if(!v(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!v(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!v(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!v(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")},x={}.hasOwnProperty,m=function(t,e){return x.call(t,e)},S=o.document,w=v(S)&&v(S.createElement),O=function(t){return w?S.createElement(t):{}},E=!a&&!i((function(){return 7!=Object.defineProperty(O("div"),"a",{get:function(){return 7}}).a})),T=Object.getOwnPropertyDescriptor,j={f:a?T:function(t,e){if(t=y(t),e=b(e,!0),E)try{return T(t,e)}catch(t){}if(m(t,e))return s(!l.f.call(t,e),t[e])}},P=function(t){if(!v(t))throw TypeError(String(t)+" is not an object");return t},A=Object.defineProperty,I={f:a?A:function(t,e,n){if(P(t),e=b(e,!0),P(n),E)try{return A(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},_=a?function(t,e,n){return I.f(t,e,s(1,n))}:function(t,e,n){return t[e]=n,t},R=function(t,e){try{_(o,t,e)}catch(n){o[t]=e}return e},C=o["__core-js_shared__"]||R("__core-js_shared__",{}),L=Function.toString;"function"!=typeof C.inspectSource&&(C.inspectSource=function(t){return L.call(t)});var k,M,$,D=C.inspectSource,N=o.WeakMap,F="function"==typeof N&&/native code/.test(D(N)),B=n((function(t){(t.exports=function(t,e){return C[t]||(C[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.0",mode:"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})})),G=0,V=Math.random(),H=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++G+V).toString(36)},q=B("keys"),z=function(t){return q[t]||(q[t]=H(t))},U={},W=o.WeakMap;if(F){var K=new W,Y=K.get,X=K.has,J=K.set;k=function(t,e){return J.call(K,t,e),e},M=function(t){return Y.call(K,t)||{}},$=function(t){return X.call(K,t)}}else{var Q=z("state");U[Q]=!0,k=function(t,e){return _(t,Q,e),e},M=function(t){return m(t,Q)?t[Q]:{}},$=function(t){return m(t,Q)}}var Z,tt={set:k,get:M,has:$,enforce:function(t){return $(t)?M(t):k(t,{})},getterFor:function(t){return function(e){var n;if(!v(e)||(n=M(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}},et=n((function(t){var e=tt.get,n=tt.enforce,r=String(String).split("String");(t.exports=function(t,e,i,a){var c=!!a&&!!a.unsafe,u=!!a&&!!a.enumerable,l=!!a&&!!a.noTargetGet;"function"==typeof i&&("string"!=typeof e||m(i,"name")||_(i,"name",e),n(i).source=r.join("string"==typeof e?e:"")),t!==o?(c?!l&&t[e]&&(u=!0):delete t[e],u?t[e]=i:_(t,e,i)):u?t[e]=i:R(e,i)})(Function.prototype,"toString",(function(){return"function"==typeof this&&e(this).source||D(this)}))})),nt=o,rt=function(t){return"function"==typeof t?t:void 0},ot=function(t,e){return arguments.length<2?rt(nt[t])||rt(o[t]):nt[t]&&nt[t][e]||o[t]&&o[t][e]},it=Math.ceil,at=Math.floor,ct=function(t){return isNaN(t=+t)?0:(t>0?at:it)(t)},ut=Math.min,lt=function(t){return t>0?ut(ct(t),9007199254740991):0},st=Math.max,ft=Math.min,pt=function(t,e){var n=ct(t);return n<0?st(n+e,0):ft(n,e)},dt=function(t){return function(e,n,r){var o,i=y(e),a=lt(i.length),c=pt(r,a);if(t&&n!=n){for(;a>c;)if((o=i[c++])!=o)return!0}else for(;a>c;c++)if((t||c in i)&&i[c]===n)return t||c||0;return!t&&-1}},ht={includes:dt(!0),indexOf:dt(!1)}.indexOf,gt=function(t,e){var n,r=y(t),o=0,i=[];for(n in r)!m(U,n)&&m(r,n)&&i.push(n);for(;e.length>o;)m(r,n=e[o++])&&(~ht(i,n)||i.push(n));return i},yt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],vt=yt.concat("length","prototype"),bt={f:Object.getOwnPropertyNames||function(t){return gt(t,vt)}},xt={f:Object.getOwnPropertySymbols},mt=ot("Reflect","ownKeys")||function(t){var e=bt.f(P(t)),n=xt.f;return n?e.concat(n(t)):e},St=function(t,e){for(var n=mt(e),r=I.f,o=j.f,i=0;ii;)I.f(t,n=r[i++],e[n]);return t},Dt=ot("document","documentElement"),Nt=z("IE_PROTO"),Ft=function(){},Bt=function(t){return" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +'; + global $error_message; + if ( $error_message ) { + echo '
'.$error_message.'
'; + } +} // end function getBodyTopHTML + +function getNavBarHTML() { + # Provide a facility to turn off the headers if you put navbar=0 into the url + if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar'] == '0' ) + return ''; + + global $running; + global $user; + global $bandwidth_options; + global $view; + global $filterQuery; + global $sortQuery; + global $limitQuery; + global $skin; + + if ( !$sortQuery ) { + parseSort(); + } + if ( (!$filterQuery) and isset($_REQUEST['filter']) ) { + parseFilter($_REQUEST['filter']); + $filterQuery = $_REQUEST['filter']['query']; + } + + ob_start(); + + if ( ZM_WEB_NAVBAR_TYPE == "normal" ) { + echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery, $skin); + } else { + echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery, $skin); + } + + return ob_get_clean(); +} + +// +// The legacy navigation bar that collapses into a pulldown menu on small screens. +// +function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery, $skin) { + + $status = runtimeStatus($running); + +?> +
+ + + + + +
+ +
+ + + +
+ + '.PHP_EOL; + $result .= 'trending_up'.PHP_EOL; + $result .= ' '.translate('Load').': '.getLoad().PHP_EOL; + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the current number of connections made to the database +function getDbConHTML() { + $result = ''; + + $connections = dbFetchOne('SHOW status WHERE variable_name=\'threads_connected\'', 'Value'); + $max_connections = dbFetchOne('SHOW variables WHERE variable_name=\'max_connections\'', 'Value'); + $percent_used = $max_connections ? 100 * $connections / $max_connections : 100; + $class = ( $percent_used > 90 ) ? ' text-warning' : ''; + + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns an html dropdown showing capacity of all storage areas +function getStorageHTML() { + $result=''; + + $func = function($S) { + $class = ''; + if ( $S->disk_usage_percent() > 98 ) { + $class = 'text-danger'; + } else if ( $S->disk_usage_percent() > 90 ) { + $class = 'text-warning'; + } + $title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()). + ( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' ); + return ''.$S->Name() . ': ' . $S->disk_usage_percent().'%' . ''; + }; + + $storage_areas = ZM\Storage::find(array('Enabled'=>true)); + $num_storage_areas = count($storage_areas); + + $full_warning = 0; + $full_error = 0; + foreach ( $storage_areas as $area ) { + if ( $area->disk_usage_percent() > 98 ) { $full_error++; continue; } + if ( $area->disk_usage_percent() > 90 ) $full_warning++; + } + + $class = ''; + if ( $full_error ) { + $class = 'text-danger'; + } else if ( $full_warning ) { + $class = 'text-warning'; + } + + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the current capacity of mapped memory filesystem (usually /dev/shm) +function getShmHTML() { + $result = ''; + + $shm_percent = getDiskPercent(ZM_PATH_MAP); + $shm_total_space = disk_total_space(ZM_PATH_MAP); + $shm_used = $shm_total_space - disk_free_space(ZM_PATH_MAP); + + $class = ''; + if ( $shm_percent > 98 ) { + $class = 'text-danger'; + } else if ( $shm_percent > 90 ) { + $class = 'text-warning'; + } + $result .= ' '.PHP_EOL; + + return $result; +} + +// Returns the html representing the optional web console banner text +function getConsoleBannerHTML() { + $result = ''; + + if ( defined('ZM_WEB_CONSOLE_BANNER') and ZM_WEB_CONSOLE_BANNER != '' ) { + $result .= '

'.validHtmlStr(ZM_WEB_CONSOLE_BANNER).'

'; + } + return $result; +} + +// Returns the html representing the current high,medium,low bandwidth setting +function getBandwidthHTML($bandwidth_options, $user) { + + # Limit available options to what are available in user + if ( $user && !empty($user['MaxBandwidth']) ) { + if ( $user['MaxBandwidth'] == 'low' ) { + unset($bandwidth_options['high']); + unset($bandwidth_options['medium']); + } else if ( $user['MaxBandwidth'] == 'medium' ) { + unset($bandwidth_options['high']); + } + } + + $result = ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the version of ZoneMinder +function getZMVersionHTML() { + $result = ''; + $content = ''; + + if ( ZM_DYN_DB_VERSION && (ZM_DYN_DB_VERSION != ZM_VERSION) ) { // Must upgrade before proceeding + $class = 'text-danger'; + $tt_text = translate('RunLocalUpdate'); + $content = 'v'.ZM_VERSION.PHP_EOL; + } else if ( verNum( ZM_DYN_LAST_VERSION ) <= verNum( ZM_VERSION ) ) { // No update needed + $class = ''; // Don't change the text color under normal conditions + $tt_text = translate('UpdateNotNecessary'); + $content = 'v'.ZM_VERSION.PHP_EOL; + } else if ( canEdit('System') ) { // An update is available and the user is an administrator + $class = 'text-warning'; + $tt_text = translate('UpdateAvailable'); + $content = 'v' .ZM_VERSION. ''.PHP_EOL; + $content .= ''.PHP_EOL; + } else { // An update is available and the user is NOT an administrator + $class = 'text-warning'; + $tt_text = translate('UpdateAvailable'); + $content = 'v'.ZM_VERSION.PHP_EOL; + } + + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the ZoneMinder logo and about menu +function getNavBrandHTML() { + $result = ''; + + if ( ZM_HOME_ABOUT ) { + $result .= 'ZoneMinder'.PHP_EOL; + $result .= ''.PHP_EOL; + } else { + $result .= '' .ZM_HOME_CONTENT. ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the Console menu item +function getConsoleHTML() { + $result = ''; + + if ( canView('Monitors') ) { + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the Options menu item +function getOptionsHTML() { + $result = ''; + + if ( canView('System') ) { + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the Log menu item +function getLogHTML() { + $result = ''; + + if ( canView('System') ) { + if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) { + $logstate = logState(); + $class = ($logstate == 'ok') ? 'text-success' : ($logstate == 'alert' ? 'text-warning' : (($logstate == 'alarm' ? 'text-danger' : ''))); + $result .= ''.PHP_EOL; + } + } + + return $result; +} + +// Returns the html representing the log icon +function getLogIconHTML() { + $result = ''; + + if ( canView('System') ) { + if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) { + $logstate = logState(); + $class = ( $logstate == 'alert' ) ? 'text-warning' : (( $logstate == 'alarm' ) ? 'text-danger' : ''); + $result .= ''.PHP_EOL; + } + } + + return $result; +} + +// Returns the html representing the X10 Devices menu item +function getDevicesHTML() { + $result = ''; + + if ( ZM_OPT_X10 && canView('Devices') ) { + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the Groups menu item +function getGroupsHTML($view) { + $result = ''; + + $class = $view == 'groups' ? ' selected' : ''; + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the Filter menu item +function getFilterHTML($view, $filterQuery, $sortQuery, $limitQuery) { + $result = ''; + + $class = $view == 'filter' ? ' selected' : ''; + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the Cycle menu item +function getCycleHTML($view) { + $result = ''; + + if ( canView('Stream') ) { + $class = $view == 'cycle' ? ' selected' : ''; + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the Montage menu item +function getMontageHTML($view) { + $result = ''; + + if ( canView('Stream') ) { + $class = $view == 'cycle' ? ' selected' : ''; + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the MontageReview menu item +function getMontageReviewHTML($view) { + $result = ''; + + if ( canView('Events') ) { + if ( isset($_REQUEST['filter']['Query']['terms']['attr']) ) { + $terms = $_REQUEST['filter']['Query']['terms']; + $count = 0; + foreach ($terms as $term) { + if ( $term['attr'] == 'StartDateTime' ) { + $count += 1; + if ($term['op'] == '>=') $minTime = $term['val']; + if ($term['op'] == '<=') $maxTime = $term['val']; + } + } + if ( $count == 2 ) { + $montageReviewQuery = '&minTime='.$minTime.'&maxTime='.$maxTime; + } + } + $live = isset($montageReviewQuery) ? '&fit=1'.$montageReviewQuery.'&live=0' : ''; + $class = $view == 'montagereview' ? ' selected' : ''; + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the Audit Events Report menu item +function getRprtEvntAuditHTML($view) { + $result = ''; + + if ( canView('Events') ) { + $class = $view == 'report_event_audit' ? ' selected' : ''; + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the header collapse toggle menu item +function getHeaderFlipHTML() { + $result = ''; + + $header = ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down') ? 'down' : 'up'; + $result .= ''.PHP_EOL; + + return $result; +} + +// Returns the html representing the logged in user name and avatar +function getAcctCircleHTML($skin, $user=null) { + // Include Logout modal + include("skins/$skin/views/logout.php"); + $result = ''; + + if ( ZM_OPT_USE_AUTH and $user ) { + $result .= ''.PHP_EOL; + } + + return $result; +} + +// Returns the html representing the runtime status button +function getStatusBtnHTML($status) { + $result = ''; + + if ( canEdit('System') ) { + //$result .= ''.PHP_EOL; + + if ( ZM_SYSTEM_SHUTDOWN ) { + $result .= ''.PHP_EOL; + } + + } else if ( canView('System') ) { + $result .= ''.PHP_EOL; + } + + return $result; +} + +function runtimeStatus($running=null) { + if ( $running == null ) + $running = daemonCheck(); + if ( $running ) { + $state = dbFetchOne('SELECT Name FROM States WHERE isActive=1', 'Name'); + if ( $state == 'default' ) + $state = ''; + } + + return $running ? ($state ? $state : translate('Running')) : translate('Stopped'); +} + +function xhtmlFooter() { + global $cspNonce; + global $view; + global $skin; + if ( canEdit('System') ) { + include("skins/$skin/views/state.php"); + } +?> + + + + diff --git a/web/skins/classic/includes/functions.php.rej b/web/skins/classic/includes/functions.php.rej new file mode 100644 index 000000000..3d66a03a7 --- /dev/null +++ b/web/skins/classic/includes/functions.php.rej @@ -0,0 +1,47 @@ +--- web/skins/classic/includes/functions.php ++++ web/skins/classic/includes/functions.php +@@ -223,24 +223,13 @@ function getNavBarHTML() { + global $user; + global $bandwidth_options; + global $view; +- global $filterQuery; +- global $sortQuery; +- global $limitQuery; +- +- if ( !$sortQuery ) { +- parseSort(); +- } +- if ( (!$filterQuery) and isset($_REQUEST['filter']) ) { +- parseFilter($_REQUEST['filter']); +- $filterQuery = $_REQUEST['filter']['query']; +- } + + ob_start(); + + if ( ZM_WEB_NAVBAR_TYPE == "normal" ) { +- echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery); ++ echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view); + } else { +- echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery); ++ echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view); + } + + return ob_get_clean(); +@@ -249,7 +238,7 @@ function getNavBarHTML() { + // + // The legacy navigation bar that collapses into a pulldown menu on small screens. + // +-function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) { ++function getNormalNavBarHTML($running, $user, $bandwidth_options, $view) { + + $status = runtimeStatus($running); + +@@ -340,7 +329,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filter + // + // A new, slimmer navigation bar, permanently collapsed into a dropdown + // +-function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) { ++function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view) { + + $status = runtimeStatus($running); + From 367c0607908ccea1e676a11e0d101df794da1cb3 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 26 Aug 2020 17:07:58 -0500 Subject: [PATCH 104/117] remove unwanted patch files --- web/skins/classic/includes/functions.php.orig | 857 ------------------ web/skins/classic/includes/functions.php.rej | 47 - 2 files changed, 904 deletions(-) delete mode 100644 web/skins/classic/includes/functions.php.orig delete mode 100644 web/skins/classic/includes/functions.php.rej diff --git a/web/skins/classic/includes/functions.php.orig b/web/skins/classic/includes/functions.php.orig deleted file mode 100644 index 0a3fd4f42..000000000 --- a/web/skins/classic/includes/functions.php.orig +++ /dev/null @@ -1,857 +0,0 @@ -'; - } - } - $html[] = ''; // So we ge a trailing \n - return implode(PHP_EOL, $html); - } - - function output_cache_busted_stylesheet_links($files) { - $html = array(); - foreach ( $files as $file ) { - $html[] = ''; - } - $html[] = ''; // So we ge a trailing \n - return implode(PHP_EOL, $html); - } -?> - - - - - - - <?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX) . ' - ' . validHtmlStr($title) ?> - - -"; -} else { - echo ' - - -'; -} -echo output_cache_busted_stylesheet_links(array( - 'css/reset.css', - 'css/overlay.css', - 'css/font-awesome.min.css', - 'css/bootstrap.min.css', - 'css/bootstrap-table.min.css', -)); - -echo output_link_if_exists(array( - 'css/base/skin.css', - 'css/base/views/'.$basename.'.css', - 'js/dateTimePicker/jquery-ui-timepicker-addon.css', - 'js/jquery-ui-1.12.1/jquery-ui.structure.min.css', -)); -if ( $css != 'base' ) - echo output_link_if_exists(array( - 'css/'.$css.'/skin.css', - 'css/'.$css.'/views/'.$basename.'.css', - 'css/'.$css.'/jquery-ui-theme.css', - )); -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'; - global $error_message; - if ( $error_message ) { - echo '
'.$error_message.'
'; - } -} // end function getBodyTopHTML - -function getNavBarHTML() { - # Provide a facility to turn off the headers if you put navbar=0 into the url - if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar'] == '0' ) - return ''; - - global $running; - global $user; - global $bandwidth_options; - global $view; - global $filterQuery; - global $sortQuery; - global $limitQuery; - global $skin; - - if ( !$sortQuery ) { - parseSort(); - } - if ( (!$filterQuery) and isset($_REQUEST['filter']) ) { - parseFilter($_REQUEST['filter']); - $filterQuery = $_REQUEST['filter']['query']; - } - - ob_start(); - - if ( ZM_WEB_NAVBAR_TYPE == "normal" ) { - echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery, $skin); - } else { - echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery, $skin); - } - - return ob_get_clean(); -} - -// -// The legacy navigation bar that collapses into a pulldown menu on small screens. -// -function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery, $skin) { - - $status = runtimeStatus($running); - -?> -
- - - - - -
- -
- - - -
- - '.PHP_EOL; - $result .= 'trending_up'.PHP_EOL; - $result .= ' '.translate('Load').': '.getLoad().PHP_EOL; - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the current number of connections made to the database -function getDbConHTML() { - $result = ''; - - $connections = dbFetchOne('SHOW status WHERE variable_name=\'threads_connected\'', 'Value'); - $max_connections = dbFetchOne('SHOW variables WHERE variable_name=\'max_connections\'', 'Value'); - $percent_used = $max_connections ? 100 * $connections / $max_connections : 100; - $class = ( $percent_used > 90 ) ? ' text-warning' : ''; - - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns an html dropdown showing capacity of all storage areas -function getStorageHTML() { - $result=''; - - $func = function($S) { - $class = ''; - if ( $S->disk_usage_percent() > 98 ) { - $class = 'text-danger'; - } else if ( $S->disk_usage_percent() > 90 ) { - $class = 'text-warning'; - } - $title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()). - ( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' ); - return ''.$S->Name() . ': ' . $S->disk_usage_percent().'%' . ''; - }; - - $storage_areas = ZM\Storage::find(array('Enabled'=>true)); - $num_storage_areas = count($storage_areas); - - $full_warning = 0; - $full_error = 0; - foreach ( $storage_areas as $area ) { - if ( $area->disk_usage_percent() > 98 ) { $full_error++; continue; } - if ( $area->disk_usage_percent() > 90 ) $full_warning++; - } - - $class = ''; - if ( $full_error ) { - $class = 'text-danger'; - } else if ( $full_warning ) { - $class = 'text-warning'; - } - - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the current capacity of mapped memory filesystem (usually /dev/shm) -function getShmHTML() { - $result = ''; - - $shm_percent = getDiskPercent(ZM_PATH_MAP); - $shm_total_space = disk_total_space(ZM_PATH_MAP); - $shm_used = $shm_total_space - disk_free_space(ZM_PATH_MAP); - - $class = ''; - if ( $shm_percent > 98 ) { - $class = 'text-danger'; - } else if ( $shm_percent > 90 ) { - $class = 'text-warning'; - } - $result .= ' '.PHP_EOL; - - return $result; -} - -// Returns the html representing the optional web console banner text -function getConsoleBannerHTML() { - $result = ''; - - if ( defined('ZM_WEB_CONSOLE_BANNER') and ZM_WEB_CONSOLE_BANNER != '' ) { - $result .= '

'.validHtmlStr(ZM_WEB_CONSOLE_BANNER).'

'; - } - return $result; -} - -// Returns the html representing the current high,medium,low bandwidth setting -function getBandwidthHTML($bandwidth_options, $user) { - - # Limit available options to what are available in user - if ( $user && !empty($user['MaxBandwidth']) ) { - if ( $user['MaxBandwidth'] == 'low' ) { - unset($bandwidth_options['high']); - unset($bandwidth_options['medium']); - } else if ( $user['MaxBandwidth'] == 'medium' ) { - unset($bandwidth_options['high']); - } - } - - $result = ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the version of ZoneMinder -function getZMVersionHTML() { - $result = ''; - $content = ''; - - if ( ZM_DYN_DB_VERSION && (ZM_DYN_DB_VERSION != ZM_VERSION) ) { // Must upgrade before proceeding - $class = 'text-danger'; - $tt_text = translate('RunLocalUpdate'); - $content = 'v'.ZM_VERSION.PHP_EOL; - } else if ( verNum( ZM_DYN_LAST_VERSION ) <= verNum( ZM_VERSION ) ) { // No update needed - $class = ''; // Don't change the text color under normal conditions - $tt_text = translate('UpdateNotNecessary'); - $content = 'v'.ZM_VERSION.PHP_EOL; - } else if ( canEdit('System') ) { // An update is available and the user is an administrator - $class = 'text-warning'; - $tt_text = translate('UpdateAvailable'); - $content = 'v' .ZM_VERSION. ''.PHP_EOL; - $content .= ''.PHP_EOL; - } else { // An update is available and the user is NOT an administrator - $class = 'text-warning'; - $tt_text = translate('UpdateAvailable'); - $content = 'v'.ZM_VERSION.PHP_EOL; - } - - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the ZoneMinder logo and about menu -function getNavBrandHTML() { - $result = ''; - - if ( ZM_HOME_ABOUT ) { - $result .= 'ZoneMinder'.PHP_EOL; - $result .= ''.PHP_EOL; - } else { - $result .= '' .ZM_HOME_CONTENT. ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the Console menu item -function getConsoleHTML() { - $result = ''; - - if ( canView('Monitors') ) { - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the Options menu item -function getOptionsHTML() { - $result = ''; - - if ( canView('System') ) { - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the Log menu item -function getLogHTML() { - $result = ''; - - if ( canView('System') ) { - if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) { - $logstate = logState(); - $class = ($logstate == 'ok') ? 'text-success' : ($logstate == 'alert' ? 'text-warning' : (($logstate == 'alarm' ? 'text-danger' : ''))); - $result .= ''.PHP_EOL; - } - } - - return $result; -} - -// Returns the html representing the log icon -function getLogIconHTML() { - $result = ''; - - if ( canView('System') ) { - if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) { - $logstate = logState(); - $class = ( $logstate == 'alert' ) ? 'text-warning' : (( $logstate == 'alarm' ) ? 'text-danger' : ''); - $result .= ''.PHP_EOL; - } - } - - return $result; -} - -// Returns the html representing the X10 Devices menu item -function getDevicesHTML() { - $result = ''; - - if ( ZM_OPT_X10 && canView('Devices') ) { - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the Groups menu item -function getGroupsHTML($view) { - $result = ''; - - $class = $view == 'groups' ? ' selected' : ''; - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the Filter menu item -function getFilterHTML($view, $filterQuery, $sortQuery, $limitQuery) { - $result = ''; - - $class = $view == 'filter' ? ' selected' : ''; - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the Cycle menu item -function getCycleHTML($view) { - $result = ''; - - if ( canView('Stream') ) { - $class = $view == 'cycle' ? ' selected' : ''; - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the Montage menu item -function getMontageHTML($view) { - $result = ''; - - if ( canView('Stream') ) { - $class = $view == 'cycle' ? ' selected' : ''; - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the MontageReview menu item -function getMontageReviewHTML($view) { - $result = ''; - - if ( canView('Events') ) { - if ( isset($_REQUEST['filter']['Query']['terms']['attr']) ) { - $terms = $_REQUEST['filter']['Query']['terms']; - $count = 0; - foreach ($terms as $term) { - if ( $term['attr'] == 'StartDateTime' ) { - $count += 1; - if ($term['op'] == '>=') $minTime = $term['val']; - if ($term['op'] == '<=') $maxTime = $term['val']; - } - } - if ( $count == 2 ) { - $montageReviewQuery = '&minTime='.$minTime.'&maxTime='.$maxTime; - } - } - $live = isset($montageReviewQuery) ? '&fit=1'.$montageReviewQuery.'&live=0' : ''; - $class = $view == 'montagereview' ? ' selected' : ''; - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the Audit Events Report menu item -function getRprtEvntAuditHTML($view) { - $result = ''; - - if ( canView('Events') ) { - $class = $view == 'report_event_audit' ? ' selected' : ''; - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the header collapse toggle menu item -function getHeaderFlipHTML() { - $result = ''; - - $header = ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down') ? 'down' : 'up'; - $result .= ''.PHP_EOL; - - return $result; -} - -// Returns the html representing the logged in user name and avatar -function getAcctCircleHTML($skin, $user=null) { - // Include Logout modal - include("skins/$skin/views/logout.php"); - $result = ''; - - if ( ZM_OPT_USE_AUTH and $user ) { - $result .= ''.PHP_EOL; - } - - return $result; -} - -// Returns the html representing the runtime status button -function getStatusBtnHTML($status) { - $result = ''; - - if ( canEdit('System') ) { - //$result .= ''.PHP_EOL; - - if ( ZM_SYSTEM_SHUTDOWN ) { - $result .= ''.PHP_EOL; - } - - } else if ( canView('System') ) { - $result .= ''.PHP_EOL; - } - - return $result; -} - -function runtimeStatus($running=null) { - if ( $running == null ) - $running = daemonCheck(); - if ( $running ) { - $state = dbFetchOne('SELECT Name FROM States WHERE isActive=1', 'Name'); - if ( $state == 'default' ) - $state = ''; - } - - return $running ? ($state ? $state : translate('Running')) : translate('Stopped'); -} - -function xhtmlFooter() { - global $cspNonce; - global $view; - global $skin; - if ( canEdit('System') ) { - include("skins/$skin/views/state.php"); - } -?> - - - - diff --git a/web/skins/classic/includes/functions.php.rej b/web/skins/classic/includes/functions.php.rej deleted file mode 100644 index 3d66a03a7..000000000 --- a/web/skins/classic/includes/functions.php.rej +++ /dev/null @@ -1,47 +0,0 @@ ---- web/skins/classic/includes/functions.php -+++ web/skins/classic/includes/functions.php -@@ -223,24 +223,13 @@ function getNavBarHTML() { - global $user; - global $bandwidth_options; - global $view; -- global $filterQuery; -- global $sortQuery; -- global $limitQuery; -- -- if ( !$sortQuery ) { -- parseSort(); -- } -- if ( (!$filterQuery) and isset($_REQUEST['filter']) ) { -- parseFilter($_REQUEST['filter']); -- $filterQuery = $_REQUEST['filter']['query']; -- } - - ob_start(); - - if ( ZM_WEB_NAVBAR_TYPE == "normal" ) { -- echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery); -+ echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view); - } else { -- echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery); -+ echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view); - } - - return ob_get_clean(); -@@ -249,7 +238,7 @@ function getNavBarHTML() { - // - // The legacy navigation bar that collapses into a pulldown menu on small screens. - // --function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) { -+function getNormalNavBarHTML($running, $user, $bandwidth_options, $view) { - - $status = runtimeStatus($running); - -@@ -340,7 +329,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filter - // - // A new, slimmer navigation bar, permanently collapsed into a dropdown - // --function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) { -+function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view) { - - $status = runtimeStatus($running); - From b451c323e94b3f34dc9e82394a058191eb47d955 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 26 Aug 2020 18:40:31 -0400 Subject: [PATCH 105/117] remove debug code at Warning level --- web/includes/functions.php | 42 +++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 4445e74b7..79d661b11 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -849,7 +849,6 @@ function daemonStatus($daemon, $args=false) { if ( $args ) { if ( is_array($args) ) { $string .= join(' ', $args); -ZM\Warning("daemonStatus args: $string"); } else { $string .= ' ' . $args; } @@ -2052,28 +2051,51 @@ function validHtmlStr($input) { return htmlspecialchars($input, ENT_QUOTES); } +/* options['width'] is the desired view width not necessarily the image width requested. + * It can be % in which case we us it to set the scale + * It can be px in which case we can use it to calculate the scale + * Same width height. If both are set we should calculate the smaller resulting scale + */ function getStreamHTML($monitor, $options = array()) { + ZM\Warning(print_r($options, true)); - if ( isset($options['scale']) ) { - if ( $options['scale'] != 'auto' && $options['scale'] != '0' and $options['scale'] != '' ) { - ZM\Logger::Debug("Setting dimensions from scale:".$options['scale']); + if ( isset($options['scale']) and $options['scale'] != '' ) { + if ( $options['scale'] != 'auto' && $options['scale'] != '0' ) { + ZM\Warning("Setting dimensions from scale:".$options['scale']); $options['width'] = reScale($monitor->ViewWidth(), $options['scale']).'px'; $options['height'] = reScale($monitor->ViewHeight(), $options['scale']).'px'; - } else { + } else if ( ! ( isset($options['width']) or isset($options['height']) ) ) { $options['width'] = '100%'; $options['height'] = 'auto'; } } else { + $options['scale'] = 100; # scale is empty or 100 # There may be a fixed width applied though, in which case we need to leave the height empty if ( ! ( isset($options['width']) and $options['width'] ) ) { - $options['width'] = $monitor->ViewWidth().'px'; - if ( ! ( isset($options['height']) and $options['height'] ) ) { + # Havn't specified width. If we specified height, then we should + # use a width that keeps the aspect ratio, otherwise no scaling, + # no dimensions, so assume the dimensions of the Monitor + + if ( ! (isset($options['height']) and $options['height']) ) { + $options['width'] = $monitor->ViewWidth().'px'; $options['height'] = $monitor->ViewHeight().'px'; } - } else if ( ! isset($options['height']) ) { - $options['height'] = ''; - } + } else { + ZM\Warning("Have width ".$options['width']); + if ( preg_match('/^(\d+)px$/', $options['width'], $matches) ) { + $scale = intval(100*$matches[1]/$monitor->ViewWidth()); + ZM\Warning("Scale is $scale"); + if ( $scale < $options['scale'] ) + $options['scale'] = $scale; + } else if ( preg_match('/^(\d+)%$/', $options['width'], $matches) ) { + $scale = intval($matches[1]); + if ( $scale < $options['scale'] ) + $options['scale'] = $scale; + } else { + Warning("Invalid value for width: ".$options['width']); + } + } } if ( ! isset($options['mode'] ) ) { $options['mode'] = 'stream'; From 43b4177a5b7b7651c254e88d9a951d54b6ef1384 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 27 Aug 2020 08:14:45 -0400 Subject: [PATCH 106/117] fix crash due to incomplete code --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index d18df337c..852a05e9b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -82,7 +82,7 @@ sub Execute { my $self = $_[0]; my $sql = $self->Sql(undef); - if ( @{$$self{PreSQLConditions}} ) { + if ( $$self{PreSQLConditions} and @{$$self{PreSQLConditions}} ) { foreach my $term ( @{$$self{PreSQLConditions}} ) { if ( $$term{attr} eq 'DiskPercent' ) { } From 9b69eb576214106640290833ffa0afd2c37701a0 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 27 Aug 2020 07:35:05 -0500 Subject: [PATCH 107/117] fix corrupted merge conflict --- web/skins/classic/views/frames.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index b5017c5d9..4f850dc08 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -146,22 +146,20 @@ xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id()); - - - - - - - ->>>>>>> master + + + + + + - + - + Date: Thu, 27 Aug 2020 07:42:39 -0500 Subject: [PATCH 108/117] continue to fix corrupted merge conflict --- web/skins/classic/views/frames.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index 4f850dc08..ba1a3a229 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -146,20 +146,21 @@ xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id()); - - - - - - + + + + + + + - + - + Date: Thu, 27 Aug 2020 07:46:52 -0500 Subject: [PATCH 109/117] enable page-jump-to table extension --- web/css/bootstrap-table-page-jump-to.min.css | 10 ++++++++++ web/skins/classic/includes/functions.php | 2 ++ .../classic/js/bootstrap-table-page-jump-to.min.js | 10 ++++++++++ web/skins/classic/views/events.php | 1 + 4 files changed, 23 insertions(+) create mode 100644 web/css/bootstrap-table-page-jump-to.min.css create mode 100644 web/skins/classic/js/bootstrap-table-page-jump-to.min.js diff --git a/web/css/bootstrap-table-page-jump-to.min.css b/web/css/bootstrap-table-page-jump-to.min.css new file mode 100644 index 000000000..0c8e7d527 --- /dev/null +++ b/web/css/bootstrap-table-page-jump-to.min.css @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.17.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +.bootstrap-table.bootstrap3 .fixed-table-pagination>.pagination .page-jump-to,.bootstrap-table.bootstrap3 .fixed-table-pagination>.pagination ul.pagination{display:inline}.bootstrap-table .fixed-table-pagination>.pagination .page-jump-to input{width:70px;margin-left:5px;text-align:center;float:left} \ No newline at end of file diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index fff3618ad..5d9481471 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -88,6 +88,7 @@ echo output_cache_busted_stylesheet_links(array( 'css/font-awesome.min.css', 'css/bootstrap.min.css', 'css/bootstrap-table.min.css', + 'css/bootstrap-table-page-jump-to.min.css', )); echo output_link_if_exists(array( @@ -135,6 +136,7 @@ if ( $css != 'base' ) + diff --git a/web/skins/classic/js/bootstrap-table-page-jump-to.min.js b/web/skins/classic/js/bootstrap-table-page-jump-to.min.js new file mode 100644 index 000000000..f4bb237ad --- /dev/null +++ b/web/skins/classic/js/bootstrap-table-page-jump-to.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.17.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],n):n((t=t||self).jQuery)}(this,(function(t){"use strict";t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(t,n){return t(n={exports:{}},n.exports),n.exports}var r=function(t){return t&&t.Math==Math&&t},o=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n&&n)||Function("return this")(),i=function(t){try{return!!t()}catch(t){return!0}},u=!i((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})),c={}.propertyIsEnumerable,f=Object.getOwnPropertyDescriptor,a={f:f&&!c.call({1:2},1)?function(t){var n=f(this,t);return!!n&&n.enumerable}:c},l=function(t,n){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:n}},s={}.toString,p=function(t){return s.call(t).slice(8,-1)},y="".split,d=i((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==p(t)?y.call(t,""):Object(t)}:Object,h=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},b=function(t){return d(h(t))},v=function(t){return"object"==typeof t?null!==t:"function"==typeof t},g=function(t,n){if(!v(t))return t;var e,r;if(n&&"function"==typeof(e=t.toString)&&!v(r=e.call(t)))return r;if("function"==typeof(e=t.valueOf)&&!v(r=e.call(t)))return r;if(!n&&"function"==typeof(e=t.toString)&&!v(r=e.call(t)))return r;throw TypeError("Can't convert object to primitive value")},m={}.hasOwnProperty,w=function(t,n){return m.call(t,n)},O=o.document,j=v(O)&&v(O.createElement),S=function(t){return j?O.createElement(t):{}},T=!u&&!i((function(){return 7!=Object.defineProperty(S("div"),"a",{get:function(){return 7}}).a})),P=Object.getOwnPropertyDescriptor,E={f:u?P:function(t,n){if(t=b(t),n=g(n,!0),T)try{return P(t,n)}catch(t){}if(w(t,n))return l(!a.f.call(t,n),t[n])}},x=function(t){if(!v(t))throw TypeError(String(t)+" is not an object");return t},_=Object.defineProperty,A={f:u?_:function(t,n,e){if(x(t),n=g(n,!0),x(e),T)try{return _(t,n,e)}catch(t){}if("get"in e||"set"in e)throw TypeError("Accessors not supported");return"value"in e&&(t[n]=e.value),t}},M=u?function(t,n,e){return A.f(t,n,l(1,e))}:function(t,n,e){return t[n]=e,t},k=function(t,n){try{M(o,t,n)}catch(e){o[t]=n}return n},C=o["__core-js_shared__"]||k("__core-js_shared__",{}),I=Function.toString;"function"!=typeof C.inspectSource&&(C.inspectSource=function(t){return I.call(t)});var F,N,R,L=C.inspectSource,q=o.WeakMap,z="function"==typeof q&&/native code/.test(L(q)),D=e((function(t){(t.exports=function(t,n){return C[t]||(C[t]=void 0!==n?n:{})})("versions",[]).push({version:"3.6.0",mode:"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})})),G=0,J=Math.random(),W=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++G+J).toString(36)},B=D("keys"),K=function(t){return B[t]||(B[t]=W(t))},Q={},V=o.WeakMap;if(z){var X=new V,Y=X.get,$=X.has,H=X.set;F=function(t,n){return H.call(X,t,n),n},N=function(t){return Y.call(X,t)||{}},R=function(t){return $.call(X,t)}}else{var U=K("state");Q[U]=!0,F=function(t,n){return M(t,U,n),n},N=function(t){return w(t,U)?t[U]:{}},R=function(t){return w(t,U)}}var Z,tt,nt={set:F,get:N,has:R,enforce:function(t){return R(t)?N(t):F(t,{})},getterFor:function(t){return function(n){var e;if(!v(n)||(e=N(n)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return e}}},et=e((function(t){var n=nt.get,e=nt.enforce,r=String(String).split("String");(t.exports=function(t,n,i,u){var c=!!u&&!!u.unsafe,f=!!u&&!!u.enumerable,a=!!u&&!!u.noTargetGet;"function"==typeof i&&("string"!=typeof n||w(i,"name")||M(i,"name",n),e(i).source=r.join("string"==typeof n?n:"")),t!==o?(c?!a&&t[n]&&(f=!0):delete t[n],f?t[n]=i:M(t,n,i)):f?t[n]=i:k(n,i)})(Function.prototype,"toString",(function(){return"function"==typeof this&&n(this).source||L(this)}))})),rt=o,ot=function(t){return"function"==typeof t?t:void 0},it=function(t,n){return arguments.length<2?ot(rt[t])||ot(o[t]):rt[t]&&rt[t][n]||o[t]&&o[t][n]},ut=Math.ceil,ct=Math.floor,ft=function(t){return isNaN(t=+t)?0:(t>0?ct:ut)(t)},at=Math.min,lt=function(t){return t>0?at(ft(t),9007199254740991):0},st=Math.max,pt=Math.min,yt=function(t){return function(n,e,r){var o,i=b(n),u=lt(i.length),c=function(t,n){var e=ft(t);return e<0?st(e+n,0):pt(e,n)}(r,u);if(t&&e!=e){for(;u>c;)if((o=i[c++])!=o)return!0}else for(;u>c;c++)if((t||c in i)&&i[c]===e)return t||c||0;return!t&&-1}},dt={includes:yt(!0),indexOf:yt(!1)}.indexOf,ht=function(t,n){var e,r=b(t),o=0,i=[];for(e in r)!w(Q,e)&&w(r,e)&&i.push(e);for(;n.length>o;)w(r,e=n[o++])&&(~dt(i,e)||i.push(e));return i},bt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],vt=bt.concat("length","prototype"),gt={f:Object.getOwnPropertyNames||function(t){return ht(t,vt)}},mt={f:Object.getOwnPropertySymbols},wt=it("Reflect","ownKeys")||function(t){var n=gt.f(x(t)),e=mt.f;return e?n.concat(e(t)):n},Ot=function(t,n){for(var e=wt(n),r=A.f,o=E.f,i=0;i=74)&&(Z=Jt.match(/Chrome\/(\d+)/))&&(tt=Z[1]);var Qt,Vt=tt&&+tt,Xt=zt("species"),Yt=zt("isConcatSpreadable"),$t=Vt>=51||!i((function(){var t=[];return t[Yt]=!1,t.concat()[0]!==t})),Ht=(Qt="concat",Vt>=51||!i((function(){var t=[];return(t.constructor={})[Xt]=function(){return{foo:1}},1!==t[Qt](Boolean).foo}))),Ut=function(t){if(!v(t))return!1;var n=t[Yt];return void 0!==n?!!n:kt(t)};Mt({target:"Array",proto:!0,forced:!$t||!Ht},{concat:function(t){var n,e,r,o,i,u=Ct(this),c=Gt(u,0),f=0;for(n=-1,r=arguments.length;n9007199254740991)throw TypeError("Maximum allowed index exceeded");for(e=0;e=9007199254740991)throw TypeError("Maximum allowed index exceeded");It(c,f++,i)}return c.length=f,c}});var Zt,tn=function(t,n,e){if(function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function")}(t),void 0===n)return t;switch(e){case 0:return function(){return t.call(n)};case 1:return function(e){return t.call(n,e)};case 2:return function(e,r){return t.call(n,e,r)};case 3:return function(e,r,o){return t.call(n,e,r,o)}}return function(){return t.apply(n,arguments)}},nn=[].push,en=function(t){var n=1==t,e=2==t,r=3==t,o=4==t,i=6==t,u=5==t||i;return function(c,f,a,l){for(var s,p,y=Ct(c),h=d(y),b=tn(f,a,3),v=lt(h.length),g=0,m=l||Gt,w=n?m(c,v):e?m(c,0):void 0;v>g;g++)if((u||g in h)&&(p=b(s=h[g],g,y),t))if(n)w[g]=p;else if(p)switch(t){case 3:return!0;case 5:return s;case 6:return g;case 2:nn.call(w,s)}else if(o)return!1;return i?-1:r||o?o:w}},rn={forEach:en(0),map:en(1),filter:en(2),some:en(3),every:en(4),find:en(5),findIndex:en(6)},on=Object.keys||function(t){return ht(t,bt)},un=u?Object.defineProperties:function(t,n){x(t);for(var e,r=on(n),o=r.length,i=0;o>i;)A.f(t,e=r[i++],n[e]);return t},cn=it("document","documentElement"),fn=K("IE_PROTO"),an=function(){},ln=function(t){return"