< Day Day Up > |
Custom conditions and actions can be created via RT's web interface, or you can create a Perl module for each custom condition and action. Additionally, a scrip can have custom cleanup code that will run after all other code, but before the scrip exits. Custom scrip code is always written in standard Perl, and templates are created using the Text::Template module. Scrips can be applied across all queues or to individual queues. With the current version of RT, if you want to apply the same scrip to a subset of queues, you will have to go into each queue's configuration and create the scrip for each one. The scrips system is the last major part of RT that works exactly how it did when RT 2.0 came out in 2001. In a future version of RT, the scrips system will be overhauled to make it easier to specify which scrips apply to which queues and to build more complex workflow. 6.1.1. TransactionsA scrip is always run in the context of a transaction. Transactions represent a set of changes to a ticket. For example, when a ticket is resolved, its status changes, and a comment or reply may be added as part of the same transaction. The transaction object is important when implementing custom scrip conditions and actions, as it lets you see what is being changed in the ticket. 6.1.2. Cc and AdminCcScrip action and templates often refer to Cc and AdminCc as email recipients, which are simply two generic recipient groups. The AdminCc group usually consists of some or all of the privileged RT users. The Cc group would be anyone else with an interest in a particular ticket. For example, in a tech support department, the support staff and their supervisors could all be in the AdminCc group. The AdminCc group consists of the people who work directly with RT the most. RT is by default configured to send different types of messages based on whether or not the recipient is in the AdminCc or Cc group. For example, by default RT includes the URL for a ticket when emailing a member of the AdminCc group. 6.1.3. ConditionsRT comes with a set of standard conditions for scrips, as shown in Table 6-1.
Additionally, you can create a new scrip with a user-defined action. The following example is a very simple user-defined condition: $self->TicketObj->status eq 'deleted'; This condition is true whenever a ticket's status is changed to deleted. This code is suitable for pasting into RT's web interface. The equivalent Perl module would look like this: package RT::Condition::OnDelete; use strict; use base 'RT::Condition::Generic'; sub IsApplicable { my $self = shift; return ($self->TicketObj->status eq 'deleted'); } 1; If your RT base directory is /opt/rt3, this code could be installed as /opt/rt3/local/lib/RT/Condition/OnDelete.pm. You can automate this process using the Module::Install::RTx module, which is covered in Chapter 10. You also need to make RT aware of this module, which means adding some information to the database. Mucking around with the database directly is not a good idea, but there is a simple way to write command-line scrips to manipulate RT's database. Use the RT::Interface::CLI module to talk to RT: #!/usr/bin/perl use strict; use lib "/opt/rt3/lib"; use RT; use RT::Interface::CLI qw( CleanEnv GetCurrentUser ); use RT::ScripCondition; CleanEnv( ); RT::LoadConfig( ); RT::Init( ); my $user = GetCurrentUser( ); unless( $user->Id ) { print "No RT user found. Please consult your RT administrator.\n"; exit 1; } This first part is the voodoo needed to begin doing anything with RT from a command-line script. When GetCurrentUser( ) is called, it will look for a user in the RT database matching the username running the script. It does this by checking the Unix login field for the user, which by default is empty. So you will need to set this for at least one user via the web interface. Now that you have RT initialized and the current user loaded, you can add the following code to make RT aware of this new condition: my $sc = RT::ScripCondition->new($user); $sc->Create( Name => 'On Delete', Description => 'When a ticket is deleted', ExecModule => 'OnDelete', ApplicableTransTypes => 'Status', ); The Name is a short description for the condition and will be seen in the web interface. After you run this script, when you go to create a new scrip in the web interface, you'll see a new condition available in the condition select list. Later in this chapter we'll explore the possibilities for custom conditions in more detail. 6.1.4. ActionsAn action is what the scrip does if its condition is true. RT comes with a number of actions built in, as shown in Table 6-2.
Of course, just as with conditions, you can write your own custom actions. And also like conditions, these actions can be defined either through a bit of Perl code pasted into the web interface, or as a separate module. Let's assume that you have an LDAP directory that lets you look up the department someone belongs to, based on their email address. You'd like to include that department as a custom field for all tickets. To do that, you can create a custom action that sets this field for all newly created tickets. That means you would have this action run when the On Create condition was triggered, as part of the action preparation. Your action code would look something like this: my $email = ($self->TicketObj->RequestorAddresses)[0]; my $ldap = Net::LDAP->new( 'ldap.example.com' ); $ldap->bind; my $msg = $ldap->search( base => 'dc=ldap,dc=example,dc=com', filter => "(email=$email)", ); my $entry = $msg->entry(0); my $dept = $entry->get_value('ou'); my $cf = RT::CustomField->new( $RT::SystemUser ); $cf->LoadByName( Name => 'Department' ); $self->TicketObj->AddCustomFieldValue( Field => $cf, Value => $dept ); return 1; This same code as a Perl module looks like this: package RT::Action::AddDepartment; use strict; use base 'RT::Action::Generic'; sub Prepare { my $self = shift; my $email = ($self->TicketObj->RequestorAddresses)[0]; my $ldap = Net::LDAP->new( 'ldap.example.com' ); $ldap->bind; my $msg = $ldap->search( base => 'dc=ldap,dc=example,dc=com', filter => "(email=$email)", ); my $entry = $msg->entry(0); my $dept = $entry->get_value('ou'); my $cf = RT::CustomField->new( $RT::SystemUser ); $cf->LoadByName( Name => 'Department' ); $self->TicketObj->AddCustomFieldValue( Field => $cf, Value => $dept ); return 1; } 1; Again, if you add a new module, you need to make RT aware of it by adding it to the database. This can be done with a script just like the one for adding new conditions, except with the following code at the end: my $sc = RT::ScripAction->new($user); $sc->Create( Name => 'Add Department', Description => 'set department custom field for new tickets', ExecModule => 'AddDepartment', ); After creating this action, you can use the web interface to add a new scrip with the condition set to On Create and the action set to Add Department. You also need to make sure that there is a custom field named Department. 6.1.5. TemplatesEach scrip can have one associated template. These usually generate email, but they can be used for any purpose you like. They allow you to generate arbitrary text based on the content of a transaction. For example, a scrip with the Create Tickets action will use the output of its template to generate new tickets. Templates are written using the Text::Template templating language, which is a very simple templating language allowing you to embed Perl in text. Perl code is placed in curly braces ({ and }). Everything else is plain text. RT installs the base templates shown in Table 6-3.
You can make your own custom templates. If you're using a template to send email, you also can set the email headers from the template. Let's assume that you created a custom scrip to fire whenever someone steals a ticket. You want to send email to the former owner letting them know this. The following example is a template for that email: To: { my $old_owner = RT::User->new( $self->CurrentUser ); $old_owner->Load( $Transaction->OldValue ); $old_owner->EmailAddress( ) } Subject: Ticket #{ $Ticket->Id( ) } taken by { $Ticket->OwnerObj->Name( ) } A ticket you owned: { $Ticket->Subject( ) } has been taken by { $Ticket->OwnerObj->Name( ) }. { $RT::WebURL }Ticket/Display.html?id={ $Ticket->Id( ) } If the template is being used to send an email, then you can set headers simply by specifying them as name/value pairs at the beginning of the template. In the code just shown the To and Subject header is set from the template. To actually send this message only when a ticket is stolen also requires a custom condition, which we will see later. If a transaction adds attachments to a ticket, and you want to include those attachments with the outgoing email, add this line to the top of your template: RT-Attach-Message: Yes |
< Day Day Up > |