Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / rt / lib / RT / Shredder.pm
index 8022775..af675bd 100644 (file)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -105,7 +105,7 @@ See also 'rt-shredder --help'.
 =head2 Web based interface (WebUI)
 
 Shredder's WebUI integrates into RT's WebUI.  You can find it in the
 =head2 Web based interface (WebUI)
 
 Shredder's WebUI integrates into RT's WebUI.  You can find it in the
-Configuration->Tools->Shredder tab.  The interface is similar to the
+Admin->Tools->Shredder tab.  The interface is similar to the
 CLI and gives you the same functionality. You can find 'Shredder' link
 at the bottom of tickets search results, so you could wipeout tickets
 in the way similar to the bulk update.
 CLI and gives you the same functionality. You can find 'Shredder' link
 at the bottom of tickets search results, so you could wipeout tickets
 in the way similar to the bulk update.
@@ -178,7 +178,7 @@ shredding on most databases.
     CREATE INDEX SHREDDER_TXN1 ON Transactions(ReferenceType, OldReference);
     CREATE INDEX SHREDDER_TXN2 ON Transactions(ReferenceType, NewReference);
     CREATE INDEX SHREDDER_TXN3 ON Transactions(Type, OldValue);
     CREATE INDEX SHREDDER_TXN1 ON Transactions(ReferenceType, OldReference);
     CREATE INDEX SHREDDER_TXN2 ON Transactions(ReferenceType, NewReference);
     CREATE INDEX SHREDDER_TXN3 ON Transactions(Type, OldValue);
-    CREATE INDEX SHREDDER_TXN4 ON Transactions(Type, NewValue)
+    CREATE INDEX SHREDDER_TXN4 ON Transactions(Type, NewValue);
 
     CREATE INDEX SHREDDER_ATTACHMENTS1 ON Attachments(Creator);
 
 
     CREATE INDEX SHREDDER_ATTACHMENTS1 ON Attachments(Creator);
 
@@ -212,7 +212,6 @@ objects in the cache and backups storage.
 
 =cut
 
 
 =cut
 
-our $VERSION = '0.04';
 use File::Spec ();
 
 
 use File::Spec ();
 
 
@@ -224,29 +223,6 @@ BEGIN {
 ### after:     push @INC, qw(@RT_LIB_PATH@);
     use RT::Shredder::Constants;
     use RT::Shredder::Exceptions;
 ### after:     push @INC, qw(@RT_LIB_PATH@);
     use RT::Shredder::Constants;
     use RT::Shredder::Exceptions;
-
-    require RT;
-
-    require RT::Shredder::Record;
-
-    require RT::Shredder::ACE;
-    require RT::Shredder::Attachment;
-    require RT::Shredder::CachedGroupMember;
-    require RT::Shredder::CustomField;
-    require RT::Shredder::CustomFieldValue;
-    require RT::Shredder::GroupMember;
-    require RT::Shredder::Group;
-    require RT::Shredder::Link;
-    require RT::Shredder::Principal;
-    require RT::Shredder::Queue;
-    require RT::Shredder::Scrip;
-    require RT::Shredder::ScripAction;
-    require RT::Shredder::ScripCondition;
-    require RT::Shredder::Template;
-    require RT::Shredder::ObjectCustomFieldValue;
-    require RT::Shredder::Ticket;
-    require RT::Shredder::Transaction;
-    require RT::Shredder::User;
 }
 
 our @SUPPORTED_OBJECTS = qw(
 }
 
 our @SUPPORTED_OBJECTS = qw(
@@ -291,6 +267,7 @@ sub Init
     %opt = @_;
     RT::LoadConfig();
     RT::Init();
     %opt = @_;
     RT::LoadConfig();
     RT::Init();
+    return;
 }
 
 =head4 new
 }
 
 =head4 new
@@ -307,8 +284,7 @@ sub new
 {
     my $proto = shift;
     my $self = bless( {}, ref $proto || $proto );
 {
     my $proto = shift;
     my $self = bless( {}, ref $proto || $proto );
-    $self->_Init( @_ );
-    return $self;
+    return $self->_Init( @_ );
 }
 
 sub _Init
 }
 
 sub _Init
@@ -318,6 +294,7 @@ sub _Init
     $self->{'cache'}        = {};
     $self->{'resolver'}     = {};
     $self->{'dump_plugins'} = [];
     $self->{'cache'}        = {};
     $self->{'resolver'}     = {};
     $self->{'dump_plugins'} = [];
+    return $self;
 }
 
 =head4 CastObjectsToRecords( Objects => undef )
 }
 
 =head4 CastObjectsToRecords( Objects => undef )
@@ -367,12 +344,18 @@ sub CastObjectsToRecords
         }
     } elsif ( UNIVERSAL::isa( $targets, 'SCALAR' ) || !ref $targets ) {
         $targets = $$targets if ref $targets;
         }
     } elsif ( UNIVERSAL::isa( $targets, 'SCALAR' ) || !ref $targets ) {
         $targets = $$targets if ref $targets;
-        my ($class, $id) = split /-/, $targets;
+        my ($class, $org, $id);
+        if ($targets =~ /-.*-/) {
+            ($class, $org, $id) = split /-/, $targets;
+            RT::Shredder::Exception->throw( "Can't wipeout remote object $targets" )
+                  unless $org eq RT->Config->Get('Organization');
+        } else {
+            ($class, $id) = split /-/, $targets;
+        }
         RT::Shredder::Exception->throw( "Unsupported class $class" )
               unless $class =~ /^\w+(::\w+)*$/;
         $class = 'RT::'. $class unless $class =~ /^RTx?::/i;
         RT::Shredder::Exception->throw( "Unsupported class $class" )
               unless $class =~ /^\w+(::\w+)*$/;
         $class = 'RT::'. $class unless $class =~ /^RTx?::/i;
-        eval "require $class";
-        die "Couldn't load '$class' module" if $@;
+        $class->require or die "Failed to load $class: $@";
         my $obj = $class->new( RT->SystemUser );
         die "Couldn't construct new '$class' object" unless $obj;
         $obj->Load( $id );
         my $obj = $class->new( RT->SystemUser );
         die "Couldn't construct new '$class' object" unless $obj;
         $obj->Load( $id );
@@ -434,8 +417,11 @@ sub PutObject
         RT::Shredder::Exception->throw( "Unsupported type '". (ref $obj || $obj || '(undef)')."'" );
     }
 
         RT::Shredder::Exception->throw( "Unsupported type '". (ref $obj || $obj || '(undef)')."'" );
     }
 
-    my $str = $obj->_AsString;
-    return ($self->{'cache'}->{ $str } ||= { State => ON_STACK, Object => $obj } );
+    my $str = $obj->UID;
+    return ($self->{'cache'}->{ $str } ||= {
+        State  => RT::Shredder::Constants::ON_STACK,
+        Object => $obj
+    } );
 }
 
 =head4 GetObject, GetState, GetRecord( String => ''| Object => '' )
 }
 
 =head4 GetObject, GetState, GetRecord( String => ''| Object => '' )
@@ -463,7 +449,7 @@ sub _ParseRefStrArgs
         Carp::croak( "both String and Object args passed" );
     }
     return $args{'String'} if $args{'String'};
         Carp::croak( "both String and Object args passed" );
     }
     return $args{'String'} if $args{'String'};
-    return $args{'Object'}->_AsString if UNIVERSAL::can($args{'Object'}, '_AsString' );
+    return $args{'Object'}->UID if UNIVERSAL::can($args{'Object'}, 'UID' );
     return '';
 }
 
     return '';
 }
 
@@ -557,9 +543,10 @@ sub WipeoutAll
     my $self = $_[0];
 
     foreach my $cache_val ( values %{ $self->{'cache'} } ) {
     my $self = $_[0];
 
     foreach my $cache_val ( values %{ $self->{'cache'} } ) {
-        next if $cache_val->{'State'} & (WIPED | IN_WIPING);
+        next if $cache_val->{'State'} & (RT::Shredder::Constants::WIPED | RT::Shredder::Constants::IN_WIPING);
         $self->Wipeout( Object => $cache_val->{'Object'} );
     }
         $self->Wipeout( Object => $cache_val->{'Object'} );
     }
+    return;
 }
 
 sub Wipeout
 }
 
 sub Wipeout
@@ -580,6 +567,7 @@ sub Wipeout
         die $error if RT::Shredder::Exception::Info->caught;
         die "Couldn't wipeout object: $error";
     }
         die $error if RT::Shredder::Exception::Info->caught;
         die "Couldn't wipeout object: $error";
     }
+    return;
 }
 
 sub _Wipeout
 }
 
 sub _Wipeout
@@ -589,9 +577,9 @@ sub _Wipeout
 
     my $record = $args{'CacheRecord'};
     $record = $self->PutObject( Object => $args{'Object'} ) unless $record;
 
     my $record = $args{'CacheRecord'};
     $record = $self->PutObject( Object => $args{'Object'} ) unless $record;
-    return if $record->{'State'} & (WIPED | IN_WIPING);
+    return if $record->{'State'} & (RT::Shredder::Constants::WIPED | RT::Shredder::Constants::IN_WIPING);
 
 
-    $record->{'State'} |= IN_WIPING;
+    $record->{'State'} |= RT::Shredder::Constants::IN_WIPING;
     my $object = $record->{'Object'};
 
     $self->DumpObject( Object => $object, State => 'before any action' );
     my $object = $record->{'Object'};
 
     $self->DumpObject( Object => $object, State => 'before any action' );
@@ -602,25 +590,25 @@ sub _Wipeout
 
     my $deps = $object->Dependencies( Shredder => $self );
     $deps->List(
 
     my $deps = $object->Dependencies( Shredder => $self );
     $deps->List(
-        WithFlags => DEPENDS_ON | VARIABLE,
+        WithFlags => RT::Shredder::Constants::DEPENDS_ON | RT::Shredder::Constants::VARIABLE,
         Callback  => sub { $self->ApplyResolvers( Dependency => $_[0] ) },
     );
     $self->DumpObject( Object => $object, State => 'after resolvers' );
 
     $deps->List(
         Callback  => sub { $self->ApplyResolvers( Dependency => $_[0] ) },
     );
     $self->DumpObject( Object => $object, State => 'after resolvers' );
 
     $deps->List(
-        WithFlags    => DEPENDS_ON,
-        WithoutFlags => WIPE_AFTER | VARIABLE,
+        WithFlags    => RT::Shredder::Constants::DEPENDS_ON,
+        WithoutFlags => RT::Shredder::Constants::WIPE_AFTER | RT::Shredder::Constants::VARIABLE,
         Callback     => sub { $self->_Wipeout( Object => $_[0]->TargetObject ) },
     );
     $self->DumpObject( Object => $object, State => 'after wiping dependencies' );
 
     $object->__Wipeout;
         Callback     => sub { $self->_Wipeout( Object => $_[0]->TargetObject ) },
     );
     $self->DumpObject( Object => $object, State => 'after wiping dependencies' );
 
     $object->__Wipeout;
-    $record->{'State'} |= WIPED; delete $record->{'Object'};
+    $record->{'State'} |= RT::Shredder::Constants::WIPED; delete $record->{'Object'};
     $self->DumpObject( Object => $object, State => 'after wipeout' );
 
     $deps->List(
     $self->DumpObject( Object => $object, State => 'after wipeout' );
 
     $deps->List(
-        WithFlags => DEPENDS_ON | WIPE_AFTER,
-        WithoutFlags => VARIABLE,
+        WithFlags => RT::Shredder::Constants::DEPENDS_ON | RT::Shredder::Constants::WIPE_AFTER,
+        WithoutFlags => RT::Shredder::Constants::VARIABLE,
         Callback => sub { $self->_Wipeout( Object => $_[0]->TargetObject ) },
     );
     $self->DumpObject( Object => $object, State => 'after late dependencies' );
         Callback => sub { $self->_Wipeout( Object => $_[0]->TargetObject ) },
     );
     $self->DumpObject( Object => $object, State => 'after late dependencies' );
@@ -628,17 +616,6 @@ sub _Wipeout
     return;
 }
 
     return;
 }
 
-sub ValidateRelations
-{
-    my $self = shift;
-    my %args = ( @_ );
-
-    foreach my $record( values %{ $self->{'cache'} } ) {
-        next if( $record->{'State'} & VALID );
-        $record->{'Object'}->ValidateRelations( Shredder => $self );
-    }
-}
-
 =head3 Data storage and backups
 
 =head4 GetFileName( FileName => '<ISO DATETIME>-XXXX.sql', FromStorage => 1 )
 =head3 Data storage and backups
 
 =head4 GetFileName( FileName => '<ISO DATETIME>-XXXX.sql', FromStorage => 1 )
@@ -788,6 +765,7 @@ sub DumpObject {
         my ($state, $msg) = $_->Run( %args );
         die "Couldn't run plugin: $msg" unless $state;
     }
         my ($state, $msg) = $_->Run( %args );
         die "Couldn't run plugin: $msg" unless $state;
     }
+    return;
 }
 
 { my $mark = 1; # XXX: integer overflows?
 }
 
 { my $mark = 1; # XXX: integer overflows?
@@ -803,9 +781,10 @@ sub PushDumpMark {
 sub PopDumpMark {
     my $self = shift;
     foreach (@{ $self->{'dump_plugins'} }) {
 sub PopDumpMark {
     my $self = shift;
     foreach (@{ $self->{'dump_plugins'} }) {
-        my ($state, $msg) = $_->PushMark( @_ );
+        my ($state, $msg) = $_->PopMark( @_ );
         die "Couldn't pop mark: $msg" unless $state;
     }
         die "Couldn't pop mark: $msg" unless $state;
     }
+    return;
 }
 sub RollbackDumpTo {
     my $self = shift;
 }
 sub RollbackDumpTo {
     my $self = shift;
@@ -813,6 +792,7 @@ sub RollbackDumpTo {
         my ($state, $msg) = $_->RollbackTo( @_ );
         die "Couldn't rollback to mark: $msg" unless $state;
     }
         my ($state, $msg) = $_->RollbackTo( @_ );
         die "Couldn't rollback to mark: $msg" unless $state;
     }
+    return;
 }
 }
 
 }
 }