Approvals no longer in files, but in the ticket comments.

This script was originally written to handle the approval data appearing in
files in a directory rather than the ticket traffic itself.  This change
reworks that so that the script is always processing a group of tickets, and
searches for payment approval in the ticket traffic itself.

Note that this change is not yet secure, as the interns, if they know format,
could "approve themselves".  The "security" comes from the script before (or
a by hand action with someone with RT access to set the completed-internship
field to 'payment-N-approved'.
This commit is contained in:
Bradley M. Kuhn 2019-02-28 16:09:25 -08:00
parent 6a659c102c
commit e5bf1e9f90

View file

@ -210,10 +210,6 @@ if (@ARGV > 0) {
}
push(@processList, $ticket);
}
} elsif ($PAYMENT_NUMBER != 1) {
opendir(my $dh, $PAYMENT_DIR);
@processList = readdir $dh;
close $dh;
} else {
open(my $rtLsFH, "-|", "$RT_CMD", "ls", "-i", 'Queue = outreachy-interns ' .
"AND Subject LIKE '" . $ROUND . "' AND status = 'needs-project-ok'");
@ -226,60 +222,55 @@ if (@ARGV > 0) {
close $rtLsFH;
}
foreach my $entry (@processList) {
my($ticket, $pass, $mentorDate);
foreach my $ticket (@processList) {
my(%paymentVals, $pass, $mentorDate, $approvalTag);
if ($PAYMENT_NUMBER == 1) {
$ticket = $entry;
$pass = 1;
$mentorDate = $LEDGER_ENTRY_DATE;
} else {
unless ($entry =~ /^\s*(success|faile?d?)-(\S+)\.txt\s*$/i) {
print STDERR "Skipping $entry which does not match proper format...\n" if ($VERBOSE >= 2);
next;
}
my $name;
($pass, $name) = ($1, $2);
$pass = ($pass =~ /success/) ? 1 : 0;
$approvalTag = " ;Approval: $OVERRIDE_APPROVAL_TAG";
}
my $ticketNum = $ticket; $ticketNum =~ s%^.*ticket/(\d+).*$%$1%;
open(my $fh, "<", File::Spec->catfile($PAYMENT_DIR, $entry));
my $mentorDate;
while (my $line = <$fh> ) {
if ($line =~ /^\s*Date\s*:\s*(.+)\s*$/) {
$mentorDate = UnixDate(ParseDate($1), "%Y-%m-%d");
open(my $logFH, "-|", $RT_CMD, "show", $ticketNum);
while (my $line = <$logFH>) {
if ($line =~ /^\s*([^:]+)\s*:\s*(.+)$/) {
my($key, $val) = ($1, $2);
# Note that this will take the last one used, since rt log gives ticket traffic IN ORDER.
$paymentVals{$key} = $val if $key =~ /(CONTRACTED NAME|PAYMENT NAME|PAYMENT METHOD)/i;
print STDERR "\"$ticket\": rt show $ticketNum line match: $key $val for $line" if ($VERBOSE > 7);
} elsif ($PAYMENT_NUMBER != 1 and (not defined $pass) and $line =~ /^\s*Payment\s+approved\s+by/) {
$pass = 1;
$line = <$logFH>;
unless ($line =~ /^\s*on([\d:\+\.\-\s]+)\s+from/) {
print STDERR "\"$ticket\": Skipping: Found Payment approved but there is no proper date field.";
next;
}
}
if (not defined $mentorDate) {
print STDERR "\"$entry\": Skipping: Inside that file there is no valid Date: header" ;
next;
}
my(@nameComponents) = split(/\s*-\s*/, $name);
my(@searchTerms);
foreach my $name (@nameComponents) {
push(@searchTerms, 'Subject LIKE "' . $name . '"');
}
# Find the ticket number for this intern.
my $ticket = Outreachy_FindUniqueTicket($ROUND, @searchTerms);
if (not defined $ticket) {
foreach my $term (@searchTerms) {
print STDERR "\"$entry\": full search failed, trying \"$term\" by itself\n" if ($VERBOSE > 6);
$ticket = Outreachy_FindUniqueTicket($ROUND, ($term));
last if (defined $ticket);
$mentorDate = UnixDate(ParseDate($1), "%Y-%m-%d");
next unless defined $mentorDate;
my $attachmentNum;
while (my $subLine = <$logFH>) {
last if $subLine =~ /^\=\=\=\>\s+/;
if ($subLine =~ /^\s+(\d+)\s+\:/) {
$attachmentNum = $1;
last;
}
}
$approvalTag = " ;Approval: rt://ticket/${ticketNum}/attachments/";
}
}
if (not defined $ticket) {
if (not $INTERACTIVE) {
print STDERR "\"$entry\": TICKET-NOT-FOUND: Skipped: unable to to find a matching ticket.\n";
next;
} else {
# FIXME: prompt for ticket
die "interactive mode not yet supported";
}
close $logFH;
if (not defined $pass) {
print STDERR "\"$ticket\": Skipping: pass/fail information not found" ;
next;
}
if ($pass and not defined $mentorDate) {
print STDERR "\"$ticket\": Skipping: there was a pass here for this payment, but unable to find mentor evaluation date for that pass." ;
next;
}
my $completedInternshipField = GetCustomFieldForTicket($ticket, "completed-internship");
if (not defined $completedInternshipField) {
print STDERR "\"$entry\": \"$ticket\": FIELD-NOT-FOUND: Skipping: cannot determine Entity from ticket.\n" ;
print STDERR "\"$ticket\": FIELD-NOT-FOUND: Skipping: cannot determine Entity from ticket.\n" ;
next;
} elsif ($completedInternshipField eq 'successful') {
# Don't print to STDERR here, just keep a count since these are "old interns"
@ -288,7 +279,7 @@ foreach my $entry (@processList) {
}
my $entity = LedgerTagFromTicket($ticket, 'Entity');
if (not defined $entity) {
print STDERR "\"$entry\": \"$ticket\": ENTITY-NOT-FOUND: Skipping: cannot determine Entity from ticket.\n" ;
print STDERR "\"$ticket\": ENTITY-NOT-FOUND: Skipping: cannot determine Entity from ticket.\n" ;
next;
}
@ -299,7 +290,7 @@ foreach my $entry (@processList) {
# Check to see if this payment was already made
my $thisPayDate = PaymentDateByTicket($ticket, $PAYMENT_NUMBER);
if (defined $thisPayDate) {
print STDERR "\"$entry\": \"$ticket\": Skipped: payment $PAYMENT_NUMBER",
print STDERR "\"$ticket\": Skipped: payment $PAYMENT_NUMBER",
" was already made on \"$thisPayDate\"";
if ($pass) {
print STDERR ".\n";
@ -314,7 +305,7 @@ foreach my $entry (@processList) {
if ($prevPayNum > 0) {
my $lastPayDate = PaymentDateByTicket($ticket, $prevPayNum);
if (not defined $lastPayDate) {
print STDERR "\"$entry\": \"$ticket\": Skipped: payment $prevPayNum was not made yet";
print STDERR "\"$ticket\": Skipped: payment $prevPayNum was not made yet";
if ($pass) {
print STDERR ".\n";
} else {
@ -325,69 +316,47 @@ foreach my $entry (@processList) {
}
my $expectVal = 'payment-' . $PAYMENT_NUMBER . "-approved";
if ($completedInternshipField eq $expectVal and $PAYMENT_NUMBER != 1) {
print STDERR "\"$entry\": \"$ticket\": $PAYMENT_NUMBER PAYMENT-DONE: Skipped: completed-internship is ",
print STDERR "\"$ticket\": $PAYMENT_NUMBER PAYMENT-DONE: Skipped: completed-internship is ",
"\"$completedInternshipField\" which indicates this payment round is in process.\n";
next;
}
$expectVal = 'payment-' . $prevPayNum . "-approved" if $PAYMENT_NUMBER != 1;
if ($prevPayNum > 0 and $completedInternshipField ne $expectVal) {
print STDERR "\"$entry\": \"$ticket\": Skipped: completed-internship field was ",
print STDERR "\"$ticket\": Skipped: completed-internship field was ",
"\"$completedInternshipField\" instead of \"$expectVal\".\n";
next;
}
my(%links) = GetLinksForTicket($ticket);
if ($VERBOSE > 5) {
use Data::Dumper;
print STDERR "\"$entry\": \"$ticket\": Found the following links: " , Data::Dumper->Dump([\%links]), "\n";
print STDERR "\"$ticket\": Found the following links: " , Data::Dumper->Dump([\%links]), "\n";
}
my $taxTicket = FindTaxTicketFromList(@{$links{DependsOn}});
if (not defined $taxTicket) {
print STDERR "\"$entry\": \"$ticket\": Skipped: no tax ticket found.\n";
print STDERR "\"$ticket\": Skipped: no tax ticket found.\n";
next;
}
my $reimbursementTicket = FindReimbursementTicketFromList($ROUND, @{$links{Members}});
if (not defined $reimbursementTicket) {
print STDERR "\"$entry\": \"$ticket\": Skipped: no reimbursement ticket found.\n";
print STDERR "\"$ticket\": Skipped: no reimbursement ticket found.\n";
next;
}
print STDERR "\"$entry\": \"$ticket\": found a tax ticket of \"$taxTicket\"\n" if ($VERBOSE > 5);
print STDERR "\"$ticket\": found a tax ticket of \"$taxTicket\"\n" if ($VERBOSE > 5);
my $taxTicketStatus = GetStatusFromTicket($taxTicket);
if ($taxTicketStatus ne "resolved") {
print STDERR "\"$entry\": \"$ticket\": TAX-TICKET-PENDING: \"$taxTicket\": Skipped: ",
print STDERR "\"$ticket\": TAX-TICKET-PENDING: \"$taxTicket\": Skipped: ",
"tax ticket is in status \"$taxTicketStatus\" instead of \"resolved\"\n";
next;
}
my $mainTicketStatus = GetStatusFromTicket($ticket);
if ($mainTicketStatus ne "needs-project-ok") {
print STDERR "\"$entry\": \"$ticket\": PREV-PAYMENT-INCOMPLETE: Skipped: ",
print STDERR "\"$ticket\": PREV-PAYMENT-INCOMPLETE: Skipped: ",
"ticket is in status \"$mainTicketStatus\" instead of \"needs-project-ok\"\n";
next;
}
my $ticketNum = $ticket; $ticketNum =~ s%^.*ticket/(\d+).*$%$1%;
my %paymentVals;
open(my $logFH, "-|", $RT_CMD, "show", $ticketNum);
while (my $line = <$logFH>) {
# Note that this will take the last one used, since rt log gives ticket traffic IN ORDER.
if ($line =~ /^\s*([^:]+)\s*:\s*(.+)$/) {
my($key, $val) = ($1, $2);
$paymentVals{$key} = $val if $key =~ /(CONTRACTED NAME|PAYMENT NAME|PAYMENT METHOD)/i;
print STDERR "\"$entry\": \"$ticket\": rt show $ticketNum line match: $key $val for $line" if ($VERBOSE > 7);
}
}
close $logFH;
print STDERR "\"$entry\": \"$ticket\": processing to payment $PAYMENT_NUMBER state... ";
print STDERR "\"$ticket\": processing to payment $PAYMENT_NUMBER state... ";
my $successString = ($pass) ? "success" : "failed";
my $repositoryFile = File::Spec->catfile($PAYMENT_DIR, $mentorDate . "_" . $entity . '_' . $successString . '-report.mbox');
my $approvalTag = $repositoryFile;
if ($PAYMENT_NUMBER == 1) {
$approvalTag = " ;Approval: $OVERRIDE_APPROVAL_TAG";
} else {
$approvalTag =~ s%^.*(Projects/Outreachy/.*)$%$1%;
$approvalTag = " ;Approval: $approvalTag";
rename(File::Spec->catfile($PAYMENT_DIR, $entry), $repositoryFile);
system($SVN_CMD, "add", $repositoryFile);
}
open(my $rtCorrespondFH, "|-", $RT_CMD, 'correspond', $ticket, '-m', '-');
my @dd;
foreach my $line (@{$internCorrespond{$successString}}) {
@ -459,12 +428,12 @@ LEDGER_ENTRY
$travelTicketNum =~ s%^.*ticket/(\d+).*$%$1%;
my $travelTicketStatus = GetStatusFromTicket($travelTicketNum);
if ( (not defined $travelTicketSpec) or $travelTicketStatus ne 'needs-project-ok') {
print STDERR "\"$entry\": \"$ticket\": Travel Ticket: \"$travelTicketSpec\": unable to open travel ticket which is in status \"$travelTicketStatus\"\n";
print STDERR "\"$ticket\": Travel Ticket: \"$travelTicketSpec\": unable to open travel ticket which is in status \"$travelTicketStatus\"\n";
goto NEXT_TICKET;
}
my $found = TravelTicketDeLink($TRAVEL_NOTICE_TICKET, $travelTicketNum);
if ((not defined $found) or (not $found)) {
print STDERR "\"$entry\": \"$ticket\": WARNING: unable to open travel ticket, $travelTicketNum, as it is not linked to $TRAVEL_NOTICE_TICKET... ";
print STDERR "\"$ticket\": WARNING: unable to open travel ticket, $travelTicketNum, as it is not linked to $TRAVEL_NOTICE_TICKET... ";
goto NEXT_TICKET;
}
open(my $travelTicketCorrespondFH, "|-", $RT_CMD, 'correspond', $travelTicketNum, '-m', '-');
@ -493,7 +462,7 @@ LEDGER_ENTRY
my $travelTicketNum = $travelTicketSpec;
my $found = TravelTicketDeLink($TRAVEL_NOTICE_TICKET, $travelTicketNum);
if (not defined $found) {
print STDERR "\"$entry\": \"$ticket\": WARNING: unable to determine what to do about Travel ticket, $travelTicketNum, as it is not linked to $TRAVEL_NOTICE_TICKET... ";
print STDERR "\"$ticket\": WARNING: unable to determine what to do about Travel ticket, $travelTicketNum, as it is not linked to $TRAVEL_NOTICE_TICKET... ";
} elsif (not $found) {
# This means we already activiated this travel ticket, so we have to explain to the intern
open(my $travelTicketCorrespondFH, "|-", $RT_CMD, 'correspond', $travelTicketNum, '-m', '-');