Bug 364780: The keyword cache cannot be fixed with editkeywords privs only - Patch by Fr��d��ric Buclin <LpSolit@gmail.com> r/a=justdave

This commit is contained in:
lpsolit%gmail.com 2006-12-26 20:17:26 +00:00
Родитель 69ee31d5eb
Коммит f79ed84aa6
4 изменённых файлов: 178 добавлений и 147 удалений

Просмотреть файл

@ -22,6 +22,7 @@
# Matthew Tuck <matty@chariot.net.au>
# Max Kanat-Alexander <mkanat@bugzilla.org>
# Marc Schumann <wurblzap@gmail.com>
# Frédéric Buclin <LpSolit@gmail.com>
use strict;
@ -78,11 +79,13 @@ Bugzilla->login(LOGIN_REQUIRED);
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
my $template = Bugzilla->template;
my $user = Bugzilla->user;
# Make sure the user is authorized to access sanitycheck.cgi.
# As this script can now alter the group_control_map table, we no longer
# let users with editbugs privs run it anymore.
Bugzilla->user->in_group("editcomponents")
$user->in_group("editcomponents")
|| ($user->in_group('editkeywords') && defined $cgi->param('rebuildkeywordcache'))
|| ThrowUserError("auth_failure", {group => "editcomponents",
action => "run",
object => "sanity_check"});
@ -93,6 +96,16 @@ my @row;
$template->put_header("Sanity Check");
###########################################################################
# Users with 'editkeywords' privs only can only check keywords.
###########################################################################
unless ($user->in_group('editcomponents')) {
check_votes_or_keywords('keywords');
Status("Sanity check completed.");
$template->put_footer();
exit;
}
###########################################################################
# Fix vote cache
###########################################################################
@ -602,164 +615,180 @@ sub AlertBadVoteCache {
Alert("Bad vote cache for bug " . BugLink($id));
}
$sth = $dbh->prepare(q{SELECT bug_id, votes, keywords
FROM bugs
WHERE votes != 0
OR keywords != ''});
$sth->execute;
check_votes_or_keywords();
my %votes;
my %bugid;
my %keyword;
sub check_votes_or_keywords {
my $check = shift || 'all';
while (my ($id, $v, $k) = $sth->fetchrow_array) {
if ($v != 0) {
$votes{$id} = $v;
}
if ($k) {
$keyword{$id} = $k;
}
}
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare(q{SELECT bug_id, votes, keywords
FROM bugs
WHERE votes != 0 OR keywords != ''});
$sth->execute;
Status("Checking cached vote counts");
$sth = $dbh->prepare(q{SELECT bug_id, SUM(vote_count)
FROM votes }.
$dbh->sql_group_by('bug_id'));
$sth->execute;
my %votes;
my %keyword;
my $offer_votecache_rebuild = 0;
while (my ($id, $v) = $sth->fetchrow_array) {
if ($v <= 0) {
Alert("Bad vote sum for bug $id");
} else {
if (!defined $votes{$id} || $votes{$id} != $v) {
AlertBadVoteCache($id);
$offer_votecache_rebuild = 1;
while (my ($id, $v, $k) = $sth->fetchrow_array) {
if ($v != 0) {
$votes{$id} = $v;
}
delete $votes{$id};
}
}
foreach my $id (keys %votes) {
AlertBadVoteCache($id);
$offer_votecache_rebuild = 1;
}
if ($offer_votecache_rebuild) {
print qq{<a href="sanitycheck.cgi?rebuildvotecache=1">Click here to rebuild the vote cache</a><p>\n};
}
Status("Checking keywords table");
my %keywordids;
my $keywords = $dbh->selectall_arrayref(q{SELECT id, name
FROM keyworddefs});
foreach my $keyword (@$keywords) {
my ($id, $name) = @$keyword;
if ($keywordids{$id}) {
Alert("Duplicate entry in keyworddefs for id $id");
}
$keywordids{$id} = 1;
if ($name =~ /[\s,]/) {
Alert("Bogus name in keyworddefs for id $id");
}
}
$sth = $dbh->prepare(q{SELECT bug_id, keywordid
FROM keywords
ORDER BY bug_id, keywordid});
$sth->execute;
my $lastid;
my $lastk;
while (my ($id, $k) = $sth->fetchrow_array) {
if (!$keywordids{$k}) {
Alert("Bogus keywordids $k found in keywords table");
}
if (defined $lastid && $id eq $lastid && $k eq $lastk) {
Alert("Duplicate keyword ids found in bug " . BugLink($id));
}
$lastid = $id;
$lastk = $k;
}
Status("Checking cached keywords");
my %realk;
if (defined $cgi->param('rebuildkeywordcache')) {
$dbh->bz_lock_tables('bugs write', 'keywords read',
'keyworddefs read');
}
my $query = q{SELECT keywords.bug_id, keyworddefs.name
FROM keywords
INNER JOIN keyworddefs
ON keyworddefs.id = keywords.keywordid
INNER JOIN bugs
ON keywords.bug_id = bugs.bug_id
ORDER BY keywords.bug_id, keyworddefs.name};
$sth = $dbh->prepare($query);
$sth->execute;
my $lastb = 0;
my @list;
while (1) {
my ($b, $k) = $sth->fetchrow_array;
if (!defined $b || $b != $lastb) {
if (@list) {
$realk{$lastb} = join(', ', @list);
if ($k) {
$keyword{$id} = $k;
}
if (!$b) {
last;
}
$lastb = $b;
@list = ();
}
push(@list, $k);
# If we only want to check keywords, skip checks about votes.
_check_votes(\%votes) unless ($check eq 'keywords');
# If we only want to check votes, skip checks about keywords.
_check_keywords(\%keyword) unless ($check eq 'votes');
}
my @badbugs = ();
sub _check_votes {
my $votes = shift;
foreach my $b (keys(%keyword)) {
if (!exists $realk{$b} || $realk{$b} ne $keyword{$b}) {
push(@badbugs, $b);
}
}
foreach my $b (keys(%realk)) {
if (!exists $keyword{$b}) {
push(@badbugs, $b);
}
}
if (@badbugs) {
@badbugs = sort {$a <=> $b} @badbugs;
Alert(scalar(@badbugs) . " bug(s) found with incorrect keyword cache: " .
BugListLinks(@badbugs));
my $sth_update = $dbh->prepare(q{UPDATE bugs
SET keywords = ?
WHERE bug_id = ?});
if (defined $cgi->param('rebuildkeywordcache')) {
Status("OK, now fixing keyword cache.");
foreach my $b (@badbugs) {
my $k = '';
if (exists($realk{$b})) {
$k = $realk{$b};
Status("Checking cached vote counts");
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare(q{SELECT bug_id, SUM(vote_count)
FROM votes }.
$dbh->sql_group_by('bug_id'));
$sth->execute;
my $offer_votecache_rebuild = 0;
while (my ($id, $v) = $sth->fetchrow_array) {
if ($v <= 0) {
Alert("Bad vote sum for bug $id");
} else {
if (!defined $votes->{$id} || $votes->{$id} != $v) {
AlertBadVoteCache($id);
$offer_votecache_rebuild = 1;
}
$sth_update->execute($k, $b);
delete $votes->{$id};
}
Status("Keyword cache fixed.");
} else {
print qq{<a href="sanitycheck.cgi?rebuildkeywordcache=1">Click here to rebuild the keyword cache</a><p>\n};
}
foreach my $id (keys %$votes) {
AlertBadVoteCache($id);
$offer_votecache_rebuild = 1;
}
if ($offer_votecache_rebuild) {
print qq{<a href="sanitycheck.cgi?rebuildvotecache=1">Click here to rebuild the vote cache</a><p>\n};
}
}
if (defined $cgi->param('rebuildkeywordcache')) {
$dbh->bz_unlock_tables();
sub _check_keywords {
my $keyword = shift;
Status("Checking keywords table");
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
my %keywordids;
my $keywords = $dbh->selectall_arrayref(q{SELECT id, name
FROM keyworddefs});
foreach (@$keywords) {
my ($id, $name) = @$_;
if ($keywordids{$id}) {
Alert("Duplicate entry in keyworddefs for id $id");
}
$keywordids{$id} = 1;
if ($name =~ /[\s,]/) {
Alert("Bogus name in keyworddefs for id $id");
}
}
my $sth = $dbh->prepare(q{SELECT bug_id, keywordid
FROM keywords
ORDER BY bug_id, keywordid});
$sth->execute;
my $lastid;
my $lastk;
while (my ($id, $k) = $sth->fetchrow_array) {
if (!$keywordids{$k}) {
Alert("Bogus keywordids $k found in keywords table");
}
if (defined $lastid && $id eq $lastid && $k eq $lastk) {
Alert("Duplicate keyword ids found in bug " . BugLink($id));
}
$lastid = $id;
$lastk = $k;
}
Status("Checking cached keywords");
if (defined $cgi->param('rebuildkeywordcache')) {
$dbh->bz_lock_tables('bugs write', 'keywords read', 'keyworddefs read');
}
my $query = q{SELECT keywords.bug_id, keyworddefs.name
FROM keywords
INNER JOIN keyworddefs
ON keyworddefs.id = keywords.keywordid
INNER JOIN bugs
ON keywords.bug_id = bugs.bug_id
ORDER BY keywords.bug_id, keyworddefs.name};
$sth = $dbh->prepare($query);
$sth->execute;
my $lastb = 0;
my @list;
my %realk;
while (1) {
my ($b, $k) = $sth->fetchrow_array;
if (!defined $b || $b != $lastb) {
if (@list) {
$realk{$lastb} = join(', ', @list);
}
last unless $b;
$lastb = $b;
@list = ();
}
push(@list, $k);
}
my @badbugs = ();
foreach my $b (keys(%$keyword)) {
if (!exists $realk{$b} || $realk{$b} ne $keyword->{$b}) {
push(@badbugs, $b);
}
}
foreach my $b (keys(%realk)) {
if (!exists $keyword->{$b}) {
push(@badbugs, $b);
}
}
if (@badbugs) {
@badbugs = sort {$a <=> $b} @badbugs;
Alert(scalar(@badbugs) . " bug(s) found with incorrect keyword cache: " .
BugListLinks(@badbugs));
my $sth_update = $dbh->prepare(q{UPDATE bugs
SET keywords = ?
WHERE bug_id = ?});
if (defined $cgi->param('rebuildkeywordcache')) {
Status("OK, now fixing keyword cache.");
foreach my $b (@badbugs) {
my $k = '';
if (exists($realk{$b})) {
$k = $realk{$b};
}
$sth_update->execute($k, $b);
}
Status("Keyword cache fixed.");
} else {
print qq{<a href="sanitycheck.cgi?rebuildkeywordcache=1">Click here to rebuild the keyword cache</a><p>\n};
}
}
if (defined $cgi->param('rebuildkeywordcache')) {
$dbh->bz_unlock_tables();
}
}
###########################################################################
@ -888,7 +917,7 @@ BugCheck("bugs INNER JOIN products ON bugs.product_id = products.id " .
Status("Checking for bad values in group_control_map");
my $groups = join(", ", (CONTROLMAPNA, CONTROLMAPSHOWN, CONTROLMAPDEFAULT,
CONTROLMAPMANDATORY));
$query = qq{
my $query = qq{
SELECT COUNT(product_id)
FROM group_control_map
WHERE membercontrol NOT IN( $groups )

Просмотреть файл

@ -122,6 +122,6 @@
[% '<link rel="Administration" title="Whining"
href="editwhines.cgi">' IF user.groups.bz_canusewhines %]
[% '<link rel="Administration" title="Sanity Check"
href="sanitycheck.cgi">' IF user.groups.tweakparams %]
href="sanitycheck.cgi">' IF user.groups.editcomponents %]
[% END %]
[% END %]

Просмотреть файл

@ -48,6 +48,8 @@
<li><span class="separator">[% sep %]</span><a href="editparams.cgi">Parameters</a></li>
[% sep = "| " %]
<li><span class="separator">[% sep %]</span><a href="editsettings.cgi">User Preferences</a></li>
[% END %]
[% IF user.groups.editcomponents %]
<li><span class="separator">[% sep %]</span><a href="sanitycheck.cgi">Sanity Check</a></li>
[% END %]
[% IF user.groups.editusers || user.can_bless %]

Просмотреть файл

@ -94,7 +94,7 @@ function normal_keypress_handler( aEvent ) {
[%- IF user.groups.bz_canusewhines %]
<text class="text-link" onclick="load_relative_url('editwhines.cgi')" value="edit whining"/>
[%- END %]
[%- IF user.groups.tweakparams %]
[%- IF user.groups.editcomponents %]
<text class="text-link" onclick="load_relative_url('sanitycheck.cgi')" value="sanity check"/>
[%- END %]
[%- IF user.authorizer.can_logout %]