Added access controls to test plans. Users must now either be a member of the Testers group, added to a plan via regular expressions, or added explicitly to modify plans and their objects.
This commit is contained in:
Родитель
7fad6a15c3
Коммит
23071d7e64
|
@ -44,6 +44,17 @@ sub get_param_list {
|
|||
default => 0,
|
||||
},
|
||||
|
||||
{
|
||||
name => 'testopia-allow-group-member-deletes',
|
||||
type => 'b',
|
||||
default => 0,
|
||||
},
|
||||
|
||||
{
|
||||
name => 'testopia-default-plan-testers-regexp',
|
||||
type => 't',
|
||||
},
|
||||
|
||||
# {
|
||||
# name => 'print-tag-in-case-log',
|
||||
# type => 'b',
|
||||
|
|
|
@ -104,7 +104,7 @@ sub init {
|
|||
my @fields;
|
||||
my %specialorderjoin;
|
||||
my %chartfields;
|
||||
|
||||
#my ($testergroup) = $dbh->selectrow_array("SELECT id FROM groups WHERE name = ?",undef, 'Testers');
|
||||
|
||||
# $chartid is the number of the current chart whose SQL we're constructing
|
||||
# $row is the current row of the current chart
|
||||
|
@ -302,7 +302,30 @@ sub init {
|
|||
}
|
||||
|
||||
}
|
||||
# Set up tables for access control
|
||||
unless (Bugzilla->user->in_group('Testers')){
|
||||
if ($obj eq 'case'){
|
||||
push(@supptables, "INNER JOIN test_case_plans AS case_plans " .
|
||||
"ON test_cases.case_id = case_plans.case_id");
|
||||
push(@supptables, "INNER JOIN test_plans " .
|
||||
"ON case_plans.plan_id = test_plans.plan_id"); }
|
||||
elsif ($obj eq 'case_run'){
|
||||
push(@supptables, "INNER JOIN test_case_runs AS case_runs " .
|
||||
"ON test_runs.run_id = case_runs.run_id");
|
||||
push(@supptables, "INNER JOIN test_cases " .
|
||||
"ON case_runs.case_id = test_cases.case_id");
|
||||
}
|
||||
elsif ($obj eq 'run'){
|
||||
push(@supptables, "INNER JOIN test_plans " .
|
||||
"ON test_runs.plan_id = test_plans.plan_id");
|
||||
}
|
||||
|
||||
push @supptables, "INNER JOIN test_plan_permissions ON test_plans.plan_id = test_plan_permissions.plan_id";
|
||||
push @supptables, "INNER JOIN user_group_map AS map_testers ON map_testers.user_id = test_plan_permissions.userid";
|
||||
push @supptables, "INNER JOIN groups on map_testers.group_id = groups.id";
|
||||
push @wherepart, "((test_plan_permissions.permissions > 0 AND test_plan_permissions.userid = ". Bugzilla->user->id
|
||||
.") OR (map_testers.user_id = ". Bugzilla->user->id ." AND groups.name = 'Testers'))";
|
||||
}
|
||||
# Set up tables for field sort order
|
||||
my $order = $cgi->param('order') || '';
|
||||
if ($order eq 'author') {
|
||||
|
|
|
@ -740,18 +740,26 @@ sub unlink_plan {
|
|||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($plan_id) = @_;
|
||||
|
||||
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
|
||||
|
||||
if (scalar @{$self->plans} == 1){
|
||||
$self->obliterate;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$dbh->bz_lock_tables('test_case_plans WRITE', 'test_case_runs WRITE',
|
||||
'test_runs READ', 'test_plans READ');
|
||||
|
||||
if (!$self->can_unlink_plan($plan_id)){
|
||||
$dbh->bz_unlock_tables();
|
||||
return 0;
|
||||
foreach my $run (@{$plan->test_runs}){
|
||||
$dbh->do("DELETE FROM test_case_runs
|
||||
WHERE case_id = ?
|
||||
AND run_id = ?", undef, $self->id, $run->id);
|
||||
}
|
||||
|
||||
$dbh->do("DELETE FROM test_case_plans
|
||||
WHERE plan_id = ?
|
||||
AND case_id = ?", undef, $plan_id, $self->{'case_id'});
|
||||
AND case_id = ?",
|
||||
undef, $plan_id, $self->{'case_id'});
|
||||
|
||||
$dbh->bz_unlock_tables();
|
||||
|
||||
|
@ -1262,20 +1270,12 @@ sub can_unlink_plan {
|
|||
my $self = shift;
|
||||
my ($plan_id) = @_;
|
||||
|
||||
return 0 if (!UserInGroup('managetestplans'));
|
||||
|
||||
return 0 if scalar @{$self->plans} < 2;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($res) = $dbh->selectrow_array(
|
||||
"SELECT 1
|
||||
FROM test_case_runs
|
||||
INNER JOIN test_runs ON test_case_runs.run_id = test_runs.run_id
|
||||
WHERE test_runs.plan_id = ?
|
||||
AND test_case_runs.case_id = ?",
|
||||
undef, ($plan_id, $self->{'case_id'}));
|
||||
|
||||
return !$res;
|
||||
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
|
||||
return 1 if Bugzilla->user->in_group('admin');
|
||||
return 1 if Bugzilla->user->in_group('Testers') && Param("testopia-allow-group-member-deletes");
|
||||
return 1 if $plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 4;
|
||||
return 1 if $plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 obliterate
|
||||
|
@ -1315,9 +1315,10 @@ Returns true if the logged in user has rights to edit this test case.
|
|||
|
||||
sub canedit {
|
||||
my $self = shift;
|
||||
return $self->canview
|
||||
&& UserInGroup('managetestplans')
|
||||
|| UserInGroup('edittestcases');
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 2;
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 canview
|
||||
|
@ -1328,13 +1329,10 @@ Returns true if the logged in user has rights to view this test case.
|
|||
|
||||
sub canview {
|
||||
my $self = shift;
|
||||
return $self->{'canview'} if exists $self->{'canview'};
|
||||
my $ret = 1;
|
||||
foreach my $p (@{$self->plans}){
|
||||
$ret = 0 unless Bugzilla::Testopia::Util::can_view_product($p->product_id);
|
||||
}
|
||||
$self->{'canview'} = $ret;
|
||||
return $self->{'canview'};
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) > 0;
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) > 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 candelete
|
||||
|
@ -1345,26 +1343,36 @@ Returns true if the logged in user has rights to delete this test case.
|
|||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
return 0 unless $self->canedit && Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group("admin");
|
||||
|
||||
# Allow plan author to delete if this case is linked only to plans she owns.
|
||||
return 1 if Bugzilla->user->in_group('admin');
|
||||
return 0 unless Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group('Testers') && Param("testopia-allow-group-member-deletes");
|
||||
# Otherwise, check for delete rights on all the plans this is linked to
|
||||
my $own_all = 1;
|
||||
foreach my $plan (@{$self->plans}){
|
||||
if (Bugzilla->user->id != $plan->author->id) {
|
||||
if (!($plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 4)
|
||||
|| !($plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 4)) {
|
||||
$own_all = 0;
|
||||
last;
|
||||
}
|
||||
}
|
||||
return 1 if $own_all;
|
||||
|
||||
# Allow case author to delete if this case is not in any runs.
|
||||
return 1 if Bugzilla->user->id == $self->author->id &&
|
||||
$self->get_caserun_count == 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub get_user_rights {
|
||||
my $self = shift;
|
||||
my ($userid, $type) = @_;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($perms) = $dbh->selectrow_array(
|
||||
"SELECT MAX(permissions) FROM test_plan_permissions
|
||||
LEFT JOIN test_case_plans ON test_plan_permissions.plan_id = test_case_plans.plan_id
|
||||
INNER JOIN test_cases ON test_case_plans.case_id = test_cases.case_id
|
||||
WHERE userid = ? AND test_plan_permissions.plan_id = ? AND grant_type = ?",
|
||||
undef, ($userid, $self->id, $type));
|
||||
|
||||
return $perms;
|
||||
}
|
||||
###############################
|
||||
#### Accessors ####
|
||||
###############################
|
||||
|
|
|
@ -48,6 +48,7 @@ use Bugzilla::Util;
|
|||
use Bugzilla::Error;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Testopia::Util;
|
||||
use Bugzilla::Testopia::Constants;
|
||||
use Bugzilla::Bug;
|
||||
|
@ -976,66 +977,11 @@ Returns true if the logged in user has rights to view this case-run.
|
|||
=cut
|
||||
|
||||
sub canview {
|
||||
|
||||
my $self = shift;
|
||||
# return $self->{'canview'} if exists $self->{'canview'};
|
||||
# my ($case_log_id, $run_id, $plan_id, $current_user_id) = @_;
|
||||
#
|
||||
# my $dbh = Bugzilla->dbh;
|
||||
# my $canview = 0;
|
||||
# my $current_user_id = Bugzilla->user->id;
|
||||
# my ($plan_id) = $dbh->selectrow_array("SELECT plan_id FROM test_runs
|
||||
# WHERE run_id=?",
|
||||
# undef, $self->{'test_run_id'});
|
||||
#
|
||||
# if (0 == &Bugzilla::Param('private-cases-log')) {
|
||||
# $canview = 1;
|
||||
# } else {
|
||||
#
|
||||
# if (0 == $self->{'isprivate'}) {
|
||||
# # if !isprivate, then everybody can run it and should be able to see
|
||||
# # the current status
|
||||
# $canview = 1;
|
||||
# } else {
|
||||
# # check is the current user is a tester:
|
||||
# if (defined $current_user_id) {
|
||||
#
|
||||
# SendSQL("select 1 from test_case_run_testers ".
|
||||
# "where case_log_id=". $self->{'id'} ." and userid=$current_user_id");
|
||||
#
|
||||
# if (FetchOneColumn()) {
|
||||
# # current user is a tester
|
||||
# $canview = 1;
|
||||
# } else {
|
||||
# # check editors
|
||||
# SendSQL("select 1 from test_plans where plan_id=$plan_id and editor=$current_user_id");
|
||||
#
|
||||
# if (FetchOneColumn()) {
|
||||
# $canview = 1;
|
||||
# } else {
|
||||
# # check watchers
|
||||
# SendSQL("select 1 from test_plans_watchers where plan_id=$plan_id and userid=$current_user_id");
|
||||
# if (FetchOneColumn()) {
|
||||
# $canview = 1;
|
||||
# } else {
|
||||
# #check test run manager
|
||||
# SendSQL("select 1 from test_runs where test_run_id=". $self->{'test_run_id'} ." and manager=$current_user_id");
|
||||
# $canview = FetchOneColumn()? 1 : 0;
|
||||
#
|
||||
# if (0 == $canview) {
|
||||
# if (UserInGroup('admin')) {
|
||||
# $canview = 1;
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
|
||||
$self->{'canview'} = 1;
|
||||
return $self->{'canview'};
|
||||
my $self = shift;
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->run->plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) > 0;
|
||||
return 1 if $self->run->plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) > 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 canedit
|
||||
|
@ -1046,10 +992,10 @@ Returns true if the logged in user has rights to edit this case-run.
|
|||
|
||||
sub canedit {
|
||||
my $self = shift;
|
||||
return !$self->run->stop_date && $self->canview
|
||||
&& (UserInGroup('managetestplans')
|
||||
|| UserInGroup('edittestcases')
|
||||
|| UserInGroup('runtests'));
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->run->plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 2;
|
||||
return 1 if $self->run->plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 candelete
|
||||
|
@ -1060,9 +1006,11 @@ Returns true if the logged in user has rights to delete this case-run.
|
|||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
return 0 unless $self->canedit && Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group("admin");
|
||||
return 1 if Bugzilla->user->id == $self->run->manager->id;
|
||||
return 1 if Bugzilla->user->in_group('admin');
|
||||
return 0 unless Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group('Testers') && Param("testopia-allow-group-member-deletes");
|
||||
return 1 if $self->run->plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 4;
|
||||
return 1 if $self->run->plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ use Bugzilla::User;
|
|||
use Bugzilla::Util;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Testopia::Util;
|
||||
use Bugzilla::Testopia::TestRun;
|
||||
use Bugzilla::Testopia::TestCase;
|
||||
|
@ -77,14 +78,14 @@ use base qw(Exporter);
|
|||
=cut
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
test_plans.plan_id
|
||||
test_plans.product_id
|
||||
test_plans.author_id
|
||||
test_plans.type_id
|
||||
test_plans.default_product_version
|
||||
test_plans.name
|
||||
test_plans.creation_date
|
||||
test_plans.isactive
|
||||
plan_id
|
||||
product_id
|
||||
author_id
|
||||
type_id
|
||||
default_product_version
|
||||
name
|
||||
creation_date
|
||||
isactive
|
||||
);
|
||||
|
||||
use constant NAME_MAX_LENGTH => 255;
|
||||
|
@ -183,6 +184,14 @@ sub store {
|
|||
my $key = $dbh->bz_last_key( 'test_plans', 'plan_id' );
|
||||
$self->store_text($key, $self->{'author_id'}, $self->text, $timestamp);
|
||||
$self->{'plan_id'} = $key;
|
||||
|
||||
# Add permissions for the plan
|
||||
$self->add_tester($self->{'author_id'},15);
|
||||
if (Param('testopia-default-plan-testers-regexp')) {
|
||||
$self->set_tester_regexp( Param('testopia-default-plan-testers-regexp'), 3);
|
||||
$self->derive_regexp_testers(Param('testopia-default-plan-testers-regexp'));
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
@ -595,6 +604,20 @@ sub check_plan_type {
|
|||
return $type;
|
||||
}
|
||||
|
||||
sub check_tester {
|
||||
my $self = shift;
|
||||
my $userid = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($exists) = $dbh->selectrow_array(
|
||||
"SELECT 1
|
||||
FROM test_plan_permissions
|
||||
WHERE userid = ? AND plan_id = ?",
|
||||
undef, ($userid, $self->id));
|
||||
|
||||
return $exists;
|
||||
|
||||
}
|
||||
=head2 update_plan_type
|
||||
|
||||
Update the given type
|
||||
|
@ -772,6 +795,30 @@ sub history {
|
|||
return $ref;
|
||||
}
|
||||
|
||||
sub copy_permissions {
|
||||
my $self = shift;
|
||||
my ($planid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($regexp, $perms) = $dbh->selectrow_array(
|
||||
"SELECT user_regexp, permissions
|
||||
FROM test_plan_permissions_regexp
|
||||
WHERE plan_id = ?",undef, $self->id);
|
||||
|
||||
$dbh->do("INSERT INTO test_plan_permissions_regexp (plan_id, user_regexp, permissions)
|
||||
VALUES(?,?,?)", undef,($planid, $regexp, $perms));
|
||||
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT userid, permissions
|
||||
FROM test_plan_permissions
|
||||
WHERE plan_id = ? AND grant_type = ?",
|
||||
{'Slice' =>{}}, ($self->id, GRANT_DIRECT));
|
||||
foreach my $row (@$ref){
|
||||
$dbh->do("INSERT INTO test_plan_permissions (userid, plan_id, permissions, grant_type)
|
||||
VALUES(?,?,?,?)", undef, ($row->{'userid'}, $planid, $row->{'permissions'}, GRANT_DIRECT));
|
||||
}
|
||||
}
|
||||
|
||||
=head2 lookup_type
|
||||
|
||||
Takes an ID of the type field and returns the value
|
||||
|
@ -846,7 +893,94 @@ sub lookup_product_by_name {
|
|||
return $value;
|
||||
}
|
||||
|
||||
sub set_tester_regexp {
|
||||
my $self = shift;
|
||||
my ($regexp, $permissions) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($is, $oldreg, $oldperms) = $dbh->selectrow_array(
|
||||
"SELECT 1, user_regexp, permissions
|
||||
FROM test_plan_permissions_regexp
|
||||
WHERE plan_id = ?",undef, $self->id);
|
||||
|
||||
return unless ($oldreg ne $regexp || $oldperms != $permissions);
|
||||
if ($is){
|
||||
$dbh->do("UPDATE test_plan_permissions_regexp
|
||||
SET user_regexp = ?, permissions = ?
|
||||
WHERE plan_id = ?", undef, ($regexp, $permissions, $self->id));
|
||||
}
|
||||
else {
|
||||
$dbh->do("INSERT INTO test_plan_permissions_regexp(plan_id, user_regexp, permissions)
|
||||
VALUES(?,?,?)",
|
||||
undef, ($self->id, $regexp, $permissions));
|
||||
}
|
||||
|
||||
$self->derive_regexp_testers($regexp);
|
||||
|
||||
}
|
||||
sub derive_regexp_testers {
|
||||
my $self = shift;
|
||||
my $regexp = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
# Get the permissions of the regexp testers so we can set it later.
|
||||
my ($permissions) = $dbh->selectrow_array(
|
||||
"SELECT permissions
|
||||
FROM test_plan_permissions_regexp
|
||||
WHERE plan_id = ?", undef, $self->id);
|
||||
# If something has changed, it is easier to delete everyone and add tham back in
|
||||
$dbh->do("DELETE FROM test_plan_permissions
|
||||
WHERE plan_id = ? AND grant_type = ?",
|
||||
undef, ($self->id, GRANT_REGEXP));
|
||||
|
||||
my $sth = $dbh->prepare("SELECT profiles.userid, profiles.login_name, plan_id
|
||||
FROM profiles
|
||||
LEFT JOIN test_plan_permissions
|
||||
ON test_plan_permissions.userid = profiles.userid
|
||||
AND test_plan_permissions.plan_id = ?
|
||||
AND grant_type = ?");
|
||||
my $plan_add = $dbh->prepare("INSERT INTO test_plan_permissions
|
||||
(userid, plan_id, permissions, grant_type)
|
||||
VALUES (?,?,?,?)");
|
||||
my $plan_del = $dbh->prepare("DELETE FROM test_plan_permissions
|
||||
WHERE user_id = ? AND plan_id = ?
|
||||
AND grant_type = ?");
|
||||
$sth->execute($self->id, GRANT_REGEXP);
|
||||
while (my ($userid, $login, $present) = $sth->fetchrow_array()) {
|
||||
if (($regexp =~ /\S+/) && ($login =~ m/$regexp/i)){
|
||||
$plan_add->execute($userid, $self->id, $permissions, GRANT_REGEXP) unless $present;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub remove_tester {
|
||||
my $self = shift;
|
||||
my ($userid) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->do("DELETE FROM test_plan_permissions
|
||||
WHERE userid = ? AND plan_id = ? AND grant_type = ?",
|
||||
undef, ($userid, $self->id, GRANT_DIRECT));
|
||||
}
|
||||
|
||||
sub add_tester {
|
||||
my $self = shift;
|
||||
my ($userid, $perms) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->do("INSERT INTO test_plan_permissions(userid, plan_id, permissions)
|
||||
VALUES(?,?,?,?)",
|
||||
undef, ($userid, $self->id, $perms, GRANT_DIRECT));
|
||||
}
|
||||
|
||||
sub update_tester {
|
||||
my $self = shift;
|
||||
my ($userid, $perms) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$dbh->do("UPDATE test_plan_permissions SET permissions = ?
|
||||
WHERE userid = ? AND plan_id = ? AND grant_type = ?",
|
||||
undef, ($perms, $userid, $self->id, GRANT_DIRECT));
|
||||
}
|
||||
|
||||
=head2 obliterate
|
||||
|
||||
|
@ -903,7 +1037,11 @@ Returns true if the logged in user has rights to edit this plan
|
|||
|
||||
sub canedit {
|
||||
my $self = shift;
|
||||
return $self->canview && UserInGroup("managetestplans");
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 2;
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 2;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
=head2 canview
|
||||
|
@ -914,8 +1052,10 @@ Returns true if the logged in user has rights to view this plan
|
|||
|
||||
sub canview {
|
||||
my $self = shift;
|
||||
return 1 if (Bugzilla->user->id == $self->author->id);
|
||||
return Bugzilla::Testopia::Util::can_view_product($self->product_id);
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) > 0;
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) > 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 candelete
|
||||
|
@ -926,12 +1066,34 @@ Returns true if the logged in user has rights to delete this plan
|
|||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
return 0 unless $self->canedit && Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group('admin');
|
||||
return 0 unless Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group('Testers') && Param("testopia-allow-group-member-deletes");
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 4;
|
||||
return 1 if $self->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub canadmin {
|
||||
my $self = shift;
|
||||
return 1 if Bugzilla->user->in_group("admin");
|
||||
return 1 if Bugzilla->user->id == $self->author->id;
|
||||
return 1 if ($self->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 8);
|
||||
return 1 if ($self->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub get_user_rights {
|
||||
my $self = shift;
|
||||
my ($userid, $type) = @_;
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($perms) = $dbh->selectrow_array(
|
||||
"SELECT permissions FROM test_plan_permissions
|
||||
WHERE userid = ? AND plan_id = ? AND grant_type = ?",
|
||||
undef, ($userid, $self->id, $type));
|
||||
|
||||
return $perms;
|
||||
}
|
||||
|
||||
###############################
|
||||
#### Accessors ####
|
||||
|
@ -970,6 +1132,12 @@ Returns the type id of this plan
|
|||
|
||||
Returns true if this plan is not archived
|
||||
|
||||
=head2 use_product_rights
|
||||
|
||||
If true, user access is granted based first on product groups and then on the
|
||||
plan's access list otherwise, all right associated with this plan are
|
||||
determined bey the ACL.
|
||||
|
||||
=cut
|
||||
|
||||
sub id { return $_[0]->{'plan_id'}; }
|
||||
|
@ -993,6 +1161,59 @@ sub type {
|
|||
return $self->{'type'};
|
||||
}
|
||||
|
||||
sub tester_regexp {
|
||||
my ($self) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($regexp) = $dbh->selectrow_array(
|
||||
"SELECT user_regexp
|
||||
FROM test_plan_permissions_regexp
|
||||
WHERE plan_id = ?", undef, $self->id);
|
||||
|
||||
return $regexp;
|
||||
}
|
||||
|
||||
sub tester_regexp_permissions {
|
||||
my ($self) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my ($perms) = $dbh->selectrow_array(
|
||||
"SELECT permissions
|
||||
FROM test_plan_permissions_regexp
|
||||
WHERE plan_id = ?", undef, $self->id);
|
||||
my $p;
|
||||
|
||||
$p->{'read'} = 1 & $perms;
|
||||
$p->{'write'} = 2 & $perms;
|
||||
$p->{'delete'} = 4 & $perms;
|
||||
$p->{'admin'} = 8 & $perms;
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
sub access_list {
|
||||
my ($self) = @_;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $ref = $dbh->selectall_arrayref(
|
||||
"SELECT tpt.userid, permissions
|
||||
FROM test_plan_permissions AS tpt
|
||||
JOIN profiles ON profiles.userid = tpt.userid
|
||||
WHERE plan_id = ? AND grant_type = ?
|
||||
ORDER BY profiles.realname", {'Slice' =>{}}, ($self->id, GRANT_DIRECT));
|
||||
my @rows;
|
||||
foreach my $row (@$ref){
|
||||
push @rows, {'user' => Bugzilla::User->new($row->{'userid'}),
|
||||
'read' => 1 & $row->{'permissions'},
|
||||
'write' => 2 & $row->{'permissions'},
|
||||
'delete' => 4 & $row->{'permissions'},
|
||||
'admin' => 8 & $row->{'permissions'},
|
||||
};
|
||||
}
|
||||
$self->{'access_list'} = \@rows;
|
||||
return $self->{'access_list'};
|
||||
}
|
||||
|
||||
=head2 attachments
|
||||
|
||||
Returns a reference to a list of attachments on this plan
|
||||
|
|
|
@ -738,10 +738,10 @@ Returns true if the logged in user has rights to edit this test run.
|
|||
|
||||
sub canedit {
|
||||
my $self = shift;
|
||||
return $self->canview
|
||||
&& (UserInGroup('managetestplans')
|
||||
|| UserInGroup('edittestcases')
|
||||
|| UserInGroup('runtests'));
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 2;
|
||||
return 1 if $self->plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 canview
|
||||
|
@ -752,9 +752,11 @@ Returns true if the logged in user has rights to view this test run.
|
|||
|
||||
sub canview {
|
||||
my $self = shift;
|
||||
return $self->{'canview'} if exists $self->{'canview'};
|
||||
$self->{'canview'} = Bugzilla::Testopia::Util::can_view_product($self->plan->product_id);
|
||||
return $self->{'canview'};
|
||||
return 1 if Bugzilla->user->in_group('Testers');
|
||||
return 1 if $self->plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) > 0;
|
||||
return 1 if $self->plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) > 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
=head2 candelete
|
||||
|
@ -765,10 +767,11 @@ Returns true if the logged in user has rights to delete this test run.
|
|||
|
||||
sub candelete {
|
||||
my $self = shift;
|
||||
return 0 unless $self->canedit && Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group("admin");
|
||||
return 1 if Bugzilla->user->id == $self->manager->id;
|
||||
return 1 if Bugzilla->user->id == $self->plan->author->id;
|
||||
return 1 if Bugzilla->user->in_group('admin');
|
||||
return 0 unless Param("allow-test-deletion");
|
||||
return 1 if Bugzilla->user->in_group('Testers') && Param("testopia-allow-group-member-deletes");
|
||||
return 1 if $self->plan->get_user_rights(Bugzilla->user->id, GRANT_REGEXP) & 4;
|
||||
return 1 if $self->plan->get_user_rights(Bugzilla->user->id, GRANT_DIRECT) & 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
"allow-test-deletion" => "If this option is on, users can delete objects including plans and cases",
|
||||
|
||||
"testopia-allow-group-member-deletes" => "If this option is on, members of the Testers group will be
|
||||
allowed to delete test objects",
|
||||
|
||||
"testopia-default-plan-testers-regexp" => "This is the default regular expression for granting
|
||||
access to new test plans",
|
||||
|
||||
"print-tag-in-case-log" => 'If this option is on, the entire tag text is printed in a test case ' _
|
||||
'log entry. Otherwise, only an href to the tag is put there.',
|
||||
|
||||
|
|
|
@ -120,5 +120,11 @@
|
|||
[% ELSIF error == "missing-plans-list" %]
|
||||
[% title = "No plans selected" %]
|
||||
You did not select any plans to copy this case to.
|
||||
[% ELSIF error == "testopia-tester-already-on-list" %]
|
||||
[% title = "Selected user is already on the list" %]
|
||||
The user [% login FILTER html %] is already a member of the ACL for this plan.
|
||||
[% ELSIF error == "testopia-plan-acl-denied" %]
|
||||
[% title = "Plan Administrator Privileges Required" %]
|
||||
You must be an administrator of this test plan to modify the access control list.
|
||||
[% END %]
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
[%# 1.0@bugzilla.org %]
|
||||
[%# 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>
|
||||
#%]
|
||||
|
||||
<link href="testopia/css/default.css" rel="stylesheet" type="text/css" />
|
||||
[% PROCESS global/header.html.tmpl %]
|
||||
|
||||
<h1>Access Control for Plan [% plan.id FILTER none %] - [% plan.name FILTER html %]</h1>
|
||||
<p>
|
||||
This page allows plan managers to permit access to a test plan. By default, members of the
|
||||
<b>Testers</b> group in Bugzilla will have read and write access. Beyond this, users login names
|
||||
(email addresses) that match a given regular expression will be granted the level of permissions
|
||||
specified. Lastly, individuals can be granted additional permissions by adding them
|
||||
explicitly.
|
||||
</p>
|
||||
<p>
|
||||
Delete and Admin rights are always handled by the access control list, unless the
|
||||
<b>testopia-allow-group-member-deletes</b> parameter is set to <i>on</i>. Doing so will grant
|
||||
delete rights to the <b>Testers</b> group.
|
||||
</p>
|
||||
|
||||
[% PROCESS testopia/messages.html.tmpl %]
|
||||
<form action="tr_plan_access.cgi" method="POST">
|
||||
<input type="hidden" name="plan_id" value="[% plan.id FILTER none %]">
|
||||
<h3>Access Method</h3>
|
||||
<table>
|
||||
<tr class="bz_row_header">
|
||||
<th>User Regular Expression</th>
|
||||
<th>Read</th>
|
||||
<th>Write</th>
|
||||
<th>Delete</th>
|
||||
<th>Admin</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input name="userregexp" value="[% plan.tester_regexp FILTER none %]" size="70"><br></td>
|
||||
<td align="center"><input type="checkbox" name="pr" [% 'checked="checked"' IF plan.tester_regexp_permissions.read %] value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="pw" [% 'checked="checked"' IF plan.tester_regexp_permissions.write %] value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="pd" [% 'checked="checked"' IF plan.tester_regexp_permissions.delete %] value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="pa" [% 'checked="checked"' IF plan.tester_regexp_permissions.admin %] value="1"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<h3>Access Control List</h3>
|
||||
<table>
|
||||
<tr class="bz_row_header">
|
||||
<th>User</th>
|
||||
<th>Read</th>
|
||||
<th>Write</th>
|
||||
<th>Delete</th>
|
||||
<th>Admin</th>
|
||||
</tr>
|
||||
[% FOREACH row = plan.access_list %]
|
||||
<tr class="[% loop.count % 2 == 0 ? "bz_row_odd" : "bz_row_even" %]">
|
||||
<td>[%'*' IF row.user.id == plan.author.id %][% row.user.identity FILTER html %]</td>
|
||||
<td align="center"><input type="checkbox" name="r[% row.user.id %]" [% 'checked="checked"' IF row.read %] value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="w[% row.user.id %]" [% 'checked="checked"' IF row.write %] value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="d[% row.user.id %]" [% 'checked="checked"' IF row.delete %] value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="a[% row.user.id %]" [% 'checked="checked"' IF row.admin %] value="1"></td>
|
||||
<td><a href="tr_plan_access.cgi?action=delete&user=[% row.user.id %]&plan_id=[% plan.id FILTER none %]">Remove</a></td>
|
||||
</tr>
|
||||
[% END %]
|
||||
<tr style="background-color:#D8E5EE">
|
||||
<td style="padding: 3px;"><input style="width:200px;" name="adduser"></td>
|
||||
<td align="center"><input type="checkbox" name="nr" value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="nw" value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="nd" value="1"></td>
|
||||
<td align="center"><input type="checkbox" name="na" value="1"></td>
|
||||
<td align="left"><input type="submit" name="action" value="Add User"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p align="right">
|
||||
<input type="submit" name="action" value="Apply Changes">
|
||||
</p>
|
||||
<dl>
|
||||
<dt>Read</dt>
|
||||
<dd>Allows viewing rights to the plan and all test cases, test runs, and test case-runs associated with it.
|
||||
Test cases linked to more than one plan will not be visible unless the user has view rights on all plans linked</dd>
|
||||
<dt>Write</dt>
|
||||
<dd>Implies Read. Allows rights to modify the plan and associated cases, runs, and case-runs.</dd>
|
||||
<dt>Delete</dt>
|
||||
<dd>Implies Read and Write. Allows rights to delete the plan and associated cases, runs, and case-runs.</dd>
|
||||
<dt>Admin</dt>
|
||||
<dd>Implies Read, Write, and Delete. Allows rights to modify the plan's access controls (this page).</dd>
|
||||
</dl>
|
||||
* Plan author
|
||||
<p>
|
||||
<a href="tr_show_plan.cgi?plan_id=[% plan.id FILTER none %]">Back</a> to test plan
|
||||
</p>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
|
@ -34,7 +34,7 @@
|
|||
[%############################################################################%]
|
||||
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Delete Test Case $case.summary"
|
||||
title = "Delete Test Case: $case.id - $case.summary"
|
||||
%]
|
||||
|
||||
[% IF NOT deleted %]
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
[%# 1.0@bugzilla.org %]
|
||||
[%# 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) 2007
|
||||
# Novell. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# ...
|
||||
#%]
|
||||
|
||||
[% PROCESS global/variables.none.tmpl %]
|
||||
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Unlink Test Case: $case.id - $case.summary"
|
||||
%]
|
||||
|
||||
You are about to permanently unlink this test case from test plan<br>
|
||||
<b>[% plan.id FILTER none %] - [% plan.name FILTER html %]</b>.
|
||||
<p>
|
||||
This will remove all history of this case from this plan.
|
||||
<br>
|
||||
<span style="font-size:12pt; font-weight:bold; color:#cc0000;">Warning: This action cannot be undone</span>
|
||||
<br>
|
||||
<br>
|
||||
<form action="tr_show_case.cgi">
|
||||
<input type="hidden" name="case_id" value="[% case.id FILTER none %]" />
|
||||
<input type="hidden" name="plan_id" value="[% plan.id FILTER none %]" />
|
||||
<input type="hidden" name="action" value="do_unlink" />
|
||||
<input type="submit" value="Unlink This Test Case" />
|
||||
</form>
|
||||
|
||||
<a href="tr_show_case.cgi?case_id=[% case.id FILTER none %]">Go back</a>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
|
@ -90,6 +90,12 @@
|
|||
type="radio" name="copy_tags" value="0" />No</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="TOP" align="RIGHT">Copy permissions:</td>
|
||||
<td><input type="radio" name="copy_perms" value="1" checked />Yes <input
|
||||
type="radio" name="copy_perms" value="0" />No</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="TOP" align="RIGHT">Maintain Plan and Case Authors:</td>
|
||||
<td><input type="radio" name="keepauthor" value="1" checked />Yes <input
|
||||
|
|
|
@ -154,6 +154,10 @@
|
|||
<tr class="bz_row_data">
|
||||
<td colspan="3"><div align="right">
|
||||
<a href="#attributes">Edit Plan Attributes</a>
|
||||
[% IF plan.canadmin %]
|
||||
| <a href="tr_plan_access.cgi?plan_id=[% plan.id FILTER none %]">Edit Access Controls</a>
|
||||
[% END %]
|
||||
|
||||
<input type="hidden" name="plan_id" value="[% plan.id FILTER none %]">
|
||||
<input type="submit" name="action" value="Commit" style="visibility:hidden;">
|
||||
<input type="submit" name="action" value="[% plan.isactive ? "Archive" : "Unarchive" %]">
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
textarea {
|
||||
background-color: #fff;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.resultsTable {
|
||||
border-collapse: collapse; /*cellspacing*/
|
||||
border-spacing: 0px;
|
||||
}
|
||||
.resultsTable td { /*only immediate tds of mytable*/
|
||||
padding: 4px; /*cellpadding*/
|
||||
}
|
||||
|
||||
.resultsTable td a:hover {
|
||||
text-decoration:underline overline;
|
||||
}
|
||||
|
||||
.resultsTable th {
|
||||
border-color:#FFF;
|
||||
background-color:#C0FFC0;
|
||||
|
||||
border-style:solid;
|
||||
border-width: 2px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.dlgTable {
|
||||
border-collapse: collapse; /*cellspacing*/
|
||||
border-spacing: 0px;
|
||||
}
|
||||
|
||||
.dlgTable td { /*only immediate tds of mytable*/
|
||||
padding: 4px; /*cellpadding*/
|
||||
background-color:#EEE;
|
||||
}
|
||||
|
||||
.spacerTable {
|
||||
border-collapse: collapse; /*cellspacing*/
|
||||
border-spacing: 0px;
|
||||
}
|
||||
.spacerTable td { /*only immediate tds of mytable*/
|
||||
padding: 16px; /*cellpadding*/
|
||||
background-color:#FFF;
|
||||
}
|
||||
|
||||
.menuTable {
|
||||
border-collapse: collapse; /*cellspacing*/
|
||||
border-spacing: 0px;
|
||||
}
|
||||
.menuTable td { /*only immediate tds of mytable*/
|
||||
padding: 4px; /*cellpadding*/
|
||||
background-color:#EEE;
|
||||
|
||||
border-style:solid;
|
||||
border-width: 3px;
|
||||
border-color:#FFF;
|
||||
}
|
||||
|
||||
.evenRow_first {
|
||||
background-color:#FFF;
|
||||
}
|
||||
.evenRow {
|
||||
background-color:#FFF;
|
||||
}
|
||||
.evenRow td{
|
||||
background-color:#FFF;border-top-style:solid;border-top-width:1px;border-top-color:#CCC;
|
||||
}
|
||||
|
||||
.oddRow_first {
|
||||
background-color:#EEE;
|
||||
}
|
||||
.oddRow {
|
||||
background-color:#EEE;
|
||||
}
|
||||
.oddRow td {
|
||||
background-color:#EEE;border-top-style:solid;border-top-width:1px;border-top-color:#CCC;
|
||||
}
|
||||
|
||||
.highlightedCell {
|
||||
border-width:1px;
|
||||
border-style:solid;
|
||||
background-color:lightyellow;
|
||||
}
|
||||
|
||||
/* tr_showcaselog */
|
||||
|
||||
.short_body {
|
||||
border-bottom:1px solid #000;
|
||||
border-left:1px solid #000;
|
||||
border-right:1px solid #000;
|
||||
}
|
||||
|
||||
.short_head {
|
||||
border-top:1px solid #000;
|
||||
border-left:1px solid #000;
|
||||
border-right:1px solid #000;
|
||||
}
|
||||
|
||||
.ae_dv {
|
||||
display:none;
|
||||
margin-left:15px;
|
||||
border-width:0px;
|
||||
}
|
||||
|
||||
.ae_tb {
|
||||
width:100%;
|
||||
border:0;
|
||||
margin:0;
|
||||
margin-right:30px;
|
||||
margin-bottom:10px;
|
||||
border-collapse:collapse;
|
||||
border-spacing: 0px;
|
||||
}
|
||||
|
||||
.ae_s {
|
||||
border-style:solid;
|
||||
border-width:1px;
|
||||
border-color:#000;
|
||||
background-color:#FFFFE0;
|
||||
}
|
||||
|
||||
.cc_i {
|
||||
float:left;
|
||||
margin-left:10px;
|
||||
}
|
||||
|
||||
.cc_xx {
|
||||
clear:both;
|
||||
margin-right:30px;
|
||||
padding-top:5px;
|
||||
}
|
||||
|
||||
.cc_trg {
|
||||
padding-left:5px;
|
||||
padding-right:5px;
|
||||
vertical-align:baseline;
|
||||
}
|
||||
|
||||
/* TODO: refactor these two: */
|
||||
|
||||
#floatMsg {
|
||||
text-align:right;
|
||||
background-color:#FFDD66;
|
||||
color:black;
|
||||
padding:4px;
|
||||
padding-left:20px;
|
||||
padding-right:20px;
|
||||
font-family:Arial;
|
||||
font-weight:bold;
|
||||
font-size:12px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.floatMsg {
|
||||
text-align:right;
|
||||
background-color:#FFDD66;
|
||||
color:black;
|
||||
padding:4px;
|
||||
padding-left:20px;
|
||||
padding-right:20px;
|
||||
font-family:Arial;
|
||||
font-weight:bold;
|
||||
font-size:12px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.tr_button {
|
||||
width:100px;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
h3 {
|
||||
border-bottom: 1px dotted #000;
|
||||
}
|
|
@ -87,6 +87,9 @@ if (!GroupDoesExist($dbh, "runtests")) {
|
|||
'Can add, delete and edit test runs.', $adminid);
|
||||
tr_AssignAdminGrants($dbh, $groupid, $adminid);
|
||||
}
|
||||
|
||||
updateACLs($dbh);
|
||||
|
||||
print "Done.\n\n";
|
||||
##############################################################################
|
||||
print "Cleaning up Testopia cache ...\n";
|
||||
|
@ -295,9 +298,9 @@ sub UpdateDB {
|
|||
$dbh->bz_drop_table('test_case_group_map');
|
||||
$dbh->bz_drop_table('test_category_templates');
|
||||
$dbh->bz_drop_table('test_plan_testers');
|
||||
|
||||
$dbh->bz_drop_table('test_plan_group_map');
|
||||
$dbh->bz_drop_column('test_plans', 'editor_id');
|
||||
|
||||
|
||||
$dbh->bz_add_column('test_case_bugs', 'case_id', {TYPE => 'INT4', UNSIGNED => 1});
|
||||
$dbh->bz_add_column('test_case_runs', 'environment_id', {TYPE => 'INT4', UNSIGNED => 1, NOTNULL => 1}, 0);
|
||||
$dbh->bz_add_column('test_case_tags', 'userid', {TYPE => 'INT3', NOTNULL => 1}, 0);
|
||||
|
@ -380,7 +383,7 @@ sub UpdateDB {
|
|||
$dbh->bz_add_index('test_runs', 'test_run_plan_id_run_id_idx', [qw(plan_id run_id)]);
|
||||
$dbh->bz_add_index('test_runs', 'test_runs_summary_idx', {FIELDS => ['summary'], TYPE => 'FULLTEXT'});
|
||||
|
||||
if ($dbh->bz_index_info('test_case_tags', 'case_tags_case_id_idx')->{TYPE} eq '') {
|
||||
if ($dbh->bz_index_info('test_case_tags', 'case_tags_case_id_idx') && $dbh->bz_index_info('test_case_tags', 'case_tags_case_id_idx')->{TYPE} eq '') {
|
||||
$dbh->bz_drop_index('test_case_tags', 'case_tags_case_id_idx');
|
||||
$dbh->bz_add_index('test_case_tags', 'case_tags_case_id_idx', {FIELDS => [qw(tag_id case_id)], TYPE => 'UNIQUE'});
|
||||
}
|
||||
|
@ -399,6 +402,21 @@ sub UpdateDB {
|
|||
migrateEnvData($dbh);
|
||||
}
|
||||
|
||||
sub updateACLs {
|
||||
my $dbh = shift;
|
||||
print "Checking plan ACLs \n";
|
||||
my $ref = $dbh->selectall_arrayref("SELECT plan_id, author_id FROM test_plans", {'Slice' =>{}});
|
||||
foreach my $plan (@$ref){
|
||||
my ($finished) = $dbh->selectrow_array(
|
||||
"SELECT COUNT(*) FROM test_plan_permissions
|
||||
WHERE plan_id = ? AND userid = ?",
|
||||
undef, ($plan->{'plan_id'}, $plan->{'author_id'}));
|
||||
next if ($finished);
|
||||
$dbh->do("INSERT INTO test_plan_permissions(userid, plan_id, permissions)
|
||||
VALUES(?,?,?)",
|
||||
undef, ($plan->{'author_id'}, $plan->{'plan_id'}, 15));
|
||||
}
|
||||
}
|
||||
sub populateMiscTables {
|
||||
my ($dbh) = (@_);
|
||||
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#!/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) 2007
|
||||
# Novell. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
||||
|
||||
use strict;
|
||||
use lib ".";
|
||||
|
||||
use Bugzilla;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::Testopia::Util;
|
||||
use Bugzilla::Testopia::Product;
|
||||
|
||||
use vars qw($vars);
|
||||
use Data::Dumper;
|
||||
|
||||
require 'globals.pl';
|
||||
|
||||
my $template = Bugzilla->template;
|
||||
my $cgi = Bugzilla->cgi;
|
||||
Bugzilla->login();
|
||||
print $cgi->header;
|
||||
|
||||
my $plan_id = trim($cgi->param('plan_id') || '');
|
||||
my $action = $cgi->param('action') || '';
|
||||
|
||||
unless (detaint_natural($plan_id)){
|
||||
$vars->{'form_action'} = 'tr_plan_access.cgi';
|
||||
$template->process("testopia/plan/choose.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
exit;
|
||||
}
|
||||
|
||||
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
|
||||
|
||||
unless ($plan->canadmin){
|
||||
ThrowUserError('testopia-plan-acl-denied', {plan_id => $plan->id});
|
||||
}
|
||||
|
||||
|
||||
#print Dumper($plan->access_list);
|
||||
|
||||
if ($action eq 'Apply Changes'){
|
||||
do_update();
|
||||
display();
|
||||
}
|
||||
elsif ($action eq 'Add User'){
|
||||
do_update();
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $userid = DBNameToIdAndCheck(trim($cgi->param('adduser')));
|
||||
ThrowUserError('testopia-tester-already-on-list', {'login' => $cgi->param('adduser')})
|
||||
if ($plan->check_tester($userid));
|
||||
|
||||
my $perms = 0;
|
||||
|
||||
# The order we check these is important since each permission
|
||||
# implies the prior ones.
|
||||
$perms = $cgi->param("nr") ? 1 : $perms;
|
||||
$perms = $cgi->param("nw") ? 3 : $perms;
|
||||
$perms = $cgi->param("nd") ? 7 : $perms;
|
||||
$perms = $cgi->param("na") ? 15 : $perms;
|
||||
|
||||
$plan->add_tester($userid, $perms);
|
||||
|
||||
display();
|
||||
}
|
||||
elsif ($action eq 'delete'){
|
||||
my $userid = $cgi->param('user');
|
||||
detaint_natural($userid);
|
||||
my $user = Bugzilla::User->new($userid);
|
||||
$plan->remove_tester($user->id);
|
||||
$vars->{'tr_message'} = $user->login ." Removed from Plan";
|
||||
display();
|
||||
}
|
||||
|
||||
else{
|
||||
display();
|
||||
}
|
||||
|
||||
sub do_update {
|
||||
# We need at least on admin
|
||||
my $params = join(" ", $cgi->param());
|
||||
ThrowUserErorr('testopia-no-admins') unless $params =~ /a\d+/;
|
||||
|
||||
my $tester_regexp = $cgi->param('userregexp');
|
||||
trick_taint($tester_regexp);
|
||||
|
||||
my $regexp_perms = 0;
|
||||
|
||||
# The order we check these is important since each permission
|
||||
# implies the prior ones.
|
||||
$regexp_perms = $cgi->param('pr') ? 1 : $regexp_perms;
|
||||
$regexp_perms = $cgi->param('pw') ? 3 : $regexp_perms;
|
||||
$regexp_perms = $cgi->param('pd') ? 7 : $regexp_perms;
|
||||
$regexp_perms = $cgi->param('pa') ? 15 : $regexp_perms;
|
||||
|
||||
$plan->set_tester_regexp($tester_regexp, $regexp_perms);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
foreach my $row (@{$plan->access_list}){
|
||||
my $perms = 0;
|
||||
|
||||
# The order we check these is important since each permission
|
||||
# implies the prior ones.
|
||||
$perms = $cgi->param('r'.$row->{'user'}->id) ? 1 : $perms;
|
||||
$perms = $cgi->param('w'.$row->{'user'}->id) ? 3 : $perms;
|
||||
$perms = $cgi->param('d'.$row->{'user'}->id) ? 7 : $perms;
|
||||
$perms = $cgi->param('a'.$row->{'user'}->id) ? 15 : $perms;
|
||||
|
||||
$plan->update_tester($row->{'user'}->id, $perms);
|
||||
}
|
||||
}
|
||||
|
||||
sub display {
|
||||
$vars->{'plan'} = $plan;
|
||||
$vars->{'user'} = Bugzilla->user;
|
||||
$template->process("testopia/admin/access-list.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
}
|
|
@ -222,12 +222,37 @@ elsif ($action eq 'unlink'){
|
|||
my $plan_id = $cgi->param('plan_id');
|
||||
validate_test_id($plan_id, 'plan');
|
||||
my $case = Bugzilla::Testopia::TestCase->new($case_id);
|
||||
ThrowUserError("testopia-read-only", {'object' => 'case'})
|
||||
unless ($case->can_unlink_plan($plan_id));
|
||||
|
||||
if (scalar @{$case->plans} == 1){
|
||||
$vars->{'case'} = $case;
|
||||
$vars->{'runcount'} = scalar @{$case->runs};
|
||||
$vars->{'plancount'} = scalar @{$case->plans};
|
||||
$vars->{'bugcount'} = scalar @{$case->bugs};
|
||||
$template->process("testopia/case/delete.html.tmpl", $vars) ||
|
||||
ThrowTemplateError($template->error());
|
||||
}
|
||||
else {
|
||||
$vars->{'plan'} = Bugzilla::Testopia::TestPlan->new($plan_id);
|
||||
$vars->{'case'} = $case;
|
||||
$template->process("testopia/case/unlink.html.tmpl", $vars) ||
|
||||
ThrowTemplateError($template->error());
|
||||
}
|
||||
}
|
||||
|
||||
elsif ($action eq 'do_unlink'){
|
||||
Bugzilla->login(LOGIN_REQUIRED);
|
||||
my $plan_id = $cgi->param('plan_id');
|
||||
validate_test_id($plan_id, 'plan');
|
||||
my $case = Bugzilla::Testopia::TestCase->new($case_id);
|
||||
ThrowUserError("testopia-read-only", {'object' => 'case'})
|
||||
unless ($case->can_unlink_plan($plan_id));
|
||||
|
||||
if ($case->unlink_plan($plan_id)){
|
||||
$vars->{'tr_message'} = "Test plan successfully unlinked";
|
||||
}
|
||||
else {
|
||||
$vars->{'tr_error'} = "Test plan could not be unlinked. It is used in test runs.";
|
||||
}
|
||||
|
||||
$vars->{'backlink'} = $case;
|
||||
display($case);
|
||||
}
|
||||
|
|
|
@ -135,6 +135,17 @@ elsif ($action eq 'do_clone'){
|
|||
$newplan->add_tag($newtagid);
|
||||
}
|
||||
}
|
||||
if ($cgi->param('copy_perms')){
|
||||
$plan->copy_permissions($newplanid);
|
||||
$newplan->derive_regexp_testers($plan->tester_regexp);
|
||||
}
|
||||
else {
|
||||
# Give the author admin rights
|
||||
$newplan->add_tester($author, 15);
|
||||
$newplan->set_tester_regexp( Param('testopia-default-plan-testers-regexp'), 3)
|
||||
if Param('testopia-default-plan-testers-regexp');
|
||||
$newplan->derive_regexp_testers(Param('testopia-default-plan-testers-regexp'))
|
||||
}
|
||||
if ($cgi->param('copy_cases')){
|
||||
my @catids;
|
||||
#TODO: Copy case to the new category
|
||||
|
@ -478,13 +489,13 @@ sub display {
|
|||
my @time = localtime(time());
|
||||
my $date = sprintf "%04d-%02d-%02d", 1900+$time[5],$time[4]+1,$time[3];
|
||||
my $filename = "testcases-$date.$format->{extension}";
|
||||
# print $cgi->multipart_final if ($serverpush && $vars->{'case_table'}->list_count >= 1000);
|
||||
print $cgi->header(-type => $format->{'ctype'},
|
||||
-content_disposition => "$disp; filename=$filename");
|
||||
-content_disposition => "$disp; filename=$filename")
|
||||
unless ($action eq 'do_clone');
|
||||
|
||||
$vars->{'percentage'} = \&percentage;
|
||||
$template->process($format->{'template'}, $vars) ||
|
||||
ThrowTemplateError($template->error());
|
||||
$vars->{'percentage'} = \&percentage;
|
||||
$template->process($format->{'template'}, $vars) ||
|
||||
ThrowTemplateError($template->error());
|
||||
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче