Commit 9d4872be authored by bugreport%peshkin.net's avatar bugreport%peshkin.net

Bug 304583: Remove all remaining need to rederive inherited groups

Patch by Joel Peshkin <bugreport@peshkin.net> r=mkanat, a=justdave
parent d11ebe02
......@@ -38,6 +38,7 @@ sub login {
my $matched_userid = '';
my $matched_extern_id = '';
my $disabledtext = '';
my $new_login_name = 0;
my $dbh = Bugzilla->dbh;
my $sth;
......@@ -122,6 +123,7 @@ sub login {
") VALUES ( ?, ?, ?, '' )");
$sth->execute($env_email, '*', $env_realname);
$matched_userid = $dbh->bz_last_key('profiles', 'userid');
$new_login_name = $matched_userid;
}
}
}
......@@ -147,9 +149,16 @@ sub login {
($env_realname || $this_realname),
$matched_userid);
$sth->execute;
$new_login_name = $matched_userid;
}
}
# If the login name may be new, make sure the regexp groups are current
if ($new_login_name) {
my $userprofile = new Bugzilla::User($matched_userid);
$userprofile->derive_regexp_groups;
}
# Now we throw an error if the user has been disabled
if ($disabledtext) {
ThrowUserError("account_disabled",
......
......@@ -541,25 +541,22 @@ sub groups {
# user_group_map record putting the user in that group.
# The LEFT JOINs are checking for record existence.
#
my $grouplist = Bugzilla->user->groups_as_string;
my $sth = $dbh->prepare(
"SELECT DISTINCT groups.id, name, description," .
" bug_group_map.group_id IS NOT NULL," .
" user_group_map.group_id IS NOT NULL," .
" CASE WHEN groups.id IN($grouplist) THEN 1 ELSE 0 END," .
" isactive, membercontrol, othercontrol" .
" FROM groups" .
" LEFT JOIN bug_group_map" .
" ON bug_group_map.group_id = groups.id" .
" AND bug_id = ?" .
" LEFT JOIN user_group_map" .
" ON user_group_map.group_id = groups.id" .
" AND user_id = ?" .
" AND isbless = 0" .
" LEFT JOIN group_control_map" .
" ON group_control_map.group_id = groups.id" .
" AND group_control_map.product_id = ? " .
" WHERE isbuggroup = 1" .
" ORDER BY description");
$sth->execute($self->{'bug_id'}, Bugzilla->user->id,
$sth->execute($self->{'bug_id'},
$self->{'product_id'});
while (my ($groupid, $name, $description, $ison, $ingroup, $isactive,
......
......@@ -53,7 +53,6 @@ use base qw(Exporter);
LOGOUT_KEEP_CURRENT
GRANT_DIRECT
GRANT_DERIVED
GRANT_REGEXP
GROUP_MEMBERSHIP
......@@ -68,8 +67,6 @@ use base qw(Exporter);
COMMENT_COLS
DERIVE_GROUPS_TABLES_ALREADY_LOCKED
UNLOCK_ABORT
RELATIONSHIPS
......@@ -157,7 +154,6 @@ use constant contenttypes =>
};
use constant GRANT_DIRECT => 0;
use constant GRANT_DERIVED => 1;
use constant GRANT_REGEXP => 2;
use constant GROUP_MEMBERSHIP => 0;
......@@ -180,10 +176,6 @@ use constant DEFAULT_QUERY_NAME => '(Default query)';
# The column length for displayed (and wrapped) bug comments.
use constant COMMENT_COLS => 80;
# Used to indicate to User::new and User::new_from_login calls
# that the derive_groups tables are already locked
use constant DERIVE_GROUPS_TABLES_ALREADY_LOCKED => 1;
# used by Bugzilla::DB to indicate that tables are being unlocked
# because of error
use constant UNLOCK_ABORT => 1;
......
......@@ -906,9 +906,7 @@ sub notify {
{
my @new_cc_list;
foreach my $cc (split(/[, ]+/, $flag->{'type'}->{'cc_list'})) {
my $ccuser = Bugzilla::User->new_from_login($cc,
DERIVE_GROUPS_TABLES_ALREADY_LOCKED)
|| next;
my $ccuser = Bugzilla::User->new_from_login($cc) || next;
next if $flag->{'target'}->{'bug'}->{'restricted'}
&& !$ccuser->can_see_bug($flag->{'target'}->{'bug'}->{'id'});
......
......@@ -31,6 +31,7 @@
# Erik Stambaugh <erik@dasbistro.com>
# Dave Lawrence <dkl@redhat.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
# Joel Peshkin <bugreport@peshkin.net>
#
#
#
......@@ -3557,11 +3558,8 @@ AddFDef("owner_idle_time", "Time Since Assignee Touched", 0);
if ($dbh->bz_column_info("user_group_map", "isderived")) {
$dbh->bz_add_column('user_group_map', 'grant_type',
{TYPE => 'INT1', NOTNULL => 1, DEFAULT => '0'});
$dbh->do("UPDATE user_group_map SET grant_type = " .
"IF(isderived, " . GRANT_DERIVED . ", " .
GRANT_DIRECT . ")");
$dbh->do("DELETE FROM user_group_map
WHERE isbless = 0 AND grant_type != " . GRANT_DIRECT);
$dbh->do("DELETE FROM user_group_map WHERE isderived != 0");
$dbh->do("UPDATE user_group_map SET grant_type = " . GRANT_DIRECT);
$dbh->bz_drop_column("user_group_map", "isderived");
$dbh->bz_drop_index('user_group_map', 'user_group_map_user_id_idx');
......@@ -3569,21 +3567,6 @@ if ($dbh->bz_column_info("user_group_map", "isderived")) {
{TYPE => 'UNIQUE',
FIELDS => [qw(user_id group_id grant_type isbless)]});
# Evaluate regexp-based group memberships
my $sth = $dbh->prepare("SELECT profiles.userid, profiles.login_name,
groups.id, groups.userregexp
FROM profiles, groups
WHERE userregexp != ''");
$sth->execute();
my $sth2 = $dbh->prepare("INSERT IGNORE INTO user_group_map
(user_id, group_id, isbless, grant_type)
VALUES(?, ?, 0, " . GRANT_REGEXP . ")");
while (my ($uid, $login, $gid, $rexp) = $sth->fetchrow_array()) {
if ($login =~ m/$rexp/i) {
$sth2->execute($uid, $gid);
}
}
# Make sure groups get rederived
$dbh->do("UPDATE groups SET last_changed = NOW() WHERE name = 'admin'");
}
......@@ -4090,6 +4073,42 @@ if (!GroupDoesExist('bz_canusewhines')) {
GROUP_MEMBERSHIP . ")") unless $group_exists;
}
# 2005-08-14 bugreport@peshkin.net -- Bug 304583
use constant GRANT_DERIVED => 1;
# Get rid of leftover DERIVED group permissions
$dbh->do("DELETE FROM user_group_map WHERE grant_type = " . GRANT_DERIVED);
# Evaluate regexp-based group memberships
$sth = $dbh->prepare("SELECT profiles.userid, profiles.login_name,
groups.id, groups.userregexp,
user_group_map.group_id
FROM profiles
CROSS JOIN groups
LEFT JOIN user_group_map
ON user_group_map.user_id = profiles.userid
AND user_group_map.group_id = groups.id
AND user_group_map.grant_type = ?
WHERE (userregexp != ''
OR user_group_map.group_id IS NOT NULL)");
my $sth_add = $dbh->prepare("INSERT INTO user_group_map
(user_id, group_id, isbless, grant_type)
VALUES(?, ?, 0, " . GRANT_REGEXP . ")");
my $sth_del = $dbh->prepare("DELETE FROM user_group_map
WHERE user_id = ?
AND group_id = ?
AND isbless = 0
AND grant_type = " . GRANT_REGEXP);
$sth->execute(GRANT_REGEXP);
while (my ($uid, $login, $gid, $rexp, $present) = $sth->fetchrow_array()) {
if ($login =~ m/$rexp/i) {
$sth_add->execute($uid, $gid) unless $present;
} else {
$sth_del->execute($uid, $gid) if $present;
}
}
###########################################################################
# Create --SETTINGS-- users can adjust
###########################################################################
......
......@@ -56,20 +56,21 @@ sub RederiveRegexp
my $regexp = shift;
my $gid = shift;
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare("SELECT userid, login_name FROM profiles");
my $sthqry = $dbh->prepare("SELECT 1 FROM user_group_map
WHERE user_id = ? AND group_id = ?
AND grant_type = ? and isbless = 0");
my $sth = $dbh->prepare("SELECT userid, login_name, group_id
FROM profiles
LEFT JOIN user_group_map
ON user_group_map.user_id = profiles.userid
AND group_id = ?
AND grant_type = ?
AND isbless = 0");
my $sthadd = $dbh->prepare("INSERT INTO user_group_map
(user_id, group_id, grant_type, isbless)
VALUES (?, ?, ?, 0)");
my $sthdel = $dbh->prepare("DELETE FROM user_group_map
WHERE user_id = ? AND group_id = ?
AND grant_type = ? and isbless = 0");
$sth->execute();
while (my ($uid, $login) = $sth->fetchrow_array()) {
my $present = $dbh->selectrow_array($sthqry, undef,
$uid, $gid, GRANT_REGEXP);
$sth->execute($gid, GRANT_REGEXP);
while (my ($uid, $login, $present) = $sth->fetchrow_array()) {
if (($regexp =~ /\S+/) && ($login =~ m/$regexp/i))
{
$sthadd->execute($uid, $gid, GRANT_REGEXP) unless $present;
......
......@@ -185,6 +185,8 @@ if ($action eq 'search') {
insert_new_user($login, $realname, $password, $disabledtext);
$otherUserID = $dbh->bz_last_key('profiles', 'userid');
$dbh->bz_unlock_tables();
my $newprofile = new Bugzilla::User($otherUserID);
$newprofile->derive_regexp_groups();
userDataToVars($otherUserID);
$vars->{'message'} = 'account_created';
......@@ -290,6 +292,12 @@ if ($action eq 'search') {
'WHERE userid = ?',
undef, @values);
# XXX: should create profiles_activity entries.
#
# We create a new user object here because it needs to
# read information that may have changed since this
# script started.
my $newprofile = new Bugzilla::User($otherUserID);
$newprofile->derive_regexp_groups();
}
}
......@@ -639,7 +647,7 @@ sub userDataToVars {
my $query;
my $dbh = Bugzilla->dbh;
$otheruser->derive_groups();
my $grouplist = $otheruser->groups_as_string;
$vars->{'otheruser'} = $otheruser;
$vars->{'groups'} = $user->bless_groups();
......@@ -648,7 +656,7 @@ sub userDataToVars {
qq{SELECT id,
COUNT(directmember.group_id) AS directmember,
COUNT(regexpmember.group_id) AS regexpmember,
COUNT(derivedmember.group_id) AS derivedmember,
CASE WHEN groups.id IN ($grouplist) THEN 1 ELSE 0 END,
COUNT(directbless.group_id) AS directbless
FROM groups
LEFT JOIN user_group_map AS directmember
......@@ -661,11 +669,6 @@ sub userDataToVars {
AND regexpmember.user_id = ?
AND regexpmember.isbless = 0
AND regexpmember.grant_type = ?
LEFT JOIN user_group_map AS derivedmember
ON derivedmember.group_id = id
AND derivedmember.user_id = ?
AND derivedmember.isbless = 0
AND derivedmember.grant_type = ?
LEFT JOIN user_group_map AS directbless
ON directbless.group_id = id
AND directbless.user_id = ?
......@@ -675,20 +678,17 @@ sub userDataToVars {
'id', undef,
($otheruserid, GRANT_DIRECT,
$otheruserid, GRANT_REGEXP,
$otheruserid, GRANT_DERIVED,
$otheruserid, GRANT_DIRECT));
# Find indirect bless permission.
$query = qq{SELECT groups.id
FROM groups, user_group_map AS ugm, group_group_map AS ggm
WHERE ugm.user_id = ?
AND groups.id = ggm.grantor_id
AND ggm.member_id = ugm.group_id
AND ugm.isbless = 0
FROM groups, group_group_map AS ggm
WHERE groups.id = ggm.grantor_id
AND ggm.member_id IN ($grouplist)
AND ggm.grant_type = ?
} . $dbh->sql_group_by('id');
foreach (@{$dbh->selectall_arrayref($query, undef,
($otheruserid, GROUP_BLESS))}) {
(GROUP_BLESS))}) {
# Merge indirect bless permissions into permission variable.
$vars->{'permissions'}{${$_}[0]}{'indirectbless'} = 1;
}
......
......@@ -335,11 +335,7 @@ foreach my $b (grep(/^bit-\d*$/, $cgi->param())) {
$vars->{'bit'} = $v;
ThrowCodeError("inactive_group");
}
SendSQL("SELECT user_id FROM user_group_map
WHERE user_id = $::userid
AND group_id = $v
AND isbless = 0");
my ($permit) = FetchSQLData();
my ($permit) = $user->in_group_id($v);
if (!$permit) {
SendSQL("SELECT othercontrol FROM group_control_map
WHERE group_id = $v AND product_id = $product_id");
......
......@@ -73,6 +73,7 @@ use vars qw(@legal_product
my $user = Bugzilla->login(LOGIN_REQUIRED);
my $whoid = $user->id;
my $grouplist = $user->groups_as_string;
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
......@@ -704,10 +705,9 @@ sub ChangeResolution {
my @groupAdd = ();
my @groupDel = ();
SendSQL("SELECT groups.id, isactive FROM groups INNER JOIN user_group_map " .
"ON groups.id = user_group_map.group_id " .
"WHERE user_group_map.user_id = $whoid " .
"AND isbless = 0 AND isbuggroup = 1");
SendSQL("SELECT groups.id, isactive FROM groups " .
"WHERE id IN($grouplist) " .
"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)
......@@ -1560,7 +1560,7 @@ foreach my $id (@idlist) {
# - Is the bug in this group?
SendSQL("SELECT DISTINCT groups.id, isactive, " .
"oldcontrolmap.membercontrol, newcontrolmap.membercontrol, " .
"user_group_map.user_id IS NOT NULL, " .
"CASE WHEN groups_id IN ($grouplist) THEN 1 ELSE 0 END, " .
"bug_group_map.group_id IS NOT NULL " .
"FROM groups " .
"LEFT JOIN group_control_map AS oldcontrolmap " .
......@@ -1569,10 +1569,6 @@ foreach my $id (@idlist) {
" LEFT JOIN group_control_map AS newcontrolmap " .
"ON newcontrolmap.group_id = groups.id " .
"AND newcontrolmap.product_id = $newproduct_id " .
"LEFT JOIN user_group_map " .
"ON user_group_map.group_id = groups.id " .
"AND user_group_map.user_id = $whoid " .
"AND user_group_map.isbless = 0 " .
"LEFT JOIN bug_group_map " .
"ON bug_group_map.group_id = groups.id " .
"AND bug_group_map.bug_id = $id "
......
......@@ -118,66 +118,6 @@ if (defined $cgi->param('rebuildvotecache')) {
}
###########################################################################
# Fix group derivations
###########################################################################
if (defined $cgi->param('rederivegroups')) {
Status("OK, All users' inherited permissions will be rechecked when " .
"they next access Bugzilla.");
SendSQL("UPDATE groups SET last_changed = NOW() " . $dbh->sql_limit(1));
}
# rederivegroupsnow is REALLY only for testing.
# If it wasn't, then we'd do this the faster way as a per-group
# thing rather than per-user for group inheritance
if (defined $cgi->param('rederivegroupsnow')) {
require Bugzilla::User;
Status("OK, now rederiving groups.");
SendSQL("SELECT userid FROM profiles");
while ((my $id) = FetchSQLData()) {
my $user = new Bugzilla::User($id);
$user->derive_groups();
Status("User $id");
}
}
if (defined $cgi->param('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() - " .
$dbh->sql_interval('1 HOUR'));
(my $cutoff) = FetchSQLData();
Status("Cutoff is $cutoff");
SendSQL("SELECT COUNT(*) FROM user_group_map");
(my $before) = FetchSQLData();
$dbh->bz_lock_tables('user_group_map WRITE', 'profiles WRITE');
SendSQL("SELECT userid FROM profiles " .
"WHERE refreshed_when > 0 " .
"AND refreshed_when < " . SqlQuote($cutoff) . " " .
$dbh->sql_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();
}
$dbh->bz_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");
}
###########################################################################
# Create missing group_control_map entries
###########################################################################
......
......@@ -268,7 +268,7 @@ sub changeEmail {
# The email address has been changed, so we need to rederive the groups
my $user = new Bugzilla::User($userid);
$user->derive_groups;
$user->derive_regexp_groups;
# Return HTTP response headers.
print $cgi->header();
......@@ -313,7 +313,7 @@ sub cancelChangeEmail {
# issue
my $user = new Bugzilla::User($userid);
$user->derive_groups;
$user->derive_regexp_groups;
$vars->{'message'} = "email_change_cancelled_reinstated";
}
......
......@@ -311,11 +311,9 @@ sub DoPermissions {
my (@has_bits, @set_bits);
SendSQL("SELECT DISTINCT name, description FROM groups " .
"INNER JOIN user_group_map " .
"ON user_group_map.group_id = groups.id " .
"WHERE user_id = $::userid " .
"AND isbless = 0 " .
"ORDER BY name");
"WHERE id IN (" .
Bugzilla->user->groups_as_string .
") ORDER BY name");
while (MoreSQLData()) {
my ($nam, $desc) = FetchSQLData();
push(@has_bits, {"desc" => $desc, "name" => $nam});
......
......@@ -240,8 +240,7 @@ sub get_next_event {
return undef unless $fetched;
my ($eventid, $owner_id, $subject, $body) = @{$fetched};
my $owner = Bugzilla::User->new($owner_id,
DERIVE_GROUPS_TABLES_ALREADY_LOCKED);
my $owner = Bugzilla::User->new($owner_id);
my $whineatothers = $owner->in_group('bz_canusewhineatothers');
......@@ -275,10 +274,13 @@ sub get_next_event {
my $group_id = Bugzilla::Group::ValidateGroupName(
$groupname, $owner);
if ($group_id) {
my $glist = join(',',
Bugzilla::User->flatten_group_membership(
$group_id));
$sth = $dbh->prepare("SELECT user_id FROM " .
"user_group_map " .
"WHERE group_id=?");
$sth->execute($group_id);
"WHERE group_id IN ($glist)");
$sth->execute();
for my $row (@{$sth->fetchall_arrayref}) {
if (not defined $user_objects{$row->[0]}) {
$user_objects{$row->[0]} =
......
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