X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=rt%2Fsbin%2Frt-email-group-admin.in;fp=rt%2Fsbin%2Frt-email-group-admin.in;h=dd6548f1e6f77810aafac85b1d533c28bc06b9ce;hb=b4b0c7e72d7eaee2fbfc7022022c9698323203dd;hp=0000000000000000000000000000000000000000;hpb=2dfda73eeb3eae2d4f894099754794ef07d060dd;p=freeside.git diff --git a/rt/sbin/rt-email-group-admin.in b/rt/sbin/rt-email-group-admin.in new file mode 100755 index 000000000..dd6548f1e --- /dev/null +++ b/rt/sbin/rt-email-group-admin.in @@ -0,0 +1,508 @@ +#!@PERL@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# +# (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 }}} +=head1 NAME + +rt-email-group-admin - Command line tool for administrating NotifyGroup actions + +=head1 SYNOPSIS + + rt-email-group-admin --list + rt-email-group-admin --create 'Notify foo team' --group Foo + rt-email-group-admin --create 'Notify foo team as comment' --comment --group Foo + rt-email-group-admin --create 'Notify group Foo and Bar' --group Foo --group Bar + rt-email-group-admin --create 'Notify user foo@bar.com' --user foo@bar.com + rt-email-group-admin --create 'Notify VIPs' --user vip1@bar.com + rt-email-group-admin --add 'Notify VIPs' --user vip2@bar.com --group vip1 --user vip3@foo.com + rt-email-group-admin --rename 'Notify VIPs' --newname 'Inform VIPs' + rt-email-group-admin --switch 'Notify VIPs' + rt-email-group-admin --delete 'Notify user foo@bar.com' + +=head1 DESCRIPTION + +This script list, create, modify or delete scrip actions in the RT DB. Once +you've created an action you can use it in a scrip. + +For example you can create the following action using this script: + + rt-email-group-admin --create 'Notify developers' --group 'Development Team' + +Then you can add the followoing scrip to your Bugs queue: + + Condition: On Create + Action: Notify developers + Template: Transaction + Stage: TransactionCreate + +Your development team will be notified on every new ticket in the queue. + +=cut + +use warnings; +use strict; + +# fix lib paths, some may be relative +BEGIN { + require File::Spec; + my @libs = ("@RT_LIB_PATH@", "@LOCAL_LIB_PATH@"); + my $bin_path; + + for my $lib (@libs) { + unless ( File::Spec->file_name_is_absolute($lib) ) { + unless ($bin_path) { + if ( File::Spec->file_name_is_absolute(__FILE__) ) { + $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; + } + else { + require FindBin; + no warnings "once"; + $bin_path = $FindBin::Bin; + } + } + $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); + } + unshift @INC, $lib; + } + +} + +use RT; +RT::LoadConfig; +RT::Init; + +require RT::Principal; +require RT::User; +require RT::Group; +require RT::ScripActions; + +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 { + local $@; + 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-email-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 @princ = argument_to_list( $action ); + + 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-email-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 @cur = argument_to_list( $action ); + + my $id = $obj->id; + return if grep $_ == $id, @cur; + + push @cur, $id; + + return $action->__Set( Field => 'Argument', Value => join(',', @cur) ); +} + +=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( ", ", map "#$_", @sid ) + . "\n"; + exit(-1); + } + + return __delete( $action ); +} + +sub __delete { + require DBIx::SearchBuilder::Record; + return 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' + ); + + return $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); + } + + return $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 argument_to_list { + my $action = shift; + require RT::Action::NotifyGroup; + return RT::Action::NotifyGroup->__SplitArg( $action->Argument ); +} + +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 Eruz@bestpractical.comE + +=head1 SEE ALSO + +L, L + +=cut