aboutsummaryrefslogtreecommitdiffstats
path: root/editflagtypes.cgi
diff options
context:
space:
mode:
authorFrédéric Buclin <LpSolit@gmail.com>2010-12-04 02:22:49 +0100
committerFrédéric Buclin <LpSolit@gmail.com>2010-12-04 02:22:49 +0100
commit6fac08b94b6cd67d8dd7ae8f7eeb5de5233c59d7 (patch)
tree3125cfcf7eddc39feb0966957bc3d59265fe112b /editflagtypes.cgi
parent4c2a23f4df1041fe21d534b38654a0d1c911282e (diff)
downloadbugs-6fac08b94b6cd67d8dd7ae8f7eeb5de5233c59d7.tar
bugs-6fac08b94b6cd67d8dd7ae8f7eeb5de5233c59d7.tar.gz
bugs-6fac08b94b6cd67d8dd7ae8f7eeb5de5233c59d7.tar.bz2
bugs-6fac08b94b6cd67d8dd7ae8f7eeb5de5233c59d7.tar.xz
bugs-6fac08b94b6cd67d8dd7ae8f7eeb5de5233c59d7.zip
Bug 529974: Let users with local editcomponents privs manage flags for products they can administer
a=LpSolit (module owner)
Diffstat (limited to 'editflagtypes.cgi')
-rwxr-xr-xeditflagtypes.cgi215
1 files changed, 161 insertions, 54 deletions
diff --git a/editflagtypes.cgi b/editflagtypes.cgi
index ecfa32ca8..4d11eecdb 100755
--- a/editflagtypes.cgi
+++ b/editflagtypes.cgi
@@ -38,7 +38,6 @@ use Bugzilla::Group;
use Bugzilla::Util;
use Bugzilla::Error;
use Bugzilla::Product;
-use Bugzilla::Component;
use Bugzilla::Token;
# Make sure the user is logged in and has the right privileges.
@@ -46,16 +45,18 @@ my $user = Bugzilla->login(LOGIN_REQUIRED);
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
-# We need this everywhere.
-my $vars = get_products_and_components();
-
print $cgi->header();
$user->in_group('editcomponents')
+ || scalar(@{$user->get_products_by_permission('editcomponents')})
|| ThrowUserError("auth_failure", {group => "editcomponents",
action => "edit",
object => "flagtypes"});
+# We need this everywhere.
+my $vars = get_products_and_components();
+my @products = @{$vars->{products}};
+
my $action = $cgi->param('action') || 'list';
my $token = $cgi->param('token');
my $product = $cgi->param('product');
@@ -63,13 +64,18 @@ my $component = $cgi->param('component');
my $flag_id = $cgi->param('id');
if ($product) {
- $product = Bugzilla::Product->check({ name => $product, allow_inaccessible => 1 });
+ # Make sure the user is allowed to view this product name.
+ # Users with global editcomponents privs can see all product names.
+ ($product) = grep { lc($_->name) eq lc($product) } @products;
+ $product || ThrowUserError('product_access_denied', { name => $cgi->param('product') });
}
if ($component) {
($product && $product->id)
|| ThrowUserError('flag_type_component_without_product');
- $component = Bugzilla::Component->check({ product => $product, name => $component });
+ ($component) = grep { lc($_->name) eq lc($component) } @{$product->components};
+ $component || ThrowUserError('product_unknown_component', { product => $product->name,
+ comp => $cgi->param('component') });
}
# If 'categoryAction' is set, it has priority over 'action'.
@@ -78,15 +84,30 @@ if (my ($category_action) = grep { $_ =~ /^categoryAction-(?:\w+)$/ } $cgi->para
my @inclusions = $cgi->param('inclusions');
my @exclusions = $cgi->param('exclusions');
+ my @categories;
+ if ($category_action =~ /^(in|ex)clude$/) {
+ if (!$user->in_group('editcomponents') && !$product) {
+ # The user can only add the flag type to products he can administrate.
+ foreach my $prod (@products) {
+ push(@categories, $prod->id . ':0')
+ }
+ }
+ else {
+ my $category = ($product ? $product->id : 0) . ':' .
+ ($component ? $component->id : 0);
+ push(@categories, $category);
+ }
+ }
+
if ($category_action eq 'include') {
- my $category = ($product ? $product->id : 0) . ":" .
- ($component ? $component->id : 0);
- push(@inclusions, $category) unless grep($_ eq $category, @inclusions);
+ foreach my $category (@categories) {
+ push(@inclusions, $category) unless grep($_ eq $category, @inclusions);
+ }
}
elsif ($category_action eq 'exclude') {
- my $category = ($product ? $product->id : 0) . ":" .
- ($component ? $component->id : 0);
- push(@exclusions, $category) unless grep($_ eq $category, @exclusions);
+ foreach my $category (@categories) {
+ push(@exclusions, $category) unless grep($_ eq $category, @exclusions);
+ }
}
elsif ($category_action eq 'removeInclusion') {
my @inclusion_to_remove = $cgi->param('inclusion_to_remove');
@@ -101,11 +122,6 @@ if (my ($category_action) = grep { $_ =~ /^categoryAction-(?:\w+)$/ } $cgi->para
}
}
- # Convert the array @clusions('prod_ID:comp_ID') back to a hash of
- # the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID'
- my %inclusions = clusion_array_to_hash(\@inclusions);
- my %exclusions = clusion_array_to_hash(\@exclusions);
-
$vars->{'groups'} = [Bugzilla::Group->get_all];
$vars->{'action'} = $action;
@@ -122,11 +138,13 @@ if (my ($category_action) = grep { $_ =~ /^categoryAction-(?:\w+)$/ } $cgi->para
$type->{'request_group'} = {};
$type->{'request_group'}->{'name'} = $cgi->param('request_group');
- $type->{'inclusions'} = \%inclusions;
- $type->{'exclusions'} = \%exclusions;
+ $vars->{'inclusions'} = clusion_array_to_hash(\@inclusions, \@products);
+ $vars->{'exclusions'} = clusion_array_to_hash(\@exclusions, \@products);
+
$vars->{'type'} = $type;
$vars->{'token'} = $token;
$vars->{'check_clusions'} = 1;
+ $vars->{'can_fully_edit'} = $cgi->param('can_fully_edit');
$template->process("admin/flag-type/edit.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
@@ -165,8 +183,7 @@ if ($action eq 'list') {
}
# If no product is given, then show all flag types available.
else {
- my $flagtypes = Bugzilla::FlagType::match({ group => $group_id });
-
+ my $flagtypes = get_editable_flagtypes(\@products, $group_id);
$bug_flagtypes = [grep { $_->target_type eq 'bug' } @$flagtypes];
$attach_flagtypes = [grep { $_->target_type eq 'attachment' } @$flagtypes];
}
@@ -202,8 +219,12 @@ if ($action eq 'enter') {
$vars->{'action'} = 'insert';
$vars->{'token'} = issue_session_token('add_flagtype');
- $vars->{'type'} = { 'target_type' => $type,
- 'inclusions' => { '__Any__:__Any__' => '0:0' } };
+ $vars->{'type'} = { 'target_type' => $type };
+ # Only users with global editcomponents privs can add a flagtype
+ # to all products.
+ $vars->{'inclusions'} = { '__Any__:__Any__' => '0:0' }
+ if $user->in_group('editcomponents');
+ $vars->{'can_fully_edit'} = 1;
# Get a list of groups available to restrict this flag type against.
$vars->{'groups'} = [Bugzilla::Group->get_all];
@@ -213,7 +234,19 @@ if ($action eq 'enter') {
}
if ($action eq 'edit' || $action eq 'copy') {
- $vars->{'type'} = Bugzilla::FlagType->check({ id => $flag_id });
+ my ($flagtype, $can_fully_edit) = $user->check_can_admin_flagtype($flag_id);
+ $vars->{'type'} = $flagtype;
+ $vars->{'can_fully_edit'} = $can_fully_edit;
+
+ if ($user->in_group('editcomponents')) {
+ $vars->{'inclusions'} = $flagtype->inclusions;
+ $vars->{'exclusions'} = $flagtype->exclusions;
+ }
+ else {
+ # Filter products the user shouldn't know about.
+ $vars->{'inclusions'} = clusion_array_to_hash([values %{$flagtype->inclusions}], \@products);
+ $vars->{'exclusions'} = clusion_array_to_hash([values %{$flagtype->exclusions}], \@products);
+ }
if ($action eq 'copy') {
$vars->{'action'} = "insert";
@@ -249,6 +282,12 @@ if ($action eq 'insert') {
my @inclusions = $cgi->param('inclusions');
my @exclusions = $cgi->param('exclusions');
+ # Filter inclusion and exclusion lists to products the user can see.
+ unless ($user->in_group('editcomponents')) {
+ @inclusions = values %{clusion_array_to_hash(\@inclusions, \@products)};
+ @exclusions = values %{clusion_array_to_hash(\@exclusions, \@products)};
+ }
+
my $flagtype = Bugzilla::FlagType->create({
name => $name,
description => $description,
@@ -270,9 +309,9 @@ if ($action eq 'insert') {
$vars->{'name'} = $flagtype->name;
$vars->{'message'} = "flag_type_created";
- my @flagtypes = Bugzilla::FlagType->get_all;
- $vars->{'bug_types'} = [grep { $_->target_type eq 'bug' } @flagtypes];
- $vars->{'attachment_types'} = [grep { $_->target_type eq 'attachment' } @flagtypes];
+ my $flagtypes = get_editable_flagtypes(\@products);
+ $vars->{'bug_types'} = [grep { $_->target_type eq 'bug' } @$flagtypes];
+ $vars->{'attachment_types'} = [grep { $_->target_type eq 'attachment' } @$flagtypes];
$template->process("admin/flag-type/list.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
@@ -295,17 +334,34 @@ if ($action eq 'update') {
my @inclusions = $cgi->param('inclusions');
my @exclusions = $cgi->param('exclusions');
- my $flagtype = Bugzilla::FlagType->check({ id => $flag_id });
- $flagtype->set_name($name);
- $flagtype->set_description($description);
- $flagtype->set_cc_list($cc_list);
- $flagtype->set_sortkey($sortkey);
- $flagtype->set_is_active($is_active);
- $flagtype->set_is_requestable($is_requestable);
- $flagtype->set_is_specifically_requestable($is_specifically);
- $flagtype->set_is_multiplicable($is_multiplicable);
- $flagtype->set_grant_group($grant_group);
- $flagtype->set_request_group($request_group);
+ my ($flagtype, $can_fully_edit) = $user->check_can_admin_flagtype($flag_id);
+ if ($cgi->param('check_clusions') && !$user->in_group('editcomponents')) {
+ # Filter inclusion and exclusion lists to products the user can edit.
+ @inclusions = values %{clusion_array_to_hash(\@inclusions, \@products)};
+ @exclusions = values %{clusion_array_to_hash(\@exclusions, \@products)};
+ # Bring back the products the user cannot edit.
+ foreach my $item (values %{$flagtype->inclusions}) {
+ my ($prod_id, $comp_id) = split(':', $item);
+ push(@inclusions, $item) unless grep { $_->id == $prod_id } @products;
+ }
+ foreach my $item (values %{$flagtype->exclusions}) {
+ my ($prod_id, $comp_id) = split(':', $item);
+ push(@exclusions, $item) unless grep { $_->id == $prod_id } @products;
+ }
+ }
+
+ if ($can_fully_edit) {
+ $flagtype->set_name($name);
+ $flagtype->set_description($description);
+ $flagtype->set_cc_list($cc_list);
+ $flagtype->set_sortkey($sortkey);
+ $flagtype->set_is_active($is_active);
+ $flagtype->set_is_requestable($is_requestable);
+ $flagtype->set_is_specifically_requestable($is_specifically);
+ $flagtype->set_is_multiplicable($is_multiplicable);
+ $flagtype->set_grant_group($grant_group);
+ $flagtype->set_request_group($request_group);
+ }
$flagtype->set_clusions({ inclusions => \@inclusions, exclusions => \@exclusions})
if $cgi->param('check_clusions');
my $changes = $flagtype->update();
@@ -316,9 +372,9 @@ if ($action eq 'update') {
$vars->{'changes'} = $changes;
$vars->{'message'} = 'flag_type_updated';
- my @flagtypes = Bugzilla::FlagType->get_all;
- $vars->{'bug_types'} = [grep { $_->target_type eq 'bug' } @flagtypes];
- $vars->{'attachment_types'} = [grep { $_->target_type eq 'attachment' } @flagtypes];
+ my $flagtypes = get_editable_flagtypes(\@products);
+ $vars->{'bug_types'} = [grep { $_->target_type eq 'bug' } @$flagtypes];
+ $vars->{'attachment_types'} = [grep { $_->target_type eq 'attachment' } @$flagtypes];
$template->process("admin/flag-type/list.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
@@ -326,7 +382,10 @@ if ($action eq 'update') {
}
if ($action eq 'confirmdelete') {
- $vars->{'flag_type'} = Bugzilla::FlagType->check({ id => $flag_id });
+ my ($flagtype, $can_fully_edit) = $user->check_can_admin_flagtype($flag_id);
+ ThrowUserError('flag_type_cannot_delete', { flagtype => $flagtype }) unless $can_fully_edit;
+
+ $vars->{'flag_type'} = $flagtype;
$vars->{'token'} = issue_session_token('delete_flagtype');
$template->process("admin/flag-type/confirm-delete.html.tmpl", $vars)
@@ -337,7 +396,9 @@ if ($action eq 'confirmdelete') {
if ($action eq 'delete') {
check_token_data($token, 'delete_flagtype');
- my $flagtype = Bugzilla::FlagType->check({ id => $flag_id });
+ my ($flagtype, $can_fully_edit) = $user->check_can_admin_flagtype($flag_id);
+ ThrowUserError('flag_type_cannot_delete', { flagtype => $flagtype }) unless $can_fully_edit;
+
$flagtype->remove_from_db();
delete_token($token);
@@ -357,7 +418,9 @@ if ($action eq 'delete') {
if ($action eq 'deactivate') {
check_token_data($token, 'delete_flagtype');
- my $flagtype = Bugzilla::FlagType->check({ id => $flag_id });
+ my ($flagtype, $can_fully_edit) = $user->check_can_admin_flagtype($flag_id);
+ ThrowUserError('flag_type_cannot_deactivate', { flagtype => $flagtype }) unless $can_fully_edit;
+
$flagtype->set_is_active(0);
$flagtype->update();
@@ -383,8 +446,15 @@ ThrowUserError('unknown_action', {action => $action});
sub get_products_and_components {
my $vars = {};
+ my $user = Bugzilla->user;
- my @products = Bugzilla::Product->get_all;
+ my @products;
+ if ($user->in_group('editcomponents')) {
+ @products = Bugzilla::Product->get_all;
+ }
+ else {
+ @products = @{$user->get_products_by_permission('editcomponents')};
+ }
# We require all unique component names.
my %components;
foreach my $product (@products) {
@@ -397,6 +467,29 @@ sub get_products_and_components {
return $vars;
}
+sub get_editable_flagtypes {
+ my ($products, $group_id) = @_;
+ my $flagtypes;
+
+ if (Bugzilla->user->in_group('editcomponents')) {
+ $flagtypes = Bugzilla::FlagType::match({ group => $group_id });
+ return $flagtypes;
+ }
+
+ my %visible_flagtypes;
+ foreach my $product (@$products) {
+ foreach my $target ('bug', 'attachment') {
+ my $prod_flagtypes = $product->flag_types->{$target};
+ $visible_flagtypes{$_->id} ||= $_ foreach @$prod_flagtypes;
+ }
+ }
+ @$flagtypes = sort { $a->sortkey <=> $b->sortkey || $a->name cmp $b->name }
+ values %visible_flagtypes;
+ # Filter flag types if a group ID is given.
+ $flagtypes = filter_group($flagtypes, $group_id);
+ return $flagtypes;
+}
+
sub filter_group {
my ($flag_types, $gid) = @_;
return $flag_types unless $gid;
@@ -410,24 +503,38 @@ sub filter_group {
# Convert the array @clusions('prod_ID:comp_ID') back to a hash of
# the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID'
sub clusion_array_to_hash {
- my $array = shift;
+ my ($array, $visible_products) = @_;
+ my $user = Bugzilla->user;
+ my $has_privs = $user->in_group('editcomponents');
+
my %hash;
my %products;
my %components;
+
foreach my $ids (@$array) {
- trick_taint($ids);
my ($product_id, $component_id) = split(":", $ids);
my $product_name = "__Any__";
+ my $component_name = "__Any__";
+
if ($product_id) {
- $products{$product_id} ||= new Bugzilla::Product($product_id);
- $product_name = $products{$product_id}->name if $products{$product_id};
+ ($products{$product_id}) = grep { $_->id == $product_id } @$visible_products;
+ next unless $products{$product_id};
+ $product_name = $products{$product_id}->name;
+
+ if ($component_id) {
+ ($components{$component_id}) =
+ grep { $_->id == $component_id } @{$products{$product_id}->components};
+ next unless $components{$component_id};
+ $component_name = $components{$component_id}->name;
+ }
}
- my $component_name = "__Any__";
- if ($component_id) {
- $components{$component_id} ||= new Bugzilla::Component($component_id);
- $component_name = $components{$component_id}->name if $components{$component_id};
+ else {
+ # Users with local editcomponents privs cannot use __Any__:__Any__.
+ next unless $has_privs;
+ # It's illegal to select a component without a product.
+ next if $component_id;
}
$hash{"$product_name:$component_name"} = $ids;
}
- return %hash;
+ return \%hash;
}