RT Scrip

Is there a library of RT-scrips? If so where can I find it?

Bryon Baker
Network Operations Manager
Copesan - Specialists in Pest Solutions
800-267-3726 . 262-783-6261 ext. 2296

“Servicing North America with Local Care”

Not really. What are looking for?On Tue, Jul 2, 2013 at 12:07 AM, Bryon Baker bbaker@copesan.com wrote:

Is there a library of RT-scrips? If so where can I find it?

Bryon Baker
Network Operations Manager
Copesan - Specialists in Pest Solutions
800-267-3726 . 262-783-6261 ext. 2296
"Servicing North America with Local Care"

Best regards, Ruslan.

That the issue I have some ideas like routing tickets based on text. But looking at what other people have done gives me ideas on how to extend the capabilities of RT.

I did look at this link

which gave good information about how the scrips work but it would be nice if there was a place people could put their scrips.

Bryon Baker
Network Operations Manager
Copesan - Specialists in Pest Solutions
800-267-3726 • 262-783-6261 ext. 2296
"Servicing North America with Local Care"From: ruslan.zakirov@gmail.com [mailto:ruslan.zakirov@gmail.com] On Behalf Of Ruslan Zakirov
Sent: Tuesday, July 02, 2013 5:06 AM
To: Bryon Baker
Cc: rt-users@lists.bestpractical.com
Subject: Re: [rt-users] RT Scrip

Not really. What are looking for?

From: Bryon Baker bbaker@copesan.com
Is there a library of RT-scrips? If so where can I find it?

A few good sources:
-http://requesttracker.wikia.com - just search for scrip for examples or
toss in a keyword related to your goal (e.g. requestor)
-http://bestpractical.com/rt/docs/4.0/ - reference docs; all the objects
(e.g. Ticket) which you may want to use in a scrip are documented

Here are some of the active RT maintainers on CPAN - they produce
extensions/plug-ins etc that may help:

You can also just search CPAN for “RT” to get tons of results:

Lastly but still quite tasty is the rt-users history - I use gossamer but
it’s archived/indexed by other sites as wel

it would be nice if there was a place people could put their scrips.

A very good way to distribute custom scrips, actions, and conditions is
to package them up into proper Perl classes and put them in an extension
you publish to CPAN. That way they’re installable and versionable and
don’t rely on error-prone copy and paste.

Is there a library of RT-scrips? If so where can I find it

Personally I think any useful set of scrips should generally be turned
into an extension and published on CPAN.

That’s what I’ve been doing with the ones I’ve written so far, like
RT::Extension::SMSNotify and RT::Extension::CustomerGroups .

I have another in the pipeline that’s more of a collection of generally
useful small scrips, I just need to untangle it from some in-house-only

I’ll reproduce my notes on extension creation in case they’re useful to
anyone. I really need to convert them to wikia syntax or integrate them
into the current guide. The following uses Redmine wiki markup. Details
of paths are specific to Debian installs of RT.

h1. RT development notes

To test an action without installing it to the DB and hooking it up to a
queue, you can use rt-crontool. Searches can be any TicketSQL, but
sometimes a simple ticket id is useful:

rt-crontool --transaction last --search RT::Search::FromSQL

–search-arg “(id = 1033)” --action

The error messages for compilation and module load errors are not very
informative. If you get errors about I18N or Locale, it’ probably
actually your module failing to compile. Test with:

perl -mRT::Action::ConvertRequestorCustomersToGroups

h2. Test script

The following code starts up an RT script you can run arbitrary RT code in.


use Modern::Perl;

        push(@INC, '/usr/share/request-tracker4/lib');
        push(@INC, '/usr/local/share/request-tracker4/lib');

use strict;
use lib "/opt/rt3/lib";
use RT;
use RT::Interface::CLI qw( CleanEnv GetCurrentUser );
use RT::ScripCondition;
use RT::Utils2ndQ;

CleanEnv( );
RT::LoadConfig( );
RT::Init( );
my $user = GetCurrentUser( );
unless( $user->Id ) {
        print "No RT user found. Please consult your RT administrator.\n";
        exit 1;
say "Current RT::User is in \$user variable. Entering interactive shell.";

Good for testing scripts and snippets.

You might find it useful to load this in re.pl from Perl’s
(in CPAN) so you can interactively work with RT’s API. Just point re.pl
to the file, eg:

bash$ re.pl --rcfile /path/to/rtcmdline.pl
$_ $user->Id
$_ $user->Name

You’ll need the full explicit path; re.pl silently ignores files it
can’t find and doesn’t search the current directory for rcfiles.

I like to alias this to rtrepl in my bashrc:

alias rtrepl='re.pl --rcfile ~/rtcmdline.pl'

h2. Manually adding actions to the DB

You can use the following code in an RT script like the above test
script to create an action in the DB:

        Name => 'ConvertRequestorCustomersToGroups',
        Description => 'Convert all customer accounts added as a
requestor into the associated customer group',
        ExecModule => 'ConvertRequestorCustomersToGroups',
        Argument => 'Requestor'

Argument is optional, though some actions require it. The meaning varies
from action to action.

h2. Packaging RT extensions

The packaging process for RT extensions is rather underdocumented. Most
of it is standard Perl module stuff, though:

h3. Packaging a Perl module

Create a Makefile.PL according to Perl’s
or use the example below, which adds use of

use inc::Module::Install 0.77;
use Module::Install::AutoManifest;
use Module::Install::ReadmeFromPod;

name 'Example-Module';

all_from      'lib/Example/Module.pm';
requires      'Carp'            => 0;
# add additional dependencies here
test_requires 'Test::More'      => '0.47';

readme_from 'lib/Example/Module.pm';


homepage 'https://github.com/yours/module-example-perl';
repository 'git://github.com/yours/module-example-perl.git';


Create a MANIFEST.SKIP like:


Make sure your main module’s POD begins like this, replacing
Example::Module with your module package and name:

package Example::Module;


=head1 NAME

Example::Module - Sample module with package Example::Module


... code sample here ...


... descriptive text ...

=head1 LICENSE

The same as for Perl itself


use 5.010;
use strict;

use vars qw{$VERSION @ISA};
        $VERSION = '1.04';
        @ISA     = 'Example::Module';

Add this to .gitignore:


h2. Additions for RT support

To turn the above into an RT extension module, add the following to
Makefile.PL after the ‘use’ statements and before the ‘name’ statement,

requires 'Module::Install::RTx' => '0.30';
use Module::Install::RTx;
RTx ('RT-Extension-SMSNotify');

This allows you to auto-detect the RT installation and install the
module to it. You can create a file etc/initialdata that sets up
database contents like scrips and scrip actions. This appears to be
undocumented, but examples can be found in RT::Extension::SLA among
others. The initialdata is applied with “make initdb”.

h1. Extension mechanisms

See “Customizing”:http://requesttracker.wikia.com/wiki/Customizing on
the RT wiki

h2. Scrip Actions and Scrip Conditions

RT’s scrips are the most common way to extend RT. They can be run when
certain events occur on tickets or on a timed basis using rt-crontool
and can act on tickets. Actions are somewhat documented and there are
lots of sample modules you can use to learn how it works.

See “Scrips”:http://requesttracker.wikia.com/wiki/Scrip and
"Extensions":http://requesttracker.wikia.com/wiki/Extensions .

scrip actions and conditions go in the lib/RT/Actions/ and
lib/RT/Conditions directories in extensions.

Scrip actions and conditions can be added directly as Perl modules in
the local lib directory, but are better added by packaged plugin extensions.

h2. Mail plugins

See the “Customization” section of “the rt-mailgate man
page”:http://linux.die.net/man/1/rt-mailgate where it mentions the
@MailPlugins parameter.

MailPlugins appears to be for user authentication. The docs aren’t very
clear, but the default Auth::MailFrom plugin is only added to the list
automatically if @MailPlugins isn’t defined in the config.

There isn’t a plug or hook mechanism for other parts of the mail import;
the rt-mailgate program invokes
RT::Interface::email::Gateway, which is a rather monolithic
method. To hook it you have to replace it with an overlay, which means
the whole method is copied.

The lookup of sender address to user is handled by
GetAuthenticationLevel . The comment on this is considerably more useful
than rt-mailgate’s docs. Looking at the code we can see:

    # Authentication Level
    # -1 - Get out.  this user has been explicitly declined
    # 0 - User may not do anything (Not used at the moment)
    # 1 - Normal user
    # 2 - User is allowed to specify status updates etc. a la

and in the loop over plugins, you can see that the auth level of the
result is the greatest auth level returned by any plugin a plugin
returns -1 to deny this user explicitly.

The user returned is whatever the last plugin executed returned. Each
plugin gets the previous plugin’s CurrentUser as its input; it’s free to
return this, modify it, or return a different CurrentUser.

The default plugin RT::Interface::email::Auth::MailFrom does not use
the input CurrentUser argument, it presumes it is undef and ignores
it. This is raised in RT bug 23089. It can therefore not be used as the
last entry for user lookup since it’ll clobber whatever came first. It
can be used BEFORE another plugin that overrides the input user, or you
can just rip the simple user lookup out of it and use your own module
instead of it.

h2. Callbacks

Callbacks allow you to customise the RT web UI’s Mason pages. They’re
fairly critically under-documented, but there’s a “useful article
here”:http://www.runpcrun.com/node/272. There’s some information on the
"CustomizingWithCallbacks section of the RT
wiki":http://requesttracker.wikia.com/wiki/CustomizingWithCallbacks too.

Callbacks are placed in the html/ directory of extensions.

RT callbacks are written with Perl’s Mason templating language. See “the
documentation for mason”:http://www.masonbook.com/book/chapter-2.mhtml

You’ll also need to read the docs on the <%init> and <%args> blocks.

Callbacks are “Components called with content” in Mason terms, as
covered in the “advanced features

You can find available callbacks in the RT sources. Look in the
share/html/ directory; in say Ticket/Create.html you’ll find ->callback
invocations like:

$m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS,
skip_create => \$skip_create,
              checks_failure => $checks_failure, results => \@results );

Sometimes the logic is a bit hard to trace. For example, ticket creation
starts in the <%init> methods of SelfService/Create.html (unpriv) and
Ticket/Create.html (priv) where, in response to form data submission,
the BeforeCreate callback is invoked. These components then invoke the
corresponding Display.html code in the same directories to do the actual
ticket creation in their <%init> methods.

Both of these appear to go via lib/RT/Interface/Web.pm’s CreateTicket
method, but email submission doesn’t; it looks like
lib/RT/Interface/Email.pm calls RT::Ticket->new(…) directly from its
Gateway method.

h2. Overlays

Overlays may be used to fully override methods in RT’s core modules or
to insert new methods. They’re not usually recommended for use in
extensions because there’s no good way to handle multiple extensions
overriding the same method.

in the RT wiki.

h1. The RT database

The RT DB is notably lacking in foreign keys and documentation. Here are
a few notes. It seems like a good idea to interact with it from Perl
most of the time.

h2. Finding the Privileged group

The system internal group Privileged can be found with:

select id  from groups were where type = 'Privileged' and domain =

or from within RT to get the RT::Group ($priv) and then get the RT::User
members at all nested levels.

my $priv = RT::Group->new( RT::SystemUser );

h2. Finding privileged users

select u.id, u.name from groups g INNER JOIN groupmembers gm ON (g.id =
gm.groupid) INNER JOIN users u ON (u.id = gm.memberid) where g.type =
'Privileged' and g.domain = 'SystemInternal';

You can not use this approach to find group memberships to
non-SystemInternal groups because non-SystemInternal groups can have
other groups as members. You have to use a recursive query or query via
the cachedgroupmembers table. It’s fine for the SystemInternal groups
’Everyone’, ‘Privileged’ and ‘Unprivileged’.

Don’t query the DB directly from RT, use the RT::Group methods. Querying
the DB can mainly be useful for reporting.

From within RT:

my $u = RT::Users->new( RT::SystemUser );

to list users you can do something like:

foreach my $uid (@{$u->ItemsArrayRef}) {say $uid->Id, ',', $uid->Name,
',', $uid->EmailAddress; }

or more usefully:

use Text::CSV;
my $csv = Text::CSV->new();
foreach my $uid (@{$u->ItemsArrayRef}) {
    $csv->print(\*STDOUT, [$uid->Id, $uid->Name]);
    say '';

Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services