Merge branch 'master' into storageareas

This commit is contained in:
Isaac Connor 2019-08-07 11:21:19 -04:00
commit d4b59211cd
18 changed files with 643 additions and 431 deletions

View File

@ -186,6 +186,7 @@ CREATE TABLE `Events` (
`Id` bigint unsigned NOT NULL auto_increment,
`MonitorId` int(10) unsigned NOT NULL default '0',
`StorageId` smallint(5) unsigned default 0,
`SecondaryStorageId` smallint(5) unsigned default 0,
`Name` varchar(64) NOT NULL default '',
`Cause` varchar(32) NOT NULL default '',
`StartTime` datetime default NULL,

51
db/zm_update-1.33.14.sql Normal file
View File

@ -0,0 +1,51 @@
--
-- Add CopyTo action to Filters
--
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'AutoCopy'
) > 0,
"SELECT 'Column AutoCopy already exists in Filters'",
"ALTER TABLE Filters ADD `AutoCopy` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoMove`"
));
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 = 'AutoCopyTo'
) > 0,
"SELECT 'Column AutoCopyTo already exists in Filters'",
"ALTER TABLE Filters ADD `AutoCopyTo` smallint(5) unsigned NOT NULL default '0' AFTER `AutoCopy`"
));
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 = 'Query_json'
) > 0,
"SELECT 'Column Query_json already exists in Filters'",
"ALTER TABLE `Filters` Change `Query` `Query_json` text NOT NULL"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Events'
AND column_name = 'SecondaryStorageId'
) > 0,
"SELECT 'Column SecondaryStorageId already exists in Events'",
"ALTER TABLE `Events` ADD `SecondaryStorageId` smallint(5) unsigned default 0 AFTER `StorageId`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -189,11 +189,17 @@ Add the following to the bottom of the file
::
# Backports repository
deb http://httpredir.debian.org/debian jessie-backports main contrib non-free
deb http://archive.debian.org/debian/ jessie-backports main contrib non-free
CTRL+o and <Enter> to save
CTRL+x to exit
Run the following
::
echo 'Acquire::Check-Valid-Until no;' > /etc/apt/apt.conf.d/99no-check-valid-until
**Step 5:** Install ZoneMinder
::

View File

@ -41,6 +41,7 @@ require Number::Bytes::Human;
require Date::Parse;
require POSIX;
use Date::Format qw(time2str);
use Time::HiRes qw(gettimeofday tv_interval);
#our @ISA = qw(ZoneMinder::Object);
use parent qw(ZoneMinder::Object);
@ -63,6 +64,7 @@ $serial = $primary_key = 'Id';
Id
MonitorId
StorageId
SecondaryStorageId
Name
Cause
StartTime
@ -163,7 +165,8 @@ sub RelativePath {
if ( $event->Time() ) {
$$event{RelativePath} = join('/',
$event->{MonitorId},
POSIX::strftime( '%y/%m/%d/%H/%M/%S',
POSIX::strftime(
'%y/%m/%d/%H/%M/%S',
localtime($event->Time())
),
);
@ -203,7 +206,8 @@ sub LinkPath {
if ( $event->Time() ) {
$$event{LinkPath} = join('/',
$event->{MonitorId},
POSIX::strftime( '%y/%m/%d',
POSIX::strftime(
'%y/%m/%d',
localtime($event->Time())
),
'.'.$$event{Id}
@ -282,10 +286,10 @@ sub GenerateVideo {
$file_scale =~ s/_00//;
$file_scale =~ s/(_\d+)0+$/$1/;
$file_scale = 's'.$file_scale;
push( @file_parts, $file_scale );
push @file_parts, $file_scale;
} elsif ( $size ) {
my $file_size = 'S'.$size;
push( @file_parts, $file_size );
push @file_parts, $file_size;
}
my $video_file = join('-', $video_name, $file_parts[0], $file_parts[1] ).'.'.$format;
if ( $overwrite || !-s $video_file ) {
@ -393,7 +397,11 @@ sub delete {
sub delete_files {
my $event = shift;
my $Storage = @_ ? $_[0] : new ZoneMinder::Storage($$event{StorageId});
foreach my $Storage (
@_ ? ($_[0]) : (
new ZoneMinder::Storage($$event{StorageId}),
( $$event{SecondaryStorageId} ? new ZoneMinder::Storage($$event{SecondaryStorageId}) : () ),
) ) {
my $storage_path = $Storage->Path();
if ( ! $storage_path ) {
@ -438,7 +446,7 @@ sub delete_files {
my $command = "/bin/rm -rf $storage_path/$event_path";
ZoneMinder::General::executeShellCommand($command);
}
}
} # end if event_path
if ( $event->Scheme() eq 'Deep' ) {
my $link_path = $event->LinkPath();
@ -447,7 +455,8 @@ sub delete_files {
( $link_path ) = ( $link_path =~ /^(.*)$/ ); # De-taint
unlink($storage_path.'/'.$link_path) or Error("Unable to unlink '$storage_path/$link_path': $!");
}
}
} # end if Scheme eq Deep
} # end foreach Storage
} # end sub delete_files
sub StorageId {
@ -519,7 +528,7 @@ sub DiskSpace {
return $_[0]{DiskSpace};
}
sub MoveTo {
sub CopyTo {
my ( $self, $NewStorage ) = @_;
my $OldStorage = $self->Storage(undef);
@ -531,9 +540,9 @@ sub MoveTo {
# We do this before bothering to lock the event
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) {
return "New storage does not have an id. Moving will not happen.";
return 'New storage does not have an id. Moving will not happen.';
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
return "Event is already located at " . $NewPath;
return 'Event is already located at ' . $NewPath;
} elsif ( !$NewPath ) {
return "New path ($NewPath) is empty.";
} elsif ( ! -e $NewPath ) {
@ -545,7 +554,7 @@ sub MoveTo {
# data is reloaded, so need to check that the move hasn't already happened.
if ( $$self{StorageId} == $$NewStorage{Id} ) {
$ZoneMinder::Database::dbh->commit();
return "Event has already been moved by someone else.";
return 'Event has already been moved by someone else.';
}
if ( $$OldStorage{Id} != $$self{StorageId} ) {
@ -559,7 +568,7 @@ sub MoveTo {
$ZoneMinder::Database::dbh->commit();
return "New path and old path are the same! $NewPath";
}
Debug("Moving event $$self{Id} from $OldPath to $NewPath");
Debug("Copying event $$self{Id} from $OldPath to $NewPath");
my $moved = 0;
@ -580,7 +589,7 @@ sub MoveTo {
}
my $event_path = 'events/'.$self->RelativePath();
Info("Making dir ectory $event_path/");
Debug("Making directory $event_path/");
if ( ! $bucket->add_key( $event_path.'/','' ) ) {
die "Unable to add key for $event_path/";
}
@ -590,7 +599,7 @@ Debug("Files to move @files");
for my $file (@files) {
next if $file =~ /^\./;
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
my $starttime = time;
my $starttime = [gettimeofday];
Debug("Moving file $file to $NewPath");
my $size = -s $file;
if ( ! $size ) {
@ -605,7 +614,7 @@ Debug("Files to move @files");
if ( ! $bucket->add_key($filename, $file_contents) ) {
die "Unable to add key for $filename";
}
my $duration = time - $starttime;
my $duration = tv_interval($starttime);
Debug('PUT to S3 ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($duration?$size/$duration:$size) . '/sec');
} # end foreach file.
@ -636,21 +645,21 @@ Debug("Files to move @files");
my @files = glob("$OldPath/*");
if ( ! @files ) {
$ZoneMinder::Database::dbh->commit();
return "No files to move.";
return 'No files to move.';
}
for my $file (@files) {
next if $file =~ /^\./;
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
my $starttime = time;
my $starttime = [gettimeofday];
Debug("Moving file $file to $NewPath");
my $size = -s $file;
if ( ! File::Copy::copy( $file, $NewPath ) ) {
$error .= "Copy failed: for $file to $NewPath: $!";
last;
}
my $duration = time - $starttime;
Debug("Copied " . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . ($duration?Number::Bytes::Human::format_bytes($size/$duration):'inf') . "/sec");
my $duration = tv_interval($starttime);
Debug('Copied ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . ($duration?Number::Bytes::Human::format_bytes($size/$duration):'inf') . '/sec');
} # end foreach file.
} # end if ! moved
@ -658,6 +667,15 @@ Debug("Files to move @files");
$ZoneMinder::Database::dbh->commit();
return $error;
}
} # end sub CopyTo
sub MoveTo {
my ( $self, $NewStorage ) = @_;
my $OldStorage = $self->Storage(undef);
my $error = $self->CopyTo($NewStorage);
return $error if $error;
# Succeeded in copying all files, so we may now update the Event.
$$self{StorageId} = $$NewStorage{Id};
@ -667,10 +685,8 @@ Debug("Files to move @files");
$ZoneMinder::Database::dbh->commit();
return $error;
}
Debug("Committing");
$ZoneMinder::Database::dbh->commit();
$self->delete_files($OldStorage);
Debug("Done deleting files, returning");
return $error;
} # end sub MoveTo

View File

@ -132,11 +132,13 @@ sub Sql {
my $self = shift;
$$self{Sql} = shift if @_;
if ( ! $$self{Sql} ) {
if ( !$self->{Query} ) {
Warning('No Query in filter.');
$self->{Sql} = '';
if ( ! $self->{Query_json} ) {
Warning("No query in Filter!");
return;
}
my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query});
my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query_json});
my $sql = 'SELECT E.*,
unix_timestamp(E.StartTime) as Time,
M.Name as MonitorName,
@ -146,7 +148,6 @@ sub Sql {
INNER JOIN Monitors as M on M.Id = E.MonitorId
LEFT JOIN Storage as S on S.Id = E.StorageId
';
$self->{Sql} = '';
if ( $filter_expr->{terms} ) {
foreach my $term ( @{$filter_expr->{terms}} ) {

View File

@ -46,56 +46,13 @@ use ZoneMinder::Database qw(:all);
use POSIX;
use vars qw/ $table $primary_key /;
use vars qw/ $table $primary_key %fields/;
$table = 'Storage';
$primary_key = 'Id';
#__PACKAGE__->table('Storage');
#__PACKAGE__->primary_key('Id');
%fields = map { $_ => $_ } qw( Id Name Path DoDelete ServerId Type Url DiskSpace Scheme );
sub find {
shift if $_[0] eq 'ZoneMinder::Storage';
my %sql_filters = @_;
my $sql = 'SELECT * FROM Storage';
my @sql_filters;
my @sql_values;
if ( exists $sql_filters{Id} ) {
push @sql_filters , ' Id=? ';
push @sql_values, $sql_filters{Id};
}
if ( exists $sql_filters{Name} ) {
push @sql_filters , ' Name = ? ';
push @sql_values, $sql_filters{Name};
}
if ( exists $sql_filters{ServerId} ) {
push @sql_filters, ' ServerId = ?';
push @sql_values, $sql_filters{ServerId};
}
$sql .= ' WHERE ' . join(' AND ', @sql_filters) if @sql_filters;
$sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit};
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
my $res = $sth->execute( @sql_values )
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
my @results;
while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Storage( $$db_filter{Id}, $db_filter );
push @results, $filter;
} # end while
Debug("SQL: $sql returned " . @results . ' results');
return @results;
}
sub find_one {
my @results = find(@_);
return $results[0] if @results;
}
sub Path {
if ( @_ > 1 ) {

View File

@ -240,6 +240,7 @@ sub getFilters {
or AutoDelete = 1
or UpdateDiskSpace = 1
or AutoMove = 1
or AutoCopy = 1
) ORDER BY Name';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
@ -283,6 +284,7 @@ sub checkFilter {
($filter->{AutoMessage}?'message':()),
($filter->{AutoExecute}?'execute':()),
($filter->{AutoMove}?'move':()),
($filter->{AutoCopy}?'copy':()),
($filter->{UpdateDiskSpace}?'update disk space':()),
),
'returned' , scalar @Events , 'events',
@ -343,6 +345,23 @@ sub checkFilter {
$_ = $Event->MoveTo($NewStorage);
Error($_) if $_;
}
if ( $filter->{AutoCopy} ) {
# Copy To is different from MoveTo in that it JUST copies the files
# So we still need to update the Event object with the new SecondaryStorageId
my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoCopyTo});
if ( $NewStorage ) {
$_ = $Event->CopyTo($NewStorage);
if ( $_ ) {
$ZoneMinder::Database::dbh->commit();
Error($_);
} else {
$Event->save({SecondaryStorageId=>$$NewStorage{Id}});
$ZoneMinder::Database::dbh->commit();
}
} else {
Error("No storage area found for copy to operation. AutoCopyTo was $$filter{AutoCopyTo}");
}
} # end if AutoCopy
if ( $filter->{UpdateDiskSpace} ) {
$ZoneMinder::Database::dbh->begin_work();
@ -361,7 +380,7 @@ sub checkFilter {
$ZoneMinder::Database::dbh->commit();
} # end if UpdateDiskSpace
} # end foreach event
}
} # end sub checkFilter
sub generateVideo {
my $filter = shift;
@ -623,7 +642,7 @@ sub substituteTags {
my $Monitor = $Event->Monitor() if $need_monitor;
# Do we need the image information too?
my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA)%/;
my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA|EIMOD)%/;
my $first_alarm_frame;
my $max_alarm_frame;
my $max_alarm_score = 0;

View File

@ -1 +1 @@
1.33.13
1.33.14

View File

@ -12,6 +12,7 @@ class Event {
'Name',
'MonitorId',
'StorageId',
'SecondaryStorageId',
'Name',
'Cause',
'StartTime',
@ -85,6 +86,19 @@ class Event {
return $this->{'Storage'};
}
public function SecondaryStorage( $new = null ) {
if ( $new ) {
$this->{'SecondaryStorage'} = $new;
}
if ( ! ( array_key_exists('SecondaryStorage', $this) and $this->{'SecondaryStorage'} ) ) {
if ( isset($this->{'SecondaryStorageId'}) and $this->{'SecondaryStorageId'} )
$this->{'SecondaryStorage'} = Storage::find_one(array('Id'=>$this->{'SecondaryStorageId'}));
if ( ! ( array_key_exists('SecondaryStorage', $this) and $this->{'SecondaryStorage'} ) )
$this->{'SecondaryStorage'} = new Storage(NULL);
}
return $this->{'SecondaryStorage'};
}
public function Monitor() {
if ( isset($this->{'MonitorId'}) ) {
$Monitor = Monitor::find_one(array('Id'=>$this->{'MonitorId'}));

View File

@ -1,9 +1,11 @@
<?php
namespace ZM;
require_once('Object.php');
class Filter {
class Filter extends ZM_Object {
protected static $table = 'Filters';
public $defaults = array(
protected $defaults = array(
'Id' => null,
'Name' => '',
'AutoExecute' => 0,
@ -16,68 +18,55 @@ public $defaults = array(
'AutoMessage' => 0,
'AutoMove' => 0,
'AutoMoveTo' => 0,
'AutoCopy' => 0,
'AutoCopyTo' => 0,
'UpdateDiskSpace' => 0,
'Background' => 0,
'Concurrent' => 0,
'limit' => 100,
'Query' => array(),
'sort_field' => ZM_WEB_EVENT_SORT_FIELD,
'sort_asc' => ZM_WEB_EVENT_SORT_ORDER,
'Query_json' => '',
);
public function __construct( $IdOrRow=NULL ) {
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
$row = dbFetchOne('SELECT * FROM Filters WHERE Id=?', NULL, array($IdOrRow));
if ( ! $row ) {
Error('Unable to load Filter record for Id=' . $IdOrRow);
public function Query_json() {
if ( func_num_args( ) ) {
$this->{'Query_json'} = func_get_arg(0);;
$this->{'Query'} = jsonDecode($this->{'Query_json'});
}
} elseif ( is_array($IdOrRow) ) {
$row = $IdOrRow;
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Unknown argument passed to Filter Constructor from $file:$line)");
Error("Unknown argument passed to Filter Constructor ($IdOrRow)");
return;
return $this->{'Query_json'};
}
} # end if isset($IdOrRow)
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
public function Query() {
if ( func_num_args( ) ) {
$this->{'Query'} = func_get_arg(0);;
$this->{'Query_json'} = jsonEncode($this->{'Query'});
}
if ( array_key_exists('Query', $this) and $this->{'Query'} ) {
$this->{'Query'} = jsonDecode($this->{'Query'});
if ( !array_key_exists('Query', $this) ) {
if ( array_key_exists('Query_json', $this) and $this->{'Query_json'} ) {
$this->{'Query'} = jsonDecode($this->{'Query_json'});
} else {
$this->{'Query'} = array();
}
}
} // end function __construct
public function __call( $fn, array $args ) {
if ( count( $args ) ) {
$this->{$fn} = $args[0];
}
if ( array_key_exists( $fn, $this ) ) {
return $this->{$fn};
} else if ( array_key_exists( $fn, $this->defaults ) ) {
$this->{$fn} = $this->defaults{$fn};
return $this->{$fn};
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Warning( "Unknown function call Filter->$fn from $file:$line" );
if ( !is_array($this->{'Query'}) ) {
# Handle existence of both Query_json and Query in the row
$this->{'Query'} = jsonDecode($this->{'Query_json'});
}
}
return $this->{'Query'};
}
public static function find( $parameters = array(), $options = array() ) {
return ZM_Object::_find(get_class(), $parameters, $options);
}
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
public function terms( ) {
if ( func_num_args() ) {
$this->Query()['terms'] = func_get_arg(0);
$Query = $this->Query();
$Query['terms'] = func_get_arg(0);
$this->Query($Query);
}
if ( isset( $this->Query()['terms'] ) ) {
return $this->Query()['terms'];
@ -88,106 +77,42 @@ public $defaults = array(
// The following three fields are actually stored in the Query
public function sort_field( ) {
if ( func_num_args( ) ) {
$this->Query()['sort_field'] = func_get_arg(0);
$Query = $this->Query();
$Query['sort_field'] = func_get_arg(0);
$this->Query($Query);
}
if ( isset( $this->Query()['sort_field'] ) ) {
return $this->{'Query'}['sort_field'];
}
return $this->defaults{'sort_field'};
return ZM_WEB_EVENT_SORT_FIELD;
#return $this->defaults{'sort_field'};
}
public function sort_asc( ) {
if ( func_num_args( ) ) {
$this->{'Query'}['sort_asc'] = func_get_arg(0);
$Query = $this->Query();
$Query['sort_asc'] = func_get_arg(0);
$this->Query($Query);
}
if ( isset( $this->Query()['sort_asc'] ) ) {
return $this->{'Query'}['sort_asc'];
}
return $this->defaults{'sort_asc'};
return ZM_WEB_EVENT_SORT_ORDER;
#return $this->defaults{'sort_asc'};
}
public function limit( ) {
if ( func_num_args( ) ) {
$this->{'Query'}['limit'] = func_get_arg(0);
$Query = $this->Query();
$Query['limit'] = func_get_arg(0);
$this->Query($Query);
}
if ( isset( $this->Query()['limit'] ) )
return $this->{'Query'}['limit'];
return $this->defaults{'limit'};
return 100;
#return $this->defaults{'limit'};
}
public static function find( $parameters = null, $options = null ) {
$filters = array();
$sql = 'SELECT * FROM Filters ';
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = $field.' IS NULL';
} else if ( is_array( $value ) ) {
$func = function(){return '?';};
$fields[] = $field.' IN ('.implode(',', array_map($func, $value)). ')';
$values += $value;
} else {
$fields[] = $field.'=?';
$values[] = $value;
}
}
$sql .= implode(' AND ', $fields);
}
if ( $options ) {
if ( isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $options['limit'];
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Invalid value for limit(".$options['limit'].") passed to Filter::find from $file:$line");
return array();
}
}
}
$result = dbQuery($sql, $values);
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Filter');
foreach ( $results as $row => $obj ) {
$filters[] = $obj;
}
return $filters;
} # end find()
public static function find_one( $parameters = array() ) {
$results = Filter::find($parameters, array('limit'=>1));
if ( ! sizeof($results) ) {
return;
}
return $results[0];
} # end find_one()
public function delete() {
dbQuery('DELETE FROM Filters WHERE Id=?', array($this->{'Id'}));
} # end function delete()
public function set( $data ) {
foreach ($data as $k => $v) {
if ( is_array( $v ) ) {
$this->{$k} = $v;
} else if ( is_string( $v ) ) {
$this->{$k} = trim( $v );
} else if ( is_integer( $v ) ) {
$this->{$k} = $v;
} else if ( is_bool( $v ) ) {
$this->{$k} = $v;
} else {
Error( "Unknown type $k => $v of var " . gettype( $v ) );
$this->{$k} = $v;
}
}
} # end function set
public function control($command, $server_id=null) {
$Servers = $server_id ? Server::find(array('Id'=>$server_id)) : Server::find();
if ( !count($Servers) and !$server_id ) {

254
web/includes/Object.php Normal file
View File

@ -0,0 +1,254 @@
<?php
namespace ZM;
require_once('database.php');
$object_cache = array();
class ZM_Object {
public function __construct($IdOrRow = NULL) {
$class = get_class($this);
global $object_cache;
if ( ! isset($object_cache[$class]) )
$object_cache[$class] = array();
$cache = $object_cache[$class];
$table = $class::$table;
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer($IdOrRow) or ctype_digit($IdOrRow) ) {
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($IdOrRow));
if ( !$row ) {
Error("Unable to load $class record for Id=$IdOrRow");
}
} elseif ( is_array($IdOrRow) ) {
$row = $IdOrRow;
}
} # end if isset($IdOrRow)
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
$cache[$row['Id']] = $this;
} else {
# Set defaults
foreach ( $this->defaults as $k => $v ) $this->{$k} = $v;
}
}
public function __call($fn, array $args){
if ( count($args) ) {
$this->{$fn} = $args[0];
}
if ( array_key_exists($fn, $this) ) {
return $this->{$fn};
} else {
if ( array_key_exists($fn, $this->defaults) ) {
return $this->defaults{$fn};
} else {
$backTrace = debug_backtrace();
Warning("Unknown function call Sensor->$fn from ".print_r($backTrace,true));
}
}
}
public static function _find($class, $parameters = null, $options = null ) {
$table = $class::$table;
$filters = array();
$sql = "SELECT * FROM `$table` ";
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = '`'.$field.'` IS NULL';
} else if ( is_array($value) ) {
$func = function(){return '?';};
$fields[] = '`'.$field.'` IN ('.implode(',', array_map($func, $value)). ')';
$values += $value;
} else {
$fields[] = '`'.$field.'`=?';
$values[] = $value;
}
}
$sql .= implode(' AND ', $fields );
}
if ( $options ) {
if ( isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $options['limit'];
} else {
Error('Invalid value for limit('.$options['limit'].') passed to '.get_class()."::find from ".print_r($backTrace,true));
return array();
}
}
}
$rows = dbFetchAll($sql, NULL, $values);
$results = array();
if ( $rows ) {
foreach ( $rows as $row ) {
array_push($results , new $class($row));
}
}
return $results;
} # end public function find()
public static function _find_one($class, $parameters = array(), $options = array() ) {
global $object_cache;
if ( ! isset($object_cache[$class]) )
$object_cache[$class] = array();
$cache = $object_cache[$class];
if (
( count($parameters) == 1 ) and
isset($parameters['Id']) and
isset($cache[$parameters['Id']]) ) {
return $cache[$parameters['Id']];
}
$options['limit'] = 1;
$results = ZM_Object::_find($class, $parameters, $options);
if ( ! sizeof($results) ) {
return;
}
return $results[0];
}
public static function Objects_Indexed_By_Id($class) {
$results = array();
foreach ( ZM_Object::_find($class, null, array('order'=>'lower(Name)')) as $Object ) {
$results[$Object->Id()] = $Object;
}
return $results;
}
public function to_json() {
$json = array();
foreach ($this->defaults as $key => $value) {
if ( is_callable(array($this, $key)) ) {
$json[$key] = $this->$key();
} else if ( array_key_exists($key, $this) ) {
$json[$key] = $this->{$key};
} else {
$json[$key] = $this->defaults{$key};
}
}
return json_encode($json);
}
public function set($data) {
foreach ( $data as $k => $v ) {
if ( method_exists($this, $k) ) {
$this->{$k}($v);
} else {
if ( is_array($v) ) {
# perhaps should turn into a comma-separated string
$this->{$k} = implode(',', $v);
} else if ( is_string($v) ) {
if ( $v == '' and array_key_exists($k, $this->defaults) ) {
$this->{$k} = $this->defaults[$k];
} else {
$this->{$k} = trim($v);
}
} else if ( is_integer($v) ) {
$this->{$k} = $v;
} else if ( is_bool($v) ) {
$this->{$k} = $v;
} else if ( is_null($v) ) {
$this->{$k} = $v;
} else {
Error( "Unknown type $k => $v of var " . gettype( $v ) );
$this->{$k} = $v;
}
} # end if method_exists
} # end foreach $data as $k=>$v
}
public function changes( $new_values ) {
$changes = array();
foreach ( $new_values as $field => $value ) {
if ( method_exists($this, $field) ) {
$old_value = $this->$field();
Logger::Debug("Checking method $field () ".print_r($old_value,true)." => " . print_r($value,true));
if ( is_array($old_value) ) {
$diff = array_recursive_diff($old_value, $value);
Logger::Debug("Checking method $field () diff is".print_r($diff,true));
if ( count($diff) ) {
$changes[$field] = $value;
}
} else if ( $this->$field() != $value ) {
$changes[$field] = $value;
}
} else if ( array_key_exists($field, $this) ) {
Logger::Debug("Checking field $field => ".$this->{$field} . " ?= " .$value);
if ( $this->{$field} != $value ) {
$changes[$field] = $value;
}
} else if ( array_key_exists($field, $this->defaults) ) {
Logger::Debug("Checking default $field => ".$this->defaults[$field] . " " .$value);
if ( $this->defaults[$field] != $value ) {
$changes[$field] = $value;
}
}
#if ( (!array_key_exists($field, $this)) or ( $this->{$field} != $new_values[$field] ) ) {
#Logger::Debug("Checking default $field => $default_value changes becaause" . $new_values[$field].' != '.$new_values[$field]);
#$changes[$field] = $new_values[$field];
##} else if {
#Logger::Debug("Checking default $field => $default_value changes becaause " . $new_values[$field].' != '.$new_values[$field]);
##array_push( $changes, [$field=>$defaults[$field]] );
#}
#} else {
#Logger::Debug("Checking default $field => $default_value not in new_values");
#}
} # end foreach default
return $changes;
} # end public function changes
public function save($new_values = null) {
$class = get_class($this);
$table = $class::$table;
if ( $new_values ) {
Logger::Debug("New values" . print_r($new_values,true));
$this->set($new_values);
}
if ( $this->Id() ) {
$fields = array_keys($this->defaults);
$sql = 'UPDATE '.$table.' SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields )) . ' WHERE Id=?';
$values = array_map(function($field){return $this->{$field};}, $fields);
$values[] = $this->{'Id'};
if ( dbQuery($sql, $values) )
return true;
} else {
$fields = $this->defaults;
unset($fields['Id']);
$sql = 'INSERT INTO '.$table.' ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, array_keys($fields))).') VALUES ('.implode(', ', array_map(function($field){return '?';}, array_values($fields))).')';
$values = array_map(function($field){return $this->{$field};}, array_keys($fields));
if ( dbQuery($sql, $values) ) {
$this->{'Id'} = dbInsertId();
return true;
}
}
return false;
} // end function save
public function delete() {
$class = get_class($this);
$table = $class::$table;
dbQuery("DELETE FROM $table WHERE Id=?", array($this->{'Id'}));
if ( isset($object_cache[$class]) and isset($object_cache[$class][$this->{'Id'}]) )
unset($object_cache[$class][$this->{'Id'}]);
}
} # end class Sensor Action
?>

View File

@ -2,10 +2,11 @@
namespace ZM;
require_once('database.php');
require_once('Event.php');
require_once('Object.php');
$storage_cache = array();
class Storage {
private $defaults = array(
class Storage extends ZM_Object {
protected static $table = 'Storage';
protected $defaults = array(
'Id' => null,
'Path' => '',
'Name' => '',
@ -16,31 +17,12 @@ class Storage {
'ServerId' => 0,
'DoDelete' => 1,
);
public static function find($parameters = array(), $options = array() ) {
return ZM_Object::_find(get_class(), $parameters, $options);
}
public function __construct( $IdOrRow = NULL ) {
global $storage_cache;
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
$row = dbFetchOne('SELECT * FROM Storage WHERE Id=?', NULL, array($IdOrRow));
if ( ! $row ) {
Error('Unable to load Storage record for Id=' . $IdOrRow);
}
} else if ( is_array($IdOrRow) ) {
$row = $IdOrRow;
}
}
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
$storage_cache[$row['Id']] = $this;
} else {
$this->{'Name'} = '';
$this->{'Path'} = '';
$this->{'Type'} = 'local';
}
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
public function Path() {
@ -66,93 +48,6 @@ class Storage {
return $this->{'Name'};
}
public function __call( $fn, array $args= NULL ) {
if ( count($args) ) {
$this->{$fn} = $args[0];
}
if ( array_key_exists($fn, $this) )
return $this->{$fn};
if ( array_key_exists($fn, $this->defaults) )
return $this->defaults{$fn};
$backTrace = debug_backtrace();
$file = $backTrace[0]['file'];
$line = $backTrace[0]['line'];
Warning("Unknown function call Storage->$fn from $file:$line");
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Warning("Unknown function call Storage->$fn from $file:$line");
}
public static function find_one( $parameters = null, $options = null ) {
global $storage_cache;
if (
( count($parameters) == 1 ) and
isset($parameters['Id']) and
isset($storage_cache[$parameters['Id']]) ) {
return $storage_cache[$parameters['Id']];
}
$results = Storage::find($parameters, $options);
if ( count($results) > 1 ) {
Error('Storage Returned more than 1');
return $results[0];
} else if ( count($results) ) {
return $results[0];
} else {
return null;
}
}
public static function find( $parameters = null, $options = null ) {
$sql = 'SELECT * FROM Storage ';
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = $field.' IS NULL';
} else if ( is_array($value) ) {
$func = function(){return '?';};
$fields[] = $field.' IN ('.implode(',', array_map($func, $value)).')';
$values += $value;
} else {
$fields[] = $field.'=?';
$values[] = $value;
}
}
$sql .= implode(' AND ', $fields);
} # end if parameters
if ( $options ) {
if ( isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
} # end if options
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $option['limit'];
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Invalid value for limit(".$options['limit'].") passed to Control::find from $file:$line");
return array();
}
} # end if limit
} # end if options
$storage_areas = array();
$result = dbQuery($sql, $values);
if ( $result ) {
$results = $result->fetchALL();
foreach ( $results as $row ) {
$storage_areas[] = new Storage($row);
}
}
return $storage_areas;
} # end find()
public function disk_usage_percent() {
$path = $this->Path();
if ( ! $path ) {
@ -226,18 +121,5 @@ class Storage {
return $this->{'Server'};
}
public function to_json() {
$json = array();
foreach ($this->defaults as $key => $value) {
if ( is_callable(array($this, $key)) ) {
$json[$key] = $this->$key();
} else if ( array_key_exists($key, $this) ) {
$json[$key] = $this->{$key};
} else {
$json[$key] = $this->defaults{$key};
}
}
return json_encode($json);
}
} // end class Storage
?>

View File

@ -51,11 +51,30 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
if ( $action == 'execute' ) {
$tempFilterName = '_TempFilter'.time();
$sql .= ' Name = \''.$tempFilterName.'\'';
} else {
$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
$_REQUEST['filter']['Name'] = '_TempFilter'.time();
unset($_REQUEST['Id']);
#$tempFilterName = '_TempFilter'.time();
#$sql .= ' Name = \''.$tempFilterName.'\'';
#} else {
#$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
}
$_REQUEST['filter']['AutoCopy'] = empty($_REQUEST['filter']['AutoCopy']) ? 0 : 1;
$_REQUEST['filter']['AutoMove'] = empty($_REQUEST['filter']['AutoMove']) ? 0 : 1;
$_REQUEST['filter']['AutoArchive'] = empty($_REQUEST['filter']['AutoArchive']) ? 0 : 1;
$_REQUEST['filter']['AutoVideo'] = empty($_REQUEST['filter']['AutoVideo']) ? 0 : 1;
$_REQUEST['filter']['AutoUpload'] = empty($_REQUEST['filter']['AutoUpload']) ? 0 : 1;
$_REQUEST['filter']['AutoEmail'] = empty($_REQUEST['filter']['AutoEmail']) ? 0 : 1;
$_REQUEST['filter']['AutoMessage'] = empty($_REQUEST['filter']['AutoMessage']) ? 0 : 1;
$_REQUEST['filter']['AutoExecute'] = empty($_REQUEST['filter']['AutoExecute']) ? 0 : 1;
$_REQUEST['filter']['AutoDelete'] = empty($_REQUEST['filter']['AutoDelete']) ? 0 : 1;
$_REQUEST['filter']['UpdateDiskSpace'] = empty($_REQUEST['filter']['UpdateDiskSpace']) ? 0 : 1;
$_REQUEST['filter']['Background'] = empty($_REQUEST['filter']['Background']) ? 0 : 1;
$_REQUEST['filter']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
$changes = $filter->changes($_REQUEST['filter']);
ZM\Logger::Debug("Changes: " . print_r($changes,true));
if ( 0 ) {
$sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter']['Query']));
$sql .= ', AutoArchive = '.(!empty($_REQUEST['filter']['AutoArchive']) ? 1 : 0);
$sql .= ', AutoVideo = '. ( !empty($_REQUEST['filter']['AutoVideo']) ? 1 : 0);
@ -73,17 +92,25 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
$sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
$sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
}
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
if ( 0 ) {
dbQuery('UPDATE Filters SET '.$sql.' WHERE Id=?', array($_REQUEST['Id']));
}
$filter->save($changes);
if ( $filter->Background() )
$filter->control('stop');
} else {
# COuld be execute
if ( 0 ) {
dbQuery('INSERT INTO Filters SET'.$sql);
$_REQUEST['Id'] = dbInsertId();
$filter = new ZM\Filter($_REQUEST['Id']);
}
if ( !empty($_REQUEST['filter']['Background']) )
$filter->save($changes);
}
if ( $filter->Background() )
$filter->control('start');
if ( $action == 'execute' ) {

View File

@ -2518,4 +2518,45 @@ function format_duration($time, $separator=':') {
return sprintf('%02d%s%02d%s%02d', floor($time/3600), $separator, ($time/60)%60, $separator, $time%60);
}
function array_recursive_diff($aArray1, $aArray2) {
$aReturn = array();
foreach ($aArray1 as $mKey => $mValue) {
if ( array_key_exists($mKey, $aArray2) ) {
if ( is_array($mValue) ) {
$aRecursiveDiff = array_recursive_diff($mValue, $aArray2[$mKey]);
if ( count($aRecursiveDiff) ) {
$aReturn[$mKey] = $aRecursiveDiff;
}
} else {
if ( $mValue != $aArray2[$mKey] ) {
$aReturn[$mKey] = $mValue;
}
}
} else {
$aReturn[$mKey] = $mValue;
}
}
# Now check for keys in array2 that are not in array1
foreach ($aArray2 as $mKey => $mValue) {
if ( array_key_exists($mKey, $aArray1) ) {
# Already checked it... I think.
#if ( is_array($mValue) ) {
#$aRecursiveDiff = array_recursive_diff($mValue, $aArray2[$mKey]);
#if ( count($aRecursiveDiff) ) {
#$aReturn[$mKey] = $aRecursiveDiff;
#}
#} else {
#if ( $mValue != $aArray2[$mKey] ) {
#$aReturn[$mKey] = $mValue;
#}
#}
} else {
$aReturn[$mKey] = $mValue;
}
}
return $aReturn;
}
?>

View File

@ -132,6 +132,7 @@ $SLANG = array(
'AttrMaxScore' => 'Max. Score',
'AttrMonitorId' => 'Monitor Id',
'AttrMonitorName' => 'Monitor Name',
'AttrSecondaryStorageArea' => 'Secondary Storage Area',
'AttrStorageArea' => 'Storage Area',
'AttrFilterServer' => 'Server Filter is Running On',
'AttrMonitorServer' => 'Server Monitor is Running On',
@ -356,6 +357,7 @@ $SLANG = array(
'FilterArchiveEvents' => 'Archive all matches',
'FilterUpdateDiskSpace' => 'Update used disk space',
'FilterDeleteEvents' => 'Delete all matches',
'FilterCopyEvents' => 'Copy all matches',
'FilterMoveEvents' => 'Move all matches',
'FilterEmailEvents' => 'Email details of all matches',
'FilterExecuteEvents' => 'Execute command on all matches',

View File

@ -134,7 +134,11 @@ if ( ! $Event->Id() ) {
<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>
<span id="Storage"> <?php echo human_filesize($Event->DiskSpace(null)) . ' on ' . $Event->Storage()->Name() ?></span>
<span id="Storage">
<?php echo
human_filesize($Event->DiskSpace(null)) . ' on ' . $Event->Storage()->Name().
( $Event->SecondaryStorageId() ? ', ' . $Event->SecondaryStorage()->Name() :'' )
?></span>
<div id="closeWindow"><a href="#" onclick="<?php echo $popup ? 'window.close()' : 'window.history.back();return false;' ?>"><?php echo $popup ? translate('Close') : translate('Back') ?></a></div>
</div>
<div id="menuBar1">

View File

@ -22,36 +22,35 @@ if ( !canView('Events') ) {
$view = 'error';
return;
}
require_once 'includes/Filter.php';
require_once('includes/Object.php');
require_once('includes/Storage.php');
require_once('includes/Filter.php');
parseSort();
$filterNames = array(''=>translate('ChooseFilter'));
$filter = NULL;
foreach ( dbFetchAll('SELECT * FROM Filters ORDER BY Name') as $row ) {
$filterNames[$row['Id']] = $row['Id'] . ' ' . $row['Name'];
if ( $row['Background'] )
$filterNames[$row['Id']] .= '*';
if ( $row['Concurrent'] )
$filterNames[$row['Id']] .= '&';
foreach ( ZM\Filter::find(null,array('order'=>'lower(Name)')) as $Filter ) {
$filterNames[$Filter->Id()] = $Filter->Id() . ' ' . $Filter->Name();
if ( $Filter->Background() )
$filterNames[$Filter->Id()] .= '*';
if ( $Filter->Concurrent() )
$filterNames[$Filter->Id()] .= '&';
if ( isset($_REQUEST['Id']) && $_REQUEST['Id'] == $row['Id'] ) {
$filter = new ZM\Filter($row);
if ( isset($_REQUEST['Id']) && ($_REQUEST['Id'] == $Filter->Id()) ) {
$filter = $Filter;
}
}
if ( !$filter ) {
$filter = new ZM\Filter();
}
if ( isset($_REQUEST['sort_field']) && isset($_REQUEST['filter']) ) {
$_REQUEST['filter']['Query']['sort_field'] = $_REQUEST['sort_field'];
$_REQUEST['filter']['Query']['sort_asc'] = $_REQUEST['sort_asc'];
$_REQUEST['filter']['Query']['limit'] = $_REQUEST['limit'];
}
ZM\Logger::Debug("Query: " . $filter->Query_json());
ZM\Logger::Debug("Query: " . print_r($filter->Query(), true));
if ( isset($_REQUEST['filter']) ) {
$filter->set($_REQUEST['filter']);
# Update our filter object with whatever changes we have made before saving
#$filter->set($_REQUEST['filter']);
}
$conjunctionTypes = getFilterQueryConjunctionTypes();
@ -98,6 +97,7 @@ $attrTypes = array(
'DiskSpace' => translate('AttrDiskSpace'),
'SystemLoad' => translate('AttrSystemLoad'),
'StorageId' => translate('AttrStorageArea'),
'SecondaryStorageId' => translate('AttrSecondaryStorageArea'),
'ServerId' => translate('AttrMonitorServer'),
'FilterServerId' => translate('AttrFilterServer'),
'MonitorServerId' => translate('AttrMonitorServer'),
@ -127,27 +127,24 @@ $archiveTypes = array(
$focusWindow = true;
$storageareas = array('' => 'All');
//$storageareas[0] = 'Default ' . ZM_DIR_EVENTS;
foreach ( dbFetchAll('SELECT Id,Name FROM Storage ORDER BY lower(Name) ASC') as $storage ) {
$storageareas[$storage['Id']] = $storage['Name'];
}
$storageareas = array('' => 'All') + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
$weekdays = array();
for ( $i = 0; $i < 7; $i++ ) {
$weekdays[$i] = strftime('%A', mktime(12, 0, 0, 1, $i+1, 2001));
}
$states = array();
foreach ( dbFetchAll('SELECT Id, Name FROM States ORDER BY lower(Name) ASC') as $state_row ) {
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `States` ORDER BY lower(`Name`) ASC') as $state_row ) {
$states[$state_row['Id']] = validHtmlStr($state_row['Name']);
}
$servers = array();
$servers['ZM_SERVER_ID'] = 'Current Server';
$servers['NULL'] = 'No Server';
foreach ( dbFetchAll('SELECT Id, Name FROM Servers ORDER BY lower(Name) ASC') as $server ) {
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Servers` ORDER BY lower(`Name`) ASC') as $server ) {
$servers[$server['Id']] = validHtmlStr($server['Name']);
}
$monitors = array();
foreach ( dbFetchAll('SELECT Id, Name FROM Monitors ORDER BY Name ASC') as $monitor ) {
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Monitors` ORDER BY lower(`Name`) ASC') as $monitor ) {
if ( visibleMonitor($monitor['Id']) ) {
$monitors[$monitor['Name']] = validHtmlStr($monitor['Name']);
}
@ -273,7 +270,7 @@ for ( $i=0; $i < count($terms); $i++ ) {
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $servers, $term['val']); ?></td>
<?php
} elseif ( $term['attr'] == 'StorageId' ) {
} elseif ( ($term['attr'] == 'StorageId') || ($term['attr'] == 'SecondaryStorageId') ) {
?>
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val']); ?></td>
@ -391,7 +388,13 @@ if ( ZM_OPT_MESSAGE ) {
<label><?php echo translate('FilterDeleteEvents') ?></label>
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
</p>
<p><label><?php echo translate('FilterMoveEvents') ?></label>
<p>
<label><?php echo translate('FilterCopyEvents') ?></label>
<input type="checkbox" name="filter[AutoCopy]" value="1"<?php if ( $filter->AutoCopy() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_autocopy"/>
<?php echo htmlSelect('filter[AutoCopyTo]', $storageareas, $filter->AutoCopyTo(), $filter->AutoCopy() ? null : array('style'=>'display:none;')); ?>
</p>
<p>
<label><?php echo translate('FilterMoveEvents') ?></label>
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( $filter->AutoMove() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_automove"/>
<?php echo htmlSelect('filter[AutoMoveTo]', $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;')); ?>
</p>

View File

@ -72,6 +72,15 @@ function click_automove(element) {
}
}
function click_autocopy(element) {
updateButtons(this);
if ( this.checked ) {
$j(this.form.elements['filter[AutoCopyTo]']).css('display', 'inline');
} else {
this.form.elements['filter[AutoCopyTo]'].hide();
}
}
function checkValue( element ) {
var rows = $j(element).closest('tbody').children();
parseRows(rows);
@ -200,10 +209,10 @@ function parseRows(rows) {
}
var serverVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(serverSelect).children().val(serverVal).chosen({width: "101%"});
} else if ( attr == 'StorageId' ) { //Choose by storagearea
} else if ( (attr == 'StorageId') || (attr == 'SecondaryStorageId') ) { //Choose by storagearea
var storageSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for ( key in storageareas ) {
storageSelect.append('<option value="' + key + '">' + storageareas[key] + '</option>');
storageSelect.append('<option value="' + key + '">' + storageareas[key].Name + '</option>');
}
var storageVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"});