#!/usr/local/bin/perl # CGIgnats.pl - a WWW interface to the GNATS bug tracking system # Based on wwwgnats.pl, by Dan Kegel and Huy Lee use CGI require "libgnats.pl"; # Configuration begins here # Miscellanous data $EDITOR_FILE = "$GNATS_LIB/gnats/local/editors"; $ORIGIN_FILE = $EDITOR_FILE; # Outside commands $MAILER = "/usr/sbin/sendmail -oi -t"; $DATEPROG = "/bin/date"; $LSPROG = "/bin/ls"; # Configuration ends here # Modification log: # 7/14/94 Dan Kegel (dank@adventure.com) - Originally written # 7/15/94 Huy Le - Created front-end, added quick-query output restrictions # 7/16/94 Dan Kegel - added config section & read responsible file # 7/18/94 Huy Le - Added send-pr function # 8/19/94 Huy Le - Added edit-pr function # 1/17/95 Dan Kegel - Rewrote edit-pr for robustness # 1/20/95 Dan Kegel - cleanup, added way to look for bugs waiting on person # 1/20/95 Dan Kegel - added a button to report summary of active bugs # 1/30/95 Dan Kegel - Moved some code into sub parse_pr() # 2/1/95 Dan kegel - moved all non-WWW code into libgnats.pl # 3/1/95 Dan Kegel - Edit code now uses associative array to represent # current PR. PR is output in fixed order, not input order. # Fewer hardcoded paths to external programs. Moved pr_addr code to # subroutine in libgnats.pl. # 3/2/95 Dan Kegel - Fixed small bug in timestamp; : was confusing browsers. # 4/16/96 Brian Lenihan - modified forms for PN use # 4/18/96 Brian Lenihan - modified to use HTML tables # 4/20/96 Brian Lenihan - modified to use perl5 CGI module # 7/30/96 Brian Lenihan - added javascript # End Modifcation log # Array definitions # Query-pr's -i option outputs the following fields numerically. # Define arrays to map numbers to name. # Arrays for quick output display with restricted output fields @quickSeverity = ("", "critical", "serious", "non-critical"); @quickPriority = ("", "high", "medium", "low"); @quickfmt = ("brief","regular","verbose"); # Array for Organizations @nOrganization = ( "pndev", "pnqa", ); # The number is the quickfmt %field = ( "CATEGORY", "0", "RELEASE", "2", "SEVERITY", "1", "PRIORITY", "4", # Not displayed "RESPONSIBLE", "0", "STATE", "0", "CLASS", "1", "SUBMITTER", "4", # Not displayed "ARRIVAL_DATE", "2", "ORIGINATOR", "1", "SYNOPSIS", "0", ); # Defines order of field display in quick output @field = ( "CATEGORY", "SEVERITY", "PRIORITY", "RESPONSIBLE", "STATE", "CLASS", "SUBMITTER", "ARRIVAL_DATE", "RELEASE", "ORIGINATOR", "SYNOPSIS", ); # Defines order of quick output restrictions @quickrestr = ( "Category", "State", "Responsible", "Originator", ); # Main routine $query = new CGI; $scriptname = $query->script_name(); print $query->header('text/html','200 OK'); $jscript=<param('Cmd'); &read_originator; &read_editor; # Dump query key/value pairs for debugging #&dumpkeys($query); # Submit a new PR if ($cmd eq 'send_pr') { &send_pr($query); } elsif ($cmd eq 'do_send_pr') { &do_send_pr($query); # Edit an existing PR } elsif ($cmd eq 'edit_pr') { &edit_pr($query); } elsif ($cmd eq 'do_edit_pr') { &do_edit_pr($query); # Display the entire PR } elsif ($cmd eq 'full') { &query_full($query); # Query a number of PR's and display in quick output form } elsif ($cmd eq 'quick') { &query_quick($query); # Get count of pending bugs by category } elsif ($cmd eq 'summary_cat') { &query_summary_cat($query); # Get count of pending bugs by person } elsif ($cmd eq 'summary') { &query_summary($query); # Main menu } elsif ($cmd eq "") { print $query->start_html(-title=>"GNATS problem report management", -script=>$jscript, -background=>'/pix/o030.jpg', -text=>'#FFFF00', -link=>'#DDECA4', -vlink=>'#DDECA4'); &main_menu($query); print "
Version: 30 Jul 96
Send problems or comments on this system to:\n"; print "brianl\@prognet\.com
\n"; print $query->end_html(); } else { print $query->start_html("SPR Front End"); print "

SPR Front End

\n"; print "Bad subdirectory/parameters specified in URL.\n"; print $query->end_html(); } #&dumpenv; exit(0); # Miscellaneous functions # Dumps the environment sub dumpenv { print "\n


\n"; print "

\n";
    foreach (sort(keys(%ENV))) {
    	print "$_ ", $ENV{$_}, "\n";
    }
    print "
\n"; } # Dumps the query parameters sub dumpkeys { my($query) = @_; local(@values); foreach $key ($query->param) { print "$key -> "; @values = $query->param($key); print join(", ",@values), "
\n"; } } # Reads in possible PR originators sub read_originator { # Full_name e-mail@address of originators # Huy_Le Huy_Le@ccmail.adventure.com open(ORIGINATOR, "$ORIGIN_FILE") || die "Couldn't get originator file\n"; while () { if (!/^\s*(#|\n)/) { ($name, $email) = split(/ /); chop($email); $nOriginator{$name} = $email; } } close(ORIGINATOR); @nOriginator = sort(keys(%nOriginator)); } # Reads in possible PR editors sub read_editor { # Full_name e-mail@address of editors # Huy_Le Huy_Le@ccmail.adventure.com open(EDITOR, "$EDITOR_FILE") || die "Couldn't open editor file $EDITOR_FILE\n"; while () { if (!/^\s*(#|\n)/) { ($name, $email) = split(/ /); chop($email); $nEditor{$name} = $email; } } close(EDITOR); @nEditor = sort(keys(%nEditor)); } # PR submission # Sends the new PR sub do_send_pr { my($query) = @_; my(@values,$key); # Display title print $query->start_html("New Problem Report Submission"); # Get arguments undef(%fieldvalues); # Global! foreach $key ($query->param) { local($val) = $query->param($key); # By convention, multi-line fields have newlines at end of # each line. I think some browsers forget the last newline? if ($fieldnames_multi{$key} > 0 && $val !~ /\n$/) { $val .= "\n"; } $fieldvalues{$key}=$val; } # Verify arguments local($field); foreach $field ("Originator", "Category") { if ($fieldvalues{$field} eq "") { print "

Your problem report has not been sent.

\n"; print "You must fill in the $field field.\n"; return; } } # megakludge. $fieldvalues{"Submitter-Id"} = $fieldvalues{"Organization"}; # Send the PR $prtext = &unparse_pr("send"); open(MAIL, "|$MAILER") || die "Error while invoking sendmail"; print MAIL "To: $GNATS_ADDR Subject: From: $nOriginator{$fieldvalues{\"Originator\"}} ($fieldvalues{\"Originator\"}) Reply-to: $nOriginator{$fieldvalues{\"Originator\"}} ($fieldvalues{\"Originator\"}) X-send-pr-version: $GNATS_VER $prtext"; close(MAIL); print "

Your problem report has been sent. It will take about a minute to show up in the system.

\n"; } sub send_pr { my($query) = @_; print $query->start_html("New Problem Report Submission"); print "

New Problem Report form:

\n"; print "
To send mail to the proper member of the server team, in order to notify them about issues or problems with a particular server subsystem, fill out this form and the email message will be sent both to the developer responsible for the Server subsystem and to Dion O'Neill (program manager).
"; print $query->startform(); $query->delete('Cmd'); print $query->hidden('Cmd','do_send_pr'); print "
"; print "\n"; print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
"; print "Please see the field \n"; print "\n"; print "descriptions if you are not sure how to fill out this form

\n"; print "

\n"; print "Organization: \n"; print ""; print $query->radio_group( -name=>'Organization', -values=>\@nOrganization, -default=>'pndev', -override=>1); print "
\n"; print "Originator (your e-mail address): \n"; print "\n"; print $query->textfield( -name=>'Originator', -size=>16); print "
\n"; print "Server Subsystem: \n"; print "\n"; print $query->popup_menu( -name=>'Category', -values=>\@nCategory, -default=>'server_core', -override=>1); print "
\n"; print "Class: \n"; print "\n"; print $query->popup_menu( -name=>'Class', -values=>\@nClass, -default=>'sw-bug', -override=>1); print "
\n"; print "Severity: \n"; print "\n"; print $query->popup_menu( -name=>'Severity', -values=>\@nSeverity, -default=>'serious', -override=>1); print "
\n"; print "Priority: \n"; print "\n"; print $query->popup_menu( -name=>'Priority', -values=>\@nPriority, -default=>'high', -override=>1); print "
\n"; print "Release (given in program -v output): \n"; print "\n"; print $query->textfield( -name=>"Release", -size=>20); print "

\n"; # Maximize box dimensions local($width)= 80; local($height)= 4; local($height2)=$height*2; print "Synopsis of the issue or problem:
\n"; print $query->textfield( -name=>'Synopsis', -default=>'', -override=>1, -size=>$width); print "
Description of the issue or problem you noted:
\n"; print $query->textarea( -name=>'Description', -default=>'', -override=>1, -cols=>$width, -rows=>$height2); print "
How-To-Repeat:
\n"; print $query->textarea( -name=>'How-To-Repeat', -default=>'', -override=>1, -cols=>$width, -rows=>$height); print "
Anything relevant about the machine environment, including operating system:
\n"; print $query->textarea( -name=>'Environment', -default=>'', -override=>1, -cols=>$width, -rows=>$height); print "

\n"; print $query->submit('Send Mail'); print " or \n"; print $query->reset('Clear the page.'); print "
\n"; print $query->endform(); print $query->end_html(); } # PR editing # Gets the timestamp of the given file sub timestamp { local($fname) = shift(@_); open(TIMESTAMP, "$LSPROG -l $fname|") || die "Error: can't record the timestamp of the PR ($fname)"; ($_=)=~ /\s(\S+\s+\S+\s+\S+)\s+\S+$/ || die "Error: can't record the timestamp of the PR ($fname)"; close(TIMESTAMP); local($ts)=$1; $ts =~ tr/ /+/; $ts =~ tr/:/_/; $ts; } # Sends the PR changes sub do_edit_pr { my($query) = @_; my(@values,$key); # Display title print $query->start_html( -title=>'Problem Report editing', -script=>$jscript); # Initialization $errmsg="

Your problem report changes have not been sent.

\n"; # Get the PR, editor, old state, and timestamp local($pr, $oldstate, $timestamp); $pr = $query->param('Pr'); $oldstate = $query->param('Oldstate'); $timestamp = $query->param('Timestamp'); # Get arguments local(%input); foreach $key ($query->param) { local($val) = $query->param($key); $input{$key} = $val; } # Verify arguments if (!$input{"Editor"}) { print $errmsg, "You must register your name.\n"; return; } # Lock and read the PR into @oldpr and %fieldvalues # Also sets $semipr and $fullpr $err = &read_pr($pr, $input{'Editor'}); if ($err ne "") { print $errmsg, $err; return; } local($oldsyn) = $fieldvalues{'Synopsis'}; local($oldresp) = $fieldvalues{'Responsible'}; $oldresp =~ s/\s*\(.*$//; # Get rid of comment in responsible party name local($reply_to) = $fieldvalues{'Reply-To'}; if ($reply_to eq "") { # "Reply-To:" takes precedence over "From:". $reply_to = $fieldvalues{'From'}; } local($ed_err); local(%mail_to); local($change_msg) = ""; LOCKED: { # Now that pr has been locked, if any errors are encountered, # set $ed_err to the reason and jump to UNLOCK. # Check that the timestamp hasn't changed since the form was generated if ($timestamp ne ×tamp($fullpr)) { $ed_err = "$errmsg\nThis PR has been modified since you started editing it.\n"; last LOCKED; } # Another sanity check if ($reply_to eq "" || $oldresp eq "") { $ed_err = "$errmsg\nHey! Old responsible is '$oldresp', reply address on pr is '$reply_to'!\n"; last LOCKED; } # Get the date local($date); if (!open(DATE, "$DATEPROG|")) { $ed_err = "$errmsg\nError: can't run $DATEPROG"; last LOCKED; } chop($date=); close(DATE); $mail_to{&tolower($nEditor{$input{'Editor'}})} = 1; local($to_subm, $to_old, $to_new); # Update the audit trail if ($input{"State"} ne $fieldvalues{'State'}) { if ($input{'StateReason'} eq "") { $ed_err = "$errmsg\n You must tell why the State changed.\n"; last LOCKED; } $change_msg .= "State-Changed-From-To: $fieldvalues{'State'}-$input{'State'} State-Changed-By: $input{'Editor'} State-Changed-When: $date State-Changed-Why: $input{'StateReason'} "; $to_old = $to_subm = 1; $fieldvalues{'State'} = $input{'State'}; } if ($input{'Responsible'} ne $oldresp) { if ($input{'ResponsibleReason'} eq "") { $ed_err = "$errmsg\nYou must tell why the Responsible person changed.\n"; last LOCKED; } $change_msg .= "Responsible-Changed-From-To: $fieldvalues{'Responsible'}-$input{'Responsible'} Responsible-Changed-By: $input{'Editor'} Responsible-Changed-When: $date Responsible-Changed-Why: $input{'ResponsibleReason'} "; $to_old = $to_new = 1; $fieldvalues{'Responsible'} = $input{'Responsible'}; } if ($input{'Category'} ne $fieldvalues{'Category'}) { # Gnats' original edit-pr command didn't generate an audit # trail for this change # Note: category names might have dashes in them, making # the following line hard to parse! $change_msg .= "Category-Changed-From-To: $fieldvalues{'Category'}-$input{'Category'} Category-Changed-By: $input{'Editor'} Category-Changed-When: $date \n"; $fieldvalues{'Category'} = $input{'Category'}; } # Check that changes were actually made if ($change_msg eq "") { $ed_err = "$errmsg\nNothing was changed.\n"; last LOCKED; } # Add the change log to the PR $fieldvalues{'Audit-Trail'} .= $change_msg; # Generate the mailing list if ($to_subm) { $mail_to{&tolower($reply_to)} = 1; } if ($to_old) { ($adr, $err) = &pr_addr($oldresp); if ($err ne "") { $ed_err = "$errmsg\n$err"; last LOCKED; } $mail_to{&tolower($adr)} = 1; } if ($to_new) { ($adr, $err) = &pr_addr($input{'Responsible'}); if ($err ne "") { $ed_err = "$errmsg\n$err"; last LOCKED; } $mail_to{&tolower($adr)} = 1; } # Apply the changes and send the new PR $newpr = &unparse_pr(""); unlink("/tmp/wwwgnats.$$"); if (!open(PREDIT, "|$PR_EDIT > /tmp/wwwgnats.$$ 2>&1")) { $ed_err = "$errmsg\nError: can't invoke pr-edit\n"; last LOCKED; } print PREDIT $newpr; close(PREDIT); if ($?) { $ed_err = "$errmsg\nError: pr-edit returns status $?, and reports:\n"; if (!open(PREDIT, "/tmp/wwwgnats.$$")) { $ed_err .= "(whoops, no output from pr-edit found; couldn't open /tmp/wwwgnats.$$)\n"; } else { $ed_err .= join("\n",); close(PREDIT); } unlink("/tmp/wwwgnats.$$"); last LOCKED; } unlink("/tmp/wwwgnats.$$"); } # Unlock the PR system("$PR_EDIT --unlock $semipr"); # if we got here via a last, report the error and quit if ($ed_err ne "") { print "
";
	print $ed_err;
	print "
"; print "[Go Back]\n"; return; } # Email-notify all concerned parties local($mail_to); $mail_to = join(", ", sort(keys(%mail_to))); if ($mail_to ne "") { if (open(MAILER, "|$MAILER")) { $msg = "To: $mail_to From: $input{'Editor'} Subject: Changed information for PR $semipr Synopsis: $oldsyn $change_msg "; print MAILER $msg; close(MAILER); # Display message print "

Your changes to PR $pr were filed to the database.

The parties concerned were notified via e-mail as follows:
$msg
"; } else { print "Error: can't run $MAILER\n"; } } } # Gives the interface to change the PR sub edit_pr { my($query) = @_; # Display title print $query->start_html("Problem Report editing"); local($pr) = $query->param('Pr'); if ($pr eq "") { print "

Sorry

\n"; print "You must specify the number of the problem report to edit.\n"; return; } $err = &read_pr($pr, ""); if ($err ne "") { print "$err\n"; return; } local($oldsyn) = $fieldvalues{"Synopsis"}; local($oldstate) = $fieldvalues{"State"}; local($oldresp) = $fieldvalues{"Responsible"}; $oldresp =~ s/\s*\(.*$//; # Get rid of comment in responsible party name local($timestamp)=×tamp($fullpr); # The modification form print "
\n"; print "

Modification form for PR number $pr

\n"; print "
\n"; print "Synopsis: " . $oldsyn . "
\n"; print "

\n"; print "View the full text of PR #$pr"; print "\n"; print "

\n"; print "\n"; print $query->startform(); $query->delete('Cmd'); $query->delete('Pr'); $query->delete('Oldstate'); $query->delete('Timestamp'); print $query->hidden('Cmd','do_edit_pr'); print $query->hidden('Pr',$pr); print $query->hidden('Oldstate',$oldstate); print $query->hidden('Timestamp',$timestamp); # Maximize box dimensions local($width)= 80; local($height)= 4; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; if (! $somebody_resp) { print "Error! No known person responsible for this bug!\n"; } print "\n"; print "\n"; print "\n"; print "
\n"; print "Editor (you):\n"; print "\n"; print $query->hidden( -name=>'Editor', -value=>$query->remote_user()); print "", $query->remote_user(), "\n"; print "
\n"; print "New State:\n"; print "\n"; print $query->popup_menu( -name=>'State', -values=>\@nState, -default=>$oldstate, -override=>1); print "
\n"; print "If state changed, give the reason here:"; print "
\n"; print $query->textarea( -name=>'StateReason', -cols=>$width, -rows=>$height); print "
\n"; print "New category:\n"; print "\n"; print $query->popup_menu( -name=>'Category', -values=>\@nCategory, -default=>$fieldvalues{"Category"}, -override=>1); print "
\n"; print "New responsible person:\n"; print "\n"; print $query->popup_menu( -name=>'Responsible', -values=>\@nResponsible, -default=>$oldresp, -override=>1); local($somebody_resp); foreach $option (@nResponsible) { next if (!$option); if ($option eq $oldresp) { $somebody_resp = 1; } } print "
\n"; print "If responsible person changed, give the reason here:"; print "
\n"; print $query->textarea( -name=>'ResponsibleReason', -cols=>$width, -rows=>$height); print "
\n"; print $query->submit('Submit the changes'); print " or \n"; print $query->reset('Clear the form.'); print "
"; print $query->endform(); print $query->end_html(); } #################### Quick query sub numerically { $a <=> $b; } sub query_quick { my($query) = @_; my(@values,$key); # Print title print $query->start_html(-title=>"Quick summary of PR's", -script=>$jscript); print "


\n"; print "

Quick summary of PR's:


\n"; local($quickfmt) = $query->param('Quickfmt'); # Convert $quickfmt to index into @quickfmt LOOP: for ($i=0; $i<@quickfmt; $i++) { if ($quickfmt eq $quickfmt[$i]) { $quickfmt=$i; last LOOP; } } # Split restrictions into key,value pairs # Collapse multiple selections with same key # Store collapsed restrictions in %restrict local($oldkey,$oldval); local(%restrict); foreach $key ($query->param) { next if ($key eq 'Cmd' || $key eq 'Quickfmt'); if ($oldval ne "") { $restrict{$oldkey} = $oldval; } $oldkey = &tolower($key); $oldval = ""; #just continue adding to the old restriction @selected = $query->param($key); foreach $val (@selected) { $oldval .= "|" if ($oldval ne ""); $oldval .= "$val" if ($val ne ""); } } # Could have put a sentinal on the end of @restrict, but let's duplicate # code instead. if ($oldval ne "") { $restrict{$oldkey} = $oldval; } local($opts); local(@prs); # Read in quick format list of pr's matching query # If querying by person, then do two queries: originator and responsible if ($restrict{"person"} ne "") { $fullname = $restrict{"person"}; # Look up bugs for which this person is the originator. if ($fullname eq "any") { $opts = "--state=\"open|analyzed|feedback\""; } else { $oldval = $fullname; # Turn underscores and spaces into regular expression # that match either underscores or spaces # (Our database sometimes puts underscores instead of spaces). $oldval =~ s/\[s_]/[ _]/g; # Handle bugs with no known originator if ($oldval eq "nobody") { $oldval = "nobody|^\$"; } # Convert this key into a query-pr option $opts = " --originator=\"$oldval\""; # The originator cares about bugs which are in feedback state. $opts .= " --state=\"feedback\""; } print "
query-pr -i $opts\n
\n"; open(PIPE,"$GNATS_BIN/query-pr -i $opts|") || die "Can't open"; @prs = ; close(PIPE); # Look up bugs for which this person is the responsible party. # Convert person's name into nickname $nickname = $fullname2nametag{$fullname}; # Golly, maybe the spaces have been replaced with underscores. if ($nickname eq "") { $fullname =~ s/_/\040/g; $nickname = $fullname2nametag{$fullname}; } if ($nickname ne "") { # Convert this key into a query-pr option $opts = " --responsible=\"$nickname\""; # Responsible person cares about bugs which are open or analyzed. $opts .= " --state=\"open|analyzed\""; print "
query-pr -i $opts\n
\n"; open(PIPE,"$GNATS_BIN/query-pr -i $opts|") || die "Can't open"; @prs = (@prs,); close(PIPE); } else { #print "Warning: $fullname has no nickname.\n"; ; } } else { # Output restrictions as query-pr options foreach (keys(%restrict)) { $oldkey = $_; $oldval = $restrict{$oldkey}; # If "any" was given, don't bother using this key if ($oldval !~ /\bany\b/) { # Turn underscores and spaces into regular expression # that match either underscores or spaces # (Our database sometimes puts underscores instead of spaces). $oldval =~ s/[\s_]/[ _]/g; # Convert this key into a query-pr option $opts .= " --$oldkey=\"$oldval\""; } } print "
query-pr -i $opts\n
\n"; open(PIPE,"$GNATS_BIN/query-pr -i $opts|") || die "Can't open"; @prs = ; close(PIPE); } @prs = sort numerically (@prs); if (@prs == 0) { print "

No bugs match your query.

\n"; return; } # Print field headers. local($QUICKFMT, $fstring, $str); $fstring = ""; print "\n"; print "\n"; foreach (@field) { $QUICKFMT=$field{$_}; if ($QUICKFMT <= $quickfmt) { print "\n"; } } print "\n"; # Print each PR in result as link to full text foreach (@prs) { s/\s*\|\s*/|/go; ( $NUMBER, $CATEGORY, $SYNOPSIS, $CONFIDENTIAL, $SEVERITY, $PRIORITY, $RESPONSIBLE, $STATE, $CLASS, $SUBMITTER, $ARRIVAL_DATE, $ORIGINATOR, $RELEASE ) = split(/\|/, $_); $SEVERITY = $quickSeverity[$SEVERITY]; $PRIORITY = $quickPriority[$PRIORITY]; $STATE = $nState[$STATE - 1]; $CLASS = $nClass[$CLASS - 1]; $fstring = sprintf("%s", substr(" ", 0, (length($NUMBER)<5)?4-length("$NUMBER"):1)); # @field is an array of the variable names $NUMBER, etc., in presentation order. # %field tells which quickfmt level and ?below? to print this variable # in, and how wide to print it. foreach (@field) { $QUICKFMT=$field{$_}; if ($QUICKFMT <= $quickfmt) { $str = eval "\$$_"; $fstring .= ""; } } $query->delete('Cmd'); $query->delete('Pr'); print "\n"; print $fstring; print "\n"; } print "
ID"; print $_; print "
" . $str . "
"; print "$NUMBER\n"; print "
\n"; print $query->end_html(); } sub query_summary { my($query) = @_; # Print title print $query->start_html("Summary of active PR's by person and status"); print "

Summary of active PR's by person and status


\n"; print "
query-pr -i --state=\"open|analyzed|feedback\" \n
\n"; open(PIPE,"$GNATS_BIN/query-pr -i --state=\"open|analyzed|feedback\" |") || die "Can't open"; @prs = ; close(PIPE); if (@prs == 0) { print "

No bugs match your query.

\n"; return; } # Count bugs by person. # Print each PR in result as link to full text local(%counts,%names); foreach (@prs) { s/\s*\|\s*/|/go; ( $NUMBER, $CATEGORY, $SYNOPSIS, $CONFIDENTIAL, $SEVERITY, $PRIORITY, $RESPONSIBLE, $STATE, $CLASS, $SUBMITTER, $ARRIVAL_DATE, $ORIGINATOR, $RELEASE ) = split(/\|/, $_); $STATE = $nState[$STATE - 1]; # Figure out which person this bug is waiting on, if any if ($STATE eq "open" || $STATE eq "analyzed") { # Waiting on responsible person # Convert nickname to fullname $nickname = $RESPONSIBLE; $nickname = &tolower($nickname); $fullname = $nametag2fullname{$nickname}; if ($fullname eq "") { $fullname = $nickname; } } elsif ($STATE eq "feedback") { $fullname = $ORIGINATOR; $fullname = &tolower($fullname); $fullname =~ tr/_/\040/; } if ($fullname eq "") { $fullname = "nobody"; } if ($STATE eq "open" || $STATE eq "analyzed" || $STATE eq "feedback") { $counts{$fullname."_".$STATE}++; $names{$fullname}++; } } # Print field headers. print "\n"; print "\n"; local(@states) = ("open", "analyzed", "feedback"); local($fstring, $str); foreach (@states) { print "\n"; } print "\n"; # Print counts per person. foreach $fullname (sort(keys(%names))) { $fstring = $fullname; local($_fullname) = $fullname; $_fullname =~ tr/ /_/; $fstring =~ s/(\s*)$//; $query->delete('Cmd'); $query->delete('Quickfmt'); $query->delete('Person'); print "\n"; $fstring = ""; foreach (@states) { $str = $counts{$fullname."_".$_}+0; print "\n"; } print "\n"; } print "
"; print $_, "
"; print "$fstring$1"; print "", $str, "
\n"; print $query->end_html(); } sub query_summary_cat { my($query) = @_; # Print title print $query->start_html("Summary of PR's by category and status"); print "

Summary of PR's by category and status


\n"; print "
query-pr -i\n
\n"; open(PIPE,"$GNATS_BIN/query-pr -i |") || die "Can't open"; @prs = ; close(PIPE); if (@prs == 0) { print "

No bugs match your query.

\n"; return; } # Count bugs by category. # Print each PR in result as link to full text local(%counts,%names,%states); foreach (@prs) { s/\s*\|\s*/|/go; ( $NUMBER, $CATEGORY, $SYNOPSIS, $CONFIDENTIAL, $SEVERITY, $PRIORITY, $RESPONSIBLE, $STATE, $CLASS, $SUBMITTER, $ARRIVAL_DATE, $ORIGINATOR, $RELEASE ) = split(/\|/, $_); $STATE = $nState[$STATE - 1]; $counts{$CATEGORY."_".$STATE}++; $names{$CATEGORY}++; $states{$STATE}++; } # Print field headers. print "\n"; local(@states) = sort(keys(%states)); #local(@states) = ("open", "analized", "feedback"); local($fstring, $str); foreach (@states) { print ""; } print "\n"; # Print counts per category. foreach $CATEGORY (sort(keys(%names))) { $fstring = $CATEGORY; $fstring =~ s/(\s*)$//; $query->delete('Cmd'); $query->delete('Quickfmt'); $query->delete('Category'); print "\n"; $fstring = ""; $query->delete('Cmd'); $query->delete('Quickfmt'); $query->delete('Category'); $query->delete('State'); foreach (@states) { next if ($_ eq ""); $str = $counts{$CATEGORY."_".$_}+0; if ($str > 0) { # Who's gonna answer the following query? $fstring = "$str"; } else { $fstring = $str; } print "\n"; } print "\n"; } print "
", $_, "
"; print "$fstring$1"; print "", $fstring, "
\n"; print $query->end_html(); } #################### Full query sub query_full { my($query) = @_; $pr = $query->param('Pr'); print $query->start_html("Full Problem Report Text"); if ($pr eq "") { print "

Sorry

\n"; print "You must specify the number of the problem report to view.\n"; return; } $err = &read_pr($pr, ""); if ($err ne "") { print "$err\n"; } else { print "

Full text of PR number $pr:


\n"; print $query->startform(-action=>"http://horton.dev.prognet.com/cgi-bin/secure/CGIgnats.pl"); print $query->submit('Edit this Report'); $query->delete('Cmd'); print $query->hidden('Cmd','edit_pr'); print $query->hidden('Pr',$pr); print $query->endform(); print "
\n";
	$prtext = (join("",@oldpr));
	print $prtext;
	print "
\n"; print $query->startform(-action=>"http://horton.dev.prognet.com/cgi-bin/secure/CGIgnats.pl"); print $query->submit('Edit this Report'); $query->delete('Cmd'); print $query->hidden('Cmd','edit_pr'); print $query->hidden('Pr',$pr); print $query->endform(); print "
\n"; print $query->end_html(); } } # Main Menu # Very first page of front end sub main_menu { my($query) = @_; # Display title print "\n"; print "

Server Team Bug Tracking System

\n"; print "

\n"; print "

\n"; print "See the GNATS info pages,\n"; print "or choose one of the following commands:

\n"; print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
\n"; print $query->startform(); print $query->hidden('Cmd','send_pr'); print $query->submit('Submit'); print "\n"; print "a new problem report\n"; print $query->endform(); print "
\n"; print $query->startform( -target=>'OpenWindow'); print $query->hidden('Cmd','full'); # XXX this is a CGI.pm 2.25 bug XXX # XXX the next line should be: # print $query->button( print $query->submit( -name=>'View/Edit', -onClick=>"winExam()"), "\n"; print "\n"; print $query->textfield( -name=>'Pr', -size=>6); print " an existing problem report\n"; print $query->endform(); print "
\n"; print $query->startform(); print $query->hidden('Cmd','summary'); print $query->submit('Summary'); print "\n"; print "of active bugs by status and person\n"; print $query->endform(); print "
\n"; print $query->startform(); print $query->hidden('Cmd','summary_cat'); print $query->submit('Summary'); print "\n"; print "of bugs by status and category\n"; print $query->endform(); print "
\n"; #------------------------------------------------------------------ # Bug look-up by person print "
\n"; print "

Look up active bugs by the responsible person

\n"; print "Selecting \'any\' as the responsible person will show all active bugs.
\n"; print "Selecting \'name\' as the responsible person will show bugs in feedback for originator \'name\'.

\n"; print $query->startform(); print $query->hidden('Cmd','quick'); # Choose quick output format. print ""; print ""; print "
"; print "Format:\n"; print "\n"; print $query->popup_menu( -name=>'Quickfmt', -values=>\@quickfmt, -default=>'brief'); print "
"; print "Responsible:\n"; print ""; unshift(@nResponsible, "any"); print $query->popup_menu( -name=>'Person', -values=>\@nResponsible, -default=>'any'); print "

"; print $query->submit; print " or \n"; print $query->defaults('Reset'); print $query->endform(); print "
"; #------------------------------------------------------------------ # Quick query print "
\n"; print "

Freeform Query

"; print $query->startform(); print $query->hidden('Cmd','quick'); print "\n"; # Choose quick output format. print ""; print ""; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
"; print "Format: \n"; print ""; print $query->popup_menu( -name=>'Quickfmt', -values=>\@quickfmt, -default=>'brief', -override=>1); print "
"; print "Restrict the output by specifying a value for one or more\n"; print "\n"; print "problem report fields\n"; print "
\n"; print "Category: \n"; print ""; unshift(@nCategory, "any"); print $query->popup_menu( -name=>'Category', -values=>\@nCategory, -default=>'any', -override=>1); print "
\n"; print "State: \n"; print ""; unshift(@nState, "any"); print $query->scrolling_list( -name=>'State', -values=>\@nState, -default=>'open', -override=>1, -size=>6, -multiple=>'true'); print "
\n"; print "Responsible: \n"; print ""; print $query->popup_menu( -name=>'Responsible', -values=>\@nResponsible, -default=>'any', -override=>1); print "
\n"; print "Originator: \n"; print ""; unshift(@nOriginator, "any"); print $query->popup_menu( -name=>'Originator', -values=>\@nOriginator, -default=>'any', -override=>1); print "
\n"; print "Freeform text search\n"; print "on any GNATS field\n"; print "
\n"; print "Synopsis:\n"; print "\n"; print $query->textfield( -name=>'text', -size=>32); print "
\n"; print "Multitext:\n"; print "\n"; print $query->textfield( -name=>'multitext', -size=>32); print "
\n"; print $query->submit; print " or \n"; print $query->defaults('Reset'); print "
\n"; print $query->endform(); print $query->end_html(); }