#!/usr/bin/perl
=head1 NAME
rt-notify-group-admin - Command line tool for administrating NotifyGroup actions
=head1 SYNOPSIS
rt-notify-group-admin --list
rt-notify-group-admin --create 'Notify foo team' --group Foo
rt-notify-group-admin --create 'Notify foo team as comment' --comment --group Foo
rt-notify-group-admin --create 'Notify group Foo and Bar' --group Foo --group Bar
rt-notify-group-admin --create 'Notify user foo@bar.com' --user foo@bar.com
rt-notify-group-admin --create 'Notify VIPs' --user vip1@bar.com
rt-notify-group-admin --add 'Notify VIPs' --user vip2@bar.com --group vip1 --user vip3@foo.com
rt-notify-group-admin --rename 'Notify VIPs' --newname 'Inform VIPs'
rt-notify-group-admin --switch 'Notify VIPs'
rt-notify-group-admin --delete 'Notify user foo@bar.com'
=head1 DESCRIPTION
rt-notify-group-admin
=cut
use strict;
### replace: use lib qw(@RT_LIB_PATH@);
use lib qw(/opt/rt3/local/lib /opt/rt3/lib);
use RT;
RT::LoadConfig;
RT::Init;
require RT::Principal;
require RT::User;
require RT::Group;
require Storable;
use Getopt::Long qw(GetOptions);
our $cmd = 'usage';
our $opts = {};
sub parse_args
{
my $tmp;
Getopt::Long::Configure( "pass_through" );
if( GetOptions( 'list' => \$tmp ) && $tmp ) {
$cmd = 'list';
} elsif( GetOptions( 'create=s' => \$tmp ) && $tmp ) {
$cmd = 'create';
$opts->{'name'} = $tmp;
$opts->{'groups'} = [];
$opts->{'users'} = [];
GetOptions( 'comment' => \$opts->{'comment'} );
GetOptions( 'group:s@' => $opts->{'groups'} );
GetOptions( 'user:s@' => $opts->{'users'} );
unless( @{ $opts->{'users'} } + @{ $opts->{'groups'} } ) {
usage();
exit(-1);
}
} elsif( GetOptions( 'add=s' => \$tmp ) && $tmp ) {
$cmd = 'add';
$opts->{'name'} = $tmp;
$opts->{'groups'} = [];
$opts->{'users'} = [];
GetOptions( 'group:s@' => $opts->{'groups'} );
GetOptions( 'user:s@' => $opts->{'users'} );
unless( @{ $opts->{'users'} } + @{ $opts->{'groups'} } ) {
usage();
exit(-1);
}
} elsif( GetOptions( 'switch=s' => \$tmp ) && $tmp ) {
$cmd = 'switch';
$opts->{'name'} = $tmp;
} elsif( GetOptions( 'rename=s' => \$tmp ) && $tmp ) {
$cmd = 'rename';
$opts->{'name'} = $tmp;
GetOptions( 'newname=s' => \$opts->{'newname'} );
unless( $opts->{'newname'} ) {
usage();
exit(-1);
}
} elsif( GetOptions( 'delete=s' => \$tmp ) && $tmp) {
$cmd = 'delete';
$opts->{'name'} = $tmp;
} else {
$cmd = 'usage';
}
return;
}
sub usage
{
eval "require Pod::PlainText;";
if( $@ ) {
print "see `perldoc $0`\n";
} else {
my $parser = Pod::PlainText->new (sentence => 0, width => 78);
$parser->parse_from_file( $0 );
}
}
parse_args();
{
eval "main::$cmd()";
if( $@ ) {
print STDERR $@ ."\n";
}
}
exit(0);
=head1 USAGE
rt-notify-group-admin --COMMAND ARGS
=head1 COMMANDS
=head2 list
Lists actions and its descriptions.
=cut
sub list
{
my $actions = _get_our_actions();
while( my $a = $actions->Next ) {
_list( $a );
}
return;
}
sub _list
{
my $action = shift;
print "Name: ". $action->Name() ."\n";
print "Module: ". $action->ExecModule() ."\n";
my $arg = $action->Argument;
# old variant via Storable
my $old = eval { Storable::thaw( $arg ) };
unless( $@ ) {
$arg = __convert_old($old);
}
my @princ = _split_arg( $arg );
print "Members: \n";
foreach( @princ ) {
my $obj = RT::Principal->new( $RT::SystemUser );
$obj->Load( $_ );
next unless( $obj->id );
print "\t". $obj->PrincipalType;
print "\t=> ". $obj->Object->Name;
print "(Disabled!!!)" if $obj->Disabled;
print "\n";
}
print "\n";
return;
}
=head2 create NAME [--comment] [--group GNAME] [--user UNAME]
Creates new action with NAME and adds users and/or groups to its
recipient list. Would be notify as comment if --comment specified.
=cut
sub create
{
my $actions = RT::ScripActions->new( $RT::SystemUser );
$actions->Limit( FIELD => 'Name',
VALUE => $opts->{'name'} );
if( $actions->Count ) {
print STDERR "ScripAction '". $opts->{'name'} ."' allready exists\n";
exit(-1);
}
my @groups = _check_groups( @{ $opts->{'groups'} } );
my @users = _check_users( @{ $opts->{'users'} } );
unless( @users + @groups ) {
print STDERR "List of groups and users is empty\n";
exit(-1);
}
my $action = __create_empty( $opts->{'name'}, $opts->{'comment'} );
__add( $action, $_ ) foreach( @users );
__add( $action, $_ ) foreach( @groups );
return;
}
sub __create_empty
{
my $name = shift;
my $as_comment = shift || 0;
require RT::ScripAction;
my $action = RT::ScripAction->new( $RT::SystemUser );
$action->Create(
Name => $name,
Description => "Created with rt-notify-group-admin script",
ExecModule => $as_comment? 'NotifyGroupAsComment': 'NotifyGroup',
Argument => '',
);
return $action;
}
sub _check_groups
{
return grep { $_ ? 1: do { print STDERR "Group '$_' skipped, doesn't exist\n"; 0; } }
map { __check_group($_) } @_;
}
sub __check_group
{
my $instance = shift;
require RT::Group;
my $obj = RT::Group->new( $RT::SystemUser );
$obj->LoadUserDefinedGroup( $instance );
return $obj->id ? $obj : undef;
}
sub _check_users
{
return grep { $_ ? 1: do { print STDERR "User '$_' skipped, doesn't exist\n"; 0; } }
map { __check_user($_) } @_;
}
sub __check_user
{
my $instance = shift;
require RT::User;
my $obj = RT::User->new( $RT::SystemUser );
$obj->Load( $instance );
return $obj->id ? $obj : undef;
}
=head2 add NAME [--group GNAME] [--user UNAME]
Adds groups and/or users to recipients of the action NAME.
=cut
sub add
{
my $action = _get_action_by_name( $opts->{'name'} );
unless( $action ) {
print STDERR "ScripAction '". $opts->{'name'} ."' doesn't exist\n";
exit(-1);
}
my @groups = _check_groups( @{ $opts->{'groups'} } );
my @users = _check_users( @{ $opts->{'users'} } );
unless( @users + @groups ) {
print STDERR "List of groups and users is empty\n";
exit(-1);
}
__add( $action, $_ ) foreach( @users );
__add( $action, $_ ) foreach( @groups );
return;
}
sub __add
{
my $action = shift;
my $obj = shift;
my $arg = $action->Argument;
# Support old variant with storable
my $old = eval { Storable::thaw( $arg ) };
unless( $@ ) {
$arg = __convert_old($old);
}
my @cur = _split_arg( $arg );
my $id = $obj->id;
foreach( @cur ) {
return if( $_ == $id );
}
push( @cur, $id );
$action->__Set( Field => 'Argument', Value => join(';', @cur) );
return;
}
=head2 delete NAME
Deletes action NAME if scrips doesn't use it.
=cut
sub delete
{
my $action = _get_action_by_name( $opts->{'name'} );
unless( $action ) {
print STDERR "ScripAction '". $opts->{'name'} ."' doesn't exist\n";
exit(-1);
}
require RT::Scrips;
my $scrips = RT::Scrips->new( $RT::SystemUser );
$scrips->Limit( FIELD => 'ScripAction', VALUE => $action->id );
if( $scrips->Count ) {
my @sid;
while( my $s = $scrips->Next ) {
push @sid, $s->id;
}
print STDERR "ScripAction '"
. $opts->{'name'}
. "' is in use by Scrip(s) #"
. join( ";", @sid )
. "\n";
exit(-1);
}
return __delete( $action );
}
sub __delete
{
DBIx::SearchBuilder::Record::Delete( shift );
}
sub _get_action_by_name
{
my $name = shift;
my $actions = _get_our_actions();
$actions->Limit( FIELD => 'Name',
VALUE => $name );
if( $actions->Count > 1 ) {
print STDERR "More then one ScripAction with name '$name'\n";
}
return $actions->First;
}
=head2 switch NAME
Switch action NAME from notify as correspondence to comment and back.
=cut
sub switch
{
my $action = _get_action_by_name( $opts->{'name'} );
unless( $action ) {
print STDERR "ScripAction '". $opts->{'name'} ."' doesn't exist\n";
exit(-1);
}
my %h = ('NotifyGroup' => 'NotifyGroupAsComment',
'NotifyGroupAsComment' => 'NotifyGroup');
$action->__Set( Field => 'ExecModule',
Value => $h{ $action->ExecModule } );
}
=head2 rename NAME --newname NEWNAME
Renames action NAME to NEWNAME.
=cut
sub rename
{
my $action = _get_action_by_name( $opts->{'name'} );
unless( $action ) {
print STDERR "ScripAction '". $opts->{'name'} ."' doesn't exist\n";
exit(-1);
}
my $actions = RT::ScripActions->new( $RT::SystemUser );
$actions->Limit( FIELD => 'Name',
VALUE => $opts->{'newname'} );
if( $actions->Count ) {
print STDERR "ScripAction '". $opts->{'newname'} ."' allready exists\n";
exit(-1);
}
$action->__Set( Field => 'Name',
Value => $opts->{'newname'} );
}
=head2 NOTES
If command has option --group or --user then you can use it more then once,
if other is not specified.
=cut
###############
#### Utils ####
###############
sub _split_arg
{
return split /[^0-9]+/, $_[0];
}
sub __convert_old
{
my $arg = shift;
my @res;
foreach my $r ( @{ $arg } ) {
my $obj;
next unless $r->{'Type'};
if( lc $r->{'Type'} eq 'user' ) {
$obj = RT::User->new( $RT::SystemUser );
} elsif ( lc $r->{'Type'} eq 'user' ) {
$obj = RT::Group->new( $RT::SystemUser );
} else {
next;
}
$obj->Load( $r->{'Instance'} );
my $id = $obj->id;
next unless( $id );
push @res, $id;
}
return join ';', @res;
}
sub _get_our_actions
{
my $actions = RT::ScripActions->new( $RT::SystemUser );
$actions->Limit( FIELD => 'ExecModule',
VALUE => 'NotifyGroup',
ENTRYAGGREGATOR => 'OR');
$actions->Limit( FIELD => 'ExecModule',
VALUE => 'NotifyGroupAsComment',
ENTRYAGGREGATOR => 'OR');
return $actions;
}
=head1 AUTHOR
Ruslan U. Zakirov
cubic@wildgate.miee.ru
=head1 COPYRIGHT
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with perl distribution.
=head1 SEE ALSO
RT::Action::NotifyGroup, RT::Action::NotifyGroupAsComment
=cut