bugzilla-4intranet/tr_import_environment.cgi

348 lines
10 KiB
Perl
Executable File

#!/usr/bin/perl -wT
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Testopia System.
#
# The Initial Developer of the Original Code is Greg Hendricks.
# Portions created by Greg Hendricks are Copyright (C) 2006
# Novell. All Rights Reserved.
#
# Contributor(s): Garrett Braden <garrett@tnbd.org>
# This script reads in an environment in xml and persists it to the database.
=head1 NAME
tr_import_environment.cgi - Imports an environment from a XML file into the database.
=head1 DESCRIPTION
Administrator's and testopia users can import an environment from XML into the database.
A tool is being designed to automatically scan a system and create such an XML file to
import.
=cut
#************************************************** Uses ****************************************************#
use strict;
use CGI;
use lib qw(. lib);
use Bugzilla::Constants;
use lib (bz_locations()->{extensionsdir} . '/testopia/lib');
use Bugzilla;
use Bugzilla::Util;
use Bugzilla::Config;
use Bugzilla::Error;
use Testopia::Util;
use Testopia::Environment;
use Testopia::Environment::Xml;
use Data::Dumper;
#************************************ Variable Declarations/Initialization **********************************#
Bugzilla->login(LOGIN_REQUIRED);
local our $cgi = Bugzilla->cgi;
local our $template = Bugzilla->template;
local our $vars = {};
local our $upload_dir = "testopia/temp";
local our $env_filename = $cgi->param('env_file');
local our $env_fh = $cgi->upload('env_file');
local our $action = $cgi->param('action') || '';
local our $xml = $cgi->param('xml');
local our $submit = $cgi->param('submit');
local our $environment = Testopia::Environment->new({'environment_id' => 0});
local our $user_can_edit = $environment->canedit;
#my $user_can_edit = 0; # Remove on production <- used to toggle user's rights.
our $message = '';
$CGI::POST_MAX = 1024 * 500; # max file size 500K
#***************************************** UI Logic ************************************************************#
$cgi->send_header;
# Make sure the file isn't too big.
if (!$env_filename && $cgi->cgi_error()) {
$vars->{'tr_error'} .= "File size cannot exceed 500K.<BR/>";
}
# Upload the file and read it into a string if it's been posted.
if ($action eq 'import' && $env_filename) {
trick_taint($env_filename);
# Continue only if import exits without errors, otherwise display the errors.
if (slurp_env_file() && $xml && import()) {
# Check for new data
if (check_new_items()) {
if (write_env_file()) {
# If there's new data and the user can edit have them approve the changes.
if ($user_can_edit) {
admin_approve();
}
else {
$vars->{'tr_error'} .= "Please contact an admin who can import the above mentioned non-existing data.<BR/>";
}
}
}
# If there's no new Categories, Elements, or Properties then store the environment.
else {
store_environment(); # Stores the new Environment values based on existing Categories, Elements, Properties, and Valid Expressions.
}
}
}
# If the admin form posted
elsif ($action eq 'admin' && $xml) {
if ($user_can_edit) {
my $file = "$upload_dir/$xml";
trick_taint($file);
# If the admin clicked the 'Add Now' and not the 'Cancel' button
if ($submit eq 'Add Now') {
if (read_env_file($file)) {
import("admin"); # Creates Testopia::Environment::Xml object and store's it to the database.
}
}
else {
$vars->{'tr_error'} .= "Import XML Environment Cancelled.<BR/>";
delete_env_file($file);
}
}
else {
$vars->{'tr_error'} .= "Error reading from file. Please try again.<BR/>If the problem persists please contact the site administrator.<BR/>";
}
}
display();
#*********************************************** EXISTS HERE *************************************************#
#************************************* Sub Routine Deffinitions Below ****************************************#
=head2 Create XML document
=head2 DESCRIPTION
Creates the Environment XML Document and node lists.
=cut
sub import {
# If the user is an admin and has approved to add the values pass 1 to parse().
my $admin = @_;
$environment = Testopia::Environment::Xml->new($xml, $admin);
if ($environment->{'error'}) {
$vars->{'tr_error'} .= $environment->{'error'};
return 0;
}
return 1;
}
=head2 Checking Exists
=head2 DESCRIPTION
Checking if the Environment, Elements, Categories, and Properties already exist or not.
=cut
sub check_new_items {
return $environment->check_new_items();
}
=head2 Admin Approve
=head2 Description
Prepares the $vars being passed to the template to display the
Admin Approval Form first before importing an environment with
new data.
=cut
sub admin_approve {
$vars->{'action'} = "admin";
$vars->{'xml'} = $xml;
}
=head2 Store the Environment
=head2 Description
Stores the Environment based on existing Categories, Elements, Properties, and selectable values.
=cut
sub store_environment {
$environment->store();
}
=head2 Upload and read the XML file
=head2 Description
Uploads and reads the XML Environment file and prepares it into an array for parsing.
=cut
sub slurp_env_file {
my $untainted_filename;
my $post_max = $CGI::POST_MAX;
if (!$env_filename) {
$vars->{'tr_error'} .= "Please upload an Environment XML file.<BR/>";
return 0;
}
# untaint $env_file
if ($env_filename =~ /^([-\@:\/\\\w.]+)$/) {
$untainted_filename = $1;
}
else {
$vars->{'tr_error'} .= "The filename must contain numbers and letters only. Please try again.<BR/>";
return 0;
}
if ($untainted_filename =~ m/\.\./) {
$vars->{'tr_error'} .= "The filename cannot conain the sequence '..' Please try again.<BR/>";
return 0;
}
my $num_bytes = $CGI::POST_MAX;
my ($totalbytes, $byteswritten, $buffer);
while ($byteswritten = read($env_fh, $buffer, $num_bytes)) {
$xml .= $buffer;
$totalbytes += $num_bytes;
}
if (!($byteswritten && $totalbytes)) {
$vars->{'error'} .= "Problem uploading file " . $env_filename . ".<BR/>"
}
if (!$xml) {
$vars->{'tr_error'} .= "File is empty. Please upload a valid Environment XML file.<BR/>";
return 0;
}
if (length($xml) > $post_max) {
$vars->{'tr_error'} .= "File uploaded was too large. Please make sure the file size is no bigger than 500 KB.<BR/>";
return 0;
}
return 1;
}
=head2 Write the Environment XML File to the Server
=head Description
Writes the environment XML File to the $upload_dir directory where it will be read in later by the admin to be approved. Once approved it's deleted.
=cut
sub write_env_file {
# If a writable $upload_dir exists, log error details there.
if (-w "$upload_dir") {
my $timestamp = Testopia::Util::get_time_stamp();
my $filename = $env_filename;
$filename =~ s/(.xml)//;
$filename .= "_" . $timestamp;
$filename =~ s/\:/./g;
$filename =~ s/[\: -]/_/g;
$filename .= ".xml";
my $untainted_filename;
if (!$filename) {
$vars->{'tr_error'} .= "Please upload an Environment XML file.<BR/>";
return 0;
}
# untaint $env_file
if ($filename =~ /^([-\@:\/\\\w.]+)$/) {
$untainted_filename = $1;
}
else {
$vars->{'tr_error'} .= "The filename must contain numbers and letters only. Please try again.<BR/>";
return 0;
}
if ($untainted_filename =~ m/\.\./) {
$vars->{'tr_error'} .= "The filename cannot conain the sequence '..' Please try again.<BR/>";
return 0;
}
open (my $fh, ">$upload_dir/$filename") || die "PROBLEM WRITING FILE.<BR/>";
print $fh $xml;
close $fh;
$xml = $filename;
}
else {
$vars->{'tr_error'} .= "Unable to write temporary environment file. Please try again.<BR/>If the problem persists please contact the site administrator.<BR/>";
return 0;
}
return 1;
}
=head2 Read the uploaded Environment XML file
=head2 Description
Uploads and reads the XML Environment file and prepares it into an array for parsing.
=cut
sub read_env_file {
my ($file) = @_;
$xml = '';
open (my $fh, "<$file") || do {
$vars->{'tr_error'} .= "Unable to read temporary environment file. Please to try again.<BR/>If the problem persists please contact the site administrator.<BR/>";
return 0;
};
binmode($fh);
while (<$fh>) {
$xml .= $_;
}
close $fh;
if (!$xml) {
$vars->{'tr_error'} .= "File is empty. Please upload a valid Environment XML file.<BR/>";
return 0;
}
if (length($xml) > $CGI::POST_MAX) {
$vars->{'tr_error'} .= "File uploaded was too large. Please make sure the file size is no bigger than 500 KB.<BR/>";
return 0;
}
return delete_env_file($file);
}
=head2 delete_env_file
=head2 Description
Deletes the temporary environment file.
=cut
sub delete_env_file {
my ($file) = @_;
if (!unlink($file)) {
$vars->{'tr_error'} .= "Unable to delete temporary environment file.<BR/>If the problem persists please contact the site administrator.<BR/>";
return 0;
}
return 1;
}
=head2 Display
=head2 Description
Displays the Import Environment template
=cut
sub display {
$vars->{'tr_message'} .= $message . $environment->{'message'};
$template->process("testopia/environment/import.xml.tmpl", $vars) || print $template->error();
}