Rt-askForFeedback

From Request Tracker Wiki
Jump to navigation Jump to search

Installation

  1. Create a Global "Custom Field" with the Name: "Reminder4Stalled".
  2. Place this script somewhere on a server:

    Contents

    !/usr/bin/perl -w

    This Script bases on:

    http://requesttracker.wikia.com/wiki/RtUnifiedreminder

    #

    Author: Pascal Wagenhofer / Q-X GmbH, Switzerland

    Email: wagenhofer@q-x.ch

    Date: 07/15/2013

    #

    This script is provided "as it is" and comes without any warranty. Use it, modify

    it or do whatever you want with it.

    #

    Feedback is always welcome at wagenhofer@q-x.ch

    #

    INSTALLATION

    Read http://requesttracker.wikia.com/wiki/Rt-askForFeedback

    RT3 reminder script

    One big reminder report about ALL tickets that are getting to be too long since LastUpdated

    Sends multipart HTML + plaintext email, so HTML capable mail readers can click links

    Many pieces cannibalized from the other reminder scripts in the wiki.

    You will run this script from cron as a user with perms to read the RT_SiteConfig.pm config file

    Crontab would look like this to run twice a day, at 10:15am and 3:15pm

    send unified remind email twice per day

    15 10 * * * /home/crystalfontz/scripts/rt_reminder2cust.pl

    This Script bases on:

    http://requesttracker.wikia.com/wiki/RtUnifiedreminder

    Configuration

    Location of RT3's libs -- Change this to where yours are

    use lib ("/usr/share/request-tracker3.8/lib", "/usr/local/share/request-tracker3.8/lib", "/usr/local/rt/lib");

    Address emails should originate from

    my($from) = 'Ticket Sys your@mail.ticketsys.com';

    maximum number of seconds since LastUpdated, beyond which the ticket will be reported

    my %max_untouched_ages = (

                           "stalled" => 60 * 60 * 24 * 3,  # 3 days before warn about stalled
                           "2beclosed" => 60 * 60 * 24 * 3,  # 3 days before warn about stalled
                          );
    

    Queues to operate on. Default is all

    my @goodqueues = qw[ThisQueue ThatQueue]; # to look only in specific queues, uncomment this line and comment the next one

    my @goodqueues = (); # leave like this to look in all queues

    Queues to skip. Default is none. Use either @goodqueues or @badqueues, not both.

    my @badqueues = qw[ ]; # If you have no queues to exclude, uncomment this line and comment the next one

    my @badqueues = qw[Ignoreme IgnoreAnother]; # To exclude certain queues, list them here and comment line above

    my($debug) = 0; # nonzero will print plaintext report to STOUT instead of emailing it

    The length at which lines for plaintext mail will be truncated. 78, or thereabouts looks

    best for most people. Setting to 0 will stop lines being truncated.

    my($linelen) = 78; # has no effect on HTML mail

    Enter here the path/url for the REST-API of Request Tracker

    my($apiurl) = "https://your.url.tld/rt3/REST/1.0/"; my($username) = "username"; #Username to access RT3 (needs to have rights to update CF in the appropriate Queue(s) my($password) = "password"; #Password of the above username my($agentname) = "Your LWP::Agent-Name";

    Mail-Section

    my $plainbody = "your Body of the E-Mail (Plaintext)"; my $subjectline = "Your subject of the e-mail to the customer"; #Example: "[TicketSys #$ticketNumber] $subject"

    Code

    use strict; use Carp; use MIME::Lite; use URI::Escape; use LWP;

    Pull in the RT stuff

    package RT; use RT::Interface::CLI qw(CleanEnv GetCurrentUser GetMessageContent loc);

    CleanEnv(); # Clean our the environment RT::LoadConfig(); # Load the RT configuration RT::Init(); # Initialise RT

    use RT::Date; use RT::Queue; use RT::Queues; use RT::Tickets;

    my $max_age = 0;

    my $user = new RT::User($RT::SystemUser); # Define an RT User variable my $tickets = new RT::Tickets($RT::SystemUser); # Used to store Ticket search results my $date = new RT::Date($RT::SystemUser); # Define a date variable (used for comparisions) my $now = new RT::Date($RT::SystemUser); # get current time $now->SetToNow();

    Limit the ticket search to new and open only.

    $tickets->LimitCustomField( CUSTOMFIELD => 'Reminder4Stalled',

       OPERATOR => '!=',
       VALUE => '1'
    

    ); $tickets->LimitStatus(VALUE => 'stalled');

    my $searchqueue = ;

    if($#goodqueues != -1) {

     $tickets->_OpenParen();
     foreach my $queue (@goodqueues)
     {
         $tickets->LimitQueue(VALUE => $queue, OPERATOR => '=');
     }
     $tickets->_CloseParen();
     $searchqueue = " AND (Queue = '". join("' OR Queue = '", @goodqueues) ."')";
    

    } elsif($#badqueues != -1) {

     foreach my $queue (@badqueues)
     {
         $tickets->LimitQueue(VALUE => $queue, OPERATOR => '!=');
     }
     $searchqueue = " AND Queue != '". join("' AND Queue != '", @badqueues) ."'";
    

    }

    $tickets->OrderByCols( {FIELD => 'Status', ORDER => 'ASC'},

                        {FIELD => 'queue', ORDER => 'ASC'},
                        {FIELD => 'Priority', ORDER => 'DESC'},
                        {FIELD => 'LastUpdated', ORDER => 'ASC'},
                       );
    

    We might not want to print the message if there are no tickets

    my($printmsg) = 0;

    my $j = 0; my $bgcolor = ; my $last_status = ; my $status_title = ; my $count_by_status = 0; my $searchURL = ;

    Loop through tickets for reminder

    while (my $Ticket = $tickets->Next) {

     # Compare Dates to see if LastUpdated date is old enough to report
     $max_age = $max_untouched_ages{$Ticket->Status} || 0;
     my $max_age_2resolve = $max_untouched_ages{'2beclosed'} || 0;
    

    $date->Set(Format => "ISO", Value => $Ticket->LastUpdated);

     if ($now->Unix - $date->Unix < $max_age) { next; } # skip it if too young
     $j++;
    

    $user->Load($Ticket->Owner);

    use LWP; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->agent($agentname); my $uri = $apiurl; my $access_user = $username; my $access_password = $password; my $ticketNumber = $Ticket->{values}->{'id'}; my @customermail = "";

    my $response = $ua->post($uri."ticket/$ticketNumber/edit", ['user' => $access_user, 'pass' => $access_password,

    'content' => 'CF.{Reminder4Stalled}: 1']);
    

    if ($response->is_success) {

    if($Ticket->Status ne $last_status)

     { 
         $last_status = $Ticket->Status;
    
      $count_by_status = 0; # reset on every difft status
    
      # get a date object that can give us the datetime cutoff for this query
      $date->SetToNow();
    

    }

    1. Use our own date formatting routine
     my($updated) = &formatDate($Ticket->LastUpdatedObj->Unix);
     my($subject) = $Ticket->Subject ? $Ticket->Subject : "(No subject)";
     my($queue) = substr($Ticket->QueueObj->Name, 0, 7);
    

    my($line) = sprintf "%5d %-7s %3d %-13s %-7s %-6s %-30s",

                          $Ticket->Id, $Ticket->Status, $Ticket->Priority, $updated, $queue, $user->Name, $subject;
    
    1. Truncate lines if required
     if($linelen)
     {
         $line = substr($line, 0, $linelen);
     }
    
    1. ---- GET ALL REQUESTORS

    my $response = $ua->post($uri."ticket/$ticketNumber", ['user' => $access_user, 'pass' => $access_password]);

    if ($response->is_success) { my $html = $response->decoded_content; my @array1=split(/\n/,$html); my @array2=split(/Requestors: (.)/,$array1[11]); if ($#array2 > 1) {

       @customermail=split(m/\ (.)/,$array2[1]);
    

    } else {

       @customermail=$array2[1];
    

    }

    ----- END GET ALL REQUESTORS

    my $receiviers = ""; my $sendto = $array2[1];

    my $subjecttot = $subjectline;

    my $msg = MIME::Lite->new(From => $from,

                           To      =>  join(',', $sendto),
                           Subject => $subjecttot,
                           Type    => 'text/plain',
                           Charset    => 'utf8',
              Data => $plainbody);
    

    if ($debug)

     {
    print "Would send E-Mail for Ticket #".$ticketNumber."\n";
     }
     else
     {
    

    $msg->send;

     }
     }
    

    } }

    $tickets = new RT::Tickets($RT::SystemUser); # Used to store Ticket search results $tickets->LimitCustomField( CUSTOMFIELD => 'Reminder4Stalled',

       OPERATOR => '=',
       VALUE => '1'
    

    ); $searchqueue = ;

    if($#goodqueues != -1) {

     $tickets->_OpenParen();
     foreach my $queue (@goodqueues)
     {
         $tickets->LimitQueue(VALUE => $queue, OPERATOR => '=');
     }
     $tickets->_CloseParen();
     $searchqueue = " AND (Queue = '". join("' OR Queue = '", @goodqueues) ."')";
    

    } elsif($#badqueues != -1) {

     foreach my $queue (@badqueues)
     {
         $tickets->LimitQueue(VALUE => $queue, OPERATOR => '!=');
     }
     $searchqueue = " AND Queue != '". join("' AND Queue != '", @badqueues) ."'";
    

    }

    $tickets->OrderByCols( {FIELD => 'Status', ORDER => 'ASC'},

                        {FIELD => 'queue', ORDER => 'ASC'},
                        {FIELD => 'Priority', ORDER => 'DESC'},
                        {FIELD => 'LastUpdated', ORDER => 'ASC'},
                       );
    

    We might not want to print the message if there are no tickets

    ($printmsg) = 0;

    $j = 0; $bgcolor = ; $last_status = ; $status_title = ; $count_by_status = 0; $searchURL = ;

    Loop through tickets to close

    while (my $Ticket = $tickets->Next) {

     # Compare Dates to see if LastUpdated date is old enough to report
     $max_age = $max_untouched_ages{$Ticket->Status} || 0;
     my $max_age_2resolve = $max_untouched_ages{'2beclosed'} || 0;
    

    $date->Set(Format => "ISO", Value => $Ticket->LastUpdated);

     if ($now->Unix - $date->Unix < $max_age_2resolve) { next; } # skip it if too young
     $j++;
    

    $user->Load($Ticket->Owner);

    if($Ticket->Status ne $last_status)

     { 
         $last_status = $Ticket->Status;
    
      $count_by_status = 0; # reset on every difft status
    
      # get a date object that can give us the datetime cutoff for this query
      $date->SetToNow();
    

    }

    1. Use our own date formatting routine
     my ($updated) = &formatDate($Ticket->LastUpdatedObj->Unix);
     my ($subject) = $Ticket->Subject ? $Ticket->Subject : "(No subject)";
     my ($queue) = substr($Ticket->QueueObj->Name, 0, 7);
    

    my ($line) = sprintf "%5d %-7s %3d %-13s %-7s %-6s %-30s",

                          $Ticket->Id, $Ticket->Status, $Ticket->Priority, $updated, $queue, $user->Name, $subject;
    

    if ($debug)

     {
    print "Would close Ticket ".$Ticket->Id."\n\n";
     }
     else
     {
     $Ticket->Resolve();
     }
    

    }

    Disconnect before we finish off

    $RT::Handle->Disconnect(); exit 0;

    Formats a date like: Thu 10-07-03

    Designed to be consice yet useful

    sub formatDate() {

     my($unixtime) = @_;
     my(@days) = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );
     # Return an empty string if we haven't been given a time
     return "" if $unixtime <= 0;
     my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($unixtime);
     return sprintf "%s %02d-%02d-%02d", $days[$wday], $mon+1, $mday, $year%100;
    
    }
  3. install a Cronjob on your server (see script head)
  4. Now, we need to setup a new Scrip to reset the "Reminder4Stalled"-Field in case of Correspondance. Create a new Scrip in the Global-Section which looks like this:

Description: "Set Reminder4Stalled = 0"
Condition: "On Correspondance"
Action: "User defined"
Template: "Global Template: empty"
Phase: "TransactionCreate"

User Defined Condition:

return 1;

User Defined Action Preparation Code:

my $ticket = $self->TicketObj;
my $cf_obj = RT::CustomField->new($RT::SystemUser);
my $cf_name = "Reminder4Stalled";
my $cf_value = "0";

$cf_obj->LoadByName( Name => $cf_name );

$RT::Logger->debug( "Loaded \$cf_obj->Name = ". $cf_obj->Name() ."\n" );
$ticket->AddCustomFieldValue( Field=>$cf_obj, Value=>$cf_value,
RecordTransaction=>0 );

User Defined Post Action Code:

return 1;