Commit 618959cb authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 364780: The keyword cache cannot be fixed with editkeywords privs only -…

Bug 364780: The keyword cache cannot be fixed with editkeywords privs only - Patch by Fré©ric Buclin <LpSolit@gmail.com> r/a=justdave
parent f9f63fd6
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
# Matthew Tuck <matty@chariot.net.au> # Matthew Tuck <matty@chariot.net.au>
# Max Kanat-Alexander <mkanat@bugzilla.org> # Max Kanat-Alexander <mkanat@bugzilla.org>
# Marc Schumann <wurblzap@gmail.com> # Marc Schumann <wurblzap@gmail.com>
# Frédéric Buclin <LpSolit@gmail.com>
use strict; use strict;
...@@ -78,11 +79,13 @@ Bugzilla->login(LOGIN_REQUIRED); ...@@ -78,11 +79,13 @@ Bugzilla->login(LOGIN_REQUIRED);
my $cgi = Bugzilla->cgi; my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my $template = Bugzilla->template; my $template = Bugzilla->template;
my $user = Bugzilla->user;
# Make sure the user is authorized to access sanitycheck.cgi. # Make sure the user is authorized to access sanitycheck.cgi.
# As this script can now alter the group_control_map table, we no longer # As this script can now alter the group_control_map table, we no longer
# let users with editbugs privs run it anymore. # 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", || ThrowUserError("auth_failure", {group => "editcomponents",
action => "run", action => "run",
object => "sanity_check"}); object => "sanity_check"});
...@@ -94,6 +97,16 @@ my @row; ...@@ -94,6 +97,16 @@ my @row;
$template->put_header("Sanity Check"); $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 # Fix vote cache
########################################################################### ###########################################################################
...@@ -602,63 +615,81 @@ sub AlertBadVoteCache { ...@@ -602,63 +615,81 @@ sub AlertBadVoteCache {
Alert("Bad vote cache for bug " . BugLink($id)); Alert("Bad vote cache for bug " . BugLink($id));
} }
$sth = $dbh->prepare(q{SELECT bug_id, votes, keywords check_votes_or_keywords();
sub check_votes_or_keywords {
my $check = shift || 'all';
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare(q{SELECT bug_id, votes, keywords
FROM bugs FROM bugs
WHERE votes != 0 WHERE votes != 0 OR keywords != ''});
OR keywords != ''}); $sth->execute;
$sth->execute;
my %votes; my %votes;
my %bugid; my %keyword;
my %keyword;
while (my ($id, $v, $k) = $sth->fetchrow_array) { while (my ($id, $v, $k) = $sth->fetchrow_array) {
if ($v != 0) { if ($v != 0) {
$votes{$id} = $v; $votes{$id} = $v;
} }
if ($k) { if ($k) {
$keyword{$id} = $k; $keyword{$id} = $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');
} }
Status("Checking cached vote counts"); sub _check_votes {
$sth = $dbh->prepare(q{SELECT bug_id, SUM(vote_count) my $votes = shift;
Status("Checking cached vote counts");
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare(q{SELECT bug_id, SUM(vote_count)
FROM votes }. FROM votes }.
$dbh->sql_group_by('bug_id')); $dbh->sql_group_by('bug_id'));
$sth->execute; $sth->execute;
my $offer_votecache_rebuild = 0; my $offer_votecache_rebuild = 0;
while (my ($id, $v) = $sth->fetchrow_array) { while (my ($id, $v) = $sth->fetchrow_array) {
if ($v <= 0) { if ($v <= 0) {
Alert("Bad vote sum for bug $id"); Alert("Bad vote sum for bug $id");
} else { } else {
if (!defined $votes{$id} || $votes{$id} != $v) { if (!defined $votes->{$id} || $votes->{$id} != $v) {
AlertBadVoteCache($id); AlertBadVoteCache($id);
$offer_votecache_rebuild = 1; $offer_votecache_rebuild = 1;
} }
delete $votes{$id}; delete $votes->{$id};
} }
} }
foreach my $id (keys %votes) { foreach my $id (keys %$votes) {
AlertBadVoteCache($id); AlertBadVoteCache($id);
$offer_votecache_rebuild = 1; $offer_votecache_rebuild = 1;
} }
if ($offer_votecache_rebuild) { if ($offer_votecache_rebuild) {
print qq{<a href="sanitycheck.cgi?rebuildvotecache=1">Click here to rebuild the vote cache</a><p>\n}; print qq{<a href="sanitycheck.cgi?rebuildvotecache=1">Click here to rebuild the vote cache</a><p>\n};
}
} }
sub _check_keywords {
my $keyword = shift;
Status("Checking keywords table"); Status("Checking keywords table");
my $dbh = Bugzilla->dbh;
my %keywordids; my $cgi = Bugzilla->cgi;
my $keywords = $dbh->selectall_arrayref(q{SELECT id, name my %keywordids;
my $keywords = $dbh->selectall_arrayref(q{SELECT id, name
FROM keyworddefs}); FROM keyworddefs});
foreach my $keyword (@$keywords) { foreach (@$keywords) {
my ($id, $name) = @$keyword; my ($id, $name) = @$_;
if ($keywordids{$id}) { if ($keywordids{$id}) {
Alert("Duplicate entry in keyworddefs for id $id"); Alert("Duplicate entry in keyworddefs for id $id");
} }
...@@ -666,15 +697,15 @@ foreach my $keyword (@$keywords) { ...@@ -666,15 +697,15 @@ foreach my $keyword (@$keywords) {
if ($name =~ /[\s,]/) { if ($name =~ /[\s,]/) {
Alert("Bogus name in keyworddefs for id $id"); Alert("Bogus name in keyworddefs for id $id");
} }
} }
$sth = $dbh->prepare(q{SELECT bug_id, keywordid my $sth = $dbh->prepare(q{SELECT bug_id, keywordid
FROM keywords FROM keywords
ORDER BY bug_id, keywordid}); ORDER BY bug_id, keywordid});
$sth->execute; $sth->execute;
my $lastid; my $lastid;
my $lastk; my $lastk;
while (my ($id, $k) = $sth->fetchrow_array) { while (my ($id, $k) = $sth->fetchrow_array) {
if (!$keywordids{$k}) { if (!$keywordids{$k}) {
Alert("Bogus keywordids $k found in keywords table"); Alert("Bogus keywordids $k found in keywords table");
} }
...@@ -683,18 +714,15 @@ while (my ($id, $k) = $sth->fetchrow_array) { ...@@ -683,18 +714,15 @@ while (my ($id, $k) = $sth->fetchrow_array) {
} }
$lastid = $id; $lastid = $id;
$lastk = $k; $lastk = $k;
} }
Status("Checking cached keywords");
my %realk; Status("Checking cached keywords");
if (defined $cgi->param('rebuildkeywordcache')) { if (defined $cgi->param('rebuildkeywordcache')) {
$dbh->bz_lock_tables('bugs write', 'keywords read', $dbh->bz_lock_tables('bugs write', 'keywords read', 'keyworddefs read');
'keyworddefs read'); }
}
my $query = q{SELECT keywords.bug_id, keyworddefs.name my $query = q{SELECT keywords.bug_id, keyworddefs.name
FROM keywords FROM keywords
INNER JOIN keyworddefs INNER JOIN keyworddefs
ON keyworddefs.id = keywords.keywordid ON keyworddefs.id = keywords.keywordid
...@@ -702,39 +730,39 @@ my $query = q{SELECT keywords.bug_id, keyworddefs.name ...@@ -702,39 +730,39 @@ my $query = q{SELECT keywords.bug_id, keyworddefs.name
ON keywords.bug_id = bugs.bug_id ON keywords.bug_id = bugs.bug_id
ORDER BY keywords.bug_id, keyworddefs.name}; ORDER BY keywords.bug_id, keyworddefs.name};
$sth = $dbh->prepare($query); $sth = $dbh->prepare($query);
$sth->execute; $sth->execute;
my $lastb = 0; my $lastb = 0;
my @list; my @list;
while (1) { my %realk;
while (1) {
my ($b, $k) = $sth->fetchrow_array; my ($b, $k) = $sth->fetchrow_array;
if (!defined $b || $b != $lastb) { if (!defined $b || $b != $lastb) {
if (@list) { if (@list) {
$realk{$lastb} = join(', ', @list); $realk{$lastb} = join(', ', @list);
} }
if (!$b) { last unless $b;
last;
}
$lastb = $b; $lastb = $b;
@list = (); @list = ();
} }
push(@list, $k); push(@list, $k);
} }
my @badbugs = (); my @badbugs = ();
foreach my $b (keys(%keyword)) { foreach my $b (keys(%$keyword)) {
if (!exists $realk{$b} || $realk{$b} ne $keyword{$b}) { if (!exists $realk{$b} || $realk{$b} ne $keyword->{$b}) {
push(@badbugs, $b); push(@badbugs, $b);
} }
} }
foreach my $b (keys(%realk)) { foreach my $b (keys(%realk)) {
if (!exists $keyword{$b}) { if (!exists $keyword->{$b}) {
push(@badbugs, $b); push(@badbugs, $b);
} }
} }
if (@badbugs) { if (@badbugs) {
@badbugs = sort {$a <=> $b} @badbugs; @badbugs = sort {$a <=> $b} @badbugs;
Alert(scalar(@badbugs) . " bug(s) found with incorrect keyword cache: " . Alert(scalar(@badbugs) . " bug(s) found with incorrect keyword cache: " .
BugListLinks(@badbugs)); BugListLinks(@badbugs));
...@@ -756,10 +784,11 @@ if (@badbugs) { ...@@ -756,10 +784,11 @@ if (@badbugs) {
} else { } else {
print qq{<a href="sanitycheck.cgi?rebuildkeywordcache=1">Click here to rebuild the keyword cache</a><p>\n}; print qq{<a href="sanitycheck.cgi?rebuildkeywordcache=1">Click here to rebuild the keyword cache</a><p>\n};
} }
} }
if (defined $cgi->param('rebuildkeywordcache')) { if (defined $cgi->param('rebuildkeywordcache')) {
$dbh->bz_unlock_tables(); $dbh->bz_unlock_tables();
}
} }
########################################################################### ###########################################################################
...@@ -888,7 +917,7 @@ BugCheck("bugs INNER JOIN products ON bugs.product_id = products.id " . ...@@ -888,7 +917,7 @@ BugCheck("bugs INNER JOIN products ON bugs.product_id = products.id " .
Status("Checking for bad values in group_control_map"); Status("Checking for bad values in group_control_map");
my $groups = join(", ", (CONTROLMAPNA, CONTROLMAPSHOWN, CONTROLMAPDEFAULT, my $groups = join(", ", (CONTROLMAPNA, CONTROLMAPSHOWN, CONTROLMAPDEFAULT,
CONTROLMAPMANDATORY)); CONTROLMAPMANDATORY));
$query = qq{ my $query = qq{
SELECT COUNT(product_id) SELECT COUNT(product_id)
FROM group_control_map FROM group_control_map
WHERE membercontrol NOT IN( $groups ) WHERE membercontrol NOT IN( $groups )
......
...@@ -122,6 +122,6 @@ ...@@ -122,6 +122,6 @@
[% '<link rel="Administration" title="Whining" [% '<link rel="Administration" title="Whining"
href="editwhines.cgi">' IF user.groups.bz_canusewhines %] href="editwhines.cgi">' IF user.groups.bz_canusewhines %]
[% '<link rel="Administration" title="Sanity Check" [% '<link rel="Administration" title="Sanity Check"
href="sanitycheck.cgi">' IF user.groups.tweakparams %] href="sanitycheck.cgi">' IF user.groups.editcomponents %]
[% END %] [% END %]
[% END %] [% END %]
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
<li><span class="separator">[% sep %]</span><a href="editparams.cgi">Parameters</a></li> <li><span class="separator">[% sep %]</span><a href="editparams.cgi">Parameters</a></li>
[% sep = "| " %] [% sep = "| " %]
<li><span class="separator">[% sep %]</span><a href="editsettings.cgi">User Preferences</a></li> <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> <li><span class="separator">[% sep %]</span><a href="sanitycheck.cgi">Sanity Check</a></li>
[% END %] [% END %]
[% IF user.groups.editusers || user.can_bless %] [% IF user.groups.editusers || user.can_bless %]
......
...@@ -94,7 +94,7 @@ function normal_keypress_handler( aEvent ) { ...@@ -94,7 +94,7 @@ function normal_keypress_handler( aEvent ) {
[%- IF user.groups.bz_canusewhines %] [%- IF user.groups.bz_canusewhines %]
<text class="text-link" onclick="load_relative_url('editwhines.cgi')" value="edit whining"/> <text class="text-link" onclick="load_relative_url('editwhines.cgi')" value="edit whining"/>
[%- END %] [%- END %]
[%- IF user.groups.tweakparams %] [%- IF user.groups.editcomponents %]
<text class="text-link" onclick="load_relative_url('sanitycheck.cgi')" value="sanity check"/> <text class="text-link" onclick="load_relative_url('sanitycheck.cgi')" value="sanity check"/>
[%- END %] [%- END %]
[%- IF user.authorizer.can_logout %] [%- IF user.authorizer.can_logout %]
......
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