From c64d51111a5ae02d6fc45163a847d0b7e2004548 Mon Sep 17 00:00:00 2001 From: "bugreport%peshkin.net" <> Date: Mon, 25 Nov 2002 03:56:17 +0000 Subject: Bug 147275 Rearchitect product groups Patch by joel r=bbaetz,justdave a=justdave --- editproducts.cgi | 539 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 527 insertions(+), 12 deletions(-) (limited to 'editproducts.cgi') diff --git a/editproducts.cgi b/editproducts.cgi index 5649c4440..675a70d9e 100755 --- a/editproducts.cgi +++ b/editproducts.cgi @@ -29,7 +29,8 @@ use strict; use lib "."; - +use vars qw ($template $vars); +use Bugzilla::Constants; require "CGI.pl"; require "globals.pl"; @@ -38,9 +39,16 @@ require "globals.pl"; sub sillyness { my $zz; + $zz = %::MFORM; $zz = $::unconfirmedstate; } +my %ctl = ( + &::CONTROLMAPNA => 'NA', + &::CONTROLMAPSHOWN => 'Shown', + &::CONTROLMAPDEFAULT => 'Default', + &::CONTROLMAPMANDATORY => 'Mandatory' +); # TestProduct: just returns if the specified product does exists # CheckProduct: same check, optionally emit an error text @@ -187,10 +195,9 @@ unless (UserInGroup("editcomponents")) { # my $product = trim($::FORM{product} || ''); my $action = trim($::FORM{action} || ''); +my $headerdone = 0; my $localtrailer = "edit more products"; - - # # action='' -> Show nice list of products # @@ -342,7 +349,7 @@ if ($action eq 'new') { # If we're using bug groups, then we need to create a group for this # product as well. -JMR, 2/16/00 - if(Param("usebuggroups")) { + if(Param("makeproductgroups")) { # Next we insert into the groups table SendSQL("INSERT INTO groups " . "(name, description, isbuggroup, last_changed) " . @@ -356,6 +363,35 @@ if ($action eq 'new') { VALUES ($admin, $gid, 0)"); SendSQL("INSERT INTO group_group_map (member_id, grantor_id, isbless) VALUES ($admin, $gid, 1)"); + + # Associate the new group and new product. + SendSQL("INSERT INTO group_control_map " . + "(group_id, product_id, entry, " . + "membercontrol, othercontrol, canedit) VALUES " . + "($gid, $product_id, " . Param("useentrygroupdefault") . + ", " . CONTROLMAPDEFAULT . ", " . + CONTROLMAPNA . ", 0)"); + + # Permit the new product to use any non-product bug groups. + SendSQL("SELECT groups.id, products.id IS NULL FROM groups " . + "LEFT JOIN products " . + "ON groups.name = products.name " . + "WHERE isactive != 0 AND isbuggroup != 0 "); + while (MoreSQLData()) { + my ($grpid, $nonproductgroup) = FetchSQLData(); + if ($nonproductgroup) { + PushGlobalSQLState(); + SendSQL("INSERT INTO group_control_map " . + "(group_id, product_id, entry, " . + "membercontrol, othercontrol, canedit) VALUES " . + "entry, control, canedit) VALUES " . + "($grpid, $product_id, 0, " . + CONTROLMAPSHOWN . ", " . + CONTROLMAPNA . ", 0)"); + PopGlobalSQLState(); + } + } + } @@ -510,7 +546,7 @@ one."; print "\n"; print "\n"; print "\n"; + html_quote($product) . "\">\n"; print ""; PutTrailer($localtrailer); @@ -538,6 +574,7 @@ if ($action eq 'delete') { versions WRITE, products WRITE, groups WRITE, + group_control_map WRITE, profiles WRITE, milestones WRITE, flaginclusions WRITE, @@ -583,6 +620,10 @@ if ($action eq 'delete') { WHERE product_id=$product_id"); print "Milestones deleted.
\n"; + SendSQL("DELETE FROM group_control_map + WHERE product_id=$product_id"); + print "Group controls deleted.
\n"; + SendSQL("DELETE FROM flaginclusions WHERE product_id=$product_id"); SendSQL("DELETE FROM flagexclusions @@ -593,7 +634,6 @@ if ($action eq 'delete') { WHERE id=$product_id"); print "Product '$product' deleted.
\n"; - SendSQL("UNLOCK TABLES"); unlink "data/versioncache"; @@ -692,6 +732,27 @@ if ($action eq 'edit') { } } + print "\n\n"; + print " Edit Group Access Controls\n"; + print "\n"; + SendSQL("SELECT id, name, isactive, entry, membercontrol, othercontrol, canedit " . + "FROM groups, " . + "group_control_map " . + "WHERE group_control_map.group_id = id AND product_id = $product_id " . + "AND isbuggroup != 0 ORDER BY name"); + while (MoreSQLData()) { + my ($id, $name, $isactive, $entry, $membercontrol, $othercontrol, $canedit) + = FetchSQLData(); + print "" . html_quote($name) . ": "; + if ($isactive) { + print $ctl{$membercontrol} . "/" . $ctl{$othercontrol}; + print ", ENTRY" if $entry; + print ", CANEDIT" if $canedit; + } else { + print "DISABLED"; + } + print "
\n"; + } print "\n\n"; print " Bugs:\n"; print " "; @@ -706,11 +767,11 @@ if ($action eq 'edit') { print "\n\n"; print "\n"; + html_quote($product) . "\">\n"; print "\n"; + html_quote($description) . "\">\n"; print "\n"; + html_quote($milestoneurl) . "\">\n"; print "\n"; print "\n"; print "\n"; @@ -729,6 +790,230 @@ if ($action eq 'edit') { } +# +# action='updategroupcontrols' -> update the product +# + +if ($action eq 'updategroupcontrols') { + my $product_id = get_product_id($product); + my @now_na = (); + my @now_mandatory = (); + foreach my $f (keys %::FORM) { + if ($f =~ /^membercontrol_(\d+)$/) { + my $id = $1; + if ($::FORM{$f} == CONTROLMAPNA) { + push @now_na,$id; + } elsif ($::FORM{$f} == CONTROLMAPMANDATORY) { + push @now_mandatory,$id; + } + } + } + if (!($::FORM{'confirmed'})) { + $vars->{'form'} = \%::FORM; + $vars->{'mform'} = \%::MFORM; + my @na_groups = (); + if (@now_na) { + SendSQL("SELECT groups.name, COUNT(bugs.bug_id) + FROM bugs, bug_group_map, groups + WHERE groups.id IN(" . join(',',@now_na) . ") + AND bug_group_map.group_id = groups.id + AND bug_group_map.bug_id = bugs.bug_id + AND bugs.product_id = $product_id + GROUP BY groups.name"); + while (MoreSQLData()) { + my ($groupname, $bugcount) = FetchSQLData(); + my %g = (); + $g{'name'} = $groupname; + $g{'count'} = $bugcount; + push @na_groups,\%g; + } + } + + my @mandatory_groups = (); + if (@now_mandatory) { + SendSQL("SELECT groups.name, COUNT(bugs.bug_id) + FROM bugs, groups + LEFT JOIN bug_group_map + ON bug_group_map.group_id = groups.id + AND bug_group_map.bug_id = bugs.bug_id + WHERE groups.id IN(" . join(',',@now_mandatory) . ") + AND bugs.product_id = $product_id + AND bug_group_map.bug_id IS NULL + GROUP BY groups.name"); + while (MoreSQLData()) { + my ($groupname, $bugcount) = FetchSQLData(); + my %g = (); + $g{'name'} = $groupname; + $g{'count'} = $bugcount; + push @mandatory_groups,\%g; + } + } + if ((@na_groups) || (@mandatory_groups)) { + $vars->{'product'} = $product; + $vars->{'na_groups'} = \@na_groups; + $vars->{'mandatory_groups'} = \@mandatory_groups; + $template->process("admin/products/groupcontrol/confirm-edit.html.tmpl", $vars) + || ThrowTemplateError($template->error()); + exit; + } + } + PutHeader("Update group access controls for product \"$product\""); + $headerdone = 1; + SendSQL("SELECT id, name FROM groups " . + "WHERE isbuggroup != 0 AND isactive != 0"); + while (MoreSQLData()){ + my ($groupid, $groupname) = FetchSQLData(); + my $newmembercontrol = $::FORM{"membercontrol_$groupid"} || 0; + my $newothercontrol = $::FORM{"othercontrol_$groupid"} || 0; + # Legality of control combination is a function of + # membercontrol\othercontrol + # NA SH DE MA + # NA + - - - + # SH + + + + + # DE + - + + + # MA - - - + + unless (($newmembercontrol == $newothercontrol) + || ($newmembercontrol == CONTROLMAPSHOWN) + || (($newmembercontrol == CONTROLMAPDEFAULT) + && ($newothercontrol != CONTROLMAPSHOWN))) { + ThrowUserError('illegal_group_control_combination', + {groupname => $groupname, + header_done => 1}); + } + } + SendSQL("LOCK TABLES groups READ, + group_control_map WRITE, + bugs WRITE, + bugs_activity WRITE, + bug_group_map WRITE, + fielddefs READ"); + SendSQL("SELECT id, name, entry, membercontrol, othercontrol, canedit " . + "FROM groups " . + "LEFT JOIN group_control_map " . + "ON group_control_map.group_id = id AND product_id = $product_id " . + "WHERE isbuggroup != 0 AND isactive != 0"); + while (MoreSQLData()) { + my ($groupid, $groupname, $entry, $membercontrol, + $othercontrol, $canedit) = FetchSQLData(); + my $newentry = $::FORM{"entry_$groupid"} || 0; + my $newmembercontrol = $::FORM{"membercontrol_$groupid"} || 0; + my $newothercontrol = $::FORM{"othercontrol_$groupid"} || 0; + my $newcanedit = $::FORM{"canedit_$groupid"} || 0; + my $oldentry = $entry; + $entry = $entry || 0; + $membercontrol = $membercontrol || 0; + $othercontrol = $othercontrol || 0; + $canedit = $canedit || 0; + detaint_natural($newentry); + detaint_natural($newothercontrol); + detaint_natural($newmembercontrol); + detaint_natural($newcanedit); + if ((!defined($oldentry)) && + (($newentry) || ($newmembercontrol) || ($newcanedit))) { + PushGlobalSQLState(); + SendSQL("INSERT INTO group_control_map " . + "(group_id, product_id, entry, " . + "membercontrol, othercontrol, canedit) " . + "VALUES " . + "($groupid, $product_id, $newentry, " . + "$newmembercontrol, $newothercontrol, $newcanedit)"); + PopGlobalSQLState(); + } elsif (($newentry != $entry) + || ($newmembercontrol != $membercontrol) + || ($newothercontrol != $othercontrol) + || ($newcanedit != $canedit)) { + PushGlobalSQLState(); + SendSQL("UPDATE group_control_map " . + "SET entry = $newentry, " . + "membercontrol = $newmembercontrol, " . + "othercontrol = $newothercontrol, " . + "canedit = $newcanedit " . + "WHERE group_id = $groupid " . + "AND product_id = $product_id"); + PopGlobalSQLState(); + } + + if (($newentry == 0) && ($newmembercontrol == 0) + && ($newothercontrol == 0) && ($newcanedit == 0)) { + PushGlobalSQLState(); + SendSQL("DELETE FROM group_control_map " . + "WHERE group_id = $groupid " . + "AND product_id = $product_id"); + PopGlobalSQLState(); + } + } + + foreach my $groupid (@now_na) { + print "Removing bugs from NA group " + . html_quote(GroupIdToName($groupid)) . "

\n"; + my $count = 0; + SendSQL("SELECT bugs.bug_id, + (lastdiffed >= delta_ts) + FROM bugs, bug_group_map + WHERE group_id = $groupid + AND bug_group_map.bug_id = bugs.bug_id + AND bugs.product_id = $product_id + ORDER BY bugs.bug_id"); + while (MoreSQLData()) { + my ($bugid, $mailiscurrent) = FetchSQLData(); + PushGlobalSQLState(); + SendSQL("DELETE FROM bug_group_map WHERE + bug_id = $bugid AND group_id = $groupid"); + SendSQL("SELECT name, NOW() FROM groups WHERE id = $groupid"); + my ($removed, $timestamp) = FetchSQLData(); + LogActivityEntry($bugid, "bug_group", $removed, "", + $::userid, $timestamp); + if ($mailiscurrent != 0) { + SendSQL("UPDATE bugs SET lastdiffed = " . SqlQuote($timestamp) + . " WHERE bug_id = $bugid"); + } + SendSQL("UPDATE bugs SET delta_ts = " . SqlQuote($timestamp) + . " WHERE bug_id = $bugid"); + PopGlobalSQLState(); + $count++; + } + print "dropped $count bugs

\n"; + } + + foreach my $groupid (@now_mandatory) { + print "Adding bugs to Mandatory group " + . html_quote(GroupIdToName($groupid)) . "

\n"; + my $count = 0; + SendSQL("SELECT bugs.bug_id, + (lastdiffed >= delta_ts) + FROM bugs + LEFT JOIN bug_group_map + ON bug_group_map.bug_id = bugs.bug_id + AND group_id = $groupid + WHERE bugs.product_id = $product_id + AND bug_group_map.bug_id IS NULL + ORDER BY bugs.bug_id"); + while (MoreSQLData()) { + my ($bugid, $mailiscurrent) = FetchSQLData(); + PushGlobalSQLState(); + SendSQL("INSERT INTO bug_group_map (bug_id, group_id) + VALUES ($bugid, $groupid)"); + SendSQL("SELECT name, NOW() FROM groups WHERE id = $groupid"); + my ($added, $timestamp) = FetchSQLData(); + LogActivityEntry($bugid, "bug_group", "", $added, + $::userid, $timestamp); + if ($mailiscurrent != 0) { + SendSQL("UPDATE bugs SET lastdiffed = " . SqlQuote($timestamp) + . " WHERE bug_id = $bugid"); + } + SendSQL("UPDATE bugs SET delta_ts = " . SqlQuote($timestamp) + . " WHERE bug_id = $bugid"); + PopGlobalSQLState(); + $count++; + } + print "added $count bugs

\n"; + } + SendSQL("UNLOCK TABLES"); + print "Group control updates done

\n"; + + PutTrailer($localtrailer); + exit; +} # # action='update' -> update the product @@ -770,6 +1055,7 @@ if ($action eq 'update') { SendSQL("LOCK TABLES products WRITE, versions READ, groups WRITE, + group_control_map WRITE, profiles WRITE, milestones READ"); @@ -863,9 +1149,9 @@ if ($action eq 'update') { } SendSQL("UPDATE products SET name=$qp WHERE id=$product_id"); - # Need to do an update to groups as well. If there is a corresponding - # bug group, whether usebuggroups is currently set or not, we want to - # update it so it will match in the future. If there is no group, this + # Need to do an update to groups as well. If there is + # a corresponding bug group, we want to update it so it will + # match in the future. If there is no group, this # update statement will do nothing, so no harm done. -JMR, 3/8/00 SendSQL("UPDATE groups " . "SET name = $qp, " . @@ -945,6 +1231,235 @@ if ($action eq 'update') { exit; } +# +# action='editgroupcontrols' -> update product group controls +# + +if ($action eq 'editgroupcontrols') { + my $product_id = get_product_id($product); + # Display a group if it is either enabled or has bugs for this product. + SendSQL("SELECT id, name, entry, membercontrol, othercontrol, canedit, " . + "isactive, COUNT(bugs.bug_id) " . + "FROM groups " . + "LEFT JOIN group_control_map " . + "ON group_control_map.group_id = id " . + "AND group_control_map.product_id = $product_id " . + "LEFT JOIN bug_group_map " . + "ON bug_group_map.group_id = groups.id " . + "LEFT JOIN bugs " . + "ON bugs.bug_id = bug_group_map.bug_id " . + "AND bugs.product_id = $product_id " . + "WHERE isbuggroup != 0 " . + "AND (isactive != 0 OR entry IS NOT NULL " . + "OR bugs.bug_id IS NOT NULL) " . + "GROUP BY name"); + my @groups = (); + while (MoreSQLData()) { + my %group = (); + my ($groupid, $groupname, $entry, $membercontrol, $othercontrol, + $canedit, $isactive, $bugcount) = FetchSQLData(); + $group{'id'} = $groupid; + $group{'name'} = $groupname; + $group{'entry'} = $entry; + $group{'membercontrol'} = $membercontrol; + $group{'othercontrol'} = $othercontrol; + $group{'canedit'} = $canedit; + $group{'isactive'} = $isactive; + $group{'bugcount'} = $bugcount; + push @groups,\%group; + } + $vars->{'header_done'} = $headerdone; + $vars->{'product'} = $product; + $vars->{'groups'} = \@groups; + $vars->{'const'} = { + 'CONTROLMAPNA' => CONTROLMAPNA, + 'CONTROLMAPSHOWN' => CONTROLMAPSHOWN, + 'CONTROLMAPDEFAULT' => CONTROLMAPDEFAULT, + 'CONTROLMAPMANDATORY' => CONTROLMAPMANDATORY, + }; + + $template->process("admin/products/groupcontrol/edit.html.tmpl", $vars) + || ThrowTemplateError($template->error()); + exit; + + print "\n"; + print "\n"; + print "

\n"; + print "\n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + while (MoreSQLData()) { + print "\n"; + my ($groupid, $groupname, $entry, $membercontrol, $othercontrol, + $canedit) = FetchSQLData(); + print "\n"; + print " \n"; + print "
GroupEntryMemberControlOtherControlCanedit
\n"; + print " $groupname\n"; + print " \n"; + $entry |= 0; + print " \n"; + print " \n"; + $membercontrol |= 0; + $othercontrol |= 0; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + $canedit |= 0; + print " \n"; + + } + + print "

"; + print "Add controls to the panel above:
\n"; + print "

\n"; + + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print "
\n"; + print "

note: Any group controls Set to NA/NA with no other checkboxes "; + print "will automatically be removed from the panel the next time "; + print "update is clicked.\n"; + print "

These settings control the relationship of the groups to this "; + print "product.\n"; + print "

If any group has Entry selected, then this product will "; + print "restrict bug entry to only those users who are members of all the "; + print "groups with entry selected.\n"; + print "

If any group has Canedit selected, then this product "; + print "will be read-only for any users who are not members of all of "; + print "the groups with Canedit selected. ONLY users who are members of "; + print "all the canedit groups will be able to edit. This is an additional "; + print "restriction that further restricts what can be edited by a user.\n"; + print "

The MemberControl and OtherControl fields "; + print "indicate which bugs will be placed in "; + print "this group according to the following definitions.\n"; + print "
"; + print ""; + print ""; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print "
MemberControlOtherControlInterpretation
NANABugs in this product are never associated with this group.
ShownNABugs in this product are permitted to be restricted to this "; + print "group. Users who are a member of this group will be able "; + print "to place bugs in this group.
ShownShownBugs in this product can be placed in this group by anyone "; + print "with permission to edit the bug even if they are not a member "; + print "of this group.
ShownDefaultBugs in this product can be placed in this group by anyone "; + print "with permission to edit the bug even if they are not a member "; + print "of this group. Non-members place bugs in this group by default."; + print "
ShownMandatoryBugs in this product are permitted to be restricted to this "; + print "group. Users who are a member of this group will be able "; + print "to place bugs in this group."; + print "Non-members will be forced to restrict bugs to this group "; + print "when they initially enter a bug in this product."; + print "
DefaultNABugs in this product are permitted to be restricted to this "; + print "group and are placed in this group by default."; + print "Users who are a member of this group will be able "; + print "to place bugs in this group.
DefaultDefaultBugs in this product are permitted to be restricted to this "; + print "group and are placed in this group by default."; + print "Users who are a member of this group will be able "; + print "to place bugs in this group. Non-members will be able to "; + print "restrict bugs to this group on entry and will do so by default "; + print "
DefaultMandatoryBugs in this product are permitted to be restricted to this "; + print "group and are placed in this group by default."; + print "Users who are a member of this group will be able "; + print "to place bugs in this group. Non-members will be forced "; + print "to place bugs in this group on entry."; + print "
MandatoryMandatoryBugs in this product are required to be restricted to this "; + print "group. Users are not given any option.
"; + + + PutTrailer($localtrailer); + exit; +} # -- cgit v1.2.3-24-g4f1b