diff options
Diffstat (limited to 'rt/bin/rt')
-rwxr-xr-x | rt/bin/rt | 1391 |
1 files changed, 1391 insertions, 0 deletions
diff --git a/rt/bin/rt b/rt/bin/rt new file mode 100755 index 0000000..41220bb --- /dev/null +++ b/rt/bin/rt @@ -0,0 +1,1391 @@ +#!!!PERL!! -w +# +# $Header: /home/cvs/cvsroot/freeside/rt/bin/Attic/rt,v 1.1 2002-08-12 06:17:07 ivan Exp $ +# RT is (c) 1996-2001 Jesse Vincent <jesse@bestpractical.com> + +use strict; +use Carp; +use Getopt::Long; + +use lib "!!RT_LIB_PATH!!"; +use lib "!!RT_ETC_PATH!!"; + +use RT::Interface::CLI qw(CleanEnv LoadConfig DBConnect + GetCurrentUser GetMessageContent); + +#Clean out all the nasties from the environment +CleanEnv(); + +#Load etc/config.pm and drop privs +LoadConfig(); + +#Connect to the database and get RT::SystemUser and RT::Nobody loaded +DBConnect(); + +#Drop setgid permissions +RT::DropSetGIDPermissions(); + +#Get the current user all loaded +my $CurrentUser = GetCurrentUser(); + +unless ($CurrentUser->Id) { + print "No RT user found. Please consult your RT administrator.\n"; + exit(1); +} + + +# {{{ commandline flags + +my ( @id, + @limit_queue, + @limit_status, + @limit_owner, + @limit_priority, + @limit_final_priority, + @limit_requestor, + @limit_subject, + @limit_body, + @limit_created, + @limit_resolved, + @limit_lastupdated, + @limit_dependson, + @limit_dependedonby, + @limit_memberof, + @limit_hasmember, + @limit_refersto, + @limit_referredtoby, + @limit_keyword, + + @limit_due, + @limit_starts, + @limit_started, + $limit_first, + $limit_rows, + $history, + $summary, + $create, + @requestors, + @cc, + @admincc, + $status, + $subject, + $owner, + $steal, + $queue, + $time_left, + $priority, + $final_priority, + $due, + $starts, + $started, + $contacted, + $comment, + $reply, + $source, + $edit, + @dependson, + @memberof, + @refersto, + $mergeinto, + @keywords, + $time_taken, + $verbose, + $debug, + $help, + $version); + +# }}} + +# Set defaults for cli args + +$edit = 1; # Assume the user wants to edit replies and comments + # unless they specify --noedit + +# {{{ args + +my @args =("id=s" => \@id, + "limit-queue=s" => \@limit_queue, + "limit-status=s" => \@limit_status, + "limit-owner=s" => \@limit_owner, + "limit-priority=s" => \@limit_priority, + "limit-final-priority=s" => \@limit_final_priority, + "limit-requestor=s" => \@limit_requestor, + "limit-subject=s" => \@limit_subject, + "limit-body=s", \@limit_body, + "limit-created=s" => \@limit_created, + "limit-due=s" => \@limit_due, + "limit-last-updated=s" => \@limit_lastupdated, + "limit-keyword=s" => \@limit_keyword, + + "limit-member-of=s" => \@limit_memberof, + "limit-has-member=s" => \@limit_hasmember, + "limit-depended-on-by=s" => \@limit_dependedonby, + "limit-depends-on=s" => \@limit_dependson, + "limit-referred-to-by=s" => \@limit_referredtoby, + "limit-refers-to=s" => \@limit_refersto, + + "limit-starts=s" => \@limit_starts, + "limit-started=s" => \@limit_started, + "limit-first=i" => \$limit_first, + "limit-rows=i" => \$limit_rows, + "history|show" => \$history, + "summary:s" => \$summary, + "create" => \$create, + "keywords=s" => \@keywords, + "requestor|requestors=s" => \@requestors, + "cc=s" => \@cc, + "admincc=s" => \@admincc, + "status=s" => \$status, + "subject=s" => \$subject, + "owner=s" => \$owner, + "steal" => \$steal, + "queue=s" => \$queue, + + + "priority=i" => \$priority, + "final-priority=i" => \$final_priority, + "due=s" => \$due, + "starts=s" => \$starts, + "started=s" => \$started, + "contacted=s" => \$contacted, + "comment", \$comment, + "reply|respond", \$reply, + "source=s" => \$source, + "edit!" => \$edit, + "depends-on=s" => \@dependson, + "member-of=s" => \@memberof, + "merge-into=s" => \$mergeinto, + "refers-to=s" => \@refersto, + "time-left=i" => \$time_left, + "time-taken=i" => \$time_taken, + "verbose+" => \$verbose, + "debug" => \$debug, + "version" => \$version, + "help|h|usage" => \$help + ); + +# }}} + + + +GetOptions(@args); + +print join(':',@keywords); +# {{{ If they want it, print a usage message and get out + +if ($help) { + + +print <<EOUSAGE; + +Limit the set of records returned: + +--id=[first][-][last] + Specify a single ticket, a range, or to start with (n-) or end with (-n) +a specific ticket. + + --limit-queue=<queue> + --limit-status=[!](new|open|stalled|resolved) + + --limit-owner=[!]<userid> + --limit-priority=[starts][-][ends] + --limit-final-priority=[starts][-][ends] + starts is less than ends + --limit-requestor=[!]<userid>|<email> + --limit-subject=[!]<text> + --limit-body=[!]<text> + --limit-keyword=[!]<select>/<keyword> + + Links + --limit-member-of=<ticketid> + --limit-has-member=<ticketid> + --limit-refers-to=<ticketid> + --limit-referred-to-by=<ticketid> + --limit-depends-on=<ticketid> + --limit-depended-on-by=<ticketid> + + + Dates + --limit-created=[starts][-][ends] + --limit-due=[starts][-][ends] + --limit-starts=[starts][-][ends] + --limit-started=[starts][-][ends] + --limit-resolved=[starts][-][ends] + --limit-last-updated=[starts][-][ends] + starts and ends are dates. starts can not be less than ends + + --limit-first=<first row returned> + --limit-rows=<row count> + + --history | --show + show a history of the tickets found + + + --summary [format-string] + show a listing-style summary of the tickets found. If format string + is ommitted, uses \$RT_SUMMARY_FORMAT or an internal default + + + #TODO: doc summary + format: <atom>%<format> + atom: <name><size> + size: <integer> + name: (grep for # {{{ attribs for the array of ok values) + + + --create + create a new ticket. Any attributes that you can modify on an existing ticket + can also be used for ticket creation. + + + +Attributes + Basics + --status=<new|open|stalled|resolved|dead> + sets status + --subject=<subject> + sets subject + --owner=<userid> + set owner to + --steal + Become the owner, even if someone else owns the ticket + --queue=<queueid> + set queue to + + --priority=<int> + + --final-priority=<int> + + Watchers + --requestors=[+|-]<userid|email address> + add or remove this user as a ticket requestor + --cc=[+|-]<userid|email address> + add or remove this user as a ticket cc + --admincc=[+|-]<userid|email address> + add or remove this user as a ticket admincc + + (When creating tickets, just leave off the + or - ) + + Keywords + --keywords[+|-]<keyword_select>/<keyword> + Add or remove a keyword. + + + + Dates + --due=<date> + --starts=<date> + --started=<date> + --contacted=<date> + + --time-left=<int> + + --time-taken=<int> + + + Link related manipulation: + + --depends-on=[+|-]<ticketid> + --member-of=[+|-]<ticketid> + --refers-to=[+|-]<ticketid> + --merge-into=<ticketid> + +Comments and replies + + --comment + --reply|respond + --source <path> + Specify the path to the source file for this ticket update + + --noedit + Don't invoke \$EDITOR to edit the content of this update + + + + + Condiments + + --verbose + --debug + --version + --help|h|usage + You're reading it. + +EOUSAGE + + exit(0); +} + +# Print version, and leave +if ($version) { + print "RT $RT::VERSION for $RT::rtname. Copyright 1996-2001 Jesse Vincent <jesse\@fsck.com>\n"; + exit(0); +} + +# }}} + +# {{{ Validate any options that were passed in. normalize them. + +#if a queue was specified +if ($queue) { + # make sure that $queue is a valid queue and load it into $queue_obj +} + +#For each date in: $due, $starts, $started + +# load up an RT::Date object and parse it into a normalized form +# if it can't parse it, log an error and null out the variable + +# }}} + +# {{{ Check if we're creating, if so, create the ticket and be done + +if ($create) { + $RT::Logger->debug("Creating a new ticket"); + + #Make sure the current user can create tickets in this queue + + #Make sure that the owner specified can own tickets in this queue + + + + my $linesref = GetMessageContent( Edit => $edit, Source => $source, + CurrentUser => $CurrentUser + ); + + require MIME::Entity; + my $MIMEObj; + + if ($linesref) { + $MIMEObj = MIME::Entity->build(Data => $linesref); + } + + use RT::Ticket; + my $Ticket=new RT::Ticket($CurrentUser); + my ($ticket, $trans, $msg) = + $Ticket->Create(Queue => $queue, + Owner => $owner, + Status => $status || 'new' , + Subject => $subject, + Requestor => \@requestors, + Cc => \@cc, + AdminCc => \@admincc, + Due => $due, + Starts => $starts, + Started => $started, + TimeLeft => $time_left, + InitialPriority => $priority, + FinalPriority => $final_priority, + MIMEObj => $MIMEObj + ); + print $msg . "\n"; +} + +# }}} + +else { + #Apply restrictions + use RT::Tickets; + my $Tickets = new RT::Tickets($CurrentUser); + + # {{{ Limit our search + my $value; #to use when iterating through restrictions + my $queue_id; #to use when limiting by keyword + + # {{{ limit on id + + foreach $value (@id) { + if ($value =~ /^(\d+)$/) { + $Tickets->LimitId ( VALUE => $1, + OPERATOR => '='); + } + elsif ($value =~ /^(\d*)\D?(\d*)$/) { + my $start = $1; + my $end = $2; + $Tickets->LimitId( + VALUE => "$start", + OPERATOR => '>=') if ($start); + $Tickets->LimitId( + VALUE => "$end", + OPERATOR => '<=') if ($end); + } + } + + + # }}} + + # {{{ limit on status + + foreach $value (@limit_status) { + if ($value =~ /^(=|!=|!|)(.*)$/) { + my $op = $1; + my $val = $2; + + + $op = ParseBooleanOp($op); + $Tickets->LimitStatus(VALUE => "$val", + OPERATOR => "$op"); + } + } + + # }}} + + + + # {{{ limit on queue + foreach $value (@limit_queue) { + if ($value =~ /^(\W?)(.*?)$/i) { + my $op = $1; + my $val = $2; + + $op = ParseBooleanOp($op); + + my $queue_obj = new RT::Queue($RT::SystemUser); + + unless ($queue_obj->Load($val)) { + $RT::Logger->debug("Queue '$val' not found"); + print STDERR "Queue '$val' not found\n"; + exit(-1); + } + $RT::Logger->debug ("Limiting queue to $op ".$queue_obj->Name); + $Tickets->LimitQueue(VALUE => $queue_obj->Name, + OPERATOR => $op); + $queue_id=$queue_obj->id; + } + } + + # {{{ limit on keyword + foreach $value (@limit_keyword) { + if ($value =~ /^(\W?)(.*?)\/(.*)$/i) { + my $op = $1; + my $select = $2; + my $keyword = $3; + + $op = ParseBooleanOp($op); + + # load the keyword select + my $keyselect = RT::KeywordSelect->new($RT::SystemUser); + unless ($keyselect->LoadByName(Name=>$select, Queue=>$queue_id)) { + $RT::Logger->debug("KeywordSelect '$select' not found"); + print STDERR "KeywordSelect '$select' not fount\n"; + exit(-1); + } + + # load the keyword + my $k = RT::Keyword->new($RT::SystemUser); + unless ($k->LoadByNameAndParentId($keyword, $keyselect->Keyword)) { + $RT::Logger->debug("Keyword '$keyword' not found"); + print STDERR "Keyword '$keyword' not found\n"; + exit(-1); + } + $Tickets->LimitKeyword(OPERATOR => $op, + KEYWORDSELECT => $keyselect->id, + KEYWORD => $k->id); + $RT::Logger->debug ("Limiting keyword to $op ".$k->Path); + } + } + # }}} + # {{{ limit on owner + foreach $value (@limit_owner) { + if ($value =~ /^(\W?)(.*?)$/i) { + my $op = $1; + my $val = $2; + + $op = ParseBooleanOp($op); + + my $user_obj = new RT::User($RT::SystemUser); + + unless ($user_obj->Load($val)) { + $RT::Logger->debug("User '$val' not found"); + print STDERR "User '$val' not found\n"; + exit(-1); + } + $val = $user_obj->id(); + + $RT::Logger->debug ("Limiting owner to $op $val"); + $Tickets->LimitOwner(VALUE => "$val", + OPERATOR => "$op"); + } + } + # }}} + # {{{ limt on priority + + foreach $value (@limit_priority) { + my ($start, $end) = ParseRange($value); + if ($start == $end) { + $Tickets->LimitPriority( VALUE => $start, + OPERATOR => '='); + } elsif ($start) { + $Tickets->LimitPriority( VALUE => $start, + OPERATOR => '>='); + } elsif ($end) { + $Tickets->LimitPriority( VALUE => $end, + OPERATOR => '<='); + } + + } + foreach $value (@limit_final_priority) { + my ($start, $end) = ParseRange($value); + if ($start == $end) { + $Tickets->LimitFinalPriority( VALUE => $start, + OPERATOR => '='); + } elsif ($start) { + $Tickets->LimitFinalPriority( VALUE => $start, + OPERATOR => '>='); + } elsif ($end) { + $Tickets->LimitFinalPriority( VALUE => $end, + OPERATOR => '<='); + } + } + # }}} + + foreach $value (@limit_requestor) { + if ($value =~ /^(\W?)(.*?)$/i) { + my $op = $1; + my $val = $2; + + $op = ParseBooleanOp($op); + $Tickets->LimitRequestor(VALUE => $val, + OPERATOR => $op ); + } + + } + foreach $value (@limit_subject) { + + if ($value =~ /^(\W?)(.*?)$/i) { + my $op = $1; + my $val = $2; + + $op = ParseLikeOp($op); + + $Tickets->LimitSubject(VALUE => $val, + OPERATOR => $op ); + } + } + + foreach $value (@limit_body) { + if ($value =~ /^(\W?)(.*?)$/i) { + my $op = $1; + my $val = $2; + + $op = ParseLikeOp($op); + + $Tickets->LimitBody(VALUE => $val, + OPERATOR => $op ); + } + + } + + + + # Dates + foreach my $date (@limit_created) { + my ($start, $end) = ParseDateRange($date); + $Tickets->LimitCreated ( VALUE => $start, + OPERATOR => '>=' ) if ($start); + $Tickets->LimitCreated ( VALUE => $end, + OPERATOR => '<=' ) if ($end); + } + + foreach my $date (@limit_due) { + my ($start, $end) = ParseDateRange($date); + $Tickets->LimitDue ( VALUE => $start, + OPERATOR => '>=' ) if ($start); + $Tickets->LimitDue ( VALUE => $end, + OPERATOR => '<=' ) if ($end); + } + + foreach my $date (@limit_starts) { + my ($start, $end) = ParseDateRange($date); + $Tickets->LimitStarts ( VALUE => $start, + OPERATOR => '>=' ) if ($start); + $Tickets->LimitStarts ( VALUE => $end, + OPERATOR => '<=' ) if ($end); + } + + foreach my $date (@limit_started) { + my ($start, $end) = ParseDateRange($date); + $Tickets->LimitStarted ( VALUE => $start, + OPERATOR => '>=' ) if ($start); + $Tickets->LimitStarted ( VALUE => $end, + OPERATOR => '<=' ) if ($end); + } + + foreach my $date (@limit_resolved) { + my ($start, $end) = ParseDateRange($date); + $Tickets->LimitResolved ( VALUE => $start, + OPERATOR => '>=' ) if ($start); + $Tickets->LimitResolved ( VALUE => $end, + OPERATOR => '<=' ) if ($end); + } + + foreach my $date (@limit_lastupdated) { + my ($start, $end) = ParseDateRange($date); + $Tickets->LimitLastUpdated( VALUE => $start, + OPERATOR => '>=' ) if ($start); + $Tickets->LimitLastUpdated ( VALUE => $end, + OPERATOR => '<=' ) if ($end); + } + + foreach my $link (@limit_memberof) { + $Tickets->LimitMemberOf($link); + } + + foreach my $link (@limit_hasmember) { + $Tickets->LimitHasMember($link); + } + + foreach my $link (@limit_dependson) { + $Tickets->LimitDependsOn($link); + } + + foreach my $link (@limit_dependedonby) { + $Tickets->LimitDependedOnBy($link); + } + foreach my $link (@limit_refersto) { + $Tickets->LimitRefersTo($link); + } + + foreach my $link (@limit_referredtoby) { + $Tickets->LimitReferredToBy($link); + } + + + if ($limit_first){ + } + if ($limit_rows){ + } + +# }}} + + # {{{ Iterate through all tickets we found + + + my ($format, $titles, $code); + + #Set up the summary format if we need to + if (defined $summary) { + my $format_string = $summary || $ENV{'RT_SUMMARY_FORMAT'} || "%id4%status4%queue7%subject40%requestor16"; + + ($format, $titles, $code) = BuildListingFormat($format_string); + printf "$format\n", eval "$titles"; + } + + + + while (my $Ticket = $Tickets->Next()) { + $RT::Logger->debug ("Now working on ticket ". $Ticket->id); + + #Run through all the ticket modifications we might want to do + #TODO: these are all insufficiently lazy and should be replaced with some + # nice foreaches. + + + # {{{ deal with watchers + + # add / delete requestors + foreach $value (@requestors) { + if ($value =~ /^(\W?)(.*)$/) { + my $op = $1; + my $addr = $2; + + $Ticket->AddRequestor(Email => $addr) if ($op eq '+'); + $Ticket->DeleteRequestor( $addr) if ($op eq '-'); + } + } + + # add / delete ccs + foreach $value (@cc) { + if ($value =~ /^(\W?)(.*)$/) { + my $op = $1; + my $addr = $2; + $Ticket->AddCc(Email => $addr) if ($op eq '+'); + $Ticket->DeleteCc($addr) if ($op eq '-'); + } + } + + # add / delete adminccs + $RT::Logger->debug("Looking at admin ccs"); + foreach $value (@admincc) { + if ($value =~ /^(\W?)(.*)$/) { + my $op = $1; + my $addr = $2; + $Ticket->AddAdminCc(Email => $addr) if ($op eq '+'); + $Ticket->DeleteAdminCc($addr) if ($op eq '-'); + } + } + + # }}} + + # {{{ Deal with ticket keywords + + my $KeywordSelects = $Ticket->QueueObj->KeywordSelects(); + $RT::Logger->debug ("Looking at keywords"); + foreach $value (@keywords) { + $RT::Logger->debug("Looking at --keyword=$value"); + if ($value =~ /^(\W?)(.*?)\/(.*)$/) { + my $op = $1; + my $select = $2; + my $keyword = $3; + + $RT::Logger->debug("Going to $op Keyword $select / $keyword"); + while (my $ks = $KeywordSelects->Next) { + $RT::Logger->debug("$select is select ".$ks->Name." is found"); + next unless ($ks->Name =~ /$select/i); + $RT::Logger->debug ("Found a match for $select\n"); + my $kids = $ks->KeywordObj->Descendents; + + my ($kid); + foreach $kid (keys %{$kids}) { + $RT::Logger->debug("Now comparing $keyword with ".$kids->{$kid}. "\n"); + next unless ($kids->{$kid} =~ /^$keyword$/i); + $RT::Logger->debug("Going to $op $select / $keyword (".$kids->{$kid} .")"); + $Ticket->DeleteKeyword(KeywordSelect => $ks->id, + Keyword => $kid) if ($op eq '-'); + + $Ticket->AddKeyword(KeywordSelect => $ks->id, + Keyword => $kid) if ($op eq '+'); + } + + } + } + } + # }}} + + # {{{ deal with links + + # Deal with merging { + if ($mergeinto) { + my ($trans, $msg) =$Ticket->MergeInto($mergeinto); + print $msg."\n"; + } + # add /delete depends-ons + + foreach my $value (@dependson) { + if ($value =~ /^(\W?)(.*)$/) { + my $op = $1; + my $ticket = $2; + if (!$op or ($op eq '+')) { + my ($trans, $msg) = + $Ticket->AddLink(Type => 'DependsOn', Target => $ticket); + print $msg."\n"; + } + elsif ($op eq '-') { + my ($trans, $msg) = + $Ticket->DeleteLink(Type => 'DependsOn', Target => $ticket); + print $msg."\n"; + } + + } + } + # add /delete member-of + foreach my $value (@memberof) { + if ($value =~ /^(\W?)(.*)$/) { + my $op = $1; + my $ticket = $2; + if ($op eq '+') { + my ($trans, $msg) = + $Ticket->AddLink(Type => 'MemberOf', Target => $ticket); + print $msg; + } + elsif ($op eq '-') { + my ($trans, $msg) = + $Ticket->DeleteLink(Type => 'MemberOf', Target => $ticket); + print $msg; + } + + } + } + # add / delete refers-to + foreach my $value (@refersto) { + if ($value =~ /^(\W?)(.*)$/) { + my $op = $1; + my $ticket = $2; + if ($op eq '+') { + my ($trans, $msg) = + $Ticket->AddLink(Type => 'RefersTo', Target => $ticket); + print $msg; + } + elsif ($op eq '-') { + my ($trans, $msg) = + $Ticket->DeleteLink(Type => 'RefersTo', Target => $ticket); + print $msg; + } + + } + } + + # }}} + + # {{{ deal with dates + + #set due + if ($due) { + my $iso = ParseDateToISO($due); + if ($iso) { + $RT::Logger->debug("Setting due date to $iso ($due)"); + my ($trans, $msg) = + $Ticket->SetDue($iso); + print $msg; + } + else { + print "Due date '$due' could not be parsed"; + } + } + + #set starts + if ($starts) { + my $iso = ParseDateToISO($due); + if ($iso) { + my ($trans, $msg) = + $Ticket->SetStarts($iso); + print $msg."\n"; + } + else { + print "Starts date '$starts' could not be parsed"; + } + } + #set started + if ($started) { + my $iso = ParseDateToISO($started); + if ($iso) { + my ($trans, $msg) = + $Ticket->SetStarted($iso); + print $msg."\n"; + } + else { + print "Started date '$started' could not be parsed"; + } + } + #set contacted + if ($contacted) { + my $iso = ParseDateToISO($contacted); + if ($iso) { + my ($trans, $msg) = + $Ticket->SetContacted($iso); + print $msg."\n"; + } + else { + print "Contacted date '$contacted' could not be parsed"; + } + } + + # }}} + + # {{{ set other attributes + + #Set subject + if ($subject) { + my ($trans, $msg) = $Ticket->SetSubject($subject); + print $msg."\n"; + } + + #Set priority + if ($priority) { + my ($trans, $msg) = + $Ticket->SetPriority($priority); + print $msg."\n"; + } + + #Set final priority + if ($final_priority) { + my ($trans, $msg) = + $Ticket->SetFinalPriority($final_priority); + print $msg."\n"; + } + + #Set status + if ($status) { + my ($trans, $msg) = + $Ticket->SetStatus($status); + print $msg."\n"; + } + + #Set time left + if ($time_left) { + my ($trans, $msg) = + $Ticket->SetTimeLeft($time_left); + print $msg."\n"; + } + + #Set time_taken + if ($time_taken) { + my ($trans, $msg) = + $Ticket->SetTimeTaken($time_taken); + print $msg."\n"; + } + + #Set owner + if ($owner) { + my ($trans, $msg) = + $Ticket->SetOwner($owner); + print $msg."\n"; + } + + # Steal + if ($steal) { + my ($trans, $msg) = + $Ticket->Steal(); + print $msg . "\n"; + } + #Set queue + if ($queue) { + my ($trans, $msg) = + $Ticket->SetQueue($queue); + print $msg."\n"; + } + + # }}} + + + + # {{{ Perform ticket comments/replies + if ($reply) { + $RT::Logger->debug("Replying to ticket ".$Ticket->Id); + + my $linesref = GetMessageContent( Edit => $edit, Source => $source, + CurrentUser => $CurrentUser + ); + + #TODO build this entity + require MIME::Entity; + my $MIMEObj = MIME::Entity->build(Data => $linesref); + + $Ticket->Correspond( MIMEObj => $MIMEObj , + TimeTaken => $time_taken); + } + + elsif ($comment) { + $RT::Logger->debug("Commenting on ticket ".$Ticket->Id); + + my $linesref =GetMessageContent(Edit => $edit, Source => $source, + CurrentUser => $CurrentUser); + #TODO build this entity + require MIME::Entity; + my $MIMEObj = MIME::Entity->build(Data => $linesref); + + $Ticket->Comment( MIMEObj => $MIMEObj, + TimeTaken => $time_taken); + } + + # }}} + + # {{{ Display whatever we need to display + + # {{{ Display a full ticket listing and history + if ($history) { + #Display the history + $RT::Logger->debug("Show history for ".$Ticket->id); + + if ($Ticket->CurrentUserHasRight("ShowTicket")) { + &ShowSummary($Ticket); + print "\n"; + &ShowHistory($Ticket); + } + else { + print "You don't have permission to view that ticket.\n"; + } + } + + # }}} + + # {{{ Display a summary if we need to + if (defined $summary) { + $RT::Logger->debug ("Show ticket summary with format $format"); + + printf $format."\n", eval $code; + + } + # }}} + + # }}} + + } + + # }}} + +} + + +$RT::Handle->Disconnect(); + + + + + + + +# {{{ sub ParseBooleanOp + +=head2 ParseBooleanOp + + Takes an option modifier. returns the apropriate SQL operator. + If it's handed ! or -, returns !=. Otherwise returns =. + +=cut + +sub ParseBooleanOp { + + my $op = shift; + + #so that !new limits to not new, etc + if ($op =~ /^(\!|-)/) { + $op = "!="; + } + else { + $op = "="; + } + + return($op); +} + +# }}} + +# {{{ sub ParseLikeOp +=head2 ParseLikeOp + + Takes an option modifier. returns the apropriate SQL operator. + If it's handed ! or -, returns NOT LIKE. Otherwise returns LIKE + +=cut + +sub ParseLikeOp { + + my $op = shift; + + #so that !new limits to not new, etc + if ($op =~ /^(\!|-)/) { + $op = "NOT LIKE"; + } + else { + $op = "LIKE"; + } + + return($op); +} +# }}} + +# {{{ sub ParseDateToISO + +=head2 ParseDateToISO + +Takes a date in an arbitrary format. +Returns an ISO date and time in GMT + +=cut + +sub ParseDateToISO { + my $date = shift; + + my $date_obj = new RT::Date($CurrentUser); + $date_obj->Set( Format => 'unknown', + Value => $date + ); + return ($date_obj->ISO); +} + +# }}} + +# {{{ sub ParseDateRange + +=head2 ParseDateRange [RANGE] + +Takes a range of dates of the form [<date>][-][<date>] and returns +starting and ending dates (as ISOs) If a date is specified as neither a starting nor ending +date, we parse it it as "midnight tonight to midnight tomorrow" + +=cut + +sub ParseDateRange { + my $in = shift; + my ($start, $end); + + + use RT::Date; + my $start_obj = new RT::Date($CurrentUser); + my $end_obj = new RT::Date($CurrentUser); + + if ($in =~ /^(.*?)-(.*?)$/) { + $start = $1; + $end = $2; + + if ($start) { + $start_obj->Set(Format => 'unknown', + Value => $start); + } + if ($end) { + $end_obj->Set(Format => 'unknown', + Value => $end); + } + } + else { + $start = $in; + $end = $in; + + $start_obj->Set(Format => 'unknown', + Value => $start); + + $end_obj->Set(Format => 'unknown', + Value => $end); + + $start_obj->SetToMidnight(); + $end_obj->SetToMidnight(); + $end_obj->AddDay(); + } + + if ($start) { + $start = $start_obj->ISO; + } + if ($end) { + $end = $end_obj->ISO; + } + + return ($start, $end); +} + +# }}} + +# {{{ ParseRange +=head2 ParseRange [RANGE] + +Takes a range of the form [<int>][-][<int>] and returns +a first and a last value. If the - is omitted, both $start and $end are the same. +=cut + +sub ParseRange { + my $in = shift; + my ($start, $end); + + if ($in =~ /(.*?)-(.*?)/) { + $start = $1; + $end = $2; + } + else { + $start = $in; + $end = $in; + } + + return ($start, $end); + + + +} + +# }}} + +# {{{ sub ShowSummary + +sub ShowSummary { + my $Ticket = shift; + + + print <<EOFORM; +Serial Number: @{[$Ticket->Id]} Status:@{[$Ticket->Status]} Worked: @{[$Ticket->TimeWorked]} minutes Queue:@{[$Ticket->QueueObj->Name]} + Subject: @{[$Ticket->Subject]} + Requestors: @{[$Ticket->RequestorsAsString]} + Cc: @{[$Ticket->CcAsString]} + Admin Cc: @{[$Ticket->AdminCcAsString]} + Owner: @{[$Ticket->OwnerObj->Name]} + Priority: @{[$Ticket->Priority]} / @{[$Ticket->FinalPriority]} + Due: @{[$Ticket->DueAsString]} + Created: @{[$Ticket->CreatedAsString]} (@{[$Ticket->AgeAsString]}) + Last Contact: @{[$Ticket->ToldAsString]} (@{[$Ticket->LongSinceToldAsString]}) + Last Update: @{[$Ticket->LastUpdatedAsString]} by @{[$Ticket->LastUpdatedByObj->Name]} + +EOFORM + +my $selects = $Ticket->QueueObj->KeywordSelects(); + #get the keyword selects + print "Keywords:\n"; + while (my $select = $selects->Next) { + print "\t" .$select->Name .": "; + my $keys = $Ticket->KeywordsObj($select->id); + while (my $key = $keys->Next) { + print $key->KeywordObj->RelativePath($select->KeywordObj) . " "; + + } + print "\n"; + } + +#iterate through the keyword selects. +#print the keyword select and all the related keywords + + + +#TODO: finish link descriptions +print "Dependencies: \n"; + while (my $l=$Ticket->DependedOnBy->Next) { + print $l->BaseObj->id," (",$l->BaseObj->Subject,") ",$l->Type," this ticket\n"; + } + while (my $l=$Ticket->DependsOn->Next) { + print "This ticket ",$l->Type," ",$l->TargetObj->Id," (",$l->TargetObj->Subject,")\n"; + } +} + +# }}} + +# {{{ sub ShowHistory +sub ShowHistory { + my $Ticket = shift; + my $Transaction; + my $Transactions = $Ticket->Transactions; + + while ($Transaction = $Transactions->Next) { + &ShowTransaction($Transaction); + } + } +# }}} + +# {{{ sub ShowTransaction +sub ShowTransaction { + my $transaction = shift; + +print <<EOFORM; +========================================================================== +Date: @{[$transaction->CreatedAsString]} (@{[$transaction->TimeTaken]} minutes) +@{[$transaction->Description]} +EOFORM + ; + my $attachments=$transaction->Attachments(); + while (my $message=$attachments->Next) { + print <<EOFORM; +-------------------------------------------------------------------------- +@{[$message->Headers]} +EOFORM + + if ($message->ContentType =~ m{^(text/plain|message|text$)}) { + print $message->Content; + } else { + print $message->ContentType, " not shown"; + } + } + print "\n"; + return(); +} +# }}} + + +# {{{ sub BuildListingFormat + +sub BuildListingFormat { + my $format_string = shift; + + my ($id, @format, @code, @titles); + my ($field,$titles,$length, $format); + + my $code = ""; + + # {{{ attribs + my $attribs = { id => { chars => '4', + justify => 'r', + title => 'id', + value => '$Ticket->id', + }, + + queue => { chars => '8', + justify => 'l', + title => 'Queue', + value => '$Ticket->QueueObj->Name' + }, + subject => { chars => '30', + justify => 'l', + title => 'Subject', + value => '$Ticket->Subject', + }, + priority => { chars => '2', + justify => 'r', + title => 'Pri', + value => '$Ticket->Priority', + }, + final_priority => { chars => '2', + justify => 'r', + title => 'Fin', + value => '$Ticket->FinalPriority', + }, + time_worked => { chars => '6', + justify => 'r', + title => 'Worked', + value => '$Ticket->TimeWorked', + }, + time_left => { chars => '5', + justify => 'r', + title => 'Left', + value => '$Ticket->TimeLeft', + + }, + + status => { chars => '6', + justify => 'r', + title => 'Status', + value => '$Ticket->Status', + }, + owner => { chars => '10', + justify => 'r', + title => 'Owner', + value => '$Ticket->OwnerObj->Name' + }, + requestor => { chars => '10', + justify => 'r', + title => 'Requestor', + value => '$Ticket->RequestorsAsString' + }, + created => { chars => '12', + justify => 'r', + title => 'Created', + value => '$Ticket->CreatedAsString' + }, + updated => { chars => '12', + justify => 'r', + title => 'Updated', + value => '$Ticket->LastUpdatedAsString' + }, + due => { chars => '12', + justify => 'r', + title => 'Due', + value => '$Ticket->DueAsString' + }, + told => { chars => '12', + justify => 'r', + title => 'Told', + value => '$Ticket->ToldAsString' + }, + + + + }; + + # }}} + + + foreach $field (split ('%',$format_string)) { + + if ($field =~ /^(\D*?)(\d*?)$/) { + $id = $1; + $length = $2; + } + else { + $RT::Logger->debug ("Error parsing $field\n"); + } + if ($length) { + push (@format, "%".$length.".".$length."s "); + + push (@code, $attribs->{"$id"}->{'value'}); + + push (@titles, "'". $attribs->{"$id"}->{title}. "'"); + } + + + } + $code = join (',', @code); + $format = join (" ", @format); + $titles = join (', ', @titles); + + + return ($format, $titles, $code); +} + +# }}} + + + +1; |