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

This commit is contained in:
Isaac Connor 2020-09-28 16:14:07 -04:00
commit 3531b8a854
137 changed files with 3405 additions and 1998 deletions

View File

@ -1,6 +1,6 @@
language: cpp
sudo: required
dist: xenial
dist: bionic
git:
depth: 9999999
notifications:
@ -37,6 +37,7 @@ env:
- SMPFLAGS=-j4 OS=el DIST=8 DOCKER_REPO=knnniggett/packpack
- SMPFLAGS=-j4 OS=fedora DIST=31 DOCKER_REPO=knnniggett/packpack
- SMPFLAGS=-j4 OS=fedora DIST=32 DOCKER_REPO=knnniggett/packpack
- SMPFLAGS=-j4 OS=fedora DIST=33 DOCKER_REPO=knnniggett/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=focal DOCKER_REPO=iconzm/packpack

View File

@ -70,18 +70,19 @@ Docker is a system to run applications inside isolated containers. ZoneMinder, a
Dockerfile contained in this repository. However, there is still work needed to ensure that the main ZM features work
properly and are documented.
## Contribution Model and Development
## Contribution Model and Development
* Source hosted at [GitHub](https://github.com/ZoneMinder/ZoneMinder/)
* Report issues/questions/feature requests on [GitHub Issues](https://github.com/ZoneMinder/ZoneMinder/issues)
* Report issues at [GitHub Issues](https://github.com/ZoneMinder/ZoneMinder/issues)
* Questions/feature requests in [Slack](https://zoneminder-chat.slack.com/) or [forums](https://forums.zoneminder.com)
Pull requests are very welcome! If you would like to contribute, please follow
the following steps. While step 3 is optional, it is preferred.
1. Fork the repo
2. Open an issue at our [GitHub Issues Tracker](https://github.com/ZoneMinder/ZoneMinder/issues).
Describe the bug that you've found, or the feature which you're asking for.
Jot down the issue number (e.g. 456)
Follow the issue template to describe the bug or security issue you found. Please note feature
requests or questions should be posted in our user forum or Slack channel.
3. Create your feature branch (`git checkout -b 456-my-new-feature`)
4. Commit your changes (`git commit -am 'Added some feature'`)
It is preferred that you 'commit early and often' instead of bunching all

View File

@ -536,6 +536,8 @@ CREATE TABLE `Monitors` (
`ArchivedEventDiskSpace` bigint default NULL,
`ZoneCount` TINYINT NOT NULL DEFAULT 0,
`Refresh` int(10) unsigned default NULL,
`Latitude` DECIMAL(10,8),
`Longitude` DECIMAL(10,8),
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;

View File

@ -13,6 +13,8 @@ SET @s = (SELECT IF(
PREPARE stmt FROM @s;
EXECUTE stmt;
UPDATE `Events` SET `SaveJPEGs`=(SELECT `SaveJPEGs` FROM `Monitors` WHERE Monitors.Id = MonitorId) WHERE `SaveJPEGs` IS NULL;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Storage'

23
db/zm_update-1.35.7.sql Normal file
View File

@ -0,0 +1,23 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'Latitude'
) > 0,
"SELECT 'Column Latitude already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `Latitude` DECIMAL(10,8) AFTER `Refresh`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'Longitude'
) > 0,
"SELECT 'Column Longitude already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `Longitude` DECIMAL(10,8) AFTER `Latitude`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -5,6 +5,7 @@
Description=ZoneMinder CCTV recording and security system
After=network.target mariadb.service
Requires=mariadb.service
BindsTo=mariadb.service
[Service]
Type=forking

View File

@ -28,7 +28,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.35.6
Version: 1.35.7
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons
@ -206,8 +206,6 @@ mv -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Beh
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes
./utils/zmeditconfigdata.sh ZM_CHECK_FOR_UPDATES no
./utils/zmeditconfigdata.sh ZM_DYN_SHOW_DONATE_REMINDER no
./utils/zmeditconfigdata.sh ZM_OPT_FAST_DELETE no
%build
# Disable LTO due to top level asm

View File

@ -0,0 +1,91 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: zoneminder
# Required-Start: $network $remote_fs $syslog
# Required-Stop: $network $remote_fs $syslog
# Should-Start: mysql
# Should-Stop: mysql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Control ZoneMinder as a Service
# Description: ZoneMinder CCTV recording and surveillance system
### END INIT INFO
# chkconfig: 2345 20 20
# Source function library.
. /lib/lsb/init-functions
prog=ZoneMinder
ZM_PATH_BIN="/usr/bin"
RUNDIR="/run/zm"
TMPDIR="/tmp/zm"
command="$ZM_PATH_BIN/zmpkg.pl"
start() {
echo -n "Starting $prog: "
export TZ=:/etc/localtime
mkdir -p "$RUNDIR" && chown www-data:www-data "$RUNDIR"
mkdir -p "$TMPDIR" && chown www-data:www-data "$TMPDIR"
$command start
RETVAL=$?
[ $RETVAL = 0 ] && echo success
[ $RETVAL != 0 ] && echo failure
echo
[ $RETVAL = 0 ] && touch /var/lock/zm
return $RETVAL
}
stop() {
echo -n "Stopping $prog: "
#
# Why is this status check being done?
# as $command stop returns 1 if zoneminder
# is stopped, which will result in
# this returning 1, which will stuff
# dpkg when it tries to stop zoneminder before
# uninstalling . . .
#
result=`$command status`
if [ ! "$result" = "running" ]; then
echo "Zoneminder already stopped"
echo
RETVAL=0
else
$command stop
RETVAL=$?
[ $RETVAL = 0 ] && echo success
[ $RETVAL != 0 ] && echo failure
echo
[ $RETVAL = 0 ] && rm -f /var/lock/zm
fi
}
status() {
result=`$command status`
if [ "$result" = "running" ]; then
echo "ZoneMinder is running"
RETVAL=0
else
echo "ZoneMinder is stopped"
RETVAL=1
fi
}
case "$1" in
'start')
start
;;
'stop')
stop
;;
'restart' | 'force-reload')
stop
start
;;
'status')
status
;;
*)
echo "Usage: $0 { start | stop | restart | status }"
RETVAL=1
;;
esac
exit $RETVAL

View File

@ -2,13 +2,47 @@
set +e
create_db () {
echo "Checking for db"
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
# test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
echo "Creating zm db"
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
if [ $? -ne 0 ]; then
echo "Error creating db."
exit 1;
fi
else
echo "Db exists."
fi
USER_EXISTS="$(mysql --defaults-file=/etc/mysql/debian.cnf -sse "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '$ZM_DB_USER')")"
if [ $USER_EXISTS -ne 1 ]; then
echo "Creating zm user $ZM_DB_USER"
# This creates the user.
echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
}
update_db () {
echo "Updating permissions"
echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
# Add any new PTZ control configurations to the database (will not overwrite)
zmcamtool.pl --import >/dev/null 2>&1
echo "Done Updating"
}
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
for CONFFILE in /etc/zm/conf.d/*.conf; do
. "$CONFFILE"
done
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
chown www-data:root /var/log/zm
chown www-data:www-data /var/lib/zm
@ -20,16 +54,24 @@ if [ "$1" = "configure" ]; then
a2enmod cgi
fi
SYSTEMD=0
if [ -e "/run/systemd/system" ]; then
SYSTEMD=1
echo "detected systemd"
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
else
# Ensure zoneminder is stopped
invoke-rc.d zoneminder stop || true
fi
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/lib/systemd/system/mysql.service" ] || [ -e "/lib/systemd/system/mariadb.service" ] || [ -e "/etc/init.d/mysql" ]; then
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
if [ $SYSTEMD -eq 1 ] && ([ -e "/lib/systemd/system/mysql.service" ] || [ -e "/lib/systemd/system/mariadb.service" ]); then
#
# Get mysql started if it isn't running
#
if [ -e "/lib/systemd/system/mariadb.service" ]; then
DBSERVICE="mariadb.service"
else
@ -42,48 +84,48 @@ if [ "$1" = "configure" ]; then
echo "run sudo systemctl restart $DBSERVICE then run sudo dpkg-reconfigure zoneminder."
exit 1
fi
if ! systemctl is-active --quiet mysql.service mariadb.service; then
# Due to /etc/init.d service autogeneration, mysql.service always returns the status of mariadb.service
# However, mariadb.service will not return the status of mysql.service.
deb-systemd-invoke start $DBSERVICE
fi
# Make sure systemctl status exit code is 0; i.e. the DB is running
if systemctl is-active --quiet "$DBSERVICE"; then
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
# test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
echo "Creating zm db"
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
if [ $? -ne 0 ]; then
echo "Error creating db."
exit 1;
fi
# This creates the user.
echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
echo "Updating permissions"
echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
# Add any new PTZ control configurations to the database (will not overwrite)
zmcamtool.pl --import >/dev/null 2>&1
echo "Done Updating; starting ZoneMinder."
create_db
update_db
else
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
elif [ -e "/etc/init.d/mysql" ]; then
#
# Get mysql started if it isn't
#
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
service mysql start
fi
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
create_db
update_db
else
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo 'MySQL/MariaDB not found; assuming remote server.'
fi
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)."
fi
deb-systemd-invoke restart zoneminder.service
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)."
fi
if [ $SYSTEMD -eq 1 ]; then
deb-systemd-invoke restart zoneminder.service
#else
#service zoneminder start || true
fi
#DEBHELPER#

View File

@ -51,7 +51,7 @@ This screen is called the "console" screen in ZoneMinder and shows a summary of
* **A**: The options menu lets you configure many aspects of ZoneMinder. Refer to :doc:`options`.
* **B**: This brings up a color coded log window that shows various system and component level logs. This window is useful if you are trying to diagnose issues. Refer to :doc:`logging`.
* **C**: ZoneMinder allows you to group monitors gor logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups.
* **C**: ZoneMinder allows you to group monitors for logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups.
* **D**: Filters are a powerful mechanism to perform actions when certain conditions are met. ZoneMinder comes with some preset filters that keep a tab of disk space and others. Many users create their own filters for more advanced actions like sending emails when certain events occur and more. Refer to :doc:`filterevents`.
* **E**: The Cycle option allows you to rotate between live views of each cofigured monitor.
* **F**: The Montage option shows a collage of your monitors. You can customize them including moving them around.

View File

@ -1,40 +0,0 @@
{
"abstract" : "unknown",
"author" : [
"Jan Hochstein"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010",
"license" : [
"unknown"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "ONVIF",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {}
}
},
"release_status" : "stable",
"version" : "",
"x_serialization_backend" : "JSON::PP version 4.02"
}

View File

@ -1,22 +0,0 @@
---
abstract: unknown
author:
- 'Jan Hochstein'
build_requires:
ExtUtils::MakeMaker: '0'
configure_requires:
ExtUtils::MakeMaker: '0'
dynamic_config: 0
generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010'
license: unknown
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: ONVIF
no_index:
directory:
- t
- inc
requires: {}
version: ''
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'

View File

@ -1,40 +0,0 @@
{
"abstract" : "unknown",
"author" : [
"Jan Hochstein"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010",
"license" : [
"unknown"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "ONVIF",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {}
}
},
"release_status" : "stable",
"version" : "",
"x_serialization_backend" : "JSON::PP version 4.02"
}

View File

@ -1,22 +0,0 @@
---
abstract: unknown
author:
- 'Jan Hochstein'
build_requires:
ExtUtils::MakeMaker: '0'
configure_requires:
ExtUtils::MakeMaker: '0'
dynamic_config: 0
generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010'
license: unknown
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: ONVIF
no_index:
directory:
- t
- inc
requires: {}
version: ''
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'

View File

View File

@ -479,6 +479,33 @@ our @options = (
type => $types{string},
category => 'system',
},
{
name => 'ZM_OPT_USE_GEOLOCATION',
description => 'Add geolocation features to ZoneMinder.',
help => 'Whether or not to enable Latitude/Longitude settings on Monitors and enable mapping options.',
type => $types{boolean},
category => 'system',
},
{
name => 'ZM_OPT_GEOLOCATION_TILE_PROVIDER',
description => 'Tile provider to use for maps.',
help => 'OpenStreetMaps does not itself provide the images to use in the map. There are many to choose from. Mapbox.com is one example that offers free tiles and has been tested during development of this feature.',
requires => [
{name=>'ZM_OPT_USE_GEOLOCATION', value=>'yes'}
],
type => $types{string},
category => 'system',
},
{
name => 'ZM_OPT_GEOLOCATION_ACCESS_TOKEN',
description => 'Access Token for the tile provider used for maps.',
help => 'OpenStreetMaps does not itself provide the images to use in the map. There are many to choose from. Mapbox.com is one example that offers free tiles and has been tested during development of this feature. You must go to mapbox.com and sign up and get an access token and cutnpaste it here.',
requires => [
{name=>'ZM_OPT_USE_GEOLOCATION', value=>'yes'}
],
type => $types{string},
category => 'system',
},
{
name => 'ZM_SYSTEM_SHUTDOWN',
default => 'true',
@ -2621,7 +2648,7 @@ our @options = (
},
{
name => 'ZM_WEB_EVENT_SORT_FIELD',
default => 'DateTime',
default => 'StartDateTime',
description => 'Default field the event lists are sorted by',
help => q`
Events in lists can be initially ordered in any way you want.
@ -2633,7 +2660,7 @@ our @options = (
`,
type => {
db_type =>'string',
hint =>'Id|Name|Cause|MonitorName|DateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore',
hint =>'Id|Name|Cause|DiskSpace|MonitorName|StartDateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore',
pattern =>qr|.|,
format =>q( $1 )
},

View File

@ -146,15 +146,15 @@ sub zmDbGetMonitors {
if ( $function ) {
if ( $function == DB_MON_CAPT ) {
$sql .= " where `Function` >= 'Monitor'";
$sql .= " WHERE `Function` >= 'Monitor'";
} elsif ( $function == DB_MON_ACTIVE ) {
$sql .= " where `Function` > 'Monitor'";
$sql .= " WHERE `Function` > 'Monitor'";
} elsif ( $function == DB_MON_MOTION ) {
$sql .= " where `Function` = 'Modect' or Function = 'Mocord'";
$sql .= " WHERE `Function` = 'Modect' OR `Function` = 'Mocord'";
} elsif ( $function == DB_MON_RECORD ) {
$sql .= " where `Function` = 'Record' or Function = 'Mocord'";
$sql .= " WHERE `Function` = 'Record' OR `Function` = 'Mocord'";
} elsif ( $function == DB_MON_PASSIVE ) {
$sql .= " where `Function` = 'Nodect'";
$sql .= " WHERE `Function` = 'Nodect'";
}
}
my $sth = $dbh->prepare_cached( $sql );

View File

@ -83,7 +83,7 @@ if ( $options{command} ) {
my $server_up;
while ( $tries and ! ( $server_up = connect(CLIENT, $saddr) ) ) {
Debug("Failed to connect to zmcontrol server at $sock_file");
runCommand("zmdc.pl start zmcontrol.pl --id=$id");
runCommand("zmdc.pl start zmcontrol.pl --id $id");
sleep 1;
$tries -= 1;
}
@ -142,9 +142,9 @@ if ( $options{command} ) {
.strftime('%y/%m/%d %H:%M:%S', localtime())
);
$0 = $0." --id=$id";
$0 = $0.' --id '.$id;
my $control = "ZoneMinder::Control::$protocol"->new($id);
my $control = ('ZoneMinder::Control::'.$protocol)->new($id);
my $control_key = $control->getKey();
$control->loadMonitor();

View File

@ -691,6 +691,7 @@ sub substituteTags {
$text =~ s/%EC%/$Event->{Cause}/g;
$text =~ s/%ED%/$Event->{Notes}/g;
$text =~ s/%ET%/$Event->{StartTime}/g;
$text =~ s/%EVF%/$$Event{DefaultVideo}/g; # Event video filename
$text =~ s/%EL%/$Event->{Length}/g;
$text =~ s/%EF%/$Event->{Frames}/g;
$text =~ s/%EFA%/$Event->{AlarmFrames}/g;
@ -1017,8 +1018,7 @@ sub executeCommand {
my $event_path = $Event->Path();
my $command = $filter->{AutoExecuteCmd};
$command .= " $event_path";
my $command = $filter->{AutoExecuteCmd}.' '.$event_path;
$command = substituteTags($command, $filter, $Event);
Info("Executing '$command'");

View File

@ -280,8 +280,8 @@ Event::~Event() {
// Should not be static because we might be multi-threaded
char sql[ZM_SQL_LGE_BUFSIZ];
snprintf(sql, sizeof(sql),
"UPDATE Events SET Name='%s%" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
snprintf(sql, sizeof(sql),
"UPDATE Events SET Name='%s%" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'",
monitor->EventPrefix(), id, end_time.tv_sec,
delta_time.positive?"":"-", delta_time.sec, delta_time.fsec,
frames, alarm_frames,
@ -294,6 +294,22 @@ Event::~Event() {
sleep(1);
db_mutex.lock();
}
if ( !mysql_affected_rows(&dbconn) ) {
// Name might have been changed during recording, so just do the update without changing the name.
snprintf(sql, sizeof(sql),
"UPDATE Events SET EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
end_time.tv_sec,
delta_time.positive?"":"-", delta_time.sec, delta_time.fsec,
frames, alarm_frames,
tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score,
id);
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
db_mutex.unlock();
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
sleep(1);
db_mutex.lock();
}
} // end if no changed rows due to Name change during recording
db_mutex.unlock();
} // Event::~Event()

View File

@ -88,7 +88,7 @@ public:
} Orientation;
typedef enum {
UNKNOWN,
UNKNOWN=-1,
IDLE,
PREALARM,
ALARM,

View File

@ -247,7 +247,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
if ( config.record_diag_images_fifo ) {
FifoDebug(5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}",
id,alarm_pixels, pixel_diff);
id, alarm_pixels, pixel_diff);
}
if ( alarm_pixels ) {
@ -264,11 +264,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
return false;
}
if ( max_alarm_pixels != 0 )
score = (100*alarm_pixels)/max_alarm_pixels;
else
score = (100*alarm_pixels)/polygon.Area();
score = (100*alarm_pixels)/(max_alarm_pixels?max_alarm_pixels:polygon.Area());
if ( score < 1 )
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
Debug(5, "Current score is %d", score);
@ -358,8 +354,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
if ( check_method >= BLOBS ) {
Debug(5, "Checking for blob pixels");
typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats;
BlobStats blob_stats[256];
// ICON FIXME Would like to get rid of this memset
memset(blob_stats, 0, sizeof(BlobStats)*256);
uint8_t *spdiff;
uint8_t last_x, last_y;
@ -369,22 +364,15 @@ bool Zone::CheckAlarms(const Image *delta_image) {
int lo_x = ranges[y].lo_x;
int hi_x = ranges[y].hi_x;
pdiff = (uint8_t*)diff_image->Buffer( lo_x, y );
pdiff = (uint8_t*)diff_image->Buffer(lo_x, y);
for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) {
if ( *pdiff == WHITE ) {
Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff);
//last_x = (x>lo_x)?*(pdiff-1):0;
//last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0;
last_x = 0;
if ( x > 0 ) {
if ( (x-1) >= lo_x ) {
last_x = *(pdiff-1);
}
}
last_x = ((x > 0) && ( (x-1) >= lo_x )) ? *(pdiff-1) : 0;
last_y = 0;
if (y > 0 ) {
if ( y > 0 ) {
if ( (y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x ) {
last_y = *(pdiff-diff_width);
}
@ -631,7 +619,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
}
if ( max_blob_pixels != 0 )
score = (100*alarm_blob_pixels)/(max_blob_pixels);
score = (100*alarm_blob_pixels)/max_blob_pixels;
else
score = (100*alarm_blob_pixels)/polygon.Area();
@ -758,67 +746,42 @@ bool Zone::CheckAlarms(const Image *delta_image) {
}
bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) {
Debug(3, "Parsing polygon string '%s'", poly_string);
char *str_ptr = new char[strlen(poly_string)+1];
char *str = str_ptr;
strcpy(str, poly_string);
char *str = (char *)poly_string;
char *ws;
char *cp;
int n_coords = 0;
int max_n_coords = strlen(str)/4;
Coord *coords = new Coord[max_n_coords];
while( true ) {
if ( *str == '\0' ) {
break;
}
ws = strchr(str, ' ');
if ( ws ) {
*ws = '\0';
}
char *cp = strchr(str, ',');
while ( *str != '\0' ) {
cp = strchr(str, ',');
if ( !cp ) {
Error("Bogus coordinate %s found in polygon string", str);
delete[] coords;
delete[] str_ptr;
return false;
} else {
*cp = '\0';
char *xp = str;
char *yp = cp+1;
break;
}
int x = atoi(str);
int y = atoi(cp+1);
Debug(3, "Got coordinate %d,%d from polygon string", x, y);
coords[n_coords++] = Coord(x, y);
int x = atoi(xp);
int y = atoi(yp);
Debug(3, "Got coordinate %d,%d from polygon string", x, y);
#if 0
if ( x < 0 )
x = 0;
else if ( x >= width )
x = width-1;
if ( y < 0 )
y = 0;
else if ( y >= height )
y = height-1;
#endif
coords[n_coords++] = Coord( x, y );
}
ws = strchr(cp+2, ' ');
if ( ws )
str = ws+1;
else
break;
}
polygon = Polygon(n_coords, coords);
} // end while ! end of string
Debug(3, "Successfully parsed polygon string");
//printf( "Area: %d\n", pg.Area() );
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
if ( n_coords > 2 ) {
Debug(3, "Successfully parsed polygon string %s", str);
polygon = Polygon(n_coords, coords);
} else {
Error("Not enough coordinates to form a polygon!");
n_coords = 0;
}
delete[] coords;
delete[] str_ptr;
return true;
}
return n_coords ? true : false;
} // end bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon)
bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) {
Debug(3, "Parsing zone string '%s'", zone_string);
@ -827,13 +790,12 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P
char *str = str_ptr;
strcpy(str, zone_string);
zone_id = strtol(str, 0, 10);
Debug(3, "Got zone %d from zone string", zone_id);
char *ws = strchr(str, ' ');
if ( !ws ) {
Debug(3, "No initial whitespace found in zone string '%s', finishing", str);
}
zone_id = strtol(str, 0, 10);
Debug(3, "Got zone %d from zone string", zone_id);
if ( !ws ) {
delete[] str_ptr;
return true;
}
@ -841,13 +803,11 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P
*ws = '\0';
str = ws+1;
colour = strtol(str, 0, 16);
Debug(3, "Got colour %06x from zone string", colour);
ws = strchr(str, ' ');
if ( !ws ) {
Debug(3, "No secondary whitespace found in zone string '%s', finishing", zone_string);
}
colour = strtol(str, 0, 16);
Debug(3, "Got colour %06x from zone string", colour);
if ( !ws ) {
delete[] str_ptr;
return true;
}
@ -855,27 +815,28 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P
str = ws+1;
bool result = ParsePolygonString(str, polygon);
//printf( "Area: %d\n", pg.Area() );
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
delete[] str_ptr;
return result;
}
} // end bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon)
int Zone::Load(Monitor *monitor, Zone **&zones) {
static char sql[ZM_SQL_MED_BUFSIZ];
db_mutex.lock();
snprintf(sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id());
snprintf(sql, sizeof(sql), "SELECT Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,"
"MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,"
"FilterX,FilterY,MinFilterPixels,MaxFilterPixels,"
"MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,"
"OverloadFrames,ExtendAlarmFrames"
" FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id());
if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn));
db_mutex.unlock();
return 0;
}
MYSQL_RES *result = mysql_store_result( &dbconn );
MYSQL_RES *result = mysql_store_result(&dbconn);
if ( !result ) {
Error("Can't use query result: %s", mysql_error(&dbconn));
db_mutex.unlock();
@ -944,7 +905,13 @@ int Zone::Load(Monitor *monitor, Zone **&zones) {
} else if ( atoi(dbrow[2]) == Zone::PRIVACY ) {
zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon);
}
zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames);
zones[i] = new Zone(
monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB,
(Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold,
MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ),
MinFilterPixels, MaxFilterPixels,
MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs,
OverloadFrames, ExtendAlarmFrames);
} // end foreach row
mysql_free_result(result);
return n_zones;
@ -953,9 +920,9 @@ int Zone::Load(Monitor *monitor, Zone **&zones) {
bool Zone::DumpSettings(char *output, bool /*verbose*/) {
output[0] = 0;
sprintf( output+strlen(output), " Id : %d\n", id );
sprintf( output+strlen(output), " Label : %s\n", label );
sprintf( output+strlen(output), " Type: %d - %s\n", type,
sprintf(output+strlen(output), " Id : %d\n", id );
sprintf(output+strlen(output), " Label : %s\n", label );
sprintf(output+strlen(output), " Type: %d - %s\n", type,
type==ACTIVE?"Active":(
type==INCLUSIVE?"Inclusive":(
type==EXCLUSIVE?"Exclusive":(
@ -1020,10 +987,10 @@ void Zone::std_alarmedpixels(
*pdiff = BLACK;
}
}
}
} // end for y = lo_y to hi_y
/* Store the results */
*pixel_count = pixelsalarmed;
*pixel_sum = pixelsdifference;
Debug(7, "STORED pixelsalarmed(%d), pixelsdifference(%d)", pixelsalarmed, pixelsdifference);
}
} // end void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsigned int* pixel_count, unsigned int* pixel_sum)

View File

@ -32,15 +32,14 @@ class Monitor;
// This describes a 'zone', or an area of an image that has certain
// detection characteristics.
//
class Zone
{
class Zone {
protected:
struct Range
{
struct Range {
int lo_x;
int hi_x;
int off_x;
};
typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats;
public:
typedef enum { ACTIVE=1, INCLUSIVE, EXCLUSIVE, PRECLUSIVE, INACTIVE, PRIVACY } ZoneType;
@ -52,8 +51,8 @@ protected:
int id;
char *label;
ZoneType type;
Polygon polygon;
ZoneType type;
Polygon polygon;
Rgb alarm_rgb;
CheckMethod check_method;
@ -67,17 +66,18 @@ protected:
int min_filter_pixels;
int max_filter_pixels;
BlobStats blob_stats[256];
int min_blob_pixels;
int max_blob_pixels;
int min_blobs;
int max_blobs;
int overload_frames;
int overload_frames;
int extend_alarm_frames;
// Outputs/Statistics
bool alarmed;
bool was_alarmed;
bool alarmed;
bool was_alarmed;
int pixel_diff;
unsigned int alarm_pixels;
int alarm_filter_pixels;
@ -139,8 +139,7 @@ public:
inline Coord GetAlarmCentre() const { return( alarm_centre ); }
inline unsigned int Score() const { return( score ); }
inline void ResetStats()
{
inline void ResetStats() {
alarmed = false;
was_alarmed = false;
pixel_diff = 0;

View File

@ -156,10 +156,14 @@ if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
if [ -d "${GITHUB_FORK}_ZoneMinder.git" ]; then
echo "Using local clone ${GITHUB_FORK}_ZoneMinder.git to pull from."
cd "${GITHUB_FORK}_ZoneMinder.git"
echo "git pull..."
git pull
echo "git fetch..."
git fetch
echo "git checkout $BRANCH"
git checkout $BRANCH
if [ $? -ne 0 ]; then
echo "Failed to switch to branch."
exit 1;
fi;
echo "git pull..."
git pull
cd ../
@ -335,7 +339,7 @@ EOF
dput="Y";
if [ "$INTERACTIVE" != "no" ]; then
read -p "Ready to dput $SC to $PPA ? Y/N...";
read -p "Ready to dput $SC to $PPA ? Y/n...";
if [[ "$REPLY" == [yY] ]]; then
dput $PPA $SC
fi;

View File

@ -361,7 +361,7 @@ elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbia
execpackpack
# Try to install and run the newly built zoneminder package
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "xenial" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "bionic" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
echo "Begin Deb package installation..."
install_deb
fi

45
utils/resample_event_video.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/sh
FFMPEG=`which ffmpeg`;
if [ -z "$FFMPEG" ]; then
echo "You must install the ffmpeg package. Try sudo apt-get install ffmpeg";
exit;
fi
for i in "$@"
do
case $i in
-r=*|--rate=*)
FPS="${i#*=}"
shift
;;
-f=*|--file=*)
VIDEO_FILE="${i#*=}"
shift
;;
*)
EVENT_PATH="${i#*=}"
shift
;;
esac
done
if [ -z "$EVENT_PATH" ]; then
echo "You must specify the path to the event.";
exit 255
fi;
if [ -z "$FPS" ]; then
echo "You must specify the new fps.";
exit 255
fi;
$FFMPEG -i "$EVENT_PATH/$VIDEO_FILE" -filter:v fps=fps=$FPS "$EVENT_PATH/output.mp4"
echo $?
if [ $? -eq 0 ]; then
mv "$EVENT_PATH/output.mp4" "$EVENT_PATH/$VIDEO_FILE"
fi;
exit 0;

View File

@ -1 +1 @@
1.35.6
1.35.7

33
web/ajax/controlcaps.php Normal file
View File

@ -0,0 +1,33 @@
<?php
if ( !canEdit('Control') ) {
ZM\Warning('Need Control permissions to edit control capabilities');
return;
}
if ( empty($_REQUEST['action']) ) {
ajaxError('Action Not Provided');
return;
} else {
$action = $_REQUEST['action'];
}
if ( isset($_REQUEST['cids']) ) {
$cids = $_REQUEST['cids'];
} else {
ajaxError('At least one Control Id must be Provided.');
return;
}
if ( $action == 'delete' ) {
foreach( $cids as $cid ) {
dbQuery('UPDATE Monitors SET Controllable = 0, ControlId = 0 WHERE ControlId = ?', array($cid));
dbQuery('DELETE FROM Controls WHERE Id = ?', array($cid));
}
} else {
ajaxError('Unrecognised action ' .$_REQUEST['action']);
return;
}
ajaxResponse();
return;
?>

View File

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

View File

@ -185,7 +185,7 @@ switch ( $_REQUEST['task'] ) {
$Servers = ZM\Server::find();
$servers_by_Id = array();
# There is probably a better way to do this.
foreach ( $servers as $server ) {
foreach ( $Servers as $server ) {
$servers_by_Id[$server->Id()] = $server;
}
@ -245,6 +245,9 @@ switch ( $_REQUEST['task'] ) {
}
$exportKey = substr(md5(rand()), 0, 8);
$exportFile = 'zm-log.'.$exportExt;
// mkdir will generate a warning if it exists, but that is ok
error_reporting(0);
if ( ! ( mkdir(ZM_DIR_EXPORTS) || file_exists(ZM_DIR_EXPORTS) ) ) {
ZM\Fatal('Can\'t create exports dir at \''.ZM_DIR_EXPORTS.'\'');
}
@ -371,8 +374,16 @@ switch ( $_REQUEST['task'] ) {
<'.strtolower($field).'>'.htmlspecialchars($value).'</'.strtolower($field).'>
</filter>' );
fwrite( $exportFP,
' <columns>
<column field="datetime">'.translate('DateTime').'</column><column field="component">'.translate('Component').'</column><column field="'.translate('Server').'</column><column field="pid">'.translate('Pid').'</column><column field="level">'.translate('Level').'</column><column field="message">'.translate('Message').'</column><column field="file">'.translate('File').'</column><column field="line">'.translate('Line').'</column>
'
<columns>
<column field="datetime">'.translate('DateTime').'</column>
<column field="component">'.translate('Component').'</column>
<column field="server">'.translate('Server').'</column>
<column field="pid">'.translate('Pid').'</column>
<column field="level">'.translate('Level').'</column>
<column field="message">'.translate('Message').'</column>
<column field="file">'.translate('File').'</column>
<column field="line">'.translate('Line').'</column>
</columns>
<logs count="'.count($logs).'">
' );

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

@ -0,0 +1,24 @@
<?php
if ( empty($_REQUEST['modal']) ) {
ajaxError('Modal Name Not Provided');
return;
}
$modal = validJsStr($_REQUEST['modal']);
$data = array();
ZM\Logger::Debug("Including modals/$modal.php");
# Shouldn't be necessary but at the moment we have last .conf file contents
ob_start();
@$result = include('modals/'.$modal.'.php');
$data['html'] = ob_get_contents();
ob_end_clean();
if ( !$result ) {
ajaxError("Unknown modal '".$modal."'");
return;
}
ajaxResponse($data);
return;
?>

View File

@ -0,0 +1,26 @@
<?php
// This is the HTML representing the Delete confirmation modal on the Events page and other pages
$delTextKey = isset($_REQUEST['key']) ? $_REQUEST['key'] : 'ConfirmDeleteEvents';
?>
<div id="deleteConfirm" class="modal fade" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('ConfirmDeleteTitle') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p><?php echo translate($delTextKey) ?></p>
</div>
<div class="modal-footer">
<button id="delCancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
<button id ="delConfirmBtn" type="button" class="btn btn-danger"><?php echo translate('Delete') ?></button>
</div>
</div>
</div>
</div>

View File

@ -18,10 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit('System') ) {
$view = 'error';
return;
}
if ( !canEdit('System') ) return;
$options = array(
'go' => translate('DonateYes'),
@ -45,25 +42,25 @@ $options = array(
</button>
</div>
<div class="modal-body">
<form name="contentForm" id="contentForm" method="post" action="?">
<input type="hidden" name="view" value="donate"/>
<input type="hidden" name="action" value="donate"/>
<p>
<?php echo translate('DonateEnticement') ?>
</p>
<p>
<?php echo buildSelect('option', $options); ?>
</p>
<div id="contentButtons">
<button type="submit"><?php echo translate('Apply') ?></button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Close') ?></button>
</div>
</form>
<form name="contentForm" id="donateForm" method="post" action="?">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="donate"/>
<input type="hidden" name="action" value="donate"/>
<p>
<?php echo translate('DonateEnticement') ?>
</p>
<p>
<?php echo buildSelect('option', $options); ?>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Understood</button>
<button type="submit" class="btn btn-primary" id="donateApplyBtn"><?php echo translate('Apply') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Close') ?></button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,24 @@
<?php
// Return an Error No Permissions Modal
?>
<div id="ENoPerm" class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">ZoneMinder <?php echo translate('Error') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p><?php echo translate('YouNoPerms') ?></p>
<p><?php echo translate('ContactAdmin') ?></p>
</div>
<div class="modal-footer">
<button type="button" id="enpCloseBtn" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,89 @@
<?php
// This is the HTML representing the Event Detail modal on the Events page
$eid = isset($_REQUEST['eid']) ? $_REQUEST['eid'] : '';
$eids = isset($_REQUEST['eids']) ? $_REQUEST['eids'] : '';
$result = '';
$inputs = '';
$disabled = 'disabled="disabled"';
$null = '';
if ( !canEdit('Events') ) return;
if ( $eid ){ // Single Event Mode
$eid = validInt($eid);
$title = translate('Event').' '.$eid.PHP_EOL;
$inputs .= '<input type="hidden" name="markEids[]" value="' .$eid. '"/>';
$newEvent = dbFetchOne('SELECT E.* FROM Events AS E WHERE E.Id = ?', NULL, array($eid));
} elseif ( $eids ) { // Multi Event Mode
$title = translate('Events');
$sql = 'SELECT E.* FROM Events AS E WHERE ';
$sqlWhere = array();
$sqlValues = array();
foreach ( $eids as $eid ) {
$eid = validInt($eid);
$inputs .= '<input type="hidden" name="markEids[]" value="' .$eid. '"/>';
$sqlWhere[] = 'E.Id = ?';
$sqlValues[] = $eid;
}
unset($eid);
$sql .= join(' OR ', $sqlWhere);
foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row ) {
if ( !isset($newEvent) ) {
$newEvent = $row;
} else {
if ( $newEvent['Cause'] && $newEvent['Cause'] != $row['Cause'] )
$newEvent['Cause'] = '';
if ( $newEvent['Notes'] && $newEvent['Notes'] != $row['Notes'] )
$newEvent['Notes'] = '';
}
}
} else { // Event Mode not specified - should we really proceed if neither eid nor eids is set?
$title = translate('Events');
}
?>
<div class="modal fade" id="eventDetailModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo $title ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form name="contentForm" id="eventDetailForm" method="post" action="?view=eventdetail&action=eventdetail">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
echo $inputs;
?>
<input type="hidden" name="action" value="eventdetail"/>
<input type="hidden" name="view" value="eventdetail"/>
<table class="table-sm">
<tbody>
<tr>
<th scope="row"><?php echo translate('Cause') ?></th>
<td><input type="text" name="newEvent[Cause]" value="<?php echo validHtmlStr($newEvent['Cause']) ?>" size="32"/></td>
</tr>
<tr>
<th scope="row" class="align-middle"><?php echo translate('Notes') ?></th>
<td><textarea name="newEvent[Notes]" rows="6" cols="33"><?php echo validHtmlStr($newEvent['Notes']) ?></textarea></td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="submit" name="action" id="eventDetailSaveBtn" class="btn btn-primary" value="save" <?php echo !canEdit('Events') ? $disabled : $null .'>'. translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,35 @@
<div class="modal fade" id="filterdebugModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('FilterDebug') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<?php
//require_once('includes/Filter.php');
$fid = validInt($_REQUEST['fid']);
if ( !$fid ) {
echo '<div class="error">No filter id specified.</div>';
} else {
$filter = new ZM\Filter($_REQUEST['fid']);
if ( ! $filter->Id() ) {
echo '<div class="error">Filter not found for id '.$_REQUEST['fid'].'</div>';
}
}
?>
<form name="contentForm" id="filterdebugForm" method="post" action="?">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<p><label>SQL</label><?php echo $filter->sql() ?></p>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel')?> </button>
</div>
</form>
</div>
</div>
</div>

View File

@ -18,17 +18,18 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit('Monitors') ) {
$view = 'error';
return;
}
?>
if ( !canEdit('Monitors') ) return;
?>
<div id="modalFunction" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form id="function_form" action="?view=function&action=function" method="post">
<input type="hidden" name="mid"/>
<form id="function_form" action="?view=function&action=function" method="post">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="mid"/>
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('Function') ?> - <span id="function_monitor_name"></span></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
@ -46,7 +47,7 @@ if ( !canEdit('Monitors') ) {
<button type="button" class="funcSaveBtn btn btn-primary"><?php echo translate('Save') ?></button>
<button type="button" class="funcCancelBtn btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
</form>
</div>
</div>
</div>

135
web/ajax/modals/group.php Normal file
View File

@ -0,0 +1,135 @@
<?php
// This is the HTML representing the Group modal accessed from the Groups (plural) view
//
// DEFINE SUPPORTING FUNCTIONS
//
function get_Id( $G ) {
return $G->Id();
}
function get_children($Group) {
global $children;
$kids = array();
if ( isset( $children[$Group->Id()] ) ) {
$kids += array_map('get_Id', $children[$Group->Id()]);
foreach ( $children[$Group->Id()] as $G ) {
foreach ( get_children($G) as $id ) {
$kids[] = $id;
}
}
}
return $kids;
}
function parentGrpSelect($newGroup) {
$Groups = array();
foreach ( ZM\Group::find() as $Group ) {
$Groups[$Group->Id()] = $Group;
}
# This array is indexed by parent_id
$children = array();
foreach ( $Groups as $id=>$Group ) {
if ( $Group->ParentId() != null ) {
if ( ! isset( $children[$Group->ParentId()] ) )
$children[$Group->ParentId()] = array();
$children[$Group->ParentId()][] = $Group;
}
}
$kids = get_children($newGroup);
if ( $newGroup->Id() )
$kids[] = $newGroup->Id();
$sql = 'SELECT Id,Name FROM `Groups`'.(count($kids)?' WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids)).')' : '').' ORDER BY Name';
$options = array(''=>'None');
foreach ( dbFetchAll($sql, null, $kids) as $option ) {
$options[$option['Id']] = str_repeat('&nbsp;&nbsp;', $Groups[$option['Id']]->depth()) . $option['Name'];
}
return htmlSelect('newGroup[ParentId]', $options, $newGroup->ParentId(), array('data-on-change'=>'configModalBtns'));
}
function monitorList($newGroup) {
$result = '';
$monitors = dbFetchAll('SELECT Id,Name FROM Monitors ORDER BY Sequence ASC');
$monitorIds = $newGroup->MonitorIds();
foreach ( $monitors as $monitor ) {
if ( visibleMonitor($monitor['Id']) ) {
$result .= '<option value="' .$monitor['Id']. '"' .( in_array( $monitor['Id'], $monitorIds ) ? ' selected="selected"' : ''). '>' .validHtmlStr($monitor['Name']). '</option>'.PHP_EOL;
}
}
return $result;
}
//
// INITIAL SANITY CHECKS
//
if ( !canEdit('Groups') ) {
$view = 'error';
return;
}
if ( !empty($_REQUEST['gid']) ) {
$newGroup = new ZM\Group($_REQUEST['gid']);
} else {
$newGroup = new ZM\Group();
}
//
// BEGIN HTML
//
?>
<div id="groupModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('Group').($newGroup->Name() ? ' - ' .validHtmlStr($newGroup->Name()) : '') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="groupForm" name="groupForm" method="post" action="?view=group&action=save">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="group"/>
<input type="hidden" name="gid" value="<?php echo $newGroup->Id() ?>"/>
<table id="groupModalTable" class="table-sm table-borderless">
<tbody>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newGroup[Name]" value="<?php echo validHtmlStr($newGroup->Name()) ?>" data-on-input="configModalBtns"/></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('ParentGroup') ?></th>
<td><?php echo parentGrpSelect($newGroup) ?></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Monitor') ?></th>
<td>
<select name="newGroup[MonitorIds][]" class="chosen" multiple="multiple" data-on-change="configModalBtns">
<?php echo monitorList($newGroup) ?>
</select>
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" name="action" id="grpModalSaveBtn" value="save"<?php $newGroup->Id() ? '' : ' disabled="disabled"'?>><?php echo translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,46 @@
<div class="modal fade" id="log_exportModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('ExportLog') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="exportForm" action="" method="post">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
echo $inputs;
?>
<fieldset title="<?php echo translate('ChooseLogSelection') ?>">
<legend><?php echo translate('SelectLog') ?></legend>
<label for="selectorAll"><?php echo translate('All') ?></label>
<input type="radio" id="selectorAll" name="selector" value="all"/>
<label for="selectorFilter"><?php echo translate('Filter') ?></label>
<input type="radio" id="selectorFilter" name="selector" value="filter"/>
<label for="selectorCurrent"><?php echo translate('Current') ?></label>
<input type="radio" id="selectorCurrent" name="selector" value="current" data-validators="validate-one-required"/>
</fieldset>
<fieldset title="<?php echo translate('ChooseLogFormat') ?>">
<legend><?php echo translate('SelectFormat') ?></legend>
<label for="formatText">TXT</label><input type="radio" id="formatText" name="format" value="text"/>
<label for="formatTSV">TSV</label><input type="radio" id="formatTSV" name="format" value="tsv"/>
<label for="formatXML">HTML</label><input type="radio" id="formatHTML" name="format" value="html"/>
<label for="formatXML">XML</label><input type="radio" id="formatXML" name="format" value="xml" class="validate-one-required"/>
</fieldset>
<div id="exportError">
<?php echo translate('ExportFailed') ?>: <span id="exportErrorText"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="exportButton" value="Export" data-on-click="exportRequest"><?php echo translate('Export') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
</div>

View File

@ -33,6 +33,10 @@ global $CLANG;
</div>
<div class="modal-footer">
<form name="logoutForm" id="logoutForm" method="post" action="?">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="logout"/>
<button type="submit" name="action" value="logout"><?php echo translate('Logout') ?></button>
<?php if ( ZM_USER_SELF_EDIT ) echo '<button type="submit" name="action" value="config">'.translate('Config').'</button>'.PHP_EOL; ?>

View File

@ -0,0 +1,43 @@
<?php
// Returns the modal html representing the selected Option Help item
if ( empty($_REQUEST['ohndx']) ) {
ajaxError('Option Help Index Not Provided');
return;
}
global $OLANG;
$result = '';
$optionHelpIndex = $_REQUEST['ohndx'];
$ZMoptionHelpIndex = 'ZM_'.$optionHelpIndex;
if ( !empty($OLANG[$optionHelpIndex]) ) {
$optionHelpText = $OLANG[$optionHelpIndex]['Help'];
} else {
$optionHelpText = dbFetchOne('SELECT Help FROM Config WHERE Name=?', 'Help', array($optionHelpIndex));
}
$optionHelpText = validHtmlStr($optionHelpText);
$optionHelpText = preg_replace('/~~/', '<br/>', $optionHelpText );
$optionHelpText = preg_replace('/\[(.+)\]\((.+)\)/', '<a href="$2" target="_blank">$1</a>', $optionHelpText);
?>
<div id="optionhelp" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('OptionHelp') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h3><?php echo validHtmlStr($optionHelpIndex) ?></h3>
<p class="textblock"><?php echo $optionHelpText ?></p>
</div>
<div class="modal-footer">
<button type="button" id="ohCloseBtn" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

View File

@ -1,49 +1,40 @@
<?php
//
// ZoneMinder web user view file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit('System') ) {
$view = 'error';
// This is the HTML representing the Server modal from Options -> Server
if ( !isset($_REQUEST['id']) ) {
ajaxError('Server Id Not Provided');
return;
}
$Server = new ZM\Server($_REQUEST['id']);
if ( $_REQUEST['id'] and ! $Server->Id() ) {
$view = 'error';
return;
}
$result = '';
$checked = ' checked="checked"';
$null = '';
$sid = $_REQUEST['id'];
$focusWindow = true;
if ( !canEdit('System') ) return;
$Server = new ZM\Server($sid);
if ( $sid and ! $Server->Id() ) return;
xhtmlHeaders(__FILE__, translate('Server').' - '.$Server->Name());
getBodyTopHTML();
?>
<div id="page">
<div id="header">
<h2><?php echo translate('Server').' - '.$Server->Name() ?></h2>
</div>
<div id="content">
<form name="contentForm" method="post" action="?" class="validateFormOnSubmit">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<div class="modal fade" id="ServerModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('Server') .' - '. $Server->Name() ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="serverModalForm" name="contentForm" method="post" action="?view=server&action=save" class="validateFormOnSubmit">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="server"/>
<input type="hidden" name="object" value="server"/>
<input type="hidden" name="id" value="<?php echo validHtmlStr($_REQUEST['id']) ?>"/>
<table id="contentTable" class="major">
<table class="table-sm">
<tbody>
<tr>
<th scope="row"><?php echo translate('Name') ?></th>
@ -76,38 +67,39 @@ getBodyTopHTML();
<tr>
<th scope="row"><?php echo translate('RunStats') ?></th>
<td>
<input type="radio" name="newServer[zmstats]" value="1"<?php echo $Server->zmstats() ? ' checked="checked"' : '' ?>/> Yes
<input type="radio" name="newServer[zmstats]" value="0"<?php echo $Server->zmstats() ? '' : ' checked="checked"' ?>/> No
<input type="radio" name="newServer[zmstats]" value="1" <?php echo $Server->zmstats() ? $checked : $null ?>/> Yes
<input type="radio" name="newServer[zmstats]" value="0" <?php echo $Server->zmstats() ? $null : $checked ?>/> No
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('RunAudit') ?></th>
<td>
<input type="radio" name="newServer[zmaudit]" value="1"<?php echo $Server->zmaudit() ? ' checked="checked"' : '' ?>/> Yes
<input type="radio" name="newServer[zmaudit]" value="0"<?php echo $Server->zmaudit() ? '' : ' checked="checked"' ?>/> No
<input type="radio" name="newServer[zmaudit]" value="1"<?php echo $Server->zmaudit() ? $checked : $null ?>/> Yes
<input type="radio" name="newServer[zmaudit]" value="0"<?php echo $Server->zmaudit() ? $null : $checked ?>/> No
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('RunTrigger') ?></th>
<td>
<input type="radio" name="newServer[zmtrigger]" value="1"<?php echo $Server->zmtrigger() ? ' checked="checked"' : '' ?>/> Yes
<input type="radio" name="newServer[zmtrigger]" value="0"<?php echo $Server->zmtrigger() ? '' : ' checked="checked"' ?>/> No
<input type="radio" name="newServer[zmtrigger]" value="1" <?php echo $Server->zmtrigger() ? $checked : $null ?>/> Yes
<input type="radio" name="newServer[zmtrigger]" value="0" <?php echo $Server->zmtrigger() ? $null : $checked ?>/> No
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('RunEventNotification') ?></th>
<td>
<input type="radio" name="newServer[zmeventnotification]" value="1"<?php echo $Server->zmeventnotification() ? ' checked="checked"' : '' ?>/> Yes
<input type="radio" name="newServer[zmeventnotification]" value="0"<?php echo $Server->zmeventnotification() ? '' : ' checked="checked"' ?>/> No
<input type="radio" name="newServer[zmeventnotification]" value="1" <?php echo $Server->zmeventnotification() ? $checked : $null ?>/> Yes
<input type="radio" name="newServer[zmeventnotification]" value="0" <?php echo $Server->zmeventnotification() ? $null : $checked ?>/> No
</td>
</tr>
</tbody>
</table>
<div id="contentButtons">
<button type="submit" name="action" value="Save" ><?php echo translate('Save') ?></button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
<div class="modal-footer">
<button name="action" id="serverSubmitBtn" type="submit" class="btn btn-primary" value="Save"><?php echo translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</div>
</div>
<?php xhtmlFooter() ?>
</div>

View File

@ -17,12 +17,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
global $running;
if ( !canEdit('System') ) {
$view = 'error';
return;
}
if ( !canEdit('System') ) return;
$running = daemonCheck();
$content = '';
if ( $running ) {
@ -53,6 +51,10 @@ foreach ( $states as $state ) {
</div>
<div class="modal-body">
<form class="" name="contentForm" method="get" action="?view=state">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="state"/>
<input type="hidden" name="action" value="state"/>
<input type="hidden" name="apply" value="1"/>

110
web/ajax/modals/storage.php Normal file
View File

@ -0,0 +1,110 @@
<?php
// This is the HTML representing the Storage modal from Options -> Storage
if ( !isset($_REQUEST['id']) ) {
ajaxError('Storage Id Not Provided');
return;
}
$null = '';
$checked = 'checked="checked"';
$sid = $_REQUEST['id'];
if ( !canEdit('System') ) return;
require_once('includes/Server.php');
require_once('includes/Storage.php');
if ( $_REQUEST['id'] ) {
if ( !($newStorage = ZM\Storage::find_one(array('Id'=>$sid)) ) ) {
// Perhaps do something different here, rather than return nothing
return;
}
} else {
$newStorage = new ZM\Storage();
$newStorage->Name(translate('NewStorage'));
}
$type_options = array( 'local' => translate('Local'), 's3fs' => translate('s3fs') );
$scheme_options = array(
'Deep' => translate('Deep'),
'Medium' => translate('Medium'),
'Shallow' => translate('Shallow'),
);
$servers = ZM\Server::find( null, array('order'=>'lower(Name)') );
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
?>
<div class="modal fade" id="storageModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo translate('Storage') .' - '. $newStorage->Name() ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="storageModalForm" name="contentForm" method="post" action="?view=storage&action=save" class="validateFormOnSubmit">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="storage"/>
<input type="hidden" name="object" value="storage"/>
<input type="hidden" name="id" value="<?php echo validHtmlStr($sid) ?>"/>
<table class="major table-sm">
<tbody>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newStorage[Name]" value="<?php echo $newStorage->Name() ?>"/></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Path') ?></th>
<td><input type="text" name="newStorage[Path]" value="<?php echo $newStorage->Path() ?>"/></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Url') ?></th>
<td><input type="text" name="newStorage[Url]" value="<?php echo $newStorage->Url() ?>"/></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Server') ?></th>
<td><?php echo htmlSelect('newStorage[ServerId]', array(''=>'Remote / No Specific Server') + $ServersById, $newStorage->ServerId()) ?></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Type') ?></th>
<td><?php echo htmlSelect('newStorage[Type]', $type_options, $newStorage->Type()) ?></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('StorageScheme') ?></th>
<td><?php echo htmlSelect('newStorage[Scheme]', $scheme_options, $newStorage->Scheme()) ?></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('StorageDoDelete') ?></th>
<td>
<input type="radio" name="newStorage[DoDelete]" value="1" <?php echo $newStorage->DoDelete() ? $checked : $null ?>>Yes
<input type="radio" name="newStorage[DoDelete]" value="0" <?php echo $newStorage->DoDelete() ? $null : $checked ?>>No
</td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Enabled') ?></th>
<td>
<input type="radio" name="newStorage[Enabled]" value="1" <?php echo $newStorage->Enabled() ? $checked : $null ?>>Yes
<input type="radio" name="newStorage[Enabled]" value="0" <?php echo $newStorage->Enabled() ? $null : $checked ?>>No
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button name="action" id="storageSubmitBtn" type="submit" class="btn btn-primary" value="Save"><?php echo translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
</div>

132
web/ajax/newlog.php Normal file
View File

@ -0,0 +1,132 @@
<?php
global $Servers;
if ( !canView('System') ) {
ajaxError('Insufficient permissions to view log entries');
return;
}
// Only the query task is supported at the moment
if ( !isset($_REQUEST['task']) or $_REQUEST['task'] != 'query' ) {
ajaxError('Unrecognised action');
return;
}
// The table we want our data from
$table = 'Logs';
// The names of the dB columns in the log table we are interested in
$columns = array('TimeKey', 'Component', 'ServerId', 'Pid', 'Code', 'Message', 'File', 'Line');
// The names of columns shown in the log view that are NOT dB columns in the database
$col_alt = array('DateTime', 'Server');
// Search contains a user entered string to search on
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
// Advanced search contains an array of "column name" => "search text" pairs
// Bootstrap table sends json_ecoded array, which we must decode
$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array();
// Sort specifies the name of the column to sort on
$sort = 'TimeKey';
if ( isset($_REQUEST['sort']) ) {
if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) {
ZM\Error('Invalid sort field: ' . $_REQUEST['sort']);
} else {
$sort = $_REQUEST['sort'];
if ( $sort == 'DateTime' ) $sort = 'TimeKey';
}
}
// Offset specifies the starting row to return, used for pagination
$offset = 0;
if ( isset($_REQUEST['offset']) ) {
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) {
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
} else {
$offset = $_REQUEST['offset'];
}
}
// Order specifies the sort direction, either asc or desc
$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC';
// Limit specifies the number of rows to return
$limit = 100;
if ( isset($_REQUEST['limit']) ) {
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
} else {
$limit = $_REQUEST['limit'];
}
}
$col_str = implode(', ', $columns);
$data = array();
$query = array();
$query['values'] = array();
$likes = array();
$where = '';
// There are two search bars in the log view, normal and advanced
// Making an exuctive decision to ignore the normal search, when advanced search is in use
// Alternatively we could try to do both
if ( count($advsearch) ) {
foreach ( $advsearch as $col=>$text ) {
if ( !in_array($col, array_merge($columns, $col_alt)) ) {
ZM\Error("'$col' is not a sortable column name");
continue;
}
$text = '%' .$text. '%';
array_push($likes, $col.' LIKE ?');
array_push($query['values'], $text);
}
$wherevalues = $query['values'];
$where = ' WHERE (' .implode(' OR ', $likes). ')';
} else if ( $search != '' ) {
$search = '%' .$search. '%';
foreach ( $columns as $col ) {
array_push($likes, $col.' LIKE ?');
array_push($query['values'], $search);
}
$wherevalues = $query['values'];
$where = ' WHERE (' .implode(' OR ', $likes). ')';
}
$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?';
array_push($query['values'], $offset, $limit);
//ZM\Warning('Calling the following sql query: ' .$query['sql']);
$data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total');
if ( $search != '' || count($advsearch) ) {
$data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues);
} else {
$data['total'] = $data['totalNotFiltered'];
}
if ( !$Servers )
$Servers = ZM\Server::find();
$servers_by_Id = array();
# There is probably a better way to do this.
foreach ( $Servers as $server ) {
$servers_by_Id[$server->Id()] = $server;
}
$rows = array();
foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) {
$row['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($row['TimeKey']));
$row['Server'] = ( $row['ServerId'] and isset($servers_by_Id[$row['ServerId']]) ) ? $servers_by_Id[$row['ServerId']]->Name() : '';
// First strip out any html tags
// Second strip out all characters that are not ASCII 32-126 (yes, 126)
$row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message']));
$rows[] = $row;
}
$data['rows'] = $rows;
$data['logstate'] = logState();
$data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG);
ajaxResponse($data);

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

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

View File

@ -434,14 +434,11 @@ class EventsController extends AppController {
// Find the max Frame for this Event. Error out otherwise.
$this->loadModel('Frame');
if (! $frame = $this->Frame->find('first', array(
$frame = $this->Frame->find('first', array(
'conditions' => array(
'EventId' => $event['Event']['Id'],
'Score' => $event['Event']['MaxScore']
)
))) {
throw new NotFoundException(__('Can not find Frame for Event ' . $event['Event']['Id']));
}
return $frame['Frame']['Id'];
'EventId' => $event['Event']['Id'],
'Score' => $event['Event']['MaxScore']
)));
return empty($frame)?null:$frame['Frame']['Id'];
}
} // end class EventsController

View File

@ -115,6 +115,7 @@ class ZonesController extends AppController {
if ( !$this->Zone->exists($id) ) {
throw new NotFoundException(__('Invalid zone'));
}
$message = '';
if ( $this->request->is(array('post', 'put')) ) {
global $user;
$canEdit = (!$user) || $user['Monitors'] == 'Edit';
@ -123,14 +124,15 @@ class ZonesController extends AppController {
return;
}
if ( $this->Zone->save($this->request->data) ) {
return $this->flash(__('The zone has been saved.'), array('action' => 'index'));
$message = 'The zone has been saved.';
} else {
$message = 'Error ' . print_r($this->Zone->invalidFields());
}
} else {
$options = array('conditions' => array('Zone.' . $this->Zone->primaryKey => $id));
$this->request->data = $this->Zone->find('first', $options);
}
$monitors = $this->Zone->Monitor->find('list');
$this->set(compact('monitors'));
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
/**

View File

@ -41,19 +41,15 @@ class Zone extends AppModel {
//array('naturalNumber'),
'message' => 'Zones must have a valid MonitorId',
'allowEmpty' => false,
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
'Name' => array(
'required' => array(
//'on' => 'create',
'rule' => 'notBlank',
'message' => 'Zone Name must be specified for creation',
'required' => true,
),
)
);
//The Associations below have been created with all possible keys, those that are not needed can be removed

View File

@ -1,7 +1,7 @@
/**
* 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
* @version v1.18.0
* @homepage https://bootstrap-table.com
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
* @license MIT

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ class Filter extends ZM_Object {
'Id' => null,
'Name' => '',
'AutoExecute' => 0,
'AutoExecuteCmd' => 0,
'AutoExecuteCmd' => '',
'AutoEmail' => 0,
'EmailTo' => '',
'EmailSubject' => '',
@ -50,10 +50,10 @@ class Filter extends ZM_Object {
return $this->_sql;
}
public function querystring() {
if ( ! isset($this->_querystring) ) {
public function querystring($separator='&amp;') {
if ( (! isset($this->_querystring)) or ( $separator != '&amp;' ) ) {
foreach ( $this->FilterTerms() as $term ) {
$this->_querystring .= $term->querystring();
$this->_querystring .= $term->querystring($separator);
} # end foreach term
}
return $this->_querystring;
@ -196,7 +196,7 @@ class Filter extends ZM_Object {
if ( isset( $this->Query()['sort_asc'] ) ) {
return $this->{'Query'}['sort_asc'];
}
return ZM_WEB_EVENT_SORT_ORDER;
return ZM_WEB_EVENT_SORT_ORDER == 'asc' ? 1 : 0;
#return $this->defaults{'sort_asc'};
}
@ -308,6 +308,312 @@ class Filter extends ZM_Object {
return $failed;
}
function tree() {
$terms = $this->terms();
if ( count($terms) <= 0 ) {
return false;
}
$StorageArea = NULL;
$postfixExpr = array();
$postfixStack = array();
$priorities = array(
'<' => 1,
'<=' => 1,
'>' => 1,
'>=' => 1,
'=' => 2,
'!=' => 2,
'=~' => 2,
'!~' => 2,
'=[]' => 2,
'![]' => 2,
'and' => 3,
'or' => 4,
);
for ( $i = 0; $i < count($terms); $i++ ) {
$term = $terms[$i];
if ( !empty($term['cnj']) ) {
while( true ) {
if ( !count($postfixStack) ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
} elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
} elseif ( $priorities[$term['cnj']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
} else {
$postfixExpr[] = array_pop($postfixStack);
}
}
} # end if ! empty cnj
if ( !empty($term['obr']) ) {
for ( $j = 0; $j < $term['obr']; $j++ ) {
$postfixStack[] = array('type'=>'obr', 'value'=>$term['obr']);
}
}
if ( !empty($term['attr']) ) {
$dtAttr = false;
switch ( $term['attr']) {
case 'MonitorName':
$sqlValue = 'M.'.preg_replace( '/^Monitor/', '', $term['attr']);
break;
case 'ServerId':
$sqlValue .= 'M.ServerId';
break;
case 'StorageServerId':
$sqlValue .= 'S.ServerId';
break;
case 'FilterServerId':
$sqlValue .= ZM_SERVER_ID;
break;
case 'DateTime':
case 'StartDateTime':
$sqlValue = 'E.StartTime';
$dtAttr = true;
break;
case 'Date':
case 'StartDate':
$sqlValue = 'to_days(E.StartTime)';
$dtAttr = true;
break;
case 'Time':
case 'StartTime':
$sqlValue = 'extract(hour_second from E.StartTime)';
break;
case 'Weekday':
case 'StartWeekday':
$sqlValue = 'weekday(E.StartTime)';
break;
case 'EndDateTime':
$sqlValue = 'E.EndTime';
$dtAttr = true;
break;
case 'EndDate':
$sqlValue = 'to_days(E.EndTime)';
$dtAttr = true;
break;
case 'EndTime':
$sqlValue = 'extract(hour_second from E.EndTime)';
break;
case 'EndWeekday':
$sqlValue = 'weekday(E.EndTime)';
break;
case 'Id':
case 'Name':
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':
$sqlValue = '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 ) {
for ( $j = 0; $j < count($terms); $j++ ) {
if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) {
$StorageArea = new Storage($terms[$j]['val']);
break;
}
} // end foreach remaining term
if ( ! $StorageArea ) $StorageArea = new Storage();
} // end no StorageArea found yet
$sqlValue = getDiskPercent($StorageArea);
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 = 0; $j < count($terms); $j++ ) {
if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) {
$StorageArea = new Storage($terms[$j]['val']);
break;
}
} // end foreach remaining term
if ( ! $StorageArea ) $StorageArea = new Storage();
} // end no StorageArea found yet
$sqlValue = getDiskBlocks($StorageArea);
break;
default :
$sqlValue = $term['attr'];
break;
}
if ( $dtAttr ) {
$postfixExpr[] = array('type'=>'attr', 'value'=>$term['attr'], 'sqlValue'=>$sqlValue, 'dtAttr'=>true);
} else {
$postfixExpr[] = array('type'=>'attr', 'value'=>$term['attr'], 'sqlValue'=>$sqlValue);
}
} # end if attr
if ( isset($term['op']) ) {
if ( empty($term['op']) ) {
$term['op'] = '=';
}
switch ( $term['op']) {
case '=' :
case '!=' :
case '>=' :
case '>' :
case '<' :
case '<=' :
case 'LIKE' :
case 'NOT LIKE':
$sqlValue = $term['op'];
break;
case '=~' :
$sqlValue = 'regexp';
break;
case '!~' :
$sqlValue = 'not regexp';
break;
case '=[]' :
case 'IN' :
$sqlValue = 'in (';
break;
case '![]' :
$sqlValue = 'not in (';
break;
case 'IS' :
case 'IS NOT' :
if ( $term['val'] == 'Odd' ) {
$sqlValue .= ' % 2 = 1';
} else if ( $term['val'] == 'Even' ) {
$sqlValue .= ' % 2 = 0';
} else {
$sqlValue .= ' '.$term['op'];
}
break;
default :
ZM\Error('Unknown operator in filter '.$term['op']);
}
while( true ) {
if ( !count($postfixStack) ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
break;
} elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
break;
} elseif ( $priorities[$term['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue );
break;
} else {
$postfixExpr[] = array_pop($postfixStack);
}
} // end while
} // end if operator
if ( isset($term['val']) ) {
$valueList = array();
foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) {
switch ( $term['attr'] ) {
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 = new Storage($value);
if ( $value != 'NULL' )
$value = dbEscape($value);
break;
case 'DateTime':
case 'EndDateTime':
case 'StartDateTime':
$value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'";
break;
case 'Date':
case 'EndDate':
case 'StartDate':
$value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
case 'Time':
case 'EndTime':
case 'StartTime':
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
case 'Weekday':
case 'EndWeekday':
case 'StartWeekday':
$value = 'weekday(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
default :
if ( $value != 'NULL' )
$value = dbEscape($value);
} // end switch attribute
$valueList[] = $value;
} // end foreach value
$postfixExpr[] = array('type'=>'val', 'value'=>$term['val'], 'sqlValue'=>join(',', $valueList));
} // end if has val
if ( !empty($term['cbr']) ) {
for ( $j = 0; $j < $term['cbr']; $j++ ) {
while ( count($postfixStack) ) {
$element = array_pop($postfixStack);
if ( $element['type'] == 'obr' ) {
$postfixExpr[count($postfixExpr)-1]['bracket'] = true;
break;
}
$postfixExpr[] = $element;
}
}
} #end if cbr
} # end foreach term
while ( count($postfixStack) ) {
$postfixExpr[] = array_pop($postfixStack);
}
$exprStack = array();
foreach ( $postfixExpr as $element ) {
if ( $element['type'] == 'attr' || $element['type'] == 'val' ) {
$node = array('data'=>$element, 'count'=>0);
$exprStack[] = $node;
} elseif ( $element['type'] == 'op' || $element['type'] == 'cnj' ) {
$right = array_pop($exprStack);
$left = array_pop($exprStack);
$node = array('data'=>$element, 'count'=>2+$left['count']+$right['count'], 'right'=>$right, 'left'=>$left);
$exprStack[] = $node;
} else {
ZM\Fatal('Unexpected element type \''.$element['type'].'\', value \''.$element['value'].'\'');
}
}
if ( count($exprStack) != 1 ) {
ZM\Fatal('Expression stack has '.count($exprStack).' elements');
}
return array_pop($exprStack);
} # end function tree
} # end class Filter

View File

@ -50,7 +50,7 @@ class FilterTerm {
}
if ( isset($term['cbr']) ) {
if ( (string)(int)$term['cbr'] == $term['cbr'] ) {
$this->obr = $term['cbr'];
$this->cbr = $term['cbr'];
} else {
Warning('Invalid cbr ' . $term['cbr'] . ' in ' . print_r($term, true));
}
@ -61,7 +61,7 @@ class FilterTerm {
public function sql_values() {
$values = array();
if ( !isset($this->val) ) {
Logger::Warning("No value in term ");
Logger::Warning('No value in term'.$this->attr);
return $values;
}
@ -75,6 +75,10 @@ class FilterTerm {
case 'ExistsInFileSystem':
$value = '';
break;
case 'DiskSpace':
$value = '';
break;
case 'MonitorName':
case 'MonitorName':
case 'Name':
case 'Cause':
@ -137,10 +141,11 @@ class FilterTerm {
} # end function sql_values
public function sql_operator() {
if ( $this->attr == 'AlarmZoneId' ) {
switch ( $this->attr ) {
case 'AlarmZoneId':
return ' EXISTS ';
}
if ( $this->attr == 'ExistsInFileSystem' ) {
case 'ExistsInFileSystem':
case 'DiskSpace':
return '';
}
@ -197,6 +202,7 @@ class FilterTerm {
switch ( $this->attr ) {
case 'ExistsInFileSystem':
case 'DiskSpace':
$sql .= 'TRUE /*'.$this->attr.'*/';
break;
case 'MonitorName':
@ -256,7 +262,7 @@ class FilterTerm {
break;
case 'Id':
case 'Name':
case 'DiskSpace':
case 'EventDiskSpace':
case 'MonitorId':
case 'StorageId':
case 'SecondaryStorageId':

View File

@ -129,6 +129,8 @@ class Monitor extends ZM_Object {
'Refresh' => null,
'DefaultCodec' => 'auto',
'GroupIds' => array('default'=>array(), 'do_not_update'=>1),
'Latitude' => null,
'Longitude' => null,
);
private $status_fields = array(
'Status' => null,
@ -567,7 +569,7 @@ class Monitor extends ZM_Object {
return false;
}
} else if ( $command != 'quit' ) {
$command = ZM_PATH_BIN.'/zmcontrol.pl '.$command.' --id='.$this->{'Id'};
$command = ZM_PATH_BIN.'/zmcontrol.pl '.$command.' --id '.$this->{'Id'};
// Can't connect so use script
$ctrlOutput = exec(escapeshellcmd($command));
@ -628,5 +630,9 @@ class Monitor extends ZM_Object {
return $this->connKey;
}
function canEdit() {
global $user;
return ( $user && ($user['Monitors'] == 'Edit') && ( !$this->{'Id'} || visibleMonitor($this->{'Id'}) ));
}
} // end class Monitor
?>

View File

@ -144,7 +144,6 @@ class ZM_Object {
public function _remove_from_cache($class, $object) {
global $object_cache;
unset($object_cache[$class][$object->Id()]);
Logger::Debug("Unsset $class " . $object->Id() . " " . count($object_cache[$class]));
}
public static function Objects_Indexed_By_Id($class, $params=null) {

View File

@ -8,8 +8,9 @@ class Zone extends ZM_Object {
protected static $table = 'Zones';
protected $defaults = array(
'Id' => null,
'Name' => '',
'Id' => null,
'MonitorId' => null,
'Name' => '',
'Type' => 'Active',
'Units' => 'Pixels',
'CheckMethod' => 'Blobs',
@ -36,6 +37,14 @@ class Zone extends ZM_Object {
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
public function Monitor() {
if ( isset($this->{'MonitorId'}) ) {
$Monitor = Monitor::find_one(array('Id'=>$this->{'MonitorId'}));
if ( $Monitor )
return $Monitor;
}
return new Monitor();
}
} # end class Zone
?>

View File

@ -89,7 +89,6 @@ if ( $action == 'controlcap' ) {
//$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
$Control->save($_REQUEST['newControl']);
$refreshParent = true;
$view = 'none';
$redirect = '?view=controlcaps';
} // end if action
?>

View File

@ -49,6 +49,6 @@ if ( $action == 'donate' && isset($_REQUEST['option']) ) {
Warning("Unknown value for option in donate: $option");
break;
} // end switch option
$view = 'none';
$redirect = '?view=console';
}
?>

View File

@ -41,7 +41,6 @@ if ( $action == 'eventdetail' ) {
);
}
$dbConn->commit();
$refreshParent = true;
$closePopup = true;
$redirect = $_SERVER['HTTP_REFERER'];
}
?>

View File

@ -51,11 +51,9 @@ if ( $action == 'function' ) {
if ( $newFunction != 'None' && $newFunction != 'NoDect' )
zmaControl($monitor, 'start');
}
$refreshParent = true;
} else {
ZM\Logger::Debug('No change to function, not doing anything.');
}
} // end if action
$view = 'none';
$closePopup = true;
$view = 'console';
?>

View File

@ -26,26 +26,24 @@ if ( !canEdit('Groups') ) {
return;
}
if ( $action == 'Save' ) {
if ( $action == 'save' ) {
$group_id = null;
if ( !empty($_POST['gid']) )
$group_id = $_POST['gid'];
if ( !empty($_REQUEST['gid']) )
$group_id = $_REQUEST['gid'];
$group = new ZM\Group($group_id);
$group->save(
array(
'Name'=> $_POST['newGroup']['Name'],
'ParentId'=>( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ),
'Name'=> $_REQUEST['newGroup']['Name'],
'ParentId'=>( $_REQUEST['newGroup']['ParentId'] == '' ? null : $_REQUEST['newGroup']['ParentId'] ),
)
);
dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id));
$group_id = $group->Id();
if ( $group_id ) {
foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) {
foreach ( $_REQUEST['newGroup']['MonitorIds'] as $mid ) {
dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid));
}
}
$view = 'none';
$refreshParent = true;
$closePopup = true;
$redirect = '?view=groups';
}
?>

View File

@ -24,7 +24,7 @@ if ( ! canEdit('Monitors') ) {
return;
}
if ( $action == 'monitor' ) {
if ( $action == 'save' ) {
$mid = 0;
if ( !empty($_REQUEST['mid']) ) {
$mid = validInt($_REQUEST['mid']);
@ -273,7 +273,7 @@ if ( $action == 'monitor' ) {
// really should thump zmwatch and maybe zmtrigger too.
//daemonControl( 'restart', 'zmwatch.pl' );
} // end if restart
$view = 'console';
$redirect = '?view=console';
} else {
ZM\Warning("Unknown action $action in Monitor");
} // end if action == Delete

View File

@ -24,7 +24,7 @@ if ( ! canEdit('System') ) {
return;
}
if ( $action == 'Save' ) {
if ( $action == 'save' ) {
if ( !empty($_REQUEST['id']) ) {
$dbServer = dbFetchOne(
'SELECT * FROM Servers WHERE Id=?',
@ -46,7 +46,7 @@ if ( $action == 'Save' ) {
}
$refreshParent = true;
}
$view = 'none';
$redirect = '?view=options&tab=servers';
} else {
ZM\Error("Unknown action $action in saving Server");
}

View File

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

View File

@ -17,33 +17,39 @@
// 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('includes/Zone.php');
global $error_message;
if ( !empty($_REQUEST['mid']) && canEdit('Monitors', $_REQUEST['mid']) ) {
$mid = validInt($_REQUEST['mid']);
$monitor = new ZM\Monitor($mid);
if ( $action == 'delete' ) {
if ( isset($_REQUEST['markZids']) ) {
$restart_zmc = 0;
foreach ( $_REQUEST['markZids'] as $markZid ) {
$monitors_to_restart = array();
if ( ! $restart_zmc ) {
$zone = dbFetchOne('SELECT * FROM Zones WHERE Id=?', NULL, array($markZid));
if ( $zone['Type'] == 'Privacy' ) {
$restart_zmc = 1;
}
}
dbQuery('DELETE FROM Zones WHERE MonitorId=? AND Id=?', array($mid, $markZid));
if ( $action == 'delete' ) {
if ( isset($_REQUEST['markZids']) ) {
foreach ( $_REQUEST['markZids'] as $markZid ) {
$zone = new ZM\Zone($markZid);
if ( ! $zone->Id() ) {
$error_message .= 'Zone not found for id ' . $markZid.'<br/>';
continue;
}
if ( daemonCheck() && $monitor->Type() != 'WebSite' ) {
$monitor = $zone->Monitor();
if ( !$monitor->CanEdit() ) {
$error_message .= 'You do not have permission to edit zones for monitor ' . $monitor->Name().'.<br/>';
continue;
}
# Could use true but store the object instead for easy access later
$monitors_to_restart[$monitor->Id()] = $monitor;
$error_message .= $zone->delete();
} # end foreach Zone
foreach ( $monitors_to_restart as $mid => $monitor ) {
if ( daemonCheck() and ($monitor->Type() != 'WebSite') ) {
zmaControl($mid, 'stop');
if ( $restart_zmc )
if ( $monitor->Type() == 'Privacy' )
zmcControl($mid, 'restart');
zmaControl($mid, 'start');
} // end if daemonCheck()
$refreshParent = true;
} // end if isset($_REQUEST['markZids'])
} // end if action
} // end if $mid and canEdit($mid)
}
$refreshParent = true;
} // end if isset($_REQUEST['markZids'])
} // end if action
?>

View File

@ -64,7 +64,8 @@ function dbConnect() {
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $ex) {
echo "Unable to connect to ZM db using dsn $dsn host".ZM_DB_HOST.' user: ('.ZM_DB_USER.') password ('.ZM_DB_PASS.': '.$ex->getMessage();
global $error_message;
$error_message = "Unable to connect to ZM db using dsn $dsn<br/><br/>".$ex->getMessage();
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
$dbConn = null;
}
@ -72,7 +73,8 @@ function dbConnect() {
} // end function dbConnect
if ( !dbConnect() ) {
ZM\Fatal('Failed db connection');
include('views/no_database_connection.php');
exit();
}
function dbDisconnect() {

View File

@ -79,14 +79,12 @@ function CSPHeaders($view, $nonce) {
case 'storage':
case 'version': {
// Enforce script-src on pages where inline scripts and event handlers have been fixed.
// 'unsafe-inline' is only for backwards compatibility with browsers which
// only support CSP 1 (with no nonce-* support).
header("Content-Security-Policy: script-src 'unsafe-inline' 'self' 'nonce-$nonce' $additionalScriptSrc");
header("Content-Security-Policy: script-src 'self' 'nonce-$nonce' $additionalScriptSrc");
break;
}
default: {
// Use Report-Only mode on all other pages.
header("Content-Security-Policy-Report-Only: script-src 'unsafe-inline' 'self' 'nonce-$nonce' $additionalScriptSrc;".
header("Content-Security-Policy-Report-Only: script-src 'self' 'nonce-$nonce' $additionalScriptSrc;".
(ZM_CSP_REPORT_URI ? ' report-uri '.ZM_CSP_REPORT_URI : '' )
);
break;
@ -438,6 +436,13 @@ function makeLink($url, $label, $condition=1, $options='') {
return $string;
}
//Make it slightly easier to create a link to help text modal
function makeHelpLink($ohndx) {
$string = '&nbsp;(<a id="' .$ohndx. '" class="optionhelp" href="#">?</a>)';
return $string;
}
/**
* $label must be already escaped. It can't be done here since it sometimes contains HTML tags.
*/
@ -482,6 +487,16 @@ function makePopupButton($url, $winName, $winSize, $buttonValue, $condition=1, $
return $string;
}
function makeButton($url, $buttonValue, $condition=1, $options='') {
$string = '<button type="button" data-on-click-this="'.$buttonValue.'"';
$string .= ' data-url="' .$url. '"';
if (!$condition) {
$string .= ' disabled="disabled"';
}
$string .= ($options ? (' ' . $options) : '') . '/>'.translate($buttonValue).'</button>'.PHP_EOL;
return $string;
}
function htmlSelect($name, $contents, $values, $behaviours=false) {
$behaviourText = '';
if ( !empty($behaviours) ) {
@ -1104,7 +1119,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
$Filter = ZM\Filter::parse($filter, $querySep);
$filter['sql'] = $Filter->sql();
$filter['querystring'] = $Filter->querystring();
$filter['querystring'] = $Filter->querystring($querySep);
$filter['hidden_fields'] = $Filter->hidden_fields();
$filter['pre_sql_conditions'] = $Filter->pre_sql_conditions();
$filter['post_sql_conditions'] = $Filter->post_sql_conditions();
@ -2143,7 +2158,10 @@ function getStreamHTML($monitor, $options = array()) {
}
$options['mode'] = 'single';
$streamSrc = $monitor->getStreamSrc($options);
return getImageStill('liveStream'.$monitor->Id(), $streamSrc, $options['width'], $options['height'], $monitor->Name());
return getImageStill('liveStream'.$monitor->Id(), $streamSrc,
(isset($options['width']) ? $options['width'] : null),
(isset($options['height']) ? $options['height'] : null),
$monitor->Name());
}
} // end function getStreamHTML

View File

@ -125,7 +125,8 @@ $SLANG = array(
'AttrEndDate' => 'End Date',
'AttrStartDateTime' => 'Start Date/Time',
'AttrEndDateTime' => 'End Date/Time',
'AttrDiskSpace' => 'Disk Space',
'AttrEventDiskSpace' => 'Event Disk Space',
'AttrDiskSpace' => 'File System Disk Space',
'AttrDiskBlocks' => 'Disk Blocks',
'AttrDiskPercent' => 'Disk Percent',
'AttrDuration' => 'Duration',
@ -260,7 +261,9 @@ $SLANG = array(
'ConfigType' => 'Config Type',
'ConfiguredFor' => 'Configured for',
'ConfigURL' => 'Config Base URL',
'ConfirmDeleteControl' => 'Warning, deleting a control will reset all monitors that use it to be uncontrollable.<br><br>Are you sure you wish to delete?',
'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?',
'ConfirmDeleteTitle' => 'Delete Confirmation',
'ConfirmPassword' => 'Confirm Password',
'ConjAnd' => 'and',
'ConjOr' => 'or',
@ -319,6 +322,7 @@ $SLANG = array(
'DuplicateMonitorName' => 'Duplicate Monitor Name',
'Duration' => 'Duration',
'Edit' => 'Edit',
'EditControl' => 'Edit Control',
'EditLayout' => 'Edit Layout',
'Email' => 'Email',
'EnableAlarms' => 'Enable Alarms',

View File

@ -326,24 +326,10 @@ ul.tabList li.active a {
color: #dc143c;
}
fieldset {
border: 1px solid black;
padding: 4px;
margin-bottom: 8px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
}
fieldset > legend {
padding: 0 2px;
}
/*
* Behavior classes
*/
.ok, .infoText {
color: #0fb9b1;
}

View File

@ -0,0 +1,18 @@
tr.log-fat td {
background-color:#ffcccc;
font-weight: bold;
}
tr.log-err td {
background-color:#ffcccc;
}
tr.log-war td {
background-color: #ffe4b5;
}
tr.log-dbg td {
color: #666666;
font-style: italic;
}

View File

@ -21,6 +21,9 @@ input.large {
#contentTable.userTable .colMonitor, #contentTable.userTable .colUsername {
text-align: left;
}
#contentTable th {
text-align: left;
}
input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SITEKEY]"],
input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SECRETKEY]"] {

View File

@ -0,0 +1,3 @@
input[type="number"] {
width: 50px;
}

View File

@ -39,12 +39,37 @@ function xhtmlHeaders($file, $title) {
$baseViewCssPhpFile = getSkinFile('/css/base/views/'.$basename.'.css.php');
$viewCssPhpFile = getSkinFile('/css/'.$css.'/views/'.$basename.'.css.php');
function output_link_if_exists($files) {
function output_link_if_exists($files, $cache_bust=true) {
global $skin;
$html = array();
foreach ( $files as $file ) {
if ( getSkinFile($file) ) {
if ( $cache_bust ) {
$html[] = '<link rel="stylesheet" href="'.cache_bust('skins/'.$skin.'/'.$file).'" type="text/css"/>';
} else {
$html[] = '<link rel="stylesheet" href="skins/'.$skin.'/'.$file.'" type="text/css"/>';
}
}
}
$html[] = ''; // So we ge a trailing \n
return implode(PHP_EOL, $html);
}
function output_script_if_exists($files, $cache_bust=true) {
global $skin;
$html = array();
foreach ( $files as $file ) {
if ( file_exists('skins/'.$skin.'/'.$file) ) {
if ( $cache_bust ) {
$html[] = '<script src="'.cache_bust('skins/'.$skin.'/'.$file).'"></script>';
} else {
$html[] = '<script src="skins/'.$skin.'/'.$file.'"></script>';
}
} else if ( file_exists($file) ) {
if ( $cache_bust ) {
$html[] = '<script src="'.cache_bust($file).'"></script>';
} else {
$html[] = '<script src="'.$file.'"></script>';
}
}
}
$html[] = ''; // So we ge a trailing \n
@ -56,6 +81,9 @@ function xhtmlHeaders($file, $title) {
foreach ( $files as $file ) {
$html[] = '<link rel="stylesheet" href="'.cache_bust($file).'" type="text/css"/>';
}
if ( ! count($html) ) {
ZM\Warning("No files found for $files");
}
$html[] = ''; // So we ge a trailing \n
return implode(PHP_EOL, $html);
}
@ -109,6 +137,8 @@ if ( $css != 'base' )
echo output_link_if_exists(array('/css/base/views/control.css'));
if ( $css != 'base' )
echo output_link_if_exists(array('/css/'.$css.'/views/control.css'));
} else if ( $basename == 'monitor' ) {
echo output_link_if_exists(array('js/leaflet/leaflet.css'), false);
}
?>
<style>
@ -572,7 +602,7 @@ function getLogHTML() {
if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) {
$logstate = logState();
$class = ($logstate == 'ok') ? 'text-success' : ($logstate == 'alert' ? 'text-warning' : (($logstate == 'alarm' ? 'text-danger' : '')));
$result .= '<li id="getLogHTML" class="nav-item dropdown mx-2">'.makePopupLink('?view=log', 'zmLog', 'log', '<span class="nav-link '.$class.'">'.translate('Log').'</span>').'</li>'.PHP_EOL;
$result .= '<li id="getLogHTML" class="nav-item dropdown mx-2">'.makeLink('?view=log', '<span class="nav-link '.$class.'">'.translate('Log').'</span>').'</li>'.PHP_EOL;
}
}
@ -588,7 +618,7 @@ function getLogIconHTML() {
$logstate = logState();
$class = ( $logstate == 'alert' ) ? 'text-warning' : (( $logstate == 'alarm' ) ? 'text-danger' : '');
$result .= '<li id="getLogIconHTML" class="nav-item dropdown">'.
makePopupLink('?view=log', 'zmLog', 'log', '<span class="mx-1 ' .$class. '"><i class="material-icons md-18">report</i>'.translate('Log').'</span>').
makeLink('?view=log', '<span class="mx-1 ' .$class. '"><i class="material-icons md-18">report</i>'.translate('Log').'</span>').
'</li>'.PHP_EOL;
}
}
@ -702,8 +732,6 @@ function getHeaderFlipHTML() {
// 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 ) {
@ -723,7 +751,7 @@ function getStatusBtnHTML($status) {
if ( canEdit('System') ) {
//$result .= '<li class="nav-item dropdown">'.PHP_EOL;
$result .= '<form id="getStatusBtnHTML" class="form-inline">'.PHP_EOL;
$result .= '<button type="button" class="btn btn-default navbar-btn" data-toggle="modal" data-target="#modalState">' .$status. '</button>'.PHP_EOL;
$result .= '<button type="button" class="btn btn-default navbar-btn" id="stateModalBtn">' .$status. '</button>'.PHP_EOL;
$result .= '</form>'.PHP_EOL;
//$result .= '</li>'.PHP_EOL;
@ -754,15 +782,84 @@ function runtimeStatus($running=null) {
return $running ? ($state ? $state : translate('Running')) : translate('Stopped');
}
function getStatsTableHTML($eid, $fid, $row='') {
if ( !canView('Events') ) return;
$result = '';
$sql = 'SELECT S.*,E.*,Z.Name AS ZoneName,Z.Units,Z.Area,M.Name AS MonitorName FROM Stats AS S LEFT JOIN Events AS E ON S.EventId = E.Id LEFT JOIN Zones AS Z ON S.ZoneId = Z.Id LEFT JOIN Monitors AS M ON E.MonitorId = M.Id WHERE S.EventId = ? AND S.FrameId = ? ORDER BY S.ZoneId';
$stats = dbFetchAll( $sql, NULL, array( $eid, $fid ) );
$result .= '<table id="contentStatsTable' .$row. '"'.PHP_EOL;
$result .= 'data-toggle="table"'.PHP_EOL;
$result .= 'data-toolbar="#toolbar"'.PHP_EOL;
$result .= 'class="table-sm table-borderless contentStatsTable"'.PHP_EOL;
$result .= 'cellspacing="0">'.PHP_EOL;
$result .= '<caption>' .translate('Stats'). ' - ' .$eid. ' - ' .$fid. '</caption>'.PHP_EOL;
$result .= '<thead>'.PHP_EOL;
$result .= '<tr>'.PHP_EOL;
$result .= '<th class="colZone font-weight-bold" data-align="center">' .translate('Zone'). '</th>'.PHP_EOL;
$result .= '<th class="colPixelDiff font-weight-bold" data-align="center">' .translate('PixelDiff'). '</th>'.PHP_EOL;
$result .= '<th class="colAlarmPx font-weight-bold" data-align="center">' .translate('AlarmPx'). '</th>'.PHP_EOL;
$result .= '<th class="colFilterPx font-weight-bold" data-align="center">' .translate('FilterPx'). '</th>'.PHP_EOL;
$result .= '<th class="colBlobPx font-weight-bold" data-align="center">' .translate('BlobPx'). '</th>'.PHP_EOL;
$result .= '<th class="colBlobs font-weight-bold" data-align="center">' .translate('Blobs'). '</th>'.PHP_EOL;
$result .= '<th class="colBlobSizes font-weight-bold" data-align="center">' .translate('BlobSizes'). '</th>'.PHP_EOL;
$result .= '<th class="colAlarmLimits font-weight-bold" data-align="center">' .translate('AlarmLimits'). '</th>'.PHP_EOL;
$result .= '<th class="colScore font-weight-bold" data-align="center">' .translate('Score'). '</th>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
$result .= '</thead>'.PHP_EOL;
$result .= '<tbody>'.PHP_EOL;
if ( count($stats) ) {
foreach ( $stats as $stat ) {
$result .= '<tr>'.PHP_EOL;
$result .= '<td class="colZone">' .validHtmlStr($stat['ZoneName']). '</td>'.PHP_EOL;
$result .= '<td class="colPixelDiff">' .validHtmlStr($stat['PixelDiff']). '</td>'.PHP_EOL;
$result .= '<td class="colAlarmPx">' .sprintf( "%d (%d%%)", $stat['AlarmPixels'], (100*$stat['AlarmPixels']/$stat['Area']) ). '</td>'.PHP_EOL;
$result .= '<td class="colFilterPx">' .sprintf( "%d (%d%%)", $stat['FilterPixels'], (100*$stat['FilterPixels']/$stat['Area']) ).'</td>'.PHP_EOL;
$result .= '<td class="colBlobPx">' .sprintf( "%d (%d%%)", $stat['BlobPixels'], (100*$stat['BlobPixels']/$stat['Area']) ). '</td>'.PHP_EOL;
$result .= '<td class="colBlobs">' .validHtmlStr($stat['Blobs']). '</td>'.PHP_EOL;
if ( $stat['Blobs'] > 1 ) {
$result .= '<td class="colBlobSizes">' .sprintf( "%d-%d (%d%%-%d%%)", $stat['MinBlobSize'], $stat['MaxBlobSize'], (100*$stat['MinBlobSize']/$stat['Area']), (100*$stat['MaxBlobSize']/$stat['Area']) ). '</td>'.PHP_EOL;
} else {
$result .= '<td class="colBlobSizes">' .sprintf( "%d (%d%%)", $stat['MinBlobSize'], 100*$stat['MinBlobSize']/$stat['Area'] ). '</td>'.PHP_EOL;
}
$result .= '<td class="colAlarmLimits">' .validHtmlStr($stat['MinX'].",".$stat['MinY']."-".$stat['MaxX'].",".$stat['MaxY']). '</td>'.PHP_EOL;
$result .= '<td class="colScore">' .$stat['Score']. '</td>'.PHP_EOL;
}
} else {
$result .= '<tr>'.PHP_EOL;
$result .= '<td class="rowNoStats" colspan="9">' .translate('NoStatisticsRecorded'). '</td>'.PHP_EOL;
$result .= '</tr>'.PHP_EOL;
}
$result .= '</tbody>'.PHP_EOL;
$result .= '</table>'.PHP_EOL;
return $result;
}
// Use this function to manually insert the csrf key into the form when using a modal generated via ajax call
function getCSRFinputHTML() {
if ( isset($GLOBALS['csrf']['key']) ) {
$result = '<input type="hidden" name="__csrf_magic" value="key:' .csrf_hash($GLOBALS['csrf']['key']). '" />'.PHP_EOL;
} else {
$result = '';
}
return $result;
}
function xhtmlFooter() {
global $css;
global $cspNonce;
global $view;
global $skin;
global $basename;
if ( canEdit('System') ) {
include("skins/$skin/views/state.php");
}
$skinJsPhpFile = getSkinFile('js/skin.js.php');
$cssJsFile = getSkinFile('js/'.$css.'.js');
$viewJsFile = getSkinFile('views/js/'.$basename.'.js');
@ -776,17 +873,20 @@ function xhtmlFooter() {
<script src="skins/<?php echo $skin; ?>/js/jquery.js"></script>
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.12.1/jquery-ui.js"></script>
<script src="skins/<?php echo $skin; ?>/js/bootstrap.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/bootstrap-table.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/tableExport.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/bootstrap-table-export.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/bootstrap-table-page-jump-to.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/bootstrap-table-cookie.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/chosen/chosen.jquery.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/dateTimePicker/jquery-ui-timepicker-addon.js"></script>
<script src="<?php echo cache_bust('js/Server.js'); ?>"></script>
<?php echo output_script_if_exists(array(
'js/bootstrap-table.min.js',
'js/tableExport.min.js',
'js/bootstrap-table-export.min.js',
'js/bootstrap-table-page-jump-to.min.js',
'js/bootstrap-table-cookie.min.js',
'js/bootstrap-table-toolbar.min.js',
'js/bootstrap-table-auto-refresh.min.js',
'js/chosen/chosen.jquery.min.js',
'js/dateTimePicker/jquery-ui-timepicker-addon.js',
'js/Server.js',
), true );
?>
<script nonce="<?php echo $cspNonce; ?>">var $j = jQuery.noConflict();</script>
<script src="<?php echo cache_bust('skins/'.$skin.'/views/js/state.js') ?>"></script>
<?php
if ( $view == 'event' ) {
?>
@ -834,7 +934,10 @@ function xhtmlFooter() {
// This is used in the log popup for the export function. Not sure if it's used anywhere else
?>
<script src="<?php echo cache_bust('js/overlay.js') ?>"></script>
<?php } ?>
<?php
} else if ( $basename == 'monitor' ) {
echo output_script_if_exists(array('js/leaflet/leaflet.js'), false);
} ?>
<script nonce="<?php echo $cspNonce; ?>">$j('.chosen').chosen();</script>
</body>
</html>

View File

@ -43,316 +43,6 @@ function getSlotFrame($slot) {
return $slotFrame;
}
function parseFilterToTree($filter) {
if ( count($filter['terms']) <= 0 ) {
return false;
}
$terms = $filter['terms'];
$StorageArea = NULL;
$postfixExpr = array();
$postfixStack = array();
$priorities = array(
'<' => 1,
'<=' => 1,
'>' => 1,
'>=' => 1,
'=' => 2,
'!=' => 2,
'=~' => 2,
'!~' => 2,
'=[]' => 2,
'![]' => 2,
'and' => 3,
'or' => 4,
);
for ( $i = 0; $i < count($terms); $i++ ) {
$term = $terms[$i];
if ( !empty($term['cnj']) ) {
while( true ) {
if ( !count($postfixStack) ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
} elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
} elseif ( $priorities[$term['cnj']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
} else {
$postfixExpr[] = array_pop($postfixStack);
}
}
} # end if ! empty cnj
if ( !empty($term['obr']) ) {
for ( $j = 0; $j < $term['obr']; $j++ ) {
$postfixStack[] = array('type'=>'obr', 'value'=>$term['obr']);
}
}
if ( !empty($term['attr']) ) {
$dtAttr = false;
switch ( $term['attr']) {
case 'MonitorName':
$sqlValue = 'M.'.preg_replace( '/^Monitor/', '', $term['attr']);
break;
case 'ServerId':
$sqlValue .= 'M.ServerId';
break;
case 'StorageServerId':
$sqlValue .= 'S.ServerId';
break;
case 'FilterServerId':
$sqlValue .= ZM_SERVER_ID;
break;
case 'DateTime':
case 'StartDateTime':
$sqlValue = 'E.StartTime';
$dtAttr = true;
break;
case 'Date':
case 'StartDate':
$sqlValue = 'to_days(E.StartTime)';
$dtAttr = true;
break;
case 'Time':
case 'StartTime':
$sqlValue = 'extract(hour_second from E.StartTime)';
break;
case 'Weekday':
case 'StartWeekday':
$sqlValue = 'weekday(E.StartTime)';
break;
case 'EndDateTime':
$sqlValue = 'E.EndTime';
$dtAttr = true;
break;
case 'EndDate':
$sqlValue = 'to_days(E.EndTime)';
$dtAttr = true;
break;
case 'EndTime':
$sqlValue = 'extract(hour_second from E.EndTime)';
break;
case 'EndWeekday':
$sqlValue = 'weekday(E.EndTime)';
break;
case 'Id':
case 'Name':
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':
$sqlValue = '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 ) {
for ( $j = 0; $j < count($terms); $j++ ) {
if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) {
$StorageArea = new Storage($terms[$j]['val']);
break;
}
} // end foreach remaining term
if ( ! $StorageArea ) $StorageArea = new Storage();
} // end no StorageArea found yet
$sqlValue = getDiskPercent($StorageArea);
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 = 0; $j < count($terms); $j++ ) {
if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) {
$StorageArea = new Storage($terms[$j]['val']);
break;
}
} // end foreach remaining term
if ( ! $StorageArea ) $StorageArea = new Storage();
} // end no StorageArea found yet
$sqlValue = getDiskBlocks($StorageArea);
break;
default :
$sqlValue = $term['attr'];
break;
}
if ( $dtAttr ) {
$postfixExpr[] = array('type'=>'attr', 'value'=>$term['attr'], 'sqlValue'=>$sqlValue, 'dtAttr'=>true);
} else {
$postfixExpr[] = array('type'=>'attr', 'value'=>$term['attr'], 'sqlValue'=>$sqlValue);
}
} # end if attr
if ( isset($term['op']) ) {
if ( empty($term['op']) ) {
$term['op'] = '=';
}
switch ( $term['op']) {
case '=' :
case '!=' :
case '>=' :
case '>' :
case '<' :
case '<=' :
case 'LIKE' :
case 'NOT LIKE':
$sqlValue = $term['op'];
break;
case '=~' :
$sqlValue = 'regexp';
break;
case '!~' :
$sqlValue = 'not regexp';
break;
case '=[]' :
case 'IN' :
$sqlValue = 'in (';
break;
case '![]' :
$sqlValue = 'not in (';
break;
case 'IS' :
case 'IS NOT' :
if ( $term['val'] == 'Odd' ) {
$sqlValue .= ' % 2 = 1';
} else if ( $term['val'] == 'Even' ) {
$sqlValue .= ' % 2 = 0';
} else {
$sqlValue .= ' '.$term['op'];
}
break;
default :
ZM\Error('Unknown operator in filter '.$term['op']);
}
while( true ) {
if ( !count($postfixStack) ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
break;
} elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
break;
} elseif ( $priorities[$term['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue );
break;
} else {
$postfixExpr[] = array_pop($postfixStack);
}
} // end while
} // end if operator
if ( isset($term['val']) ) {
$valueList = array();
foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) {
switch ( $term['attr'] ) {
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 = new Storage($value);
if ( $value != 'NULL' )
$value = dbEscape($value);
break;
case 'DateTime':
case 'EndDateTime':
case 'StartDateTime':
$value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'";
break;
case 'Date':
case 'EndDate':
case 'StartDate':
$value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
case 'Time':
case 'EndTime':
case 'StartTime':
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
case 'Weekday':
case 'EndWeekday':
case 'StartWeekday':
$value = 'weekday(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
default :
if ( $value != 'NULL' )
$value = dbEscape($value);
} // end switch attribute
$valueList[] = $value;
} // end foreach value
$postfixExpr[] = array('type'=>'val', 'value'=>$term['val'], 'sqlValue'=>join(',', $valueList));
} // end if has val
if ( !empty($term['cbr']) ) {
for ( $j = 0; $j < $term['cbr']; $j++ ) {
while ( count($postfixStack) ) {
$element = array_pop($postfixStack);
if ( $element['type'] == 'obr' ) {
$postfixExpr[count($postfixExpr)-1]['bracket'] = true;
break;
}
$postfixExpr[] = $element;
}
}
} #end if cbr
} # end foreach term
while ( count($postfixStack) ) {
$postfixExpr[] = array_pop($postfixStack);
}
$exprStack = array();
//foreach ( $postfixExpr as $element )
//{
//echo $element['value'].' ';
//}
//echo "<br>";
foreach ( $postfixExpr as $element ) {
if ( $element['type'] == 'attr' || $element['type'] == 'val' ) {
$node = array('data'=>$element, 'count'=>0);
$exprStack[] = $node;
} elseif ( $element['type'] == 'op' || $element['type'] == 'cnj' ) {
$right = array_pop($exprStack);
$left = array_pop($exprStack);
$node = array('data'=>$element, 'count'=>2+$left['count']+$right['count'], 'right'=>$right, 'left'=>$left);
$exprStack[] = $node;
} else {
ZM\Fatal('Unexpected element type \''.$element['type'].'\', value \''.$element['value'].'\'');
}
}
if ( count($exprStack) != 1 ) {
ZM\Fatal('Expression stack has '.count($exprStack).' elements');
}
return array_pop($exprStack);
}
function _parseTreeToInfix($node) {
$expression = '';
if ( isset($node) ) {
@ -443,7 +133,7 @@ function parseTreeToFilter($tree) {
function parseTreeToQuery($tree) {
$filter = parseTreeToFilter($tree);
parseFilter($filter, false, '&');
return $filter['query'];
return $filter['querystring'];
}
function _drawTree($node, $level) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -23,6 +23,22 @@
//
var popupOptions = "resizable,scrollbars,status=no,toolbar=yes";
// Globally define the icons used in the bootstrap-table top-right toolbar
var icons = {
paginationSwitchDown: 'fa-caret-square-o-down',
paginationSwitchUp: 'fa-caret-square-o-up',
export: 'fa-download',
refresh: 'fa-retweet',
autoRefresh: 'fa-clock-o',
advancedSearchIcon: 'fa-chevron-down',
toggleOff: 'fa-toggle-off',
toggleOn: 'fa-toggle-on',
columns: 'fa-th-list',
fullscreen: 'fa-arrows-alt',
detailOpen: 'fa-plus',
detailClose: 'fa-minus'
};
function checkSize() {
if ( 0 ) {
if (window.outerHeight) {
@ -159,6 +175,22 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() {
});
});
document.querySelectorAll(".zmlink").forEach(function(el) {
el.addEventListener("click", function onClick(evt) {
var el = this;
var url;
if ( el.hasAttribute("href") ) {
// <a>
url = el.getAttribute("href");
} else {
// buttons
url = el.getAttribute("data-url");
}
evt.preventDefault();
window.location.assign(url);
});
});
document.querySelectorAll(".pillList a").forEach(function addOnClick(el) {
el.addEventListener("click", submitTab);
});
@ -312,6 +344,10 @@ if ( currentView != 'none' && currentView != 'login' ) {
$j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON.
$j(document).ready(function() {
// Load the Logout and State modals into the dom
getLogoutModal();
if ( canEditSystem ) $j('#stateModalBtn').click(getStateModal);
// Trigger autorefresh of the widget bar stats on the navbar
if ( $j('.navbar').length ) {
setInterval(getNavBar, navBarRefresh);
@ -385,13 +421,35 @@ if ( currentView != 'none' && currentView != 'login' ) {
$j("button.navbar-toggler").click();
}
});
// Manage the optionhelp links
$j(".optionhelp").click(function(evt) {
$j.getJSON(thisUrl + '?request=modal&modal=optionhelp&ohndx=' + evt.target.id)
.done(optionhelpModal)
.fail(logAjaxFail);
});
});
// Manage the modal html we received after user clicks help link
function optionhelpModal(data) {
if ( $j('#optionhelp').length ) {
$j('#optionhelp').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
$j('#optionhelp').modal('show');
// Manage the CLOSE optionhelp modal button
document.getElementById("ohCloseBtn").addEventListener("click", function onOhCloseClick(evt) {
$j('#optionhelp').modal('hide');
});
}
function getNavBar() {
$j.getJSON(thisUrl + '?view=request&request=status&entity=navBar')
.done(setNavBar)
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText.replace(/(<([^>]+)>)/gi, ''));
if ( textStatus != "timeout" ) {
// The idea is that this should only fail due to auth, so reload the page
// which should go to login if it can't stay logged in.
@ -401,6 +459,10 @@ if ( currentView != 'none' && currentView != 'login' ) {
}
function setNavBar(data) {
if ( !data ) {
console.error("No data in setNavBar");
return;
}
if ( data.auth ) {
if ( data.auth != auth_hash ) {
// Update authentication token.
@ -687,7 +749,179 @@ function bwClickFunction() {
function reminderClickFunction() {
$j("#dropdown_reminder a").click(function() {
var option = $j(this).data('pdsa-dropdown-val');
$j.getJSON(thisUrl + '?view=version&action=version&option=' + option);
window.location.reload(true); //Do a full refresh to update ZM_DYN_LAST_VERSION
$j.getJSON(thisUrl + '?view=version&action=version&option=' + option)
.done(window.location.reload(true)) //Do a full refresh to update ZM_DYN_LAST_VERSION
.fail(logAjaxFail);
});
}
// Load then show the "You No Permission" error modal
function enoperm() {
$j.getJSON(thisUrl + '?request=modal&modal=enoperm')
.done(function(data) {
if ( $j('#ENoPerm').length ) {
$j('#ENoPerm').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
$j('#ENoPerm').modal('show');
// Manage the CLOSE optionhelp modal button
document.getElementById("enpCloseBtn").addEventListener("click", function onENPCloseClick(evt) {
$j('#ENoPerm').modal('hide');
});
})
.fail(logAjaxFail);
}
function getLogoutModal() {
$j.getJSON(thisUrl + '?request=modal&modal=logout')
.done(function(data) {
if ( $j('#modalLogout').length ) {
$j('#modalLogout').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
})
.fail(logAjaxFail);
}
function getStateModal() {
$j.getJSON(thisUrl + '?request=modal&modal=state')
.done(function(data) {
if ( $j('#modalState').length ) {
$j('#modalState').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
$j('#modalState').modal('show');
manageStateModalBtns();
})
.fail(logAjaxFail);
}
function manageStateModalBtns() {
// Enable or disable the Delete button depending on the selected run state
$j("#runState").change(function() {
runstate = $j(this).val();
if ( (runstate == 'stop') || (runstate == 'restart') || (runstate == 'start') || (runstate == 'default') ) {
$j("#btnDelete").prop("disabled", true);
} else {
$j("#btnDelete").prop("disabled", false);
}
});
// Enable or disable the Save button when entering a new state
$j("#newState").keyup(function() {
length = $j(this).val().length;
if ( length < 1 ) {
$j("#btnSave").prop("disabled", true);
} else {
$j("#btnSave").prop("disabled", false);
}
});
// Delete a state
$j("#btnDelete").click(function() {
stateStuff('delete', $j("#runState").val());
});
// Save a new state
$j("#btnSave").click(function() {
stateStuff('save', undefined, $j("#newState").val());
});
// Change state
$j("#btnApply").click(function() {
stateStuff('state', $j("#runState").val());
});
}
function stateStuff(action, runState, newState) {
// the state action will redirect to console
var formData = {
'view': 'state',
'action': action,
'apply': 1,
'runState': runState,
'newState': newState
};
$j("#pleasewait").toggleClass("hidden");
$j.ajax({
type: 'POST',
url: thisUrl,
data: formData,
dataType: 'html',
timeout: 0
}).done(function(data) {
location.reload();
});
}
function logAjaxFail(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + ", " + error);
console.log("Response Text: " + jqxhr.responseText.replace(/(<([^>]+)>)/gi, '')); // strip any html from the response
}
// Load the Modal HTML via Ajax call
function getModal(id) {
$j.getJSON(thisUrl + '?request=modal&modal='+id)
.done(function(data) {
if ( !data ) {
console.error("Get modal returned no data");
return;
}
if ( $j('#'+id).length ) {
$j('#'+id).replaceWith(data.html);
} else {
$j('body').append(data.html);
}
manageModalBtns(id);
modal = $j('#'+id+'Modal');
if ( ! modal.length ) {
console.log('No modal found');
}
$j('#'+id+'Modal').modal('show');
})
.fail(logAjaxFail);
}
function manageModalBtns(id) {
// Manage the CANCEL modal button
var cancelBtn = document.getElementById(id+"CancelBtn");
if ( cancelBtn ) {
document.getElementById(id+"CancelBtn").addEventListener('click', function onCancelClick(evt) {
$j('#'+id).modal('hide');
});
}
// 'data-on-click-this' calls the global function in the attribute value with the element when a click happens.
document.querySelectorAll('#'+id+'Modal button[data-on-click]').forEach(function attachOnClick(el) {
var fnName = el.getAttribute('data-on-click');
if ( !window[fnName] ) {
console.error('Nothing found to bind to ' + fnName + ' on element ' + el.name);
return;
} else {
console.log("Setting onclick for " + el.name);
}
el.onclick = window[fnName].bind(el, el);
});
}
function human_filesize(size, precision = 2) {
var units = Array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
var step = 1024;
var i = 0;
while ((size / step) > 0.9) {
size = size / step;
i++;
}
return (Math.round(size*(10^precision))/(10^precision))+units[i];
}

View File

@ -72,3 +72,4 @@ var imagePrefix = "<?php echo '?view=image&eid=' ?>";
var auth_hash = '<?php echo generateAuthHash(ZM_AUTH_HASH_IPS) ?>';
var auth_relay = '<?php echo get_auth_relay() ?>';
var running = <?php echo daemonCheck()?'true':'false' ?>;

View File

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

View File

@ -372,7 +372,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<?php
}
?>
<td class="colZones"><?php echo makePopupLink('?view=zones&amp;mid='.$monitor['Id'], 'zmZones', array('zones', $monitor['Width'], $monitor['Height']), $monitor['ZoneCount'], canView('Monitors')) ?></td>
<td class="colZones"><?php echo makeLink('?view=zones&amp;mid='.$monitor['Id'], $monitor['ZoneCount'], canView('Monitors')) ?></td>
<?php
if ( canEdit('Monitors') ) {
?>
@ -437,8 +437,5 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
</div>
</form>
<?php
include('function.php');
// Include Donate Modal
include('donate.php');
xhtmlFooter();
?>

View File

@ -145,32 +145,39 @@ if ( isset($_REQUEST['newControl']) ) {
$newControl = $control;
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('ControlCap').' - '.$newControl['Name']);
?>
<body>
<div id="page">
<div id="header">
<h2><?php echo translate('ControlCap') ?> - <?php echo validHtmlStr($newControl['Name']) ?></h2>
</div>
<div id="content">
<ul class="tabList">
<?php echo getNavBarHTML() ?>
<div id="page" class="container-fluid">
<div class="row flex-nowrap">
<nav> <!-- BEGIN PILL LIST -->
<ul class="nav nav-pills flex-column h-100 pillList" id="pills-tab" role="tab" aria-orientation="vertical">
<?php
foreach ( $tabs as $name=>$value ) {
if ( $tab == $name ) {
?>
<li class="active"><?php echo $value ?></li>
<li class="nav-item form-control-sm my-1"><a class="nav-link<?php echo $tab == $name ? ' active' : '' ?>" href="#" data-tab-name="<?php echo $name ?>"><?php echo $value ?></a></li>
<?php
} else {
?>
<li><a href="#" data-tab-name="<?php echo $name ?>"><?php echo $value ?></a></li>
<?php
}
}
?>
</ul>
</nav> <!-- END PILL LIST -->
<div class="clear"></div>
<div class="d-flex flex-column col-sm-offset-2 container-fluid">
<!-- BEGIN MINI HEADER -->
<div class="w-100 py-1">
<div class="float-left pl-3">
<button type="button" id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
<button type="button" id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
</div>
<div class="w-100 pt-2">
<h2><?php echo translate('ControlCap') ?> - <?php echo validHtmlStr($newControl['Name']) ?></h2>
</div>
</div>
<!-- BEGIN ITEM LIST -->
<div class="d-flex flex-row container-fluid pr-0">
<form name="contentForm" id="contentForm" method="post" action="?" class="validateFormOnSubmit">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
@ -320,158 +327,158 @@ switch ( $tab ) {
case 'main' :
{
?>
<tr><th scope="row"><?php echo translate('Name') ?></th><td><input type="text" name="newControl[Name]" value="<?php echo validHtmlStr($newControl['Name']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('Type') ?></th><td><?php
<tr><th class="text-right pr-3" scope="row"><?php echo translate('Name') ?></th><td><input type="text" name="newControl[Name]" value="<?php echo validHtmlStr($newControl['Name']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('Type') ?></th><td><?php
$types = array( 'Local'=>translate('Local'), 'Remote'=>translate('Remote'), 'Ffmpeg'=>translate('Ffmpeg'), 'Libvlc'=>translate('Libvlc'), 'cURL'=>'cURL');
echo buildSelect('newControl[Type]', $types); ?></td></tr>
<tr><th scope="row"><?php echo translate('Protocol') ?></th><td><input type="text" name="newControl[Protocol]" value="<?php echo validHtmlStr($newControl['Protocol']) ?>" size="24"/></td></tr>
<tr><th scope="row"><?php echo translate('CanWake') ?></th><td><input type="checkbox" name="newControl[CanWake]" value="1"<?php if ( !empty($newControl['CanWake']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanSleep') ?></th><td><input type="checkbox" name="newControl[CanSleep]" value="1"<?php if ( !empty($newControl['CanSleep']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanReset') ?></th><td><input type="checkbox" name="newControl[CanReset]" value="1"<?php if ( !empty($newControl['CanReset']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanReboot') ?></th><td><input type="checkbox" name="newControl[CanReboot]" value="1"<?php if ( !empty($newControl['CanReboot']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('Protocol') ?></th><td><input type="text" name="newControl[Protocol]" value="<?php echo validHtmlStr($newControl['Protocol']) ?>" size="24"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanWake') ?></th><td><input type="checkbox" name="newControl[CanWake]" value="1"<?php if ( !empty($newControl['CanWake']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanSleep') ?></th><td><input type="checkbox" name="newControl[CanSleep]" value="1"<?php if ( !empty($newControl['CanSleep']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanReset') ?></th><td><input type="checkbox" name="newControl[CanReset]" value="1"<?php if ( !empty($newControl['CanReset']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanReboot') ?></th><td><input type="checkbox" name="newControl[CanReboot]" value="1"<?php if ( !empty($newControl['CanReboot']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php
break;
}
case 'move' :
{
?>
<tr><th scope="row"><?php echo translate('CanMove') ?></th><td><input type="checkbox" name="newControl[CanMove]" value="1"<?php if ( !empty($newControl['CanMove']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanMoveDiag') ?></th><td><input type="checkbox" name="newControl[CanMoveDiag]" value="1"<?php if ( !empty($newControl['CanMoveDiag']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanMoveMap') ?></th><td><input type="checkbox" name="newControl[CanMoveMap]" value="1"<?php if ( !empty($newControl['CanMoveMap']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanMoveAbs') ?></th><td><input type="checkbox" name="newControl[CanMoveAbs]" value="1"<?php if ( !empty($newControl['CanMoveAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanMoveRel') ?></th><td><input type="checkbox" name="newControl[CanMoveRel]" value="1"<?php if ( !empty($newControl['CanMoveRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanMoveCon') ?></th><td><input type="checkbox" name="newControl[CanMoveCon]" value="1"<?php if ( !empty($newControl['CanMoveCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanMove') ?></th><td><input type="checkbox" name="newControl[CanMove]" value="1"<?php if ( !empty($newControl['CanMove']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanMoveDiag') ?></th><td><input type="checkbox" name="newControl[CanMoveDiag]" value="1"<?php if ( !empty($newControl['CanMoveDiag']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanMoveMap') ?></th><td><input type="checkbox" name="newControl[CanMoveMap]" value="1"<?php if ( !empty($newControl['CanMoveMap']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanMoveAbs') ?></th><td><input type="checkbox" name="newControl[CanMoveAbs]" value="1"<?php if ( !empty($newControl['CanMoveAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanMoveRel') ?></th><td><input type="checkbox" name="newControl[CanMoveRel]" value="1"<?php if ( !empty($newControl['CanMoveRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanMoveCon') ?></th><td><input type="checkbox" name="newControl[CanMoveCon]" value="1"<?php if ( !empty($newControl['CanMoveCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php
break;
}
case 'pan' :
{
?>
<tr><th scope="row"><?php echo translate('CanPan') ?></th><td><input type="checkbox" name="newControl[CanPan]" value="1"<?php if ( !empty($newControl['CanPan']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th scope="row"><?php echo translate('MinPanRange') ?></th><td><input type="number" name="newControl[MinPanRange]" value="<?php echo validHtmlStr($newControl['MinPanRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxPanRange') ?></th><td><input type="number" name="newControl[MaxPanRange]" value="<?php echo validHtmlStr($newControl['MaxPanRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinPanStep') ?></th><td><input type="number" name="newControl[MinPanStep]" value="<?php echo validHtmlStr($newControl['MinPanStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxPanStep') ?></th><td><input type="number" name="newControl[MaxPanStep]" value="<?php echo validHtmlStr($newControl['MaxPanStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasPanSpeed') ?></th><td><input type="checkbox" name="newControl[HasPanSpeed]" value="1"<?php if ( !empty($newControl['HasPanSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinPanSpeed') ?></th><td><input type="number" name="newControl[MinPanSpeed]" value="<?php echo validHtmlStr($newControl['MinPanSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxPanSpeed') ?></th><td><input type="number" name="newControl[MaxPanSpeed]" value="<?php echo validHtmlStr($newControl['MaxPanSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasTurboPan') ?></th><td><input type="checkbox" name="newControl[HasTurboPan]" value="1"<?php if ( !empty($newControl['HasTurboPan']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('TurboPanSpeed') ?></th><td><input type="number" name="newControl[TurboPanSpeed]" value="<?php echo validHtmlStr($newControl['TurboPanSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanPan') ?></th><td><input type="checkbox" name="newControl[CanPan]" value="1"<?php if ( !empty($newControl['CanPan']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinPanRange') ?></th><td><input type="number" name="newControl[MinPanRange]" value="<?php echo validHtmlStr($newControl['MinPanRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxPanRange') ?></th><td><input type="number" name="newControl[MaxPanRange]" value="<?php echo validHtmlStr($newControl['MaxPanRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinPanStep') ?></th><td><input type="number" name="newControl[MinPanStep]" value="<?php echo validHtmlStr($newControl['MinPanStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxPanStep') ?></th><td><input type="number" name="newControl[MaxPanStep]" value="<?php echo validHtmlStr($newControl['MaxPanStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasPanSpeed') ?></th><td><input type="checkbox" name="newControl[HasPanSpeed]" value="1"<?php if ( !empty($newControl['HasPanSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinPanSpeed') ?></th><td><input type="number" name="newControl[MinPanSpeed]" value="<?php echo validHtmlStr($newControl['MinPanSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxPanSpeed') ?></th><td><input type="number" name="newControl[MaxPanSpeed]" value="<?php echo validHtmlStr($newControl['MaxPanSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasTurboPan') ?></th><td><input type="checkbox" name="newControl[HasTurboPan]" value="1"<?php if ( !empty($newControl['HasTurboPan']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('TurboPanSpeed') ?></th><td><input type="number" name="newControl[TurboPanSpeed]" value="<?php echo validHtmlStr($newControl['TurboPanSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'tilt' :
{
?>
<tr><th scope="row"><?php echo translate('CanTilt') ?></th><td><input type="checkbox" name="newControl[CanTilt]" value="1"<?php if ( !empty($newControl['CanTilt']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th scope="row"><?php echo translate('MinTiltRange') ?></th><td><input type="number" name="newControl[MinTiltRange]" value="<?php echo validHtmlStr($newControl['MinTiltRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxTiltRange') ?></th><td><input type="number" name="newControl[MaxTiltRange]" value="<?php echo validHtmlStr($newControl['MaxTiltRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinTiltStep') ?></th><td><input type="number" name="newControl[MinTiltStep]" value="<?php echo validHtmlStr($newControl['MinTiltStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxTiltStep') ?></th><td><input type="number" name="newControl[MaxTiltStep]" value="<?php echo validHtmlStr($newControl['MaxTiltStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasTiltSpeed') ?></th><td><input type="checkbox" name="newControl[HasTiltSpeed]" value="1"<?php if ( !empty($newControl['HasTiltSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinTiltSpeed') ?></th><td><input type="number" name="newControl[MinTiltSpeed]" value="<?php echo validHtmlStr($newControl['MinTiltSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxTiltSpeed') ?></th><td><input type="number" name="newControl[MaxTiltSpeed]" value="<?php echo validHtmlStr($newControl['MaxTiltSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasTurboTilt') ?></th><td><input type="checkbox" name="newControl[HasTurboTilt]" value="1"<?php if ( !empty($newControl['HasTurboTilt']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('TurboTiltSpeed') ?></th><td><input type="number" name="newControl[TurboTiltSpeed]" value="<?php echo validHtmlStr($newControl['TurboTiltSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanTilt') ?></th><td><input type="checkbox" name="newControl[CanTilt]" value="1"<?php if ( !empty($newControl['CanTilt']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinTiltRange') ?></th><td><input type="number" name="newControl[MinTiltRange]" value="<?php echo validHtmlStr($newControl['MinTiltRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxTiltRange') ?></th><td><input type="number" name="newControl[MaxTiltRange]" value="<?php echo validHtmlStr($newControl['MaxTiltRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinTiltStep') ?></th><td><input type="number" name="newControl[MinTiltStep]" value="<?php echo validHtmlStr($newControl['MinTiltStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxTiltStep') ?></th><td><input type="number" name="newControl[MaxTiltStep]" value="<?php echo validHtmlStr($newControl['MaxTiltStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasTiltSpeed') ?></th><td><input type="checkbox" name="newControl[HasTiltSpeed]" value="1"<?php if ( !empty($newControl['HasTiltSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinTiltSpeed') ?></th><td><input type="number" name="newControl[MinTiltSpeed]" value="<?php echo validHtmlStr($newControl['MinTiltSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxTiltSpeed') ?></th><td><input type="number" name="newControl[MaxTiltSpeed]" value="<?php echo validHtmlStr($newControl['MaxTiltSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasTurboTilt') ?></th><td><input type="checkbox" name="newControl[HasTurboTilt]" value="1"<?php if ( !empty($newControl['HasTurboTilt']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('TurboTiltSpeed') ?></th><td><input type="number" name="newControl[TurboTiltSpeed]" value="<?php echo validHtmlStr($newControl['TurboTiltSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'zoom' :
{
?>
<tr><th scope="row"><?php echo translate('CanZoom') ?></th><td><input type="checkbox" name="newControl[CanZoom]" value="1"<?php if ( !empty($newControl['CanZoom']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th scope="row"><?php echo translate('CanZoomAbs') ?></th><td><input type="checkbox" name="newControl[CanZoomAbs]" value="1"<?php if ( !empty($newControl['CanZoomAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanZoomRel') ?></th><td><input type="checkbox" name="newControl[CanZoomRel]" value="1"<?php if ( !empty($newControl['CanZoomRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanZoomCon') ?></th><td><input type="checkbox" name="newControl[CanZoomCon]" value="1"<?php if ( !empty($newControl['CanZoomCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinZoomRange') ?></th><td><input type="number" name="newControl[MinZoomRange]" value="<?php echo validHtmlStr($newControl['MinZoomRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxZoomRange') ?></th><td><input type="number" name="newControl[MaxZoomRange]" value="<?php echo validHtmlStr($newControl['MaxZoomRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinZoomStep') ?></th><td><input type="number" name="newControl[MinZoomStep]" value="<?php echo validHtmlStr($newControl['MinZoomStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxZoomStep') ?></th><td><input type="number" name="newControl[MaxZoomStep]" value="<?php echo validHtmlStr($newControl['MaxZoomStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasZoomSpeed') ?></th><td><input type="checkbox" name="newControl[HasZoomSpeed]" value="1"<?php if ( !empty($newControl['HasZoomSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinZoomSpeed') ?></th><td><input type="number" name="newControl[MinZoomSpeed]" value="<?php echo validHtmlStr($newControl['MinZoomSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxZoomSpeed') ?></th><td><input type="number" name="newControl[MaxZoomSpeed]" value="<?php echo validHtmlStr($newControl['MaxZoomSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanZoom') ?></th><td><input type="checkbox" name="newControl[CanZoom]" value="1"<?php if ( !empty($newControl['CanZoom']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanZoomAbs') ?></th><td><input type="checkbox" name="newControl[CanZoomAbs]" value="1"<?php if ( !empty($newControl['CanZoomAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanZoomRel') ?></th><td><input type="checkbox" name="newControl[CanZoomRel]" value="1"<?php if ( !empty($newControl['CanZoomRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanZoomCon') ?></th><td><input type="checkbox" name="newControl[CanZoomCon]" value="1"<?php if ( !empty($newControl['CanZoomCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinZoomRange') ?></th><td><input type="number" name="newControl[MinZoomRange]" value="<?php echo validHtmlStr($newControl['MinZoomRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxZoomRange') ?></th><td><input type="number" name="newControl[MaxZoomRange]" value="<?php echo validHtmlStr($newControl['MaxZoomRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinZoomStep') ?></th><td><input type="number" name="newControl[MinZoomStep]" value="<?php echo validHtmlStr($newControl['MinZoomStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxZoomStep') ?></th><td><input type="number" name="newControl[MaxZoomStep]" value="<?php echo validHtmlStr($newControl['MaxZoomStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasZoomSpeed') ?></th><td><input type="checkbox" name="newControl[HasZoomSpeed]" value="1"<?php if ( !empty($newControl['HasZoomSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinZoomSpeed') ?></th><td><input type="number" name="newControl[MinZoomSpeed]" value="<?php echo validHtmlStr($newControl['MinZoomSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxZoomSpeed') ?></th><td><input type="number" name="newControl[MaxZoomSpeed]" value="<?php echo validHtmlStr($newControl['MaxZoomSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'focus' :
{
?>
<tr><th scope="row"><?php echo translate('CanFocus') ?></th><td><input type="checkbox" name="newControl[CanFocus]" value="1"<?php if ( !empty($newControl['CanFocus']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanAutoFocus') ?></th><td><input type="checkbox" name="newControl[CanAutoFocus]" value="1"<?php if ( !empty($newControl['CanAutoFocus']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanFocusAbs') ?></th><td><input type="checkbox" name="newControl[CanFocusAbs]" value="1"<?php if ( !empty($newControl['CanFocusAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanFocusRel') ?></th><td><input type="checkbox" name="newControl[CanFocusRel]" value="1"<?php if ( !empty($newControl['CanFocusRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanFocusCon') ?></th><td><input type="checkbox" name="newControl[CanFocusCon]" value="1"<?php if ( !empty($newControl['CanFocusCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinFocusRange') ?></th><td><input type="number" name="newControl[MinFocusRange]" value="<?php echo validHtmlStr($newControl['MinFocusRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxFocusRange') ?></th><td><input type="number" name="newControl[MaxFocusRange]" value="<?php echo validHtmlStr($newControl['MaxFocusRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinFocusStep') ?></th><td><input type="number" name="newControl[MinFocusStep]" value="<?php echo validHtmlStr($newControl['MinFocusStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxFocusStep') ?></th><td><input type="number" name="newControl[MaxFocusStep]" value="<?php echo validHtmlStr($newControl['MaxFocusStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasFocusSpeed') ?></th><td><input type="checkbox" name="newControl[HasFocusSpeed]" value="1"<?php if ( !empty($newControl['HasFocusSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinFocusSpeed') ?></th><td><input type="number" name="newControl[MinFocusSpeed]" value="<?php echo validHtmlStr($newControl['MinFocusSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxFocusSpeed') ?></th><td><input type="number" name="newControl[MaxFocusSpeed]" value="<?php echo validHtmlStr($newControl['MaxFocusSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanFocus') ?></th><td><input type="checkbox" name="newControl[CanFocus]" value="1"<?php if ( !empty($newControl['CanFocus']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanAutoFocus') ?></th><td><input type="checkbox" name="newControl[CanAutoFocus]" value="1"<?php if ( !empty($newControl['CanAutoFocus']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanFocusAbs') ?></th><td><input type="checkbox" name="newControl[CanFocusAbs]" value="1"<?php if ( !empty($newControl['CanFocusAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanFocusRel') ?></th><td><input type="checkbox" name="newControl[CanFocusRel]" value="1"<?php if ( !empty($newControl['CanFocusRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanFocusCon') ?></th><td><input type="checkbox" name="newControl[CanFocusCon]" value="1"<?php if ( !empty($newControl['CanFocusCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinFocusRange') ?></th><td><input type="number" name="newControl[MinFocusRange]" value="<?php echo validHtmlStr($newControl['MinFocusRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxFocusRange') ?></th><td><input type="number" name="newControl[MaxFocusRange]" value="<?php echo validHtmlStr($newControl['MaxFocusRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinFocusStep') ?></th><td><input type="number" name="newControl[MinFocusStep]" value="<?php echo validHtmlStr($newControl['MinFocusStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxFocusStep') ?></th><td><input type="number" name="newControl[MaxFocusStep]" value="<?php echo validHtmlStr($newControl['MaxFocusStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasFocusSpeed') ?></th><td><input type="checkbox" name="newControl[HasFocusSpeed]" value="1"<?php if ( !empty($newControl['HasFocusSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinFocusSpeed') ?></th><td><input type="number" name="newControl[MinFocusSpeed]" value="<?php echo validHtmlStr($newControl['MinFocusSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxFocusSpeed') ?></th><td><input type="number" name="newControl[MaxFocusSpeed]" value="<?php echo validHtmlStr($newControl['MaxFocusSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'iris' :
{
?>
<tr><th scope="row"><?php echo translate('CanIris') ?></th><td><input type="checkbox" name="newControl[CanIris]" value="1"<?php if ( !empty($newControl['CanIris']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th scope="row"><?php echo translate('CanAutoIris') ?></th><td><input type="checkbox" name="newControl[CanAutoIris]" value="1"<?php if ( !empty($newControl['CanAutoIris']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanIrisAbs') ?></th><td><input type="checkbox" name="newControl[CanIrisAbs]" value="1"<?php if ( !empty($newControl['CanIrisAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanIrisRel') ?></th><td><input type="checkbox" name="newControl[CanIrisRel]" value="1"<?php if ( !empty($newControl['CanIrisRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanIrisCon') ?></th><td><input type="checkbox" name="newControl[CanIrisCon]" value="1"<?php if ( !empty($newControl['CanIrisCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinIrisRange') ?></th><td><input type="number" name="newControl[MinIrisRange]" value="<?php echo validHtmlStr($newControl['MinIrisRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxIrisRange') ?></th><td><input type="number" name="newControl[MaxIrisRange]" value="<?php echo validHtmlStr($newControl['MaxIrisRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinIrisStep') ?></th><td><input type="number" name="newControl[MinIrisStep]" value="<?php echo validHtmlStr($newControl['MinIrisStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxIrisStep') ?></th><td><input type="number" name="newControl[MaxIrisStep]" value="<?php echo validHtmlStr($newControl['MaxIrisStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasIrisSpeed') ?></th><td><input type="checkbox" name="newControl[HasIrisSpeed]" value="1"<?php if ( !empty($newControl['HasIrisSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinIrisSpeed') ?></th><td><input type="number" name="newControl[MinIrisSpeed]" value="<?php echo validHtmlStr($newControl['MinIrisSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxIrisSpeed') ?></th><td><input type="number" name="newControl[MaxIrisSpeed]" value="<?php echo validHtmlStr($newControl['MaxIrisSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanIris') ?></th><td><input type="checkbox" name="newControl[CanIris]" value="1"<?php if ( !empty($newControl['CanIris']) ) { ?> checked="checked"<?php } ?>></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanAutoIris') ?></th><td><input type="checkbox" name="newControl[CanAutoIris]" value="1"<?php if ( !empty($newControl['CanAutoIris']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanIrisAbs') ?></th><td><input type="checkbox" name="newControl[CanIrisAbs]" value="1"<?php if ( !empty($newControl['CanIrisAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanIrisRel') ?></th><td><input type="checkbox" name="newControl[CanIrisRel]" value="1"<?php if ( !empty($newControl['CanIrisRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanIrisCon') ?></th><td><input type="checkbox" name="newControl[CanIrisCon]" value="1"<?php if ( !empty($newControl['CanIrisCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinIrisRange') ?></th><td><input type="number" name="newControl[MinIrisRange]" value="<?php echo validHtmlStr($newControl['MinIrisRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxIrisRange') ?></th><td><input type="number" name="newControl[MaxIrisRange]" value="<?php echo validHtmlStr($newControl['MaxIrisRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinIrisStep') ?></th><td><input type="number" name="newControl[MinIrisStep]" value="<?php echo validHtmlStr($newControl['MinIrisStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxIrisStep') ?></th><td><input type="number" name="newControl[MaxIrisStep]" value="<?php echo validHtmlStr($newControl['MaxIrisStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasIrisSpeed') ?></th><td><input type="checkbox" name="newControl[HasIrisSpeed]" value="1"<?php if ( !empty($newControl['HasIrisSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinIrisSpeed') ?></th><td><input type="number" name="newControl[MinIrisSpeed]" value="<?php echo validHtmlStr($newControl['MinIrisSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxIrisSpeed') ?></th><td><input type="number" name="newControl[MaxIrisSpeed]" value="<?php echo validHtmlStr($newControl['MaxIrisSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'gain' :
{
?>
<tr><th scope="row"><?php echo translate('CanGain') ?></th><td><input type="checkbox" name="newControl[CanGain]" value="1"<?php if ( !empty($newControl['CanGain']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanAutoGain') ?></th><td><input type="checkbox" name="newControl[CanAutoGain]" value="1"<?php if ( !empty($newControl['CanAutoGain']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanGainAbs') ?></th><td><input type="checkbox" name="newControl[CanGainAbs]" value="1"<?php if ( !empty($newControl['CanGainAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanGainRel') ?></th><td><input type="checkbox" name="newControl[CanGainRel]" value="1"<?php if ( !empty($newControl['CanGainRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanGainCon') ?></th><td><input type="checkbox" name="newControl[CanGainCon]" value="1"<?php if ( !empty($newControl['CanGainCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinGainRange') ?></th><td><input type="number" name="newControl[MinGainRange]" value="<?php echo validHtmlStr($newControl['MinGainRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxGainRange') ?></th><td><input type="number" name="newControl[MaxGainRange]" value="<?php echo validHtmlStr($newControl['MaxGainRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinGainStep') ?></th><td><input type="number" name="newControl[MinGainStep]" value="<?php echo validHtmlStr($newControl['MinGainStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxGainStep') ?></th><td><input type="number" name="newControl[MaxGainStep]" value="<?php echo validHtmlStr($newControl['MaxGainStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasGainSpeed') ?></th><td><input type="checkbox" name="newControl[HasGainSpeed]" value="1"<?php if ( !empty($newControl['HasGainSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinGainSpeed') ?></th><td><input type="number" name="newControl[MinGainSpeed]" value="<?php echo validHtmlStr($newControl['MinGainSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxGainSpeed') ?></th><td><input type="number" name="newControl[MaxGainSpeed]" value="<?php echo validHtmlStr($newControl['MaxGainSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanGain') ?></th><td><input type="checkbox" name="newControl[CanGain]" value="1"<?php if ( !empty($newControl['CanGain']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanAutoGain') ?></th><td><input type="checkbox" name="newControl[CanAutoGain]" value="1"<?php if ( !empty($newControl['CanAutoGain']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanGainAbs') ?></th><td><input type="checkbox" name="newControl[CanGainAbs]" value="1"<?php if ( !empty($newControl['CanGainAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanGainRel') ?></th><td><input type="checkbox" name="newControl[CanGainRel]" value="1"<?php if ( !empty($newControl['CanGainRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanGainCon') ?></th><td><input type="checkbox" name="newControl[CanGainCon]" value="1"<?php if ( !empty($newControl['CanGainCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinGainRange') ?></th><td><input type="number" name="newControl[MinGainRange]" value="<?php echo validHtmlStr($newControl['MinGainRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxGainRange') ?></th><td><input type="number" name="newControl[MaxGainRange]" value="<?php echo validHtmlStr($newControl['MaxGainRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinGainStep') ?></th><td><input type="number" name="newControl[MinGainStep]" value="<?php echo validHtmlStr($newControl['MinGainStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxGainStep') ?></th><td><input type="number" name="newControl[MaxGainStep]" value="<?php echo validHtmlStr($newControl['MaxGainStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasGainSpeed') ?></th><td><input type="checkbox" name="newControl[HasGainSpeed]" value="1"<?php if ( !empty($newControl['HasGainSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinGainSpeed') ?></th><td><input type="number" name="newControl[MinGainSpeed]" value="<?php echo validHtmlStr($newControl['MinGainSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxGainSpeed') ?></th><td><input type="number" name="newControl[MaxGainSpeed]" value="<?php echo validHtmlStr($newControl['MaxGainSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'white' :
{
?>
<tr><th scope="row"><?php echo translate('CanWhite') ?></th><td><input type="checkbox" name="newControl[CanWhite]" value="1"<?php if ( !empty($newControl['CanWhite']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanAutoWhite') ?></th><td><input type="checkbox" name="newControl[CanAutoWhite]" value="1"<?php if ( !empty($newControl['CanAutoWhite']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanWhiteAbs') ?></th><td><input type="checkbox" name="newControl[CanWhiteAbs]" value="1"<?php if ( !empty($newControl['CanWhiteAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanWhiteRel') ?></th><td><input type="checkbox" name="newControl[CanWhiteRel]" value="1"<?php if ( !empty($newControl['CanWhiteRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanWhiteCon') ?></th><td><input type="checkbox" name="newControl[CanWhiteCon]" value="1"<?php if ( !empty($newControl['CanWhiteCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinWhiteRange') ?></th><td><input type="number" name="newControl[MinWhiteRange]" value="<?php echo validHtmlStr($newControl['MinWhiteRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxWhiteRange') ?></th><td><input type="number" name="newControl[MaxWhiteRange]" value="<?php echo validHtmlStr($newControl['MaxWhiteRange']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MinWhiteStep') ?></th><td><input type="number" name="newControl[MinWhiteStep]" value="<?php echo validHtmlStr($newControl['MinWhiteStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxWhiteStep') ?></th><td><input type="number" name="newControl[MaxWhiteStep]" value="<?php echo validHtmlStr($newControl['MaxWhiteStep']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasWhiteSpeed') ?></th><td><input type="checkbox" name="newControl[HasWhiteSpeed]" value="1"<?php if ( !empty($newControl['HasWhiteSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('MinWhiteSpeed') ?></th><td><input type="number" name="newControl[MinWhiteSpeed]" value="<?php echo validHtmlStr($newControl['MinWhiteSpeed']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('MaxWhiteSpeed') ?></th><td><input type="number" name="newControl[MaxWhiteSpeed]" value="<?php echo validHtmlStr($newControl['MaxWhiteSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanWhite') ?></th><td><input type="checkbox" name="newControl[CanWhite]" value="1"<?php if ( !empty($newControl['CanWhite']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanAutoWhite') ?></th><td><input type="checkbox" name="newControl[CanAutoWhite]" value="1"<?php if ( !empty($newControl['CanAutoWhite']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanWhiteAbs') ?></th><td><input type="checkbox" name="newControl[CanWhiteAbs]" value="1"<?php if ( !empty($newControl['CanWhiteAbs']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanWhiteRel') ?></th><td><input type="checkbox" name="newControl[CanWhiteRel]" value="1"<?php if ( !empty($newControl['CanWhiteRel']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanWhiteCon') ?></th><td><input type="checkbox" name="newControl[CanWhiteCon]" value="1"<?php if ( !empty($newControl['CanWhiteCon']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinWhiteRange') ?></th><td><input type="number" name="newControl[MinWhiteRange]" value="<?php echo validHtmlStr($newControl['MinWhiteRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxWhiteRange') ?></th><td><input type="number" name="newControl[MaxWhiteRange]" value="<?php echo validHtmlStr($newControl['MaxWhiteRange']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinWhiteStep') ?></th><td><input type="number" name="newControl[MinWhiteStep]" value="<?php echo validHtmlStr($newControl['MinWhiteStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxWhiteStep') ?></th><td><input type="number" name="newControl[MaxWhiteStep]" value="<?php echo validHtmlStr($newControl['MaxWhiteStep']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasWhiteSpeed') ?></th><td><input type="checkbox" name="newControl[HasWhiteSpeed]" value="1"<?php if ( !empty($newControl['HasWhiteSpeed']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MinWhiteSpeed') ?></th><td><input type="number" name="newControl[MinWhiteSpeed]" value="<?php echo validHtmlStr($newControl['MinWhiteSpeed']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('MaxWhiteSpeed') ?></th><td><input type="number" name="newControl[MaxWhiteSpeed]" value="<?php echo validHtmlStr($newControl['MaxWhiteSpeed']) ?>"/></td></tr>
<?php
break;
}
case 'presets' :
{
?>
<tr><th scope="row"><?php echo translate('HasPresets') ?></th><td><input type="checkbox" name="newControl[HasPresets]" value="1"<?php if ( !empty($newControl['HasPresets']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('NumPresets') ?></th><td><input type="number" name="newControl[NumPresets]" value="<?php echo validHtmlStr($newControl['NumPresets']) ?>"/></td></tr>
<tr><th scope="row"><?php echo translate('HasHomePreset') ?></th><td><input type="checkbox" name="newControl[HasHomePreset]" value="1"<?php if ( !empty($newControl['HasHomePreset']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th scope="row"><?php echo translate('CanSetPresets') ?></th><td><input type="checkbox" name="newControl[CanSetPresets]" value="1"<?php if ( !empty($newControl['CanSetPresets']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasPresets') ?></th><td><input type="checkbox" name="newControl[HasPresets]" value="1"<?php if ( !empty($newControl['HasPresets']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('NumPresets') ?></th><td><input type="number" name="newControl[NumPresets]" value="<?php echo validHtmlStr($newControl['NumPresets']) ?>"/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('HasHomePreset') ?></th><td><input type="checkbox" name="newControl[HasHomePreset]" value="1"<?php if ( !empty($newControl['HasHomePreset']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><th class="text-right pr-3" scope="row"><?php echo translate('CanSetPresets') ?></th><td><input type="checkbox" name="newControl[CanSetPresets]" value="1"<?php if ( !empty($newControl['CanSetPresets']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php
break;
}
@ -481,9 +488,11 @@ switch ( $tab ) {
</table>
<div id="contentButtons">
<button type="submit" value="Save"<?php if ( !canEdit( 'Control' ) ) { ?> disabled="disabled"<?php } ?>><?php echo translate('Save') ?></button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
<button type="button" id="cancelBtn"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
</div>
</div>
<?php xhtmlFooter() ?>

View File

@ -30,30 +30,47 @@ $focusWindow = true;
xhtmlHeaders(__FILE__, translate('ControlCaps'));
?>
<body>
<?php echo getNavBarHTML() ?>
<div id="page">
<div id="header">
<div id="headerButtons">
<a href="#" data-on-click="closeWindow"><?php echo translate('Close') ?></a>
</div>
<h2><?php echo translate('ControlCaps') ?></h2>
<!-- Toolbar button placement and styling handled by bootstrap-tables -->
<div id="toolbar">
<button id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
<button id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
<button id="addNewBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('AddNewControl') ?>" data-on-click-this="addNewControl" data-url="?view=controlcap"><i class="fa fa-plus"></i></button>
<button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('EditControl') ?>" data-on-click-this="editControl" data-url="?view=controlcap&cid=" disabled><i class="fa fa-pencil"></i></button>
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>" disabled><i class="fa fa-trash"></i></button>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="get" action="?" onsubmit="return( confirmDelete( 'Warning, deleting a control will reset all monitors that use it to be uncontrollable.\nAre you sure you wish to delete?' ) );">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="action" value="delete"/>
<table id="contentTable" class="major">
<table
id="controlTable"
class="table-sm table-borderless"
data-search="true"
data-cookie="true"
data-cookie-id-table="zmControlTable"
data-cookie-expire="2y"
data-remember-order="true"
data-click-to-select="true"
data-maintain-meta-data="true"
data-mobile-responsive="true"
data-buttons-class="btn btn-normal"
data-toolbar="#toolbar"
data-show-columns="true"
>
<thead>
<tr>
<th class="colName"><?php echo translate('Name') ?></th>
<th class="colType"><?php echo translate('Type') ?></th>
<th class="colProtocol"><?php echo translate('Protocol') ?></th>
<th class="colCanMove"><?php echo translate('CanMove') ?></th>
<th class="colCanZoom"><?php echo translate('CanZoom') ?></th>
<th class="colCanFocus"><?php echo translate('CanFocus') ?></th>
<th class="colCanIris"><?php echo translate('CanIris') ?></th>
<th class="colCanWhiteBal"><?php echo translate('CanWhiteBal') ?></th>
<th class="colHasPresets"><?php echo translate('HasPresets') ?></th>
<th class="colMark"><?php echo translate('Mark') ?></th>
<th data-sortable="false" data-field="toggleCheck" data-checkbox="true"></th>
<th class="colId" data-sortable="true" data-field="Id"><?php echo translate('Id') ?></th>
<th class="colName" data-sortable="true" data-field="Name"><?php echo translate('Name') ?></th>
<th class="colType" data-sortable="true" data-field="Type"><?php echo translate('Type') ?></th>
<th class="colProtocol" data-sortable="true" data-field="Protocol"><?php echo translate('Protocol') ?></th>
<th class="colCanMove" data-sortable="true" data-field="CanMove"><?php echo translate('CanMove') ?></th>
<th class="colCanZoom" data-sortable="true" data-field="CanZoom"><?php echo translate('CanZoom') ?></th>
<th class="colCanFocus" data-sortable="true" data-field="CanFocus"><?php echo translate('CanFocus') ?></th>
<th class="colCanIris" data-sortable="true" data-field="CanIris"><?php echo translate('CanIris') ?></th>
<th class="colCanWhiteBal" data-sortable="true" data-field="CanWhiteBal"><?php echo translate('CanWhiteBal') ?></th>
<th class="colHasPresets" data-sortable="true" data-field="HasPresets"><?php echo translate('HasPresets') ?></th>
</tr>
</thead>
<tbody>
@ -61,7 +78,9 @@ xhtmlHeaders(__FILE__, translate('ControlCaps'));
foreach( $controls as $control ) {
?>
<tr>
<td class="colName"><?php echo makePopupLink( '?view=controlcap&cid='.$control['Id'], 'zmControlCap', 'controlcap', validHtmlStr($control['Name']), canView( 'Control' ) ) ?></td>
<td class="colMark" data-checkbox="true"></td>
<td class="colId"><?php echo $control['Id'] ?></td>
<td class="colName"><?php echo $control['Name'] ?></td>
<td class="colType"><?php echo $control['Type'] ?></td>
<td class="colProtocol"><?php echo validHtmlStr($control['Protocol']) ?></td>
<td class="colCanMove"><?php echo $control['CanMove']?translate('Yes'):translate('No') ?></td>
@ -70,18 +89,12 @@ foreach( $controls as $control ) {
<td class="colCanIris"><?php echo $control['CanIris']?translate('Yes'):translate('No') ?></td>
<td class="colCanWhiteBal"><?php echo $control['CanWhite']?translate('Yes'):translate('No') ?></td>
<td class="colHasPresets"><?php echo $control['HasHomePreset']?'H':'' ?><?php echo $control['HasPresets']?$control['NumPresets']:'0' ?></td>
<td class="colMark"><input type="checkbox" name="markCids[]" value="<?php echo $control['Id'] ?>" data-on-click-this="configureDeleteButton"<?php if ( !canEdit( 'Control' ) ) {?> disabled="disabled"<?php } ?>/></td>
</tr>
<?php
}
?>
</tbody>
</table>
<div id="contentButtons">
<?php echo makePopupButton('?view=controlcap', 'zmControlCap', 'controlcap', translate('AddNewControl'), canEdit( 'Control' )); ?>
<input type="submit" name="deleteBtn" value="<?php echo translate('Delete') ?>" disabled="disabled"/>
</div>
</form>
</div>
</div>
<?php xhtmlFooter() ?>

View File

@ -147,15 +147,15 @@ xhtmlHeaders(__FILE__, translate('CycleWatch'));
<div id="sizeControl">
<span id="widthControl">
<label><?php echo translate('Width') ?>:</label>
<?php echo htmlSelect('width', $widths, $options['width'], array('data-on-change-this'=>'changeSize') ); ?>
<?php echo htmlSelect('width', $widths, $options['width'], array('id'=>'width', 'data-on-change-this'=>'changeSize') ); ?>
</span>
<span id="heightControl">
<label><?php echo translate('Height') ?>:</label>
<?php echo htmlSelect('height', $heights, $options['height'], array('data-on-change-this'=>'changeSize') ); ?>
<?php echo htmlSelect('height', $heights, $options['height'], array('id'=>'height', 'data-on-change-this'=>'changeSize') ); ?>
</span>
<span id="scaleControl">
<label><?php echo translate('Scale') ?>:</label>
<?php echo htmlSelect('scale', $scales, $options['scale'], array('data-on-change-this'=>'changeScale') ); ?>
<?php echo htmlSelect('scale', $scales, $options['scale'], array('id'=>'scale', 'data-on-change-this'=>'changeScale') ); ?>
</span>
</div>
</div>

View File

@ -54,15 +54,8 @@ if ( isset($_REQUEST['exportFormat']) ) {
}
}
if ( !empty($_REQUEST['eid']) ) {
$Event = new ZM\Event($_REQUEST['eid']);
if ( !$Event->Id ) {
Error('Invalid event id');
}
}
$focusWindow = true;
$connkey = isset($_REQUEST['connkey']) ? $_REQUEST['connkey'] : generateConnKey();
$connkey = isset($_REQUEST['connkey']) ? validInt($_REQUEST['connkey']) : generateConnKey();
xhtmlHeaders(__FILE__, translate('Download'));
?>
@ -75,7 +68,7 @@ xhtmlHeaders(__FILE__, translate('Download'));
<h2><?php echo translate('Download') ?></h2>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<form name="contentForm" id="contentForm" method="post" action="?">
<input type="hidden" name="connkey" value="<?php echo $connkey; ?>"/>
<?php
if ( !empty($_REQUEST['eid']) ) {
@ -83,7 +76,12 @@ if ( !empty($_REQUEST['eid']) ) {
<input type="hidden" name="id" value="<?php echo validInt($_REQUEST['eid']) ?>"/>
<?php
$Event = new ZM\Event($_REQUEST['eid']);
echo 'Downloading event ' . $Event->Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() );
if ( !$Event->Id() ) {
ZM\Error('Invalid event id');
echo '<div class="error">Invalid event id</div>';
} else {
echo 'Downloading event ' . $Event->Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() );
}
} else if ( !empty($_REQUEST['eids']) ) {
$total_size = 0;
foreach ( $_REQUEST['eids'] as $eid ) {

View File

@ -23,6 +23,7 @@ $focusWindow = true;
xhtmlHeaders(__FILE__, translate('Error') );
?>
<body>
<?php echo getNavBarHTML() ?>
<div id="page">
<div id="header">
<h1>ZoneMinder <?php echo translate('Error') ?></h1>
@ -34,9 +35,6 @@ xhtmlHeaders(__FILE__, translate('Error') );
<p>
<?php echo translate('ContactAdmin') ?>
</p>
<p>
<button type="button" data-on-click="closeWindow"><?php echo translate('Close') ?></button>
</p>
</div>
</div>
</body>

View File

@ -1,116 +0,0 @@
<?php
//
// ZoneMinder web event detail view file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit('Events') ) {
$view = 'error';
return;
}
if ( isset($_REQUEST['eid']) ) {
$mode = 'single';
$eid = validInt($_REQUEST['eid']);
$newEvent = dbFetchOne('SELECT E.* FROM Events AS E WHERE E.Id = ?', NULL, array($eid));
} elseif ( isset($_REQUEST['eids']) ) {
$mode = 'multi';
$sql = 'SELECT E.* FROM Events AS E WHERE ';
$sqlWhere = array();
$sqlValues = array();
foreach ( $_REQUEST['eids'] as $eid ) {
$sqlWhere[] = 'E.Id = ?';
$sqlValues[] = validInt($eid);
}
unset($eid);
$sql .= join(' OR ', $sqlWhere);
foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row ) {
if ( !isset($newEvent) ) {
$newEvent = $row;
} else {
if ( $newEvent['Cause'] && $newEvent['Cause'] != $row['Cause'] )
$newEvent['Cause'] = '';
if ( $newEvent['Notes'] && $newEvent['Notes'] != $row['Notes'] )
$newEvent['Notes'] = '';
}
}
} else {
$mode = '';
}
$focusWindow = true;
if ( $mode == 'single' )
xhtmlHeaders(__FILE__, translate('Event').' - '.$eid );
else
xhtmlHeaders(__FILE__, translate('Events') );
?>
<body>
<div id="page">
<div id="header">
<?php
if ( $mode == 'single' ) {
?>
<h2><?php echo translate('Event') ?> <?php echo $eid ?></h2>
<?php
} else {
?>
<h2><?php echo translate('Events') ?></h2>
<?php
}
?>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="?">
<input type="hidden" name="action" value="eventdetail"/>
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<?php
if ( $mode == 'single' ) {
?>
<input type="hidden" name="markEids[]" value="<?php echo validInt($eid) ?>"/>
<?php
} else if ( $mode = 'multi' ) {
?>
<?php
foreach ( $_REQUEST['eids'] as $eid ) {
?>
<input type="hidden" name="markEids[]" value="<?php echo validInt($eid) ?>"/>
<?php
}
}
?>
<table id="contentTable" class="major">
<tbody>
<tr>
<th scope="row"><?php echo translate('Cause') ?></th>
<td><input type="text" name="newEvent[Cause]" value="<?php echo validHtmlStr($newEvent['Cause']) ?>" size="32"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Notes') ?></th>
<td><textarea name="newEvent[Notes]" rows="6" cols="50"><?php echo validHtmlStr($newEvent['Notes']) ?></textarea></td>
</tr>
</tbody>
</table>
<div id="contentButtons">
<button type="submit" value="Save" <?php echo !canEdit('Events') ? ' disabled="disabled"' : '' ?>>
<?php echo translate('Save') ?>
</button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
<?php xhtmlFooter() ?>

View File

@ -34,16 +34,23 @@ if ( $user['MonitorIds'] ) {
$eventsSql .= ' 1';
}
$filter = isset($_REQUEST['filter_id']) ? new ZM\Filter($_REQUEST['filter_id']) : new ZM\Filter();
if ( isset($_REQUEST['filter'])) {
$filter->set($_REQUEST['filter']);
}
parseSort();
$filter = ZM\Filter::parse($_REQUEST['filter']);
$filterQuery = $filter->querystring();
ZM\Logger::Debug("Filter ".print_r($filter, true));
ZM\Logger::Debug('Filter '.print_r($filter, true));
if ( $filter->sql() ) {
$eventsSql .= ' AND ('.$filter->sql().')';
} else {
ZM\Warning('No filters');
exit;
}
$eventsSql .= " ORDER BY $sortColumn $sortOrder";
$eventsSql .= ' ORDER BY '.$sortColumn.' '.$sortOrder;
if ( $sortColumn != 'E.Id' ) $eventsSql .= ',E.Id '.$sortOrder;
$page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 0;
@ -64,6 +71,10 @@ if ( $failed ) {
$results = $failed ? null : dbQuery($eventsSql);
$nEvents = $results ? $results->rowCount() : 0;
if ( ! $results ) {
global $error_message;
$error_message = dbError($eventsSql);
}
ZM\Logger::Debug("Pre conditions succeeded sql return $nEvents events");
if ( !empty($limit) && ($nEvents > $limit) ) {
@ -84,13 +95,12 @@ if ( !empty($page) ) {
$limitLeft = $limit - $limitStart;
$limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft;
}
$eventsSql .= " LIMIT $limitStart, $limitAmount";
$eventsSql .= ' LIMIT '.$limitStart.', '.$limitAmount;
} else if ( !empty($limit) ) {
$eventsSql .= ' LIMIT 0, '.$limit;
}
$maxShortcuts = 5;
$pagination = getPagination($pages, $page, $maxShortcuts, $filterQuery.$sortQuery.$limitQuery);
$focusWindow = true;
@ -101,9 +111,9 @@ foreach ( $storage_areas as $S ) {
}
xhtmlHeaders(__FILE__, translate('Events'));
getBodyTopHTML();
?>
<body>
<?php echo getNavBarHTML() ?>
<div id="page" class="container-fluid p-3">
<!-- Toolbar button placement and styling handled by bootstrap-tables -->
@ -124,7 +134,6 @@ xhtmlHeaders(__FILE__, translate('Events'));
<div class="row justify-content-center">
<table
id="eventTable"
data-toggle="table"
data-pagination="true"
data-show-pagination-switch="true"
data-page-list="[10, 25, 50, 100, 200, All]"
@ -222,17 +231,15 @@ if ( $results ) {
<td class="text-center"><?php echo ( $event->Archived() ) ? 'Yes' : 'No' ?></td>
<td class="text-center"><?php echo ( $event->Emailed() ) ? 'Yes' : 'No' ?></td>
<td><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?>
<td><?php echo makeLink( '?view=monitor&amp;mid='.$event->MonitorId(), $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td><?php echo makeLink( '#', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="' .htmlspecialchars($event->Notes()). '" class="eDetailLink" data-eid=' .$event->Id(). '"') ?>
<?php
# display notes as small text
if ( $event->Notes() ) {
# if notes include detection objects, then link it to objdetect.jpg
if ( strpos($event->Notes(), 'detected:') !== false ) {
# make a link
echo makePopupLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', 'zmImage',
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)),
'<div class="small text-nowrap text-muted"><u>'.$event->Notes().'</u></div>');
echo makeLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', '<div class="small text-nowrap text-muted"><u>'.$event->Notes().'</u></div>');
} else if ( $event->Notes() != 'Forced Web: ' ) {
echo '<br/><div class="small text-nowrap text-muted">'.$event->Notes().'</div>';
}
@ -247,10 +254,7 @@ if ( $results ) {
<td><a href="?view=frames&amp;eid=<?php echo $event->Id() ?>"><?php echo $event->AlarmFrames() ?></a></td>
<td><?php echo $event->TotScore() ?></td>
<td><?php echo $event->AvgScore() ?></td>
<td><?php echo makePopupLink(
'?view=frame&amp;eid='.$event->Id().'&amp;fid=0', 'zmImage',
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)), $event->MaxScore()
); ?></td>
<td><?php echo makeLink('?view=frame&amp;eid='.$event->Id().'&amp;fid=0', $event->MaxScore()); ?></td>
<?php
if ( count($storage_areas) > 1 ) {
?>
@ -322,25 +326,4 @@ if ( $results ) {
</table>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div id="deleteConfirm" class="modal fade" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p><?php echo translate('ConfirmDeleteEvents') ?></p>
</div>
<div class="modal-footer">
<button id="delCancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
<button id ="delConfirmBtn" type="button" class="btn btn-danger"><?php echo translate('Delete') ?></button>
</div>
</div>
</div>
</div>
<?php xhtmlFooter() ?>

View File

@ -17,6 +17,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
global $sortQuery;
if ( !canView('Events') ) {
$view = 'error';
@ -55,17 +56,22 @@ if (isset($_REQUEST['exportFormat'])) {
}
$focusWindow = true;
$connkey = isset($_REQUEST['connkey']) ? $_REQUEST['connkey'] : generateConnKey();
$connkey = isset($_REQUEST['connkey']) ? validInt($_REQUEST['connkey']) : generateConnKey();
xhtmlHeaders(__FILE__, translate('Export'));
?>
<body>
<div id="page">
<?php echo getNavBarHTML() ?>
<div id="header">
<h2><?php echo translate('ExportOptions') ?></h2>
</div>
<div id="content">
<div class="w-100 py-1">
<div class="float-left pl-3">
<button type="button" id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
<button type="button" id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
</div>
<div class="w-100 pt-2">
<h2><?php echo translate('ExportOptions') ?></h2>
</div>
</div> <div id="content">
<form name="contentForm" id="contentForm" method="post" action="?view=export">
<input type="hidden" name="connkey" value="<?php echo $connkey; ?>"/>
<?php
@ -144,19 +150,17 @@ while ( $event_row = dbFetchNext($results) ) {
<a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery ?>&amp;page=1"><?php echo $event->Id().($event->Archived()?'*':'') ?></a>
</td>
<td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery ?>&amp;page=1"><?php echo validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td>
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?></td>
<td class="colMonitorName"><?php echo makeLink( '?view=monitor&amp;mid='.$event->MonitorId(), $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colCause"><?php echo makeLink( '#', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="' .htmlspecialchars($event->Notes()). '" class="eDetailLink" data-eid=' .$event->Id(). '"') ?></td>
<td class="colTime"><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime())) .
( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?>
</td>
<td class="colDuration"><?php echo gmdate("H:i:s", $event->Length() ) ?></td>
<td class="colFrames"><?php echo makePopupLink( '?view=frames&amp;eid='.$event->Id(), 'zmFrames', 'frames', $event->Frames() ) ?></td>
<td class="colAlarmFrames"><?php echo makePopupLink( '?view=frames&amp;eid='.$event->Id(), 'zmFrames', 'frames', $event->AlarmFrames() ) ?></td>
<td class="colFrames"><?php echo makeLink( '?view=frames&amp;eid='.$event->Id(), $event->Frames() ) ?></td>
<td class="colAlarmFrames"><?php echo makeLink( '?view=frames&amp;eid='.$event->Id(), $event->AlarmFrames() ) ?></td>
<td class="colTotScore"><?php echo $event->TotScore() ?></td>
<td class="colAvgScore"><?php echo $event->AvgScore() ?></td>
<td class="colMaxScore"><?php echo
$event->MaxScore();
#makePopupLink('?view=frame&amp;eid='.$event->Id().'&amp;fid=0', 'zmImage', array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)), $event->MaxScore()) ?></td>
<td class="colMaxScore"><?php echo $event->MaxScore() ?></td>
<?php
if ( ZM_WEB_EVENT_DISK_SPACE ) {
$disk_space_total += $event->DiskSpace();

View File

@ -47,11 +47,11 @@ foreach ( ZM\Filter::find(null,array('order'=>'lower(Name)')) as $Filter ) {
}
if ( !$filter ) {
$filter = new ZM\Filter();
}
if ( isset($_REQUEST['filter']) ) {
# Update our filter object with whatever changes we have made before saving
#$filter->set($_REQUEST['filter']);
if ( isset($_REQUEST['filter']) ) {
# Update our filter object with whatever changes we have made before saving
$filter->set($_REQUEST['filter']);
}
}
$conjunctionTypes = ZM\getFilterQueryConjunctionTypes();
@ -80,6 +80,7 @@ $attrTypes = array(
'DiskBlocks' => translate('AttrDiskBlocks'),
'DiskPercent' => translate('AttrDiskPercent'),
'DiskSpace' => translate('AttrDiskSpace'),
'EventDiskSpace' => translate('AttrEventDiskSpace'),
'EndDateTime' => translate('AttrEndDateTime'),
'EndDate' => translate('AttrEndDate'),
'EndTime' => translate('AttrEndTime'),
@ -489,6 +490,7 @@ if ( canEdit('Events') ) {
}
}
?>
<button type="button" value="Debug" data-on-click-this="debugFilter"><?php echo translate('Debug') ?></button>
<button type="button" value="Reset" data-on-click-this="resetFilter"><?php echo translate('Reset') ?></button>
</div>
</form>

View File

@ -125,7 +125,6 @@ xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id());
<div class="row justify-content-center">
<table
id="framesTable"
data-toggle="table"
data-pagination="true"
data-show-pagination-switch="true"
data-page-list="[10, 25, 50, 100, 200, All]"
@ -207,15 +206,4 @@ if ( count($frames) ) {
</table>
</div>
</div>
<!-- Load the statistics for each frame -->
<!-- This content gets hidden on init and only revailed on detail view -->
<?php
$row = 0;
if ( count($frames) ) foreach ( $frames as $frame ) {
$eid = $frame['EventId'];
$fid = $frame['FrameId'];
include('_stats_table.php');
$row++;
}
?>
<?php xhtmlFooter() ?>

View File

@ -1,130 +0,0 @@
<?php
//
// ZoneMinder web group detail view file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit('Groups') ) {
$view = 'error';
return;
}
if ( !empty($_REQUEST['gid']) ) {
$newGroup = new ZM\Group($_REQUEST['gid']);
} else {
$newGroup = new ZM\Group();
}
xhtmlHeaders(__FILE__, translate('Group').' - '.$newGroup->Name());
?>
<body>
<div id="page">
<div id="header">
<h2><?php echo translate('Group') ?> - <?php echo validHtmlStr($newGroup->Name()); ?></h2>
</div>
<div id="content">
<form id="groupForm" name="groupForm" method="post" action="?">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="gid" value="<?php echo $newGroup->Id() ?>"/>
<table id="contentTable" class="major">
<tbody>
<tr>
<th scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newGroup[Name]" value="<?php echo validHtmlStr($newGroup->Name()) ?>" data-on-input="configureButtons"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ParentGroup') ?></th>
<td>
<?php
$Groups = array();
foreach ( ZM\Group::find() as $Group ) {
$Groups[$Group->Id()] = $Group;
}
# This array is indexed by parent_id
$children = array();
foreach ( $Groups as $id=>$Group ) {
if ( $Group->ParentId() != null ) {
if ( ! isset( $children[$Group->ParentId()] ) )
$children[$Group->ParentId()] = array();
$children[$Group->ParentId()][] = $Group;
}
}
function get_Id( $G ) {
return $G->Id();
}
function get_children($Group) {
global $children;
$kids = array();
if ( isset( $children[$Group->Id()] ) ) {
$kids += array_map('get_Id', $children[$Group->Id()]);
foreach ( $children[$Group->Id()] as $G ) {
foreach ( get_children($G) as $id ) {
$kids[] = $id;
}
}
}
return $kids;
}
$kids = get_children($newGroup);
if ( $newGroup->Id() )
$kids[] = $newGroup->Id();
$sql = 'SELECT Id,Name FROM `Groups`'.(count($kids)?' WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids)).')' : '').' ORDER BY Name';
$options = array(''=>'None');
foreach ( dbFetchAll($sql, null, $kids) as $option ) {
$options[$option['Id']] = str_repeat('&nbsp;&nbsp;', $Groups[$option['Id']]->depth()) . $option['Name'];
}
echo htmlSelect('newGroup[ParentId]', $options, $newGroup->ParentId(), array('data-on-change'=>'configureButtons'));
?>
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('Monitor') ?></th>
<td>
<select name="newGroup[MonitorIds][]" class="chosen" multiple="multiple" data-on-change="configureButtons">
<?php
$monitors = dbFetchAll('SELECT Id,Name FROM Monitors ORDER BY Sequence ASC');
$monitorIds = $newGroup->MonitorIds();
foreach ( $monitors as $monitor ) {
if ( visibleMonitor($monitor['Id']) ) {
?>
<option value="<?php echo $monitor['Id'] ?>"<?php if ( in_array( $monitor['Id'], $monitorIds ) ) { ?> selected="selected"<?php } ?>><?php echo validHtmlStr($monitor['Name']) ?></option>
<?php
}
}
?>
</select>
</td>
</tr>
</tbody>
</table>
<div id="contentButtons">
<button type="submit" name="action" value="Save"<?php $newGroup->Id() ? '' : ' disabled="disabled"'?>>
<?php echo translate('Save') ?>
</button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
<script nonce="<?php echo $cspNonce;?>">$j('.chosen').chosen();</script>
<?php xhtmlFooter() ?>

View File

@ -127,31 +127,12 @@ function reloadWindow() {
window.location.replace( thisUrl );
}
function initPage() {
reloadWindow.periodical(consoleRefreshTimeout);
if ( showVersionPopup ) {
window.location.assign('?view=version');
}
if ( showDonatePopup ) {
$j('#donate').modal('show');
}
// Makes table sortable
$j( function() {
$j( "#consoleTableBody" ).sortable({
handle: ".sort",
update: applySort,
axis: 'Y'} );
$j( "#consoleTableBody" ).disableSelection();
} );
// Setup the thumbnail video animation
initThumbAnimation();
// Manage the the Function modal and its buttons
function manageFunctionModal() {
$j('.functionLnk').click(function(evt) {
evt.preventDefault();
if ( !canEditEvents ) {
alert('You do not have permission to change monitor function.');
enoperm();
return;
}
var mid = evt.currentTarget.getAttribute('data-mid');
@ -167,12 +148,13 @@ function initPage() {
return;
}
function_form.elements['newFunction'].value = monitor.Function;
function_form.elements['newEnabled'].checked = monitor.Enabled;
function_form.elements['newEnabled'].checked = monitor.Enabled == '1';
function_form.elements['mid'].value = mid;
document.getElementById('function_monitor_name').innerHTML = monitor.Name;
$j('#modalFunction').modal('show');
});
// Manage the CANCEL modal buttons
$j('.funcCancelBtn').click(function(evt) {
evt.preventDefault();
@ -182,15 +164,59 @@ function initPage() {
// Manage the SAVE modal buttons
$j('.funcSaveBtn').click(function(evt) {
evt.preventDefault();
var form = evt.currentTarget.form;
var mid = form.elements['mid'].value;
var newFunc = $j('#newFunction').val();
var newEnabled = $j('#newEnabled').is(':checked') ? 1 : 0;
$j.getJSON(thisUrl + '?view=function&action=function&mid='+mid+'&newFunction='+newFunc+'&newEnabled='+newEnabled);
window.location.reload(true);
$j('#function_form').submit();
});
}
function initPage() {
reloadWindow.periodical(consoleRefreshTimeout);
if ( showVersionPopup ) {
window.location.assign('?view=version');
}
if ( showDonatePopup ) {
$j.getJSON(thisUrl + '?request=modal&modal=donate')
.done(function(data) {
if ( $j('#donate').length ) {
$j('#donate').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
$j('#donate').modal('show');
// Manage the Apply button
$j('#donateApplyBtn').click(function(evt) {
evt.preventDefault();
$j('#donateForm').submit();
});
})
.fail(logAjaxFail);
}
// Makes table sortable
$j( function() {
$j( "#consoleTableBody" ).sortable({
handle: ".sort",
update: applySort,
axis: 'Y'} );
$j( "#consoleTableBody" ).disableSelection();
} );
// Setup the thumbnail video animation
initThumbAnimation();
// Load the Function modal on page load
$j.getJSON(thisUrl + '?request=modal&modal=function')
.done(function(data) {
if ( $j('#modalFunction').length ) {
$j('#modalFunction').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
// Manage the Function modal
manageFunctionModal();
})
.fail(logAjaxFail);
}
function applySort(event, ui) {
var monitor_ids = $j(this).sortable('toArray');
var ajax = new Request.JSON( {

View File

@ -108,3 +108,29 @@ function validateForm( form ) {
return true;
}
function initPage() {
// Manage the BACK button
document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) {
evt.preventDefault();
window.history.back();
});
// Disable the back button if there is nothing to go back to
$j('#backBtn').prop('disabled', !document.referrer.length);
// Manage the REFRESH Button
document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) {
evt.preventDefault();
window.location.reload(true);
});
// Manage the CANCEL Button
document.getElementById("cancelBtn").addEventListener("click", function onCancelClick(evt) {
evt.preventDefault();
window.location.assign('?view=controlcaps');
});
}
$j(document).ready(function() {
initPage();
});

View File

@ -0,0 +1,119 @@
var table = $j('#controlTable');
var addNewBtn = $j('#addNewBtn');
var editBtn = $j('#editBtn');
var deleteBtn = $j('#deleteBtn');
// Manage the Add New Control button
function AddNewControl(el) {
url = el.getAttribute('data-url');
window.location.assign(url);
}
// Manage the Add New Control button
function addNewControl(el) {
url = el.getAttribute('data-url');
window.location.assign(url);
}
// Manage the Edit Control button
function editControl(el) {
var selection = getIdSelections();
url = el.getAttribute('data-url');
window.location.assign(url+selection);
}
// Returns the event id's of the selected rows
function getIdSelections() {
return $j.map(table.bootstrapTable('getSelections'), function(row) {
return row.Id.replace(/(<([^>]+)>)/gi, ''); // strip the html from the element before sending
});
}
// Load the Delete Confirmation Modal HTML via Ajax call
function getDelConfirmModal(key) {
$j.getJSON(thisUrl + '?request=modal&modal=delconfirm&key=' + key)
.done(function(data) {
if ( $j('#deleteConfirm').length ) {
$j('#deleteConfirm').replaceWith(data.html);
} else {
$j("body").append(data.html);
}
manageDelConfirmModalBtns();
})
.fail(logAjaxFail);
}
// Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() {
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEditControl ) {
enoperm();
return;
}
var selections = getIdSelections();
evt.preventDefault();
$j.getJSON(thisUrl + '?request=controlcaps&action=delete&cids[]='+selections.join('&cids[]='))
.done( function(data) {
$j('#eventTable').bootstrapTable('refresh');
window.location.reload(true);
})
.fail(logAjaxFail);
});
}
function initPage() {
// enable or disable buttons based on current selection and user rights
table.on('check.bs.table uncheck.bs.table ' +
'check-all.bs.table uncheck-all.bs.table',
function() {
selections = table.bootstrapTable('getSelections');
addNewBtn.prop('disabled', (selections.length || !canEditControl));
editBtn.prop('disabled', !((selections.length == 1) && canEditControl));
deleteBtn.prop('disabled', !(selections.length && canEditControl));
});
// Init the bootstrap-table
table.bootstrapTable({icons: icons});
// Manage the BACK button
document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) {
evt.preventDefault();
window.history.back();
});
// Disable the back button if there is nothing to go back to
$j('#backBtn').prop('disabled', !document.referrer.length);
// Manage the REFRESH Button
document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) {
evt.preventDefault();
window.location.reload(true);
});
// Manage the DELETE button
document.getElementById("deleteBtn").addEventListener("click", function onDeleteClick(evt) {
if ( ! canEditControl ) {
enoperm();
return;
}
evt.preventDefault();
$j('#deleteConfirm').modal('show');
});
// Load the delete confirmation modal into the DOM
getDelConfirmModal('ConfirmDeleteControl');
// Hide these columns on first run when no cookie is saved
if ( !getCookie("zmControlTable.bs.table.columns") ) {
table.bootstrapTable('hideColumn', 'Id');
}
}
$j(document).ready(function() {
initPage();
});

View File

@ -0,0 +1 @@
var canEditControl = <?php echo canEdit('Control')?'true':'false' ?>;

Some files were not shown because too many files have changed in this diff Show More