Archive
Tags
android (3)
ant (2)
beautifulsoup (1)
debian (1)
decorators (1)
django (9)
dovecot (1)
encryption (1)
fix (4)
gotcha (2)
hobo (1)
htmlparser (1)
imaplib (2)
java (1)
json (2)
kerberos (2)
linux (7)
lxml (5)
markdown (4)
mechanize (6)
multiprocessing (1)
mysql (2)
nagios (2)
new_features (3)
open_source (5)
optparse (2)
parsing (1)
perl (2)
postgres (1)
preseed (1)
pxe (4)
pyqt4 (1)
python (41)
raid (1)
rails (1)
red_hat (1)
reportlab (4)
request_tracker (2)
rt (2)
ruby (1)
scala (1)
screen_scraping (7)
shell_scripting (8)
soap (1)
solaris (3)
sql (2)
sqlalchemy (2)
tips_and_tricks (1)
twitter (2)
ubuntu (1)
vmware (2)
windows (1)
zimbra (2)

The management of my current place of business wants to have high priority tickets updated on a regular basis. RT doesn't have anything built in to accomplish this, which is where the RT API comes in handy. Below is my script, which is based on Tim Bishop's rt-escalate. It will send email to a set of addresses whenever a ticket of a given priority has not been updated within a specific threshold.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env perl                                 

my $criticalPriority = 3; # Minimum priority to check
my $criticalOffset = 2 * 60 * 60; # Time since update
my $fromAddr = 'root@example.com'; # Who mail should appear to come from
my $trackpath = "/tmp"; # Where to place tracking files                 
my @toAddrs = (); # You shouldn't change this.  Use command-line arguments.
my @queues; # You shouldn't change this.  Use command-line arguments.      
my $is_test = 0;                                                           
my $show_help = 0;                                                         

# Location of RT3's libs                                                   
use lib ("/opt/rt3/lib", "/opt/rt3/local/lib");                            

use strict;                                                                
use warnings;                                                              
use Getopt::Long;                                                          

GetOptions(                                                                
    'queue=s' => \@queues,                                                 
    'to=s' => \@toAddrs,                                                   
    'threshold=i' => \$criticalOffset,                                     
    'priority=i' => \$criticalPriority,                                    
    'test' => \$is_test,                                                   
    'help' => \$show_help,                                                 
);                                                                         

if ($show_help){                                                           
    print "\n$0 --threshold seconds --priority number [options]...         
        --threshold         # Number of seconds before next update         
        --priority          # Priority to check                            
        --to                # Who should get mailed, you can specify multiple
        --queue queuename   # Searches all by default, you can specify multiple
        --test              # Don't send mail, just print message              
        --help              # Show this screen                                 
        \n";                                                                   
    exit 1;                                                                    
}                                                                              


# Pull in the RT stuff                                                         
package RT;                                                                    
use RT::Interface::CLI qw(CleanEnv);                                           
use Mail::Mailer;                                                              
use POSIX qw(floor);                                                           
use Time::Piece;                                                               

# Clean our the environment                                                    
CleanEnv();                                                                    

# Load the RT configuration                                                    
RT::LoadConfig();                                                              

# Initialise RT                                                                
RT::Init();                                                                    

# If no queues given, get all enabled queues                                   
if(!@queues) {                                                                 
    my $queues = new RT::Queues($RT::SystemUser);                              
    $queues->LimitToEnabled();                                                 
    foreach my $queue (@{$queues->ItemsArrayRef()}) {                          
        push @queues, $queue->Name;                                            
    }                                                                          
}                                                                              

#Load tracking hash for repeat notification avoidance                          
my %th; # tracking hash                                                        
my @idlist; # used to strip tickets that are closed                            
my $trackfile = "$trackpath/NotifyTimed.$criticalPriority";                    
open(FH, "<$trackfile");                                                       
while(<FH>){                                                                   
    my @parts = split;                                                         
    $th{$parts[0]} = $parts[1];                                                
}                                                                              
close(FH);                                                                     

foreach my $queuename (@queues) {                                              
    my $queue = new RT::Queue($RT::SystemUser);                                
    $queue->Load($queuename);                                                  

    # Get hold of new, open, and stalled tickets only                          
    my $tickets = new RT::Tickets($RT::SystemUser);                            
    $tickets->LimitStatus(VALUE => 'open');                                    
    $tickets->LimitStatus(VALUE => 'new');                                     
    $tickets->LimitStatus(VALUE => 'stalled');                                 
    $tickets->LimitPriority(OPERATOR => '=', VALUE => $criticalPriority);      
    $tickets->LimitQueue(VALUE => $queue->Id);                                 

    while (my $ticket = $tickets->Next) {                                      
        my $ticketdt = Time::Piece->strptime($ticket->LastUpdated, "%Y-%m-%d %H:%M:%S");
        my $now = localtime;                                                            
        my $dt = $now - $criticalOffset;                                                
        my $will_notify = 0;                                                            

        if ($dt->epoch > $ticketdt->epoch){                                             
            my $minutes = floor(($now->epoch - $ticketdt->epoch) / 60);                 
            my $owner = $ticket->OwnerObj;                                              

            # Keep track of ids to strip old ones                                       
            push(@idlist, $ticket->Id);                                                 

            # Only notify once                                                          
            if (exists $th{$ticket->Id}){                                               
                if ($th{$ticket->Id} < $ticketdt->epoch){                               
                    $th{$ticket->Id} = $ticketdt->epoch;                                
                    $will_notify = 1;                                                   
                }                                                                       
            } else {                                                                    
                $th{$ticket->Id} = $ticketdt->epoch;                                    
                $will_notify = 1;                                                       
            }                                                                           

            # Prepare report                                                            
            my $mailmsg = '<html>                                                       
              <body>                                                                    
                <p>Ticket <a href="https://rt.wbsconnect.com/Ticket/Display.html?id='   
                .$ticket->Id.'">'.$ticket->Id.'</a> needs to be updated.</p>            
                <p>Subject: '.$ticket->Subject.'</p>                                    
                <p>Owner: '.$owner->RealName.'</p>                                      
                <p>Status: '.$ticket->Status.'</p>                                      
                <p>Priority: '.$ticket->Priority.'</p>                                  
                <p>Minutes since last update: '.$minutes.'</p>                          
              </body>                                                                   
            </html>';                                                                   

            # Send email, if this isn't a repeat or test                                
            next if not $will_notify;                                                   
            if ($is_test){
                print $mailmsg;
            } else {
                foreach (@toAddrs){
                    my $mailer = Mail::Mailer->new;
                    $mailer->open({
                        'From'    => $fromAddr,
                        'To'      => $_,
                        'Subject' => "Update Required:  Priority "
                            .$ticket->Priority." ticket "
                            .$ticket->Id." needs to be updated",
                        'MIME-Version' => "1.0",
                        'Content-Type' => "text/html",

                    });
                    print $mailer $mailmsg;
                    $mailer->close();
                }
            }
        }
    }
}

# Strip old ids from tracking hash
my %nth; # New tracking hash
foreach(@idlist){
    $nth{$_} = $th{$_};
}

# Write tracking hash to file for future use
open(FH, ">$trackfile");
while((my $key, my $value) = each(%nth)){
    print FH $key, " ", $value, "\n";
}
close(FH);

# Disconnect before we finish off
$RT::Handle->Disconnect();
exit 0;

Usage is as such, assuming the script is named NotifyTimed.pl.

NotifyTimed.pl --threshold seconds --priority number [options]...
        --threshold         # Number of seconds before next update
        --priority          # Priority to check
        --to                # Who should get mailed, you can specify multiple
        --queue queuename   # Searches all by default, you can specify multiple
        --test              # Don't send mail, just print message
        --help              # Show this screen

To have this be useful, you'll want to set up a cron job. This was developed and tested on RT 3.8.1. It should work fine on many older and newer RT versions.

Posted by Tyler Lesmann on December 30, 2008 at 12:06
Tagged as: perl request_tracker rt

In Request Tracker, a.k.a. RT, tickets that have a lot of correspondence tend to get long and hard to view with redundant email quotes. It's not hard to modify RT to make the quoted text collapsed. Here's how I did it with RT 3.8.3.

The first file to change is /opt/rt3/share/html/Ticket/Elements/ShowTransactionAttachments. Find these two lines and comment them out. RT handles quotes with arrow brackets and more with Text::Quoted by default. The handling is not appropriate as it will make too many levels in the quotes to handle easily. Commenting this code turns that off.

eval { require Text::Quoted;  $content = Text::Quoted::extract($content); };
if ($@) { $RT::Logger->warning( "Text::Quoted failed: $@" ) }

The next step is extending MakeClicky. Place the following code in /opt/rt3/local/html/Callbacks/MyCallbacks/Elements/MakeClicky/Default:

<%ARGS>
$types   => []
$actions => {}
</%ARGS>
<%INIT>
my $web_path = RT->Config->Get('WebPath');

$actions->{'truncate_quotes'} = sub {
    my %args = @_;
    my $rid = int(rand(100000));
    my $color = 'A22';
    return '
    <div>
        <a href="" id="show'.$rid.
        '" style="color: #'.$color.
        '; font-weight: bold;" onclick="Effect.toggle(\'quote'.$rid.
        '\', \'slide\'); return false;">Toggle quoted message</a>
        <div id="quote'.$rid.'" style="display: none;">'.$args{value}.'</div>
    </div>
    ';
};

my @customtypes = (
    {
        name   => "httpurl",
        regex  => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}/,
        action => "url",
    },
    {
        name   => "httpurl_overwrite",
        regex  => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}/,
        action => "url_overwrite",
    },
    {
        name   => 'truncate_arrowq',
        regex  => qr/(^|\s)[>].*$/s,
        action => 'truncate_quotes',
    },
    {
        name   => 'truncate_outlookq',
        regex  => qr/\s-----Original Message-----.*$/s,
        action => 'truncate_quotes',
    },
    {
        name   => 'truncate_underscoreq',
        regex  => qr/\s_{5,}.*$/s,
        action => 'truncate_quotes',
    },
);

push(@$types, @customtypes);
</%INIT>

This is the bit that will wrap the quoted text in a hidden div that can be toggled to be shown by the user. This uses RT's own install of scriptaculous to add toggle effects.

Almost done. The last part is telling RT we what to use the clickable link extensions. You'll do this in the /opt/rt3/etc/RT_SiteConfig.pm. Just add this line to turn on the changes we made.

Set(@Active_MakeClicky, qw(truncate_arrowq truncate_outlookq truncate_underscoreq));

Restart the web server and you'll now have more manageable quotes.

UPDATE: No longer as much of a hack. I found notes on extending MakeClicky. RT has yet to update its documentation to say that the custom actions go in /opt/rt3/local/html/Callbacks/MyCallbacks/Elements/MakeClicky/Default.

Posted by Tyler Lesmann on November 21, 2008 at 7:55 and commented on 1 time
Tagged as: perl request_tracker rt