Add separate "Create products" permission

classes
Vitaliy Filippov 2015-10-26 13:37:14 +03:00
parent f39407bcab
commit 9be26744ed
8 changed files with 95 additions and 41 deletions

View File

@ -94,6 +94,7 @@ use constant SYSTEM_GROUPS => (
{ name => 'editusers' }, { name => 'editusers' },
{ name => 'creategroups' }, { name => 'creategroups' },
{ name => 'editclassifications' }, { name => 'editclassifications' },
{ name => 'createproducts' },
{ name => 'editcomponents' }, { name => 'editcomponents' },
{ name => 'editkeywords' }, { name => 'editkeywords' },
{ name => 'editbugs', userregexp => '.*' }, { name => 'editbugs', userregexp => '.*' },
@ -111,7 +112,7 @@ use constant SYSTEM_GROUPS => (
{ {
name => 'admin_index', name => 'admin_index',
include => [ include => [
qw(tweakparams editusers editclassifications editcomponents creategroups qw(tweakparams editusers editclassifications createproducts editcomponents creategroups
editfields editflagtypes editkeywords bz_canusewhines bz_editcheckers) editfields editflagtypes editkeywords bz_canusewhines bz_editcheckers)
], ],
}, },
@ -162,22 +163,33 @@ sub update_settings
sub update_system_groups sub update_system_groups
{ {
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
foreach my $definition (SYSTEM_GROUPS) foreach my $definition (SYSTEM_GROUPS)
{ {
my $exists = new Bugzilla::Group({ name => $definition->{name} }); my $grp = new Bugzilla::Group({ name => $definition->{name} });
$definition->{isbuggroup} = 0; $definition->{isbuggroup} = 0;
$definition->{description} = html_strip(Bugzilla->messages->{system_groups}->{$definition->{name}}); $definition->{description} = html_strip(Bugzilla->messages->{system_groups}->{$definition->{name}});
my $include = delete $definition->{include}; my $include = delete $definition->{include};
if (!$exists) if (!$grp)
{ {
Bugzilla::Group->create($definition); $grp = Bugzilla::Group->create($definition);
if ($include && @$include) }
elsif ($definition->{name} ne 'admin_index')
{
# Always fix inclusions in admin_index
$include = undef;
}
if ($include && @$include)
{
my $cur = { map { $_ => 1 } @{$dbh->selectcol_arrayref(
'SELECT g.name FROM group_group_map gm, groups g'.
' WHERE g.id=gm.member_id AND gm.grantor_id=? AND gm.grant_type=0', undef, $grp->id
) || []} };
$include = [ grep { !$cur->{$_} } @$include ];
if (@$include)
{ {
$dbh->do( $dbh->do(
'INSERT INTO group_group_map (member_id, grantor_id, grant_type)'. 'INSERT INTO group_group_map (member_id, grantor_id, grant_type)'.
' SELECT g.id, ai.id, 0 FROM groups ai, groups g WHERE ai.name=?'. ' SELECT g.id, ?, 0 FROM groups g WHERE g.name IN (\''.join("','", @$include).'\')', undef, $grp->id
' AND g.name IN (\''.join("','", @$include).'\')', undef, $definition->{name}
); );
} }
} }

View File

@ -219,6 +219,7 @@ $Bugzilla::messages->{en} = {
tweakparams => 'Allows to <a href="editparams.cgi">change Parameters</a>.', tweakparams => 'Allows to <a href="editparams.cgi">change Parameters</a>.',
editusers => 'Allows to <a href="editusers.cgi">edit or disable users</a> and include/exclude them from <b>all</b> groups.', editusers => 'Allows to <a href="editusers.cgi">edit or disable users</a> and include/exclude them from <b>all</b> groups.',
creategroups => 'Allows to <a href="editgroups.cgi">create, destroy and edit groups</a>.', creategroups => 'Allows to <a href="editgroups.cgi">create, destroy and edit groups</a>.',
createproducts => 'Allows to <a href="editproducts.cgi">create new products</a>.',
editclassifications => 'Allows to <a href="editclassifications.cgi">create, destroy and edit classifications</a>.', editclassifications => 'Allows to <a href="editclassifications.cgi">create, destroy and edit classifications</a>.',
editcomponents => 'Allows to <a href="editproducts.cgi">create, destroy and edit all products, components, versions and milestones</a>.', editcomponents => 'Allows to <a href="editproducts.cgi">create, destroy and edit all products, components, versions and milestones</a>.',
editkeywords => 'Allows to <a href="editvalues.cgi?field=keywords">create, destroy and edit keywords</a>.', editkeywords => 'Allows to <a href="editvalues.cgi?field=keywords">create, destroy and edit keywords</a>.',

View File

@ -609,15 +609,19 @@ use constant is_default => 0;
sub _create_bug_group sub _create_bug_group
{ {
my $self = shift; my $self = shift;
my ($create_admin_group) = @_;
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my $group_name = $self->name; my $group_name = ($create_admin_group ? 'admin-' : '') . $self->name;
my $i = 1; my $i = 1;
while (new Bugzilla::Group({ name => $group_name })) while (new Bugzilla::Group({ name => $group_name }))
{ {
$group_name = $self->name . ($i++); $group_name = ($create_admin_group ? 'admin-' : '') . $self->name . ($i++);
} }
my $group_description = get_text('bug_group_description', { product => $self }); my $group_description = get_text(
$create_admin_group ? 'admin_group_description' : 'bug_group_description',
{ product => $self }
);
my $group = Bugzilla::Group->create({ my $group = Bugzilla::Group->create({
name => $group_name, name => $group_name,
@ -627,8 +631,15 @@ sub _create_bug_group
# Associate the new group and new product. # Associate the new group and new product.
$dbh->do( $dbh->do(
'INSERT INTO group_control_map (group_id, product_id, membercontrol, othercontrol)'. 'INSERT INTO group_control_map (group_id, product_id, membercontrol, othercontrol, editcomponents)'.
' VALUES (?, ?, ?, ?)', undef, $group->id, $self->id, CONTROLMAPDEFAULT, CONTROLMAPNA ' VALUES (?, ?, ?, ?, ?)', undef, $group->id, $self->id,
($create_admin_group ? (0, 0, 1) : (CONTROLMAPMANDATORY, CONTROLMAPMANDATORY, 0))
);
# Grant current user permission to edit the new group and include him in it
$dbh->do(
'INSERT INTO user_group_map (user_id, group_id, isbless, grant_type) VALUES (?, ?, ?, ?), (?, ?, ?, ?)',
undef, Bugzilla->user->id, $group->id, 1, 0, Bugzilla->user->id, $group->id, 0, 0
); );
} }

View File

@ -653,17 +653,16 @@ sub get_products_by_permission
sub get_editable_products sub get_editable_products
{ {
my ($self, $classification_id) = @_; my ($self, $classification_id) = @_;
my $sql = "SELECT DISTINCT products.id FROM products"; my $sql = "SELECT DISTINCT p.id FROM products p";
my $t = "WHERE";
if (!$self->in_group('editcomponents')) if (!$self->in_group('editcomponents'))
{ {
$sql .= ", group_control_map WHERE editcomponents=1 AND group_id IN (".$self->groups_as_string.")"; $sql .= " INNER JOIN group_control_map gm ON gm.product_id=p.id".
$t = "AND"; " AND gm.editcomponents=1 AND gm.group_id IN (".$self->groups_as_string.")";
} }
if ($classification_id) if ($classification_id)
{ {
# restrict product list by classification # restrict product list by classification
$sql .= " $t classification_id=".int($classification_id); $sql .= " WHERE classification_id=".int($classification_id);
} }
return Bugzilla::Product->new_from_list(Bugzilla->dbh->selectcol_arrayref($sql) || []); return Bugzilla::Product->new_from_list(Bugzilla->dbh->selectcol_arrayref($sql) || []);
} }
@ -971,7 +970,7 @@ sub check_can_admin_product
# First make sure the product name is valid. # First make sure the product name is valid.
my $product = Bugzilla::Product::check_product($product_name); my $product = Bugzilla::Product::check_product($product_name);
($self->in_group('editcomponents', $product->id) && $self->can_see_product($product->name)) $self->in_group('editcomponents', $product->id)
|| $self->in_group('editcomponents') || $self->in_group('editcomponents')
|| ThrowUserError('product_admin_denied', {product => $product->name}); || ThrowUserError('product_admin_denied', {product => $product->name});

View File

@ -1,10 +1,25 @@
== UNRELEASED: beta == == branch: i18n ==
UI improvements: UI improvements:
* Separate localisation layer - now it's possible to translate Bugzilla UI * Separate localisation layer - now it's possible to translate Bugzilla UI
without copying templates! without copying templates!
== UNRELEASED: beta ==
Backports from original Bugzilla:
* WebServices from Bugzilla 5.0.1 (everything except tags).
Other new features:
* Separate "createproducts" role (group) that only allows to create new products,
but not to edit the existing ones.
Bugfixes:
* Whining now works again.
== 2015.09: 2015-09-18, commit dc07c69094f616d1eb3e523181283dcdbca0499e == == 2015.09: 2015-09-18, commit dc07c69094f616d1eb3e523181283dcdbca0499e ==
UI improvements: UI improvements:

View File

@ -50,6 +50,7 @@ my $vars = {};
$vars->{doc_section} = 'products.html'; $vars->{doc_section} = 'products.html';
$user->in_group('editcomponents') || $user->in_group('editcomponents') ||
$user->in_group('createproducts') ||
scalar(@{$user->get_editable_products}) || scalar(@{$user->get_editable_products}) ||
ThrowUserError('auth_failure', { ThrowUserError('auth_failure', {
group => 'editcomponents', group => 'editcomponents',
@ -71,12 +72,12 @@ my $useclassification = Bugzilla->get_field('classification')->enabled;
# classifications enabled) # classifications enabled)
# #
if ($useclassification && !$classification_name && !$product_name) if (!$action && $useclassification && !$classification_name && !$product_name)
{ {
my $class; my $class;
if ($user->in_group('editcomponents')) if ($user->in_group('editcomponents'))
{ {
$class = [Bugzilla::Classification->get_all]; $class = [ Bugzilla::Classification->get_all ];
} }
else else
{ {
@ -84,7 +85,7 @@ if ($useclassification && !$classification_name && !$product_name)
# which you can administer. # which you can administer.
my $products = $user->get_editable_products; my $products = $user->get_editable_products;
my %class_ids = map { $_->classification_id => 1 } @$products; my %class_ids = map { $_->classification_id => 1 } @$products;
$class = Bugzilla::Classification->new_from_list([keys %class_ids]); $class = Bugzilla::Classification->new_from_list([ keys %class_ids ]);
} }
$vars->{classifications} = $class; $vars->{classifications} = $class;
@ -130,18 +131,17 @@ if (!$action && !$product_name)
if ($action eq 'add') if ($action eq 'add')
{ {
# The user must have the global editcomponents privs to add # The user must have the createproducts or global editcomponents privs to add new products.
# new products. $user->in_group('editcomponents') ||
$user->in_group('editcomponents') || ThrowUserError('auth_failure', { $user->in_group('createproducts') ||
group => 'editcomponents', ThrowUserError('auth_failure', {
action => 'add', group => 'editcomponents',
object => 'products', action => 'add',
}); object => 'products',
});
if ($useclassification) if ($useclassification)
{ {
my $classification = Bugzilla::Classification->check($classification_name); $vars->{classification} = $classification_name ? Bugzilla::Classification->new($classification_name) : undef;
$vars->{classification} = $classification;
$vars->{classifications} = [ Bugzilla::Classification->get_all ]; $vars->{classifications} = [ Bugzilla::Classification->get_all ];
} }
$vars->{token} = issue_session_token('add_product'); $vars->{token} = issue_session_token('add_product');
@ -159,13 +159,14 @@ if ($action eq 'add')
if ($action eq 'new') if ($action eq 'new')
{ {
# The user must have the global editcomponents privs to add # The user must have the createproducts or global editcomponents privs to add new products.
# new products. $user->in_group('editcomponents') ||
$user->in_group('editcomponents') || ThrowUserError('auth_failure', { $user->in_group('createproducts') ||
group => 'editcomponents', ThrowUserError('auth_failure', {
action => 'add', group => 'editcomponents',
object => 'products', action => 'add',
}); object => 'products',
});
check_token_data($token, 'add_product'); check_token_data($token, 'add_product');
@ -190,6 +191,13 @@ if ($action eq 'new')
} }
my $product = Bugzilla::Product->create(\%create_params); my $product = Bugzilla::Product->create(\%create_params);
if (!$user->in_group('editcomponents'))
{
# User has no global editcomponents permission, so grant 'createproducts'
# group the right to manage his newly created product
$product->_create_bug_group(1);
}
# Create groups and series for the new product, if requested. # Create groups and series for the new product, if requested.
$product->_create_bug_group() if $ARGS->{makeproductgroup}; $product->_create_bug_group() if $ARGS->{makeproductgroup};
$product->_create_series() if $ARGS->{createseries}; $product->_create_series() if $ARGS->{createseries};

View File

@ -51,7 +51,7 @@
] ]
%] %]
[% IF user.in_group('editcomponents') %] [% IF user.in_group('editcomponents') || user.in_group('createproducts') %]
[% columns.push({ [% columns.push({
heading => "Action..." heading => "Action..."
content => "Add product" content => "Add product"
@ -64,6 +64,10 @@
data = classifications data = classifications
%] %]
[% IF user.in_group('createproducts') && !user.in_group('editcomponents') %]
<p><a href="editproducts.cgi?action=add">Add product</a></p>
[% END %]
[%# No need for the standard edit products footer, as we have an 'add' [%# No need for the standard edit products footer, as we have an 'add'
link in the table %] link in the table %]

View File

@ -251,6 +251,10 @@
Access to [% terms.bugs %] in the [% product.name | html %] product Access to [% terms.bugs %] in the [% product.name | html %] product
[% END %] [% END %]
[% BLOCK msg_admin_group_description %]
Administration of the [% product.name | html %] product
[% END %]
[% BLOCK msg_buglist_adding_field %] [% BLOCK msg_buglist_adding_field %]
[% title = "Adding field to search page..." %] [% title = "Adding field to search page..." %]
[% link = "Click here if the page does not redisplay automatically." %] [% link = "Click here if the page does not redisplay automatically." %]