Commit 65d3dc0e authored by bugreport%peshkin.net's avatar bugreport%peshkin.net

bug 157756 - Groups_20020716_Branch Tracking : > 55 groups now supported

r=bbaetz, gerv
parent cf9b4ba2
......@@ -37,8 +37,8 @@ use Bugzilla::Util;
for my $key (qw (bug_id alias product version rep_platform op_sys bug_status
resolution priority bug_severity component assigned_to
reporter bug_file_loc short_desc target_milestone
qa_contact status_whiteboard creation_ts groupset
delta_ts votes whoid usergroupset comment query error) ){
qa_contact status_whiteboard creation_ts
delta_ts votes whoid comment query error) ){
$ok_field{$key}++;
}
......@@ -105,10 +105,6 @@ sub initBug {
$self->{'whoid'} = $user_id;
&::SendSQL("SELECT groupset FROM profiles WHERE userid=$self->{'whoid'}");
my $usergroupset = &::FetchOneColumn();
if (!$usergroupset) { $usergroupset = '0' }
$self->{'usergroupset'} = $usergroupset;
my $query = "
select
......@@ -116,7 +112,7 @@ sub initBug {
resolution, priority, bug_severity, components.name, assigned_to, reporter,
bug_file_loc, short_desc, target_milestone, qa_contact,
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
groupset, delta_ts, sum(votes.count)
delta_ts, sum(votes.count)
from bugs left join votes using(bug_id),
products, components
where bugs.bug_id = $bug_id
......@@ -124,10 +120,10 @@ sub initBug {
AND components.id = bugs.component_id
group by bugs.bug_id";
&::SendSQL(&::SelectVisible($query, $user_id, $usergroupset));
my @row;
&::SendSQL($query);
my @row = ();
if (@row = &::FetchSQLData()) {
if ((@row = &::FetchSQLData()) && &::CanSeeBug($bug_id, $self->{'whoid'})) {
my $count = 0;
my %fields;
foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
......@@ -135,24 +131,21 @@ sub initBug {
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
"qa_contact", "status_whiteboard", "creation_ts",
"groupset", "delta_ts", "votes") {
"delta_ts", "votes") {
$fields{$field} = shift @row;
if ($fields{$field}) {
$self->{$field} = $fields{$field};
}
$count++;
}
} else {
&::SendSQL("select groupset from bugs where bug_id = $bug_id");
if (@row = &::FetchSQLData()) {
} elsif (@row) {
$self->{'bug_id'} = $bug_id;
$self->{'error'} = "NotPermitted";
return $self;
} else {
} else {
$self->{'bug_id'} = $bug_id;
$self->{'error'} = "NotFound";
return $self;
}
}
$self->{'assigned_to'} = &::DBID_to_name($self->{'assigned_to'});
......@@ -356,22 +349,6 @@ sub XML_Footer {
return ("</bugzilla>\n");
}
sub UserInGroup {
my $self = shift();
my ($groupname) = (@_);
if ($self->{'usergroupset'} eq "0") {
return 0;
}
&::ConnectToDatabase();
&::SendSQL("select (bit & $self->{'usergroupset'}) != 0 from groups where name = "
. &::SqlQuote($groupname));
my $bit = &::FetchOneColumn();
if ($bit) {
return 1;
}
return 0;
}
sub CanChangeField {
my $self = shift();
my ($f, $oldvalue, $newvalue) = (@_);
......
......@@ -37,8 +37,8 @@ use Bugzilla::Util;
for my $key (qw (bug_id alias product version rep_platform op_sys bug_status
resolution priority bug_severity component assigned_to
reporter bug_file_loc short_desc target_milestone
qa_contact status_whiteboard creation_ts groupset
delta_ts votes whoid usergroupset comment query error) ){
qa_contact status_whiteboard creation_ts
delta_ts votes whoid comment query error) ){
$ok_field{$key}++;
}
......@@ -105,10 +105,6 @@ sub initBug {
$self->{'whoid'} = $user_id;
&::SendSQL("SELECT groupset FROM profiles WHERE userid=$self->{'whoid'}");
my $usergroupset = &::FetchOneColumn();
if (!$usergroupset) { $usergroupset = '0' }
$self->{'usergroupset'} = $usergroupset;
my $query = "
select
......@@ -116,7 +112,7 @@ sub initBug {
resolution, priority, bug_severity, components.name, assigned_to, reporter,
bug_file_loc, short_desc, target_milestone, qa_contact,
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
groupset, delta_ts, sum(votes.count)
delta_ts, sum(votes.count)
from bugs left join votes using(bug_id),
products, components
where bugs.bug_id = $bug_id
......@@ -124,10 +120,10 @@ sub initBug {
AND components.id = bugs.component_id
group by bugs.bug_id";
&::SendSQL(&::SelectVisible($query, $user_id, $usergroupset));
my @row;
&::SendSQL($query);
my @row = ();
if (@row = &::FetchSQLData()) {
if ((@row = &::FetchSQLData()) && &::CanSeeBug($bug_id, $self->{'whoid'})) {
my $count = 0;
my %fields;
foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
......@@ -135,24 +131,21 @@ sub initBug {
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
"qa_contact", "status_whiteboard", "creation_ts",
"groupset", "delta_ts", "votes") {
"delta_ts", "votes") {
$fields{$field} = shift @row;
if ($fields{$field}) {
$self->{$field} = $fields{$field};
}
$count++;
}
} else {
&::SendSQL("select groupset from bugs where bug_id = $bug_id");
if (@row = &::FetchSQLData()) {
} elsif (@row) {
$self->{'bug_id'} = $bug_id;
$self->{'error'} = "NotPermitted";
return $self;
} else {
} else {
$self->{'bug_id'} = $bug_id;
$self->{'error'} = "NotFound";
return $self;
}
}
$self->{'assigned_to'} = &::DBID_to_name($self->{'assigned_to'});
......@@ -356,22 +349,6 @@ sub XML_Footer {
return ("</bugzilla>\n");
}
sub UserInGroup {
my $self = shift();
my ($groupname) = (@_);
if ($self->{'usergroupset'} eq "0") {
return 0;
}
&::ConnectToDatabase();
&::SendSQL("select (bit & $self->{'usergroupset'}) != 0 from groups where name = "
. &::SqlQuote($groupname));
my $bit = &::FetchOneColumn();
if ($bit) {
return 1;
}
return 0;
}
sub CanChangeField {
my $self = shift();
my ($f, $oldvalue, $newvalue) = (@_);
......
......@@ -29,7 +29,7 @@ use strict;
# The caller MUST require CGI.pl and globals.pl before using this
use vars qw($userid $usergroupset);
use vars qw($userid);
package Bugzilla::Search;
......@@ -117,7 +117,7 @@ sub init {
my @legal_fields = ("product", "version", "rep_platform", "op_sys",
"bug_status", "resolution", "priority", "bug_severity",
"assigned_to", "reporter", "component",
"target_milestone", "groupset");
"target_milestone", "bug_group");
foreach my $field (keys %F) {
if (lsearch(\@legal_fields, $field) != -1) {
......@@ -322,6 +322,12 @@ sub init {
push(@wherepart, "$table.bug_id = bugs.bug_id");
$f = "$table.thetext";
},
"^bug_group,(?!changed)" => sub {
push(@supptables, "LEFT JOIN bug_group_map bug_group_map_$chartid ON bugs.bug_id = bug_group_map_$chartid.bug_id");
push(@supptables, "LEFT JOIN groups groups_$chartid ON groups_$chartid.id = bug_group_map_$chartid.group_id");
$f = "groups_$chartid.name";
},
"^attachments\..*," => sub {
my $table = "attachments_$chartid";
push(@supptables, "attachments $table");
......@@ -747,7 +753,7 @@ sub init {
# chart -1 is generated by other code above, not from the user-
# submitted form, so we'll blindly accept any values in chart -1
if ((!$chartfields{$f}) && ($chart != -1)) {
my $errstr = "Can't use " . html_quote($f) . " as a field name. " .
my $errstr = "Can't use $f as a field name. " .
"If you think you're getting this in error, please copy the " .
"entire URL out of the address bar at the top of your browser " .
"window and email it to <109679\@bugzilla.org>";
......@@ -807,11 +813,27 @@ sub init {
$suppseen{$str} = 1;
}
}
my $query = ("SELECT DISTINCT " . join(', ', @fields) .
my $query = ("SELECT DISTINCT " .
join(', ', @fields) .
", COUNT(DISTINCT ugmap.group_id) AS cntuseringroups, " .
" COUNT(DISTINCT bgmap.group_id) AS cntbugingroups, " .
" ((COUNT(DISTINCT ccmap.who) AND cclist_accessible) " .
" OR ((bugs.reporter = $::userid) AND bugs.reporter_accessible) " .
" OR bugs.assigned_to = $::userid ) AS canseeanyway " .
" FROM $suppstring" .
" WHERE " . join(' AND ', (@wherepart, @andlist)));
$query = &::SelectVisible($query, $::userid, $::usergroupset);
" LEFT JOIN bug_group_map AS bgmap " .
" ON bgmap.bug_id = bugs.bug_id " .
" LEFT JOIN user_group_map AS ugmap " .
" ON bgmap.group_id = ugmap.group_id " .
" AND ugmap.user_id = $::userid " .
" AND ugmap.isbless = 0" .
" LEFT JOIN cc AS ccmap " .
" ON ccmap.who = $::userid AND ccmap.bug_id = bugs.bug_id " .
" WHERE " . join(' AND ', (@wherepart, @andlist)) .
" GROUP BY bugs.bug_id " .
" HAVING cntuseringroups = cntbugingroups" .
" OR canseeanyway"
);
if ($debug) {
print "<p><code>" . value_quote($query) . "</code></p>\n";
......
......@@ -289,11 +289,6 @@ sub ValidateBugID {
# converted-from-alias ID.
$_[0] = $id;
# Get the values of the usergroupset and userid global variables
# and write them to local variables for use within this function,
# setting those local variables to the default value of zero if
# the global variables are undefined.
# First check that the bug exists
SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $id");
......@@ -303,7 +298,7 @@ sub ValidateBugID {
return if $skip_authorization;
return if CanSeeBug($id, $::userid, $::usergroupset);
return if CanSeeBug($id, $::userid);
# The user did not pass any of the authorization tests, which means they
# are not authorized to see the bug. Display an error and stop execution.
......@@ -438,30 +433,25 @@ sub PasswordForLogin {
}
sub quietly_check_login() {
$::usergroupset = '0';
my $loginok = 0;
$::disabledreason = '';
$::userid = 0;
my $userid = 0;
if (defined $::COOKIE{"Bugzilla_login"} &&
defined $::COOKIE{"Bugzilla_logincookie"}) {
SendSQL("SELECT profiles.userid, profiles.groupset, " .
"profiles.login_name, " .
"profiles.login_name = " .
SqlQuote($::COOKIE{"Bugzilla_login"}) .
" AND logincookies.ipaddr = " .
SqlQuote($ENV{"REMOTE_ADDR"}) .
", profiles.disabledtext " .
SendSQL("SELECT profiles.userid," .
" profiles.login_name, " .
" profiles.disabledtext " .
" FROM profiles, logincookies WHERE logincookies.cookie = " .
SqlQuote($::COOKIE{"Bugzilla_logincookie"}) .
" AND profiles.userid = logincookies.userid");
" AND profiles.userid = logincookies.userid AND" .
" profiles.login_name = " .
SqlQuote($::COOKIE{"Bugzilla_login"}) .
" AND logincookies.ipaddr = " .
SqlQuote($ENV{"REMOTE_ADDR"}));
my @row;
if (@row = FetchSQLData()) {
my ($userid, $groupset, $loginname, $ok, $disabledtext) = (@row);
if ($ok) {
if (MoreSQLData()) {
($userid, my $loginname, my $disabledtext) = FetchSQLData();
if ($userid > 0) {
if ($disabledtext eq '') {
$loginok = 1;
$::userid = $userid;
$::usergroupset = $groupset;
$::COOKIE{"Bugzilla_login"} = $loginname; # Makes sure case
# is in
# canonical form.
......@@ -469,6 +459,7 @@ sub quietly_check_login() {
detaint_natural($::COOKIE{"Bugzilla_logincookie"});
} else {
$::disabledreason = $disabledtext;
$userid = 0;
}
}
}
......@@ -478,13 +469,14 @@ sub quietly_check_login() {
my $whoid = DBname_to_id($::FORM{'who'});
delete $::FORM{'who'} unless $whoid;
}
if (!$loginok) {
if (!$userid) {
delete $::COOKIE{"Bugzilla_login"};
}
$::userid = $userid;
ConfirmGroup($userid);
$vars->{'user'} = GetUserInfo($::userid);
return $loginok;
return $userid;
}
# Populate a hash with information about this user.
......@@ -500,10 +492,9 @@ sub GetUserInfo {
$user{'login'} = $::COOKIE{"Bugzilla_login"};
$user{'userid'} = $userid;
SendSQL("SELECT mybugslink, realname, groupset, blessgroupset " .
SendSQL("SELECT mybugslink, realname " .
"FROM profiles WHERE userid = $userid");
($user{'showmybugslink'}, $user{'realname'}, $user{'groupset'},
$user{'blessgroupset'}) = FetchSQLData();
($user{'showmybugslink'}, $user{'realname'}) = FetchSQLData();
SendSQL("SELECT name, query, linkinfooter FROM namedqueries " .
"WHERE userid = $userid");
......@@ -516,10 +507,15 @@ sub GetUserInfo {
$user{'queries'} = \@queries;
SendSQL("select name, (bit & $user{'groupset'}) != 0 from groups");
$user{'canblessany'} = UserCanBlessAnything();
SendSQL("SELECT name FROM groups, user_group_map " .
"WHERE groups.id = user_group_map.group_id " .
"AND user_id = $userid " .
"AND NOT isbless");
while (MoreSQLData()) {
my ($name, $bit) = FetchSQLData();
$groups{$name} = $bit;
my ($name) = FetchSQLData();
$groups{$name} = 1;
}
$user{'groups'} = \%groups;
......@@ -561,6 +557,7 @@ sub confirm_login {
# to a later section. -Joe Robins, 8/3/00
my $enteredlogin = "";
my $realcryptpwd = "";
my $userid;
# If the form contains Bugzilla login and password fields, use Bugzilla's
# built-in authentication to authenticate the user (otherwise use LDAP below).
......@@ -570,7 +567,6 @@ sub confirm_login {
CheckEmailSyntax($enteredlogin);
# Retrieve the user's ID and crypted password from the database.
my $userid;
SendSQL("SELECT userid, cryptpassword FROM profiles
WHERE login_name = " . SqlQuote($enteredlogin));
($userid, $realcryptpwd) = FetchSQLData();
......@@ -765,9 +761,9 @@ sub confirm_login {
print "Set-Cookie: Bugzilla_logincookie=$logincookie ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
}
my $loginok = quietly_check_login();
$userid = quietly_check_login();
if ($loginok != 1) {
if (!$userid) {
if ($::disabledreason) {
my $cookiepath = Param("cookiepath");
print "Set-Cookie: Bugzilla_login= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT
......@@ -810,7 +806,8 @@ Content-type: text/html
SendSQL("UPDATE logincookies SET lastused = null " .
"WHERE cookie = $::COOKIE{'Bugzilla_logincookie'}");
}
return $::userid;
ConfirmGroup($userid);
return $userid;
}
sub PutHeader {
......
......@@ -50,7 +50,6 @@ require "CGI.pl";
ConnectToDatabase();
# Check whether or not the user is logged in and, if so, set the $::userid
# and $::usergroupset variables.
quietly_check_login();
################################################################################
......
......@@ -82,7 +82,7 @@ sub show_bug {
bug_file_loc, short_desc, target_milestone,
qa_contact, status_whiteboard,
date_format(creation_ts,'%Y-%m-%d %H:%i'),
groupset, delta_ts, sum(votes.count), delta_ts calc_disp_date
delta_ts, sum(votes.count), delta_ts calc_disp_date
FROM bugs LEFT JOIN votes USING(bug_id), products, components
WHERE bugs.bug_id = $id
AND bugs.product_id = products.id
......@@ -106,7 +106,7 @@ sub show_bug {
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
"qa_contact", "status_whiteboard", "creation_ts",
"groupset", "delta_ts", "votes","calc_disp_date")
"delta_ts", "votes", "calc_disp_date")
{
$value = shift(@row);
if ($field eq "calc_disp_date") {
......@@ -221,58 +221,68 @@ sub show_bug {
# Groups
my @groups;
if ($::usergroupset ne '0' || $bug{'groupset'} ne '0') {
my $bug_groupset = $bug{'groupset'};
SendSQL("SELECT bit, name, description, (bit & $bug_groupset != 0),
(bit & $::usergroupset != 0) FROM groups
WHERE isbuggroup != 0 " .
# Include active groups as well as inactive groups to which
# the bug already belongs. This way the bug can be removed
# from an inactive group but can only be added to active ones.
"AND ((isactive = 1 AND (bit & $::usergroupset != 0)) OR
(bit & $bug_groupset != 0))");
# For every group, we need to know if there is ANY bug_group_map
# record putting the current bug in that group and if there is ANY
# user_group_map record putting the user in that group.
# The LEFT JOINs are checking for record existence.
#
SendSQL("SELECT DISTINCT groups.id, name, description," .
" bug_group_map.group_id IS NOT NULL," .
" user_group_map.group_id IS NOT NULL," .
" isactive" .
" FROM groups" .
" LEFT JOIN bug_group_map" .
" ON bug_group_map.group_id = groups.id" .
" AND bug_id = $bug{'bug_id'}" .
" LEFT JOIN user_group_map" .
" ON user_group_map.group_id = groups.id" .
" AND user_id = $::userid" .
" AND NOT isbless" .
" WHERE isbuggroup");
$user{'inallgroups'} = 1;
$user{'inallgroups'} = 1;
while (MoreSQLData()) {
my ($groupid, $name, $description, $ison, $ingroup, $isactive)
= FetchSQLData();
$bug{'inagroup'} = 1 if ($ison);
# 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})))))
{
$user{'inallgroups'} &= $ingroup;
while (MoreSQLData()) {
my ($bit, $name, $description, $ison, $ingroup) = FetchSQLData();
# 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 ||
($ingroup && (($name eq $bug{'product'}) ||
(!defined $::proddesc{$name}))))
{
$user{'inallgroups'} &= $ingroup;
push (@groups, { "bit" => $bit,
"ison" => $ison,
"ingroup" => $ingroup,
"description" => $description });
}
push (@groups, { "bit" => $groupid,
"ison" => $ison,
"ingroup" => $ingroup,
"description" => $description });
}
}
# If the bug is restricted to a group, display checkboxes that allow
# the user to set whether or not the reporter
# and cc list can see the bug even if they are not members of all
# groups to which the bug is restricted.
if ($bug{'groupset'} != 0) {
$bug{'inagroup'} = 1;
# Determine whether or not the bug is always accessible by the
# reporter, QA contact, and/or users on the cc: list.
SendSQL("SELECT reporter_accessible, cclist_accessible
FROM bugs
WHERE bug_id = $id
");
($bug{'reporter_accessible'},
$bug{'cclist_accessible'}) = FetchSQLData();
}
# If the bug is restricted to a group, get flags that allow
# the user to set whether or not the reporter
# and cc list can see the bug even if they are not members of all
# groups to which the bug is restricted.
if ($bug{'inagroup'}) {
# Determine whether or not the bug is always accessible by the
# reporter, QA contact, and/or users on the cc: list.
SendSQL("SELECT reporter_accessible, cclist_accessible
FROM bugs
WHERE bug_id = $id
");
($bug{'reporter_accessible'},
$bug{'cclist_accessible'}) = FetchSQLData();
}
$vars->{'groups'} = \@groups;
......
......@@ -207,23 +207,24 @@ sub GetQuip {
return $quip;
}
sub GetGroupsByGroupSet {
my ($groupset) = @_;
sub GetGroupsByUserId {
my ($userid) = @_;
return if !$groupset;
return if !$userid;
SendSQL("
SELECT bit, name, description, isactive
FROM groups
WHERE (bit & $groupset) != 0
AND isbuggroup != 0
SELECT groups.id, name, description, isactive
FROM groups, user_group_map
WHERE user_id = $userid AND NOT isbless
AND user_group_map.group_id = groups.id
AND isbuggroup
ORDER BY description ");
my @groups;
while (MoreSQLData()) {
my $group = {};
($group->{'bit'}, $group->{'name'},
($group->{'id'}, $group->{'name'},
$group->{'description'}, $group->{'isactive'}) = FetchSQLData();
push(@groups, $group);
}
......@@ -379,7 +380,6 @@ sub DefineColumn {
# Column: ID Name Title
DefineColumn("id" , "bugs.bug_id" , "ID" );
DefineColumn("groupset" , "bugs.groupset" , "Groupset" );
DefineColumn("opendate" , "bugs.creation_ts" , "Opened" );
DefineColumn("changeddate" , "bugs.delta_ts" , "Changed" );
DefineColumn("severity" , "bugs.bug_severity" , "Severity" );
......@@ -437,9 +437,6 @@ else {
# and are hard-coded into the display templates.
@displaycolumns = grep($_ ne 'id', @displaycolumns);
# IMPORTANT! Never allow the groupset column to be displayed!
@displaycolumns = grep($_ ne 'groupset', @displaycolumns);
# Add the votes column to the list of columns to be displayed
# in the bug list if the user is searching for bugs with a certain
# number of votes and the votes column is not already on the list.
......@@ -458,10 +455,8 @@ if (trim($::FORM{'votes'}) && !grep($_ eq 'votes', @displaycolumns)) {
# Generate the list of columns that will be selected in the SQL query.
# The bug ID and groupset are always selected because bug IDs are always
# displayed and we need the groupset to determine whether or not the bug
# is visible to the user.
my @selectcolumns = ("id", "groupset");
# The bug ID is always selected because bug IDs are always displayed
my @selectcolumns = ("id");
# Display columns are selected because otherwise we could not display them.
push (@selectcolumns, @displaycolumns);
......@@ -721,7 +716,7 @@ if ($dotweak) {
$vars->{'bugstatuses'} = [ keys %$bugstatuses ];
# The groups to which the user belongs.
$vars->{'groups'} = GetGroupsByGroupSet($::usergroupset) if $::usergroupset ne '0';
$vars->{'groups'} = GetGroupsByUserId($::userid);
# If all bugs being changed are in the same product, the user can change
# their version and component, so generate a list of products, a list of
......
......@@ -37,7 +37,7 @@
#
# You need to work with bug_email.pl the MIME::Parser installed.
#
# $Id: bug_email.pl,v 1.13 2002/08/26 06:17:21 bbaetz%student.usyd.edu.au Exp $
# $Id: bug_email.pl,v 1.14 2002/09/22 17:15:03 bugreport%peshkin.net Exp $
###############################################################
# 02/12/2000 (SML)
......
......@@ -212,33 +212,11 @@
you for this username and password.</para>
<tip>
<para>If you wish to add more administrative users, you must use the
MySQL interface. Run "mysql" from the command line, and use these
commands:
<simplelist>
<member>
<prompt>mysql&gt;</prompt>
<command>use bugs;</command>
</member>
<member>
<prompt>mysql&gt;</prompt>
<command>
update profiles set groupset=0x7ffffffffffffff where login_name =
"(user's login name)";
</command>
</member>
</simplelist>
<para>If you wish to add more administrative users, add them to
the "admin" group and, optionally, add edit the tweakparams, editusers,
creategroups, editcomponents, and editkeywords groups to add the
entire admin group to those groups.
</para>
<para>Yes, that is
<emphasis>fourteen</emphasis>
<quote>f</quote>
's. A whole lot of f-ing going on if you want to create a new
administator.</para>
</tip>
</section>
......@@ -698,10 +676,22 @@
</listitem>
<listitem>
<para>Fill out the "New Name", "New Description", and
"New User RegExp" fields. "New User RegExp" allows you to automatically
<para>Fill out the "Group", "Description", and
"User RegExp" fields. "New User RegExp" allows you to automatically
place all users who fulfill the Regular Expression into the new group.
When you have finished, click "Add".</para>
<warning>
<para>The User Regexp is a perl regexp and, if not anchored, will match
any part of an address. So, if you do not want to grant access
into 'mycompany.com' to 'badperson@mycompany.com.hacker.net', use
'@mycompany\.com$' as the regexp.</para>
</warning>
</listitem>
<listitem>
<para>After you add your new group, edit the new group. On the
edit page, you can specify other groups that should be included
in this group and which groups should be permitted to add and delete
users from this group.</para>
</listitem>
</orderedlist>
......@@ -712,17 +702,6 @@
<para>Turn on "usebuggroups" and "usebuggroupsentry" in the "Edit
Parameters" screen.</para>
<warning>
<para>XXX is this still true?
"usebuggroupsentry" has the capacity to prevent the
administrative user from directly altering bugs because of
conflicting group permissions. If you plan on using
"usebuggroupsentry", you should plan on restricting
administrative account usage to administrative duties only. In
other words, manage bugs with an unpriveleged user account, and
manage users, groups, Products, etc. with the administrative
account.</para>
</warning>
</listitem>
<listitem>
......@@ -734,13 +713,6 @@
</listitem>
</orderedlist>
<warning>
<para>Bugzilla currently has a limit of 64 groups per installation. If
you have more than about 50 products, you should consider
running multiple Bugzillas. Ask in the newsgroup for other
suggestions for working around this restriction.</para>
</warning>
<para>
Note that group permissions are such that you need to be a member
of <emphasis>all</emphasis> the groups a bug is in, for whatever
......
......@@ -212,33 +212,11 @@
you for this username and password.</para>
<tip>
<para>If you wish to add more administrative users, you must use the
MySQL interface. Run "mysql" from the command line, and use these
commands:
<simplelist>
<member>
<prompt>mysql&gt;</prompt>
<command>use bugs;</command>
</member>
<member>
<prompt>mysql&gt;</prompt>
<command>
update profiles set groupset=0x7ffffffffffffff where login_name =
"(user's login name)";
</command>
</member>
</simplelist>
<para>If you wish to add more administrative users, add them to
the "admin" group and, optionally, add edit the tweakparams, editusers,
creategroups, editcomponents, and editkeywords groups to add the
entire admin group to those groups.
</para>
<para>Yes, that is
<emphasis>fourteen</emphasis>
<quote>f</quote>
's. A whole lot of f-ing going on if you want to create a new
administator.</para>
</tip>
</section>
......@@ -698,10 +676,22 @@
</listitem>
<listitem>
<para>Fill out the "New Name", "New Description", and
"New User RegExp" fields. "New User RegExp" allows you to automatically
<para>Fill out the "Group", "Description", and
"User RegExp" fields. "New User RegExp" allows you to automatically
place all users who fulfill the Regular Expression into the new group.
When you have finished, click "Add".</para>
<warning>
<para>The User Regexp is a perl regexp and, if not anchored, will match
any part of an address. So, if you do not want to grant access
into 'mycompany.com' to 'badperson@mycompany.com.hacker.net', use
'@mycompany\.com$' as the regexp.</para>
</warning>
</listitem>
<listitem>
<para>After you add your new group, edit the new group. On the
edit page, you can specify other groups that should be included
in this group and which groups should be permitted to add and delete
users from this group.</para>
</listitem>
</orderedlist>
......@@ -712,17 +702,6 @@
<para>Turn on "usebuggroups" and "usebuggroupsentry" in the "Edit
Parameters" screen.</para>
<warning>
<para>XXX is this still true?
"usebuggroupsentry" has the capacity to prevent the
administrative user from directly altering bugs because of
conflicting group permissions. If you plan on using
"usebuggroupsentry", you should plan on restricting
administrative account usage to administrative duties only. In
other words, manage bugs with an unpriveleged user account, and
manage users, groups, Products, etc. with the administrative
account.</para>
</warning>
</listitem>
<listitem>
......@@ -734,13 +713,6 @@
</listitem>
</orderedlist>
<warning>
<para>Bugzilla currently has a limit of 64 groups per installation. If
you have more than about 50 products, you should consider
running multiple Bugzillas. Ask in the newsgroup for other
suggestions for working around this restriction.</para>
</warning>
<para>
Note that group permissions are such that you need to be a member
of <emphasis>all</emphasis> the groups a bug is in, for whatever
......
......@@ -40,7 +40,7 @@ GetVersionTable();
quietly_check_login();
use vars qw (%FORM $userid $usergroupset @legal_product);
use vars qw (%FORM $userid @legal_product);
my %dbmcount;
my %count;
......@@ -160,9 +160,7 @@ if (scalar(%count)) {
# Limit to a single product if requested
$query .= (" AND bugs.product_id = " . $product_id) if $product_id;
SendSQL(SelectVisible($query,
$userid,
$usergroupset));
SendSQL($query);
while (MoreSQLData()) {
# Note: maximum row count is dealt with in the template.
......@@ -170,6 +168,7 @@ if (scalar(%count)) {
my ($id, $component, $bug_severity, $op_sys, $target_milestone,
$short_desc, $bug_status, $resolution) = FetchSQLData();
next if (!CanSeeBug($id, $::userid));
# Limit to open bugs only if requested
next if $openonly && ($resolution ne "");
......
......@@ -48,6 +48,7 @@ use vars qw(
@legal_platform
@legal_priority
@legal_severity
$userid
%MFORM
%versions
);
......@@ -326,60 +327,58 @@ $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.
if ($::usergroupset ne '0') {
# First we get the bit and description for the group.
my $group_bit = '0';
if(Param("usebuggroups") && GroupExists($product)) {
SendSQL("SELECT bit FROM groups ".
"WHERE name = " . SqlQuote($product) . " " .
"AND isbuggroup != 0");
($group_bit) = FetchSQLData();
}
SendSQL("SELECT bit, name, description FROM groups " .
"WHERE bit & $::usergroupset != 0 " .
"AND isbuggroup != 0 AND isactive = 1 ORDER BY description");
my @groups;
while (MoreSQLData()) {
my ($bit, $prodname, $description) = FetchSQLData();
# Don't want to include product groups other than this product.
next unless($prodname eq $product ||
!defined($::proddesc{$prodname}));
# First we get the bit and description for the group.
my $group_id = '0';
my $check;
if(Param("usebuggroups")) {
($group_id) = GroupExists($product);
}
# If this is the group for this product, make it checked.
if(formvalue("maketemplate") eq
"Remember values as bookmarkable template")
{
# If this is a bookmarked template, then we only want to set the
# bit for those bits set in the template.
$check = formvalue("bit-$bit", 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_bit == $bit);
}
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");
my $group =
{
'bit' => $bit ,
'checked' => $check ,
'description' => $description
};
my @groups;
push @groups, $group;
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 $check;
# If this is the group for this product, make it checked.
if(formvalue("maketemplate") eq
"Remember values as bookmarkable template")
{
# If this is a bookmarked template, then we only want to set the
# bit for those bits set in the template.
$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);
}
$vars->{'group'} = \@groups;
my $group =
{
'bit' => $id ,
'checked' => $check ,
'description' => $description
};
push @groups, $group;
}
$vars->{'group'} = \@groups;
$vars->{'default'} = \%default;
my $format =
......@@ -388,3 +387,4 @@ my $format =
print "Content-type: $format->{'ctype'}\n\n";
$template->process($format->{'template'}, $vars)
|| ThrowTemplateError($template->error());
......@@ -45,7 +45,6 @@ use vars qw(
ConnectToDatabase();
# Check whether or not the user is logged in and, if so, set the $::userid
# and $::usergroupset variables.
quietly_check_login();
###############################################################################
......
......@@ -26,7 +26,7 @@ use lib qw(.);
require "CGI.pl";
use vars qw($userid $usergroupset @legal_keywords %FORM);
use vars qw($userid @legal_keywords %FORM);
# Use global template variables.
use vars qw($template $vars);
......@@ -69,8 +69,8 @@ my @bugs;
foreach my $bug_id (split(/[:,]/, $buglist)) {
detaint_natural($bug_id) || next;
SendSQL(SelectVisible("$generic_query AND bugs.bug_id = $bug_id",
$::userid, $::usergroupset));
CanSeeBug($bug_id, $::userid) || next;
SendSQL("$generic_query AND bugs.bug_id = $bug_id");
my %bug;
my @row = FetchSQLData();
......
......@@ -34,7 +34,6 @@ require "bug_form.pl";
sub sillyness {
my $zz;
$zz = $::buffer;
$zz = $::usergroupset;
$zz = %::COOKIE;
$zz = %::components;
$zz = %::versions;
......@@ -242,7 +241,7 @@ if ($::FORM{'keywords'} && UserInGroup("editbugs")) {
# Build up SQL string to add bug.
my $sql = "INSERT INTO bugs " .
"(" . join(",", @used_fields) . ", reporter, creation_ts, groupset) " .
"(" . join(",", @used_fields) . ", reporter, creation_ts) " .
"VALUES (";
foreach my $field (@used_fields) {
......@@ -255,14 +254,15 @@ $comment = trim($comment);
# OK except for the fact that it causes e-mail to be suppressed.
$comment = $comment ? $comment : " ";
$sql .= "$::userid, now(), (0";
$sql .= "$::userid, now() )";
# Groups
my @groupstoadd = ();
foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
if ($::FORM{$b}) {
my $v = substr($b, 4);
$v =~ /^(\d+)$/
|| ThrowCodeError("group_bit_invalid", "abort");
|| ThrowCodeError("group_id_invalid", "abort");
if (!GroupIsActive($v)) {
# Prevent the user from adding the bug to an inactive group.
# Should only happen if there is a bug in Bugzilla or the user
......@@ -271,18 +271,22 @@ foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
$vars->{'bit'} = $v;
ThrowCodeError("inactive_group", "abort");
}
$sql .= " + $v"; # Carefully written so that the math is
# done by MySQL, which can handle 64-bit math,
# and not by Perl, which I *think* can not.
SendSQL("SELECT user_id FROM user_group_map
WHERE user_id = $::userid
AND group_id = $v
AND isbless = 0");
my ($member) = FetchSQLData();
if ($member) {
push(@groupstoadd, $v)
}
}
}
$sql .= ") & $::usergroupset)\n";
# Lock tables before inserting records for the new bug into the database
# if we are using a shadow database to prevent shadow database corruption
# when two bugs get created at the same time.
SendSQL("LOCK TABLES bugs WRITE, longdescs WRITE, cc WRITE, profiles READ") if Param("shadowdb");
SendSQL("LOCK TABLES bugs WRITE, bug_group_map WRITE, longdescs WRITE, cc WRITE, profiles READ") if Param("shadowdb");
# Add the bug report to the DB.
SendSQL($sql);
......@@ -291,6 +295,12 @@ SendSQL($sql);
SendSQL("select LAST_INSERT_ID()");
my $id = FetchOneColumn();
# Add the group restrictions
foreach my $grouptoadd (@groupstoadd) {
SendSQL("INSERT INTO bug_group_map (bug_id, group_id)
VALUES ($id, $grouptoadd)");
}
# Add the comment
SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext)
VALUES ($id, $::userid, now(), " . SqlQuote($comment) . ")");
......
......@@ -47,7 +47,6 @@ use vars qw(%versions
%settable_resolution
%target_milestone
%legal_severity
%superusergroupset
$next_bug);
ConnectToDatabase();
......@@ -143,7 +142,7 @@ if ( Param("usetargetmilestone") ) {
#
# This function checks if there is a comment required for a specific
# function and tests, if the comment was given.
# If comments are required for functions is defined by params.
# If comments are required for functions is defined by params.
#
sub CheckonComment( $ ) {
my ($function) = (@_);
......@@ -410,10 +409,8 @@ sub DuplicateUserConfirm {
SendSQL("SELECT reporter FROM bugs WHERE bug_id = " . SqlQuote($dupe));
my $reporter = FetchOneColumn();
SendSQL("SELECT profiles.groupset FROM profiles WHERE profiles.userid =".SqlQuote($reporter));
my $reportergroupset = FetchOneColumn();
if (CanSeeBug($original, $reporter, $reportergroupset)) {
if (CanSeeBug($original, $reporter)) {
$::FORM{'confirm_add_duplicate'} = "1";
return;
}
......@@ -460,9 +457,9 @@ if (defined $::FORM{'id'}) {
CheckFormFieldDefined(\%::FORM, 'longdesclength');
}
my $action = '';
my $action = '';
if (defined $::FORM{action}) {
$action = trim($::FORM{action});
$action = trim($::FORM{action});
}
if (Param("move-enabled") && $action eq Param("move-button-text")) {
$::FORM{'buglist'} = join (":", @idlist);
......@@ -564,33 +561,27 @@ sub ChangeResolution {
# operations
# If the form element isn't present, or the user isn't in the group, leave
# it as-is
if($::usergroupset ne '0') {
my $groupAdd = "0";
my $groupDel = "0";
SendSQL("SELECT bit, isactive FROM groups WHERE " .
"isbuggroup != 0 AND bit & $::usergroupset != 0 ORDER BY bit");
while (my ($b, $isactive) = FetchSQLData()) {
# The multiple change page may not show all groups a bug is in
# (eg product groups when listing more than one product)
# Only consider groups which were present on the form. We can't do this
# for single bug changes because non-checked checkboxes aren't present.
# All the checkboxes should be shown in that case, though, so its not
# an issue there
if ($::FORM{'id'} || exists $::FORM{"bit-$b"}) {
if (!$::FORM{"bit-$b"}) {
$groupDel .= "+$b";
} elsif ($::FORM{"bit-$b"} == 1 && $isactive) {
$groupAdd .= "+$b";
}
my @groupAdd = ();
my @groupDel = ();
SendSQL("SELECT groups.id, isactive FROM groups, user_group_map WHERE " .
"groups.id = user_group_map.group_id AND " .
"user_group_map.user_id = $::userid AND " .
"isbless = 0 AND isbuggroup = 1");
while (my ($b, $isactive) = FetchSQLData()) {
# The multiple change page may not show all groups a bug is in
# (eg product groups when listing more than one product)
# Only consider groups which were present on the form. We can't do this
# for single bug changes because non-checked checkboxes aren't present.
# All the checkboxes should be shown in that case, though, so its not
# an issue there
if ($::FORM{'id'} || exists $::FORM{"bit-$b"}) {
if (!$::FORM{"bit-$b"}) {
push(@groupDel, $b);
} elsif ($::FORM{"bit-$b"} == 1 && $isactive) {
push(@groupAdd, $b);
}
}
if ($groupAdd ne "0" || $groupDel ne "0") {
DoComma();
# mysql < 3.23.5 doesn't support the ~ operator, even though
# the docs say that it does
$::query .= "groupset = ((groupset & ($::superusergroupset - ($groupDel))) | ($groupAdd))";
}
}
foreach my $field ("rep_platform", "priority", "bug_severity",
......@@ -708,9 +699,9 @@ if (defined $::FORM{'qa_contact'}) {
# and cc list can see the bug even if they are not members of all groups
# to which the bug is restricted.
if ( $::FORM{'id'} ) {
SendSQL("SELECT groupset FROM bugs WHERE bug_id = $::FORM{'id'}");
my ($groupset) = FetchSQLData();
if ( $groupset ) {
SendSQL("SELECT group_id FROM bug_group_map WHERE bug_id = $::FORM{'id'}");
my ($havegroup) = FetchSQLData();
if ( $havegroup ) {
DoComma();
$::FORM{'reporter_accessible'} = $::FORM{'reporter_accessible'} ? '1' : '0';
$::query .= "reporter_accessible = $::FORM{'reporter_accessible'}";
......@@ -1047,6 +1038,8 @@ foreach my $id (@idlist) {
"profiles $write, dependencies $write, votes $write, " .
"products READ, components READ, " .
"keywords $write, longdescs $write, fielddefs $write, " .
"bug_group_map $write, " .
"user_group_map READ, " .
"keyworddefs READ, groups READ, attachments READ");
my @oldvalues = SnapShotBug($id);
my %oldhash;
......@@ -1206,9 +1199,29 @@ foreach my $id (@idlist) {
if ($::comma ne "") {
SendSQL($query);
}
my @groupAddNames = ();
foreach my $grouptoadd (@groupAdd) {
if (!BugInGroupId($id, $grouptoadd)) {
push(@groupAddNames, GroupIdToName($grouptoadd));
SendSQL("INSERT INTO bug_group_map (bug_id, group_id)
VALUES ($id, $grouptoadd)");
}
}
my @groupDelNames = ();
foreach my $grouptodel (@groupDel) {
if (BugInGroupId($id, $grouptodel)) {
push(@groupDelNames, GroupIdToName($grouptodel));
}
SendSQL("DELETE FROM bug_group_map
WHERE bug_id = $id AND group_id = $grouptodel");
}
SendSQL("select now()");
$timestamp = FetchOneColumn();
my $groupDelNames = join(',', @groupDelNames);
my $groupAddNames = join(',', @groupAddNames);
LogActivityEntry($id, "bug_group", $groupDelNames, $groupAddNames);
if (defined $::FORM{'comment'}) {
AppendComment($id, $::COOKIE{'Bugzilla_login'}, $::FORM{'comment'},
$::FORM{'commentprivacy'});
......@@ -1322,7 +1335,7 @@ foreach my $id (@idlist) {
# the user wants to add the bug to the new product's group;
($::FORM{'addtonewgroup'} eq 'yes'
|| ($::FORM{'addtonewgroup'} eq 'yesifinold'
&& GroupNameToBit($oldhash{'product'}) & $oldhash{'groupset'}))
&& BugInGroup($id, $oldhash{'product'})))
# the new product is associated with a group;
&& GroupExists($::FORM{'product'})
......@@ -1344,14 +1357,16 @@ foreach my $id (@idlist) {
&& (UserInGroup($::FORM{'product'}) || !Param('usebuggroupsentry'))
# the associated group is active, indicating it can accept new bugs;
&& GroupIsActive(GroupNameToBit($::FORM{'product'}))
&& GroupIsActive(GroupNameToId($::FORM{'product'}))
) {
# Add the bug to the group associated with its new product.
my $groupbit = GroupNameToBit($::FORM{'product'});
SendSQL("UPDATE bugs SET groupset = groupset + $groupbit WHERE bug_id = $id");
my $groupid = GroupNameToId($::FORM{'product'});
if (!BugInGroupId($id, $groupid)) {
SendSQL("INSERT INTO bug_group_map (bug_id, group_id) VALUES ($id, $groupid)");
}
}
if (
if (
# the old product is associated with a group;
GroupExists($oldhash{'product'})
......@@ -1359,8 +1374,8 @@ foreach my $id (@idlist) {
&& BugInGroup($id, $oldhash{'product'})
) {
# Remove the bug from the group associated with its old product.
my $groupbit = GroupNameToBit($oldhash{'product'});
SendSQL("UPDATE bugs SET groupset = groupset - $groupbit WHERE bug_id = $id");
my $groupid = GroupNameToId($oldhash{'product'});
SendSQL("DELETE FROM bug_group_map WHERE bug_id = $id AND group_id = $groupid");
}
}
......@@ -1523,7 +1538,7 @@ if ($::COOKIE{"BUGLIST"} && $::FORM{'id'}) {
my $cur = lsearch(\@bugs, $::FORM{"id"});
if ($cur >= 0 && $cur < $#bugs) {
my $next_bug = $bugs[$cur + 1];
if (detaint_natural($next_bug) && CanSeeBug($next_bug)) {
if (detaint_natural($next_bug) && CanSeeBug($next_bug, $::userid)) {
$::FORM{'id'} = $next_bug;
$vars->{'next_id'} = $next_bug;
......
......@@ -632,14 +632,17 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
}
SendSQL("SELECT userid, groupset " .
SendSQL("SELECT userid, (refreshed_when > " . SqlQuote($::last_changed) . ") " .
"FROM profiles WHERE login_name = " . SqlQuote($person));
my ($userid, $groupset) = (FetchSQLData());
my ($userid, $current) = (FetchSQLData());
$seen{$person} = 1;
detaint_natural($userid);
detaint_natural($groupset);
if (!$current) {
DeriveGroup($userid);
}
# if this person doesn't have permission to see info on this bug,
# return.
......@@ -649,19 +652,13 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
# see the action of restricting the bug itself; the bug will just
# quietly disappear from their radar.
#
return unless CanSeeBug($id, $userid, $groupset);
return unless CanSeeBug($id, $userid);
# Drop any non-insiders if the comment is private
if (Param("insidergroup") && ($anyprivate != 0)) {
ConnectToDatabase();
PushGlobalSQLState();
SendSQL("select (bit & $groupset ) != 0 from groups where name = " . SqlQuote(Param("insidergroup")));
my $bit = FetchOneColumn();
PopGlobalSQLState();
if (!$bit) {
return;
}
}
return if (Param("insidergroup") &&
($anyprivate != 0) &&
(!UserInGroup(Param("insidergroup"), $userid)));
# We shouldn't send changedmail if this is a dependency mail, and any of
# the depending bugs is not visible to the user.
......@@ -669,7 +666,7 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
my $save_id = $dep_id;
detaint_natural($dep_id) || warn("Unexpected Error: \@depbugs contains a non-numeric value: '$save_id'")
&& return;
return unless CanSeeBug($dep_id, $userid, $groupset);
return unless CanSeeBug($dep_id, $userid);
}
my %mailhead = %defmailhead;
......@@ -781,6 +778,14 @@ if (open(FID, "<data/nomail")) {
close FID;
}
# Since any email recipients must be rederived if the user has not
# been rederived since the most recent group change, figure out when that
# is once and determine the need to rederive users using the same DB access
# that gets the user's email address each time a person is processed.
#
SendSQL("SELECT MAX(last_changed) FROM groups");
($::last_changed) = FetchSQLData();
if ($#ARGV >= 0 && $ARGV[0] eq "regenerate") {
print "Regenerating is no longer required or supported\n";
exit;
......
......@@ -50,19 +50,19 @@ use vars qw(
);
ConnectToDatabase();
my $userid = 0;
if (defined $::FORM{"GoAheadAndLogIn"}) {
# We got here from a login page, probably from relogin.cgi. We better
# make sure the password is legit.
confirm_login();
$userid = confirm_login();
} else {
quietly_check_login();
$userid = quietly_check_login();
}
# Backwards compatibility hack -- if there are any of the old QUERY_*
# cookies around, and we are logged in, then move them into the database
# and nuke the cookie. This is required for Bugzilla 2.8 and earlier.
if ($::userid) {
if ($userid) {
my @oldquerycookies;
foreach my $i (keys %::COOKIE) {
if ($i =~ /^QUERY_(.*)$/) {
......@@ -79,12 +79,12 @@ if ($::userid) {
if ($value) {
my $qname = SqlQuote($name);
SendSQL("SELECT query FROM namedqueries " .
"WHERE userid = $::userid AND name = $qname");
"WHERE userid = $userid AND name = $qname");
my $query = FetchOneColumn();
if (!$query) {
SendSQL("REPLACE INTO namedqueries " .
"(userid, name, query) VALUES " .
"($::userid, $qname, " . SqlQuote($value) . ")");
"($userid, $qname, " . SqlQuote($value) . ")");
}
}
print "Set-Cookie: $cookiename= ; path=" . Param("cookiepath") .
......@@ -94,17 +94,17 @@ if ($::userid) {
}
if ($::FORM{'nukedefaultquery'}) {
if ($::userid) {
if ($userid) {
SendSQL("DELETE FROM namedqueries " .
"WHERE userid = $::userid AND name = '$::defaultqueryname'");
"WHERE userid = $userid AND name = '$::defaultqueryname'");
}
$::buffer = "";
}
my $userdefaultquery;
if ($::userid) {
if ($userid) {
SendSQL("SELECT query FROM namedqueries " .
"WHERE userid = $::userid AND name = '$::defaultqueryname'");
"WHERE userid = $userid AND name = '$::defaultqueryname'");
$userdefaultquery = FetchOneColumn();
}
......@@ -285,7 +285,7 @@ $vars->{'rep_platform'} = \@::legal_platform;
$vars->{'op_sys'} = \@::legal_opsys;
$vars->{'priority'} = \@::legal_priority;
$vars->{'bug_severity'} = \@::legal_severity;
$vars->{'userid'} = $::userid;
$vars->{'userid'} = $userid;
# Boolean charts
my @fields;
......@@ -332,10 +332,10 @@ for (my $chart = 0; $::FORM{"field$chart-0-0"}; $chart++) {
$default{'charts'} = \@charts;
# Named queries
if ($::userid) {
if ($userid) {
my @namedqueries;
SendSQL("SELECT name FROM namedqueries " .
"WHERE userid = $::userid AND name != '$::defaultqueryname' " .
"WHERE userid = $userid AND name != '$::defaultqueryname' " .
"ORDER BY name");
while (MoreSQLData()) {
push(@namedqueries, FetchOneColumn());
......
......@@ -109,6 +109,17 @@ sub CrossCheck {
}
}
sub DateCheck {
my $table = shift @_;
my $field = shift @_;
Status("Checking dates in $table.$field");
SendSQL("SELECT COUNT( $field ) FROM $table WHERE $field > NOW()");
my $c = FetchOneColumn();
if ($c) {
Alert("Found $c dates in future");
}
}
my @badbugs;
......@@ -139,6 +150,57 @@ if (exists $::FORM{'rebuildvotecache'}) {
Status("Vote cache has been rebuilt.");
}
if (exists $::FORM{'rederivegroups'}) {
Status("OK, All users' inherited permissions will be rechecked when " .
"they next access Bugzilla.");
SendSQL("UPDATE groups SET last_changed = NOW() LIMIT 1");
}
# rederivegroupsnow is REALLY only for testing.
if (exists $::FORM{'rederivegroupsnow'}) {
Status("OK, now rederiving groups.");
SendSQL("SELECT userid FROM profiles");
while ((my $id) = FetchSQLData()) {
DeriveGroup($id);
Status("Group $id");
}
}
if (exists $::FORM{'cleangroupsnow'}) {
Status("OK, now cleaning stale groups.");
# Only users that were out of date already long ago should be cleaned
# and the cleaning is done with tables locked. This is require in order
# to keep another session from proceeding with permission checks
# after the groups have been cleaned unless it first had an opportunity
# to get the groups up to date.
# If any page starts taking longer than one hour to load, this interval
# should be revised.
SendSQL("SELECT MAX(last_changed) FROM groups WHERE last_changed < NOW() - INTERVAL 1 HOUR");
(my $cutoff) = FetchSQLData();
Status("Cutoff is $cutoff");
SendSQL("SELECT COUNT(*) FROM user_group_map");
(my $before) = FetchSQLData();
SendSQL("LOCK TABLES user_group_map WRITE, profiles WRITE");
SendSQL("SELECT userid FROM profiles " .
"WHERE refreshed_when > 0 " .
"AND refreshed_when < " . SqlQuote($cutoff) .
" LIMIT 1000");
my $count = 0;
while ((my $id) = FetchSQLData()) {
$count++;
PushGlobalSQLState();
SendSQL("DELETE FROM user_group_map WHERE " .
"user_id = $id AND isderived = 1 AND isbless = 0");
SendSQL("UPDATE profiles SET refreshed_when = 0 WHERE userid = $id");
PopGlobalSQLState();
}
SendSQL("UNLOCK TABLES");
SendSQL("SELECT COUNT(*) FROM user_group_map");
(my $after) = FetchSQLData();
Status("Cleaned table for $count users " .
"- reduced from $before records to $after records");
}
print "OK, now running sanity checks.<p>\n";
# This one goes first, because if this is wrong, then the below tests
......@@ -178,6 +240,7 @@ CrossCheck("attachstatusdefs", "id",
CrossCheck("bugs", "bug_id",
["bugs_activity", "bug_id"],
["bug_group_map", "bug_id"],
["attachments", "bug_id"],
["cc", "bug_id"],
["longdescs", "bug_id"],
......@@ -188,6 +251,12 @@ CrossCheck("bugs", "bug_id",
["duplicates", "dupe_of", "dupe"],
["duplicates", "dupe", "dupe_of"]);
CrossCheck("groups", "id",
["bug_group_map", "group_id"],
["group_group_map", "grantor_id"],
["group_group_map", "member_id"],
["user_group_map", "group_id"]);
CrossCheck("profiles", "userid",
["bugs", "reporter", "bug_id"],
["bugs", "assigned_to", "bug_id"],
......@@ -203,6 +272,7 @@ CrossCheck("profiles", "userid",
["watch", "watched"],
["tokens", "userid"],
["components", "initialowner", "name"],
["user_group_map", "user_id"],
["components", "initialqacontact", "name", ["0"]]);
CrossCheck("products", "id",
......@@ -212,25 +282,9 @@ CrossCheck("products", "id",
["versions", "product_id", "value"],
["attachstatusdefs", "product_id", "name"]);
###########################################################################
# Perform group checks
###########################################################################
DateCheck("groups", "last_changed");
DateCheck("profiles", "refreshed_when");
Status("Checking groups");
SendSQL("select bit from groups where bit != pow(2, round(log(bit) / log(2)))");
while (my $bit = FetchOneColumn()) {
Alert("Illegal bit number found in group table: $bit");
}
SendSQL("select sum(bit) from groups where isbuggroup != 0");
my $buggroupset = FetchOneColumn();
if (!defined $buggroupset || $buggroupset eq "") {
$buggroupset = 0;
}
SendSQL("select bug_id, groupset from bugs where groupset & $buggroupset != groupset");
while (@row = FetchSQLData()) {
Alert("Bad groupset $row[1] found in bug " . BugLink($row[0]));
}
###########################################################################
# Perform product specific field checks
......
......@@ -35,10 +35,7 @@ ConnectToDatabase();
# Begin Data/Security Validation
###############################################################################
# Check whether or not the user is currently logged in. This function
# sets the value of $::usergroupset, the binary number that records
# the set of groups to which the user belongs and which we can use
# to determine whether or not the user is authorized to access this bug.
# Check whether or not the user is currently logged in.
quietly_check_login();
# Make sure the bug ID is a positive integer representing an existing
......
......@@ -31,7 +31,7 @@ ConnectToDatabase();
quietly_check_login();
use vars qw($template $vars $userid $usergroupset);
use vars qw($template $vars $userid);
my %seen;
my %edgesdone;
......@@ -128,13 +128,13 @@ foreach my $k (keys(%seen)) {
my $summary = "";
my $stat;
if ($::FORM{'showsummary'}) {
SendSQL(SelectVisible("SELECT bug_status, short_desc FROM bugs " .
"WHERE bugs.bug_id = $k",
$::userid,
$::usergroupset));
($stat, $summary) = FetchSQLData();
$stat = "NEW" if !defined $stat;
$summary = "" if !defined $summary;
if (CanSeeBug($k, $::userid)) {
SendSQL("SELECT bug_status, short_desc FROM bugs " .
"WHERE bugs.bug_id = $k");
($stat, $summary) = FetchSQLData();
$stat = "NEW" if !defined $stat;
$summary = "" if !defined $summary;
}
} else {
SendSQL("SELECT bug_status FROM bugs WHERE bug_id = $k");
$stat = FetchOneColumn();
......
......@@ -39,7 +39,6 @@ quietly_check_login();
# More warning suppression silliness.
$::userid = $::userid;
$::usergroupset = $::usergroupset;
################################################################################
# Data/Security Validation #
......@@ -144,7 +143,9 @@ sub GetBug {
# and returns it to the calling code.
my ($id) = @_;
SendSQL(SelectVisible("SELECT 1,
my $bug = {};
if (CanSeeBug($id, $::userid)) {
SendSQL("SELECT 1,
bug_status,
short_desc,
$milestone_column,
......@@ -152,18 +153,16 @@ sub GetBug {
assignee.login_name
FROM bugs, profiles AS assignee
WHERE bugs.bug_id = $id
AND bugs.assigned_to = assignee.userid",
$::userid,
$::usergroupset));
AND bugs.assigned_to = assignee.userid");
my $bug = {};
($bug->{'exists'},
$bug->{'status'},
$bug->{'summary'},
$bug->{'milestone'},
$bug->{'assignee_id'},
$bug->{'assignee_email'}) = FetchSQLData();
($bug->{'exists'},
$bug->{'status'},
$bug->{'summary'},
$bug->{'milestone'},
$bug->{'assignee_id'},
$bug->{'assignee_email'}) = FetchSQLData();
}
$bug->{'open'} = IsOpenedState($bug->{'status'});
$bug->{'dependencies'} = [];
......
......@@ -36,11 +36,11 @@ quietly_check_login();
$vars->{'username'} = $::COOKIE{'Bugzilla_login'} || '';
if (defined $::COOKIE{'Bugzilla_login'}) {
SendSQL("SELECT mybugslink, userid, blessgroupset FROM profiles " .
SendSQL("SELECT mybugslink, userid FROM profiles " .
"WHERE login_name = " . SqlQuote($::COOKIE{'Bugzilla_login'}));
my ($mybugslink, $userid, $blessgroupset) = (FetchSQLData());
my ($mybugslink, $userid) = (FetchSQLData());
$vars->{'userid'} = $userid;
$vars->{'blessgroupset'} = $blessgroupset;
$vars->{'canblessanything'} = UserCanBlessAnything();
if ($mybugslink) {
my $mybugstemplate = Param("mybugstemplate");
my %substs = ( 'userid' => url_quote($::COOKIE{'Bugzilla_login'}) );
......
......@@ -20,36 +20,48 @@
#%]
[%# INTERFACE:
# has_bits: array of strings. May be empty.
# Descriptions of the permission bits the user has.
# set_bits: array of strings. May be empty.
# Descriptions of the permission bits the user can set for
# has_bits: array of hashes. May be empty.
# name => Names of the permissions the user has.
# desc => Descriptions of the permissions the user has.
# set_bits: array of hashes. May be empty.
# name => Names of the permissions the user can set for
# other people.
# desc => Descriptions of the permissions the user can set for
# other people.
#%]
<table>
<table align="center">
<tr>
<td>
[% IF has_bits.size %]
You have the following permission bits set on your account:
<ul>
<p>
<br>
<table align="center">
[% FOREACH bit_description = has_bits %]
<li>[% bit_description %]</li>
<tr>
<td>[% bit_description.name %]</td>
<td>[% bit_description.desc %]</td>
</tr>
[% END %]
</ul>
</table>
[% ELSE %]
There are no permission bits set on your account.
[% END %]
[% IF set_bits.size %]
<br>
And you can turn on or off the following bits for
<a href="editusers.cgi">other users</a>:
<p>
<ul>
<table align="center">
[% FOREACH bit_description = set_bits %]
<li>[% bit_description %]</li>
<tr>
<td>[% bit_description.name %]</td>
<td>[% bit_description.desc %]</td>
</tr>
[% END %]
</ul>
</table>
</p>
[% END %]
</td>
......
......@@ -65,7 +65,7 @@
[% ', <a href="editparams.cgi">parameters</a>'
IF user.groups.tweakparams %]
[% ', <a href="editusers.cgi">users</a>' IF user.groups.editusers
|| (user.blessgroupset > 0) %]
|| user.canblessany %]
[% ', <a href="editproducts.cgi">products</a>'
IF user.groups.editcomponents %]
[% ', <a href="editattachstatuses.cgi"> attachment&nbsp;statuses</a>'
......
......@@ -73,7 +73,7 @@ function normal_keypress_handler( aEvent ) {
[%- IF UserInGroup('tweakparams') %]
<text class="text-link" onclick="load_relative_url('editparams.cgi')" value="edit params"/>
[%- END %]
[%- IF UserInGroup('editusers') || blessgroupset %]
[%- IF UserInGroup('editusers') || canblessany %]
<text class="text-link" onclick="load_relative_url('editusers.cgi')" value="edit users"/>
[%- END %]
[%- IF UserInGroup('editcomponents') %]
......
......@@ -265,6 +265,7 @@ sub changeEmail {
SendSQL("DELETE FROM tokens WHERE userid = $userid
AND tokentype = 'emailnew'");
SendSQL("UNLOCK TABLES");
DeriveGroup($userid);
# Return HTTP response headers.
print "Content-Type: text/html\n\n";
......@@ -300,6 +301,7 @@ sub cancelChangeEmail {
SET login_name = $quotedoldemail
WHERE userid = $userid");
SendSQL("UNLOCK TABLES");
DeriveGroup($userid);
$vars->{'message'} .=
" Your old account settings have been reinstated.";
}
......
......@@ -33,7 +33,6 @@ use RelationSet;
sub sillyness {
my $zz;
$zz = $::defaultqueryname;
$zz = $::usergroupset;
}
# Use global template variables.
......@@ -331,21 +330,22 @@ sub SaveFooter {
sub DoPermissions {
my (@has_bits, @set_bits);
SendSQL("SELECT description FROM groups " .
"WHERE bit & $::usergroupset != 0 " .
"ORDER BY bit");
SendSQL("SELECT DISTINCT name, description FROM groups, user_group_map " .
"WHERE user_group_map.group_id = groups.id " .
"AND user_id = $::userid " .
"AND isbless = 0 " .
"ORDER BY name");
while (MoreSQLData()) {
push(@has_bits, FetchSQLData());
my ($nam, $desc) = FetchSQLData();
push(@has_bits, {"desc" => $desc, "name" => $nam});
}
SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid");
my $blessgroupset = FetchOneColumn();
if ($blessgroupset) {
SendSQL("SELECT description FROM groups " .
"WHERE bit & $blessgroupset != 0 " .
"ORDER BY bit");
while (MoreSQLData()) {
push(@set_bits, FetchSQLData());
my @set_ids = ();
SendSQL("SELECT DISTINCT name, description FROM groups " .
"ORDER BY name");
while (MoreSQLData()) {
my ($nam, $desc) = FetchSQLData();
if (UserCanBlessGroup($nam)) {
push(@set_bits, {"desc" => $desc, "name" => $nam});
}
}
......
......@@ -28,7 +28,6 @@ use lib ".";
require "CGI.pl";
use vars qw($usergroupset);
# Use global template variables
use vars qw($template $vars);
......@@ -188,7 +187,7 @@ sub show_user {
# and they can see there are votes 'missing', but not on what bug
# they are. This seems a reasonable compromise; the alternative is
# to lie in the totals.
next if !CanSeeBug($id, $who, $usergroupset);
next if !CanSeeBug($id, $who);
push (@bugs, { id => $id,
summary => $summary,
......
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