diff options
Diffstat (limited to 'rt/lib/RT/Shredder')
34 files changed, 4861 insertions, 0 deletions
diff --git a/rt/lib/RT/Shredder/ACE.pm b/rt/lib/RT/Shredder/ACE.pm new file mode 100644 index 000000000..8512a85b7 --- /dev/null +++ b/rt/lib/RT/Shredder/ACE.pm @@ -0,0 +1,101 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::ACE (); +package RT::ACE; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Exceptions; +use RT::Shredder::Constants; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} +1; + diff --git a/rt/lib/RT/Shredder/Attachment.pm b/rt/lib/RT/Shredder/Attachment.pm new file mode 100644 index 000000000..c72203d62 --- /dev/null +++ b/rt/lib/RT/Shredder/Attachment.pm @@ -0,0 +1,136 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Attachment (); +package RT::Attachment; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Exceptions; +use RT::Shredder::Constants; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Nested attachments + my $objs = RT::Attachments->new( $self->CurrentUser ); + $objs->Limit( + FIELD => 'Parent', + OPERATOR => '=', + VALUE => $self->Id + ); + $objs->Limit( + FIELD => 'id', + OPERATOR => '!=', + VALUE => $self->Id + ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Parent, nested parts + if( $self->Parent ) { + if( $self->ParentObj && $self->ParentId ) { + push( @$list, $self->ParentObj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no parent attachment #". $self->Parent ." object"; + } + } + +# Transaction + my $obj = $self->TransactionObj; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related transaction #". $self->TransactionId ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} +1; diff --git a/rt/lib/RT/Shredder/CachedGroupMember.pm b/rt/lib/RT/Shredder/CachedGroupMember.pm new file mode 100644 index 000000000..14338031e --- /dev/null +++ b/rt/lib/RT/Shredder/CachedGroupMember.pm @@ -0,0 +1,151 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::CachedGroupMember (); +package RT::CachedGroupMember; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependency; + + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# deep memebership + my $objs = RT::CachedGroupMembers->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'Via', VALUE => $self->Id ); + $objs->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->Id ); + push( @$list, $objs ); + +# principal lost group membership and lost some rights which he could delegate to +# some body + +# XXX: Here is problem cause HasMemberRecursively would return true allways +# cause we didn't delete anything yet. :( + # if pricipal is not member anymore(could be via other groups) then proceed + if( $self->GroupObj->Object->HasMemberRecursively( $self->MemberObj ) ) { + my $acl = RT::ACL->new( $self->CurrentUser ); + $acl->LimitToPrincipal( Id => $self->GroupId ); + + # look into all rights that have group + while( my $ace = $acl->Next ) { + my $delegations = RT::ACL->new( $self->CurrentUser ); + $delegations->DelegatedFrom( Id => $ace->Id ); + $delegations->DelegatedBy( Id => $self->MemberId ); + push( @$list, $delegations ); + } + } + +# XXX: Do we need to delete records if user lost right 'DelegateRights'? + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} + +#TODO: If we plan write export tool we also should fetch parent groups +# now we only wipeout things. + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + my $obj = $self->MemberObj; + if( $obj && $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Principal #". $self->MemberId ." object."; + } + + $obj = $self->GroupObj; + if( $obj && $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Principal #". $self->GroupId ." object."; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} +1; diff --git a/rt/lib/RT/Shredder/Constants.pm b/rt/lib/RT/Shredder/Constants.pm new file mode 100644 index 000000000..a7166f363 --- /dev/null +++ b/rt/lib/RT/Shredder/Constants.pm @@ -0,0 +1,141 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Constants; + +use base qw(Exporter); + +=head1 NAME + +RT::Shredder::Constants - RT::Shredder constants that is used to mark state of RT objects. + +=head1 DESCRIPTION + +This module exports two group of bit constants. +First group is group of flags which are used to clarify dependecies between objects, and +second group is states of RT objects in Shredder cache. + +=head1 FLAGS + +=head2 DEPENDS_ON + +Targets that has such dependency flag set should be wiped out with base object. + +=head2 WIPE_AFTER + +If dependency has such flag then target object would be wiped only +after base object. You should mark dependencies with this flag +if two objects depends on each other, for example Group and Principal +have such relationship, this mean Group depends on Principal record and +that Principal record depends on the same Group record. Other examples: +User and Principal, User and its ACL equivalence group. + +=head2 VARIABLE + +This flag is used to mark dependencies that can be resolved with changing +value in target object. For example ticket can be created by user we can +change this reference when we delete user. + +=head2 RELATES + +This flag is used to validate relationships integrity. Base object +is valid only when all target objects which are marked with this flags +exist. + +=cut + +use constant { + DEPENDS_ON => 0x000001, + WIPE_AFTER => 0x000010, + RELATES => 0x000100, + VARIABLE => 0x001000, +}; + +=head1 STATES + +=head2 ON_STACK + +Default state of object in Shredder cache that means that object is +loaded and placed into cache. + +=head2 WIPED + +Objects with this state are not exist any more in DB, but perl +object is still in memory. This state is used to be shure that +delete query is called once. + +=head2 VALID + +Object is marked with this state only when its relationships +are valid. + +=head2 INVALID + +=cut + +use constant { + ON_STACK => 0x00000, + IN_WIPING => 0x00001, + WIPED => 0x00010, + VALID => 0x00100, + INVALID => 0x01000, +}; + +our @EXPORT = qw( + DEPENDS_ON + WIPE_AFTER + RELATES + VARIABLE + ON_STACK + IN_WIPING + WIPED + VALID + INVALID + ); + +1; diff --git a/rt/lib/RT/Shredder/CustomField.pm b/rt/lib/RT/Shredder/CustomField.pm new file mode 100644 index 000000000..d956373a3 --- /dev/null +++ b/rt/lib/RT/Shredder/CustomField.pm @@ -0,0 +1,126 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::CustomField (); +package RT::CustomField; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +#TODO: Queues if we wish export tool + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Custom field values + push( @$list, $self->Values ); + +# Ticket custom field values + my $objs = RT::ObjectCustomFieldValues->new( $self->CurrentUser ); + $objs->LimitToCustomField( $self->Id ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + my $obj = $self->Object; + +# Queue +# Skip if it's global CF + if( $self->Queue ) { + if( $self->QueueObj && $self->QueueObj->Id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related queue #". $self->Queue ." object"; + } + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; + diff --git a/rt/lib/RT/Shredder/CustomFieldValue.pm b/rt/lib/RT/Shredder/CustomFieldValue.pm new file mode 100644 index 000000000..56a1479e4 --- /dev/null +++ b/rt/lib/RT/Shredder/CustomFieldValue.pm @@ -0,0 +1,94 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::CustomFieldValue (); +package RT::CustomFieldValue; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +# No dependencies that should be deleted with record +# I should decide is TicketCustomFieldValue depends by this or not. +# Today I think no. What would be tomorrow I don't know. + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + my $obj = $self->CustomFieldObj; + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related CustomField #". $self->id ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/Dependencies.pm b/rt/lib/RT/Shredder/Dependencies.pm new file mode 100644 index 000000000..c4ba94ce5 --- /dev/null +++ b/rt/lib/RT/Shredder/Dependencies.pm @@ -0,0 +1,149 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Dependencies; + +use strict; +use RT::Shredder::Exceptions; +use RT::Shredder::Constants; +use RT::Shredder::Dependency; +use RT::Record; + + + +=head1 METHODS + +=head2 new + +Creates new empty collection of dependecies. + +=cut + +sub new +{ + my $proto = shift; + my $self = bless( {}, ref $proto || $proto ); + $self->{'list'} = []; + return $self; +} + +=head2 _PushDependencies + +Put in objects into collection. +Takes +BaseObject - any supported object of RT::Record subclass; +Flags - flags that describe relationship between target and base objects; +TargetObjects - any of RT::SearchBuilder or RT::Record subclassed objects +or array ref on list of this objects; +Shredder - RT::Shredder object. + +SeeAlso: _PushDependecy, RT::Shredder::Dependency + +=cut + +sub _PushDependencies +{ + my $self = shift; + my %args = ( TargetObjects => undef, Shredder => undef, @_ ); + my @objs = $args{'Shredder'}->CastObjectsToRecords( Objects => delete $args{'TargetObjects'} ); + $self->_PushDependency( %args, TargetObject => $_ ) foreach @objs; + return; +} + +sub _PushDependency +{ + my $self = shift; + my %args = ( + BaseObject => undef, + Flags => undef, + TargetObject => undef, + Shredder => undef, + @_ + ); + my $rec = $args{'Shredder'}->PutObject( Object => $args{'TargetObject'} ); + return if $rec->{'State'} & WIPED; # there is no object anymore + + push @{ $self->{'list'} }, + RT::Shredder::Dependency->new( + BaseObject => $args{'BaseObject'}, + Flags => $args{'Flags'}, + TargetObject => $rec->{'Object'}, + ); + + if( scalar @{ $self->{'list'} } > ( $RT::DependenciesLimit || 1000 ) ) { + RT::Shredder::Exception::Info->throw( 'DependenciesLimit' ); + } + return; +} + +=head2 List + + +=cut + +sub List +{ + my $self = shift; + my %args = ( + WithFlags => undef, + WithoutFlags => undef, + Callback => undef, + @_ + ); + + my $wflags = delete $args{'WithFlags'}; + my $woflags = delete $args{'WithoutFlags'}; + + return + map $args{'Callback'}? $args{'Callback'}->($_): $_, + grep !defined( $wflags ) || ($_->Flags & $wflags) == $wflags, + grep !defined( $woflags ) || !($_->Flags & $woflags), + @{ $self->{'list'} }; +} + +1; diff --git a/rt/lib/RT/Shredder/Dependency.pm b/rt/lib/RT/Shredder/Dependency.pm new file mode 100644 index 000000000..bd49ac04c --- /dev/null +++ b/rt/lib/RT/Shredder/Dependency.pm @@ -0,0 +1,112 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Dependency; + +use strict; +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; + +my %FlagDescs = ( + DEPENDS_ON, 'depends on', + VARIABLE, 'resolvable dependency', + WIPE_AFTER, 'delete after', + RELATES, 'relates with', +); + +sub new +{ + my $proto = shift; + my $self = bless( {}, ref $proto || $proto ); + $self->Set( @_ ); + return $self; +} + +sub Set +{ + my $self = shift; + my %args = ( Flags => DEPENDS_ON, @_ ); + my @keys = qw(Flags BaseObject TargetObject); + @$self{ @keys } = @args{ @keys }; + + return; +} + +sub AsString +{ + my $self = shift; + my $res = $self->BaseObject->_AsString; + $res .= " ". $self->FlagsAsString; + $res .= " ". $self->TargetObject->_AsString; + return $res; +} + +sub Flags { return $_[0]->{'Flags'} } +sub FlagsAsString +{ + my $self = shift; + my @res = (); + foreach ( sort keys %FlagDescs ) { + if( $self->Flags() & $_ ) { + push( @res, $FlagDescs{ $_ } ); + } + } + push @res, 'no flags' unless( @res ); + return "(" . join( ',', @res ) . ")"; +} + + +sub BaseObject { return $_[0]->{'BaseObject'} } +sub TargetObject { return $_[0]->{'TargetObject'} } +sub Object { return shift()->{ ({@_})->{Type}. "Object" } } + +sub TargetClass { return ref $_[0]->{'TargetObject'} } +sub BaseClass { return ref $_[0]->{'BaseObject'} } +sub Class { return ref shift()->Object( @_ ) } + +1; diff --git a/rt/lib/RT/Shredder/Exceptions.pm b/rt/lib/RT/Shredder/Exceptions.pm new file mode 100644 index 000000000..423b7b565 --- /dev/null +++ b/rt/lib/RT/Shredder/Exceptions.pm @@ -0,0 +1,113 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Exception; + +use warnings; +use strict; + +use Exception::Class; +use base qw(Exception::Class::Base); + +BEGIN { + __PACKAGE__->NoRefs(0); +} + +#sub NoRefs { return 0 } +sub show_trace { return 1 } + +package RT::Shredder::Exception::Info; + +use base qw(RT::Shredder::Exception); + +my %DESCRIPTION = ( + DependenciesLimit => <<END, +Dependecies list have reached its limit. +See \$RT::DependenciesLimit in RT::Shredder docs. +END + + SystemObject => <<END, +System object was requested for deletion, shredder couldn't +do that because system would be unusable than. +END + + CouldntLoadObject => <<END, +Shredder couldn't load object. Most probably it's not fatal error. +May be you've used Objects plugin and asked to delete object that +doesn't exist in the system. If you think that your request was +correct and it's problem of the Shredder then you can get full error +message from RT log files and send bug report. +END + + NoResolver => <<END, +Object has dependency that could be resolved, but resolver +wasn't defined. You have to re-read documentation of the +plugin you're using, for example the 'Users' plugin has +option 'replace_relations' argument. +END +); + +sub Fields { return ((shift)->SUPER::Fields(@_), 'tag') } + +sub tag { return (shift)->{'tag'} } + +sub full_message { + my $self = shift; + my $error = $self->message; + if ( my $tag = $self->tag ) { + my $message = $DESCRIPTION{ $self->tag } || ''; + warn "Tag '$tag' doesn't exist" unless $message; + $message .= "\nAdditional info:\n$error" if $error; + return $message; + } + return $DESCRIPTION{$error} || $error; +} + +sub show_trace { return 0 } + +1; diff --git a/rt/lib/RT/Shredder/Group.pm b/rt/lib/RT/Shredder/Group.pm new file mode 100644 index 000000000..867fe0263 --- /dev/null +++ b/rt/lib/RT/Shredder/Group.pm @@ -0,0 +1,185 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Group (); +package RT::Group; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# User is inconsistent without own Equivalence group + if( $self->Domain eq 'ACLEquivalence' ) { + # delete user entry after ACL equiv group + # in other case we will get deep recursion + my $objs = RT::User->new($self->CurrentUser); + $objs->Load( $self->Instance ); + $deps->_PushDependency( + BaseObject => $self, + Flags => DEPENDS_ON | WIPE_AFTER, + TargetObject => $objs, + Shredder => $args{'Shredder'} + ); + } + +# Principal + $deps->_PushDependency( + BaseObject => $self, + Flags => DEPENDS_ON | WIPE_AFTER, + TargetObject => $self->PrincipalObj, + Shredder => $args{'Shredder'} + ); + +# Group members records + my $objs = RT::GroupMembers->new( $self->CurrentUser ); + $objs->LimitToMembersOfGroup( $self->PrincipalId ); + push( @$list, $objs ); + +# Group member records group belongs to + $objs = RT::GroupMembers->new( $self->CurrentUser ); + $objs->Limit( + VALUE => $self->PrincipalId, + FIELD => 'MemberId', + ENTRYAGGREGATOR => 'OR', + QUOTEVALUE => 0 + ); + push( @$list, $objs ); + +# Cached group members records + push( @$list, $self->DeepMembersObj ); + +# Cached group member records group belongs to + $objs = RT::GroupMembers->new( $self->CurrentUser ); + $objs->Limit( + VALUE => $self->PrincipalId, + FIELD => 'MemberId', + ENTRYAGGREGATOR => 'OR', + QUOTEVALUE => 0 + ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Equivalence group id inconsistent without User + if( $self->Domain eq 'ACLEquivalence' ) { + my $obj = RT::User->new($self->CurrentUser); + $obj->Load( $self->Instance ); + if( $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "ACLEguvivalence group have no related User #". $self->Instance ." object."; + } + } + +# Principal + my $obj = $self->PrincipalObj; + if( $obj && $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Principal #". $self->id ." object."; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +sub BeforeWipeout +{ + my $self = shift; + if( $self->Domain eq 'SystemInternal' ) { + RT::Shredder::Exception::Info->throw('SystemObject'); + } + return $self->SUPER::BeforeWipeout( @_ ); +} + +1; diff --git a/rt/lib/RT/Shredder/GroupMember.pm b/rt/lib/RT/Shredder/GroupMember.pm new file mode 100644 index 000000000..d8b002e87 --- /dev/null +++ b/rt/lib/RT/Shredder/GroupMember.pm @@ -0,0 +1,183 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::GroupMember (); +package RT::GroupMember; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +# No dependencies that should be deleted with record + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + my $objs = RT::CachedGroupMembers->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'MemberId', VALUE => $self->MemberId ); + $objs->Limit( FIELD => 'ImmediateParentId', VALUE => $self->GroupId ); + push( @$list, $objs ); + + # XXX: right delegations should be cleaned here + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + + my $group = $self->GroupObj->Object; + # XXX: If we delete member of the ticket owner role group then we should also + # fix ticket object, but only if we don't plan to delete group itself! + unless( ($group->Type || '') eq 'Owner' && + ($group->Domain || '') eq 'RT::Ticket-Role' ) { + return $self->SUPER::__DependsOn( %args ); + } + + # we don't delete group, so we have to fix Ticket and Group + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON | VARIABLE, + TargetObjects => $group, + Shredder => $args{'Shredder'} + ); + $args{'Shredder'}->PutResolver( + BaseClass => ref $self, + TargetClass => ref $group, + Code => sub { + my %args = (@_); + my $group = $args{'TargetObject'}; + return if $args{'Shredder'}->GetState( Object => $group ) & (WIPED|IN_WIPING); + return unless ($group->Type || '') eq 'Owner'; + return unless ($group->Domain || '') eq 'RT::Ticket-Role'; + + return if $group->MembersObj->Count > 1; + + my $group_member = $args{'BaseObject'}; + + if( $group_member->MemberObj->id == $RT::Nobody->id ) { + RT::Shredder::Exception->throw( "Couldn't delete Nobody from owners role group" ); + } + + my( $status, $msg ) = $group->AddMember( $RT::Nobody->id ); + RT::Shredder::Exception->throw( $msg ) unless $status; + + my $ticket = RT::Ticket->new( $group->CurrentUser ); + $ticket->Load( $group->Instance ); + RT::Shredder::Exception->throw( "Couldn't load ticket" ) unless $ticket->id; + + ( $status, $msg ) = $ticket->_Set( Field => 'Owner', + Value => $RT::Nobody->id, + ); + RT::Shredder::Exception->throw( $msg ) unless $status; + + return; + }, + ); + + return $self->SUPER::__DependsOn( %args ); +} + + +#TODO: If we plan write export tool we also should fetch parent groups +# now we only wipeout things. + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + my $obj = $self->MemberObj; + if( $obj && $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Principal #". $self->MemberId ." object."; + } + + $obj = $self->GroupObj; + if( $obj && $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Principal #". $self->GroupId ." object."; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/Link.pm b/rt/lib/RT/Shredder/Link.pm new file mode 100644 index 000000000..18cf4ed48 --- /dev/null +++ b/rt/lib/RT/Shredder/Link.pm @@ -0,0 +1,140 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Link (); +package RT::Link; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; +use RT::Shredder::Constants; + +use RT::Shredder::Transaction; +use RT::Shredder::Record; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# AddLink transactions + my $map = RT::Ticket->LINKTYPEMAP; + my $link_meta = $map->{ $self->Type }; + unless ( $link_meta && $link_meta->{'Mode'} && $link_meta->{'Type'} ) { + RT::Shredder::Exception->throw( 'Wrong link link_meta, no record for '. $self->Type ); + } + if ( $self->BaseURI->IsLocal ) { + my $objs = $self->BaseObj->Transactions; + $objs->Limit( + FIELD => 'Type', + OPERATOR => '=', + VALUE => 'AddLink', + ); + $objs->Limit( FIELD => 'NewValue', VALUE => $self->Target ); + while ( my ($k, $v) = each %$map ) { + next unless $v->{'Type'} eq $link_meta->{'Type'}; + next unless $v->{'Mode'} eq $link_meta->{'Mode'}; + $objs->Limit( FIELD => 'Field', VALUE => $k ); + } + push( @$list, $objs ); + } + + my %reverse = ( Base => 'Target', Target => 'Base' ); + if ( $self->TargetURI->IsLocal ) { + my $objs = $self->TargetObj->Transactions; + $objs->Limit( + FIELD => 'Type', + OPERATOR => '=', + VALUE => 'AddLink', + ); + $objs->Limit( FIELD => 'NewValue', VALUE => $self->Base ); + while ( my ($k, $v) = each %$map ) { + next unless $v->{'Type'} eq $link_meta->{'Type'}; + next unless $v->{'Mode'} eq $reverse{ $link_meta->{'Mode'} }; + $objs->Limit( FIELD => 'Field', VALUE => $k ); + } + push( @$list, $objs ); + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON|WIPE_AFTER, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +#TODO: Link record has small strength, but should be encountered +# if we plan write export tool. + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; +# FIXME: if link is local then object should exist + + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm b/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm new file mode 100644 index 000000000..1d3c97744 --- /dev/null +++ b/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm @@ -0,0 +1,116 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::ObjectCustomFieldValue (); +package RT::ObjectCustomFieldValue; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Ticket + my $obj = $self->TicketObj; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Ticket #". $self->id ." object"; + } + +# Custom Field + $obj = $self->CustomFieldObj; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related CustomField #". $self->id ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/POD.pm b/rt/lib/RT/Shredder/POD.pm new file mode 100644 index 000000000..a3538b3d5 --- /dev/null +++ b/rt/lib/RT/Shredder/POD.pm @@ -0,0 +1,131 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::POD; + +use strict; +use warnings; +use Pod::Select; + +sub plugin_html +{ + my ($file, $out_fh) = @_; + my $parser = new RT::Shredder::POD::HTML; + $parser->select('ARGUMENTS', 'USAGE'); + $parser->parse_from_file( $file, $out_fh ); +} + +sub plugin_cli +{ + my ($file, $out_fh, $no_name) = @_; + use Pod::PlainText; + local @Pod::PlainText::ISA = ('Pod::Select', @Pod::PlainText::ISA); + my $parser = new Pod::PlainText; + $parser->select('SYNOPSIS', 'ARGUMENTS', 'USAGE'); + $parser->add_selection('NAME') unless $no_name; + $parser->parse_from_file( $file, $out_fh ); +} + +sub shredder_cli +{ + my ($file, $out_fh) = @_; + use Pod::PlainText; + local @Pod::PlainText::ISA = ('Pod::Select', @Pod::PlainText::ISA); + my $parser = new Pod::PlainText; + $parser->select('NAME', 'SYNOPSIS', 'USAGE', 'OPTIONS'); + $parser->parse_from_file( $file, $out_fh ); +} + +package RT::Shredder::POD::HTML; +use base qw(Pod::Select); + +sub command +{ + my( $self, $command, $paragraph, $line_num ) = @_; + + my $tag; + if ($command =~ /^head(\d+)$/) { $tag = "h$1" } + my $out_fh = $self->output_handle(); + my $expansion = $self->interpolate($paragraph, $line_num); + $expansion =~ s/^\s+|\s+$//; + + print $out_fh "<$tag>" if $tag; + print $out_fh $expansion; + print $out_fh "</$tag>" if $tag; + print $out_fh "\n"; +} + +sub verbatim +{ + my ($self, $paragraph, $line_num) = @_; + my $out_fh = $self->output_handle(); + print $out_fh "<pre>"; + print $out_fh $paragraph; + print $out_fh "</pre>"; + print $out_fh "\n"; +} + +sub textblock { + my ($self, $paragraph, $line_num) = @_; + my $out_fh = $self->output_handle(); + my $expansion = $self->interpolate($paragraph, $line_num); + $expansion =~ s/^\s+|\s+$//; + print $out_fh "<p>"; + print $out_fh $expansion; + print $out_fh "</p>"; + print $out_fh "\n"; +} + +sub interior_sequence { + my ($self, $seq_command, $seq_argument) = @_; + ## Expand an interior sequence; sample actions might be: + return "<b>$seq_argument</b>" if $seq_command eq 'B'; + return "<i>$seq_argument</i>" if $seq_command eq 'I'; + return "<span class=\"pod-sequence-$seq_command\">$seq_argument</span>"; +} +1; diff --git a/rt/lib/RT/Shredder/Plugin.pm b/rt/lib/RT/Shredder/Plugin.pm new file mode 100644 index 000000000..4ba625894 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin.pm @@ -0,0 +1,249 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin; + +use strict; +use warnings FATAL => 'all'; +use File::Spec (); + +=head1 NAME + +RT::Shredder::Plugin - interface to access shredder plugins + +=head1 SYNOPSIS + + use RT::Shredder::Plugin; + + # get list of the plugins + my %plugins = RT::Shredder::Plugin->List; + + # load plugin by name + my $plugin = new RT::Shredder::Plugin; + my( $status, $msg ) = $plugin->LoadByName( 'Tickets' ); + unless( $status ) { + print STDERR "Couldn't load plugin 'Tickets': $msg\n"; + exit(1); + } + + # load plugin by preformatted string + my $plugin = new RT::Shredder::Plugin; + my( $status, $msg ) = $plugin->LoadByString( 'Tickets=status,deleted' ); + unless( $status ) { + print STDERR "Couldn't load plugin: $msg\n"; + exit(1); + } + +=head1 METHODS + +=head2 new + +Object constructor, returns new object. Takes optional hash +as arguments, it's not required and this class doesn't use it, +but plugins could define some arguments and can handle them +after your've load it. + +=cut + +sub new +{ + my $proto = shift; + my $self = bless( {}, ref $proto || $proto ); + $self->_Init( @_ ); + return $self; +} + +sub _Init +{ + my $self = shift; + my %args = ( @_ ); + $self->{'opt'} = \%args; +} + +=head2 List + +Returns hash with names of the available plugins as keys and path to +library files as values. Method has no arguments. Can be used as class +method too. + +Takes optional argument C<type> and leaves in the result hash only +plugins of that type. + +=cut + +sub List +{ + my $self = shift; + my $type = shift; + + my @files; + foreach my $root( @INC ) { + my $mask = File::Spec->catfile( $root, qw(RT Shredder Plugin *.pm) ); + push @files, glob $mask; + } + + my %res = map { $_ =~ m/([^\\\/]+)\.pm$/; $1 => $_ } reverse @files; + + return %res unless $type; + + delete $res{'Base'}; + foreach my $name( keys %res ) { + my $class = join '::', qw(RT Shredder Plugin), $name; + unless( eval "require $class" ) { + delete $res{ $name }; + next; + } + next if lc $class->Type eq lc $type; + delete $res{ $name }; + } + + return %res; +} + +=head2 LoadByName + +Takes name of the plugin as first argument, loads plugin, +creates new plugin object and reblesses self into plugin +if all steps were successfuly finished, then you don't need to +create new object for the plugin. + +Other arguments are sent to the constructor of the plugin +(method new.) + +Returns C<$status> and C<$message>. On errors status +is C<false> value. + +=cut + +sub LoadByName +{ + my $self = shift; + my $name = shift or return (0, "Name not specified"); + + local $@; + my $plugin = "RT::Shredder::Plugin::$name"; + eval "require $plugin" or return( 0, $@ ); + return( 0, "Plugin '$plugin' has no method new") unless $plugin->can('new'); + + my $obj = eval { $plugin->new( @_ ) }; + return( 0, $@ ) if $@; + return( 0, 'constructor returned empty object' ) unless $obj; + + $self->Rebless( $obj ); + return( 1, "successfuly load plugin" ); +} + +=head2 LoadByString + +Takes formatted string as first argument and which is used to +load plugin. The format of the string is + + <plugin name>[=<arg>,<val>[;<arg>,<val>]...] + +exactly like in the L<rt-shredder> script. All other +arguments are sent to the plugins constructor. + +Method does the same things as C<LoadByName>, but also +checks if the plugin supports arguments and values are correct, +so you can C<Run> specified plugin immediatly. + +Returns list with C<$status> and C<$message>. On errors status +is C<false>. + +=cut + +sub LoadByString +{ + my $self = shift; + my ($plugin, $args) = split /=/, ( shift || '' ), 2; + + my ($status, $msg) = $self->LoadByName( $plugin, @_ ); + return( $status, $msg ) unless $status; + + my %args; + foreach( split /\s*;\s*/, ( $args || '' ) ) { + my( $k,$v ) = split /\s*,\s*/, ( $_ || '' ), 2; + unless( $args{$k} ) { + $args{$k} = $v; + next; + } + + $args{$k} = [ $args{$k} ] unless UNIVERSAL::isa( $args{ $k }, 'ARRAY'); + push @{ $args{$k} }, $v; + } + + ($status, $msg) = $self->HasSupportForArgs( keys %args ); + return( $status, $msg ) unless $status; + + ($status, $msg) = $self->TestArgs( %args ); + return( $status, $msg ) unless $status; + + return( 1, "successfuly load plugin" ); +} + +=head2 Rebless + +Instance method that takes one object as argument and rebless +the current object into into class of the argument and copy data +of the former. Returns nothing. + +Method is used by C<Load*> methods to automaticaly rebless +C<RT::Shredder::Plugin> object into class of the loaded +plugin. + +=cut + +sub Rebless +{ + my( $self, $obj ) = @_; + bless( $self, ref $obj ); + %{$self} = %{$obj}; + return; +} + +1; diff --git a/rt/lib/RT/Shredder/Plugin/Attachments.pm b/rt/lib/RT/Shredder/Plugin/Attachments.pm new file mode 100644 index 000000000..36dbbcfb8 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Attachments.pm @@ -0,0 +1,141 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Attachments; + +use strict; +use warnings FATAL => 'all'; +use base qw(RT::Shredder::Plugin::Base::Search); + +=head1 NAME + +RT::Shredder::Plugin::Attachments - search plugin for wiping attachments. + +=head1 ARGUMENTS + +=head2 files_only - boolean value + +Search only file attachments. + +=head2 file - mask + +Search files with specific file name only. + +Example: '*.xl?' or '*.gif' + +=head2 longer - attachment content size + +Search attachments which content is longer than specified. +You can use trailing 'K' or 'M' character to specify size in +kilobytes or megabytes. + +=cut + +sub SupportArgs { return $_[0]->SUPER::SupportArgs, qw(files_only file longer) } + +sub TestArgs +{ + my $self = shift; + my %args = @_; + my $queue; + if( $args{'file'} ) { + unless( $args{'file'} =~ /^[\w\. *?]+$/) { + return( 0, "Files mask '$args{file}' has invalid characters" ); + } + $args{'file'} = $self->ConvertMaskToSQL( $args{'file'} ); + } + if( $args{'longer'} ) { + unless( $args{'longer'} =~ /^\d+\s*[mk]?$/i ) { + return( 0, "Invalid file size argument '$args{longer}'" ); + } + } + return $self->SUPER::TestArgs( %args ); +} + +sub Run +{ + my $self = shift; + my @conditions = (); + my @values = (); + if( $self->{'opt'}{'file'} ) { + my $mask = $self->{'opt'}{'file'}; + push @conditions, "( Filename LIKE ? )"; + push @values, $mask; + } + if( $self->{'opt'}{'files_only'} ) { + push @conditions, "( LENGTH(Filename) > 0 )"; + } + if( $self->{'opt'}{'longer'} ) { + my $size = $self->{'opt'}{'longer'}; + $size =~ s/([mk])//i; + $size *= 1024 if $1 && lc $1 eq 'k'; + $size *= 1024*1024 if $1 && lc $1 eq 'm'; + push @conditions, "( LENGTH(Content) > ? )"; + push @values, $size; + } + return (0, "At least one condition should be provided" ) unless @conditions; + my $query = "SELECT id FROM Attachments WHERE ". join ' AND ', @conditions; + if( $self->{'opt'}{'limit'} ) { + $RT::Handle->ApplyLimits( \$query, $self->{'opt'}{'limit'} ); + } + my $sth = $RT::Handle->SimpleQuery( $query, @values ); + return (0, "Internal error: '$sth'. Please send bug report.") unless $sth; + + my @objs; + while( my $row = $sth->fetchrow_arrayref ) { + push @objs, $row->[0]; + } + return (0, "Internal error: '". $sth->err ."'. Please send bug report.") if $sth->err; + + map { $_ = "RT::Attachment-$_" } @objs; + + return (1, @objs); +} + +1; + diff --git a/rt/lib/RT/Shredder/Plugin/Base.pm b/rt/lib/RT/Shredder/Plugin/Base.pm new file mode 100644 index 000000000..3e3e73b27 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Base.pm @@ -0,0 +1,188 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Base; + +use strict; +use warnings FATAL => 'all'; + +=head1 NAME + +RT::Shredder::Plugin::Base - base class for Shredder plugins. + +=cut + +sub new +{ + my $proto = shift; + my $self = bless( {}, ref $proto || $proto ); + $self->_Init( @_ ); + return $self; +} + +sub _Init +{ + my $self = shift; + $self->{'opt'} = { @_ }; +} + +=head1 USAGE + +=head2 masks + +If any argument is marked with keyword C<mask> then it means +that this argument support two special characters: + +1) C<*> matches any non empty sequence of the characters. +For example C<*@example.com> will match any email address in +C<example.com> domain. + +2) C<?> matches exactly one character. +For example C<????> will match any string four characters long. + +=head1 METHODS + +=head2 for subclassing in plugins + +=head3 Type - is not supported yet + +See F<Todo> for more info. + +=cut + +sub Type { return '' } + +=head3 SupportArgs + +Takes nothing. +Returns list of the supported plugin arguments. + +Base class returns list of the arguments which all +classes B<must> support. + +=cut + +sub SupportArgs { return () } + +=head3 HasSupportForArgs + +Takes a list of argument names. Returns true if +all arguments are supported by plugin and returns +C<(0, $msg)> in other case. + +=cut + +sub HasSupportForArgs +{ + my $self = shift; + my @args = @_; + my @unsupported = (); + foreach my $a( @args ) { + push @unsupported, $a unless grep $_ eq $a, $self->SupportArgs; + } + return( 1 ) unless @unsupported; + return( 0, "Plugin doesn't support argument(s): @unsupported" ) if @unsupported; +} + +=head3 TestArgs + +Takes hash with arguments and thier values and returns true +if all values pass testing otherwise returns C<(0, $msg)>. + +Stores arguments hash in C<$self->{'opt'}>, you can access this hash +from C<Run> method. + +Method should be subclassed if plugin support non standard arguments. + +=cut + +sub TestArgs +{ + my $self = shift; + my %args = @_; + if ( $self->{'opt'} ) { + $self->{'opt'} = { %{$self->{'opt'}}, %args }; + } else { + $self->{'opt'} = \%args; + } + return 1; +} + +=head3 Run + +Takes no arguments. +Executes plugin and return C<(1, @objs)> on success or +C<(0, $msg)> if error had happenned. + +Method B<must> be subclassed, this class always returns error. + +Method B<must> be called only after C<TestArgs> method in other +case values of the arguments are not available. + +=cut + +sub Run { return (0, "This is abstract plugin, you couldn't use it directly") } + +=head2 utils + +=head3 ConvertMaskToSQL + +Takes one argument - mask with C<*> and C<?> chars and +return mask SQL chars. + +=cut + +sub ConvertMaskToSQL { + my $self = shift; + my $mask = shift || ''; + $mask =~ s/\*/%/g; + $mask =~ s/\?/_/g; + return $mask; +} + +1; diff --git a/rt/lib/RT/Shredder/Plugin/Base/Dump.pm b/rt/lib/RT/Shredder/Plugin/Base/Dump.pm new file mode 100644 index 000000000..ecfc82e5c --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Base/Dump.pm @@ -0,0 +1,70 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Base::Dump; + +use strict; +use warnings FATAL => 'all'; + +use base qw(RT::Shredder::Plugin::Base); + +=head1 NAME + +RT::Shredder::Plugin::Base - base class for Shredder plugins. + +=cut + +sub Type { return 'dump' } +sub AppliesToStates { return () } +sub SupportArgs { return () } + +sub PushMark { return 1 } +sub PopMark { return 1 } +sub RollbackTo { return 1 } + +1; diff --git a/rt/lib/RT/Shredder/Plugin/Base/Search.pm b/rt/lib/RT/Shredder/Plugin/Base/Search.pm new file mode 100644 index 000000000..21de15982 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Base/Search.pm @@ -0,0 +1,142 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Base::Search; + +use strict; +use warnings FATAL => 'all'; + +use base qw(RT::Shredder::Plugin::Base); + +=head1 NAME + +RT::Shredder::Plugin::Base - base class for Shredder plugins. + +=cut + +sub Type { return 'search' } + +=head1 ARGUMENTS + +Arguments which all plugins support. + +=head2 limit - unsigned integer + +Allow you to limit search results. B<< Default value is C<10> >>. + +=head1 METHODS + +=cut + +sub SupportArgs +{ + my %seen; + return sort + grep $_ && !$seen{$_}, + shift->SUPER::SupportArgs(@_), + qw(limit); +} + +sub TestArgs +{ + my $self = shift; + my %args = @_; + if( defined $args{'limit'} && $args{'limit'} ne '' ) { + my $limit = $args{'limit'}; + $limit =~ s/[^0-9]//g; + unless( $args{'limit'} eq $limit ) { + return( 0, "'limit' should be an unsigned integer"); + } + $args{'limit'} = $limit; + } else { + $args{'limit'} = 10; + } + return $self->SUPER::TestArgs( %args ); +} + +sub SetResolvers { return 1 } + + +=head2 FetchNext $collection [, $init] + +Returns next object in collection as method L<RT::SearchBuilder/Next>, but +doesn't stop on page boundaries. + +When method is called with true C<$init> arg it enables pages on collection +and selects first page. + +Main purpose of this method is to avoid loading of whole collection into +memory as RT does by default when pager is not used. This method init paging +on the collection, but doesn't stop when reach page end. + +Example: + + $plugin->FetchNext( $tickets, 'init' ); + while( my $ticket = $plugin->FetchNext( $tickets ) ) { + ... + } + +=cut + +use constant PAGE_SIZE => 100; +sub FetchNext { + my ($self, $objs, $init) = @_; + if ( $init ) { + $objs->RowsPerPage( PAGE_SIZE ); + $objs->FirstPage; + return; + } + + my $obj = $objs->Next; + return $obj if $obj; + $objs->NextPage; + return $objs->Next; +} + +1; + diff --git a/rt/lib/RT/Shredder/Plugin/Objects.pm b/rt/lib/RT/Shredder/Plugin/Objects.pm new file mode 100644 index 000000000..fe2314ae8 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Objects.pm @@ -0,0 +1,107 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Objects; + +use strict; +use warnings FATAL => 'all'; +use base qw(RT::Shredder::Plugin::Base::Search); + +use RT::Shredder; + +=head1 NAME + +RT::Shredder::Plugin::Objects - search plugin for wiping any selected object. + +=head1 ARGUMENTS + +This plugin searches an RT object you want, so you can use +the object name as argument and id as value, for example if +you want select ticket #123 then from CLI you write next +command: + + rt-shredder --plugin 'Objects=Ticket,123' + +=cut + +sub SupportArgs +{ + return $_[0]->SUPER::SupportArgs, @RT::Shredder::SUPPORTED_OBJECTS; +} + +sub TestArgs +{ + my $self = shift; + my %args = @_; + + my @strings; + foreach my $name( @RT::Shredder::SUPPORTED_OBJECTS ) { + next unless $args{$name}; + + my $list = $args{$name}; + $list = [$list] unless UNIVERSAL::isa( $list, 'ARRAY' ); + push @strings, map "RT::$name\-$_", @$list; + } + + my @objs = RT::Shredder->CastObjectsToRecords( Objects => \@strings ); + + my @res = $self->SUPER::TestArgs( %args ); + + $self->{'opt'}->{'objects'} = \@objs; + + return (@res); +} + +sub Run +{ + my $self = shift; + my %args = ( Shredder => undef, @_ ); + return (1, @{$self->{'opt'}->{'objects'}}); +} + +1; diff --git a/rt/lib/RT/Shredder/Plugin/SQLDump.pm b/rt/lib/RT/Shredder/Plugin/SQLDump.pm new file mode 100644 index 000000000..cd3fa33d3 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/SQLDump.pm @@ -0,0 +1,96 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::SQLDump; + +use strict; +use warnings; + +use base qw(RT::Shredder::Plugin::Base::Dump); +use RT::Shredder; + +sub AppliesToStates { return 'after wiping dependencies' } + +sub SupportArgs +{ + my $self = shift; + return $self->SUPER::SupportArgs, qw(file_name from_storage); +} + +sub TestArgs +{ + my $self = shift; + my %args = @_; + $args{'from_storage'} = 1 unless defined $args{'from_storage'}; + my $file = $args{'file_name'} = RT::Shredder->GetFileName( + FileName => $args{'file_name'}, + FromStorage => delete $args{'from_storage'}, + ); + open $args{'file_handle'}, ">:raw", $file + or return (0, "Couldn't open '$file' for write: $!"); + + return $self->SUPER::TestArgs( %args ); +} + +sub FileName { return $_[0]->{'opt'}{'file_name'} } +sub FileHandle { return $_[0]->{'opt'}{'file_handle'} } + +sub Run +{ + my $self = shift; + return (0, 'no handle') unless my $fh = $self->{'opt'}{'file_handle'}; + + my %args = ( Object => undef, @_ ); + my $query = $args{'Object'}->_AsInsertQuery; + $query .= "\n" unless $query =~ /\n$/; + + return print $fh $query or return (0, "Couldn't write to filehandle"); + return 1; +} + +1; diff --git a/rt/lib/RT/Shredder/Plugin/Summary.pm b/rt/lib/RT/Shredder/Plugin/Summary.pm new file mode 100644 index 000000000..6ab76ba0b --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Summary.pm @@ -0,0 +1,188 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Summary; + +use strict; +use warnings FATAL => 'all'; + +use base qw(RT::Shredder::Plugin::SQLDump); + +sub AppliesToStates { return 'before any action' } + +sub TestArgs +{ + my $self = shift; + my %args = (file_name => '', @_); + unless( $args{'file_name'} ) { + require POSIX; + $args{'file_name'} = POSIX::strftime( "summary-%Y%m%dT%H%M%S.XXXX.txt", gmtime ); + } + return $self->SUPER::TestArgs( %args ); +} + +sub Run +{ + my $self = shift; + my %args = ( Object => undef, @_ ); + my $class = ref $args{'Object'}; + $class =~ s/^RT:://; + $class =~ s/:://g; + my $method = 'WriteDown'. $class; + $method = 'WriteDownDefault' unless $self->can($method); + return $self->$method( %args ); + return 1; +} + +my %skip_refs_to = (); + +sub WriteDownDefault { + my $self = shift; + my %args = ( Object => undef, @_ ); + return $self->_WriteDownHash( + $args{'Object'}, + $self->_MakeHash( $args{'Object'} ), + ); +} + +# TODO: cover other objects +# ACE.pm +# Attachment.pm +# CustomField.pm +# CustomFieldValue.pm +# GroupMember.pm +# Group.pm +# Link.pm +# ObjectCustomFieldValue.pm +# Principal.pm +# Queue.pm +# Ticket.pm +# User.pm + +# ScripAction.pm - works fine with defaults +# ScripCondition.pm - works fine with defaults +# Template.pm - works fine with defaults + +sub WriteDownCachedGroupMember { return 1 } +sub WriteDownPrincipal { return 1 } + +sub WriteDownGroup { + my $self = shift; + my %args = ( Object => undef, @_ ); + if ( $args{'Object'}->Domain =~ /-Role$/ ) { + return $skip_refs_to{ $args{'Object'}->_AsString } = 1; + } + return $self->WriteDownDefault( %args ); +} + +sub WriteDownTransaction { + my $self = shift; + my %args = ( Object => undef, @_ ); + + my $props = $self->_MakeHash( $args{'Object'} ); + $props->{'Object'} = delete $props->{'ObjectType'}; + $props->{'Object'} .= '-'. delete $props->{'ObjectId'} + if $props->{'ObjectId'}; + return 1 if $skip_refs_to{ $props->{'Object'} }; + + delete $props->{$_} foreach grep + !defined $props->{$_} || $props->{$_} eq '', keys %$props; + + return $self->_WriteDownHash( $args{'Object'}, $props ); +} + +sub WriteDownScrip { + my $self = shift; + my %args = ( Object => undef, @_ ); + my $props = $self->_MakeHash( $args{'Object'} ); + $props->{'Action'} = $args{'Object'}->ActionObj->Name; + $props->{'Condition'} = $args{'Object'}->ConditionObj->Name; + $props->{'Template'} = $args{'Object'}->TemplateObj->Name; + $props->{'Queue'} = $args{'Object'}->QueueObj->Name || 'global'; + + return $self->_WriteDownHash( $args{'Object'}, $props ); +} + +sub _MakeHash { + my ($self, $obj) = @_; + my $hash = $self->__MakeHash( $obj ); + foreach (grep exists $hash->{$_}, qw(Creator LastUpdatedBy)) { + my $method = $_ .'Obj'; + my $u = $obj->$method(); + $hash->{ $_ } = $u->EmailAddress || $u->Name || $u->_AsString; + } + return $hash; +} + +sub __MakeHash { + my ($self, $obj) = @_; + my %hash; + $hash{ $_ } = $obj->$_() + foreach sort keys %{ $obj->_ClassAccessible }; + return \%hash; +} + +sub _WriteDownHash { + my ($self, $obj, $hash) = @_; + return (0, 'no handle') unless my $fh = $self->{'opt'}{'file_handle'}; + + print $fh "=== ". $obj->_AsString ." ===\n" + or return (0, "Couldn't write to filehandle"); + + foreach my $key( sort keys %$hash ) { + my $val = $hash->{ $key }; + next unless defined $val; + $val =~ s/\n/\n /g; + print $fh $key .': '. $val ."\n" + or return (0, "Couldn't write to filehandle"); + } + print $fh "\n" or return (0, "Couldn't write to filehandle"); + return 1; +} + +1; diff --git a/rt/lib/RT/Shredder/Plugin/Tickets.pm b/rt/lib/RT/Shredder/Plugin/Tickets.pm new file mode 100644 index 000000000..ebbfb3e2a --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Tickets.pm @@ -0,0 +1,153 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Tickets; + +use strict; +use warnings FATAL => 'all'; +use base qw(RT::Shredder::Plugin::Base::Search); + +=head1 NAME + +RT::Shredder::Plugin::Tickets - search plugin for wiping tickets. + +=head1 ARGUMENTS + +=head2 query - query string + +Search tickets with query string. +Examples: + Queue = 'my queue' AND ( Status = 'deleted' OR Status = 'rejected' ) + LastUpdated < '2003-12-31 23:59:59' + +B<Hint:> You can construct query with the query builder in RT's web +interface and then open advanced page and copy query string. + +Arguments C<queue>, C<status> and C<updated_before> have been dropped +as you can easy make the same search with the C<query> option. +See examples above. + +=head2 with_linked - boolen + +Deletes all tickets that are linked to tickets that match L<query>. + +=head2 apply_query_to_linked - boolean + +Delete linked tickets only if those too match L<query>. + +See also L<with_linked>. + +=cut + +sub SupportArgs { return $_[0]->SUPER::SupportArgs, qw(query with_linked apply_query_to_linked) } + +sub TestArgs +{ + my $self = shift; + my %args = @_; + my $queue; + if( $args{'query'} ) { + my $objs = RT::Tickets->new( $RT::SystemUser ); + $objs->{'allow_deleted_search'} = 1; + my ($status, $msg) = $objs->FromSQL( $args{'query'} ); + return( 0, "Bad query argument, error: $msg" ) unless $status; + $self->{'opt'}{'objects'} = $objs; + } + $args{'with_linked'} = 1 if $args{'apply_query_to_linked'}; + + return $self->SUPER::TestArgs( %args ); +} + +sub Run +{ + my $self = shift; + my $objs = $self->{'opt'}{'objects'} + or return (1, undef); + + $objs->OrderByCols( { FIELD => 'id', ORDER => 'ASC' } ); + unless ( $self->{'opt'}{'with_linked'} ) { + if( $self->{'opt'}{'limit'} ) { + $objs->RowsPerPage( $self->{'opt'}{'limit'} ); + } + return (1, $objs); + } + + my (@top, @linked, %seen); + $self->FetchNext($objs, 1); + while ( my $obj = $self->FetchNext( $objs ) ) { + next if $seen{ $obj->id }++; + push @linked, $self->GetLinked( Object => $obj, Seen => \%seen ); + push @top, $obj; + last if $self->{'opt'}{'limit'} + && @top >= $self->{'opt'}{'limit'}; + } + return (1, @top, @linked); +} + +sub GetLinked +{ + my $self = shift; + my %arg = @_; + my @res = (); + my $query = 'Linked = '. $arg{'Object'}->id; + if ( $self->{'opt'}{'apply_query_to_linked'} ) { + $query .= " AND ( ". $self->{'opt'}{'query'} ." )"; + } + my $objs = RT::Tickets->new( $RT::SystemUser ); + $objs->{'allow_deleted_search'} = 1; + $objs->FromSQL( $query ); + $self->FetchNext( $objs, 1 ); + while ( my $linked_obj = $self->FetchNext( $objs ) ) { + next if $arg{'Seen'}->{ $linked_obj->id }++; + push @res, $self->GetLinked( %arg, Object => $linked_obj ); + push @res, $linked_obj; + } + return @res; +} + +1; diff --git a/rt/lib/RT/Shredder/Plugin/Users.pm b/rt/lib/RT/Shredder/Plugin/Users.pm new file mode 100644 index 000000000..2565fc546 --- /dev/null +++ b/rt/lib/RT/Shredder/Plugin/Users.pm @@ -0,0 +1,260 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Shredder::Plugin::Users; + +use strict; +use warnings FATAL => 'all'; +use base qw(RT::Shredder::Plugin::Base::Search); + +=head1 NAME + +RT::Shredder::Plugin::Users - search plugin for wiping users. + +=head1 ARGUMENTS + +=head2 status - string + +Status argument allow you to limit result set to C<disabled>, +C<enabled> or C<any> users. +B<< Default value is C<disabled>. >> + +=head2 name - mask + +User name mask. + +=head2 email - mask + +Email address mask. + +=head2 member_of - group identifier + +Using this option users that are members of a particular group can +be selected for deletion. Identifier is name of user defined group +or id of a group, as well C<Privileged> or <unprivileged> can used +to select people from system groups. + +=head2 replace_relations - user identifier + +When you delete user there are could be minor links to him in RT DB. +This option allow you to replace this links with link to other user. +This links are Creator and LastUpdatedBy, but NOT any watcher roles, +this means that if user is watcher(Requestor, Owner, +Cc or AdminCc) of the ticket or queue then link would be deleted. + +This argument could be user id or name. + +=head2 no_tickets - boolean + +If true then plugin looks for users who are not watchers (Owners, +Requestors, Ccs or AdminCcs) of any ticket. + +Before RT 3.8.5, users who were watchers of deleted tickets B<will be deleted> +when this option was enabled. Decision has been made that it's not correct +and you should either shred these deleted tickets, change watchers or +explicitly delete user by name or email. + +Note that found users still B<may have relations> with other objects, +for example via Creator or LastUpdatedBy fields, and you most probably +want to use C<replace_relations> option. + +=cut + +sub SupportArgs +{ + return $_[0]->SUPER::SupportArgs, + qw(status name email member_of replace_relations no_tickets); +} + +sub TestArgs +{ + my $self = shift; + my %args = @_; + if( $args{'status'} ) { + unless( $args{'status'} =~ /^(disabled|enabled|any)$/i ) { + return (0, "Status '$args{'status'}' is unsupported."); + } + } else { + $args{'status'} = 'disabled'; + } + if( $args{'email'} ) { + $args{'email'} = $self->ConvertMaskToSQL( $args{'email'} ); + } + if( $args{'name'} ) { + $args{'name'} = $self->ConvertMaskToSQL( $args{'name'} ); + } + if( $args{'member_of'} ) { + my $group = RT::Group->new( $RT::SystemUser ); + if ( $args{'member_of'} =~ /^(Everyone|Privileged|Unprivileged)$/i ) { + $group->LoadSystemInternalGroup( $args{'member_of'} ); + } + else { + $group->LoadUserDefinedGroup( $args{'member_of'} ); + } + unless ( $group->id ) { + return (0, "Couldn't load group '$args{'member_of'}'" ); + } + $args{'member_of'} = $group->id; + + } + if( $args{'replace_relations'} ) { + my $uid = $args{'replace_relations'}; + # XXX: it's possible that SystemUser is not available + my $user = RT::User->new( $RT::SystemUser ); + $user->Load( $uid ); + unless( $user->id ) { + return (0, "Couldn't load user '$uid'" ); + } + $args{'replace_relations'} = $user->id; + } + return $self->SUPER::TestArgs( %args ); +} + +sub Run +{ + my $self = shift; + my %args = ( Shredder => undef, @_ ); + my $objs = RT::Users->new( $RT::SystemUser ); + # XXX: we want preload only things we need, but later while + # logging we need all data, TODO envestigate this + # $objs->Columns(qw(id Name EmailAddress Lang Timezone + # Creator Created LastUpdated LastUpdatedBy)); + if( my $s = $self->{'opt'}{'status'} ) { + if( $s eq 'any' ) { + $objs->{'find_disabled_rows'} = 1; + } elsif( $s eq 'disabled' ) { + $objs->{'find_disabled_rows'} = 1; + $objs->Limit( + ALIAS => $objs->PrincipalsAlias, + FIELD => 'Disabled', + OPERATOR => '!=', + VALUE => '0', + ); + } else { + $objs->LimitToEnabled; + } + } + if( $self->{'opt'}{'email'} ) { + $objs->Limit( FIELD => 'EmailAddress', + OPERATOR => 'MATCHES', + VALUE => $self->{'opt'}{'email'}, + ); + } + if( $self->{'opt'}{'name'} ) { + $objs->Limit( FIELD => 'Name', + OPERATOR => 'MATCHES', + VALUE => $self->{'opt'}{'name'}, + ); + } + if( $self->{'opt'}{'member_of'} ) { + $objs->MemberOfGroup( $self->{'opt'}{'member_of'} ); + } + if( $self->{'opt'}{'no_tickets'} ) { + return $self->FilterWithoutTickets( + Shredder => $args{'Shredder'}, + Objects => $objs, + ); + } else { + if( $self->{'opt'}{'limit'} ) { + $objs->RowsPerPage( $self->{'opt'}{'limit'} ); + } + } + return (1, $objs); +} + +sub SetResolvers +{ + my $self = shift; + my %args = ( Shredder => undef, @_ ); + + if( $self->{'opt'}{'replace_relations'} ) { + my $uid = $self->{'opt'}{'replace_relations'}; + my $resolver = sub { + my %args = (@_); + my $t = $args{'TargetObject'}; + foreach my $method ( qw(Creator LastUpdatedBy) ) { + next unless $t->_Accessible( $method => 'read' ); + $t->__Set( Field => $method, Value => $uid ); + } + }; + $args{'Shredder'}->PutResolver( BaseClass => 'RT::User', Code => $resolver ); + } + return (1); +} + +sub FilterWithoutTickets { + my $self = shift; + my %args = ( + Shredder => undef, + Objects => undef, + @_, + ); + my $users = $args{Objects}; + $self->FetchNext( $users, 'init' ); + + my @res; + while ( my $user = $self->FetchNext( $users ) ) { + push @res, $user if $self->_WithoutTickets( $user ); + return (1, \@res) if $self->{'opt'}{'limit'} && @res >= $self->{'opt'}{'limit'}; + } + return (1, \@res); +} + +sub _WithoutTickets { + my ($self, $user) = @_; + my $tickets = RT::Tickets->new( $RT::SystemUser ); + $tickets->{'allow_deleted_search'} = 1; + $tickets->FromSQL( 'Watcher.id = '. $user->id ); + # HACK: we may use Count method which counts all records + # that match condtion, but we really want to know only that + # at least one record exist, so we fetch first row only + $tickets->RowsPerPage(1); + return !$tickets->First; +} + +1; diff --git a/rt/lib/RT/Shredder/Principal.pm b/rt/lib/RT/Shredder/Principal.pm new file mode 100644 index 000000000..cc5cd0e26 --- /dev/null +++ b/rt/lib/RT/Shredder/Principal.pm @@ -0,0 +1,127 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Principal (); +package RT::Principal; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Exceptions; +use RT::Shredder::Constants; +use RT::Shredder::Dependencies; + + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Group or User +# Could be wiped allready + my $obj = $self->Object; + if( defined $obj->id ) { + push( @$list, $obj ); + } + +# Access Control List + my $objs = RT::ACL->new( $self->CurrentUser ); + $objs->Limit( + FIELD => 'PrincipalId', + OPERATOR => '=', + VALUE => $self->Id + ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + my $obj = $self->Object; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related ". $self->Type ." #". $self->id ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/Queue.pm b/rt/lib/RT/Shredder/Queue.pm new file mode 100644 index 000000000..4ab381559 --- /dev/null +++ b/rt/lib/RT/Shredder/Queue.pm @@ -0,0 +1,106 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Queue (); +package RT::Queue; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Tickets + my $objs = RT::Tickets->new( $self->CurrentUser ); + $objs->{'allow_deleted_search'} = 1; + $objs->Limit( FIELD => 'Queue', VALUE => $self->Id ); + push( @$list, $objs ); + +# Queue role groups( Cc, AdminCc ) + $objs = RT::Groups->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'Domain', VALUE => 'RT::Queue-Role' ); + $objs->Limit( FIELD => 'Instance', VALUE => $self->Id ); + push( @$list, $objs ); + +# Scrips + $objs = RT::Scrips->new( $self->CurrentUser ); + $objs->LimitToQueue( $self->id ); + push( @$list, $objs ); + +# Templates + $objs = $self->Templates; + push( @$list, $objs ); + +# Custom Fields + $objs = RT::CustomFields->new( $self->CurrentUser ); + $objs->LimitToQueue( $self->id ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__DependsOn( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/Record.pm b/rt/lib/RT/Shredder/Record.pm new file mode 100644 index 000000000..94208a2ad --- /dev/null +++ b/rt/lib/RT/Shredder/Record.pm @@ -0,0 +1,273 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Record (); +package RT::Record; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; + +=head2 _AsString + +Returns string in format ClassName-ObjectId. + +=cut + +sub _AsString { return ref($_[0]) ."-". $_[0]->id } + +=head2 _AsInsertQuery + +Returns INSERT query string that duplicates current record and +can be used to insert record back into DB after delete. + +=cut + +sub _AsInsertQuery +{ + my $self = shift; + + my $dbh = $RT::Handle->dbh; + + my $res = "INSERT INTO ". $dbh->quote_identifier( $self->Table ); + my $values = $self->{'values'}; + $res .= "(". join( ",", map { $dbh->quote_identifier( $_ ) } sort keys %$values ) .")"; + $res .= " VALUES"; + $res .= "(". join( ",", map { $dbh->quote( $values->{$_} ) } sort keys %$values ) .")"; + $res .= ";"; + + return $res; +} + +sub BeforeWipeout { return 1 } + +=head2 Dependencies + +Returns L<RT::Shredder::Dependencies> object. + +=cut + +sub Dependencies +{ + my $self = shift; + my %args = ( + Shredder => undef, + Flags => DEPENDS_ON, + @_, + ); + + unless( $self->id ) { + RT::Shredder::Exception->throw('Object is not loaded'); + } + + my $deps = RT::Shredder::Dependencies->new(); + if( $args{'Flags'} & DEPENDS_ON ) { + $self->__DependsOn( %args, Dependencies => $deps ); + } + if( $args{'Flags'} & RELATES ) { + $self->__Relates( %args, Dependencies => $deps ); + } + return $deps; +} + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Object custom field values + my $objs = $self->CustomFieldValues; + $objs->{'find_expired_rows'} = 1; + push( @$list, $objs ); + +# Object attributes + $objs = $self->Attributes; + push( @$list, $objs ); + +# Transactions + $objs = RT::Transactions->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'ObjectType', VALUE => ref $self ); + $objs->Limit( FIELD => 'ObjectId', VALUE => $self->id ); + push( @$list, $objs ); + +# Links + if ( $self->can('_Links') ) { + # XXX: We don't use Links->Next as it's dies when object + # is linked to object that doesn't exist + # also, ->Next skip links to deleted tickets :( + foreach ( qw(Base Target) ) { + my $objs = $self->_Links( $_ ); + $objs->_DoSearch; + push @$list, $objs->ItemsArrayRef; + } + } + +# ACE records + $objs = RT::ACL->new( $self->CurrentUser ); + $objs->LimitToObject( $self ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return; +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + + if( $self->_Accessible( 'Creator', 'read' ) ) { + my $obj = RT::Principal->new( $self->CurrentUser ); + $obj->Load( $self->Creator ); + + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + push @{ $rec->{'Description'} }, + "Have no related User(Creator) #". $self->Creator ." object"; + } + } + + if( $self->_Accessible( 'LastUpdatedBy', 'read' ) ) { + my $obj = RT::Principal->new( $self->CurrentUser ); + $obj->Load( $self->LastUpdatedBy ); + + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + push @{ $rec->{'Description'} }, + "Have no related User(LastUpdatedBy) #". $self->LastUpdatedBy ." object"; + } + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + + # cause of this $self->SUPER::__Relates should be called last + # in overridden subs + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $rec->{'State'} |= VALID unless( $rec->{'State'} & INVALID ); + + return; +} + +# implement proxy method because some RT classes +# override Delete method +sub __Wipeout +{ + my $self = shift; + my $msg = $self->_AsString ." wiped out"; + $self->SUPER::Delete; + $RT::Logger->info( $msg ); + return; +} + +sub ValidateRelations +{ + my $self = shift; + my %args = ( + Shredder => undef, + @_ + ); + unless( $args{'Shredder'} ) { + $args{'Shredder'} = new RT::Shredder(); + } + + my $rec = $args{'Shredder'}->PutObject( Object => $self ); + return if( $rec->{'State'} & VALID ); + $self = $rec->{'Object'}; + + $self->_ValidateRelations( %args, Flags => RELATES ); + $rec->{'State'} |= VALID unless( $rec->{'State'} & INVALID ); + + return; +} + +sub _ValidateRelations +{ + my $self = shift; + my %args = ( @_ ); + + my $deps = $self->Dependencies( %args ); + + $deps->ValidateRelations( %args ); + + return; +} + +1; diff --git a/rt/lib/RT/Shredder/Scrip.pm b/rt/lib/RT/Shredder/Scrip.pm new file mode 100644 index 000000000..2cf7244b7 --- /dev/null +++ b/rt/lib/RT/Shredder/Scrip.pm @@ -0,0 +1,130 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Scrip (); +package RT::Scrip; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# No dependencies that should be deleted with record +# Scrip actions and conditions should be exported in feature with it. + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Queue + my $obj = $self->QueueObj; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Queue #". $self->id ." object"; + } + +# Condition + $obj = $self->ConditionObj; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related ScripCondition #". $self->id ." object"; + } +# Action + $obj = $self->ActionObj; + if( defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related ScripAction #". $self->id ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/ScripAction.pm b/rt/lib/RT/Shredder/ScripAction.pm new file mode 100644 index 000000000..9ecfc7613 --- /dev/null +++ b/rt/lib/RT/Shredder/ScripAction.pm @@ -0,0 +1,100 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::ScripAction (); +package RT::ScripAction; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Scrips + my $objs = RT::Scrips->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'ScripAction', VALUE => $self->Id ); + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $objs, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# TODO: Check here for exec module + + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/ScripCondition.pm b/rt/lib/RT/Shredder/ScripCondition.pm new file mode 100644 index 000000000..48b8620ff --- /dev/null +++ b/rt/lib/RT/Shredder/ScripCondition.pm @@ -0,0 +1,101 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::ScripCondition (); +package RT::ScripCondition; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Scrips + my $objs = RT::Scrips->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'ScripCondition', VALUE => $self->Id ); + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $objs, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# TODO: Check here for exec module + + return $self->SUPER::__Relates( %args ); +} + + +1; diff --git a/rt/lib/RT/Shredder/Template.pm b/rt/lib/RT/Shredder/Template.pm new file mode 100644 index 000000000..db2c4c7a3 --- /dev/null +++ b/rt/lib/RT/Shredder/Template.pm @@ -0,0 +1,120 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Template (); +package RT::Template; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Scrips + my $objs = RT::Scrips->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'Template', VALUE => $self->Id ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'}, + ); + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Queue + my $obj = $self->QueueObj; + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Queue #". $self->id ." object"; + } + +# TODO: Users(Creator, LastUpdatedBy) + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/Ticket.pm b/rt/lib/RT/Shredder/Ticket.pm new file mode 100644 index 000000000..cacae2438 --- /dev/null +++ b/rt/lib/RT/Shredder/Ticket.pm @@ -0,0 +1,126 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Ticket (); +package RT::Ticket; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Tickets which were merged in + my $objs = RT::Tickets->new( $self->CurrentUser ); + $objs->{'allow_deleted_search'} = 1; + $objs->Limit( FIELD => 'EffectiveId', VALUE => $self->Id ); + $objs->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->Id ); + push( @$list, $objs ); + +# Ticket role groups( Owner, Requestors, Cc, AdminCc ) + $objs = RT::Groups->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'Domain', VALUE => 'RT::Ticket-Role' ); + $objs->Limit( FIELD => 'Instance', VALUE => $self->Id ); + push( @$list, $objs ); + +#TODO: Users, Queues if we wish export tool + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Queue + my $obj = $self->QueueObj; + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Queue #". $self->Queue ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/Transaction.pm b/rt/lib/RT/Shredder/Transaction.pm new file mode 100644 index 000000000..cdd6c3e69 --- /dev/null +++ b/rt/lib/RT/Shredder/Transaction.pm @@ -0,0 +1,115 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::Transaction (); +package RT::Transaction; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Attachments + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $self->Attachments, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Ticket + my $obj = $self->TicketObj; + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Ticket #". $self->id ." object"; + } + +# TODO: Users(Creator, LastUpdatedBy) + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +1; diff --git a/rt/lib/RT/Shredder/User.pm b/rt/lib/RT/Shredder/User.pm new file mode 100644 index 000000000..d17860a6a --- /dev/null +++ b/rt/lib/RT/Shredder/User.pm @@ -0,0 +1,191 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +use RT::User (); +package RT::User; + +use strict; +use warnings; +use warnings FATAL => 'redefine'; + +use RT::Shredder::Constants; +use RT::Shredder::Exceptions; +use RT::Shredder::Dependencies; + +my @OBJECTS = qw( + Attachments + CachedGroupMembers + CustomFields + CustomFieldValues + GroupMembers + Groups + Links + Principals + Queues + ScripActions + ScripConditions + Scrips + Templates + ObjectCustomFieldValues + Tickets + Transactions + Users +); + +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Principal + $deps->_PushDependency( + BaseObject => $self, + Flags => DEPENDS_ON | WIPE_AFTER, + TargetObject => $self->PrincipalObj, + Shredder => $args{'Shredder'} + ); + +# ACL equivalence group +# don't use LoadACLEquivalenceGroup cause it may not exists any more + my $objs = RT::Groups->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'Domain', VALUE => 'ACLEquivalence' ); + $objs->Limit( FIELD => 'Instance', VALUE => $self->Id ); + push( @$list, $objs ); + +# Cleanup user's membership + $objs = RT::GroupMembers->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'MemberId', VALUE => $self->Id ); + push( @$list, $objs ); + + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + +# TODO: Almost all objects has Creator, LastUpdatedBy and etc. fields +# which are references on users(Principal actualy) + my @var_objs; + foreach( @OBJECTS ) { + my $class = "RT::$_"; + foreach my $method ( qw(Creator LastUpdatedBy) ) { + my $objs = $class->new( $self->CurrentUser ); + next unless $objs->NewItem->_Accessible( $method => 'read' ); + $objs->Limit( FIELD => $method, VALUE => $self->id ); + push @var_objs, $objs; + } + } + $deps->_PushDependencies( + BaseObject => $self, + Flags => DEPENDS_ON | VARIABLE, + TargetObjects => \@var_objs, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} + +sub __Relates +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# Principal + my $obj = $self->PrincipalObj; + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related ACL equivalence Group object"; + } + + $obj = RT::Group->new( $RT::SystemUser ); + $obj->LoadACLEquivalenceGroup( $self->PrincipalObj ); + if( $obj && defined $obj->id ) { + push( @$list, $obj ); + } else { + my $rec = $args{'Shredder'}->GetRecord( Object => $self ); + $self = $rec->{'Object'}; + $rec->{'State'} |= INVALID; + $rec->{'Description'} = "Have no related Principal #". $self->id ." object"; + } + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RELATES, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + return $self->SUPER::__Relates( %args ); +} + +sub BeforeWipeout +{ + my $self = shift; + if( $self->Name =~ /^(RT_System|Nobody)$/ ) { + RT::Shredder::Exception::Info->throw('SystemObject'); + } + return $self->SUPER::BeforeWipeout( @_ ); +} + +1; |