RTx::Shredder::Plugin::Users - search plugin for wiping users.


RTx-Shredder documentation Contained in the RTx-Shredder distribution.

Index


Code Index:

NAME

Top

RTx::Shredder::Plugin::Users - search plugin for wiping users.

ARGUMENTS

Top

status - string

Status argument allow you to limit result set to disabled, enabled or any users. Default value is disabled.

name - mask

User name mask.

email - mask

Email address mask.

replace_relations - user identifier

When you delete user there is 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 mean 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.

no_tickets - boolean

If true then plugin looks for users who are not watchers (Owners, Requestors, Ccs or AdminCcs) of any ticket.

Note that found users still may have relations with other objects and you most probably want to use replace_relations option.


RTx-Shredder documentation Contained in the RTx-Shredder distribution.
package RTx::Shredder::Plugin::Users;

use strict;
use warnings FATAL => 'all';
use base qw(RTx::Shredder::Plugin::Base);

sub Type { return 'search' }

sub SupportArgs
{
    return $_[0]->SUPER::SupportArgs,
           qw(status name email 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{'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 );
    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'}{'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);
}

use constant PAGE_SIZE => 100;

sub FetchNext {
    my ($self, $objs, $init) = @_;
    if ( $init ) {
        $objs->RowsPerPage( PAGE_SIZE );
        $objs->FirstPage;
        return;
    }

    for (1..3) {
        my $obj = $objs->Next;
        return $obj if $obj;
        $objs->NextPage;
    }
}

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->FromSQL( 'Watcher.id = '. $user->id );
    # HACK: Count - is count all that match condtion,
    # but we really want to know if at least one record record exist,
    # so we fetch first only
    $tickets->RowsPerPage(1);
    return !$tickets->First;
}

1;