pjs/webtools/testopia/tr_admin_environment.cgi

580 строки
18 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): Greg Hendricks <ghendricks@novell.com>
# Michael Hight <mjhight@gmail.com>
# Garrett Braden <gbraden@novell.com>
# Scott Sudweeks <ssudweeks@novell.com>
# Brian Kramer <bkramer@novell.com>
use strict;
use lib ".";
use Bugzilla;
use Bugzilla::Util;
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Testopia::Util;
use Bugzilla::Testopia::TestRun;
use Bugzilla::Testopia::Product;
use Bugzilla::Testopia::Classification;
use Bugzilla::Testopia::Environment;
use Bugzilla::Testopia::Environment::Element;
use Bugzilla::Testopia::Environment::Property;
use Bugzilla::Testopia::Environment::Category;
use JSON;
use Data::Dumper;
Bugzilla->login(LOGIN_REQUIRED);
local our $cgi = Bugzilla->cgi;
local our $template = Bugzilla->template;
local our $vars = {};
print $cgi->header;
ThrowUserError('testopia-permission-denied') unless Bugzilla->user->in_group('Testers');
my $action = $cgi->param('action') || '';
my $env_id = $cgi->param('env_id') || 0;
if($action eq 'getChildren'){
my $json = new JSON;
my $data = $json->jsonToObj($cgi->param('data'));
my $node = $data->{'node'};
my $id = $node->{'objectId'};
my $type = $node->{'widgetId'};
detaint_natural($id);
trick_taint($type);
for ($type){
/classification/ && do { get_products($id); };
/product/ && do { get_categories($id); };
/category/ && do { get_category_element($id) };
/element/ && do { get_element_children($id); };
/property/ && do { get_validexp_json($id) };
}
}
elsif($action eq 'edit'){
my $type = $cgi->param('type');
my $id = $cgi->param('id');
for ($type){
/category/ && do { edit_category($id); };
/element/ && do { edit_element($id); };
/property/ && do { edit_property($id); };
/validexp/ && do { edit_validexp($id); };
}
}
elsif($action eq 'do_edit'){
my $type = $cgi->param('type');
my $id = $cgi->param('id');
for ($type){
/category/ && do { do_edit_category($id); };
/element/ && do { do_edit_element($id); };
/property/ && do { do_edit_property($id); };
/validexp/ && do { do_edit_validexp($id); };
}
}
elsif($action eq 'createChild'){
my $json = new JSON;
my $data = $json->jsonToObj($cgi->param('data'));
my $node = $data->{'parent'};
my $id = $node->{'objectId'};
my $type = $node->{'widgetId'};
my $create_type = $data->{'data'}->{'createType'};
$type = 'child' if ($create_type && $type !~ /category/);
detaint_natural($id);
trick_taint($type);
for ($type){
/product/ && do { add_category($id); };
/category/ && do { add_element($id); };
/child/ && do { add_element($id,1); };
/element/ && do { add_property($id); };
/property/ && do { add_validexp($id); };
}
}
elsif($action eq 'removeNode'){
my $json = new JSON;
my $data = $json->jsonToObj($cgi->param('data'));
my $node = $data->{'node'};
my $id = $node->{'objectId'};
my $type = $node->{'widgetId'};
detaint_natural($id) unless $type =~ /validexp/;
trick_taint($type);
for ($type){
/category/ && do { delete_category($id); };
/element/ && do { delete_element($id); };
/property/ && do { delete_property($id); };
/validexp/ && do { delete_validexp($id); };
}
}
elsif ($action eq 'getcategories'){
my $product_id = $cgi->param('product_id');
detaint_natural($product_id);
my $product = Bugzilla::Testopia::Product->new($product_id);
exit unless $product && Bugzilla->user->can_see_product($product->name);
my $cat = Bugzilla::Testopia::Environment::Category->new({});
my $categories = $cat->get_element_categories_by_product($product_id);
my $ret;
foreach my $c (@{$categories}){
my $name = $c->name;
$name =~ s/<span style='color:blue'>|<\/span>//g;
$ret .= $c->id.'||'.$name.'|||';
}
chop($ret);
print $ret;
}
elsif ($action eq 'getelements'){
my $cat_name = $cgi->param('cat_name');
my $cat = Bugzilla::Testopia::Environment::Category->new($cat_name);
my $elements = $cat->get_elements_by_category();
my $ret;
foreach my $e (@{$elements}){
my $elem = Bugzilla::Testopia::Environment::Element->new(@$e{'element_id'});
$elem->{'name'} =~ s/<span style='color:blue'>|<\/span>//g;
$ret .= $elem->{'element_id'}.'||'.$elem->{'name'}.'|||';
}
$ret = substr($ret, 0, length($ret) - 3);
print $ret;
}
else{
&display;
}
sub display{
my $category = Bugzilla::Testopia::Environment::Category->new({'id' => 0});
if (Bugzilla->params->{'useclassification'}){
$vars->{'allhaschild'} = $category->get_all_child_count;
$vars->{'toplevel'} = Bugzilla->user->get_selectable_classifications;
$vars->{'type'} = 'classification';
}
else {
$vars->{'toplevel'} = $category->get_env_product_list;
$vars->{'type'} = 'product';
}
$template->process("testopia/environment/admin/show.html.tmpl", $vars)
|| print $template->error();
}
###########################
### Tree Helper Methods ###
###########################
sub get_products{
my ($class_id) = (@_);
my $class = Bugzilla::Testopia::Classification->new($class_id);
return unless scalar(grep {$class->id eq $class_id} @{Bugzilla->user->get_selectable_classifications});
print $class->products_to_json;
}
sub get_categories{
my ($product_id) = (@_);
if ($product_id){
my $product = Bugzilla::Testopia::Product->new($product_id);
return unless $product->canedit;
}
my $category = Bugzilla::Testopia::Environment::Category->new({});
print $category->product_categories_to_json($product_id);
}
sub get_category_element{
my ($id) = (@_);
my $category = Bugzilla::Testopia::Environment::Category->new($id);
return unless $category->canedit;
print $category->elements_to_json;
}
sub get_element_children {
my ($id) = (@_);
my $element = Bugzilla::Testopia::Environment::Element->new($id);
return unless $element->canedit;
print $element->children_to_json;
}
sub get_validexp_json {
my ($id) = (@_);
my $property = Bugzilla::Testopia::Environment::Property->new($id);
return unless $property->canedit;
print $property->valid_exp_to_json;
}
###########################
### Edit Helper Methods ###
###########################
sub edit_category{
my ($id) = (@_);
my $category = Bugzilla::Testopia::Environment::Category->new($id);
return unless $category->canedit;
my $product = Bugzilla::Testopia::Product->new($category->product_id());
$category->{'name'} =~ s/<span style='color:blue'>|<\/span>//g;
$vars->{'category'} = $category;
$vars->{'products'} = $category->get_env_product_list;
$vars->{'currentproduct'} = $product ? $product : {'id' => 0, 'name' => '--ANY PRODUCT--'};
$template->process("testopia/environment/admin/category.html.tmpl", $vars)
|| print $template->error();
}
sub edit_element{
my ($id) = (@_);
my $element = Bugzilla::Testopia::Environment::Element->new($id);
return unless $element->canedit;
my $category = Bugzilla::Testopia::Environment::Category->new($element->env_category_id());
my $product = Bugzilla::Testopia::Product->new($category->product_id());
$element->{'name'} =~ s/<span style='color:blue'>|<\/span>//g;
$vars->{'element'} = $element;
$vars->{'products'} = $category->get_env_product_list;
$vars->{'currentproduct'} = $product ? $product : {'id' => 0, 'name' => '--ANY PRODUCT--'};
$vars->{'currentcategory'} = $category;
$vars->{'categories'} = $category->get_element_categories_by_product($product->{'id'});
unless($element->parent_id() == 0){
my $parent = Bugzilla::Testopia::Environment::Element->new($element->parent_id());
$vars->{'currentelement'} = $parent;
}
$vars->{'elements'} = $category->get_elements_by_category();
$template->process("testopia/environment/admin/element.html.tmpl", $vars)
|| print $template->error();
}
sub edit_property{
my ($id) = (@_);
my $property = Bugzilla::Testopia::Environment::Property->new($id);
return unless $property->canedit;
my $element = Bugzilla::Testopia::Environment::Element->new($property->element_id());
my $cat_id = $element->env_category_id();
my $elmnts = Bugzilla::Testopia::Environment::Category->new($cat_id)->get_elements_by_category();
$vars->{'property'} = $property;
$vars->{'elements'} = $elmnts;
$vars->{'currentelement'} = $element;
$template->process("testopia/environment/admin/property.html.tmpl", $vars);
}
sub edit_validexp{
my ($id) = (@_);
$id =~ /^(\d+)~/;
my $property = Bugzilla::Testopia::Environment::Property->new($1);
return unless $property->canedit;
my @expressions = split /\|/, $property->validexp();
$vars->{'property'} = $property;
$vars->{'expressions'} = \@expressions;
$template->process("testopia/environment/admin/valid_exp.html.tmpl", $vars);
}
##############################
### Do_Edit Helper Methods ###
##############################
sub do_edit_category{
my $name = $cgi->param('name');
my $product_id = $cgi->param('product');
my ($id) = (@_);
my $category = Bugzilla::Testopia::Environment::Category->new($id);
return unless $category->canedit;
trick_taint($name);
detaint_natural($product_id);
my $error_mode_cache = Bugzilla->error_mode;
Bugzilla->error_mode(ERROR_MODE_DIE);
eval{
validate_selection($product_id, 'id', 'products');
};
Bugzilla->error_mode($error_mode_cache);
if ($@ && $product_id != 0){
print '{error:"Invalid product"}';
exit;
}
$category->set_product($product_id);
unless ($category->set_name($name)) {
print '{error:"Name already used. Please choose another"}';
exit;
}
print "{name:\"$name\", product:\"product$product_id\", widget:\"category$id\"}";
}
sub do_edit_element{
my ($id) = (@_);
#
# CGI params
# productCombo -> id of product (does not matter what this is, only used to find categories)
# categoryCombo -> id of category (if zero, leave the same)
# elementCombo -> id of parent element (id of 0 means no parent)
# name -> name of the element
#
my $element = Bugzilla::Testopia::Environment::Element->new($id);
return unless $element->canedit;
my $cat_id = $cgi->param('categoryCombo');
my $parent_id = $cgi->param('elementCombo');
my $name = $cgi->param('name');
my $parent;
detaint_natural($cat_id);
detaint_natural($parent_id);
trick_taint($name);
if ($cat_id){
$element->update_element_category($cat_id);
$parent = 'category' . $cat_id;
}
else {
print '{error: "Category does not exist"}';
exit;
}
if ($parent_id){
$element->update_element_parent($parent_id);
$parent = 'element' . $parent_id;
}
elsif (!$cat_id) {
print '{error: "Parent element does not exist"}';
exit;
}
unless ($element->update_element_name($name)){
print '{error: "Name already taken. Please choose another."}';
exit;
}
print "{name:\"$name\", parent:\"$parent\", widget:\"element$id\"}";
}
sub do_edit_property{
my ($id) = (@_);
my $name = $cgi->param('name');
my $element_id = $cgi->param('element');
my $property = Bugzilla::Testopia::Environment::Property->new($id);
return unless $property->canedit;
trick_taint($name);
detaint_natural($element_id);
my $error_mode_cache = Bugzilla->error_mode;
Bugzilla->error_mode(ERROR_MODE_DIE);
eval{
validate_selection($element_id, 'element_id', 'test_environment_element');
};
Bugzilla->error_mode($error_mode_cache);
if ($@){
print '{error:"Invalid element"}';
exit;
}
$property->set_element($element_id);
unless ($property->set_name($name)) {
print '{error:"Name already used. Please choose another"}';
exit;
}
print "{name:\"$name\", element:\"element$element_id\", widget:\"property$id\"}";
}
sub do_edit_validexp{
my ($id) = (@_);
my $property = Bugzilla::Testopia::Environment::Property->new($id);
return unless $property->canedit;
my @expressions = $cgi->param('valid_exp');
my $exp = join('|', @expressions);
trick_taint($exp);
$property->update_property_validexp($exp);
display;
}
###################################
### Create Child Helper Methods ###
###################################
sub add_category{
my ($id) = (@_);
my $category = Bugzilla::Testopia::Environment::Category->new({});
if ($id){
my $product = Bugzilla::Testopia::Product->new($id);
return unless $product->canedit;
}
$category->{'product_id'} = $id;
$category->{'name'} = 'New category ' . $category->new_category_count;
my $new_cid = $category->store();
my $json = '{title:"<span style=\'color:blue\'>' . $category->{'name'} . '</span>",';
$json .= 'objectId:"'. $new_cid . '",';
$json .= 'widgetId:"category' . $new_cid . '",';
$json .= 'childIconSrc:"testopia/img/square.gif",';
$json .= 'actionsDisabled:["addCategory","addValue","addProperty"]}';
print $json;
}
sub add_element{
my ($id, $ischild) = (@_);
my $element = Bugzilla::Testopia::Environment::Element->new({});
# If we are adding this element as a child, $id is the parent element's id
if ($ischild) {
my $parent = Bugzilla::Testopia::Environment::Element->new($id);
return unless $parent->canedit;
$element->{'env_category_id'} = $parent->env_category_id;
}
# Otherwise $id is the catagory id
else {
my $parent = Bugzilla::Testopia::Environment::Category->new($id);
return unless $parent->canedit;
$element->{'env_category_id'} = $id;
}
$element->{'name'} = "New element " . $element->new_element_count;
$element->{'parent_id'} = $ischild ? $id : 0;
$element->{'isprivate'} = 0;
my $new_eid = $element->store();
my $json = '{title:"<span style=\'color:blue\'>' . $element->{'name'} .'</span>",';
$json .= 'objectId:"'. $new_eid .'",';
$json .= 'widgetId:"element'. $new_eid .'",';
$json .= 'childIconSrc:"testopia/img/circle.gif",';
$json .= 'actionsDisabled:["addCategory","addValue"]}';
print $json;
}
sub add_property{
my ($id) = (@_);
#add new property to element with id=$id
my $property = Bugzilla::Testopia::Environment::Property->new({});
my $parent = Bugzilla::Testopia::Environment::Element->new($id);
return unless $parent->canedit;
$property->{'element_id'} = $id;
$property->{'name'} = "New property " . $property->new_property_count;
$property->{'validexp'} = "";
my $new_pid = $property->store();
my $json = '{title:"<span style=\'color:blue\'>' . $property->{'name'} . '</span>",';
$json .= 'objectId:"' . $new_pid . '",';
$json .= 'widgetId:"property' . $new_pid . '",';
$json .= 'childIconSrc:"testopia/img/triangle.gif",';
$json .= 'actionsDisabled:["addCategory","addElement","addProperty"]}';
print $json;
}
sub add_validexp{
my ($id) = (@_);
my $property = Bugzilla::Testopia::Environment::Property->new($id);
return unless $property->canedit;
my $exp = $property->validexp;
$exp ? $property->update_property_validexp($exp . "|New value") : $property->update_property_validexp("New value");
my $json .= '{title: "<span style=\'color:blue\'>New value</span>",';
$json .= 'objectId:"' . $id . '~New Value",';
$json .= 'widgetId:"validexp' . $id . '~New Value",';
$json .= 'actionsDisabled:["addCategory","addElement","addProperty","addValue","remove"]}';
print $json;
}
#############################
### Delete Helper Methods ###
#############################
sub delete_category{
my ($id) = (@_);
my $category = Bugzilla::Testopia::Environment::Category->new($id);
return unless $category->candelete;
my $success = $category->obliterate;
print $success == 1 ? "true" : "false";
}
sub delete_element{
my ($id) = (@_);
my $element = Bugzilla::Testopia::Environment::Element->new($id);
return unless $element->candelete;
my $success = $element->obliterate;
print $success == 1 ? "true" : "false";
}
sub delete_property{
my ($id) = (@_);
my $property = Bugzilla::Testopia::Environment::Property->new($id);
return unless $property->candelete;
my $success = $property->obliterate;
print $success == 1 ? "true" : "false";
}
sub delete_validexp{
# $id, $type
my ($id) = (@_);
$id =~ /^(\d+)~/;
my $property = Bugzilla::Testopia::Environment::Property->new($1);
return unless $property->candelete;
my %values;
foreach my $v (split /\|/, $property->validexp){
$values{$v} = 1;
}
$id =~ /~(.+)$/;
my $value = $1;
my $deleted = delete $values{$value};
my $exp = join("|", keys %values);
$property->update_property_validexp($exp);
print $deleted ? "true" : "false";
}