#!/usr/bin/perl
use CGI qw (:standard);
use CGI::Carp qw(fatalsToBrowser);
##*************************************************
## Set-up variables from incoming data
##*************************************************
@fields = (
"Priority",
"Issue Number",
"Time Est.",
"Project",
"System",
"Device",
"Entry By",
"Entry Date",
"Issue",
"Action By",
"Date Resolved",
"Details",
"Progress",
"Resolution");
@field_html_type = (
"Select",
"Text",
"Text",
"Select",
"Select",
"Select",
"Select",
"Text",
"Text",
"Select",
"Text",
"Textarea",
"Textarea",
"Textarea");
@field_value_type = (
"General",
"General",
"General",
"General",
"General",
"General",
"Date",
"General",
"General",
"Date",
"General",
"General",
"General",
"General");
@field_select_file = (
"../priority.txt",
"none",
"none",
"../projects.txt",
"../systems.txt",
"../devices.txt",
"../mei-personnel.txt",
"none",
"none",
"../it-personnel.txt",
"none",
"none",
"none",
"none");
@search_fields = (
"Priority",
"Issue Number",
"Time Est.",
"Project",
"System",
"Device",
"Entry By",
"Entry Date",
"Issue",
"Action By",
"Date Resolved",
"Details",
"Progress",
"Resolution");
@search_fields_index = (
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13);
@multiple_results_fields = (
"Priority",
"Issue Number",
"Time Est.",
"Project",
"System",
"Device",
"Entry By",
"Entry Date",
"Issue",
"Action By",
"Date Resolved",
"Details",
"Progress",
"Resolution");
@multiple_results_field_No = (
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13);
@no_criteria = (
0,
1,
2,
3);
$database_submitted = "../issues-submitted.txt";
$database_external = "../issues-external.txt";
$database_internal = "../issues-internal.txt";
$database_archive_submitted = "../issues-submitted-archive.txt";
$database_archive_external = "../issues-external-archive.txt";
$database_archive_internal = "../issues-internal-archive.txt";
$database_delete_submitted = "../issues-submitted-delete.txt";
$database_delete_external = "../issues-external-delete.txt";
$database_delete_internal = "../issues-internal-delete.txt";
$database = " ";
$This_script = "issues.pl";
$software_title = "Issues List";
$app_mod_name = "Issues List";
$q = new CGI;
print $q->header;
$field_count = @fields;
$colspan = $field_count+1;
$EXCLUSIVE = 2;
$UNLOCK = 8;
## search criteria/field only used if AND box is checked
foreach $i (@no_criteria) {
$search_logic[$i] = $q->param("search_logic$i");
if ($search_logic[$i] == 1) {
push(@search_for, $q->param("search_for$i"));
push(@search_field, $q->param("search_field$i"));
}
}
foreach (@search_for) {
$_ = '.' if($_ eq "");
}
foreach $i (@search_field) {
$_ = "all" if($_ eq "");
}
$action = $q->param(action);
@keys = $q->param(key);
$key_matches = @keys;
$sort_by = $q->param(sort_by);
$default_sort_by = "0";
$sort_by = $search_field[0] if ($sort_by eq "");
$sort_by = $default_sort_by if($sort_by =~ /all/i);
##**************************
&print_html_head_start;
## &print_javascript;
&print_html_head_end_no_body_calls;
## &print_html_head_end;
##*************************************************
## Script Switchboard
##*************************************************
## the following three functions handle
## the add actions from the add form
if($action =~ /add internal/i){
##Add the record passed from the add record page
$database = $database_internal;
&add_notify_email(&add_record);
$message="Internal Project Issue Added";
&print_message($message);
}
elsif($action =~ /add external/i){
##Add the record passed from the add record page
$database = $database_external;
&add_notify_email(&add_record);
$message="External Project Issue Added";
&print_message($message);
}
elsif($action =~ /add submit/i){
##Add the record passed from the add record page
$database = $database_submitted;
&add_notify_email(&add_record);
$message="Project Issue Submitted";
&print_message($message);
}
## the following calls the add form
elsif($action =~ /add/i){
##Display the add record page
&print_add_screen;
}
## the following handle the change status from forms
elsif($action =~ /move to external/i){
##Display the results of the search
$database = $database_external;
&add_record;
&search_database($q->param(key), "all");
@results = @submitted_results;
$count = @submitted_results;
$database = $database_submitted;
&eliminate_records;
&no_match if($count < 1);
$message="Project Issue Submitted to Public Status";
&print_message($message);
}
elsif($action =~ /move to internal/i){
##Display the results of the search
$database = $database_internal;
&add_record;
&search_database($q->param(key), "all");
@results = @submitted_results;
$count = @submitted_results;
$database = $database_submitted;
&eliminate_records;
&no_match if($count < 1);
$message="Project Issue Submitted to Private Status";
&print_message($message);
}
elsif($action =~ /change to external/i){
##Display the results of the search
$database = $database_external;
&add_record;
&search_database($q->param(key), "all");
@results = @internal_results;
$count = @internal_results;
$database = $database_internal;
&eliminate_records;
&no_match if($count < 1);
$message="Project Issue Changed to External Status";
&print_message($message);
}
elsif($action =~ /change to internal/i){
##Display the results of the search
$database = $database_internal;
&add_record;
&search_database($q->param(key), "all");
@results = @external_results;
$count = @external_results;
$database = $database_external;
&eliminate_records;
&no_match if($count < 1);
$message="Project Issue Changed to Internal Status";
&print_message($message);
}
## the following are the modify form calls
elsif($action =~ /modify project issue/i){
##Display the results of the search
&search_database($q->param(mkey), "all");
$internal_count = @internal_results;
$external_count = @external_results;
$submitted_count = @submitted_results;
$count = $internal_count + $external_count + $submitted_count;
if($count < 1){
&no_match;
} else {
if ($internal_count==1){
@results=@internal_results;
$submit_button_mod = "Modify Internal Project Issue";
$change_button_mod = "Change to External";
} elsif ($external_count==1){
@results=@external_results;
$submit_button_mod = "Modify External Project Issue";
$change_button_mod = "Change to Internal";
} else {
@results=@submitted_results;
$submit_button_mod = "Move to Internal";
$change_button_mod = "Move to External";
}
&print_modify_page;
}
}
elsif($action =~ /modify external project issue/i){
##Modify the record that was passed
$database = $database_external;
&eliminate_records;
$key=$keys[0];
&modify_record;
$message="Public Project Issue Modified";
&print_message($message);
}
elsif($action =~ /modify internal project issue/i){
##Modify the record that was passed
$database = $database_internal;
&eliminate_records;
$key=$keys[0];
&modify_record;
$message="Private Project Issue Modified";
&print_message($message);
}
elsif($action =~ /delete submitted/i){
##Delete the record(s) that were passed
$database = $database_submitted;
$database_del = $database_delete_submitted;
&delete_records;
$message="Submitted Project Issue(s) Deleted";
&print_message($message);
}
elsif($action =~ /delete external/i){
##Delete the record(s) that were passed
$database = $database_external;
$database_del = $database_delete_external;
&delete_records;
$message="External Project Issue(s) Deleted";
&print_message($message);
}
elsif($action =~ /delete internal/i){
##Delete the record(s) that were passed
$database = $database_internal;
$database_del = $database_delete_internal;
&delete_records;
$message="Internal Project Issue(s) Deleted";
&print_message($message);
}
elsif($action =~ /archive submitted/i){
##Delete the record(s) that were passed
$database = $database_submitted;
$database_arch = $database_archive_submitted;
&archive_records;
$message="Submitted Project Issue(s) Archived";
&print_message($message);
}
elsif($action =~ /archive external/i){
##Delete the record(s) that were passed
$database = $database_external;
$database_arch = $database_archive_external;
&archive_records;
$message="External Project Issue(s) Archived";
&print_message($message);
}
elsif($action =~ /archive internal/i){
##Delete the record(s) that were passed
$database = $database_internal;
$database_arch = $database_archive_internal;
&archive_records;
$message="Internal Project Issue(s) Archived";
&print_message($message);
}
elsif($action =~ /(search|sort)/i){
## Search database and display the results
## This is exactly the same for sort by and search.
&search_database(@search_for, @search_field);
$internal_count = @internal_results;
$external_count = @external_results;
$submitted_count = @submitted_results;
$count = $internal_count + $external_count + $submitted_count;
if($count < 1){
&no_match;
} else {
&result_page_head;
&result_page_body("Submitted", $submitted_count, @submitted_results);
&result_page_body("Internal", $internal_count, @internal_results);
&result_page_body("External", $external_count, @external_results);
&result_page_end;
}
}
elsif($action =~ /view project issue/i){
## View the record that was passed
&search_database($q->param(vkey), "all");
$internal_count = @internal_results;
$external_count = @external_results;
$submitted_count = @submitted_results;
$count = $internal_count + $external_count + $submitted_count;
if($count < 1){
&no_match;
} else {
if ($internal_count==1){
@results=@internal_results;
} elsif ($external_count==1){
@results=@external_results;
} else {
@results=@submitted_results;
}
&print_form_view;
}
}
else { &print_default; }
exit;
##******************************************************************************
##******************************************************************************
## Start of RPO Report Subroutines.
##******************************************************************************
##******************************************************************************
## This subroutine adds a record to the database from
## data sent by an HTML form.
sub print_html_head_start {
print<
Client Tools
HTML
}
## end of print-html-head-start function
sub print_javascript {
print<
HTML
}
## end of print-menu function
sub print_html_head_end {
print<
HTML
}
## end of print-html-head-end
sub print_html_head_end_no_body_calls {
print<
HTML
}
## end of print-html-head-end-no-calls
sub add_record {
$key = time();
my $record=$key;
foreach $field (@fields){
${$field} = $q->param($field);
${$field} = filter(${$field});
${$field} =~ s/\n/\t/g;
if (index($field,"Date") != -1) {
${$field} = &date_format(${$field});
}
$record .= "\|${$field}";
}
unless (-e $database){
open (DB, ">$database") || die "Error creating database. $!\n";
} else {
open (DB, ">>$database") || die "Error opening database. $!\n";
}
flock DB, $EXCLUSIVE;
seek DB, 0, 2;
print DB "$record\n";
flock DB, $UNLOCK;
close(DB);
return $record;
} # End of add_record subroutine.
## this will permanently delete a record
## useful when record is moved from table to table
sub eliminate_records {
$dumy = time();
$tempfile="$database" . "$dumy" . ".tmp";
open (DB, $database) or die "Error opening file: $!\n";
open (TEMP, ">$tempfile") or die "Error opening file: $!\n";
flock TEMP, $EXCLUSIVE;
while(){
$match="";
($key,$rest)=split(/\|/);
foreach $current (@keys){
if($current == $key){$match=1;}
} # End of foreach loop.
if ($match != 1) {
print TEMP $_;
}
} # End of while loop.
close(TEMP);
close(DB);
flock DB, $EXCLUSIVE;
unlink($database);
rename($tempfile,$database);
flock DB, $UNLOCK;
flock TEMP, $UNLOCK;
} # End of eliminate_records subroutine.
## this will move records to an archive table for keeping
## useful for retention of records for later review and searching - a knowledgebase
sub archive_records {
$dumy = time();
$tempfile="$database" . "$dumy" . ".tmp";
unless (-e $database_arch){
open (ARCH, ">$database_arch") || die "Error creating database. $!\n";
} else {
open (ARCH, ">>$database_arch") || die "Error opening database. $!\n";
}
open (DB, $database) or die "Error opening file: $!\n";
open (TEMP, ">$tempfile") or die "Error opening file: $!\n";
flock TEMP, $EXCLUSIVE;
while(){
$match="";
($key,$rest)=split(/\|/);
foreach $current (@keys){
if($current == $key){$match=1;}
} # End of foreach loop.
if ($match != 1) {
print TEMP $_;
} else {
print ARCH $_;
}
} # End of while loop.
close(TEMP);
close(DB);
close(ARCH);
flock DB, $EXCLUSIVE;
unlink($database);
rename($tempfile,$database);
flock DB, $UNLOCK;
flock TEMP, $UNLOCK;
} # End of archive_records subroutine.
##******************************************************************************
## This is exactly the same as ad_record
## EXCEPT it uses the original key of the record in the new entry.
sub modify_record {
$key = $q->param(key);
$record=$key;
foreach $field (@fields){
${$field} = $q->param($field);
${$field} = filter(${$field});
${$field} =~ s/\n/\t/g;
if(index($field,"Date") != -1) {
${$field} = &date_format(${$field});
}
$record .= "\|${$field}";
}
unless (-e $database){
open (DB, ">$database") || die "Error creating database. $!\n";
} else {
open (DB, ">>$database") || die "Error opening database. $!\n";
}
flock DB, $EXCLUSIVE;
seek DB, 0, 2;
print DB "$record\n";
flock DB, $UNLOCK;
close(DB);
} # End of modify_record subroutine.
##******************************************************************************
## This subroutine deletes a record from the database.
## It searches through the records, writing each to a temporary
## file, except the record(s) to be deleted. It then turns the temporary
## file into the database file.
## New feature add (Tom Held) to move deleted files to a deleted table for later archive.
sub delete_records{
$dumy = time();
$tempfile="$database" . "$dumy" . ".tmp";
unless (-e $database_del){
open (DEL, ">$database_del") || die "Error creating database. $!\n";
} else {
open (DEL, ">>$database_del") || die "Error opening database. $!\n";
}
open (DB, $database) or die "Error opening file: $!\n";
open (TEMP, ">$tempfile") or die "Error opening file: $!\n";
flock TEMP, $EXCLUSIVE;
while(){
$match="";
($key,$rest)=split(/\|/);
foreach $current (@keys){
if($current == $key){$match=1;}
} # End of foreach loop.
if ($match != 1) {
print TEMP $_;
} else {
print DEL $_;
}
} # End of while loop.
close(TEMP);
close(DB);
close(DEL);
flock DB, $EXCLUSIVE;
unlink($database);
rename($tempfile,$database);
flock DB, $UNLOCK;
flock TEMP, $UNLOCK;
} # End of delete_records subroutine.
##******************************************************************************
## Prints the beginning of the search result page - include information that
## only needs to be printed or defined once.
sub result_page_head {
## Javascript used by view and modify buttons
print<
vbup = new Image();
vbup.src = "VBUp.gif";
vbdown = new Image();
vbdown.src = "VBDown.gif";
mbup = new Image();
mbup.src = "MBUp.gif";
mbdown = new Image();
mbdown.src = "MBDown.gif";
function vClick(key,form) {
document.results.action.value="view project issue";
document.results.vkey.value=key;
document.results.submit();
}
function mClick(key) {
document.results.action.value="modify project issue";
document.results.mkey.value=key;
document.results.submit();
}
function vDown(index){
index = "viewb" + index;
document.results.elements[index].src = vbdown.src;
}
function vUp(index){
index = "viewb" + index;
document.results.elements[index].src = vbup.src;
}
function mDown(index){
index = "modifyb" + index;
document.results.elements[index].src = mbdown.src;
}
function mUp(index){
index = "modifyb" + index;
document.results.elements[index].src = mbup.src;
}
HTML
print<$software_title $app_mod_name
HTML
} # End of result_page_end subroutine.
##******************************************************************************
## This subroutine simply prints a screen telling you it did not find
## a match for the search criteria the user asked for.
sub no_match{
print $q->start_html(-TITLE=>'',-BGCOLOR=>'white');
print "
There was no match for ";
if ($#search_for == 0 && $search_for[0] eq "."){
print ", ";
} else {
foreach $i (@search_for) {
unless ($i eq ".") {
print "$i, ";
}
}
}
print "please hit back and try again.
";
print $q->end_html;
exit;
} # End of no_match subroutine.
##******************************************************************************
## This subroutine searches through the current database
## file for the information requested
##
sub search_database{
my @search_for = ();
my @search_field = ();
if ($#_>0) { ## solves problem of empty 1st list member, w/ $q->param(key) call
for ($n=0;$n<=$#_/2;$n++){
$search_for[$n] = $_[$n];
$search_field[$n] = $_[$#_/2+$n+.5];
}
} else {
$search_for[0] = $_[0];
$search_field = $_[1];
}
my @temp_results = ();
if(-e $database_submitted) {
open(DB, $database_submitted) or die "Error opening file: $!\n";
while(){
push @submitted_results, $_;
}
close (DB);
for ($i=0;$i<=$#_/2;$i++){
@temp_results = ();
for ($n=0;$submitted_results[$n];$n++) {
if($search_field[$i] =~ /all/i){
if($submitted_results[$n] =~ /$search_for[$i]/i) {
push @temp_results, $submitted_results[$n];
}
} else {
($key,@field_vals) = split(/\|/, $submitted_results[$n]);
if($field_vals[$search_field[$i]] =~ /$search_for[$i]/i) {
push @temp_results, $submitted_results[$n];
}
} # End of else.
}
@submitted_results = @temp_results;
}
##Sort results: set up which field to $sort_by in begining of script
@unsorted_array = ();
foreach $record (@submitted_results){
($key, @dumy_vals) = split(/\|/, $record);
$temp_data = $dumy_vals[$sort_by];
if($sort_by == 2){
@temp_date_sort = split(/\//,$temp_data);
$temp_data = "$temp_date_sort[2]" . "\/" . "$temp_date_sort[0]" . "\/" . "$temp_date_sort[1]";
}
$new_record = "$temp_data" . "\|" . "$record";
push @unsorted_array, $new_record;
}
@sorted_array = sort(@unsorted_array);
@submitted_results = ();
foreach $record (@sorted_array){
($sort_by_dumy, @dumy_vals) = split(/\|/, $record);
$new_record = join("\|", @dumy_vals);
push @submitted_results, $new_record;
}
}
if(-e $database_internal) {
open(DB, $database_internal) or die "Error opening file: $!\n";
while(){
push @internal_results, $_;
}
close (DB);
for ($i=0;$i<=$#_/2;$i++){
@temp_results = ();
for ($n=0;$internal_results[$n];$n++) {
if($search_field[$i] =~ /all/i){
if($internal_results[$n] =~ /$search_for[$i]/i) {
push @temp_results, $internal_results[$n];
}
} else {
($key,@field_vals) = split(/\|/, $internal_results[$n]);
if($field_vals[$search_field[$i]] =~ /$search_for[$i]/i) {
push @temp_results, $internal_results[$n];
}
} # End of else.
}
@internal_results = @temp_results;
}
##Sort results: set up which field to $sort_by in begining of script
@unsorted_array = ();
foreach $record (@internal_results){
($key, @dumy_vals) = split(/\|/, $record);
$temp_data = $dumy_vals[$sort_by];
if($sort_by == 2){
@temp_date_sort = split(/\//,$temp_data);
$temp_data = "$temp_date_sort[2]" . "\/" . "$temp_date_sort[0]" . "\/" . "$temp_date_sort[1]";
}
$new_record = "$temp_data" . "\|" . "$record";
push @unsorted_array, $new_record;
}
@sorted_array = sort(@unsorted_array);
@internal_results = ();
foreach $record (@sorted_array){
($sort_by_dumy, @dumy_vals) = split(/\|/, $record);
$new_record = join("\|", @dumy_vals);
push @internal_results, $new_record;
}
}
if(-e $database_external) {
open(DB, $database_external) or die "Error opening file: $!\n";
while(){
push @external_results, $_;
}
close (DB);
for ($i=0;$i<=$#_/2;$i++){
@temp_results = ();
for ($n=0;$external_results[$n];$n++) {
if($search_field[$i] =~ /all/i){
if($external_results[$n] =~ /$search_for[$i]/i) {
push @temp_results, $external_results[$n];
}
} else {
($key,@field_vals) = split(/\|/, $external_results[$n]);
if($field_vals[$search_field[$i]] =~ /$search_for[$i]/i) {
push @temp_results, $external_results[$n];
}
} # End of else.
}
@external_results = @temp_results;
}
##Sort results: set up which field to $sort_by in begining of script
@unsorted_array = ();
foreach $record (@external_results){
($key, @dumy_vals) = split(/\|/, $record);
$temp_data = $dumy_vals[$sort_by];
if($sort_by == 2){
@temp_date_sort = split(/\//,$temp_data);
$temp_data = "$temp_date_sort[2]" . "\/" . "$temp_date_sort[0]" . "\/" . "$temp_date_sort[1]";
}
$new_record = "$temp_data" . "\|" . "$record";
push @unsorted_array, $new_record;
}
@sorted_array = sort(@unsorted_array);
@external_results = ();
foreach $record (@sorted_array){
($sort_by_dumy, @dumy_vals) = split(/\|/, $record);
$new_record = join("\|", @dumy_vals);
push @external_results, $new_record;
}
}
} # End of search_database subroutine.
##******************************************************************************
## Prints the default switchboard navigation page
sub print_default {
print<
To Search: Enter search criteria in the
first text box, to the immediate right select the desired search field,
and then hit the search button. Optional: Narrow the search by
entering additional search criteria in one or more of the following
text boxes, selecting the search field(s) to the right, and checking the
corresponding box(es) on the far left. To view the entire database,
leave all search criteria empty and hit the search button.
HTML
} # End of print_default subroutine.
##******************************************************************************
## This subroutine filters data from an HTML form
sub filter{
$temp = $_[0];
$temp =~ s/\|//; # Remove pipe symbols in text.
return ($temp);
}# end of filter subroutine
##******************************************************************************
## This subroutine prints whatever message was sent to it.
##
sub print_message{
print<
$_[0]
Returning you to the Search Page...
HTML
}#end of print_message
##******************************************************************************
## If there is no data returns a non-binding space -> for tables.
sub check_empty{
$r_val = $_[0];
if($r_val =~ /^\s*$/){$r_val=" "}
return($r_val);
}# end of check_empty subroutine
##******************************************************************************
## Formats a date field before adding it to the database
sub date_format{
$initial_entry = $_[0];
if($initial_entry =~ /(\/|-)/) {
if($1 eq "\/"){
(@values) = split(/\//, $initial_entry);
}
else {
(@values) = split(/\-/, $initial_entry);
}
$size_of_values = @values;
if($size_of_values != 3) {
return($initial_entry);
}
if($values[0] < 10){
$values[0] += 0;
$values[0] = "0" . "$values[0]";
}
if($values[1] < 10){
$values[1] += 0;
$values[1] = "0" . "$values[1]";
}
if($values[2] < 2000){
$values[2] = 2000 + $values[2];
}
$good_date = join("\/", @values);
return($good_date);
}
return($initial_entry);
}#end of date_format subroutine
##******************************************************************************
## This is the screen to add information
sub print_add_screen{
print<$software_title $app_mod_name - Adding Issue