implement Storage Area move

pull/2077/head
Isaac Connor 2017-12-04 11:05:50 -05:00
parent af1729792f
commit 1ccd344bf5
13 changed files with 169 additions and 92 deletions

View File

@ -79,13 +79,16 @@ BEGIN {
# Search for user created config files. If one or more are found then
# update the Config hash with those values
if ( -d ZM_CONFIG_SUBDIR ) {
if ( -R ZM_CONFIG_SUBDIR ) {
foreach my $filename ( glob ZM_CONFIG_SUBDIR."/*.conf" ) {
process_configfile($filename);
}
} else {
print( STDERR "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on ".ZM_CONFIG_SUBDIR.".\n" );
if ( -R ZM_CONFIG_SUBDIR ) {
foreach my $filename ( glob ZM_CONFIG_SUBDIR."/*.conf" ) {
process_configfile($filename);
}
} else {
print( STDERR "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on ".ZM_CONFIG_SUBDIR.".\n" );
}
}
foreach my $k ( keys %Config ) {
print "Initial config $k => $Config{$k}\n";
}
use DBI;
@ -94,14 +97,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 +126,9 @@ BEGIN {
}
$sth->finish();
#$dbh->disconnect();
if ( ! exists $Config{ZM_SERVER_ID} ) {
#
if ( ! $Config{ZM_SERVER_ID} ) {
print "Loading ServerId $Config{ZM_SERVER_NAME} HOST:$Config{ZM_SERVER_HOST}\n";
$Config{ZM_SERVER_ID} = undef;
$sth = $dbh->prepare_cached( 'SELECT * FROM Servers WHERE Name=?' );
if ( $Config{ZM_SERVER_NAME} ) {
@ -136,36 +141,38 @@ BEGIN {
$Config{ZM_SERVER_ID} = $$result{Id};
}
$sth->finish();
} else {
print "Have ZM_SERVER_ID $Config{ZM_SERVER_ID}\n";
}
# This subroutine must be inside the BEGIN block
sub process_configfile {
my $config_file = shift;
my $config_file = shift;
if ( -R $config_file ) {
open( my $CONFIG, "<", $config_file )
or croak( "Can't open config file '$config_file': $!" );
foreach my $str ( <$CONFIG> ) {
next if ( $str =~ /^\s*$/ );
next if ( $str =~ /^\s*#/ );
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
if ( ! $name ) {
print( STDERR "Warning, bad line in $config_file: $str\n" );
next;
} # end if
$name =~ tr/a-z/A-Z/;
$Config{$name} = $value;
}
close( $CONFIG );
} else {
print( STDERR "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $config_file\n" );
if ( -R $config_file ) {
open( my $CONFIG, '<', $config_file )
or croak( "Can't open config file '$config_file': $!" );
foreach my $str ( <$CONFIG> ) {
next if ( $str =~ /^\s*$/ );
next if ( $str =~ /^\s*#/ );
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
if ( ! $name ) {
print( STDERR "Warning, bad line in $config_file: $str\n" );
next;
} # end if
$name =~ tr/a-z/A-Z/;
$Config{$name} = $value;
}
close( $CONFIG );
} else {
print( STDERR "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $config_file\n" );
}
}
} # 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 +195,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 +208,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 +221,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 +235,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 +244,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

@ -47,7 +47,7 @@ use vars qw/ $AUTOLOAD $log $dbh/;
*log = \$ZoneMinder::Logger::logger;
*dbh = \$ZoneMinder::Database::dbh;
my $debug = 1;
my $debug = 0;
use constant DEBUG_ALL=>1;
sub new {

View File

@ -207,7 +207,7 @@ sub getFilters {
} else {
$sql .= ' Background = 1 AND';
}
$sql .= '( AutoArchive = 1
$sql .= '( AutoArchive = 1
or AutoVideo = 1
or AutoUpload = 1
or AutoEmail = 1
@ -215,16 +215,17 @@ 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 toprepare '$sql': ".$dbh->errstr() );
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr() );
my $res;
if ( $filter_name ) {
$res = $sth->execute( $filter_name )
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
} else {
$res = $sth->execute()
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
}
FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter );
@ -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,12 +272,12 @@ 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" );
# Do it individually to avoid locking up the table for new events
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 )
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
@ -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();
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
$Event->DiskSpace(undef);
$Event->save();
} # end if UpdateDiskSpace
} # end foreach event
}

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

@ -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);

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 ) {

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

@ -109,6 +109,7 @@ $groupSql = Group::get_group_sql( $group_id );
Warning("Monitor " . $monitors[$i]['Id'] . ' is not visible' );
continue;
}
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) {
continue;

View File

@ -45,7 +45,7 @@ xhtmlHeaders(__FILE__, translate('AddMonitors'));
<div style="width:50%;position: absolute; top:0; left: 0;height: 100%;">
<fieldset><legend>Enter by IP or URL</legend>
<!--<input type="text" name="newMonitor[Name]" />-->
<input type="url" name="newMonitor[Url]" oninput="probe(this);"/>
<input type="text" name="newMonitor[Url]" oninput="probe(this);"/>
</fieldset>
<fieldset><legend>Import CSV Spreadsheet</legend>
Spreadsheet should have the following format:<br/>

View File

@ -18,7 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView( 'Events' ) ) {
if ( !canView('Events') ) {
$view = 'error';
return;
}
@ -50,16 +50,12 @@ xhtmlHeaders(__FILE__, translate('Download') );
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<?php
if ( !empty($_REQUEST['eid']) )
{
if ( !empty($_REQUEST['eid']) ) {
?>
<input type="hidden" name="id" value="<?php echo validInt($_REQUEST['eid']) ?>"/>
<?php
}
elseif ( !empty($_REQUEST['eids']) )
{
foreach ( $_REQUEST['eids'] as $eid )
{
} else if ( !empty($_REQUEST['eids']) ) {
foreach ( $_REQUEST['eids'] as $eid ) {
?>
<input type="hidden" name="eids[]" value="<?php echo validInt($eid) ?>"/>
<?php
@ -75,30 +71,34 @@ elseif ( !empty($_REQUEST['eids']) )
<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>
<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 );" />
<input type="button" id="exportButton" name="exportButton" value="<?php echo translate('GenerateDownload') ?>" onclick="exportEvent(this.form);" />
</form>
</div>
<?php
if ( isset($_REQUEST['generated']) )
{
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>
<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
}
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']) )
{
if ( !empty($_REQUEST['generated']) ) {
?>
<h3 id="downloadLink"><a href="<?php echo validHtmlStr($_REQUEST['exportFile']) ?>"><?php echo translate('Download') ?></a></h3>
<?php

View File

@ -385,7 +385,11 @@ if ( ZM_OPT_MESSAGE ) {
</p>
<p>
<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 )"/>
<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>