Patch by "Matt Masson" <matthew@zeroknowledge.com> -- allow definition
of different target milestones by product. git-svn-id: svn://10.0.0.236/trunk@63597 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -38,6 +38,7 @@ sub bug_form_pl_sillyness {
|
||||
$zz = @::legal_priority;
|
||||
$zz = @::legal_resolution_no_dup;
|
||||
$zz = @::legal_severity;
|
||||
$zz = %::target_milestone;
|
||||
}
|
||||
|
||||
my $loginok = quietly_check_login();
|
||||
@@ -207,14 +208,11 @@ if (Param("usetargetmilestone")) {
|
||||
if ($url eq "") {
|
||||
$url = "notargetmilestone.html";
|
||||
}
|
||||
if ($bug{'target_milestone'} eq "") {
|
||||
$bug{'target_milestone'} = " ";
|
||||
}
|
||||
push(@::legal_target_milestone, " ");
|
||||
|
||||
print "
|
||||
<TD ALIGN=RIGHT><A href=\"$url\"><B>Target Milestone:</B></A></TD>
|
||||
<TD><SELECT NAME=target_milestone>" .
|
||||
make_options(\@::legal_target_milestone,
|
||||
make_options($::target_milestone{$bug{'product'}},
|
||||
$bug{'target_milestone'}) .
|
||||
"</SELECT></TD>";
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ sub sillyness {
|
||||
$zz = @::legal_severity;
|
||||
$zz = @::legal_target_milestone;
|
||||
$zz = @::versions;
|
||||
$zz = @::target_milestone;
|
||||
};
|
||||
|
||||
my $serverpush = 0;
|
||||
@@ -1232,9 +1233,11 @@ document.write(\" <input type=button value=\\\"Uncheck All\\\" onclick=\\\"SetCh
|
||||
</TR>";
|
||||
|
||||
if (Param("usetargetmilestone")) {
|
||||
push(@::legal_target_milestone, " ");
|
||||
my $tfm_popup = make_options(\@::legal_target_milestone,
|
||||
$::dontchange);
|
||||
my @legal_milestone;
|
||||
if(1 == @prod_list) {
|
||||
@legal_milestone = @{$::target_milestone{$prod_list[0]}};
|
||||
}
|
||||
my $tfm_popup = make_options(\@legal_milestone, $::dontchange);
|
||||
print "
|
||||
<TR>
|
||||
<TD ALIGN=RIGHT><B>Target milestone:</B></TD>
|
||||
|
||||
@@ -752,6 +752,12 @@ $table{keyworddefs} =
|
||||
unique(name)';
|
||||
|
||||
|
||||
$table{milestones} =
|
||||
'value varchar(190) not null,
|
||||
product varchar(64) not null,
|
||||
sortkey smallint not null,
|
||||
unique (product, value)';
|
||||
|
||||
$table{shadowlog} =
|
||||
'id int not null auto_increment primary key,
|
||||
ts timestamp,
|
||||
@@ -1493,6 +1499,44 @@ AddField('products', 'votestoconfirm', 'smallint not null');
|
||||
AddField('profiles', 'blessgroupset', 'bigint not null');
|
||||
|
||||
|
||||
# 2000-03-21 Adding a table for target milestones to
|
||||
# database - matthew@zeroknowledge.com
|
||||
|
||||
$sth = $dbh->prepare("SELECT count(*) from milestones");
|
||||
$sth->execute();
|
||||
if (!($sth->fetchrow_arrayref()->[0])) {
|
||||
print "Replacing blank milestones...\n";
|
||||
$dbh->do("UPDATE bugs SET target_milestone = '---', delta_ts=delta_ts WHERE target_milestone = ' '");
|
||||
|
||||
# Populate milestone table with all exisiting values in database
|
||||
$sth = $dbh->prepare("SELECT DISTINCT target_milestone, product FROM bugs");
|
||||
$sth->execute();
|
||||
|
||||
print "Populating milestones table...\n";
|
||||
|
||||
my $value;
|
||||
my $product;
|
||||
while(($value, $product) = $sth->fetchrow_array())
|
||||
{
|
||||
# check if the value already exists
|
||||
my $sortkey = substr($value, 1);
|
||||
if ($sortkey !~ /^\d+$/) {
|
||||
$sortkey = 0;
|
||||
} else {
|
||||
$sortkey *= 10;
|
||||
}
|
||||
$value = $dbh->quote($value);
|
||||
$product = $dbh->quote($product);
|
||||
my $s2 = $dbh->prepare("SELECT value FROM milestones WHERE value = $value AND product = $product");
|
||||
$s2->execute();
|
||||
|
||||
if(!$s2->fetchrow_array())
|
||||
{
|
||||
$dbh->do("INSERT INTO milestones(value, product, sortkey) VALUES($value, $product, $sortkey)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# If you had to change the --TABLE-- definition in any way, then add your
|
||||
# differential change code *** A B O V E *** this comment.
|
||||
|
||||
552
mozilla/webtools/bugzilla/editmilestones.cgi
Executable file
552
mozilla/webtools/bugzilla/editmilestones.cgi
Executable file
@@ -0,0 +1,552 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
|
||||
#
|
||||
# This is a script to edit the target milestones. It is largely a copy of
|
||||
# the editversions.cgi script, since the two fields were set up in a
|
||||
# very similar fashion.
|
||||
#
|
||||
# (basically replace each occurance of 'milestone' with 'version', and
|
||||
# you'll have the original script)
|
||||
#
|
||||
# Matt Masson <matthew@zeroknowledge.com>
|
||||
#
|
||||
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
|
||||
|
||||
|
||||
# TestProduct: just returns if the specified product does exists
|
||||
# CheckProduct: same check, optionally emit an error text
|
||||
# TestMilestone: just returns if the specified product/version combination exists
|
||||
# CheckMilestone: same check, optionally emit an error text
|
||||
|
||||
sub TestProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT product
|
||||
FROM products
|
||||
WHERE product=" . SqlQuote($prod));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# do we have a product?
|
||||
unless ($prod) {
|
||||
print "Sorry, you haven't specified a product.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
unless (TestProduct $prod) {
|
||||
print "Sorry, product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub TestMilestone ($$)
|
||||
{
|
||||
my ($prod,$mile) = @_;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT product,value
|
||||
FROM milestones
|
||||
WHERE product=" . SqlQuote($prod) . " and value=" . SqlQuote($mile));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckMilestone ($$)
|
||||
{
|
||||
my ($prod,$mile) = @_;
|
||||
|
||||
# do we have the milestone?
|
||||
unless ($mile) {
|
||||
print "Sorry, you haven't specified a milestone.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
CheckProduct($prod);
|
||||
|
||||
unless (TestMilestone $prod,$mile) {
|
||||
print "Sorry, milestone '$mile' for product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit a milestone
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$$)
|
||||
{
|
||||
my ($product, $milestone, $sortkey) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Milestone:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"milestone\" VALUE=\"" .
|
||||
value_quote($milestone) . "\">\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Sortkey:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"sortkey\" VALUE=\"" .
|
||||
value_quote($sortkey) . "\">\n";
|
||||
print " <INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\"></TD>\n";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("Back to the <A HREF=\"query.cgi\">query page</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup("editcomponents")) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editcomponents' group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete milestones.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# often used variables
|
||||
#
|
||||
my $product = trim($::FORM{product} || '');
|
||||
my $milestone = trim($::FORM{milestone} || '');
|
||||
my $sortkey = trim($::FORM{sortkey} || '0');
|
||||
my $action = trim($::FORM{action} || '');
|
||||
my $localtrailer;
|
||||
if ($milestone) {
|
||||
$localtrailer = "<A HREF=\"editmilestones.cgi?product=" . url_quote($product) . "\">edit</A> more milestones";
|
||||
} else {
|
||||
$localtrailer = "<A HREF=\"editmilestones.cgi\">edit</A> more milestones";
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# product = '' -> Show nice list of milestones
|
||||
#
|
||||
|
||||
unless ($product) {
|
||||
PutHeader("Select product");
|
||||
|
||||
SendSQL("SELECT products.product,products.description,'xyzzy'
|
||||
FROM products
|
||||
GROUP BY products.product
|
||||
ORDER BY products.product");
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit milestones of ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Description</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($product, $description, $bugs) = FetchSQLData();
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$bugs ||= "none";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$description</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
}
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='' -> Show nice list of milestones
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Select milestone");
|
||||
CheckProduct($product);
|
||||
|
||||
SendSQL("SELECT value,sortkey
|
||||
FROM milestones
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
ORDER BY sortkey,value");
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit milestone ...</TH>\n";
|
||||
#print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Sortkey</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Action</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($milestone,$sortkey,$bugs) = FetchSQLData();
|
||||
$bugs ||= 'none';
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=edit\"><B>$milestone</B></A></TD>\n";
|
||||
#print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"right\">$sortkey</TD>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=del\"><B>Delete</B></A></TD>\n";
|
||||
print "</TR>";
|
||||
}
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\" COLSPAN=\"2\">Add a new milestone</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"middle\"><A HREF=\"editmilestones.cgi?product=", url_quote($product) . "&action=add\">Add</A></TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new milestone
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add milestone");
|
||||
CheckProduct($product);
|
||||
|
||||
#print "This page lets you add a new milestone to a $::bugzilla_name tracked product.\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editmilestones.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, $milestone, 0);
|
||||
|
||||
print "</TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add milestone entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new milestone");
|
||||
CheckProduct($product);
|
||||
|
||||
# Cleanups and valididy checks
|
||||
|
||||
unless ($milestone) {
|
||||
print "You must enter a text for the new milestone. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestMilestone($product,$milestone)) {
|
||||
print "The milestone '$milestone' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
# Add the new milestone
|
||||
SendSQL("INSERT INTO milestones ( " .
|
||||
"value, product, sortkey" .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($milestone) . "," .
|
||||
SqlQuote($product) . ", $sortkey)");
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete milestone");
|
||||
CheckMilestone($product, $milestone);
|
||||
|
||||
SendSQL("SELECT count(bug_id),product,target_milestone
|
||||
FROM bugs
|
||||
GROUP BY product,target_milestone
|
||||
HAVING product=" . SqlQuote($product) . "
|
||||
AND target_milestone=" . SqlQuote($milestone));
|
||||
my $bugs = FetchOneColumn();
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
print "<TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Part</TH>\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Value</TH>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Product:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">$product</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Milestone:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">$milestone</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Bugs:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">", $bugs || 'none' , "</TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
|
||||
if ($bugs) {
|
||||
if (!Param("allowbugdeletion")) {
|
||||
print "Sorry, there are $bugs bugs outstanding for this milestone.
|
||||
You must reassign those bugs to another milestone before you can delete this
|
||||
one.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
print "<TABLE BORDER=0 CELLPADDING=20 WIDTH=\"70%\" BGCOLOR=\"red\"><TR><TD>\n",
|
||||
"There are bugs entered for this milestone! When you delete this ",
|
||||
"milestone, <B><BLINK>all</BLINK></B> stored bugs will be deleted, too. ",
|
||||
"You could not even see the bug history for this milestone anymore!\n",
|
||||
"</TD></TR></TABLE>\n";
|
||||
}
|
||||
|
||||
print "<P>Do you really want to delete this milestone?<P>\n";
|
||||
print "<FORM METHOD=POST ACTION=editmilestones.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"milestone\" VALUE=\"" .
|
||||
value_quote($milestone) . "\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the milestone
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting milestone");
|
||||
CheckMilestone($product,$milestone);
|
||||
|
||||
# lock the tables before we start to change everything:
|
||||
|
||||
SendSQL("LOCK TABLES attachments WRITE,
|
||||
bugs WRITE,
|
||||
bugs_activity WRITE,
|
||||
milestones WRITE,
|
||||
dependencies WRITE");
|
||||
|
||||
# According to MySQL doc I cannot do a DELETE x.* FROM x JOIN Y,
|
||||
# so I have to iterate over bugs and delete all the indivial entries
|
||||
# in bugs_activies and attachments.
|
||||
|
||||
if (Param("allowbugdeletion")) {
|
||||
|
||||
SendSQL("SELECT bug_id
|
||||
FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND target_milestone=" . SqlQuote($milestone));
|
||||
while (MoreSQLData()) {
|
||||
my $bugid = FetchOneColumn();
|
||||
|
||||
my $query =
|
||||
$::db->query("DELETE FROM attachments WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM bugs_activity WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM dependencies WHERE blocked=$bugid")
|
||||
or die "$::db_errstr";
|
||||
}
|
||||
print "Attachments, bug activity and dependencies deleted.<BR>\n";
|
||||
|
||||
|
||||
# Deleting the rest is easier:
|
||||
|
||||
SendSQL("DELETE FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND target_milestone=" . SqlQuote($milestone));
|
||||
print "Bugs deleted.<BR>\n";
|
||||
}
|
||||
|
||||
SendSQL("DELETE FROM milestones
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($milestone));
|
||||
print "Milestone deleted.<P>\n";
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
unlink "data/versioncache";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the edit milestone form
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit milestone");
|
||||
CheckMilestone($product,$milestone);
|
||||
|
||||
SendSQL("SELECT sortkey FROM milestones WHERE product=" .
|
||||
SqlQuote($product) . " AND value = " . SqlQuote($milestone));
|
||||
my $sortkey = FetchOneColumn();
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editmilestones.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, $milestone, $sortkey);
|
||||
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"milestoneold\" VALUE=\"" .
|
||||
value_quote($milestone) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"sortkeyold\" VALUE=\"" .
|
||||
value_quote($sortkey) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='update' -> update the milestone
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update milestone");
|
||||
|
||||
my $milestoneold = trim($::FORM{milestoneold} || '');
|
||||
my $sortkeyold = trim($::FORM{sortkeyold} || '0');
|
||||
|
||||
CheckMilestone($product,$milestoneold);
|
||||
|
||||
SendSQL("LOCK TABLES bugs WRITE,
|
||||
milestones WRITE");
|
||||
|
||||
if ($milestone ne $milestoneold) {
|
||||
unless ($milestone) {
|
||||
print "Sorry, I can't delete the milestone text.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
if (TestMilestone($product,$milestone)) {
|
||||
print "Sorry, milestone '$milestone' is already in use.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
SendSQL("UPDATE bugs
|
||||
SET target_milestone=" . SqlQuote($milestone) . "
|
||||
WHERE target_milestone=" . SqlQuote($milestoneold) . "
|
||||
AND product=" . SqlQuote($product));
|
||||
SendSQL("UPDATE milestones
|
||||
SET value=" . SqlQuote($milestone) . "
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($milestoneold));
|
||||
unlink "data/versioncache";
|
||||
print "Updated milestone.<BR>\n";
|
||||
}
|
||||
if ($sortkey != $sortkeyold) {
|
||||
SendSQL("UPDATE milestones SET sortkey=$sortkey
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($milestoneold));
|
||||
unlink "data/versioncache";
|
||||
print "Updated sortkey.<BR>\n";
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
@@ -485,6 +485,29 @@ if ($action eq 'del') {
|
||||
print "<FONT COLOR=\"red\">missing</FONT>";
|
||||
}
|
||||
|
||||
#
|
||||
# Adding listing for associated target milestones - matthew@zeroknowledge.com
|
||||
#
|
||||
if (Param('usetargetmilestone')) {
|
||||
print "</TD>\n</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\" VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "\">Edit milestones:</A></TH>\n";
|
||||
print " <TD>";
|
||||
SendSQL("SELECT value
|
||||
FROM milestones
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
ORDER BY sortkey,value");
|
||||
if(MoreSQLData()) {
|
||||
my $br = 0;
|
||||
while ( MoreSQLData() ) {
|
||||
my ($milestone) = FetchSQLData();
|
||||
print "<BR>" if $br;
|
||||
print $milestone;
|
||||
$br = 1;
|
||||
}
|
||||
} else {
|
||||
print "<FONT COLOR=\"red\">missing</FONT>";
|
||||
}
|
||||
}
|
||||
|
||||
print "</TD>\n</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Bugs:</TD>\n";
|
||||
@@ -548,7 +571,8 @@ if ($action eq 'delete') {
|
||||
versions WRITE,
|
||||
products WRITE,
|
||||
groups WRITE,
|
||||
profiles WRITE");
|
||||
profiles WRITE,
|
||||
milestones WRITE");
|
||||
|
||||
# According to MySQL doc I cannot do a DELETE x.* FROM x JOIN Y,
|
||||
# so I have to iterate over bugs and delete all the indivial entries
|
||||
@@ -589,6 +613,11 @@ if ($action eq 'delete') {
|
||||
WHERE program=" . SqlQuote($product));
|
||||
print "Versions deleted.<P>\n";
|
||||
|
||||
# deleting associated target milestones - matthew@zeroknowledge.com
|
||||
SendSQL("DELETE FROM milestones
|
||||
WHERE product=" . SqlQuote($product));
|
||||
print "Milestones deleted.<BR>\n";
|
||||
|
||||
SendSQL("DELETE FROM products
|
||||
WHERE product=" . SqlQuote($product));
|
||||
print "Product '$product' deleted.<BR>\n";
|
||||
@@ -700,6 +729,29 @@ if ($action eq 'edit') {
|
||||
print "<FONT COLOR=\"red\">missing</FONT>";
|
||||
}
|
||||
|
||||
#
|
||||
# Adding listing for associated target milestones - matthew@zeroknowledge.com
|
||||
#
|
||||
if (Param('usetargetmilestone')) {
|
||||
print "</TD>\n</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\" VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "\">Edit milestones:</A></TH>\n";
|
||||
print " <TD>";
|
||||
SendSQL("SELECT value
|
||||
FROM milestones
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
ORDER BY sortkey,value");
|
||||
if(MoreSQLData()) {
|
||||
my $br = 0;
|
||||
while ( MoreSQLData() ) {
|
||||
my ($milestone) = FetchSQLData();
|
||||
print "<BR>" if $br;
|
||||
print $milestone;
|
||||
$br = 1;
|
||||
}
|
||||
} else {
|
||||
print "<FONT COLOR=\"red\">missing</FONT>";
|
||||
}
|
||||
}
|
||||
|
||||
print "</TD>\n</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Bugs:</TH>\n";
|
||||
@@ -782,7 +834,8 @@ if ($action eq 'update') {
|
||||
products WRITE,
|
||||
versions WRITE,
|
||||
groups WRITE,
|
||||
profiles WRITE");
|
||||
profiles WRITE,
|
||||
milestones WRITE");
|
||||
|
||||
if ($disallownew ne $disallownewold) {
|
||||
$disallownew ||= 0;
|
||||
@@ -923,6 +976,7 @@ if ($action eq 'update') {
|
||||
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");
|
||||
SendSQL("UPDATE milestones SET product=$qp WHERE product=$qpold");
|
||||
# Need to do an update to groups as well. If there is a corresponding
|
||||
# bug group, whether usebuggroups is currently set or not, we want to
|
||||
# update it so it will match in the future. If there is no group, this
|
||||
|
||||
@@ -260,7 +260,23 @@ sub Version_element {
|
||||
return make_popup("version", $versionlist, $defversion, 1, $onchange);
|
||||
}
|
||||
|
||||
sub Milestone_element {
|
||||
my ($tm, $prod, $onchange) = (@_);
|
||||
my $tmlist;
|
||||
if (!defined $::target_milestone{$prod}) {
|
||||
$tmlist = [];
|
||||
} else {
|
||||
$tmlist = $::target_milestone{$prod};
|
||||
}
|
||||
|
||||
my $deftm = $tmlist->[0];
|
||||
|
||||
if (lsearch($tmlist, $tm) >= 0) {
|
||||
$deftm = $tm;
|
||||
}
|
||||
|
||||
return make_popup("target_milestone", $tmlist, $deftm, 1, $onchange);
|
||||
}
|
||||
|
||||
# Generate a string which, when later interpreted by the Perl compiler, will
|
||||
# be the same as the given string.
|
||||
@@ -427,11 +443,24 @@ sub GenerateVersionTable {
|
||||
print FID GenerateCode('$::anyvotesallowed');
|
||||
|
||||
if ($dotargetmilestone) {
|
||||
my $last = Param("nummilestones");
|
||||
my $i;
|
||||
for ($i=1 ; $i<=$last ; $i++) {
|
||||
push(@::legal_target_milestone, "M$i");
|
||||
# reading target milestones in from the database - matthew@zeroknowledge.com
|
||||
SendSQL("SELECT value, product FROM milestones ORDER BY sortkey, value");
|
||||
my @line;
|
||||
my %tmarray;
|
||||
@::legal_target_milestone = ();
|
||||
while(@line = FetchSQLData()) {
|
||||
my ($tm, $pr) = (@line);
|
||||
if (!defined $::target_milestone{$pr}) {
|
||||
$::target_milestone{$pr} = [];
|
||||
}
|
||||
push @{$::target_milestone{$pr}}, $tm;
|
||||
if (!exists $tmarray{$tm}) {
|
||||
$tmarray{$tm} = 1;
|
||||
push(@::legal_target_milestone, $tm);
|
||||
}
|
||||
}
|
||||
|
||||
print FID GenerateCode('%::target_milestone');
|
||||
print FID GenerateCode('@::legal_target_milestone');
|
||||
print FID GenerateCode('%::milestoneurl');
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ use vars %::versions,
|
||||
%::legal_opsys,
|
||||
%::legal_platform,
|
||||
%::legal_priority,
|
||||
%::target_milestone,
|
||||
%::legal_severity;
|
||||
|
||||
my $whoid = confirm_login();
|
||||
@@ -53,6 +54,11 @@ if ( Param("strictvaluechecks") ) {
|
||||
CheckFormFieldDefined(\%::FORM, 'product');
|
||||
CheckFormFieldDefined(\%::FORM, 'version');
|
||||
CheckFormFieldDefined(\%::FORM, 'component');
|
||||
|
||||
# check if target milestone is defined - matthew@zeroknowledge.com
|
||||
if ( Param("usetargetmilestone") ) {
|
||||
CheckFormFieldDefined(\%::FORM, 'target_milestone');
|
||||
}
|
||||
}
|
||||
|
||||
if ($::FORM{'product'} ne $::dontchange) {
|
||||
@@ -71,12 +77,18 @@ if ($::FORM{'product'} ne $::dontchange) {
|
||||
#
|
||||
my $vok = lsearch($::versions{$prod}, $::FORM{'version'}) >= 0;
|
||||
my $cok = lsearch($::components{$prod}, $::FORM{'component'}) >= 0;
|
||||
if (!$vok || !$cok) {
|
||||
print "<H1>Changing product means changing version and component.</H1>\n";
|
||||
print "You have chosen a new product, and now the version and/or\n";
|
||||
|
||||
my $mok = 1; # so it won't affect the 'if' statement if milestones aren't used
|
||||
if ( Param("usetargetmilestone") ) {
|
||||
$mok = lsearch($::target_milestone{$prod}, $::FORM{'target_milestone'}) >= 0;
|
||||
}
|
||||
|
||||
if (!$vok || !$cok || !$mok) {
|
||||
print "<H1>Changing product means changing version, target milestone and component.</H1>\n";
|
||||
print "You have chosen a new product, and now the version, target milestone and/or\n";
|
||||
print "component fields are not correct. (Or, possibly, the bug did\n";
|
||||
print "not have a valid component or version field in the first place.)\n";
|
||||
print "Anyway, please set the version and component now.<p>\n";
|
||||
print "not have a valid target milestone, component or version field in the first place.)\n";
|
||||
print "Anyway, please set the version, target milestone and component now.<p>\n";
|
||||
print "<form>\n";
|
||||
print "<table>\n";
|
||||
print "<tr>\n";
|
||||
@@ -86,12 +98,19 @@ if ($::FORM{'product'} ne $::dontchange) {
|
||||
print "<td align=right><b>Version:</b></td>\n";
|
||||
print "<td>" . Version_element($::FORM{'version'}, $prod) . "</td>\n";
|
||||
print "</tr><tr>\n";
|
||||
|
||||
if ( Param("usetargetmilestone") ) {
|
||||
print "<td align=right><b>Target Milestone:</b></td>\n";
|
||||
print "<td>" . Milestone_element($::FORM{'target_milestone'}, $prod) . "</td>\n";
|
||||
print "</tr><tr>\n";
|
||||
}
|
||||
|
||||
print "<td align=right><b>Component:</b></td>\n";
|
||||
print "<td>" . Component_element($::FORM{'component'}, $prod) . "</td>\n";
|
||||
print "</tr>\n";
|
||||
print "</table>\n";
|
||||
foreach my $i (keys %::FORM) {
|
||||
if ($i ne 'version' && $i ne 'component') {
|
||||
if ($i ne 'version' && $i ne 'component' && $i ne 'target_milestone') {
|
||||
print "<input type=hidden name=$i value=\"" .
|
||||
value_quote($::FORM{$i}) . "\">\n";
|
||||
}
|
||||
|
||||
@@ -282,12 +282,14 @@ my $jscript = << 'ENDSCRIPT';
|
||||
<!--
|
||||
var cpts = new Array();
|
||||
var vers = new Array();
|
||||
var tms = new Array();
|
||||
ENDSCRIPT
|
||||
|
||||
|
||||
my $p;
|
||||
my $v;
|
||||
my $c;
|
||||
my $m;
|
||||
my $i = 0;
|
||||
my $j = 0;
|
||||
|
||||
@@ -299,6 +301,10 @@ foreach $v (@::legal_versions) {
|
||||
$jscript .= "vers['$v'] = new Array();\n";
|
||||
}
|
||||
|
||||
my $tm;
|
||||
foreach $tm (@::legal_target_milestone) {
|
||||
$jscript .= "tms['$tm'] = new Array();\n";
|
||||
}
|
||||
|
||||
for $p (@::legal_product) {
|
||||
if ($::components{$p}) {
|
||||
@@ -312,6 +318,12 @@ for $p (@::legal_product) {
|
||||
$jscript .= "vers['$v'][vers['$v'].length] = '$p';\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($::target_milestone{$p}) {
|
||||
foreach $m (@{$::target_milestone{$p}}) {
|
||||
$jscript .= "tms['$m'][tms['$m'].length] = '$p';\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
@@ -404,8 +416,39 @@ function selectProduct(f) {
|
||||
}
|
||||
}
|
||||
|
||||
var tmsel = new Array();
|
||||
for (i=0 ; i<f.target_milestone.length ; i++) {
|
||||
if (f.target_milestone[i].selected) {
|
||||
tmsel[f.target_milestone[i].value] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
f.target_milestone.options.length = 0;
|
||||
|
||||
for (tm in tms) {
|
||||
if (typeof(tms[v]) == 'function') continue;
|
||||
var doit = doall;
|
||||
for (i=0 ; !doit && i<f.product.length ; i++) {
|
||||
if (f.product[i].selected) {
|
||||
var p = f.product[i].value;
|
||||
for (j in tms[tm]) {
|
||||
if (typeof(tms[tm][j]) == 'function') continue;
|
||||
var p2 = tms[tm][j];
|
||||
if (p2 == p) {
|
||||
doit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doit) {
|
||||
var l = f.target_milestone.length;
|
||||
f.target_milestone[l] = new Option(tm, tm);
|
||||
if (tmsel[tm]) {
|
||||
f.target_milestone[l].selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// -->
|
||||
@@ -431,7 +474,6 @@ PutHeader("Bugzilla Query Page", "Query",
|
||||
0, $jscript);
|
||||
|
||||
push @::legal_resolution, "---"; # Oy, what a hack.
|
||||
push @::legal_target_milestone, "---"; # Oy, what a hack.
|
||||
|
||||
my @logfields = ("[Bug creation]", @::log_columns);
|
||||
|
||||
|
||||
@@ -194,6 +194,25 @@ foreach my $ref (@checklist) {
|
||||
}
|
||||
}
|
||||
|
||||
# Adding check for Target Milestones / products - matthew@zeroknowledge.com
|
||||
Status("Checking milestone/products");
|
||||
|
||||
@checklist = ();
|
||||
SendSQL("select distinct product, target_milestone from bugs");
|
||||
while (@row = FetchSQLData()) {
|
||||
my @copy = @row;
|
||||
push(@checklist, \@copy);
|
||||
}
|
||||
|
||||
foreach my $ref (@checklist) {
|
||||
my ($product, $milestone) = (@$ref);
|
||||
SendSQL("SELECT count(*) FROM milestones WHERE product = '$product' AND value = '$milestone'");
|
||||
if(FetchOneColumn() != 1) {
|
||||
Alert("Bug(s) found with invalud product/milestone: $product/$milestone");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Status("Checking components/products");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user