Merge branch 'storageareas' into zma_to_thread

This commit is contained in:
Isaac Connor 2017-12-04 17:07:16 -05:00
commit 588f63b053
67 changed files with 1379 additions and 907 deletions

View File

@ -233,6 +233,8 @@ CREATE TABLE `Filters` (
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
`AutoExecuteCmd` tinytext,
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
`AutoMove` tinyint(3) unsigned NOT NULL default '0',
`AutoMoveTo` smallint(5) unsigned NOT NULL default 0,
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
`Background` tinyint(1) unsigned NOT NULL default '0',
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
@ -268,10 +270,24 @@ CREATE TABLE `Groups` (
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(64) NOT NULL default '',
`ParentId` int(10) unsigned,
`MonitorIds` text NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
--
--Table structure for table `Groups_Monitors`
--
DROP TABLE IF EXISTS `Groups_Monitors`
CREATE TABLE `Groups_Monitors` (
`Id` INT(10) unsigned NOT NULL auto_increment,
`GroupId` int(10) unsigned NOT NULL,
`MonitorId` int(10) unsigned NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
CREATE INDEX `Groups_Monitors_GroupId_idx` ON `Groups` (`GroupId`);
CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups` (`MonitorId`);
--
-- Table structure for table `Logs`
--

95
db/zm_update-1.31.16.sql Normal file
View File

@ -0,0 +1,95 @@
--
-- Add UpdateDiskSpace action to Filters
--
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'AutoMove'
) > 0,
"SELECT 'Column AutoMove already exists in Filters'",
"ALTER TABLE Filters ADD `AutoMove` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoDelete`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'AutoMoveTo'
) > 0,
"SELECT 'Column AutoMoveTo already exists in Filters'",
"ALTER TABLE Filters ADD `AutoMoveTo` smallint(5) unsigned NOT NULL default '0' AFTER `AutoMove`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'Groups_Monitors'
AND table_schema = DATABASE()
) > 0,
"SELECT 'Groups_Monitors table exists'",
"CREATE TABLE `Groups_Monitors` (
`Id` INT(10) unsigned NOT NULL auto_increment,
`GroupId` int(10) unsigned NOT NULL,
`MonitorId` int(10) unsigned NOT NULL,
PRIMARY KEY (`Id`)
)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'Groups_Monitors'
AND table_schema = DATABASE()
AND index_name = 'Groups_Monitors_GroupId_idx'
) > 0,
"SELECT 'Groups_Monitors_GroupId_idx already exists on Groups table'",
"CREATE INDEX `Groups_Monitors_GroupId_idx` ON `Groups_Monitors` (`GroupId`)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'Groups_Monitors'
AND table_schema = DATABASE()
AND index_name = 'Groups_Monitors_MonitorId_idx'
) > 0,
"SELECT 'Groups_Monitors_MonitorId_idx already exists on Groups table'",
"CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups_Monitors` (`MonitorId`)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Groups'
AND column_name = 'MonitorIds'
) > 0,
"REPLACE INTO Groups_Monitors (GroupId,MonitorId) SELECT Id,SUBSTRING_INDEX(SUBSTRING_INDEX(t.MonitorIds, ',', n.n), ',', -1) value FROM Groups t CROSS JOIN ( SELECT a.N + b.N * 10 + 1 n FROM (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b ORDER BY n ) n WHERE t.MonitorIds != '' AND n.n <= 1 + (LENGTH(t.MonitorIds) - LENGTH(REPLACE(t.MonitorIds, ',', ''))) ORDER BY value;",
"SELECT 'MonitorIds has already been removed.'"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Groups'
AND column_name = 'MonitorIds'
) > 0,
"ALTER TABLE Groups DROP MonitorIds",
"SELECT 'MonitorIds has already been removed.'"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -94,14 +94,14 @@ BEGIN {
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
$socket = ";mysql_socket=".$portOrSocket;
$socket = ';mysql_socket='.$portOrSocket;
} else {
$socket = ";host=".$host.";port=".$portOrSocket;
$socket = ';host='.$host.';port='.$portOrSocket;
}
} else {
$socket = ";host=".$Config{ZM_DB_HOST};
$socket = ';host='.$Config{ZM_DB_HOST};
}
my $sslOptions = "";
my $sslOptions = '';
if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = ';'.join(';',
"mysql_ssl=1",
@ -123,7 +123,8 @@ BEGIN {
}
$sth->finish();
#$dbh->disconnect();
if ( ! exists $Config{ZM_SERVER_ID} ) {
#
if ( ! $Config{ZM_SERVER_ID} ) {
$Config{ZM_SERVER_ID} = undef;
$sth = $dbh->prepare_cached( 'SELECT * FROM Servers WHERE Name=?' );
if ( $Config{ZM_SERVER_NAME} ) {
@ -143,7 +144,7 @@ BEGIN {
my $config_file = shift;
if ( -R $config_file ) {
open( my $CONFIG, "<", $config_file )
open( my $CONFIG, '<', $config_file )
or croak( "Can't open config file '$config_file': $!" );
foreach my $str ( <$CONFIG> ) {
next if ( $str =~ /^\s*$/ );
@ -165,7 +166,7 @@ BEGIN {
} # end BEGIN
sub loadConfigFromDB {
print( "Loading config from DB" );
print( 'Loading config from DB' );
my $dbh = ZoneMinder::Database::zmDbConnect();
if ( !$dbh ) {
print( "Error: unable to load options from database: $DBI::errstr\n" );
@ -188,7 +189,7 @@ sub loadConfigFromDB {
#next if ( $option->{category} eq 'hidden' );
if ( defined($value) ) {
if ( $option->{type} == $types{boolean} ) {
$option->{value} = $value?"yes":"no";
$option->{value} = $value?'yes':'no';
} else {
$option->{value} = $value;
}
@ -201,7 +202,7 @@ sub loadConfigFromDB {
} # end sub loadConfigFromDB
sub saveConfigToDB {
print( "Saving config to DB " . @options . " entries\n" );
print( 'Saving config to DB ' . @options . " entries\n" );
my $dbh = ZoneMinder::Database::zmDbConnect();
if ( !$dbh ) {
print( "Error: unable to save options to database: $DBI::errstr\n" );
@ -214,7 +215,7 @@ sub saveConfigToDB {
$dbh->do('LOCK TABLE Config WRITE')
or croak( "Can't lock Config table: " . $dbh->errstr() );
my $sql = "delete from Config";
my $sql = 'DELETE FROM Config';
my $res = $dbh->do( $sql )
or croak( "Can't do '$sql': ".$dbh->errstr() );
@ -228,8 +229,8 @@ sub saveConfigToDB {
$option->{db_hint} = $option->{type}->{hint};
$option->{db_pattern} = $option->{type}->{pattern};
$option->{db_format} = $option->{type}->{format};
if ( $option->{db_type} eq "boolean" ) {
$option->{db_value} = ($option->{value} eq "yes") ? "1" : "0";
if ( $option->{db_type} eq 'boolean' ) {
$option->{db_value} = ($option->{value} eq 'yes') ? '1' : '0';
} else {
$option->{db_value} = $option->{value};
}
@ -237,7 +238,7 @@ sub saveConfigToDB {
$option->{db_requires} = join( ";",
map {
my $value = $_->{value};
$value = ($value eq "yes") ? 1 : 0 if ( $options_hash{$_->{name}}->{db_type} eq "boolean" );
$value = ($value eq 'yes') ? 1 : 0 if ( $options_hash{$_->{name}}->{db_type} eq 'boolean' );
( "$_->{name}=$value" )
} @$requires
);

View File

@ -33,6 +33,8 @@ require ZoneMinder::Object;
require ZoneMinder::Storage;
require Date::Manip;
require File::Find;
require File::Path;
require File::Copy;
#our @ISA = qw(ZoneMinder::Object);
use parent qw(ZoneMinder::Object);
@ -401,6 +403,54 @@ sub DiskSpace {
}
}
sub MoveTo {
my ( $self, $NewStorage ) = @_;
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) {
return "New storage does not have an id. Moving will not happen.";
} elsif ( !$NewPath) {
return "$NewPath is empty.";
}elsif ( $NewPath eq $OldPath ) {
return "New path and old path are the same! $NewPath";
} elsif ( ! -e $NewPath ) {
return "New path $NewPath does not exist.";
}elsif ( ! -e $OldPath ) {
return "Old path $OldPath does not exist.";
}
my $error = '';
File::Path::make_path( $NewPath, {error => \my $err} );
if ( @$err ) {
for my $diag (@$err) {
my ($file, $message) = %$diag;
if ($file eq '') {
$error .= "general error: $message\n";
} else {
$error .= "problem unlinking $file: $message\n";
}
}
}
return $error if $error;
my @files = glob("$OldPath/*");
for my $file (@files) {
next if $file =~ /^\./;
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
if ( ! File::Copy::copy( $file, $NewPath ) ) {
$error .= "Copy failed: for $file to $NewPath: $!";
last;
}
} # end foreach file.
if ( ! $error ) {
# Succeeded in copying all files, so we may now update the Event.
$$self{StorageId} = $$NewStorage{Id};
$error .= $self->save();
}
return $error;
} # end sub MoveTo
1;
__END__

View File

@ -207,10 +207,11 @@ sub Sql {
if ( $term->{attr} =~ /^Monitor/ ) {
$value = "'$temp_value'";
} elsif ( $term->{attr} eq 'ServerId' ) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$Config{ZM_SERVER_ID}'";
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
# This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server( $Config{ZM_SERVER_ID} );
$$self{Server} = new ZoneMinder::Server( $ZoneMinder::Config::Config{ZM_SERVER_ID} );
} else {
$value = "'$temp_value'";
# This gets used later, I forget for what
@ -225,7 +226,7 @@ sub Sql {
) {
$value = "'$temp_value'";
} elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
if ( $temp_value == 'NULL' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL( $temp_value );
@ -237,7 +238,7 @@ sub Sql {
$value = "'$value'";
}
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
if ( $temp_value == 'NULL' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL( $temp_value );
@ -249,7 +250,7 @@ sub Sql {
$value = "to_days( '$value' )";
}
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
if ( $temp_value == 'NULL' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL( $temp_value );

View File

@ -215,6 +215,7 @@ sub getFilters {
or AutoExecute = 1
or AutoDelete = 1
or UpdateDiskSpace = 1
or AutoMove = 1
) ORDER BY Name';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr() );
@ -263,6 +264,7 @@ sub checkFilter {
($filter->{AutoEmail}?'email':()),
($filter->{AutoMessage}?'message':()),
($filter->{AutoExecute}?'execute':()),
($filter->{AutoMove}?'move':()),
($filter->{UpdateDiskSpace}?'update disk space':()),
),
'returned' , scalar @Events , 'events',
@ -270,11 +272,11 @@ sub checkFilter {
) );
foreach my $event ( @Events ) {
Debug( "Checking event $event->{Id}\n" );
Debug( "Checking event $event->{Id}" );
my $delete_ok = !undef;
$dbh->ping();
if ( $filter->{AutoArchive} ) {
Info( "Archiving event $event->{Id}\n" );
Info( "Archiving event $event->{Id}" );
# Do it individually to avoid locking up the table for new events
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql )
@ -315,11 +317,17 @@ sub checkFilter {
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
}
} # end if AutoDelete
if ( $filter->{AutoMove} ) {
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
my $NewStorage = new ZoneMinder::Storage( $filter->{AutoMoveTo} );
$_ = $Event->MoveTo( $NewStorage );
Error($_) if $_;
}
if ( $filter->{UpdateDiskSpace} ) {
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
$Event->DiskSpace(undef);
$Event->save();
} # end if UpdateDiskSpace
} # end foreach event
}

View File

@ -28,7 +28,7 @@ MYSQL dbconn;
bool zmDbConnected = false;
void zmDbConnect() {
// If these lines are uncommented, we get memory corruption and crashes
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
//if ( zmDbConnected )
//return;

View File

@ -1 +1 @@
1.31.15
1.31.16

View File

@ -76,6 +76,19 @@ if ( canView( 'Events' ) ) {
ajaxError( 'Export Failed' );
break;
}
case 'download' :
{
require_once( ZM_SKIN_PATH.'/includes/export_functions.php' );
$exportVideo = 1;
$exportFormat = $_REQUEST['exportFormat'];
$exportStructure = 'flat';
$exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id'];
if ( $exportFile = exportEvents( $exportIds, false, false, false, $exportVideo, false, $exportFormat, $exportStructure ) )
ajaxResponse( array( 'exportFile'=>$exportFile ) );
else
ajaxError( 'Export Failed' );
break;
}
}
}

View File

@ -17,12 +17,10 @@ class EventsController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('eventPermission');
if ($canView =='None')
{
if ($canView =='None') {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
@ -48,14 +46,7 @@ public function beforeFilter() {
} else {
$conditions = array();
}
// How many events to return
$this->loadModel('Config');
$limit = $this->Config->find('list', array(
'conditions' => array('Name' => 'ZM_WEB_EVENTS_PER_PAGE'),
'fields' => array('Name', 'Value')
));
$this->Paginator->settings = array(
$settings = array(
// https://github.com/ZoneMinder/ZoneMinder/issues/995
// 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'],
// 25 events per page which is what the above
@ -68,8 +59,28 @@ public function beforeFilter() {
'limit' => '100',
'order' => array('StartTime', 'MaxScore'),
'paramType' => 'querystring',
'conditions' => array (array($conditions, $mon_options))
);
//if ( $this->request->params['GroupId'] ) {
$settings['joins'] = array(
array(
'table' => 'Groups_Monitors',
'type' => 'inner',
'conditions' => array(
'Groups_Monitors.MonitorId = Event.MonitorId'
),
),
);
$settings['contain'] = array('Group');
//}
$settings['conditions'] = array($conditions, $mon_options);
// How many events to return
$this->loadModel('Config');
$limit = $this->Config->find('list', array(
'conditions' => array('Name' => 'ZM_WEB_EVENTS_PER_PAGE'),
'fields' => array('Name', 'Value')
));
$this->Paginator->settings = $settings;
$events = $this->Paginator->paginate('Event');
// For each event, get its thumbnail data (path, width, height)
@ -89,8 +100,7 @@ public function beforeFilter() {
* @param string $id
* @return void
*/
public function view($id = null)
{
public function view($id = null) {
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),

View File

@ -0,0 +1,108 @@
<?php
App::uses('AppController', 'Controller');
/**
* Groups Controller
*
* @property Group $Group
*/
class GroupsController extends AppController {
/**
* Components
*
* @var array
*/
public $components = array('RequestHandler');
/**
* index method
*
* @return void
*/
public function index() {
$this->Group->recursive = -1;
$groups = $this->Group->find('all');
$this->set(array(
'groups' => $groups,
'_serialize' => array('groups')
));
}
/**
* view method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function view($id = null) {
$this->Group->recursive = -1;
if (!$this->Group->exists($id)) {
throw new NotFoundException(__('Invalid group'));
}
$options = array('conditions' => array('Group.' . $this->Group->primaryKey => $id));
$group = $this->Group->find('first', $options);
$this->set(array(
'group' => $group,
'_serialize' => array('group')
));
}
/**
* add method
*
* @return void
*/
public function add() {
if ($this->request->is('post')) {
$this->Group->create();
if ($this->Group->save($this->request->data)) {
return $this->flash(__('The group has been saved.'), array('action' => 'index'));
}
}
$monitors = $this->Group->Monitor->find('list');
$this->set(compact('monitors'));
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
if (!$this->Group->exists($id)) {
throw new NotFoundException(__('Invalid group'));
}
if ($this->request->is(array('post', 'put'))) {
if ($this->Group->save($this->request->data)) {
return $this->flash(__('The group has been saved.'), array('action' => 'index'));
}
} else {
$options = array('conditions' => array('Group.' . $this->Group->primaryKey => $id));
$this->request->data = $this->Group->find('first', $options);
}
$monitors = $this->Group->Monitor->find('list');
$this->set(compact('monitors'));
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
$this->Group->id = $id;
if (!$this->Group->exists()) {
throw new NotFoundException(__('Invalid group'));
}
$this->request->allowMethod('post', 'delete');
if ($this->Group->delete()) {
return $this->flash(__('The group has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The group could not be deleted. Please, try again.'), array('action' => 'index'));
}
}}

View File

@ -8,7 +8,6 @@ App::uses('AppController', 'Controller');
*/
class MonitorsController extends AppController {
/**
* Components
*
@ -16,19 +15,15 @@ class MonitorsController extends AppController {
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('monitorPermission');
if ($canView =='None')
{
if ($canView =='None') {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
*
@ -48,7 +43,28 @@ public function beforeFilter() {
if (!empty($allowedMonitors)) {
$conditions['Monitor.Id' ] = $allowedMonitors;
}
$monitors = $this->Monitor->find('all',array('conditions'=>$conditions));
$find_array = array('conditions'=>$conditions,'contain'=>array('Group'));
//if ( $this->request->params['GroupId'] ) {
$find_array['joins'] = array(
array(
'table' => 'Groups_Monitors',
'type' => 'inner',
'conditions' => array(
'Groups_Monitors.MonitorId = Monitor.Id'
),
),
//array(
//'table' => 'Groups',
//'type' => 'inner',
//'conditions' => array(
//'Groups.Id = Groups_Monitors.GroupId',
//'Groups.Id' => $this->request->params['GroupId'],
//),
//)
);
//}
$monitors = $this->Monitor->find('all',$find_array);
$this->set(array(
'monitors' => $monitors,
'_serialize' => array('monitors')

View File

@ -68,4 +68,28 @@ class Event extends AppModel {
)
);
/**
* * * hasMany associations
* * *
* * * @var array
* * */
public $hasAndBelongsToMany = array(
'Group' => array(
'className' => 'Group',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'MonitorId',
'associationForeignKey' => 'GroupId',
'unique' => true,
'dependent' => false,
'conditions' => 'Groups_Monitors.MonitorId=Event.MonitorId',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
}

View File

@ -0,0 +1,68 @@
<?php
App::uses('AppModel', 'Model');
/**
* Group Model
*
* @property Event $Event
*/
class Group extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Groups';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'Name' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
);
public $recursive = -1;
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* hasMany associations
*
* @var array
*/
public $hasMany = array(
'Monitor' => array(
'className' => 'Monitor',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'GroupId',
'associationForeignKey' => 'MonitorId',
'unique'=>true,
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
}

View File

@ -85,4 +85,28 @@ class Monitor extends AppModel {
)
);
/**
* * hasMany associations
* *
* * @var array
* */
public $hasAndBelongsToMany = array(
'Group' => array(
'className' => 'Group',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'MonitorId',
'associationForeignKey' => 'GroupId',
'unique' => true,
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
}

View File

@ -1,2 +1,2 @@
$xml = Xml::fromArray(array('response' => $monitors));
$xml = Xml::fromArray(array('response' => $servers));
echo $xml->asXML();

View File

@ -1,2 +1,2 @@
$xml = Xml::fromArray(array('response' => $monitor));
$xml = Xml::fromArray(array('response' => $server));
echo $xml->asXML();

View File

@ -12,6 +12,8 @@ public $defaults = array(
'AutoArchive' => 0,
'AutoVideo' => 0,
'AutoMessage' => 0,
'AutoMove' => 0,
'AutoMoveTo' => 0,
'UpdateDiskSpace' => 0,
'Background' => 0,
'Concurrent' => 0,

View File

@ -6,7 +6,6 @@ public $defaults = array(
'Id' => null,
'Name' => '',
'ParentId' => null,
'MonitorIds' => '',
);
public function __construct( $IdOrRow=NULL ) {
@ -89,6 +88,7 @@ public $defaults = array(
public function delete() {
if ( array_key_exists( 'Id', $this ) ) {
dbQuery( 'DELETE FROM Groups WHERE Id=?', array($this->{'Id'}) );
dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}) );
if ( isset($_COOKIE['zmGroup']) ) {
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
unset( $_COOKIE['zmGroup'] );
@ -128,6 +128,13 @@ public $defaults = array(
return $this->{'depth'};
} // end public function depth
public function MonitorIds( ) {
if ( ! array_key_exists( 'MonitorIds', $this ) ) {
$this->{'MonitorIds'} = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}) );
}
return $this->{'MonitorIds'};
}
public static function get_group_dropdowns() {
# This will end up with the group_id of the deepest selection
$group_id = 0;
@ -164,19 +171,14 @@ public $defaults = array(
return $group_id;
} # end public static function get_group_dropdowns()
public static function get_group_sql( $group_id ) {
$groupSql = '';
if ( $group_id ) {
if ( $group = dbFetchOne( 'SELECT MonitorIds FROM Groups WHERE Id=?', NULL, array($group_id) ) ) {
$groupIds = array();
if ( $group['MonitorIds'] )
$groupIds = explode( ',', $group['MonitorIds'] );
$MonitorIds = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($group_id) );
foreach ( dbFetchAll( 'SELECT MonitorIds FROM Groups WHERE ParentId = ?', NULL, array($group_id) ) as $group )
if ( $group['MonitorIds'] )
$groupIds = array_merge( $groupIds, explode( ',', $group['MonitorIds'] ) );
}
$groupSql = " find_in_set( Id, '".implode( ',', $groupIds )."' )";
$MonitorIds = array_merge( $MonitorIds, dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId = ?)', 'MonitorId', array($group_id) ) );
$groupSql = " find_in_set( Id, '".implode( ',', $MonitorIds )."' )";
}
return $groupSql;
} # end public static function get_group_sql( $group_id )

View File

@ -142,7 +142,6 @@ if ( canView( 'Events' ) ) {
if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
if ( $action == 'addterm' ) {
Warning("Addterm");
$_REQUEST['filter'] = addFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
} elseif ( $action == 'delterm' ) {
$_REQUEST['filter'] = delFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
@ -173,6 +172,11 @@ Warning("Addterm");
$sql .= ', AutoExecute = '. ( !empty($_REQUEST['filter']['AutoExecute']) ? 1 : 0);
$sql .= ', AutoExecuteCmd = '.dbEscape($_REQUEST['filter']['AutoExecuteCmd']);
$sql .= ', AutoDelete = '. ( !empty($_REQUEST['filter']['AutoDelete']) ? 1 : 0);
if ( !empty($_REQUEST['filter']['AutoMove']) ? 1 : 0) {
$sql .= ', AutoMove = 1, AutoMoveTo='. validInt($_REQUEST['filter']['AutoMoveTo']);
} else {
$sql .= ', AutoMove = 0';
}
$sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
$sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
@ -542,7 +546,7 @@ if ( canEdit( 'Monitors' ) ) {
$saferName = basename($_REQUEST['newMonitor']['Name']);
symlink( $mid, ZM_DIR_EVENTS.'/'.$saferName );
if ( isset($_COOKIE['zmGroup']) ) {
dbQuery( "UPDATE Groups SET MonitorIds = concat(MonitorIds,',".$mid."') WHERE Id=?", array($_COOKIE['zmGroup']) );
dbQuery( 'INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($_COOKIE['zmGroup'],$mid) );
}
} else {
Error("Users with Monitors restrictions cannot create new monitors.");
@ -662,12 +666,16 @@ if ( canEdit( 'Groups' ) ) {
if ( $action == 'group' ) {
$monitors = empty( $_POST['newGroup']['MonitorIds'] ) ? '' : implode(',', $_POST['newGroup']['MonitorIds']);
if ( !empty($_POST['gid']) ) {
dbQuery( 'UPDATE Groups SET Name=?, ParentId=?, MonitorIds=? WHERE Id=?',
array($_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors, $_POST['gid']) );
dbQuery( 'UPDATE Groups SET Name=?, ParentId=? WHERE Id=?',
array($_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $_POST['gid']) );
dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($_POST['gid']) );
} else {
dbQuery( 'INSERT INTO Groups SET Name=?, ParentId=?, MonitorIds=?',
array( $_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors ) );
}
foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) {
dbQuery( 'INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($_POST['gid'], $mid) );
}
$view = 'none';
$refreshParent = true;
} else if ( $action == 'delete' ) {

View File

@ -137,19 +137,19 @@ require_once( 'database.php' );
loadConfig();
$GLOBALS['defaultUser'] = array(
"Username" => "admin",
"Password" => "",
"Language" => "",
"Enabled" => 1,
"Stream" => 'View',
"Events" => 'Edit',
"Control" => 'Edit',
"Monitors" => 'Edit',
"Groups" => 'Edit',
"Devices" => 'Edit',
"System" => 'Edit',
"MaxBandwidth" => "",
"MonitorIds" => false
'Username' => "admin",
'Password' => "",
'Language' => "",
'Enabled' => 1,
'Stream' => 'View',
'Events' => 'Edit',
'Control' => 'Edit',
'Monitors' => 'Edit',
'Groups' => 'Edit',
'Devices' => 'Edit',
'System' => 'Edit',
'MaxBandwidth' => '',
'MonitorIds' => false
);
function loadConfig( $defineConsts=true ) {
@ -179,7 +179,7 @@ function loadConfig( $defineConsts=true ) {
}
require_once( 'logger.php' );
// For Human-readability, user ZM_SERVER in zm.conf, and convert it here to a ZM_SERVER_ID
// For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID
if ( ! defined('ZM_SERVER_ID') ) {
if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) {
$server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_NAME));

View File

@ -134,7 +134,7 @@ function dbQuery( $sql, $params=NULL ) {
} else {
$result = $dbConn->query( $sql );
}
if ( 1 ) {
if ( defined('ZM_DB_DEBUG') ) {
if ( $params )
Warning("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() );
else

View File

@ -1872,7 +1872,10 @@ function monitorIdsToNames( $ids ) {
}
}
$names = array();
foreach ( preg_split( '/\s*,\s*/', $ids ) as $id ) {
if ( ! is_array($ids) ) {
$ids = preg_split( '/\s*,\s*/', $ids );
}
foreach ( $ids as $id ) {
if ( visibleMonitor( $id ) ) {
if ( isset($mITN_monitors[$id]) ) {
$names[] = $mITN_monitors[$id]['Name'];

View File

@ -322,6 +322,8 @@ $SLANG = array(
'ExportDetails' => 'Export Event Details',
'Exif' => 'Embed EXIF data into image',
'Export' => 'Export',
'DownloadVideo' => 'Download Video',
'GenerateDownload' => 'Generate Download',
'ExportFailed' => 'Export Failed',
'ExportFormat' => 'Export File Format',
'ExportFormatTar' => 'Tar',

View File

@ -1,3 +1,4 @@
/*
* ZoneMinder Base Stylesheet, $Date$, $Revision$
* Copyright (C) 2001-2008 Philip Coombes
@ -346,9 +347,11 @@ th.table-th-sort-rev span.table-th-sort-span {
#header {
width: 100%;
line-height: 24px;
margin: 8px auto;
margin: 0 auto 4px auto;
line-height: 1;
text-align: left;
padding: 3px 0;
border-bottom: 1px solid #555555;
}
#header h2 {
@ -378,7 +381,7 @@ th.table-th-sort-rev span.table-th-sort-span {
#content {
width: 96%;
margin: 8px auto;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
}

View File

@ -29,89 +29,42 @@ span.noneCue {
background: none;
}
#header {
display: flex;
justify-content: space-between;
flex-direction: column;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#dataBar {
width: 100%;
margin: 2px auto;
text-align: center;
}
#dataBar #dataTable {
width: 100%;
table-layout: fixed;
}
#dataBar #dataTable td {
text-align: center;
padding: 2px;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
}
#menuBar1 {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
padding: 3px 0;
text-align: center;
clear: both;
}
#menuBar1 #nameControl {
float: left;
}
#menuBar1 #nameControl #eventName {
margin-right: 4px;
margin: 4px 0 0 0;
}
#menuBar1 #replayControl {
float: right;
margin-left: 8px;
margin: 0 4px 0 auto;
}
#menuBar1 #scaleControl {
float: right;
margin-left: 8px;
#menuBar1 div {
margin: auto 5px;
}
#menuBar2 {
width: 100%;
padding: 3px 0;
margin-bottom: 4px;
}
#menuBar2 div {
text-align: left;
float: left;
padding: 0 12px;
}
#menuBar2 #closeWindow {
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#videoBar1 div {
text-align: center;
float: center;
}
#videoBar1 #prevEvent {
float: left;
}
#videoBar1 #dlEvent {
float: center;
}
#videoBar1 #nextEvent {
float: right;
#nameControl input[type="button"]{
height: 100%;
}
#eventVideo {

View File

@ -2,36 +2,6 @@
background-color: #f8f8f8;;
}
#controls {
height: 16px;
width: 100%;
text-align: center;
margin: 0 auto;
position: relative;
}
#controls a {
width: 32%;
}
#controls #refreshLink {
position: absolute;
left: 0%;
text-align: left;
}
#controls #filterLink {
position: absolute;
left: 34%;
text-align: center;
}
#controls #timelineLink {
position: absolute;
left: 68%;
text-align: right;
}
#contentTable.major .colTime {
white-space: nowrap;
}
@ -44,3 +14,26 @@
text-align: right;
padding-right: 8px;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #pagination, #header #controls {
display: flex;
flex-direction: column;
}
#header #controls {
align-items: flex-end;
}
#header #pagination {
align-items: center;
}

View File

@ -36,3 +36,7 @@
input[type=range]::-ms-tooltip {
display: none;
}
#downloadVideo {
margin-left: 5px;
}

View File

@ -5,6 +5,25 @@
margin: 0 auto;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #headerButtons {
display: flex;
flex-direction: column;
}
#header #headerButtons {
align-items: flex-end;
}
#title {
position: relative;
margin: 0 auto;
@ -15,20 +34,6 @@
line-height: 20px;
}
#listLink {
position: absolute;
top: 5px;
left: 20px;
height: 15px;
}
#closeLink {
position: absolute;
top: 5px;
right: 20px;
height: 15px;
}
#topPanel {
position: relative;
height: 220px;

View File

@ -1,37 +1,17 @@
@import url(../control.css);
#menuBar {
margin: 6px auto 4px;
text-align: center;
#header {
display: flex;
justify-content: space-between;
}
#menuBar #monitorName {
float: left;
#menuControls {
display: flex;
align-items: center;
}
#menuBar #closeControl {
float: right;
}
#menuBar #menuControls {
margin: 0 auto;
width: 60%;
}
#menuBar #menuControls #controlControl {
float: left;
}
#menuBar #menuControls #eventsControl {
float: left;
}
#menuBar #menuControls #settingsControl {
float: right;
}
#menuBar #menuControls #scaleControl {
margin: 0 auto;
#menuControls div {
margin: 0 0 0 1em;
}
#imageFeed{

View File

@ -373,11 +373,12 @@ th.table-th-sort-rev span.table-th-sort-span {
#header {
width: 100%;
line-height: 24px;
line-height: 1;
text-align: left;
margin-bottom: 10px;
padding: 10px 20px;
padding: 5px 20px;
margin: 0 auto 4px auto;
font-weight: 300;
border-bottom: 1px solid #000000;
}
#header h2 {
@ -407,7 +408,7 @@ th.table-th-sort-rev span.table-th-sort-span {
#content {
width: 96%;
margin: 8px auto;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
}

View File

@ -29,72 +29,42 @@ span.noneCue {
background: none;
}
#header {
display: flex;
justify-content: space-between;
flex-direction: column;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#dataBar {
width: 100%;
margin: 2px auto;
text-align: center;
}
#dataBar #dataTable {
width: 100%;
table-layout: fixed;
}
#dataBar #dataTable td {
text-align: center;
padding: 2px;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
}
#menuBar1 {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
padding: 3px 0;
text-align: center;
clear: both;
}
#menuBar1 #nameControl {
float: left;
}
#menuBar1 #nameControl #eventName {
margin-right: 4px;
margin: 4px 0 0 0;
}
#menuBar1 #replayControl {
float: right;
margin-left: 8px;
margin: 0 4px 0 auto;
}
#menuBar1 #scaleControl {
float: right;
margin-left: 8px;
#menuBar1 div {
margin: auto 5px;
}
#menuBar2 {
width: 100%;
padding: 3px 0;
margin-bottom: 4px;
}
#menuBar2 div {
text-align: left;
float: left;
padding: 0 12px;
}
#menuBar2 #closeWindow {
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
#nameControl input[type="button"]{
height: 100%;
}
#eventVideo {

View File

@ -2,36 +2,6 @@
background-color: #2e2e2e;
}
#controls {
height: 16px;
width: 100%;
text-align: center;
margin: 0 auto;
position: relative;
}
#controls a {
width: 32%;
}
#controls #refreshLink {
position: absolute;
left: 0%;
text-align: left;
}
#controls #filterLink {
position: absolute;
left: 34%;
text-align: center;
}
#controls #timelineLink {
position: absolute;
left: 68%;
text-align: right;
}
#contentTable.major .colTime {
white-space: nowrap;
}
@ -44,3 +14,26 @@
text-align: right;
padding-right: 8px;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #pagination, #header #controls {
display: flex;
flex-direction: column;
}
#header #controls {
align-items: flex-end;
}
#header #pagination {
align-items: center;
}

View File

@ -36,3 +36,7 @@
input[type=range]::-ms-tooltip {
display: none;
}
#downloadVideo {
margin-left: 5px;
}

View File

@ -5,6 +5,25 @@
margin: 0 auto;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #headerButtons {
display: flex;
flex-direction: column;
}
#header #headerButtons {
align-items: flex-end;
}
#title {
position: relative;
margin: 0 auto;
@ -15,20 +34,6 @@
line-height: 20px;
}
#listLink {
position: absolute;
top: 5px;
left: 20px;
height: 15px;
}
#closeLink {
position: absolute;
top: 5px;
right: 20px;
height: 15px;
}
#topPanel {
position: relative;
height: 220px;

View File

@ -1,37 +1,17 @@
@import url(../control.css);
#menuBar {
margin: 6px auto 4px;
text-align: center;
#header {
display: flex;
justify-content: space-between;
}
#menuBar #monitorName {
float: left;
#menuControls {
display: flex;
align-items: center;
}
#menuBar #closeControl {
float: right;
}
#menuBar #menuControls {
margin: 0 auto;
width: 60%;
}
#menuBar #menuControls #controlControl {
float: left;
}
#menuBar #menuControls #eventsControl {
float: left;
}
#menuBar #menuControls #settingsControl {
float: right;
}
#menuBar #menuControls #scaleControl {
margin: 0 auto;
#menuControls div {
margin: 0 0 0 1em;
}
#imageFeed{

View File

@ -368,11 +368,11 @@ th.table-th-sort-rev span.table-th-sort-span {
#header {
width: 100%;
line-height: 24px;
line-height: 1;
text-align: left;
background-color: #383836;
margin-bottom: 10px;
padding: 10px 20px;
padding: 5px 20px;
margin: 0 auto 4px auto;
color: #f2f2f2;
font-weight: 300;
}
@ -410,7 +410,7 @@ th.table-th-sort-rev span.table-th-sort-span {
#content {
width: 96%;
margin: 8px auto;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
}

View File

@ -29,72 +29,47 @@ span.noneCue {
background: none;
}
#header {
display: flex;
justify-content: space-between;
flex-direction: column;
margin: 0 0 4px 0;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#dataBar {
width: 100%;
margin: 2px auto;
text-align: center;
}
#dataBar #dataTable {
width: 100%;
table-layout: fixed;
}
#dataBar #dataTable td {
text-align: center;
padding: 2px;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
}
#menuBar1 {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
padding: 3px 0;
text-align: center;
clear: both;
margin: 4px 0 0 0;
}
#menuBar1 #nameControl {
float: left;
}
#menuBar1 #nameControl #eventName {
margin-right: 4px;
#menuBar1 input, #menuBar1 select {
padding: 2px 5px;
}
#menuBar1 #replayControl {
float: right;
margin-left: 8px;
margin: 0 4px 0 auto;
}
#menuBar1 #scaleControl {
float: right;
margin-left: 8px;
#menuBar1 div {
margin: auto 5px;
}
#menuBar2 {
width: 100%;
padding: 3px 0;
margin-bottom: 4px;
}
#menuBar2 div {
text-align: left;
float: left;
padding: 0 12px;
}
#menuBar2 #closeWindow {
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
#nameControl input[type="button"]{
height: 100%;
}
#eventVideo {

View File

@ -2,36 +2,6 @@
background-color: #f8f8f8;;
}
#controls {
height: 16px;
width: 100%;
text-align: center;
margin: 0 auto;
position: relative;
}
#controls a {
width: 32%;
}
#controls #refreshLink {
position: absolute;
left: 0%;
text-align: left;
}
#controls #filterLink {
position: absolute;
left: 34%;
text-align: center;
}
#controls #timelineLink {
position: absolute;
left: 68%;
text-align: right;
}
#contentTable.major .colTime {
white-space: nowrap;
}
@ -44,3 +14,26 @@
text-align: right;
padding-right: 8px;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #pagination, #header #controls {
display: flex;
flex-direction: column;
}
#header #controls {
align-items: flex-end;
}
#header #pagination {
align-items: center;
}

View File

@ -42,3 +42,7 @@ input[type=range]::-ms-tooltip {
color: white;
font-size: 40px;
}
#downloadVideo {
margin-left: 5px;
}

View File

@ -5,6 +5,25 @@
margin: 0 auto;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #headerButtons {
display: flex;
flex-direction: column;
}
#header #headerButtons {
align-items: flex-end;
}
#title {
position: relative;
margin: 0 auto;
@ -15,20 +34,6 @@
line-height: 20px;
}
#listLink {
position: absolute;
top: 5px;
left: 20px;
height: 15px;
}
#closeLink {
position: absolute;
top: 5px;
right: 20px;
height: 15px;
}
#topPanel {
position: relative;
height: 220px;

View File

@ -1,37 +1,17 @@
@import url(../control.css);
#menuBar {
margin: 6px auto 4px;
text-align: center;
#header {
display: flex;
justify-content: space-between;
}
#menuBar #monitorName {
float: left;
#menuControls {
display: flex;
align-items: center;
}
#menuBar #closeControl {
float: right;
}
#menuBar #menuControls {
margin: 0 auto;
width: 60%;
}
#menuBar #menuControls #controlControl {
float: left;
}
#menuBar #menuControls #eventsControl {
float: left;
}
#menuBar #menuControls #settingsControl {
float: right;
}
#menuBar #menuControls #scaleControl {
margin: 0 auto;
#menuControls div {
margin: 0 0 0 1em;
}
#imageFeed{

View File

@ -853,7 +853,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp
return( array_values( $exportFileList ) );
}
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat )
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat, $exportStructure = false )
{
if ( canView( 'Events' ) && !empty($eids) )
@ -907,8 +907,12 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
{
$archive = ZM_DIR_EXPORTS."/".$export_root.".tar.gz";
@unlink( $archive );
$command = "tar --create --gzip --file=$archive --files-from=$listFile";
exec( escapeshellcmd( $command ), $output, $status );
if ($exportStructure == 'flat') { //strip file paths if we choose
$command = "tar --create --gzip --file=".escapeshellarg($archive)." --files-from=".escapeshellarg($listFile)." --xform='s#^.+/##x'";
} else {
$command = "tar --create --gzip --file=".escapeshellarg($archive)." --files-from=".escapeshellarg($listFile);
}
exec( $command, $output, $status );
if ( $status )
{
Error( "Command '$command' returned with status $status" );
@ -921,7 +925,11 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
{
$archive = ZM_DIR_EXPORTS."/".$export_root.".zip";
@unlink( $archive );
if ($exportStructure == 'flat') {
$command = "cat ".escapeshellarg($listFile)." | zip -q -j ".escapeshellarg($archive)." -@";
} else {
$command = "cat ".escapeshellarg($listFile)." | zip -q ".escapeshellarg($archive)." -@";
}
//cat zmFileList.txt | zip -q zm_export.zip -@
//-bash: zip: command not found

View File

@ -166,6 +166,11 @@ function getNavBarHTML($reload = null) {
global $user;
global $bandwidth_options;
global $view;
global $filterQuery;
if (!$filterQuery) {
parseFilter( $_REQUEST['filter'] );
$filterQuery = $_REQUEST['filter']['query'];
}
if ($reload === null) {
ob_start();
if ( $running == null )
@ -210,7 +215,7 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
<li><a href="?view=devices">Devices</a></li>
<?php } ?>
<li><a href="?view=groups"<?php echo $view=='groups'?' class="selected"':''?>><?php echo translate('Groups') ?></a></li>
<li><a href="?view=filter"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
<li><a href="?view=filter<?php echo $filterQuery ?>"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
<?php
if ( canView( 'Stream' ) ) {
@ -219,9 +224,23 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
<li><a href="?view=montage"<?php echo $view=='montage'?' class="selected"':''?>><?php echo translate('Montage') ?></a></li>
<?php
}
if (isset($_REQUEST['filter']['Query']['terms'])) {
$terms = $_REQUEST['filter']['Query']['terms'];
$count = 0;
foreach ($terms as $term) {
if ($term['attr'] == "StartDateTime") {
$count += 1;
if ($term['op'] == '>=') $minTime = $term['val'];
if ($term['op'] == '<=') $maxTime = $term['val'];
}
}
if ($count == 2) {
$montageReviewQuery = '&minTime='.$minTime.'&maxTime='.$maxTime;
}
}
if ( canView('Events') ) {
?>
<li><a href="?view=montagereview"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
<li><a href="?view=montagereview<?php echo isset($montageReviewQuery)?'&fit=1'.$montageReviewQuery.'&live=0':'' ?>"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
<?php
}
?>

View File

@ -366,7 +366,7 @@ function parseTreeToFilter( $tree )
$level = 0;
_parseTreeToFilter( $tree, $terms, $level );
}
return( array( 'terms' => $terms ) );
return( array( 'Query' => array( 'terms' => $terms ) ) );
}
function parseTreeToQuery( $tree )
@ -468,7 +468,7 @@ function extractDatetimeRange( &$tree, &$minTime, &$maxTime, &$expandable )
function appendDatetimeRange( &$tree, $minTime, $maxTime=false )
{
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'DateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$minTime, 'sqlValue'=>$minTime ), 'count'=>0 );
$opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'>=', 'sqlValue'=>'>=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode );
if ( isset($tree) )
@ -483,7 +483,7 @@ function appendDatetimeRange( &$tree, $minTime, $maxTime=false )
if ( $maxTime )
{
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'DateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$maxTime, 'sqlValue'=>$maxTime ), 'count'=>0 );
$opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'<=', 'sqlValue'=>'<=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode );
$cnjNode = array( 'data'=>array( 'type'=>'cnj', 'value'=>'and', 'sqlValue'=>'and' ), 'count'=>2+$tree['count']+$opNode['count'], 'left'=>$tree, 'right'=>$opNode );

View File

@ -33,6 +33,7 @@ var popupSizes = {
'device': { 'width': 260, 'height': 150 },
'devices': { 'width': 400, 'height': 240 },
'donate': { 'width': 500, 'height': 280 },
'download': { 'width': 350, 'height': 215 },
'event': { 'addWidth': 108, 'minWidth': 496, 'addHeight': 230, 'minHeight': 540 },
'eventdetail': { 'width': 600, 'height': 420 },
'events': { 'width': 1220, 'height': 780 },

View File

@ -206,11 +206,11 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<?php
if ( ZM_WEB_ID_ON_CONSOLE ) {
?>
<td class="colId"><?php echo makePopupLink( '?view=watch&amp;mid='.$monitor['Id'], 'zmWatch'.$monitor['Id'], array( 'watch', reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ) ), $monitor['Id'], ($monitor['Function'] != 'None') && canView('Stream') ) ?></td>
<td class="colId"><a <?php echo (canView('Stream') && $running && $monitor['Function'] != 'None' ? 'href="?view=watch&amp;mid='.$monitor['Id'].'">' : '>') . $monitor['Id'] ?></a></td>
<?php
}
?>
<td class="colName"><?php echo makePopupLink( '?view=watch&amp;mid='.$monitor['Id'], 'zmWatch'.$monitor['Id'], array( 'watch', reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ) ), $monitor['Name'], ($monitor['Function'] != 'None') && canView('Stream') ) ?></td>
<td class="colName"><a <?php echo (canView('Stream') && $monitor['Function'] != 'None' ? 'href="?view=watch&amp;mid='.$monitor['Id'].'">' : '>') . $monitor['Name'] ?></a></td>
<td class="colFunction">
<?php echo makePopupLink( '?view=function&amp;mid='.$monitor['Id'], 'zmFunction', 'function', '<span class="'.$fclass.'">'.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'</span>', canEdit( 'Monitors' ) ) ?><br/>
<?php echo $monitor['CaptureFPS'] . ( ( $monitor['Function'] == 'Mocord' or $monitor['Function'] == 'Modect' ) ? ' / ' . $monitor['AnalysisFPS'] : '' ) . ' FPS' ?>
@ -243,8 +243,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
foreach ( array_keys( $eventCounts ) as $i ) {
?>
<td class="colEvents"><?php echo makePopupLink( '?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$monitor['eventCounts'][$i]['filter']['query'], $eventsWindow, ZM_WEB_EVENTS_VIEW,
$monitor[$i.'Events'] . '<br/>' . human_filesize($monitor[$i.'EventDiskSpace']), canView( 'Events' ) ) ?></td>
<td class="colEvents"><a <?php echo (canView('Events') ? 'href="?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$monitor['eventCounts'][$i]['filter']['query'].'">' : '') .
$monitor[$i.'Events'] . '<br/>' . human_filesize($monitor[$i.'EventDiskSpace']) ?></a></td>
<?php
}
?>
@ -279,9 +279,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
parseFilter( $eventCounts[$i]['filter'] );
?>
<td class="colEvents">
<?php echo makePopupLink( '?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$eventCounts[$i]['filter']['query'], $eventsWindow, ZM_WEB_EVENTS_VIEW,
$eventCounts[$i]['totalevents'].'<br/>'.human_filesize($eventCounts[$i]['totaldiskspace']), canView( 'Events' ) ) ?>
</td>
<a <?php echo (canView('Events') ? 'href="?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$eventCounts[$i]['filter']['query'].'">' : '') .
$eventCounts[$i]['totalevents'].'<br/>'.human_filesize($eventCounts[$i]['totaldiskspace']) ?></a></td>
<?php
}
?>

View File

@ -31,52 +31,26 @@ if ( empty($_REQUEST['mode']) ) {
} else {
$mode = validHtmlStr($_REQUEST['mode']);
}
ob_start();
include('_monitor_filters.php');
$filterbar = ob_get_contents();
ob_end_clean();
$group_id = 0;
if ( isset($_REQUEST['group']) ) {
$group_id = $_REQUEST['group'];
} else if ( isset($_COOKIE['zmGroup'] ) ) {
$group_id = $_COOKIE['zmGroup'];
}
$subgroup_id = 0;
if ( isset($_REQUEST['subgroup']) ) {
$subgroup_id = $_REQUEST['subgroup'];
} else if ( isset($_COOKIE['zmSubGroup'] ) ) {
$subgroup_id = $_COOKIE['zmSubGroup'];
}
$groupIds = null;
if ( $group_id ) {
$groupIds = array();
if ( $group = dbFetchOne( 'SELECT MonitorIds FROM Groups WHERE Id = ?', NULL, array($group_id) ) )
if ( $group['MonitorIds'] )
$groupIds = explode( ',', $group['MonitorIds'] );
if ( $subgroup_id ) {
if ( $group = dbFetchOne( 'SELECT MonitorIds FROM Groups WHERE Id = ?', NULL, array($subgroup_id) ) )
if ( $group['MonitorIds'] )
$groupIds = array_merge( $groupIds, explode( ',', $group['MonitorIds'] ) );
} else {
foreach ( dbFetchAll( 'SELECT MonitorIds FROM Groups WHERE ParentId = ?', NULL, array($group_id) ) as $group )
if ( $group['MonitorIds'] )
$groupIds = array_merge( $groupIds, explode( ',', $group['MonitorIds'] ) );
}
}
$groupSql = '';
if ( $groupIds )
$groupSql = " and find_in_set( Id, '".implode( ',', $groupIds )."' )";
$sql = "SELECT * FROM Monitors WHERE Function != 'None'$groupSql ORDER BY Sequence";
$monitors = array();
$monIdx = 0;
foreach( dbFetchAll( $sql ) as $row ) {
if ( !visibleMonitor( $row['Id'] ) )
$monitors = array();
foreach( $displayMonitors as &$row ) {
if ( $row['Function'] == 'None' )
continue;
if ( isset($_REQUEST['mid']) && $row['Id'] == $_REQUEST['mid'] )
$monIdx = count($monitors);
$row['ScaledWidth'] = reScale( $row['Width'], $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$row['ScaledHeight'] = reScale( $row['Height'], $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$row['connKey'] = generateConnKey();
$monitors[] = new Monitor( $row );
}
} # end foreach Monitor
if ( $monitors ) {
$monitor = $monitors[$monIdx];
@ -103,22 +77,7 @@ xhtmlHeaders(__FILE__, translate('CycleWatch') );
<?php } ?>
</div>
<div class="controlHeader">
<span id="groupControl"><label><?php echo translate('Group') ?>:</label>
<?php
$groups = array(0=>'All');
foreach ( Group::find_all( array('ParentId'=>null) ) as $Group ) {
$groups[$Group->Id()] = $Group->Name();
}
echo htmlSelect( 'group', $groups, $group_id, 'changeGroup(this);' );
$groups = array(0=>'All');
if ( $group_id ) {
foreach ( Group::find_all( array('ParentId'=>$group_id) ) as $Group ) {
$groups[$Group->Id()] = $Group->Name();
}
}
echo htmlSelect( 'subgroup', $groups, $subgroup_id, 'changeSubGroup(this);' );
?>
<?php echo $filterbar ?>
</div>
</div>
<div id="content">

View File

@ -0,0 +1,109 @@
<?php
//
// ZoneMinder web export 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($_REQUEST['filter'])) { //Handles montageReview filter
$eventsSql = 'SELECT E.Id FROM Events as E WHERE 1';
parseFilter($_REQUEST['filter']);
$eventsSql .= $_REQUEST['filter']['sql'];
$results = dbQuery($eventsSql);
$eids = [];
while ( $event_row = dbFetchNext( $results ) ) {
array_push($eids, 'eids[]='.$event_row['Id']);
}
$_REQUEST['eids'] = $eids;
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Download') );
?>
<body>
<div id="page">
<div id="header">
<div id="headerButtons">
<a href="#" onclick="closeWindow()"><?php echo translate('Close') ?></a>
</div>
<h2><?php echo translate('Download') ?></h2>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<?php
if ( !empty($_REQUEST['eid']) ) {
?>
<input type="hidden" name="id" value="<?php echo validInt($_REQUEST['eid']) ?>"/>
<?php
} else if ( !empty($_REQUEST['eids']) ) {
foreach ( $_REQUEST['eids'] as $eid ) {
?>
<input type="hidden" name="eids[]" value="<?php echo validInt($eid) ?>"/>
<?php
}
unset( $eid );
}
?>
<table id="contentTable" class="minor" cellspacing="0">
<tbody>
<tr>
<td><input type="hidden" name="exportVideo" value="1"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ExportFormat') ?></th>
<td>
<input type="radio" id="exportFormatTar" name="exportFormat" value="tar" onclick="configureExportButton(this)"/>
<label for="exportFormatTar"><?php echo translate('ExportFormatTar') ?></label>
<input type="radio" id="exportFormatZip" name="exportFormat" value="zip" checked="checked" onclick="configureExportButton(this);"/>
<label for="exportFormatZip"><?php echo translate('ExportFormatZip') ?></label>
</td>
</tr>
</tbody>
</table>
<input type="button" id="exportButton" name="exportButton" value="<?php echo translate('GenerateDownload') ?>" onclick="exportEvent(this.form);" />
</form>
</div>
<?php
if ( isset($_REQUEST['generated']) ) {
?>
<h2 id="exportProgress" class="<?php echo $_REQUEST['generated']?'infoText':'errorText' ?>">
<span id="exportProgressText"><?php echo $_REQUEST['generated']?translate('ExportSucceeded'):translate('ExportFailed') ?></span>
<span id="exportProgressTicker"></span>
</h2>
<?php
} else {
?>
<h2 id="exportProgress" class="hidden warnText">
<span id="exportProgressText"><?php echo translate('Exporting') ?></span>
<span id="exportProgressTicker"></span>
</h2>
<?php
}
if ( !empty($_REQUEST['generated']) ) {
?>
<h3 id="downloadLink"><a href="<?php echo validHtmlStr($_REQUEST['exportFile']) ?>"><?php echo translate('Download') ?></a></h3>
<?php
}
?>
</div>
</body>
</html>

View File

@ -100,34 +100,27 @@ xhtmlHeaders(__FILE__, translate('Event') );
?>
<body>
<div id="page">
<div id="content">
<?php echo getNavBarHTML() ?>
<div id="header">
<?php
if ( ! $Event->Id() ) {
echo 'Event was not found.';
} else {
?>
<div id="dataBar">
<table id="dataTable" class="major">
<tr>
<td><span id="dataId" title="<?php echo translate('Id') ?>"><?php echo $Event->Id() ?></span></td>
<td><span id="dataCause" title="<?php echo $Event->Notes()?validHtmlStr($Event->Notes()):translate('AttrCause') ?>"><?php echo validHtmlStr($Event->Cause()) ?></span></td>
<td><span id="dataTime" title="<?php echo translate('Time') ?>"><?php echo strftime( STRF_FMT_DATETIME_SHORT, strtotime($Event->StartTime() ) ) ?></span></td>
<td><span id="dataDuration" title="<?php echo translate('Duration') ?>"><?php echo $Event->Length() ?></span>s</td>
<td><span id="dataFrames" title="<?php echo translate('AttrFrames')."/".translate('AttrAlarmFrames') ?>"><?php echo $Event->Frames() ?>/<?php echo $Event->AlarmFrames() ?></span></td>
<td><span id="dataScore" title="<?php echo translate('AttrTotalScore')."/".translate('AttrAvgScore')."/".translate('AttrMaxScore') ?>"><?php echo $Event->TotScore() ?>/<?php echo $Event->AvgScore() ?>/<?php echo $Event->MaxScore() ?></span></td>
</tr>
</table>
<span id="dataId" title="<?php echo translate('Id') ?>"><?php echo $Event->Id() ?></span>
<span id="dataCause" title="<?php echo $Event->Notes()?validHtmlStr($Event->Notes()):translate('AttrCause') ?>"><?php echo validHtmlStr($Event->Cause()) ?></span>
<span id="dataTime" title="<?php echo translate('Time') ?>"><?php echo strftime( STRF_FMT_DATETIME_SHORT, strtotime($Event->StartTime() ) ) ?></span>
<span id="dataDuration" title="<?php echo translate('Duration') ?>"><?php echo $Event->Length().'s' ?></span>
<span id="dataFrames" title="<?php echo translate('AttrFrames')."/".translate('AttrAlarmFrames') ?>"><?php echo $Event->Frames() ?>/<?php echo $Event->AlarmFrames() ?></span>
<span id="dataScore" title="<?php echo translate('AttrTotalScore')."/".translate('AttrAvgScore')."/".translate('AttrMaxScore') ?>"><?php echo $Event->TotScore() ?>/<?php echo $Event->AvgScore() ?>/<?php echo $Event->MaxScore() ?></span>
<div id="closeWindow"><a href="#" onclick="window.history.back();"><?php echo translate('Back') ?></a></div>
</div>
<div id="menuBar1">
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect( "scale", $scales, "changeScale();" ); ?></div>
<div id="replayControl"><label for="replayMode"><?php echo translate('Replay') ?></label><?php echo buildSelect( "replayMode", $replayModes, "changeReplayMode();" ); ?></div>
<div id="nameControl">
<input type="text" id="eventName" name="eventName" value="<?php echo validHtmlStr($Event->Name()) ?>" />
<input type="button" value="<?php echo translate('Rename') ?>" onclick="renameEvent()"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/>
</div>
</div>
<div id="menuBar2">
<div id="closeWindow"><a href="#" onclick="closeWindow();"><?php echo translate('Close') ?></a></div>
<?php
if ( canEdit('Events') ) {
?>
@ -153,7 +146,11 @@ if ( canEdit('Events') ) {
} // end if Event->DefaultVideo
?>
<div id="exportEvent"><a href="#" onclick="exportEvent();"><?php echo translate('Export') ?></a></div>
<div id="replayControl"><label for="replayMode"><?php echo translate('Replay') ?></label><?php echo buildSelect( "replayMode", $replayModes, "changeReplayMode();" ); ?></div>
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect( "scale", $scales, "changeScale();" ); ?></div>
</div>
</div>
<div id="content">
<div id="eventVideo" class="">
<?php
if ( $video_tag ) {

View File

@ -81,10 +81,6 @@ if ( !empty($page) ) {
$eventsSql .= ' limit 0, '.$limit;
}
$maxWidth = 0;
$maxHeight = 0;
$archived = false;
$unarchived = false;
$maxShortcuts = 5;
$pagination = getPagination( $pages, $page, $maxShortcuts, $filterQuery.$sortQuery.'&amp;limit='.$limit );
@ -95,8 +91,20 @@ xhtmlHeaders(__FILE__, translate('Events') );
?>
<body>
<div id="page">
<?php echo getNavBarHTML() ?>
<div id="header">
<div id="headerButtons">
<div id="info">
<h2><?php echo sprintf( $CLANG['EventCount'], $nEvents, zmVlang( $VLANG['Event'], $nEvents ) ) ?></h2>
<a id="refreshLink" href="#" onclick="location.reload(true);"><?php echo translate('Refresh') ?></a>
</div>
<div id="pagination">
<?php
if ( $pagination ) {
?>
<h2 class="pagination"><?php echo $pagination ?></h2>
<?php
}
?>
<?php
if ( $pages > 1 ) {
if ( !empty($page) ) {
@ -110,9 +118,11 @@ if ( $pages > 1 ) {
}
}
?>
<a href="#" onclick="closeWindows();"><?php echo translate('Close') ?></a>
</div>
<h2><?php echo sprintf( $CLANG['EventCount'], $nEvents, zmVlang( $VLANG['Event'], $nEvents ) ) ?></h2>
<div id="controls">
<a href="#" onclick="window.history.back();"><?php echo translate('Back') ?></a>
<a id="timelineLink" href="?view=timeline<?php echo $filterQuery ?>"><?php echo translate('ShowTimeline') ?></a>
</div>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="">
@ -123,18 +133,6 @@ if ( $pages > 1 ) {
<input type="hidden" name="sort_field" value="<?php echo validHtmlStr($_REQUEST['sort_field']) ?>"/>
<input type="hidden" name="sort_asc" value="<?php echo validHtmlStr($_REQUEST['sort_asc']) ?>"/>
<input type="hidden" name="limit" value="<?php echo $limit ?>"/>
<?php
if ( $pagination ) {
?>
<h3 class="pagination"><?php echo $pagination ?></h3>
<?php
}
?>
<p id="controls">
<a id="refreshLink" href="#" onclick="location.reload(true);"><?php echo translate('Refresh') ?></a>
<a id="filterLink" href="#" onclick="createPopup( '?view=filter&amp;page=<?php echo $page ?><?php echo $filterQuery ?>', 'zmFilter', 'filter' );"><?php echo translate('ShowFilterWindow') ?></a>
<a id="timelineLink" href="#" onclick="createPopup( '?view=timeline<?php echo $filterQuery ?>', 'zmTimeline', 'timeline' );"><?php echo translate('ShowTimeline') ?></a>
</p>
<table id="contentTable" class="major">
<tbody>
<?php
@ -144,11 +142,6 @@ $disk_space_total = 0;
$results = dbQuery( $eventsSql );
while ( $event_row = dbFetchNext( $results ) ) {
$event = new Event( $event_row );
$scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
$eventWidth = reScale( $event_row['Width'], $scale );
$eventHeight = reScale( $event_row['Height'], $scale );
if ( $maxWidth < $eventWidth ) $maxWidth = $eventWidth;
if ( $maxHeight < $eventHeight ) $maxHeight = $eventHeight;
if ( $event_row['Archived'] )
$archived = true;
else
@ -187,8 +180,8 @@ while ( $event_row = dbFetchNext( $results ) ) {
$scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
?>
<tr<?php if ($event->Archived()) echo ' class="archived"' ?>>
<td class="colId"><?php echo makePopupLink( '?view=event&amp;eid='.$event->Id().$filterQuery.$sortQuery.'&amp;page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->Id().($event->Archived()?'*':'') ) ?></td>
<td class="colName"><?php echo makePopupLink( '?view=event&amp;eid='.$event->Id().$filterQuery.$sortQuery.'&amp;page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), reScale( $event->Height(), $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ) ), validHtmlStr($event->Name()).($event->Archived()?'*':'' ) ) ?></td>
<td class="colId"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1"> '.$event->Id().($event->Archived()?'*':'') ?></a></td>
<td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1"> '.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="colTime"><?php echo strftime( STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime()) ) ?></td>
@ -276,6 +269,7 @@ if ( true || canEdit( 'Events' ) ) {
<input type="button" name="unarchiveBtn" value="<?php echo translate('Unarchive') ?>" onclick="unarchiveEvents( this, 'markEids' );" disabled="disabled"/>
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editEvents( this, 'markEids' )" disabled="disabled"/>
<input type="button" name="exportBtn" value="<?php echo translate('Export') ?>" onclick="exportEvents( this, 'markEids' )" disabled="disabled"/>
<input type="button" name="downloadBtn" value="<?php echo translate('DownloadVideo') ?>" onclick="downloadVideo( this, 'markEids' )" disabled="disabled"/>
<input type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteEvents( this, 'markEids' );" disabled="disabled"/>
</div>
<?php
@ -288,8 +282,6 @@ if ( true || canEdit( 'Events' ) ) {
// These are defined in the .js.php but need to be updated down here.
archivedEvents = <?php echo !empty($archived)?'true':'false' ?>;
unarchivedEvents = <?php echo !empty($unarchived)?'true':'false' ?>;
maxWidth = <?php echo $maxWidth?$maxWidth:0 ?>;
maxHeight = <?php echo $maxHeight?$maxHeight:0 ?>;
</script>
</body>
</html>

View File

@ -387,6 +387,10 @@ if ( ZM_OPT_MESSAGE ) {
<label><?php echo translate('FilterDeleteEvents') ?></label>
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( !empty($filter->AutoDelete()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this)"/>
</p>
<p><label><?php echo translate('FilterMoveEvents') ?></label>
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( !empty($filter->AutoMove()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);if(this.checked){$j(this.form.elements['filter[AutoMoveTo]']).css('display','inline');}else{this.form.elements['filter[AutoMoveTo]'].hide();};"/>
<?php echo htmlSelect( "filter[AutoMoveTo]", $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;' ) ); ?>
</p>
<p>
<label for="background"><?php echo translate('BackgroundFilter') ?></label>
<input type="checkbox" id="filter[Background]" name="filter[Background]" value="1"<?php if ( !empty($filter->Background()) ) { ?> checked="checked"<?php } ?>/>

View File

@ -104,7 +104,7 @@ echo htmlSelect( 'newGroup[ParentId]', $options, $newGroup->ParentId(), array('o
<select name="newGroup[MonitorIds][]" size="4" multiple="multiple" onchange="configureButtons(this);">
<?php
$monitors = dbFetchAll( 'SELECT Id,Name FROM Monitors ORDER BY Sequence ASC' );
$monitorIds = array_flip( explode( ',', $newGroup->MonitorIds() ) );
$monitorIds = $newGroup->MonitorIds();
foreach ( $monitors as $monitor ) {
if ( visibleMonitor( $monitor['Id'] ) ) {
?>

View File

@ -0,0 +1,37 @@
function startDownload( exportFile ) {
window.location.replace( exportFile );
}
var exportTimer = null;
function exportProgress() {
var tickerText = $('exportProgressTicker').get('text');
if ( tickerText.length < 1 || tickerText.length > 4 )
$('exportProgressTicker').set( 'text', '.' );
else
$('exportProgressTicker').appendText( '.' );
}
function exportResponse( respObj, respText ) {
window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) );
}
function exportEvent( form ) {
var parms = 'view=request&request=event&action=download';
parms += '&'+$(form).toQueryString();
var query = new Request.JSON( { url: thisUrl, method: 'post', data: parms, onSuccess: exportResponse } );
query.send();
$('exportProgress').removeClass( 'hidden' );
$('exportProgress').setProperty( 'class', 'warnText' );
$('exportProgressText').set( 'text', exportProgressString );
exportProgress();
exportTimer = exportProgress.periodical( 500 );
}
function initPage() {
if ( exportReady ) {
startDownload.pass( exportFile ).delay( 1500 );
}
}
window.addEvent( 'domready', initPage );

View File

@ -0,0 +1,19 @@
<?php
if ( isset($_REQUEST['eids']) ) {
$eidParms = array();
foreach ( $_REQUEST['eids'] as $eid )
$eidParms[] = "eids[]=".validInt($eid);
?>
var eidParm = '<?php echo join( '&', $eidParms ) ?>';
<?php
} else if (isset($_REQUEST['eid'])) {
?>
var eidParm = 'eid=<?php echo validInt($_REQUEST['eid']) ?>';
<?php
}
?>
var exportReady = <?php echo !empty($_REQUEST['generated'])?'true':'false' ?>;
var exportFile = '<?php echo !empty($_REQUEST['exportFile'])?validJsStr($_REQUEST['exportFile']):'' ?>';
var exportProgressString = '<?php echo addslashes(translate('Exporting')) ?>';

View File

@ -812,10 +812,6 @@ function getActResponse( respObj, respText ) {
if ( checkStreamForErrors( "getActResponse", respObj ) )
return;
if ( respObj.refreshParent )
if (refreshParent == false) refreshParent = true; //Bypass filter window redirect fix.
refreshParentWindow();
if ( respObj.refreshEvent )
eventQuery( eventData.Id );
}

View File

@ -15,6 +15,7 @@ function toggleCheckbox( element, name ) {
form.editBtn.disabled = !checked;
form.archiveBtn.disabled = unarchivedEvents?!checked:true;
form.unarchiveBtn.disabled = archivedEvents?!checked:true;
form.downloadBtn.disabled = !checked;
form.exportBtn.disabled = !checked;
form.deleteBtn.disabled = !checked;
}
@ -38,6 +39,7 @@ function configureButton( element, name ) {
form.editBtn.disabled = !checked;
form.archiveBtn.disabled = (!checked)||(!unarchivedEvents);
form.unarchiveBtn.disabled = (!checked)||(!archivedEvents);
form.downloadBtn.disabled = !checked;
form.exportBtn.disabled = !checked;
form.deleteBtn.disabled = !checked;
}
@ -74,6 +76,19 @@ function editEvents( element, name ) {
createPopup( '?view=eventdetail&'+eids.join( '&' ), 'zmEventDetail', 'eventdetail' );
}
function downloadVideo( element, name ) {
var form = element.form;
var eids = new Array();
for (var i = 0; i < form.elements.length; i++) {
if (form.elements[i].name.indexOf(name) == 0) {
if ( form.elements[i].checked ) {
eids[eids.length] = 'eids[]='+form.elements[i].value;
}
}
}
createPopup( '?view=download&'+eids.join( '&' ), 'zmDownload', 'download' );
}
function exportEvents( element, name ) {
var form = element.form;
var eids = new Array();

View File

@ -4,10 +4,7 @@ var openFilterWindow = false;
var archivedEvents = <?php echo !empty($archived)?'true':'false' ?>;
var unarchivedEvents = <?php echo !empty($unarchived)?'true':'false' ?>;
var filterQuery = '<?php echo isset($filterQuery)?validJsStr($filterQuery):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr($sortQuery):'' ?>';
var maxWidth = <?php echo $maxWidth?$maxWidth:0 ?>;
var maxHeight = <?php echo $maxHeight?$maxHeight:0 ?>;
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
var confirmDeleteEventsString = "<?php echo addslashes(translate('ConfirmDeleteEvents')) ?>";

View File

@ -49,7 +49,6 @@ function submitToFilter( element ) {
function submitToEvents( element ) {
var form = element.form;
if ( validateForm( form ) ) {
form.target = 'zmEvents';
form.action = thisUrl + '?view=events';
form.submit();
}
@ -58,7 +57,6 @@ function submitToEvents( element ) {
function executeFilter( element ) {
var form = element.form;
if ( validateForm( form ) ) {
form.target = 'zmEvents';
form.action = thisUrl + '?view=events';
form.elements['action'].value = 'execute';
form.submit();
@ -67,8 +65,6 @@ function executeFilter( element ) {
function saveFilter( element ) {
var form = element.form;
//form.target = 'zmFilter';
form.target = window.name;
form.elements['action'].value = element.value;
form.action = thisUrl + '?view=filter';

View File

@ -1,3 +1,6 @@
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
var deleteSavedFilterString = "<?php echo translate('DeleteSavedFilter') ?>";
function validateForm( form ) {
<?php

View File

@ -335,6 +335,7 @@ function redrawScreen() {
$('zoomout').style.display="none";
$('panleft').style.display="none";
$('panright').style.display="none";
$('downloadVideo').style.display="none";
} else {
// switch out of liveview mode
@ -351,6 +352,7 @@ function redrawScreen() {
$('panleft').style.display="inline-flex";
$('panright').style.display="inline";
$('panright').style.display="inline-flex";
$('downloadVideo').style.display="inline";
}
if ( fitMode == 1 ) {
@ -553,6 +555,9 @@ function click_panright() {
maxTimeSecs = minTimeSecs + rangeTimeSecs - 1;
clicknav(minTimeSecs,maxTimeSecs,0);
}
function click_download() {
createPopup( '?view=download'+filterQuery, 'zmDownload', 'download' );
}
function click_all_events() {
clicknav(0,0,0);
}

View File

@ -1,4 +1,6 @@
var filterQuery = '<?php echo isset($filterQuery)?htmlspecialchars_decode($filterQuery):'' ?>';
var server_utc_offset = <?php
$TimeZone = new DateTimeZone( ini_get('date.timezone') );
$now = new DateTime('now', $TimeZone);

View File

@ -3,8 +3,7 @@ var events = {};
function showEvent( eid, fid, width, height ) {
var url = '?view=event&eid='+eid+'&fid='+fid;
url += filterQuery;
var pop=createPopup( url, 'zmEvent', 'event', width, height );
pop.vid=$('preview');
window.location.href = url;
//video element is blocking video elements elsewhere in chrome possible interaction with mouseover event?
//FIXME unless an exact cause can be determined should store all video controls and do something to the other controls when we want to load a new video seek etc or whatever may block
@ -144,13 +143,13 @@ function loadEventImage( imagePath, eid, fid, width, height, fps, videoName, dur
function tlZoomBounds( minTime, maxTime ) {
console.log( "Zooming" );
window.location = '?view='+currentView+filterQuery+'&minTime='+minTime+'&maxTime='+maxTime;
location.replace('?view='+currentView+filterQuery+'&minTime='+minTime+'&maxTime='+maxTime);
}
function tlZoomRange( midTime, range ) {
window.location = '?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range;
location.replace('?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range);
}
function tlPan( midTime, range ) {
window.location = '?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range;
location.replace('?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range);
}

View File

@ -59,6 +59,19 @@ include('_monitor_filters.php');
$filter_bar = ob_get_contents();
ob_end_clean();
if (isset($_REQUEST['minTime']) || isset($_REQUEST['maxTime'])) {
$filter = array(
'Query' => array(
'terms' => array(
array('attr' => 'StartDateTime', 'op' => '>=', 'val' => $_REQUEST['minTime']),
array('attr' => 'StartDateTime', 'op' => '<=', 'val' => $_REQUEST['maxTime'], 'cnj' => 'and'),
)
),
);
parseFilter( $filter );
$filterQuery = $filter['query'];
}
// Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame
// if the bulk record has not been written - to be able to include more current frames reduce bulk frame sizes (event size can be large)
// Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly.
@ -211,6 +224,7 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
<button type="button" id="live" onclick="setLive(1-liveMode);"><?php echo translate('Live') ?></button>
<button type="button" id="fit" onclick="setFit(1-fitMode);" ><?php echo translate('Fit') ?></button>
<button type="button" id="panright" onclick="click_panright();" ><?php echo translate('Pan') ?> &gt;</button>
<button type="button" id="downloadVideo" onclick="click_download();" ><?php echo translate('Download Video') ?></button>
</div>
<div id="timelinediv">
<canvas id="timeline" onmousemove="mmove(event);" ontouchmove="tmove(event);" onmousedown="mdown(event);" onmouseup="mup(event);" onmouseout="mout(event);"></canvas>

View File

@ -700,12 +700,16 @@ xhtmlHeaders(__FILE__, translate('Timeline') );
?>
<body>
<div id="page">
<?php echo getNavBarHTML() ?>
<div id="header">
<div id="headerButtons">
<?php echo makePopupLink( '?view=events&amp;page=1'.htmlspecialchars($filterQuery), 'zmEvents', 'events', translate('List'), canView( 'Events' ) ) ?>
<a href="#" onclick="closeWindow();"><?php echo translate('Close') ?></a>
</div>
<div id="info">
<h2><?php echo translate('Timeline') ?></h2>
<a id="refreshLink" href="#" onclick="location.reload(true);"><?php echo translate('Refresh') ?></a>
</div>
<div id="headerButtons">
<a href="#" onclick="window.history.back();"><?php echo translate('Back') ?></a>
<a href="?view=events&amp;page=1<?php echo htmlspecialchars($filterQuery) ?>"><?php echo translate('List') ?></a>
</div>
</div>
<div id="content" class="chartSize">
<div id="topPanel" class="graphWidth">

View File

@ -61,14 +61,9 @@ xhtmlHeaders( __FILE__, $monitor->Name()." - ".translate('Feed') );
?>
<body>
<div id="page">
<div id="content">
<div id="menuBar">
<?php echo getNavBarHTML() ?>
<div id="header">
<div id="monitorName"><?php echo $monitor->Name() ?></div>
<script type="text/javascript">
if ( window.opener ) {
document.write('<div id="closeControl"><a href="#" onclick="closeWindow(); return( false );"><?php echo translate('Close') ?></a></div>');
}
</script>
<div id="menuControls">
<?php
if ( canView( 'Control' ) && $monitor->Type() == 'Local' ) {
@ -79,7 +74,9 @@ if ( canView( 'Control' ) && $monitor->Type() == 'Local' ) {
?>
<div id="scaleControl"><?php echo translate('Scale') ?>: <?php echo buildSelect( "scale", $scales, "changeScale( this );" ); ?></div>
</div>
<div id="closeControl"><a href="#" onclick="window.history.back()"><?php echo translate('Back') ?></a></div>
</div>
<div id="content">
<div id="imageFeed"><?php echo getStreamHTML( $monitor, array('scale'=>$scale) ); ?></div>
<div id="monitorStatus">
<?php if ( canEdit( 'Monitors' ) ) { ?>

View File

@ -47,6 +47,7 @@ if ( $archivetype ) {
if ( is_readable($filename_path) ) {
header( "Content-type: application/$mimetype" );
header( "Content-Disposition: attachment; filename=$filename");
set_time_limit(0);
readfile( $filename_path );
} else {
Error("$filename_path does not exist or is not readable.");