Commit c64d5111 authored by bugreport%peshkin.net's avatar bugreport%peshkin.net

Bug 147275 Rearchitect product groups

Patch by joel r=bbaetz,justdave a=justdave
parent e7720dcd
......@@ -167,6 +167,16 @@ sub UpdateParams {
delete $param{'usequip'};
}
# Change from old product groups to controls for group_control_map
# 2002-10-14 bug 147275 bugreport@peshkin.net
if (exists $param{'usebuggroups'} && !exists $param{'makeproductgroups'}) {
$param{'makeproductgroups'} = $param{'usebuggroups'};
}
if (exists $param{'usebuggroupsentry'}
&& !exists $param{'useentrygroupdefault'}) {
$param{'useentrygroupdefault'} = $param{'usebuggroupsentry'};
}
# --- DEFAULTS FOR NEW PARAMS ---
foreach my $item (@param_list) {
......
# -*- 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 Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
# Dawn Endico <endico@mozilla.org>
# Dan Mosedale <dmose@mozilla.org>
# Joe Robins <jmrobins@tgix.com>
# Jake <jake@bugzilla.org>
# J. Paul Reed <preed@sigkill.com>
# Bradley Baetz <bbaetz@student.usyd.edu.au>
# Christopher Aillon <christopher@aillon.com>
package Bugzilla::Constants;
use strict;
use base qw(Exporter);
@Bugzilla::Constants::EXPORT = qw(
CONTROLMAPNA
CONTROLMAPSHOWN
CONTROLMAPDEFAULT
CONTROLMAPMANDATORY
);
# CONSTANTS
#
# ControlMap constants for group_control_map.
# membercontol:othercontrol => meaning
# Na:Na => Bugs in this product may not be restricted to this
# group.
# Shown:Na => Members of the group may restrict bugs
# in this product to this group.
# Shown:Shown => Members of the group may restrict bugs
# in this product to this group.
# Anyone who can enter bugs in this product may initially
# restrict bugs in this product to this group.
# Shown:Mandatory => Members of the group may restrict bugs
# in this product to this group.
# Non-members who can enter bug in this product
# will be forced to restrict it.
# Default:Na => Members of the group may restrict bugs in this
# product to this group and do so by default.
# Default:Default => Members of the group may restrict bugs in this
# product to this group and do so by default and
# nonmembers have this option on entry.
# Default:Mandatory => Members of the group may restrict bugs in this
# product to this group and do so by default.
# Non-members who can enter bug in this product
# will be forced to restrict it.
# Mandatory:Mandatory => Bug will be forced into this group regardless.
# All other combinations are illegal.
use constant CONTROLMAPNA => 0;
use constant CONTROLMAPSHOWN => 1;
use constant CONTROLMAPDEFAULT => 2;
use constant CONTROLMAPMANDATORY => 3;
1;
......@@ -24,7 +24,7 @@
use strict;
use RelationSet;
use Bugzilla::Constants;
# Use the Attachment module to display attachments for the bug.
use Attachment;
......@@ -144,12 +144,9 @@ sub show_bug {
next;
}
if (Param("usebuggroupsentry")
&& GroupExists($product)
&& !UserInGroup($product))
{
if (!CanEnterProduct($product)) {
# If we're using bug groups to restrict entry on products, and
# this product has a bug group, and the user is not in that
# this product has an entry group, and the user is not in that
# group, we don't want to include that product in this list.
next;
}
......@@ -275,7 +272,7 @@ sub show_bug {
SendSQL("SELECT DISTINCT groups.id, name, description," .
" bug_group_map.group_id IS NOT NULL," .
" user_group_map.group_id IS NOT NULL," .
" isactive" .
" isactive, membercontrol, othercontrol" .
" FROM groups" .
" LEFT JOIN bug_group_map" .
" ON bug_group_map.group_id = groups.id" .
......@@ -284,33 +281,48 @@ sub show_bug {
" ON user_group_map.group_id = groups.id" .
" AND user_id = $::userid" .
" AND NOT isbless" .
" LEFT JOIN group_control_map" .
" ON group_control_map.group_id = groups.id" .
" AND group_control_map.product_id = " . $bug{'product_id'} .
" WHERE isbuggroup");
$user{'inallgroups'} = 1;
while (MoreSQLData()) {
my ($groupid, $name, $description, $ison, $ingroup, $isactive)
= FetchSQLData();
my ($groupid, $name, $description, $ison, $ingroup, $isactive,
$membercontrol, $othercontrol) = FetchSQLData();
$bug{'inagroup'} = 1 if ($ison);
$membercontrol ||= 0;
if ($isactive && ($membercontrol == CONTROLMAPMANDATORY)) {
$bug{'inagroup'} = 1;
}
# For product groups, we only want to display the checkbox if either
# (1) The bit is already set, or
# (2) The user is in the group, but either:
# (a) The group is a product group for the current product, or
# (b) The group name isn't a product name
# This means that all product groups will be skipped, but
# non-product bug groups will still be displayed.
if($ison ||
($isactive && ($ingroup && (!Param("usebuggroups") || ($name eq $bug{'product'}) ||
(!defined $::proddesc{$name})))))
# (1) The bit is set and not required, or
# (2) The group is Shown or Default for members and
# the user is a member of the group.
if ($ison ||
($isactive && $ingroup
&& (($membercontrol == CONTROLMAPDEFAULT)
|| ($membercontrol == CONTROLMAPSHOWN))
))
{
$user{'inallgroups'} &= $ingroup;
push (@groups, { "bit" => $groupid,
"ison" => $ison,
"ingroup" => $ingroup,
"description" => $description });
my $mandatory;
if ($isactive && ($membercontrol == CONTROLMAPMANDATORY)) {
$mandatory = 1;
} else {
$mandatory = 0;
}
if (($ison) || ($ingroup)) {
push (@groups, { "bit" => $groupid,
"ison" => $ison,
"ingroup" => $ingroup,
"mandatory" => $mandatory,
"description" => $description });
}
}
}
......
......@@ -728,7 +728,6 @@ $vars->{'order'} = $order;
my $login = $::COOKIE{'Bugzilla_login'};
$vars->{'caneditbugs'} = UserInGroup('editbugs');
$vars->{'usebuggroups'} = Param('usebuggroups');
# Whether or not this user is authorized to move bugs to another installation.
$vars->{'ismover'} = 1
......
......@@ -112,6 +112,7 @@
use strict;
use vars qw( $db_name %answer );
use Bugzilla::Constants;
###########################################################################
# Non-interactive override
......@@ -1716,6 +1717,17 @@ $table{quips} =
userid mediumint not null default 0,
quip text not null';
$table{group_control_map} =
'group_id mediumint not null,
product_id mediumint not null,
entry tinyint not null,
membercontrol tinyint not null,
othercontrol tinyint not null,
canedit tinyint not null,
unique(product_id, group_id),
index(group_id)';
###########################################################################
# Create tables
###########################################################################
......@@ -2954,7 +2966,7 @@ if (GetFieldDef("logincookies", "hostname")) {
AddField("logincookies", "ipaddr", "varchar(40) NOT NULL");
}
# 2002-05-10 - enhanchment bug 143826
# 2002-08-19 - bugreport@peshkin.net bug 143826
# Add private comments and private attachments on less-private bugs
AddField('longdescs', 'isprivate', 'tinyint not null default 0');
AddField('attachments', 'isprivate', 'tinyint not null default 0');
......@@ -3121,7 +3133,7 @@ if (($fielddef = GetFieldDef("attachments", "creation_ts")) &&
ChangeFieldType("attachments", "creation_ts", "datetime NOT NULL");
}
# 2002-08-XX - bugreport@peshkin.net - bug 157756
# 2002-09-22 - bugreport@peshkin.net - bug 157756
#
# If the whole groups system is new, but the installation isn't,
# convert all the old groupset groups, etc...
......@@ -3464,6 +3476,54 @@ if (TableExists("attachstatuses") && TableExists("attachstatusdefs")) {
print "done.\n";
}
# 2002-11-24 - bugreport@peshkin.net - bug 147275
#
if (Param('makeproductgroups')) {
# If makeproductgroups is enabled and group_control_map is empty,
# backward-compatbility usebuggroups-equivalent records should
# be created.
my $entry = Param('useentrygroupdefault');
$sth = $dbh->prepare("SELECT COUNT(*) FROM group_control_map");
$sth->execute();
my ($mapcnt) = $sth->fetchrow_array();
if ($mapcnt == 0) {
# Initially populate group_control_map.
# First, get all the existing products and their groups.
$sth = $dbh->prepare("SELECT groups.id, products.id, groups.name, " .
"products.name FROM groups, products " .
"WHERE isbuggroup != 0 AND isactive != 0");
$sth->execute();
while (my ($groupid, $productid, $groupname, $productname)
= $sth->fetchrow_array()) {
if ($groupname eq $productname) {
# Product and group have same name.
$dbh->do("INSERT INTO group_control_map " .
"(group_id, product_id, entry, membercontrol, " .
"othercontrol, canedit) " .
"VALUES ($groupid, $productid, $entry, " .
CONTROLMAPDEFAULT . ", " .
CONTROLMAPNA . ", 0)");
} else {
# See if this group is a product group at all.
my $sth2 = $dbh->prepare("SELECT id FROM products WHERE name = " .
$dbh->quote($groupname));
$sth2->execute();
my ($id) = $sth2->fetchrow_array();
if (!$id) {
# If there is no product with the same name as this
# group, then it is permitted for all products.
$dbh->do("INSERT INTO group_control_map " .
"(group_id, product_id, entry, membercontrol, " .
"othercontrol, canedit) " .
"VALUES ($groupid, $productid, 0, " .
CONTROLMAPSHOWN . ", " .
CONTROLMAPNA . ", 0)");
}
}
}
}
}
# If you had to change the --TABLE-- definition in any way, then add your
# differential change code *** A B O V E *** this comment.
#
......@@ -3793,3 +3853,4 @@ $dbh->do("UPDATE components SET initialowner = $adminuid WHERE initialowner = 0"
unlink "data/versioncache";
print "Reminder: Bugzilla now requires version 8.7 or later of sendmail.\n" unless $silent;
......@@ -244,7 +244,7 @@ sub check_netmask {
},
{
name => 'usebuggroups',
name => 'makeproductgroups',
desc => 'If this is on, Bugzilla will associate a bug group with each ' .
'product in the database, and use it for querying bugs.',
type => 'b',
......@@ -252,9 +252,9 @@ sub check_netmask {
},
{
name => 'usebuggroupsentry',
name => 'useentrygroupdefault',
desc => 'If this is on, Bugzilla will use product bug groups to restrict ' .
'who can enter bugs. Requires usebuggroups to be on as well.',
'who can enter bugs. Requires makeproductgroups to be on as well.',
type => 'b',
default => 0
},
......
......@@ -42,11 +42,11 @@ if (!defined $::FORM{'product'}) {
# Reference to a subset of %::proddesc, which the user is allowed to see
my %products;
if (Param("usebuggroups")) {
if (AnyDefaultGroups()) {
# OK, now only add products the user can see
confirm_login() unless $::userid;
foreach my $p (@::legal_product) {
if (!GroupExists($p) || UserInGroup($p)) {
if (CanEnterProduct($p)) {
$products{$p} = $::proddesc{$p};
}
}
......@@ -88,11 +88,8 @@ if (!$product_id) {
}
# Make sure the user is authorized to access this product.
if (Param("usebuggroups") && GroupExists($product)) {
confirm_login() unless $::userid;
UserInGroup($product)
CanEnterProduct($product)
|| ThrowUserError("product_access_denied");
}
######################################################################
# End Data/Security Validation
......
......@@ -27,6 +27,7 @@
use strict;
use lib ".";
use Bugzilla::Constants;
require "CGI.pl";
ConnectToDatabase();
......@@ -117,9 +118,9 @@ unless ($action) {
while (MoreSQLData()) {
my ($groupid, $name, $desc, $regexp, $isactive, $isbuggroup) = FetchSQLData();
print "<tr>\n";
print "<td>$name</td>\n";
print "<td>$desc</td>\n";
print "<td>$regexp&nbsp</td>\n";
print "<td>" . html_quote($name) . "</td>\n";
print "<td>" . html_quote($desc) . "</td>\n";
print "<td>" . html_quote($regexp) . "&nbsp</td>\n";
print "<td align=center>";
print "X" if (($isactive != 0) && ($isbuggroup != 0));
print "&nbsp</td>\n";
......@@ -185,22 +186,27 @@ if ($action eq 'changeform') {
print "<TABLE BORDER=1 CELLPADDING=4>";
print "<TR><TH>Group:</TH><TD>";
if ($isbuggroup == 0) {
print "$name";
print html_quote($name);
} else {
print "<INPUT TYPE=HIDDEN NAME=\"oldname\" VALUE=$name>
<INPUT SIZE=60 NAME=\"name\" VALUE=\"$name\">";
print "<INPUT TYPE=HIDDEN NAME=\"oldname\" VALUE=" .
html_quote($name) . ">
<INPUT SIZE=60 NAME=\"name\" VALUE=\"" . html_quote($name) . "\">";
}
print "</TD></TR><TR><TH>Description:</TH><TD>";
if ($isbuggroup == 0) {
print "$description";
print html_quote($description);
} else {
print "<INPUT TYPE=HIDDEN NAME=\"olddesc\" VALUE=\"$description\">
<INPUT SIZE=70 NAME=\"desc\" VALUE=\"$description\">";
print "<INPUT TYPE=HIDDEN NAME=\"olddesc\" VALUE=\"" .
html_quote($description) . "\">
<INPUT SIZE=70 NAME=\"desc\" VALUE=\"" .
html_quote($description) . "\">";
}
print "</TD></TR><TR>
<TH>User Regexp:</TH><TD>";
print "<INPUT TYPE=HIDDEN NAME=\"oldrexp\" VALUE=\"$rexp\">
<INPUT SIZE=40 NAME=\"rexp\" VALUE=\"$rexp\"></TD></TR>";
print "<INPUT TYPE=HIDDEN NAME=\"oldrexp\" VALUE=\"" .
html_quote($rexp) . "\">
<INPUT SIZE=40 NAME=\"rexp\" VALUE=\"" .
html_quote($rexp) . "\"></TD></TR>";
if ($isbuggroup == 1) {
print "<TR><TH>Use For Bugs:</TH><TD>
<INPUT TYPE=checkbox NAME =\"isactive\" VALUE=1 " . (($isactive == 1) ? "CHECKED" : "") . ">
......@@ -252,8 +258,8 @@ if ($action eq 'changeform') {
print "<INPUT TYPE=HIDDEN NAME=\"oldbless-$grpid\" VALUE=$blessmember></TD>";
print "<TD><INPUT TYPE=checkbox NAME=\"grp-$grpid\" $grpchecked VALUE=1>";
print "<INPUT TYPE=HIDDEN NAME=\"oldgrp-$grpid\" VALUE=$grpmember></TD>";
print "<TD><B>$grpnam</B></TD>";
print "<TD>$grpdesc</TD>";
print "<TD><B>" . html_quote($grpnam) . "</B></TD>";
print "<TD>" . html_quote($grpdesc) . "</TD>";
print "</TR>\n";
}
......@@ -290,6 +296,10 @@ if ($action eq 'add') {
print "<td><input size=30 name=\"regexp\"></td>\n";
print "<td><input type=\"checkbox\" name=\"isactive\" value=\"1\" checked></td>\n";
print "</TR></TABLE>\n<HR>\n";
print "<input type=\"checkbox\" name=\"insertnew\" value=\"1\"";
print " checked" if Param("makeproductgroups");
print ">\n";
print "Insert new group into all existing products.<P>\n";
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
print "</FORM>";
......@@ -308,9 +318,13 @@ to this group, although bugs already in the group will remain in the group.
Doing so is a much less drastic way to stop a group from growing
than deleting the group would be. <b>Note: If you are creating a group, you
probably want it to be usable for bugs, in which case you should leave this checked.</b><p>";
print "<b>User RegExp</b> is optional, and if filled in, will automatically
grant membership to this group to anyone creating a new account with an
email address that matches this regular expression.<p>";
print "<b>User RegExp</b> is optional, and if filled in, will ";
print "automatically grant membership to this group to anyone with an ";
print "email address that matches this regular expression.<p>\n";
print "By default, the new group will be associated with existing ";
print "products. Unchecking the \"Insert new group into all existing ";
print "products\" option will prevent this and make the group become ";
print "visible only when its controls have been added to a product.<P>\n";
PutTrailer("<a href=editgroups.cgi>Back to the group list</a>");
exit;
......@@ -384,6 +398,16 @@ if ($action eq 'new') {
VALUES ($admin, $gid, 0)");
SendSQL("INSERT INTO group_group_map (member_id, grantor_id, isbless)
VALUES ($admin, $gid, 1)");
# Permit all existing products to use the new group if makeproductgroups.
if ($::FORM{insertnew}) {
SendSQL("INSERT INTO group_control_map " .
"(group_id, product_id, entry, membercontrol, " .
"othercontrol, canedit) " .
"SELECT $gid, products.id, 0, " .
CONTROLMAPSHOWN . ", " .
CONTROLMAPNA . ", 0 " .
"FROM products");
}
print "OK, done.<p>\n";
PutTrailer("<a href=\"editgroups.cgi?action=add\">Add another group</a>",
"<a href=\"editgroups.cgi\">Back to the group list</a>");
......@@ -543,6 +567,7 @@ if ($action eq 'delete') {
SendSQL("DELETE FROM user_group_map WHERE group_id = $gid");
SendSQL("DELETE FROM group_group_map WHERE grantor_id = $gid");
SendSQL("DELETE FROM bug_group_map WHERE group_id = $gid");
SendSQL("DELETE FROM group_control_map WHERE group_id = $gid");
SendSQL("DELETE FROM groups WHERE id = $gid");
print "<B>Group $gid has been deleted.</B><BR>";
......
......@@ -36,6 +36,7 @@ use strict;
use lib qw(.);
use Bugzilla::Constants;
require "CGI.pl";
use vars qw(
......@@ -51,6 +52,7 @@ use vars qw(
$userid
%MFORM
%versions
$proddesc
);
# We have to connect to the database, even though we don't use it in this code,
......@@ -60,7 +62,7 @@ ConnectToDatabase();
# If we're using bug groups to restrict bug entry, we need to know who the
# user is right from the start.
confirm_login() if (Param("usebuggroupsentry"));
confirm_login() if AnyEntryGroups();
if (!defined $::FORM{'product'}) {
GetVersionTable();
......@@ -69,9 +71,7 @@ if (!defined $::FORM{'product'}) {
my %products;
foreach my $p (@enterable_products) {
if (!(Param("usebuggroupsentry")
&& GroupExists($p)
&& !UserInGroup($p)))
if (CanEnterProduct($p))
{
$products{$p} = $::proddesc{$p};
}
......@@ -215,13 +215,11 @@ sub pickos {
# End of subroutines
##############################################################################
confirm_login() if (!(Param("usebuggroupsentry")));
confirm_login() if (!(AnyEntryGroups()));
# If the usebuggroupsentry parameter is set, we need to check and make sure
# We need to check and make sure
# that the user has permission to enter a bug against this product.
if(Param("usebuggroupsentry")
&& GroupExists($product)
&& !UserInGroup($product))
if(!CanEnterProduct($product))
{
ThrowUserError("entry_access_denied", { product => $product});
}
......@@ -309,30 +307,25 @@ if (UserInGroup("editbugs") || UserInGroup("canconfirm")) {
$vars->{'bug_status'} = \@status;
$default{'bug_status'} = $status[0];
# Select whether to restrict this bug to the product's bug group or not,
# if the usebuggroups parameter is set, and if this product has a bug group.
# First we get the bit and description for the group.
my $group_id = '0';
if(Param("usebuggroups")) {
($group_id) = GroupExists($product);
}
SendSQL("SELECT DISTINCT groups.id, groups.name, groups.description " .
"FROM groups, user_group_map " .
"WHERE user_group_map.group_id = groups.id " .
"AND user_group_map.user_id = $::userid " .
"AND isbless = 0 " .
"AND isbuggroup = 1 AND isactive = 1 ORDER BY description");
SendSQL("SELECT DISTINCT groups.id, groups.name, groups.description, " .
"membercontrol, othercontrol " .
"FROM groups LEFT JOIN group_control_map " .
"ON group_id = id AND product_id = $product_id " .
"WHERE isbuggroup != 0 AND isactive != 0 ORDER BY description");
my @groups;
while (MoreSQLData()) {
my ($id, $prodname, $description) = FetchSQLData();
# Don't want to include product groups other than this product.
next unless(!Param("usebuggroups") || $prodname eq $product ||
!defined($::proddesc{$prodname}));
my ($id, $groupname, $description, $membercontrol, $othercontrol)
= FetchSQLData();
# Only include groups if the entering user will have an option.
next if ((!$membercontrol)
|| ($membercontrol == CONTROLMAPNA)
|| ($membercontrol == CONTROLMAPMANDATORY)
|| (($othercontrol != CONTROLMAPSHOWN)
&& ($othercontrol != CONTROLMAPDEFAULT)
&& (!UserInGroup($groupname)))
);
my $check;
# If this is the group for this product, make it checked.
......@@ -343,11 +336,10 @@ while (MoreSQLData()) {
$check = formvalue("bit-$id", 0);
}
else {
# $group_bit will only have a non-zero value if we're using
# bug groups and have one for this product.
# If $group_bit is 0, it won't match the current group, so compare
# it to the current bit instead of checking for non-zero.
$check = ($group_id == $id);
# Checkbox is checked by default if $control is a default state.
$check = (($membercontrol == CONTROLMAPDEFAULT)
|| (($othercontrol == CONTROLMAPDEFAULT)
&& (!UserInGroup($groupname))));
}
my $group =
......
......@@ -28,6 +28,7 @@
use strict;
use Bugzilla::Constants;
use Bugzilla::Util;
# Bring ChmodDataFile in until this is all moved to the module
use Bugzilla::Config qw(:DEFAULT ChmodDataFile);
......@@ -684,6 +685,116 @@ sub GenerateRandomPassword {
return $password;
}
#
# This function checks if there are any entry groups defined.
# If called with no arguments, it identifies
# entry groups for all products. If called with a product
# id argument, it checks for entry groups associated with
# one particular product.
sub AnyEntryGroups {
my $product_id = shift;
$product_id = 0 unless ($product_id);
return $::CachedAnyEntryGroups{$product_id}
if defined($::CachedAnyEntryGroups{$product_id});
PushGlobalSQLState();
my $query = "SELECT 1 FROM group_control_map WHERE entry != 0";
$query .= " AND product_id = $product_id" if ($product_id);
$query .= " LIMIT 1";
SendSQL($query);
$::CachedAnyEntryGroups{$product_id} = MoreSQLData();
FetchSQLData();
PopGlobalSQLState();
return $::CachedAnyEntryGroups{$product_id};
}
#
# This function checks if there are any default groups defined.
# If so, then groups may have to be changed when bugs move from
# one bug to another.
sub AnyDefaultGroups {
return $::CachedAnyDefaultGroups if defined($::CachedAnyDefaultGroups);
PushGlobalSQLState();
SendSQL("SELECT 1 FROM group_control_map, groups WHERE " .
"groups.id = group_control_map.group_id " .
"AND isactive != 0 AND " .
"(membercontrol = " . CONTROLMAPDEFAULT .
" OR othercontrol = " . CONTROLMAPDEFAULT .
") LIMIT 1");
$::CachedAnyDefaultGroups = MoreSQLData();
FetchSQLData();
PopGlobalSQLState();
return $::CachedAnyDefaultGroups;
}
#
# This function checks if, given a product id, the user can edit
# bugs in this product at all.
sub CanEditProductId {
my ($productid) = @_;
my $query = "SELECT group_id FROM group_control_map " .
"WHERE product_id = $productid " .
"AND canedit != 0 ";
if ((defined @{$::vars->{user}{groupids}})
&& (@{$::vars->{user}{groupids}} > 0)) {
$query .= "AND group_id NOT IN(" .
join(',',@{$::vars->{user}{groupids}}) . ") ";
}
$query .= "LIMIT 1";
PushGlobalSQLState();
SendSQL($query);
my ($result) = FetchSQLData();
PopGlobalSQLState();
return (!defined($result));
}
#
# This function determines if a user can enter bugs in the named
# product.
sub CanEnterProduct {
my ($productname) = @_;
my $query = "SELECT group_id IS NULL " .
"FROM products " .
"LEFT JOIN group_control_map " .
"ON group_control_map.product_id = products.id " .
"AND group_control_map.entry != 0 ";
if ((defined @{$::vars->{user}{groupids}})
&& (@{$::vars->{user}{groupids}} > 0)) {
$query .= "AND group_id NOT IN(" .
join(',',@{$::vars->{user}{groupids}}) . ") ";
}
$query .= "WHERE products.name = " . SqlQuote($productname) . " LIMIT 1";
PushGlobalSQLState();
SendSQL($query);
my ($ret) = FetchSQLData();
PopGlobalSQLState();
return ($ret);
}
#
# This function returns an alphabetical list of product names to which
# the user can enter bugs.
sub GetEnterableProducts {
my $query = "SELECT name " .
"FROM products " .
"LEFT JOIN group_control_map " .
"ON group_control_map.product_id = products.id " .
"AND group_control_map.entry != 0 ";
if ((defined @{$::vars->{user}{groupids}})
&& (@{$::vars->{user}{groupids}} > 0)) {
$query .= "AND group_id NOT IN(" .
join(',',@{$::vars->{user}{groupids}}) . ") ";
}
$query .= "WHERE group_id IS NULL ORDER BY name";
PushGlobalSQLState();
SendSQL($query);
my @products = ();
while (MoreSQLData()) {
push @products,FetchOneColumn();
}
PopGlobalSQLState();
return (@products);
}
sub CanSeeBug {
my ($id, $userid) = @_;
......@@ -1749,5 +1860,5 @@ $::vars =
'VERSION' => $Bugzilla::Config::VERSION,
};
1;
......@@ -26,6 +26,7 @@
use strict;
use lib qw(.);
use Bugzilla::Constants;
require "CGI.pl";
require "bug_form.pl";
......@@ -101,9 +102,8 @@ if (defined $::FORM{'maketemplate'}) {
umask 0;
# Some sanity checking
if(Param("usebuggroupsentry") && GroupExists($product)) {
UserInGroup($product) ||
ThrowUserError("entry_access_denied", {product => $product});
if (!CanEnterProduct($product)) {
ThrowUserError("entry_access_denied", {product => $product});
}
my $component_id = get_component_id($product_id, $::FORM{component});
......@@ -363,13 +363,38 @@ foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
WHERE user_id = $::userid
AND group_id = $v
AND isbless = 0");
my ($member) = FetchSQLData();
if ($member) {
my ($permit) = FetchSQLData();
if (!$permit) {
SendSQL("SELECT othercontrol FROM group_control_map
WHERE group_id = $v AND product_id = $product_id");
my ($othercontrol) = FetchSQLData();
$permit = (($othercontrol == CONTROLMAPSHOWN)
|| ($othercontrol == CONTROLMAPDEFAULT));
}
if ($permit) {
push(@groupstoadd, $v)
}
}
}
SendSQL("SELECT DISTINCT groups.id, groups.name, " .
"membercontrol, othercontrol " .
"FROM groups LEFT JOIN group_control_map " .
"ON group_id = id AND product_id = $product_id " .
" WHERE isbuggroup != 0 AND isactive != 0 ORDER BY description");
while (MoreSQLData()) {
my ($id, $groupname, $membercontrol, $othercontrol ) = FetchSQLData();
$membercontrol ||= 0;
$othercontrol ||= 0;
# Add groups required
if (($membercontrol == CONTROLMAPMANDATORY)
|| (($othercontrol == CONTROLMAPMANDATORY)
&& (!UserInGroup($groupname)))) {
# User had no option, bug needs to be in this group.
push(@groupstoadd, $id)
}
}
# Lock tables before inserting records for the new bug into the database
# if we are using a shadow database to prevent shadow database corruption
......
......@@ -191,19 +191,14 @@ if ($default{'chfieldto'}->[0] eq "") {
GetVersionTable();
# if using usebuggroups, then we don't want people to see products they don't
# have access to. Remove them from the list.
# if using groups for entry, then we don't want people to see products they
# don't have access to. Remove them from the list.
my @products = ();
my %component_set;
my %version_set;
my %milestone_set;
foreach my $p (@::legal_product) {
# If we're using bug groups to restrict entry on products, and
# this product has a bug group, and the user is not in that
# group, we don't want to include that product in this list.
next if (Param("usebuggroups") && GroupExists($p) && !UserInGroup($p));
foreach my $p (GetEnterableProducts()) {
# We build up boolean hashes in the "-set" hashes for each of these things
# before making a list because there may be duplicates names across products.
push @products, $p;
......
......@@ -663,7 +663,7 @@ SendSQL("SELECT name, description FROM products ORDER BY name");
while (MoreSQLData()) {
my ($product, $productdesc) = FetchSQLData();
next if (Param("usebuggroups") && GroupExists($product) && !UserInGroup($product));
next if (!CanEnterProduct($product));
push (@products, $product);
$line_count++;
......
......@@ -23,8 +23,6 @@
# Dawn Endico <endico@mozilla.org>
# Bryce Nesbitt <bryce@nextbus.COM>,
# Joe Robins <jmrobins@tgix.com>,
# If using the usebuggroups parameter, users shouldn't be able to see
# reports for products they don't have access to.
# Gervase Markham <gerv@gerv.net> and Adam Spiers <adam@spiers.net>
# Added ability to chart any combination of resolutions/statuses.
# Derive the choice of resolutions/statuses from the -All- data file
......@@ -60,20 +58,11 @@ quietly_check_login();
GetVersionTable();
# If the usebuggroups parameter is set, we don't want to list all products.
# We only want those products that the user has permissions for.
my @myproducts;
if(Param("usebuggroups")) {
push( @myproducts, "-All-");
foreach my $this_product (@legal_product) {
if(GroupExists($this_product) && !UserInGroup($this_product)) {
next;
} else {
push( @myproducts, $this_product )
}
}
} else {
push( @myproducts, "-All-", @legal_product );
push( @myproducts, "-All-");
foreach my $this_product (@legal_product) {
push(@myproducts, $this_product) if CanEnterProduct($this_product);
}
if (! defined $FORM{'product'}) {
......@@ -91,12 +80,11 @@ if (! defined $FORM{'product'}) {
grep($_ eq $FORM{'product'}, @myproducts)
|| ThrowUserError("invalid_product_name", {product => $FORM{'product'}});
# If usebuggroups is on, we don't want people to be able to view
# We don't want people to be able to view
# reports for products they don't have permissions for...
Param("usebuggroups")
&& GroupExists($FORM{'product'})
&& !UserInGroup($FORM{'product'})
&& ThrowUserError("report_access_denied");
if (!CanEnterProduct($FORM{'product'})) {
ThrowUserError("report_access_denied");
}
# We've checked that the product exists, and that the user can see it
# This means that is OK to detaint
......
......@@ -26,6 +26,7 @@ use strict;
use lib qw(.);
require "CGI.pl";
use Bugzilla::Constants;
use vars qw(%FORM $unconfirmedstate);
......@@ -263,6 +264,7 @@ CrossCheck("groups", "id",
["bug_group_map", "group_id"],
["group_group_map", "grantor_id"],
["group_group_map", "member_id"],
["group_control_map", "group_id"],
["user_group_map", "group_id"]);
CrossCheck("profiles", "userid",
......@@ -288,6 +290,7 @@ CrossCheck("products", "id",
["components", "product_id", "name"],
["milestones", "product_id", "value"],
["versions", "product_id", "value"],
["group_control_map", "product_id"],
["flaginclusions", "product_id", "type_id"],
["flagexclusions", "product_id", "type_id"]);
......@@ -613,6 +616,53 @@ DateCheck("groups", "last_changed");
DateCheck("profiles", "refreshed_when");
###########################################################################
# Control Values
###########################################################################
# Checks for values that are invalid OR
# not among the 9 valid combinations
Status("Checking for bad values in group_control_map");
SendSQL("SELECT COUNT(product_id) FROM group_control_map WHERE " .
"membercontrol NOT IN(" . CONTROLMAPNA . "," . CONTROLMAPSHOWN .
"," . CONTROLMAPDEFAULT . "," . CONTROLMAPMANDATORY . ")" .
" OR " .
"othercontrol NOT IN(" . CONTROLMAPNA . "," . CONTROLMAPSHOWN .
"," . CONTROLMAPDEFAULT . "," . CONTROLMAPMANDATORY . ")" .
" OR " .
"( (membercontrol != othercontrol) " .
"AND (membercontrol != " . CONTROLMAPSHOWN . ") " .
"AND ((membercontrol != " . CONTROLMAPDEFAULT . ") " .
"OR (othercontrol = " . CONTROLMAPSHOWN . ")))");
my $c = FetchOneColumn();
if ($c) {
Alert("Found $c bad group_control_map entries");
}
Status("Checking for bugs with groups violating their product's group controls");
BugCheck("bugs, groups, bug_group_map
LEFT JOIN group_control_map
ON group_control_map.product_id = bugs.product_id
AND group_control_map.group_id = bug_group_map.group_id
WHERE bugs.bug_id = bug_group_map.bug_id
AND bug_group_map.group_id = groups.id
AND groups.isactive != 0
AND ((group_control_map.membercontrol = " . CONTROLMAPNA . ")
OR (group_control_map.membercontrol IS NULL))",
"Have groups not permitted for their products");
BugCheck("bugs, groups, group_control_map
LEFT JOIN bug_group_map
ON group_control_map.group_id = bug_group_map.group_id
AND bugs.bug_id = bug_group_map.bug_id
WHERE group_control_map.product_id = bugs.product_id
AND bug_group_map.group_id = groups.id
AND groups.isactive != 0
AND group_control_map.membercontrol = " . CONTROLMAPMANDATORY . "
AND bug_group_map.group_id IS NULL",
"Are missing groups required for their products");
###########################################################################
# Unsent mail
###########################################################################
......
<!-- 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 Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Joel Peshkin <bugreport@peshkin.net>
#
#%]
[% PROCESS global/header.html.tmpl title="Confirm Group Control Change for product \'$product\'" %]
[% FOREACH group = mandatory_groups %]
<P>
group '[% group.name FILTER html %]' impacts [% group.count %] bugs for which the group is
newly mandatory and will be added.
[% END %]
[% FOREACH group = na_groups %]
<P>
group '[% group.name FILTER html %]' impacts [% group.count %] bugs for which the group is no longer applicable and will be removed.
[% END %]
<form method="post" >
[% PROCESS "global/hidden-fields.html.tmpl" exclude="^(Bugzilla|LDAP)_(login|password)$" %]
<br>
Click "Continue" to proceed with the change including the changes
indicated above. If you do not want these changes, use "back" to
return to the previous page.
<p>
<input type="hidden" name="confirmed" value="confirmed">
<input type="submit" value="Continue">
</p>
</form>
[% PROCESS global/footer.html.tmpl %]
<!-- 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 Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Joel Peshkin <bugreport@peshkin.net>
#%]
[% filt_product = product FILTER html %]
[% PROCESS global/header.html.tmpl
title = "Edit Group Controls for '$filt_product'"
%]
<form method="post" action="editproducts.cgi">
<input type="hidden" name="action" value="updategroupcontrols">
<input type="hidden" name="product" value="[% filt_product %]">
<table id="form" cellspacing="0" cellpadding="4" border="1">
<tr bgcolor="#6666ff">
<th>Group</th>
<th>Entry</th>
<th>MemberControl</th>
<th>OtherControl</th>
<th>Canedit</th>
<th>Bugs</th>
</tr>
[% FOREACH group = groups %]
[% IF group.isactive == 0 AND group.bugcount > 0 %]
<tr bgcolor="#bbbbbb">
<td>
[% group.name FILTER html %]
</td>
<td align="center" colspan=4>
Disabled
</td>
<td>
[% group.bugcount %]
</td>
<tr>
[% ELSIF group.isactive != 0 %]
<tr>
<td>
[% group.name FILTER html %]
</td>
<td>
<input type=checkbox value=1 name=entry_[% group.id %]
[% " checked=\"checked\"" IF group.entry %]>
</td>
<td>
<select name="membercontrol_[% group.id %]">
<option value=[% const.CONTROLMAPNA %]
[% " selected=\"selected\""
IF group.membercontrol == const.CONTROLMAPNA %]
>NA
</option>
<option value=[% const.CONTROLMAPSHOWN %]
[% " selected=\"selected\""
IF group.membercontrol == const.CONTROLMAPSHOWN %]
>Shown
</option>
<option value=[% const.CONTROLMAPDEFAULT %]
[% " selected=\"selected\""
IF group.membercontrol == const.CONTROLMAPDEFAULT %]
>Default
</option>
<option value=[% const.CONTROLMAPMANDATORY %]
[% " selected=\"selected\""
IF group.membercontrol == const.CONTROLMAPMANDATORY %]
>Mandatory
</option>
</select>
</td>
<td>
<select name="othercontrol_[% group.id %]">
<option value=[% const.CONTROLMAPNA %]
[% " selected=\"selected\""
IF group.othercontrol == const.CONTROLMAPNA %]
>NA
</option>
<option value=[% const.CONTROLMAPSHOWN %]
[% " selected=\"selected\""
IF group.othercontrol == const.CONTROLMAPSHOWN %]
>Shown
</option>
<option value=[% const.CONTROLMAPDEFAULT %]
[% " selected=\"selected\""
IF group.othercontrol == const.CONTROLMAPDEFAULT %]
>Default
</option>
<option value=[% const.CONTROLMAPMANDATORY %]
[% " selected=\"selected\""
IF group.othercontrol == const.CONTROLMAPMANDATORY %]
>Mandatory
</option>
</select>
</td>
<td>
<input type=checkbox value=1 name=canedit_[% group.id %]
[% " checked=\"checked\"" IF group.canedit %]>
</td>
<td>
[% group.bugcount %]
</td>
</tr>
[% END %]
[% END %]
</table>
<br>
<input type=submit name="submit" value="submit">
<br>
</form>
<p>
These settings control the relationship of the groups to this
product.
<p>
If any group has <b>Entry</b> selected, then this product will
restrict bug entry to only those users who are members of all the
groups with entry selected.
<p>
If any group has <b>Canedit</b> selected, then this product
will be read-only for any users who are not members of all of
the groups with Canedit selected. ONLY users who are members of
all the canedit groups will be able to edit. This is an additional
restriction that further restricts what can be edited by a user.
<p>
The <b>MemberControl</b> and <b>OtherControl</b> fields
indicate which bugs will be placed in
this group according to the following definitions.
<br>
<table border=1>
<tr>
<th>
MemberControl
</th>
<th>
OtherControl
</th>
<th>
Interpretation
</th>
</tr>
<tr>
<td>
NA
</td>
<td>
NA
</td>
<td>
Bugs in this product are never associated with this group.
</td>
</tr>
<tr>
<td>
Shown
</td>
<td>
NA
</td>
<td>
Bugs in this product are permitted to be restricted to this
group. Users who are a member of this group will be able
to place bugs in this group.
</td>
</tr>
<tr>
<td>
Shown
</td>
<td>
Shown
</td>
<td>
Bugs in this product can be placed in this group by anyone
with permission to edit the bug even if they are not a member
of this group.
</td>
</tr>
<tr>
<td>
Shown
</td>
<td>
Default
</td>
<td>
Bugs in this product can be placed in this group by anyone
with permission to edit the bug even if they are not a member
of this group. Non-members place bugs in this group by default.
</td>
</tr>
<tr>
<td>
Shown
</td>
<td>
Mandatory
</td>
<td>
Bugs in this product are permitted to be restricted to this
group. Users who are a member of this group will be able
to place bugs in this group.
Non-members will be forced to restrict bugs to this group
when they initially enter a bug in this product.
</td>
</tr>
<tr>
<td>
Default
</td>
<td>
NA
</td>
<td>
Bugs in this product are permitted to be restricted to this
group and are placed in this group by default.
Users who are a member of this group will be able
to place bugs in this group.
</td>
</tr>
<tr>
<td>
Default
</td>
<td>
Default
</td>
<td>
Bugs in this product are permitted to be restricted to this
group and are placed in this group by default.
Users who are a member of this group will be able
to place bugs in this group. Non-members will be able to
restrict bugs to this group on entry and will do so by default
</td>
</tr>
<tr>
<td>
Default
</td>
<td>
Mandatory
</td>
<td>
Bugs in this product are permitted to be restricted to this
group and are placed in this group by default.
Users who are a member of this group will be able
to place bugs in this group. Non-members will be forced
to place bugs in this group on entry.
</td>
</tr>
<tr>
<td>
Mandatory
</td>
<td>
Mandatory
</td>
<td>
Bugs in this product are required to be restricted to this
group. Users are not given any option.
</td>
</tr>
</table>
[% PROCESS global/footer.html.tmpl %]
......@@ -405,20 +405,28 @@
<br>
[% IF groups.size > 0 %]
<br>
<b>Only users in all of the selected groups can view this bug:</b>
<br>
<font size="-1">(Unchecking all boxes makes this a public bug.)</font>
<br>
<br>
[% FOREACH group = groups %]
[% IF NOT group.mandatory %]
[% IF NOT emitted_description %]
[% emitted_description = 1 %]
<br>
<b>Only users in all of the selected groups can view this bug:</b>
<br>
<font size="-1">
(Unchecking all boxes makes this a more public bug.)
</font>
<br>
<br>
[% END %]
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="checkbox" name="bit-[% group.bit %]" value="1"
[% " checked=\"checked\"" IF group.ison %]
[% " disabled=\"disabled\"" IF NOT group.ingroup %]>
[% group.description %]
<br>
[% END %]
[% END %]
[% IF NOT user.inallgroups %]
......@@ -431,7 +439,7 @@
[% IF bug.inagroup %]
<p>
<b>But users in the roles selected below can always view this bug:</b>
<b>Users in the roles selected below can always view this bug:</b>
<br>
<small>
(The assignee
......
......@@ -81,14 +81,14 @@
<h3>Verify Bug Group</h3>
<p>
Do you want to add the bug to its new product's group (if any)?
Do you want to add the bug to its new product's default groups (if any)?
</p>
<p>
<input type="radio" name="addtonewgroup" value="no"><b>no</b><br>
<input type="radio" name="addtonewgroup" value="yes"><b>yes</b><br>
<input type="radio" name="addtonewgroup" value="yesifinold" checked="checked">
<b>yes, but only if the bug was in its old product's group</b><br>
<b>yes, but only if the bug was in any of its old product's default groups</b><br>
</p>
[% END %]
......
......@@ -230,6 +230,12 @@
It must also not contain any of these special characters:
<tt>\ ( ) &amp; &lt; &gt; , ; : &quot; [ ]</tt>, or any whitespace.
[% ELSIF error == "illegal_group_control_combination" %]
[% title = "Your Group Control Combination Is Illegal" %]
Your group control combination for group &quot;
[% groupname FILTER html %]
&quot; is illegal.
[% ELSIF error == "illegal_is_obsolete" %]
[% title = "Your Query Makes No Sense" %]
The only legal values for the <em>Attachment is obsolete</em> field are
......@@ -462,6 +468,10 @@
[% title = "Access Denied" %]
You do not have the permissions necessary to access that product.
[% ELSIF error == "product_edit_denied" %]
[% title = "Product Edit Access Denied" %]
You are not permitted to edit bugs in product [% product %].
[% ELSIF error == "query_name_missing" %]
[% title = "No Query Name Specified" %]
You must enter a name for your query.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment