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); push(@processList, $ticket);
} }
} elsif ($PAYMENT_NUMBER != 1) {
opendir(my $dh, $PAYMENT_DIR);
@processList = readdir $dh;
close $dh;
} else { } else {
open(my $rtLsFH, "-|", "$RT_CMD", "ls", "-i", 'Queue = outreachy-interns ' . open(my $rtLsFH, "-|", "$RT_CMD", "ls", "-i", 'Queue = outreachy-interns ' .
"AND Subject LIKE '" . $ROUND . "' AND status = 'needs-project-ok'"); "AND Subject LIKE '" . $ROUND . "' AND status = 'needs-project-ok'");
@ -226,60 +222,55 @@ if (@ARGV > 0) {
close $rtLsFH; close $rtLsFH;
} }
foreach my $entry (@processList) { foreach my $ticket (@processList) {
my($ticket, $pass, $mentorDate); my(%paymentVals, $pass, $mentorDate, $approvalTag);
if ($PAYMENT_NUMBER == 1) { if ($PAYMENT_NUMBER == 1) {
$ticket = $entry;
$pass = 1; $pass = 1;
$mentorDate = $LEDGER_ENTRY_DATE; $mentorDate = $LEDGER_ENTRY_DATE;
} else { $approvalTag = " ;Approval: $OVERRIDE_APPROVAL_TAG";
unless ($entry =~ /^\s*(success|faile?d?)-(\S+)\.txt\s*$/i) { }
print STDERR "Skipping $entry which does not match proper format...\n" if ($VERBOSE >= 2); my $ticketNum = $ticket; $ticketNum =~ s%^.*ticket/(\d+).*$%$1%;
next;
}
my $name;
($pass, $name) = ($1, $2);
$pass = ($pass =~ /success/) ? 1 : 0;
open(my $fh, "<", File::Spec->catfile($PAYMENT_DIR, $entry)); open(my $logFH, "-|", $RT_CMD, "show", $ticketNum);
my $mentorDate; while (my $line = <$logFH>) {
while (my $line = <$fh> ) { if ($line =~ /^\s*([^:]+)\s*:\s*(.+)$/) {
if ($line =~ /^\s*Date\s*:\s*(.+)\s*$/) { my($key, $val) = ($1, $2);
$mentorDate = UnixDate(ParseDate($1), "%Y-%m-%d"); # 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; next;
} }
} $mentorDate = UnixDate(ParseDate($1), "%Y-%m-%d");
if (not defined $mentorDate) { next unless defined $mentorDate;
print STDERR "\"$entry\": Skipping: Inside that file there is no valid Date: header" ; my $attachmentNum;
next; while (my $subLine = <$logFH>) {
} last if $subLine =~ /^\=\=\=\>\s+/;
my(@nameComponents) = split(/\s*-\s*/, $name); if ($subLine =~ /^\s+(\d+)\s+\:/) {
my(@searchTerms); $attachmentNum = $1;
foreach my $name (@nameComponents) { last;
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);
} }
$approvalTag = " ;Approval: rt://ticket/${ticketNum}/attachments/";
} }
} }
if (not defined $ticket) { close $logFH;
if (not $INTERACTIVE) { if (not defined $pass) {
print STDERR "\"$entry\": TICKET-NOT-FOUND: Skipped: unable to to find a matching ticket.\n"; print STDERR "\"$ticket\": Skipping: pass/fail information not found" ;
next; next;
} else { }
# FIXME: prompt for ticket if ($pass and not defined $mentorDate) {
die "interactive mode not yet supported"; 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"); my $completedInternshipField = GetCustomFieldForTicket($ticket, "completed-internship");
if (not defined $completedInternshipField) { 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; next;
} elsif ($completedInternshipField eq 'successful') { } elsif ($completedInternshipField eq 'successful') {
# Don't print to STDERR here, just keep a count since these are "old interns" # 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'); my $entity = LedgerTagFromTicket($ticket, 'Entity');
if (not defined $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; next;
} }
@ -299,7 +290,7 @@ foreach my $entry (@processList) {
# Check to see if this payment was already made # Check to see if this payment was already made
my $thisPayDate = PaymentDateByTicket($ticket, $PAYMENT_NUMBER); my $thisPayDate = PaymentDateByTicket($ticket, $PAYMENT_NUMBER);
if (defined $thisPayDate) { if (defined $thisPayDate) {
print STDERR "\"$entry\": \"$ticket\": Skipped: payment $PAYMENT_NUMBER", print STDERR "\"$ticket\": Skipped: payment $PAYMENT_NUMBER",
" was already made on \"$thisPayDate\""; " was already made on \"$thisPayDate\"";
if ($pass) { if ($pass) {
print STDERR ".\n"; print STDERR ".\n";
@ -314,7 +305,7 @@ foreach my $entry (@processList) {
if ($prevPayNum > 0) { if ($prevPayNum > 0) {
my $lastPayDate = PaymentDateByTicket($ticket, $prevPayNum); my $lastPayDate = PaymentDateByTicket($ticket, $prevPayNum);
if (not defined $lastPayDate) { 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) { if ($pass) {
print STDERR ".\n"; print STDERR ".\n";
} else { } else {
@ -325,69 +316,47 @@ foreach my $entry (@processList) {
} }
my $expectVal = 'payment-' . $PAYMENT_NUMBER . "-approved"; my $expectVal = 'payment-' . $PAYMENT_NUMBER . "-approved";
if ($completedInternshipField eq $expectVal and $PAYMENT_NUMBER != 1) { 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"; "\"$completedInternshipField\" which indicates this payment round is in process.\n";
next; next;
} }
$expectVal = 'payment-' . $prevPayNum . "-approved" if $PAYMENT_NUMBER != 1; $expectVal = 'payment-' . $prevPayNum . "-approved" if $PAYMENT_NUMBER != 1;
if ($prevPayNum > 0 and $completedInternshipField ne $expectVal) { 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"; "\"$completedInternshipField\" instead of \"$expectVal\".\n";
next; next;
} }
my(%links) = GetLinksForTicket($ticket); my(%links) = GetLinksForTicket($ticket);
if ($VERBOSE > 5) { if ($VERBOSE > 5) {
use Data::Dumper; 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}}); my $taxTicket = FindTaxTicketFromList(@{$links{DependsOn}});
if (not defined $taxTicket) { if (not defined $taxTicket) {
print STDERR "\"$entry\": \"$ticket\": Skipped: no tax ticket found.\n"; print STDERR "\"$ticket\": Skipped: no tax ticket found.\n";
next; next;
} }
my $reimbursementTicket = FindReimbursementTicketFromList($ROUND, @{$links{Members}}); my $reimbursementTicket = FindReimbursementTicketFromList($ROUND, @{$links{Members}});
if (not defined $reimbursementTicket) { if (not defined $reimbursementTicket) {
print STDERR "\"$entry\": \"$ticket\": Skipped: no reimbursement ticket found.\n"; print STDERR "\"$ticket\": Skipped: no reimbursement ticket found.\n";
next; 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); my $taxTicketStatus = GetStatusFromTicket($taxTicket);
if ($taxTicketStatus ne "resolved") { 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"; "tax ticket is in status \"$taxTicketStatus\" instead of \"resolved\"\n";
next; next;
} }
my $mainTicketStatus = GetStatusFromTicket($ticket); my $mainTicketStatus = GetStatusFromTicket($ticket);
if ($mainTicketStatus ne "needs-project-ok") { 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"; "ticket is in status \"$mainTicketStatus\" instead of \"needs-project-ok\"\n";
next; 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 $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', '-'); open(my $rtCorrespondFH, "|-", $RT_CMD, 'correspond', $ticket, '-m', '-');
my @dd; my @dd;
foreach my $line (@{$internCorrespond{$successString}}) { foreach my $line (@{$internCorrespond{$successString}}) {
@ -459,12 +428,12 @@ LEDGER_ENTRY
$travelTicketNum =~ s%^.*ticket/(\d+).*$%$1%; $travelTicketNum =~ s%^.*ticket/(\d+).*$%$1%;
my $travelTicketStatus = GetStatusFromTicket($travelTicketNum); my $travelTicketStatus = GetStatusFromTicket($travelTicketNum);
if ( (not defined $travelTicketSpec) or $travelTicketStatus ne 'needs-project-ok') { 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; goto NEXT_TICKET;
} }
my $found = TravelTicketDeLink($TRAVEL_NOTICE_TICKET, $travelTicketNum); my $found = TravelTicketDeLink($TRAVEL_NOTICE_TICKET, $travelTicketNum);
if ((not defined $found) or (not $found)) { 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; goto NEXT_TICKET;
} }
open(my $travelTicketCorrespondFH, "|-", $RT_CMD, 'correspond', $travelTicketNum, '-m', '-'); open(my $travelTicketCorrespondFH, "|-", $RT_CMD, 'correspond', $travelTicketNum, '-m', '-');
@ -493,7 +462,7 @@ LEDGER_ENTRY
my $travelTicketNum = $travelTicketSpec; my $travelTicketNum = $travelTicketSpec;
my $found = TravelTicketDeLink($TRAVEL_NOTICE_TICKET, $travelTicketNum); my $found = TravelTicketDeLink($TRAVEL_NOTICE_TICKET, $travelTicketNum);
if (not defined $found) { 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) { } elsif (not $found) {
# This means we already activiated this travel ticket, so we have to explain to the intern # This means we already activiated this travel ticket, so we have to explain to the intern
open(my $travelTicketCorrespondFH, "|-", $RT_CMD, 'correspond', $travelTicketNum, '-m', '-'); open(my $travelTicketCorrespondFH, "|-", $RT_CMD, 'correspond', $travelTicketNum, '-m', '-');