summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CGI.pl52
-rw-r--r--bug_form.pl100
-rwxr-xr-xbug_status.html16
-rwxr-xr-xbuglist.cgi19
-rwxr-xr-xchecksetup.pl82
-rw-r--r--confirmhelp.html154
-rw-r--r--defparams.pl9
-rwxr-xr-xdoeditvotes.cgi22
-rwxr-xr-xeditproducts.cgi178
-rwxr-xr-xeditusers.cgi222
-rwxr-xr-xenter_bug.cgi21
-rw-r--r--globals.pl45
-rwxr-xr-xpost_bug.cgi20
-rwxr-xr-xprocess_bug.cgi139
-rwxr-xr-xshowvotes.cgi3
-rwxr-xr-xuserprefs.cgi46
16 files changed, 942 insertions, 186 deletions
diff --git a/CGI.pl b/CGI.pl
index 157f7a9ff..af597f8bc 100644
--- a/CGI.pl
+++ b/CGI.pl
@@ -490,6 +490,9 @@ sub BuildPulldown {
if ($tag eq $default) {
$selectpart = " SELECTED";
}
+ if (!defined $desc) {
+ $desc = $tag;
+ }
$entry .= qq{<OPTION$selectpart VALUE="$tag">$desc\n};
}
$entry .= qq{</SELECT>};
@@ -515,28 +518,31 @@ sub quietly_check_login() {
$::usergroupset = '0';
my $loginok = 0;
$::disabledreason = '';
+ $::userid = 0;
if (defined $::COOKIE{"Bugzilla_login"} &&
defined $::COOKIE{"Bugzilla_logincookie"}) {
ConnectToDatabase();
if (!defined $ENV{'REMOTE_HOST'}) {
$ENV{'REMOTE_HOST'} = $ENV{'REMOTE_ADDR'};
}
- SendSQL("select profiles.groupset, profiles.login_name, " .
+ SendSQL("SELECT profiles.userid, profiles.groupset, " .
+ "profiles.login_name, " .
"profiles.login_name = " .
SqlQuote($::COOKIE{"Bugzilla_login"}) .
- " and profiles.cryptpassword = logincookies.cryptpassword " .
- "and logincookies.hostname = " .
+ " AND profiles.cryptpassword = logincookies.cryptpassword " .
+ "AND logincookies.hostname = " .
SqlQuote($ENV{"REMOTE_HOST"}) .
", profiles.disabledtext " .
- " from profiles,logincookies where logincookies.cookie = " .
+ " FROM profiles, logincookies WHERE logincookies.cookie = " .
SqlQuote($::COOKIE{"Bugzilla_logincookie"}) .
- " and profiles.userid = logincookies.userid");
+ " AND profiles.userid = logincookies.userid");
my @row;
if (@row = FetchSQLData()) {
- my ($groupset, $loginname, $ok, $disabledtext) = (@row);
+ my ($userid, $groupset, $loginname, $ok, $disabledtext) = (@row);
if ($ok) {
if ($disabledtext eq '') {
$loginok = 1;
+ $::userid = $userid;
$::usergroupset = $groupset;
$::COOKIE{"Bugzilla_login"} = $loginname; # Makes sure case
# is in
@@ -730,6 +736,7 @@ name=PleaseMailAPassword>
# Update the timestamp on our logincookie, so it'll keep on working.
SendSQL("update logincookies set lastused = null where cookie = $::COOKIE{'Bugzilla_logincookie'}");
+ return $::userid;
}
@@ -785,6 +792,37 @@ sub PutFooter {
}
+sub CheckIfVotedConfirmed {
+ my ($id, $who) = (@_);
+ SendSQL("SELECT bugs.votes, bugs.bug_status, products.votestoconfirm, " .
+ " bugs.everconfirmed " .
+ "FROM bugs, products " .
+ "WHERE bugs.bug_id = $id AND products.product = bugs.product");
+ my ($votes, $status, $votestoconfirm, $everconfirmed) = (FetchSQLData());
+ if ($votes >= $votestoconfirm && $status eq $::unconfirmedstate) {
+ SendSQL("UPDATE bugs SET bug_status = 'NEW', everconfirmed = 1 " .
+ "WHERE bug_id = $id");
+ my $fieldid = GetFieldID("bug_status");
+ SendSQL("INSERT INTO bugs_activity " .
+ "(bug_id,who,bug_when,fieldid,oldvalue,newvalue) VALUES " .
+ "($id,$who,now(),$fieldid,'$::unconfirmedstate','NEW')");
+ if (!$everconfirmed) {
+ $fieldid = GetFieldID("everconfirmed");
+ SendSQL("INSERT INTO bugs_activity " .
+ "(bug_id,who,bug_when,fieldid,oldvalue,newvalue) VALUES " .
+ "($id,$who,now(),$fieldid,'0','1')");
+ }
+ AppendComment($id, DBID_to_name($who),
+ "*** This bug has been confirmed by popular vote. ***");
+ print "<TABLE BORDER=1><TD><H2>Bug $id has been confirmed by votes.</H2>\n";
+ system("./processmail", $id);
+ print "<TD><A HREF=\"show_bug.cgi?id=$id\">Go To BUG# $id</A></TABLE>\n";
+ }
+
+}
+
+
+
sub DumpBugActivity {
my ($id, $starttime) = (@_);
my $datepart = "";
@@ -885,7 +923,7 @@ sub GetCommandMenu {
$html .= ", <a href=editparams.cgi>parameters</a>";
$html .= ", <a href=sanitycheck.cgi><NOBR>sanity check</NOBR></a>";
}
- if (UserInGroup("editusers")) {
+ if (UserInGroup("editusers") || UserInGroup("editgroupmembers")) {
$html .= ", <a href=editusers.cgi>users</a>";
}
if (UserInGroup("editcomponents")) {
diff --git a/bug_form.pl b/bug_form.pl
index c5cfd96e2..520949a36 100644
--- a/bug_form.pl
+++ b/bug_form.pl
@@ -31,13 +31,13 @@ sub bug_form_pl_sillyness {
$zz = %::components;
$zz = %::prodmaxvotes;
$zz = %::versions;
+ $zz = @::legal_keywords;
$zz = @::legal_opsys;
$zz = @::legal_platform;
$zz = @::legal_product;
$zz = @::legal_priority;
$zz = @::legal_resolution_no_dup;
$zz = @::legal_severity;
- $zz = @::keywordsbyname;
}
my %knownattachments;
@@ -194,14 +194,27 @@ if (@row = FetchSQLData()) {
exit;
}
+my $assignedtoid = $bug{'assigned_to'};
+my $reporterid = $bug{'reporter'};
+my $qacontactid = $bug{'qa_contact'};
+
$bug{'assigned_to'} = DBID_to_name($bug{'assigned_to'});
$bug{'reporter'} = DBID_to_name($bug{'reporter'});
+
+print qq{<FORM NAME="changeform" METHOD="POST" ACTION="process_bug.cgi">\n};
+
+# foreach my $i (sort(keys(%bug))) {
+# my $q = value_quote($bug{$i});
+# print qq{<INPUT TYPE="HIDDEN" NAME="orig-$i" VALUE="$q">\n};
+# }
+
$bug{'long_desc'} = GetLongDescription($id);
my $longdesclength = length($bug{'long_desc'});
-
GetVersionTable();
+
+
#
# These should be read from the database ...
#
@@ -229,11 +242,9 @@ if (defined $URL && $URL ne "none" && $URL ne "NULL" && $URL ne "") {
}
print "
-<FORM NAME=changeform METHOD=POST ACTION=\"process_bug.cgi\">
<INPUT TYPE=HIDDEN NAME=\"delta_ts\" VALUE=\"$bug{'delta_ts'}\">
<INPUT TYPE=HIDDEN NAME=\"longdesclength\" VALUE=\"$longdesclength\">
<INPUT TYPE=HIDDEN NAME=\"id\" VALUE=$id>
-<INPUT TYPE=HIDDEN NAME=\"was_assigned_to\" VALUE=\"$bug{'assigned_to'}\">
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0><TR>
<TD ALIGN=RIGHT><B>Bug#:</B></TD><TD><A HREF=\"show_bug.cgi?id=$bug{'bug_id'}\">$bug{'bug_id'}</A></TD>
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#rep_platform\">Platform:</A></B></TD>
@@ -449,50 +460,73 @@ my $knum = 1;
my $status = $bug{'bug_status'};
-if ($status eq "NEW" || $status eq "ASSIGNED" || $status eq "REOPENED") {
- if ($status ne "ASSIGNED") {
- print "<INPUT TYPE=radio NAME=knob VALUE=accept>";
- print "Accept bug (change status to <b>ASSIGNED</b>)<br>";
- $knum++;
- }
- if ($bug{'resolution'} ne "") {
- print "<INPUT TYPE=radio NAME=knob VALUE=clearresolution>\n";
- print "Clear the resolution (remove the current resolution of\n";
- print "<b>$bug{'resolution'}</b>)<br>\n";
+my $canedit = UserInGroup("editbugs");
+my $canconfirm;
+
+if ($status eq $::unconfirmedstate) {
+ $canconfirm = UserInGroup("canconfirm");
+ if ($canedit || $canconfirm) {
+ print "<INPUT TYPE=radio NAME=knob VALUE=confirm>";
+ print "Confirm bug (change status to <b>NEW</b>)<br>";
$knum++;
}
- print "<INPUT TYPE=radio NAME=knob VALUE=resolve>
+}
+
+
+if ($::userid && ($canedit || $::userid == $assignedtoid ||
+ $::userid == $reporterid || $::userid == $qacontactid)) {
+ if (IsOpenedState($status)) {
+ if ($status ne "ASSIGNED") {
+ print "<INPUT TYPE=radio NAME=knob VALUE=accept>";
+ my $extra = "";
+ if ($status eq $::unconfirmedstate && ($canconfirm || $canedit)) {
+ $extra = "confirm bug, ";
+ }
+ print "Accept bug (${extra}change status to <b>ASSIGNED</b>)<br>";
+ $knum++;
+ }
+ if ($bug{'resolution'} ne "") {
+ print "<INPUT TYPE=radio NAME=knob VALUE=clearresolution>\n";
+ print "Clear the resolution (remove the current resolution of\n";
+ print "<b>$bug{'resolution'}</b>)<br>\n";
+ $knum++;
+ }
+ print "<INPUT TYPE=radio NAME=knob VALUE=resolve>
Resolve bug, changing <A HREF=\"bug_status.html\">resolution</A> to
<SELECT NAME=resolution
ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\">
$resolution_popup</SELECT><br>\n";
- $knum++;
- print "<INPUT TYPE=radio NAME=knob VALUE=duplicate>
+ $knum++;
+ print "<INPUT TYPE=radio NAME=knob VALUE=duplicate>
Resolve bug, mark it as duplicate of bug #
<INPUT NAME=dup_id SIZE=6 ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\"><br>\n";
- $knum++;
- my $assign_element = "<INPUT NAME=\"assigned_to\" SIZE=32 ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\" VALUE=\"$bug{'assigned_to'}\">";
+ $knum++;
+ my $assign_element = "<INPUT NAME=\"assigned_to\" SIZE=32 ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\" VALUE=\"$bug{'assigned_to'}\">";
- print "<INPUT TYPE=radio NAME=knob VALUE=reassign>
+ print "<INPUT TYPE=radio NAME=knob VALUE=reassign>
<A HREF=\"bug_status.html#assigned_to\">Reassign</A> bug to
$assign_element
<br>\n";
- $knum++;
- print "<INPUT TYPE=radio NAME=knob VALUE=reassignbycomponent>
+ if ($status eq $::unconfirmedstate && ($canconfirm || $canedit)) {
+ print "&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=checkbox NAME=andconfirm> and confirm bug (change status to <b>NEW</b>)<BR>";
+ }
+ $knum++;
+ print "<INPUT TYPE=radio NAME=knob VALUE=reassignbycomponent>
Reassign bug to owner of selected component<br>\n";
- $knum++;
-} else {
- print "<INPUT TYPE=radio NAME=knob VALUE=reopen> Reopen bug<br>\n";
- $knum++;
- if ($status eq "RESOLVED") {
- print "<INPUT TYPE=radio NAME=knob VALUE=verify>
- Mark bug as <b>VERIFIED</b><br>\n";
$knum++;
- }
- if ($status ne "CLOSED") {
- print "<INPUT TYPE=radio NAME=knob VALUE=close>
- Mark bug as <b>CLOSED</b><br>\n";
+ } else {
+ print "<INPUT TYPE=radio NAME=knob VALUE=reopen> Reopen bug<br>\n";
$knum++;
+ if ($status eq "RESOLVED") {
+ print "<INPUT TYPE=radio NAME=knob VALUE=verify>
+ Mark bug as <b>VERIFIED</b><br>\n";
+ $knum++;
+ }
+ if ($status ne "CLOSED") {
+ print "<INPUT TYPE=radio NAME=knob VALUE=close>
+ Mark bug as <b>CLOSED</b><br>\n";
+ $knum++;
+ }
}
}
diff --git a/bug_status.html b/bug_status.html
index c9629ff38..6e9f044e1 100755
--- a/bug_status.html
+++ b/bug_status.html
@@ -30,7 +30,9 @@
The <B>status</B> and <B>resolution</B> field define and track the
life cycle of a bug.
+<a name="status">
<p>
+</a>
<TABLE BORDER=1 CELLPADDING=4>
<TR ALIGN=CENTER VALIGN=TOP>
@@ -42,7 +44,12 @@ certain status transitions are allowed.
<TD>The <b>resolution</b> field indicates what happened to this bug.
<TR VALIGN=TOP><TD>
-<DL><DT><B>NEW</B>
+<DL><DT><B>UNCONFIRMED</B>
+<DD> This bug has recently been added to the database. Nobody has
+ validated that this bug is true. Users who have the "canconfirm"
+ permission set may confirm this bug, changing its state to NEW.
+ Or, it may be directly resolved and marked RESOLVED.
+<DT><B>NEW</B>
<DD> This bug has recently been added to the assignee's list of bugs
and must be processed. Bugs in this state may be accepted, and
become <B>ASSIGNED</B>, passed on to someone else, and remain
@@ -60,8 +67,8 @@ certain status transitions are allowed.
</DL>
<TD>
<DL>
-<DD> No resolution yet. All bugs which are <B>NEW</B> or
- <B>ASSIGNED</B> have the resolution set to blank. All other bugs
+<DD> No resolution yet. All bugs which are in one of these "open" states
+ have the resolution set to blank. All other bugs
will be marked with one of the following resolutions.
</DL>
@@ -188,8 +195,7 @@ searching for bugs that have been resolved or verified, remember to set the
status field appropriately.
<hr>
-<address><a href="http://home.netscape.com/people/terry/">Terry Weissman &lt;terry@netscape.com&gt;</a></address>
<!-- hhmts start -->
-Last modified: Thu Jan 13 16:22:39 2000
+Last modified: Wed Feb 16 20:41:24 2000
<!-- hhmts end -->
</body> </html>
diff --git a/buglist.cgi b/buglist.cgi
index 8af1e9433..096508211 100755
--- a/buglist.cgi
+++ b/buglist.cgi
@@ -33,6 +33,7 @@ use Date::Parse;
sub sillyness {
my $zz;
$zz = $::defaultqueryname;
+ $zz = $::unconfirmedstate;
$zz = @::components;
$zz = @::default_column_list;
$zz = @::keywordsbyname;
@@ -824,6 +825,14 @@ my $dotweak = defined $::FORM{'tweak'};
if ($dotweak) {
confirm_login();
+ if (!UserInGroup("canedit")) {
+ print qq{
+Sorry; you do not have sufficient priviledges to edit a bunch of bugs
+at once.
+};
+ PutFooter();
+ exit();
+ }
} else {
quietly_check_login();
}
@@ -979,7 +988,7 @@ if ($splitheader) {
$tablestart .= "</TR>\n<TR><TD></TD>";
}
for (my $i=1-$pass ; $i<@th ; $i += 2) {
- my $h = @th[$i];
+ my $h = $th[$i];
$h =~ s/TH/TH COLSPAN="2" ALIGN="left"/;
$tablestart .= $h;
}
@@ -1287,6 +1296,12 @@ if ($::usergroupset ne '0' && $buggroupset =~ /^\d+$/) {
<INPUT TYPE=radio NAME=knob VALUE=none CHECKED>
Do nothing else<br>";
$knum++;
+ if ($statushash{$::unconfirmedstate} && 1 == scaler(keys(%statushash))) {
+ print "
+<INPUT TYPE=radio NAME=knob VALUE=confirm>
+ Confirm bugs (change status to <b>NEW</b>)<br>";
+ }
+ $knum++;
print "
<INPUT TYPE=radio NAME=knob VALUE=accept>
Accept bugs (change status to <b>ASSIGNED</b>)<br>";
@@ -1363,7 +1378,7 @@ if ($count > 0) {
<NOBR><A HREF=\"enter_bug.cgi\">Enter New Bug</A></NOBR>
&nbsp;&nbsp;
<NOBR><A HREF=\"colchange.cgi?$::buffer\">Change columns</A></NOBR>";
- if (!$dotweak && $count > 1) {
+ if (!$dotweak && $count > 1 && UserInGroup("canedit")) {
print "&nbsp;&nbsp;\n";
print "<NOBR><A HREF=\"buglist.cgi?$fields$orderpart&tweak=1\">";
print "Change several bugs at once</A></NOBR>\n";
diff --git a/checksetup.pl b/checksetup.pl
index 05bcf31ac..16f2a9c19 100755
--- a/checksetup.pl
+++ b/checksetup.pl
@@ -547,7 +547,7 @@ $table{bugs} =
assigned_to mediumint not null, # This is a comment.
bug_file_loc text,
bug_severity enum($severities) not null,
- bug_status enum("NEW", "ASSIGNED", "REOPENED", "RESOLVED", "VERIFIED", "CLOSED") not null,
+ bug_status enum("UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED", "RESOLVED", "VERIFIED", "CLOSED") not null,
creation_ts datetime not null,
delta_ts timestamp,
short_desc mediumtext,
@@ -567,6 +567,7 @@ $table{bugs} =
# the real data comes from the keywords table.
. '
lastdiffed datetime not null,
+ everconfirmed tinyint not null,
index (assigned_to),
index (creation_ts),
@@ -656,7 +657,10 @@ $table{products} =
description mediumtext,
milestoneurl tinytext not null,
disallownew tinyint not null,
- votesperuser smallint not null';
+ votesperuser smallint not null,
+ maxvotesperbug smallint not null default 10000,
+ votestoconfirm smallint not null
+';
$table{profiles} =
@@ -670,10 +674,25 @@ $table{profiles} =
disabledtext mediumtext not null,
newemailtech tinyint not null,
mybugslink tinyint not null default 1,
+ blessgroupset bigint not null,
+
unique(login_name)';
+$table{profiles_activity} =
+ 'userid mediumint not null,
+ who mediumint not null,
+ profiles_when datetime not null,
+ fieldid mediumint not null,
+ oldvalue tinytext,
+ newvalue tinytext,
+
+ index (userid),
+ index (profiles_when),
+ index (fieldid)';
+
+
$table{namedqueries} =
'userid mediumint not null,
name varchar(64) not null,
@@ -775,22 +794,31 @@ while (my ($tabname, $fielddef) = each %table) {
# Populate groups table
###########################################################################
+sub GroupExists ($)
+{
+ my ($name) = @_;
+ my $sth = $dbh->prepare("SELECT name FROM groups WHERE name='$name'");
+ $sth->execute;
+ if ($sth->rows) {
+ return 1;
+ }
+ return 0;
+}
+
+
#
# This subroutine checks if a group exist. If not, it will be automatically
# created with the next available bit set
#
-sub AddGroup ($$)
-{
- my ($name, $desc) = @_;
+sub AddGroup {
+ my ($name, $desc, $userregexp) = @_;
+ $userregexp ||= "";
- # does the group exist?
- my $sth = $dbh->prepare("SELECT name FROM groups WHERE name='$name'");
- $sth->execute;
- return if $sth->rows;
+ return if GroupExists($name);
# get highest bit number
- $sth = $dbh->prepare("SELECT bit FROM groups ORDER BY bit DESC");
+ my $sth = $dbh->prepare("SELECT bit FROM groups ORDER BY bit DESC");
$sth->execute;
my @row = $sth->fetchrow_array;
@@ -807,21 +835,31 @@ sub AddGroup ($$)
$sth = $dbh->prepare('INSERT INTO groups
(bit, name, description, userregexp)
VALUES (?, ?, ?, ?)');
- $sth->execute($bit, $name, $desc, "");
+ $sth->execute($bit, $name, $desc, $userregexp);
+ return $bit;
}
#
-# BugZilla uses --GROUPS-- to assign various rights to it's users.
+# BugZilla uses --GROUPS-- to assign various rights to its users.
#
AddGroup 'tweakparams', 'Can tweak operating parameters';
AddGroup 'editusers', 'Can edit or disable users';
-AddGroup 'editgroupmembers', 'Can put people in and out of groups that they are members of.';
AddGroup 'creategroups', 'Can create and destroy groups.';
AddGroup 'editcomponents', 'Can create, destroy, and edit components.';
AddGroup 'editkeywords', 'Can create, destroy, and edit keywords.';
+if (!GroupExists("editbugs")) {
+ my $id = AddGroup('editbugs', 'Can edit all aspects of any bug.', ".*");
+ $dbh->do("UPDATE profiles SET groupset = groupset | $id");
+}
+
+if (!GroupExists("canconfirm")) {
+ my $id = AddGroup('canconfirm', 'Can confirm a bug.', ".*");
+ $dbh->do("UPDATE profiles SET groupset = groupset | $id");
+}
+
@@ -1427,6 +1465,24 @@ AddField('profiles', 'mybugslink', 'tinyint not null default 1');
AddField('namedqueries', 'linkinfooter', 'tinyint not null');
+# 2000-02-12 Added a new state to bugs, UNCONFIRMED. Added ability to confirm
+# a vote via bugs. Added user bits to control which users can confirm bugs
+# by themselves, and which users can edit bugs without their names on them.
+# Added a user field which controls which groups a user can put other users
+# into.
+
+my @states = ("UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED", "RESOLVED",
+ "VERIFIED", "CLOSED");
+CheckEnumField('bugs', 'bug_status', @states);
+if (!GetFieldDef('bugs', 'everconfirmed')) {
+ AddField('bugs', 'everconfirmed', 'tinyint not null');
+ $dbh->do("UPDATE bugs SET everconfirmed = 1");
+}
+AddField('products', 'maxvotesperbug', 'smallint not null default 10000');
+AddField('products', 'votestoconfirm', 'smallint not null');
+AddField('profiles', 'blessgroupset', 'bigint not null');
+
+
#
# If you had to change the --TABLE-- definition in any way, then add your
# differential change code *** A B O V E *** this comment.
diff --git a/confirmhelp.html b/confirmhelp.html
new file mode 100644
index 000000000..5c8e64434
--- /dev/null
+++ b/confirmhelp.html
@@ -0,0 +1,154 @@
+<HTML><head>
+
+<!--
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The Original Code is the Bugzilla Bug Tracking System.
+
+ The Initial Developer of the Original Code is Netscape Communications
+ Corporation. Portions created by Netscape are
+ Copyright (C) 2000 Netscape Communications Corporation. All
+ Rights Reserved.
+
+ Contributor(s): Terry Weissman <terry@mozilla.org>
+-->
+
+<title>Understanding the UNCONFIRMED state, and other recent changes</title>
+</head>
+
+<body>
+<h1>Understanding the UNCONFIRMED state, and other recent changes</h1>
+
+[This document is aimed primarily at people who have used Bugzilla
+before the UNCONFIRMED state was implemented. It might be helpful for
+newer users as well.]
+
+<p>
+
+New bugs in some products will now show up in a new state,
+UNCONFIRMED. This means that we have nobody has confirmed that the
+bug is real. Very busy engineers will probably generally ignore
+UNCONFIRMED that have been assigned to them, until they have been
+confirmed in one way or another. (Engineers with more time will
+hopefully glance over their UNCONFIRMED bugs regularly.)
+
+<p>
+
+The <a href="bug_status.html">page describing bug fields</a> has been
+updated to include UNCONFIRMED.
+<p>
+
+There are two basic ways that a bug can become confirmed (and enter
+the NEW) state.
+
+<ul>
+ <li> A user with the appropriate permissions (see below for more on
+ permissions) decides that the bug is a valid one, and confirms
+ it. We hope to gather a small army of responsible volunteers
+ to regularly go through bugs for us.
+ <li> The bug gathers a certain number of votes. <b>Any</b> valid
+ Bugzilla user may vote for bugs (each user gets a certain
+ number of bugs); any UNCONFIRMED bug which enough bugs becomes
+ automatically confirmed, and enters the NEW state.
+</ul>
+
+One implication of this is that it is worth your time to search the
+bug system for duplicates of your bug to vote on them, before
+submitting your own bug. If we can spread around knowledge of this
+fact, it ought to help cut down the number of duplicate bugs in the
+system.
+
+<h2>Permissions.</h2>
+
+Users now have a certain set of permissions. To see your permissions,
+check out the
+<a href="userprefs.cgi?bank=permissions">user preferences</a> page.
+
+<p>
+
+If you have the "Can confirm a bug" permission, then you will be able
+to move UNCONFIRMED bugs into the NEW state.
+
+<p>
+
+If you have the "Can edit all aspects of any bug" permission, then you
+can tweak anything about any bug. If not, you may only edit those
+bugs that you have submitted, or that you have assigned to you (or
+qa-assigned to you). However, anyone may add a comment to any bug.
+
+<p>
+
+Some people (initially, the initial owners and initial qa-contacts for
+components in the system) have the ability to give the above two
+permissions to other people. So, if you really feel that you ought to
+have one of these permissions, a good person to ask (via private
+email, please!) is the person who is assigned a relevant bug.
+
+<h2>Other details.</h2>
+
+An initial stab was taken to decide who would be given which of the
+above permissions. This was determined by some simple heurstics of
+who was assigned bugs, and who the default owners of bugs were, and a
+look at people who seem to have submitted several bugs that appear to
+have been interesting and valid. Inevitably, we have failed to give
+someone the permissions they deserve. Please don't take it
+personally; just bear with us as we shake out the new system.
+
+<p>
+
+
+People with one of the two bits above can easily confirm their own
+bugs, so bugs they submit will actually start out in the NEW state.
+They can override this when submitting a bug.
+
+<p>
+
+People can ACCEPT or RESOLVE a bug assigned to them, even if they
+aren't allowed to confirm it. However, the system remembers, and if
+the bug gets REOPENED or reassigned to someone else, it will revert
+back to the UNCONFIRMED state. If the bug has ever been confirmed,
+then REOPENing or reassigning will cause it to go to the NEW or
+REOPENED state.
+
+<p>
+
+Note that only some products support the UNCONFIRMED state. In other
+products, all new bugs will automatically start in the NEW state.
+
+<h2>Things still to be done.</h2>
+
+There probably ought to be a way to get a bug back into the
+UNCONFIRMED state, but there isn't yet.
+
+<p>
+
+If a person has submitted several bugs that get confirmed, then this
+is probably a person who understands the system well, and deserves the
+"Can confirm a bug" permission. This kind of person should be
+detected and promoted automatically.
+
+<p>
+
+There should also be a way to automatically promote people to get the
+"Can edit all aspects of any bug" permission.
+
+<p>
+
+The "enter a new bug" page needs to be revamped with easy ways for new
+people to educate themselves on the benefit of searching for a bug
+like the one they're about to submit and voting on it, rather than
+adding a new useless duplicate.
+
+<hr>
+<!-- hhmts start -->
+Last modified: Wed Feb 16 21:04:56 2000
+<!-- hhmts end -->
+</body> </html>
diff --git a/defparams.pl b/defparams.pl
index 742ca3746..c5cf400e0 100644
--- a/defparams.pl
+++ b/defparams.pl
@@ -428,7 +428,7 @@ DefParam("expectbigqueries",
0);
DefParam("emailregexp",
- 'This defines the regexp to use for legal email addresses. The default tries to match fully qualified email addresses. Another popular value to put here is <tt>^[^@, ]$</tt>, which means "local usernames, no @ allowed.',
+ 'This defines the regexp to use for legal email addresses. The default tries to match fully qualified email addresses. Another popular value to put here is <tt>^[^@, ]*$</tt>, which means "local usernames, no @ allowed.',
"t",
q:^[^@, ]*@[^@, ]*\\.[^@, ]*$:);
@@ -444,7 +444,7 @@ DefParam("emailsuffix",
DefParam("voteremovedmail",
-q{This is a mail message to send to anyone who gets a vote removed from a bug for any reason. %to% gets replaced by a comma-separated list of people who used to be voting for this bug. %bugid% gets replaced by the bug number. %reason% gets replaced by a short reason describing why the vote was removed. %<i>anythingelse</i>% gets replaced by the definition of thatparameter (as defined on this page).},
+q{This is a mail message to send to anyone who gets a vote removed from a bug for any reason. %to% gets replaced by a comma-separated list of people who used to be voting for this bug. %bugid% gets replaced by the bug number. %reason% gets replaced by a short reason describing why the vote was removed. %count% is how many votes got removed.%<i>anythingelse</i>% gets replaced by the definition of that parameter (as defined on this page).},
"l",
"From: bugzilla-daemon
To: %to%
@@ -454,6 +454,8 @@ You used to have a vote on bug %bugid%, but it has been removed.
Reason: %reason%
+Votes removed: %count%
+
%urlbase%show_bug.cgi?id=%bugid%
");
@@ -488,6 +490,9 @@ DefParam("commentonaccept",
DefParam("commentonclearresolution",
"If this option is on, the user needs to enter a short comment if the bugs resolution is cleared",
"b", 0 );
+DefParam("commentonconfirm",
+ "If this option is on, the user needs to enter a short comment when confirming a bug",
+ "b", 0 );
DefParam("commentonresolve",
"If this option is on, the user needs to enter a short comment if the bug is resolved",
"b", 0 );
diff --git a/doeditvotes.cgi b/doeditvotes.cgi
index eef6381d8..3902f9118 100755
--- a/doeditvotes.cgi
+++ b/doeditvotes.cgi
@@ -63,17 +63,27 @@ foreach my $id (@buglist) {
}
}
-SendSQL("select bug_id, product from bugs where bug_id = " .
- join(" or bug_id = ", @buglist));
+SendSQL("SELECT bugs.bug_id, bugs.product, products.maxvotesperbug " .
+ "FROM bugs, products " .
+ "WHERE products.product = bugs.product ".
+ " AND bugs.bug_id IN (" . join(", ", @buglist) . ")");
my %prodcount;
while (MoreSQLData()) {
- my ($id, $prod) = (FetchSQLData());
+ my ($id, $prod, $max) = (FetchSQLData());
if (!defined $prodcount{$prod}) {
$prodcount{$prod} = 0;
}
$prodcount{$prod} += $::FORM{$id};
+ if ($::FORM{$id} > $max) {
+ PutHeader("Don't overstuff!", "Illegal vote");
+ print "You may only use at most $max votes for a single bug in the\n";
+ print "<tt>$prod</tt> product, but you are using $::FORM{$id}.\n";
+ print "<P>Please click <b>Back</b> and try again.<hr>\n";
+ PutFooter();
+ exit();
+ }
}
foreach my $prod (keys(%prodcount)) {
@@ -81,7 +91,7 @@ foreach my $prod (keys(%prodcount)) {
PutHeader("Don't overstuff!", "Illegal vote");
print "You may only use $::prodmaxvotes{$prod} votes for bugs in the\n";
print "<tt>$prod</tt> product, but you are using $prodcount{$prod}.\n";
- print "Please click <b>Back</b> and try again.<hr>\n";
+ print "<P>Please click <b>Back</b> and try again.<hr>\n";
PutFooter();
exit();
}
@@ -110,10 +120,12 @@ foreach my $id (keys %affected) {
SendSQL("unlock tables");
-
PutHeader("Voting tabulated", "Voting tabulated", $::COOKIE{'Bugzilla_login'});
print "Your votes have been recorded.\n";
print qq{<p><a href="showvotes.cgi?user=$who">Review your votes</a><hr>\n};
+foreach my $id (keys %affected) {
+ CheckIfVotedConfirmed($id, $who);
+}
PutFooter();
exit();
diff --git a/editproducts.cgi b/editproducts.cgi
index e9c5f9f35..d224077b3 100755
--- a/editproducts.cgi
+++ b/editproducts.cgi
@@ -32,7 +32,13 @@ use strict;
require "CGI.pl";
require "globals.pl";
+# Shut up misguided -w warnings about "used only once". "use vars" just
+# doesn't work for me.
+sub sillyness {
+ my $zz;
+ $zz = $::unconfirmedstate;
+}
# TestProduct: just returns if the specified product does exists
@@ -72,10 +78,10 @@ sub CheckProduct ($)
# Displays the form to edit a products parameters
#
-sub EmitFormElements ($$$$$)
+sub EmitFormElements ($$$$$$$)
{
my ($product, $description, $milestoneurl, $disallownew,
- $votesperuser) = @_;
+ $votesperuser, $maxvotesperbug, $votestoconfirm) = @_;
$product = value_quote($product);
$description = value_quote($description);
@@ -102,6 +108,14 @@ sub EmitFormElements ($$$$$)
print "</TR><TR>\n";
print " <TH ALIGN=\"right\">Maximum votes per person:</TH>\n";
print " <TD><INPUT SIZE=5 MAXLENGTH=5 NAME=\"votesperuser\" VALUE=\"$votesperuser\"></TD>\n";
+
+ print "</TR><TR>\n";
+ print " <TH ALIGN=\"right\">Maximum votes a person can put on a single bug:</TH>\n";
+ print " <TD><INPUT SIZE=5 MAXLENGTH=5 NAME=\"maxvotesperbug\" VALUE=\"$maxvotesperbug\"></TD>\n";
+
+ print "</TR><TR>\n";
+ print " <TH ALIGN=\"right\">Number of votes a bug in this product needs to automatically get out of the <A HREF=\"bug_status.html#status\">UNCONFIRMED</A> state:</TH>\n";
+ print " <TD><INPUT SIZE=5 MAXLENGTH=5 NAME=\"votestoconfirm\" VALUE=\"$votestoconfirm\"></TD>\n";
}
@@ -173,7 +187,7 @@ unless ($action) {
PutHeader("Select product");
SendSQL("SELECT products.product,description,disallownew,
- votesperuser,COUNT(bug_id)
+ votesperuser,maxvotesperbug,votestoconfirm,COUNT(bug_id)
FROM products LEFT JOIN bugs
ON products.product=bugs.product
GROUP BY products.product
@@ -183,12 +197,14 @@ unless ($action) {
print " <TH ALIGN=\"left\">Description</TH>\n";
print " <TH ALIGN=\"left\">Status</TH>\n";
print " <TH ALIGN=\"left\">Votes<br>per<br>user</TH>\n";
+ print " <TH ALIGN=\"left\">Max<br>Votes<br>per<br>bug</TH>\n";
+ print " <TH ALIGN=\"left\">Votes<br>to<br>confirm</TH>\n";
print " <TH ALIGN=\"left\">Bugs</TH>\n";
print " <TH ALIGN=\"left\">Action</TH>\n";
print "</TR>";
while ( MoreSQLData() ) {
my ($product, $description, $disallownew, $votesperuser,
- $bugs) = FetchSQLData();
+ $maxvotesperbug, $votestoconfirm, $bugs) = FetchSQLData();
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
$disallownew = $disallownew ? 'closed' : 'open';
$bugs ||= 'none';
@@ -197,6 +213,8 @@ unless ($action) {
print " <TD VALIGN=\"top\">$description</TD>\n";
print " <TD VALIGN=\"top\">$disallownew</TD>\n";
print " <TD VALIGN=\"top\" ALIGN=\"right\">$votesperuser</TD>\n";
+ print " <TD VALIGN=\"top\" ALIGN=\"right\">$maxvotesperbug</TD>\n";
+ print " <TD VALIGN=\"top\" ALIGN=\"right\">$votestoconfirm</TD>\n";
print " <TD VALIGN=\"top\" ALIGN=\"right\">$bugs</TD>\n";
print " <TD VALIGN=\"top\"><A HREF=\"editproducts.cgi?action=del&product=", url_quote($product), "\">Delete</A></TD>\n";
print "</TR>";
@@ -227,7 +245,7 @@ if ($action eq 'add') {
print "<FORM METHOD=POST ACTION=editproducts.cgi>\n";
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
- EmitFormElements('', '', '', 0, 0);
+ EmitFormElements('', '', '', 0, 0, 10000, 0);
print "</TR><TR>\n";
print " <TH ALIGN=\"right\">Version:</TH>\n";
@@ -283,16 +301,21 @@ if ($action eq 'new') {
$disallownew = 1 if $::FORM{disallownew};
my $votesperuser = $::FORM{votesperuser};
$votesperuser ||= 0;
+ my $maxvotesperbug = $::FORM{maxvotesperbug};
+ $maxvotesperbug = 10000 if !defined $maxvotesperbug;
+ my $votestoconfirm = $::FORM{votestoconfirm};
+ $votestoconfirm ||= 0;
# Add the new product.
SendSQL("INSERT INTO products ( " .
- "product, description, milestoneurl, disallownew, votesperuser" .
+ "product, description, milestoneurl, disallownew, votesperuser, " .
+ "maxvotesperbug, votestoconfirm" .
" ) VALUES ( " .
SqlQuote($product) . "," .
SqlQuote($description) . "," .
SqlQuote($milestoneurl) . "," .
$disallownew . "," .
- SqlQuote($votesperuser) . ")" );
+ "$votesperuser, $maxvotesperbug, $votestoconfirm)");
SendSQL("INSERT INTO versions ( " .
"value, program" .
" ) VALUES ( " .
@@ -513,17 +536,19 @@ if ($action eq 'edit') {
CheckProduct($product);
# get data of product
- SendSQL("SELECT description,milestoneurl,disallownew,votesperuser
+ SendSQL("SELECT description,milestoneurl,disallownew,
+ votesperuser,maxvotesperbug,votestoconfirm
FROM products
WHERE product=" . SqlQuote($product));
- my ($description, $milestoneurl, $disallownew, $votesperuser) =
+ my ($description, $milestoneurl, $disallownew,
+ $votesperuser, $maxvotesperbug, $votestoconfirm) =
FetchSQLData();
print "<FORM METHOD=POST ACTION=editproducts.cgi>\n";
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
EmitFormElements($product, $description, $milestoneurl, $disallownew,
- $votesperuser);
+ $votesperuser, $maxvotesperbug, $votestoconfirm);
print "</TR><TR VALIGN=top>\n";
print " <TH ALIGN=\"right\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "\">Edit components:</A></TH>\n";
@@ -586,6 +611,8 @@ if ($action eq 'edit') {
value_quote($milestoneurl) . "\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"disallownewold\" VALUE=\"$disallownew\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"votesperuserold\" VALUE=\"$votesperuser\">\n";
+ print "<INPUT TYPE=HIDDEN NAME=\"maxvotesperbugold\" VALUE=\"$maxvotesperbug\">\n";
+ print "<INPUT TYPE=HIDDEN NAME=\"votestoconfirmold\" VALUE=\"$votestoconfirm\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
@@ -606,18 +633,30 @@ if ($action eq 'edit') {
if ($action eq 'update') {
PutHeader("Update product");
- my $productold = trim($::FORM{productold} || '');
- my $description = trim($::FORM{description} || '');
- my $descriptionold = trim($::FORM{descriptionold} || '');
- my $disallownew = trim($::FORM{disallownew} || '');
- my $disallownewold = trim($::FORM{disallownewold} || '');
- my $milestoneurl = trim($::FORM{milestoneurl} || '');
- my $milestoneurlold = trim($::FORM{milestoneurlold} || '');
- my $votesperuser = trim($::FORM{votesperuser} || 0);
- my $votesperuserold = trim($::FORM{votesperuserold} || '');
+ my $productold = trim($::FORM{productold} || '');
+ my $description = trim($::FORM{description} || '');
+ my $descriptionold = trim($::FORM{descriptionold} || '');
+ my $disallownew = trim($::FORM{disallownew} || '');
+ my $disallownewold = trim($::FORM{disallownewold} || '');
+ my $milestoneurl = trim($::FORM{milestoneurl} || '');
+ my $milestoneurlold = trim($::FORM{milestoneurlold} || '');
+ my $votesperuser = trim($::FORM{votesperuser} || 0);
+ my $votesperuserold = trim($::FORM{votesperuserold} || '');
+ my $maxvotesperbug = trim($::FORM{maxvotesperbug} || 0);
+ my $maxvotesperbugold = trim($::FORM{maxvotesperbugold} || '');
+ my $votestoconfirm = trim($::FORM{votestoconfirm} || 0);
+ my $votestoconfirmold = trim($::FORM{votestoconfirmold} || '');
+
+ my $checkvotes = 0;
CheckProduct($productold);
+ if ($maxvotesperbug !~ /^\d+$/ || $maxvotesperbug <= 0) {
+ print "Sorry, the max votes per bug must be a positive integer.";
+ PutTrailer($localtrailer);
+ exit;
+ }
+
# Note that the order of this tests is important. If you change
# them, be sure to test for WHERE='$product' or WHERE='$productold'
@@ -659,9 +698,31 @@ if ($action eq 'update') {
SET votesperuser=$votesperuser
WHERE product=" . SqlQuote($productold));
print "Update votes per user.<BR>\n";
+ $checkvotes = 1;
}
+ if ($maxvotesperbug ne $maxvotesperbugold) {
+ SendSQL("UPDATE products
+ SET maxvotesperbug=$maxvotesperbug
+ WHERE product=" . SqlQuote($productold));
+ print "Update max votes per bug.<BR>\n";
+ $checkvotes = 1;
+ }
+
+
+ if ($votestoconfirm ne $votestoconfirmold) {
+ SendSQL("UPDATE products
+ SET votestoconfirm=$votestoconfirm
+ WHERE product=" . SqlQuote($productold));
+ print "Update votes to confirm.<BR>\n";
+ $checkvotes = 1;
+ }
+
+
+ my $qp = SqlQuote($product);
+ my $qpold = SqlQuote($productold);
+
if ($product ne $productold) {
unless ($product) {
print "Sorry, I can't delete the product name.";
@@ -676,24 +737,79 @@ if ($action eq 'update') {
exit;
}
- SendSQL("UPDATE bugs
- SET product=" . SqlQuote($product) . "
- WHERE product=" . SqlQuote($productold));
- SendSQL("UPDATE components
- SET program=" . SqlQuote($product) . "
- WHERE program=" . SqlQuote($productold));
- SendSQL("UPDATE products
- SET product=" . SqlQuote($product) . "
- WHERE product=" . SqlQuote($productold));
- SendSQL("UPDATE versions
- SET program='$product'
- WHERE program=" . SqlQuote($productold));
+ SendSQL("UPDATE bugs SET product=$qp WHERE product=$qpold");
+ SendSQL("UPDATE components SET program=$qp WHERE program=$qpold");
+ SendSQL("UPDATE products SET product=$qp WHERE product=$qpold");
+ SendSQL("UPDATE versions SET program=$qp WHERE program=$qpold");
print "Updated product name.<BR>\n";
}
unlink "data/versioncache";
SendSQL("UNLOCK TABLES");
+ if ($checkvotes) {
+ print "Checking existing votes in this product for anybody who now has too many votes.";
+ if ($maxvotesperbug < $votesperuser) {
+ SendSQL("SELECT votes.who, votes.bug_id " .
+ "FROM votes, bugs " .
+ "WHERE bugs.bug_id = votes.bug_id " .
+ " AND bugs.product = $qp " .
+ " AND votes.count > $maxvotesperbug");
+ my @list;
+ while (MoreSQLData()) {
+ my ($who, $id) = (FetchSQLData());
+ push(@list, [$who, $id]);
+ }
+ foreach my $ref (@list) {
+ my ($who, $id) = (@$ref);
+ RemoveVotes($id, $who, "The rules for voting on this product has changed;\nyou had too many votes for a single bug.");
+ my $name = DBID_to_name($who);
+ print qq{<br>Removed votes for bug <A HREF="show_bug.cgi?id=$id">$id</A> from $name\n};
+ }
+ }
+ SendSQL("SELECT votes.who, votes.count FROM votes, bugs " .
+ "WHERE bugs.bug_id = votes.bug_id " .
+ " AND bugs.product = $qp");
+ my %counts;
+ while (MoreSQLData()) {
+ my ($who, $count) = (FetchSQLData());
+ if (!defined $counts{$who}) {
+ $counts{$who} = $count;
+ } else {
+ $counts{$who} += $count;
+ }
+ }
+ foreach my $who (keys(%counts)) {
+ if ($counts{$who} > $votesperuser) {
+ SendSQL("SELECT votes.bug_id FROM votes, bugs " .
+ "WHERE bugs.bug_id = votes.bug_id " .
+ " AND bugs.product = $qp " .
+ " AND votes.who = $who");
+ while (MoreSQLData()) {
+ my $id = FetchSQLData();
+ RemoveVotes($id, $who,
+ "The rules for voting on this product has changed; you had too many\ntotal votes, so all votes have been removed.");
+ my $name = DBID_to_name($who);
+ print qq{<br>Removed votes for bug <A HREF="show_bug.cgi?id=$id">$id</A> from $name\n};
+ }
+ }
+ }
+ SendSQL("SELECT bug_id FROM bugs " .
+ "WHERE product = $qp " .
+ " AND bug_status = '$::unconfirmedstate' " .
+ " AND votes >= $votestoconfirm");
+ my @list;
+ while (MoreSQLData()) {
+ push(@list, FetchOneColumn());
+ }
+ foreach my $id (@list) {
+ SendSQL("SELECT who FROM votes WHERE bug_id = $id");
+ my $who = FetchOneColumn();
+ CheckIfVotedConfirmed($id, $who);
+ }
+
+ }
+
PutTrailer($localtrailer);
exit;
}
diff --git a/editusers.cgi b/editusers.cgi
index f4a6c4dfb..03819ec35 100755
--- a/editusers.cgi
+++ b/editusers.cgi
@@ -31,7 +31,16 @@ use strict;
require "CGI.pl";
require "globals.pl";
+# Shut up misguided -w warnings about "used only once". "use vars" just
+# doesn't work for me.
+sub sillyness {
+ my $zz;
+ $zz = $::userid;
+}
+
+my $editall;
+my $opblessgroupset = '9223372036854775807'; # This is all 64 bits.
@@ -69,59 +78,81 @@ sub CheckUser ($)
+sub EmitElement ($$)
+{
+ my ($name, $value) = (@_);
+ $value = value_quote($value);
+ if ($editall) {
+ print qq{<TD><INPUT SIZE=64 MAXLENGTH=255 NAME="$name" VALUE="$value"></TD>\n};
+ } else {
+ print qq{<TD>$value</TD>\n};
+ }
+}
+
+
#
# Displays the form to edit a user parameters
#
-sub EmitFormElements ($$$$$$)
+sub EmitFormElements ($$$$$$$)
{
- my ($user, $password, $realname, $groupset, $emailnotification,
- $disabledtext) = @_;
+ my ($user, $password, $realname, $groupset, $blessgroupset,
+ $emailnotification, $disabledtext) = @_;
print " <TH ALIGN=\"right\">Login name:</TH>\n";
- print " <TD><INPUT SIZE=64 MAXLENGTH=255 NAME=\"user\" VALUE=\"$user\"></TD>\n";
+ EmitElement("user", $user);
print "</TR><TR>\n";
print " <TH ALIGN=\"right\">Real name:</TH>\n";
- print " <TD><INPUT SIZE=64 MAXLENGTH=255 NAME=\"realname\" VALUE=\"$realname\"></TD>\n";
-
- print "</TR><TR>\n";
- print " <TH ALIGN=\"right\">Password:</TH>\n";
- print " <TD><INPUT SIZE=16 MAXLENGTH=16 NAME=\"password\" VALUE=\"$password\"></TD>\n";
-
- print "</TR><TR>\n";
- print " <TH ALIGN=\"right\">Email notification:</TH>\n";
- print qq{<TD><SELECT NAME="emailnotification">};
- foreach my $i (["ExcludeSelfChanges", "All qualifying bugs except those which I change"],
- ["CConly", "Only those bugs which I am listed on the CC line"],
- ["All", "All qualifying bugs"]) {
- my ($tag, $desc) = (@$i);
- my $selectpart = "";
- if ($tag eq $emailnotification) {
- $selectpart = " SELECTED";
+ EmitElement("realname", $realname);
+
+ if ($editall) {
+ print "</TR><TR>\n";
+ print " <TH ALIGN=\"right\">Password:</TH>\n";
+ print " <TD><INPUT SIZE=16 MAXLENGTH=16 NAME=\"password\" VALUE=\"$password\"></TD>\n";
+
+ print "</TR><TR>\n";
+ print " <TH ALIGN=\"right\">Email notification:</TH>\n";
+ print qq{<TD><SELECT NAME="emailnotification">};
+ foreach my $i (["ExcludeSelfChanges", "All qualifying bugs except those which I change"],
+ ["CConly", "Only those bugs which I am listed on the CC line"],
+ ["All", "All qualifying bugs"]) {
+ my ($tag, $desc) = (@$i);
+ my $selectpart = "";
+ if ($tag eq $emailnotification) {
+ $selectpart = " SELECTED";
+ }
+ print qq{<OPTION$selectpart VALUE="$tag">$desc\n};
}
- print qq{<OPTION$selectpart VALUE="$tag">$desc\n};
+ print "</SELECT></TD>\n";
+ print "</TR><TR>\n";
+ print " <TH ALIGN=\"right\">Disable text:</TH>\n";
+ print " <TD ROWSPAN=2><TEXTAREA NAME=\"disabledtext\" ROWS=10 COLS=60>" .
+ value_quote($disabledtext) . "</TEXTAREA>\n";
+ print " </TD>\n";
+ print "</TR><TR>\n";
+ print " <TD VALIGN=\"top\">If non-empty, then the account will\n";
+ print "be disabled, and this text should explain why.</TD>\n";
}
- print "</SELECT></TD>\n";
- print "</TR><TR>\n";
- print " <TH ALIGN=\"right\">Disable text:</TH>\n";
- print " <TD ROWSPAN=2><TEXTAREA NAME=\"disabledtext\" ROWS=10 COLS=60>" .
- value_quote($disabledtext) . "</TEXTAREA>\n";
- print " </TD>\n";
- print "</TR><TR>\n";
- print " <TD VALIGN=\"top\">If non-empty, then the account will\n";
- print "be disabled, and this text should explain why.</TD>\n";
-
-
- SendSQL("SELECT bit,name,description,bit & $groupset != 0
- FROM groups
- ORDER BY name");
+
+
+ SendSQL("SELECT bit,name,description,bit & $groupset != 0, " .
+ " bit & $blessgroupset " .
+ "FROM groups " .
+ "WHERE bit & $opblessgroupset != 0 " .
+ "ORDER BY name");
while (MoreSQLData()) {
- my ($bit,$name,$description,$checked) = FetchSQLData();
+ my ($bit,$name,$description,$checked,$blchecked) = FetchSQLData();
print "</TR><TR>\n";
print " <TH ALIGN=\"right\">", ucfirst($name), ":</TH>\n";
$checked = ($checked) ? "CHECKED" : "";
print " <TD><INPUT TYPE=CHECKBOX NAME=\"bit_$name\" $checked VALUE=\"$bit\"> $description</TD>\n";
+ if ($editall) {
+ print "</TR><TR>\n";
+ print "<TH></TH>";
+ $blchecked = ($blchecked) ? "CHECKED" : "";
+ print "<TD><INPUT TYPE=CHECKBOX NAME=\"blbit_$name\" $blchecked VALUE=\"$bit\"> Can turn this bit on for other users</TD>\n";
+ }
}
}
@@ -165,12 +196,19 @@ confirm_login();
print "Content-type: text/html\n\n";
-unless (UserInGroup("editusers")) {
- PutHeader("Not allowed");
- print "Sorry, you aren't a member of the 'editusers' group.\n";
- print "And so, you aren't allowed to add, modify or delete users.\n";
- PutTrailer();
- exit;
+$editall = UserInGroup("editusers");
+
+if (!$editall) {
+ SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $::userid");
+ $opblessgroupset = FetchOneColumn();
+ if (!$opblessgroupset) {
+ PutHeader("Not allowed");
+ print "Sorry, you aren't a member of the 'editusers' group, and you\n";
+ print "don't have permissions to put people in or out of any group.\n";
+ print "And so, you aren't allowed to add, modify or delete users.\n";
+ PutTrailer();
+ exit;
+ }
}
@@ -198,8 +236,8 @@ List users with login name matching:
<INPUT SIZE=32 NAME="matchstr">
<SELECT NAME="matchtype">
<OPTION VALUE="substr" SELECTED>case-insensitive substring
-<OPTION VALUE="regexp" SELECTED>case-sensitive regexp
-<OPTION VALUE="notregexp" SELECTED>not (case-sensitive regexp)
+<OPTION VALUE="regexp">case-sensitive regexp
+<OPTION VALUE="notregexp">not (case-sensitive regexp)
</SELECT>
<BR>
<INPUT TYPE=SUBMIT VALUE="Submit">
@@ -261,14 +299,17 @@ if ($action eq 'list') {
}
print "</TR>";
}
- print "<TR>\n";
- my $span = $candelete ? 3 : 2;
- print qq{
+ if ($editall) {
+ print "<TR>\n";
+ my $span = $candelete ? 3 : 2;
+ print qq{
<TD VALIGN="top" COLSPAN=$span ALIGN="right">
<A HREF=\"editusers.cgi?action=add\">Add a new user</A>
</TD>
};
- print "</TR></TABLE>\n";
+ print "</TR>";
+ }
+ print "</TABLE>\n";
print "$count users found.\n";
PutTrailer($localtrailer);
@@ -286,11 +327,16 @@ if ($action eq 'list') {
if ($action eq 'add') {
PutHeader("Add user");
+ if (!$editall) {
+ print "Sorry, you don't have permissions to add new users.";
+ PutTrailer();
+ exit;
+ }
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
- EmitFormElements('', '', '', 0, 'ExcludeSelfChanges', '');
+ EmitFormElements('', '', '', 0, 0, 'ExcludeSelfChanges', '');
print "</TR></TABLE>\n<HR>\n";
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
@@ -312,6 +358,12 @@ if ($action eq 'add') {
if ($action eq 'new') {
PutHeader("Adding new user");
+ if (!$editall) {
+ print "Sorry, you don't have permissions to add new users.";
+ PutTrailer();
+ exit;
+ }
+
# Cleanups and valididy checks
my $realname = trim($::FORM{realname} || '');
my $password = trim($::FORM{password} || '');
@@ -386,6 +438,11 @@ if ($action eq 'del') {
print "Sorry, deleting users isn't allowed.";
PutTrailer();
}
+ if (!$editall) {
+ print "Sorry, you don't have permissions to delete users.";
+ PutTrailer();
+ exit;
+ }
CheckUser($user);
# display some data about the user
@@ -515,6 +572,11 @@ if ($action eq 'delete') {
print "Sorry, deleting users isn't allowed.";
PutTrailer();
}
+ if (!$editall) {
+ print "Sorry, you don't have permissions to delete users.";
+ PutTrailer();
+ exit;
+ }
CheckUser($user);
SendSQL("SELECT userid
@@ -545,25 +607,28 @@ if ($action eq 'edit') {
CheckUser($user);
# get data of user
- SendSQL("SELECT password, realname, groupset, emailnotification,
- disabledtext
+ SendSQL("SELECT password, realname, groupset, blessgroupset,
+ emailnotification, disabledtext
FROM profiles
WHERE login_name=" . SqlQuote($user));
- my ($password, $realname, $groupset, $emailnotification,
+ my ($password, $realname, $groupset, $blessgroupset, $emailnotification,
$disabledtext) = FetchSQLData();
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
- EmitFormElements($user, $password, $realname, $groupset,
+ EmitFormElements($user, $password, $realname, $groupset, $blessgroupset,
$emailnotification, $disabledtext);
print "</TR></TABLE>\n";
print "<INPUT TYPE=HIDDEN NAME=\"userold\" VALUE=\"$user\">\n";
- print "<INPUT TYPE=HIDDEN NAME=\"passwordold\" VALUE=\"$password\">\n";
+ if ($editall) {
+ print "<INPUT TYPE=HIDDEN NAME=\"passwordold\" VALUE=\"$password\">\n";
+ }
print "<INPUT TYPE=HIDDEN NAME=\"realnameold\" VALUE=\"$realname\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"groupsetold\" VALUE=\"$groupset\">\n";
+ print "<INPUT TYPE=HIDDEN NAME=\"blessgroupsetold\" VALUE=\"$blessgroupset\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"emailnotificationold\" VALUE=\"$emailnotification\">\n";
print "<INPUT TYPE=HIDDEN NAME=\"disabledtextold\" VALUE=\"" .
value_quote($disabledtext) . "\">\n";
@@ -583,7 +648,7 @@ if ($action eq 'edit') {
#
if ($action eq 'update') {
- PutHeader("Update User");
+ PutHeader("Updated user");
my $userold = trim($::FORM{userold} || '');
my $realname = trim($::FORM{realname} || '');
@@ -595,12 +660,19 @@ if ($action eq 'update') {
my $disabledtext = trim($::FORM{disabledtext} || '');
my $disabledtextold = trim($::FORM{disabledtextold} || '');
my $groupsetold = trim($::FORM{groupsetold} || '');
+ my $blessgroupsetold = trim($::FORM{blessgroupsetold} || '');
my $groupset = "0";
foreach (keys %::FORM) {
next unless /^bit_/;
#print "$_=$::FORM{$_}<br>\n";
- $groupset .= "+ $::FORM{$_}";
+ $groupset .= " + $::FORM{$_}";
+ }
+ my $blessgroupset = "0";
+ foreach (keys %::FORM) {
+ next unless /^blbit_/;
+ #print "$_=$::FORM{$_}<br>\n";
+ $blessgroupset .= " + $::FORM{$_}";
}
CheckUser($userold);
@@ -608,34 +680,58 @@ if ($action eq 'update') {
# Note that the order of this tests is important. If you change
# them, be sure to test for WHERE='$product' or WHERE='$productold'
- if ($groupset != $groupsetold) {
+ if ($groupset ne $groupsetold) {
SendSQL("UPDATE profiles
- SET groupset=" . $groupset . "
+ SET groupset =
+ groupset - (groupset & $opblessgroupset) + $groupset
WHERE login_name=" . SqlQuote($userold));
+
+ # I'm paranoid that someone who I give the ability to bless people
+ # will start misusing it. Let's log who blesses who (even though
+ # nothing actually uses this log right now).
+ my $fieldid = GetFieldID("groupset");
+ SendSQL("SELECT userid, groupset FROM profiles WHERE login_name=" .
+ SqlQuote($userold));
+ my $u;
+ ($u, $groupset) = (FetchSQLData());
+ if ($groupset ne $groupsetold) {
+ SendSQL("INSERT INTO profiles_activity " .
+ "(userid,who,profiles_when,fieldid,oldvalue,newvalue)" .
+ "VALUES " .
+ "($u, $::userid, now(), $fieldid, " .
+ " $groupsetold, $groupset)");
+ }
print "Updated permissions.\n";
}
- if ($emailnotification ne $emailnotificationold) {
+ if ($editall && $blessgroupset ne $blessgroupsetold) {
+ SendSQL("UPDATE profiles
+ SET blessgroupset=" . $blessgroupset . "
+ WHERE login_name=" . SqlQuote($userold));
+ print "Updated ability to tweak permissions of other users.\n";
+ }
+
+ if ($editall && $emailnotification ne $emailnotificationold) {
SendSQL("UPDATE profiles
SET emailnotification=" . SqlQuote($emailnotification) . "
WHERE login_name=" . SqlQuote($userold));
print "Updated email notification.<BR>\n";
}
- if ($password ne $passwordold) {
+ if ($editall && $password ne $passwordold) {
my $q = SqlQuote($password);
SendSQL("UPDATE profiles
SET password= $q, cryptpassword = ENCRYPT($q)
WHERE login_name=" . SqlQuote($userold));
print "Updated password.<BR>\n";
}
- if ($realname ne $realnameold) {
+ if ($editall && $realname ne $realnameold) {
SendSQL("UPDATE profiles
SET realname=" . SqlQuote($realname) . "
WHERE login_name=" . SqlQuote($userold));
print "Updated real name.<BR>\n";
}
- if ($disabledtext ne $disabledtextold) {
+ if ($editall && $disabledtext ne $disabledtextold) {
SendSQL("UPDATE profiles
SET disabledtext=" . SqlQuote($disabledtext) . "
WHERE login_name=" . SqlQuote($userold));
@@ -647,7 +743,7 @@ if ($action eq 'update') {
WHERE userid=" . $userid);
print "Updated disabled text.<BR>\n";
}
- if ($user ne $userold) {
+ if ($editall && $user ne $userold) {
unless ($user) {
print "Sorry, I can't delete the user's name.";
PutTrailer($localtrailer);
diff --git a/enter_bug.cgi b/enter_bug.cgi
index 57d9d0de3..45ca19de5 100755
--- a/enter_bug.cgi
+++ b/enter_bug.cgi
@@ -204,7 +204,6 @@ PutHeader ("Enter Bug","Enter Bug","This page lets you enter a new bug into Bugz
print "
<FORM METHOD=POST ACTION=\"post_bug.cgi\">
-<INPUT TYPE=HIDDEN NAME=bug_status VALUE=NEW>
<INPUT TYPE=HIDDEN NAME=reporter VALUE=\"$::COOKIE{'Bugzilla_login'}\">
<INPUT TYPE=HIDDEN NAME=product VALUE=\"" . value_quote($product) . "\">
<TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0>";
@@ -260,6 +259,26 @@ print "
<td></td>
</TR>
<tr><td>&nbsp<td> <td> <td> <td> <td> </tr>
+";
+
+if (UserInGroup("canedit") || UserInGroup("canconfirm")) {
+ SendSQL("SELECT votestoconfirm FROM products WHERE product = " .
+ SqlQuote($product));
+ if (FetchOneColumn()) {
+ print qq{
+ <TR>
+ <TD ALIGN="right"><B><A HREF="bug_status.html#status">Initial state:</B></A></TD>
+ <TD COLSPAN="5">
+};
+ print BuildPulldown("bug_status",
+ [[$::unconfirmedstate], ["NEW"]],
+ "NEW");
+ print "</TD></TR>";
+ }
+}
+
+
+print "
<tr>
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#assigned_to\">Assigned To:</A></B></TD>
<TD colspan=5>$assign_element
diff --git a/globals.pl b/globals.pl
index 2f88d41a8..cbfc87357 100644
--- a/globals.pl
+++ b/globals.pl
@@ -73,6 +73,7 @@ $::param{'version'} = '2.9';
$::dontchange = "--do_not_change--";
$::chooseone = "--Choose_one:--";
$::defaultqueryname = "(Default query)";
+$::unconfirmedstate = "UNCONFIRMED";
sub ConnectToDatabase {
if (!defined $::db) {
@@ -644,7 +645,7 @@ sub UserInGroup {
sub IsOpenedState {
my ($state) = (@_);
- if ($state =~ /^(NEW|REOPENED|ASSIGNED)$/) {
+ if ($state =~ /^(NEW|REOPENED|ASSIGNED)$/ || $state eq $::unconfirmedstate) {
return 1;
}
return 0;
@@ -652,24 +653,42 @@ sub IsOpenedState {
sub RemoveVotes {
- my ($id, $reason) = (@_);
+ my ($id, $who, $reason) = (@_);
ConnectToDatabase();
- SendSQL("select profiles.login_name from votes, profiles where votes.bug_id = $id and profiles.userid = votes.who");
+ my $whopart = "";
+ if ($who) {
+ $whopart = " AND votes.who = $who";
+ }
+ SendSQL("SELECT profiles.login_name, votes.count " .
+ "FROM votes, profiles " .
+ "WHERE votes.bug_id = $id " .
+ "AND profiles.userid = votes.who" .
+ $whopart);
my @list;
while (MoreSQLData()) {
- push(@list, FetchOneColumn());
+ my ($name, $count) = (@_);
+ push(@list, [$name, $count]);
}
if (0 < @list) {
- if (open(SENDMAIL, "|/usr/lib/sendmail -t")) {
- my %substs;
- $substs{"to"} = join(',', @list);
- $substs{"bugid"} = $id;
- $substs{"reason"} = $reason;
- print SENDMAIL PerformSubsts(Param("voteremovedmail"), \%substs);
- close SENDMAIL;
+ foreach my $ref (@list) {
+ my ($name, $count) = (@$ref);
+ if (open(SENDMAIL, "|/usr/lib/sendmail -t")) {
+ my %substs;
+ $substs{"to"} = $name;
+ $substs{"bugid"} = $id;
+ $substs{"reason"} = $reason;
+ $substs{"count"} = $count;
+ print SENDMAIL PerformSubsts(Param("voteremovedmail"),
+ \%substs);
+ close SENDMAIL;
+ }
}
- SendSQL("delete from votes where bug_id = $id");
- SendSQL("update bugs set votes = 0, delta_ts=delta_ts where bug_id = $id");
+ SendSQL("DELETE FROM votes WHERE bug_id = $id" . $whopart);
+ SendSQL("SELECT SUM(count) FROM votes WHERE bug_id = $id");
+ my $v = FetchOneColumn();
+ $v ||= 0;
+ SendSQL("UPDATE bugs SET votes = $v, delta_ts = delta_ts " .
+ "WHERE bug_id = $id");
}
}
diff --git a/post_bug.cgi b/post_bug.cgi
index c3be5c67b..18b579119 100755
--- a/post_bug.cgi
+++ b/post_bug.cgi
@@ -120,12 +120,32 @@ if (Param("useqacontact")) {
+if (exists $::FORM{'bug_status'}) {
+ if (!UserInGroup("canedit") && !UserInGroup("canconfirm")) {
+ delete $::FORM{'bug_status'};
+ }
+}
+
+if (!exists $::FORM{'bug_status'}) {
+ $::FORM{'bug_status'} = $::unconfirmedstate;
+ SendSQL("SELECT votestoconfirm FROM products WHERE product = " .
+ SqlQuote($::FORM{'product'}));
+ if (!FetchOneColumn()) {
+ $::FORM{'bug_status'} = "NEW";
+ }
+}
+
+
my @used_fields;
foreach my $f (@bug_fields) {
if (exists $::FORM{$f}) {
push (@used_fields, $f);
}
}
+if (exists $::FORM{'bug_status'} && $::FORM{'bug_status'} ne $::unconfirmedstate) {
+ push(@used_fields, "everconfirmed");
+ $::FORM{'everconfirmed'} = 1;
+}
my $query = "insert into bugs (\n" . join(",\n", @used_fields) . ",
creation_ts )
diff --git a/process_bug.cgi b/process_bug.cgi
index 9eb32e129..52fc5b423 100755
--- a/process_bug.cgi
+++ b/process_bug.cgi
@@ -24,6 +24,9 @@
use diagnostics;
use strict;
+my $UserInEditGroupSet = -1;
+my $UserInCanConfirmGroupSet = -1;
+
require "CGI.pl";
# Shut up misguided -w warnings about "used only once":
@@ -38,7 +41,7 @@ use vars %::versions,
%::legal_priority,
%::legal_severity;
-confirm_login();
+my $whoid = confirm_login();
print "Content-type: text/html\n\n";
@@ -103,6 +106,97 @@ if ($::FORM{'product'} ne $::dontchange) {
}
+# Checks that the user is allowed to change the given field. Actually, right
+# now, the rules are pretty simple, and don't look at the field itself very
+# much, but that could be enhanced.
+
+my $lastbugid = 0;
+my $ownerid;
+my $reporterid;
+my $qacontactid;
+
+sub CheckCanChangeField {
+ my ($f, $bugid, $oldvalue, $newvalue) = (@_);
+ if ($f eq "assigned_to" || $f eq "reporter" || $f eq "qa_contact") {
+ if ($oldvalue =~ /^\d+$/) {
+ if ($oldvalue == 0) {
+ $oldvalue = "";
+ } else {
+ $oldvalue = DBID_to_name($oldvalue);
+ }
+ }
+ }
+ if ($oldvalue eq $newvalue) {
+ return 1;
+ }
+ if ($f =~ /^longdesc/) {
+ return 1;
+ }
+ if ($UserInEditGroupSet < 0) {
+ $UserInEditGroupSet = UserInGroup("editbugs");
+ }
+ if ($UserInEditGroupSet) {
+ return 1;
+ }
+ if ($lastbugid != $bugid) {
+ SendSQL("SELECT reporter, assigned_to, qa_contact FROM bugs " .
+ "WHERE bug_id = $bugid");
+ ($reporterid, $ownerid, $qacontactid) = (FetchSQLData());
+ }
+ if ($reporterid eq $whoid || $ownerid eq $whoid || $qacontactid eq $whoid) {
+ if ($f ne "bug_status") {
+ return 1;
+ }
+ if ($newvalue eq $::unconfirmedstate || !IsOpenedState($newvalue)) {
+ return 1;
+ }
+
+ # Hmm. They are trying to set this bug to some opened state
+ # that isn't the UNCONFIRMED state. Are they in the right
+ # group? Or, has it ever been confirmed? If not, then this
+ # isn't legal.
+
+ if ($UserInCanConfirmGroupSet < 0) {
+ $UserInCanConfirmGroupSet = UserInGroup("canconfirm");
+ }
+ if ($UserInCanConfirmGroupSet) {
+ return 1;
+ }
+ my $fieldid = GetFieldID("bug_status");
+ SendSQL("SELECT newvalue FROM bugs_activity " .
+ "WHERE fieldid = $fieldid " .
+ " AND oldvalue = '$::unconfirmedstate'");
+ while (MoreSQLData()) {
+ my $n = FetchOneColumn();
+ if (IsOpenedState($n) && $n ne $::unconfirmedstate) {
+ return 1;
+ }
+ }
+ }
+ SendSQL("UNLOCK TABLES");
+ $oldvalue = value_quote($oldvalue);
+ $newvalue = value_quote($newvalue);
+ print qq{
+<H1>Sorry, not allowed.</H1>
+Only the owner or submitter of the bug, or a sufficiently
+empowered user, may make that change to the $f field.
+<TABLE>
+<TR><TH ALIGN="right">Old value:</TH><TD>$oldvalue</TD></TR>
+<TR><TH ALIGN="right">New value:</TH><TD>$newvalue</TD></TR>
+</TABLE>
+<pre>($reporterid eq $whoid || $ownerid eq $whoid || $qacontactid eq $whoid)</PRE>
+
+<P>Click <B>Back</B> and try again.
+};
+ PutFooter();
+ exit();
+}
+
+
+
+
+
+
my @idlist;
if (defined $::FORM{'id'}) {
@@ -160,11 +254,29 @@ sub DoComma {
$::comma = ",";
}
+sub DoConfirm {
+ if ($UserInEditGroupSet < 0) {
+ $UserInEditGroupSet = UserInGroup("editbugs");
+ }
+ if ($UserInCanConfirmGroupSet < 0) {
+ $UserInCanConfirmGroupSet = UserInGroup("canconfirm");
+ }
+ if ($UserInEditGroupSet || $UserInCanConfirmGroupSet) {
+ DoComma();
+ $::query .= "everconfirmed = 1";
+ }
+}
+
+
sub ChangeStatus {
my ($str) = (@_);
if ($str ne $::dontchange) {
DoComma();
- $::query .= "bug_status = '$str'";
+ if (IsOpenedState($str)) {
+ $::query .= "bug_status = IF(everconfirmed = 1, '$str', '$::unconfirmedstate')";
+ } else {
+ $::query .= "bug_status = '$str'";
+ }
}
}
@@ -192,7 +304,7 @@ sub CheckonComment( $ ) {
if( $ret ) {
if (!defined $::FORM{'comment'} || $::FORM{'comment'} =~ /^\s*$/) {
- # No commet - sorry, action not allowed !
+ # No comment - sorry, action not allowed !
warnBanner("You have to specify a <b>comment</b> on this change." .
"<p>" .
"Please press <b>Back</b> and give some words " .
@@ -275,11 +387,17 @@ SWITCH: for ($::FORM{'knob'}) {
/^none$/ && do {
last SWITCH;
};
+ /^confirm$/ && CheckonComment( "confirm" ) && do {
+ DoConfirm();
+ ChangeStatus('NEW');
+ last SWITCH;
+ };
/^accept$/ && CheckonComment( "accept" ) && do {
+ DoConfirm();
ChangeStatus('ASSIGNED');
last SWITCH;
};
- /^clearresolution$/ && CheckonComment( "clearresolution" ) &&do {
+ /^clearresolution$/ && CheckonComment( "clearresolution" ) && do {
ChangeResolution('');
last SWITCH;
};
@@ -289,6 +407,9 @@ SWITCH: for ($::FORM{'knob'}) {
last SWITCH;
};
/^reassign$/ && CheckonComment( "reassign" ) && do {
+ if ($::FORM{'andconfirm'}) {
+ DoConfirm();
+ }
ChangeStatus('NEW');
DoComma();
if ( Param("strictvaluechecks") ) {
@@ -460,7 +581,6 @@ sub SnapShotDeps {
}
-my $whoid = DBNameToIdAndCheck($::FORM{'who'});
my $timestamp;
sub LogDependencyActivity {
@@ -489,6 +609,13 @@ foreach my $id (@idlist) {
"keywords $write, longdescs $write, fielddefs $write, " .
"keyworddefs READ, groups READ");
my @oldvalues = SnapShotBug($id);
+ my $i = 0;
+ foreach my $col (@::log_columns) {
+ if (exists $::FORM{$col}) {
+ CheckCanChangeField($col, $id, $oldvalues[$i], $::FORM{$col});
+ }
+ $i++;
+ }
if (defined $::FORM{'delta_ts'} && $::FORM{'delta_ts'} ne $delta_ts) {
print "
@@ -730,7 +857,7 @@ The changes made were:
# updates about this bug.
}
if ($col eq 'product') {
- RemoveVotes($id,
+ RemoveVotes($id, 0,
"This bug has been moved to a different product");
}
$col = GetFieldID($col);
diff --git a/showvotes.cgi b/showvotes.cgi
index 429c71545..894baafbb 100755
--- a/showvotes.cgi
+++ b/showvotes.cgi
@@ -84,8 +84,7 @@ if (defined $::FORM{'bug_id'}) {
if (!defined $status) {
next;
}
- my $opened = ($status eq "NEW" || $status eq "ASSIGNED" ||
- $status eq "REOPENED");
+ my $opened = IsOpenedState($status);
my $strike = $opened ? "" : "<strike>";
my $endstrike = $opened ? "" : "</strike>";
$summary = html_quote($summary);
diff --git a/userprefs.cgi b/userprefs.cgi
index 0ee7d576f..88f032192 100755
--- a/userprefs.cgi
+++ b/userprefs.cgi
@@ -215,6 +215,42 @@ sub SaveFooter {
+sub ShowPermissions {
+ print "You have the following permission bits set on your account:\n";
+ print "<P><UL>\n";
+ my $found = 0;
+ SendSQL("SELECT description FROM groups " .
+ "WHERE bit & $::usergroupset != 0 " .
+ "ORDER BY bit");
+ while (MoreSQLData()) {
+ my ($description) = (FetchSQLData());
+ print "<LI>$description\n";
+ $found = 1;
+ }
+ if ($found == 0) {
+ print "<LI>(No extra permission bits have been set).\n";
+ }
+ print "</UL>\n";
+ SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid");
+ my $blessgroupset = FetchOneColumn();
+ if ($blessgroupset) {
+ print "And you can turn on or off the following bits for\n";
+ print qq{<A HREF="editusers.cgi">other users</A>:\n};
+ print "<P><UL>\n";
+ SendSQL("SELECT description FROM groups " .
+ "WHERE bit & $blessgroupset != 0 " .
+ "ORDER BY bit");
+ while (MoreSQLData()) {
+ my ($description) = (FetchSQLData());
+ print "<LI>$description\n";
+ }
+ print "</UL>\n";
+ }
+}
+
+
+
+
######################################################################
################# Live code (not sub defs) starts here ###############
@@ -239,7 +275,9 @@ my @banklist = (
["diffs", "Email settings",
\&ShowDiffs, \&SaveDiffs],
["footer", "Page footer",
- \&ShowFooter, \&SaveFooter]
+ \&ShowFooter, \&SaveFooter],
+ ["permissions", "Permissions",
+ \&ShowPermissions, undef]
);
@@ -300,9 +338,11 @@ if (defined $bankdescription) {
</TABLE>
<INPUT TYPE="hidden" NAME="dosave" VALUE="1">
<INPUT TYPE="hidden" NAME="bank" VALUE="$bank">
-<INPUT TYPE="submit" VALUE="Submit">
-</FORM>
};
+ if ($savefunc) {
+ print qq{<INPUT TYPE="submit" VALUE="Submit">\n};
+ }
+ print qq{</FORM>\n};
} else {
print "<P>Please choose from the above links which settings you wish to change.</P>";
}