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