diff options
-rwxr-xr-x | editproducts.cgi | 289 | ||||
-rw-r--r-- | template/en/default/admin/products/confirm-delete.html.tmpl | 282 | ||||
-rw-r--r-- | template/en/default/admin/products/deleted.html.tmpl | 41 | ||||
-rw-r--r-- | template/en/default/filterexceptions.pl | 5 | ||||
-rw-r--r-- | template/en/default/global/user-error.html.tmpl | 5 |
5 files changed, 445 insertions, 177 deletions
diff --git a/editproducts.cgi b/editproducts.cgi index 229aa64d2..9d81f176c 100755 --- a/editproducts.cgi +++ b/editproducts.cgi @@ -139,16 +139,21 @@ sub CheckClassificationProduct ($$) { my $cl = shift; my $prod = shift; + my $dbh = Bugzilla->dbh; CheckClassification($cl); CheckProduct($prod); - # does the classification exist? - SendSQL("SELECT products.name - FROM products,classifications - WHERE products.name=" . SqlQuote($prod) . - " AND classifications.name=" . SqlQuote($cl)); - my $res = FetchOneColumn(); + trick_taint($prod); + trick_taint($cl); + + my $query = q{SELECT products.name + FROM products + INNER JOIN classifications + ON products.classification_id = classifications.id + WHERE products.name = ? + AND classifications.name = ?}; + my $res = $dbh->selectrow_array($query, undef, ($prod, $cl)); unless ($res) { print "Sorry, classification->product '$cl'->'$prod' does not exist."; @@ -157,6 +162,26 @@ sub CheckClassificationProduct ($$) } } +sub CheckClassificationProductNew ($$) +{ + my ($cl, $prod) = @_; + my $dbh = Bugzilla->dbh; + + CheckClassificationNew($cl); + + my ($res) = $dbh->selectrow_array(q{ + SELECT products.name + FROM products + INNER JOIN classifications + ON products.classification_id = classifications.id + WHERE products.name = ? AND classifications.name = ?}, + undef, ($prod, $cl)); + + unless ($res) { + ThrowUserError('classification_doesnt_exist_for_product', + { product => $prod, classification => $cl }); + } +} # # Displays the form to edit a products parameters @@ -604,180 +629,93 @@ if ($action eq 'new') { # if ($action eq 'del') { - PutHeader("Delete product"); - CheckProduct($product); - my $classification_id=1; - if (Param('useclassification')) { - CheckClassificationProduct($classification,$product); - $classification_id = get_classification_id($classification); - } - - # display some data about the product - SendSQL("SELECT classifications.description, - products.id, products.description, milestoneurl, disallownew - FROM products,classifications - WHERE products.name=" . SqlQuote($product) . - " AND classifications.id=" . SqlQuote($classification_id)); - my ($class_description, $product_id, $prod_description, $milestoneurl, $disallownew) = FetchSQLData(); - my $milestonelink = $milestoneurl ? "<a href=\"$milestoneurl\">$milestoneurl</a>" - : "<font color=\"red\">missing</font>"; - $prod_description ||= "<FONT COLOR=\"red\">description missing</FONT>"; - $class_description ||= "<FONT COLOR=\"red\">description missing</FONT>"; - $disallownew = $disallownew ? 'closed' : 'open'; - 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"; - - if (Param('useclassification')) { - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Classification:</TD>\n"; - print " <TD VALIGN=\"top\">$classification</TD>\n"; - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Description:</TD>\n"; - print " <TD VALIGN=\"top\">$class_description</TD>\n"; + if (!$product) { + ThrowUserError('product_not_specified'); } - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Product:</TD>\n"; - print " <TD VALIGN=\"top\">$product</TD>\n"; - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Description:</TD>\n"; - print " <TD VALIGN=\"top\">$prod_description</TD>\n"; - - if (Param('usetargetmilestone')) { - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Milestone URL:</TD>\n"; - print " <TD VALIGN=\"top\">$milestonelink</TD>\n"; - } - - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Closed for bugs:</TD>\n"; - print " <TD VALIGN=\"top\">$disallownew</TD>\n"; + my $product_id = get_product_id($product); + $product_id || ThrowUserError('product_doesnt_exist', + {product => $product}); - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Components:</TD>\n"; - print " <TD VALIGN=\"top\">"; - SendSQL("SELECT name,description - FROM components - WHERE product_id=$product_id"); - if (MoreSQLData()) { - print "<table>"; - while ( MoreSQLData() ) { - my ($component, $description) = FetchSQLData(); - $description ||= "<FONT COLOR=\"red\">description missing</FONT>"; - print "<tr><th align=right valign=top>$component:</th>"; - print "<td valign=top>$description</td></tr>\n"; - } - print "</table>\n"; - } else { - print "<FONT COLOR=\"red\">missing</FONT>"; - } + my $classification_id = 1; - print "</TD>\n</TR><TR>\n"; - print " <TD VALIGN=\"top\">Versions:</TD>\n"; - print " <TD VALIGN=\"top\">"; - SendSQL("SELECT value - FROM versions - WHERE product_id=$product_id - ORDER BY value"); - if (MoreSQLData()) { - my $br = 0; - while ( MoreSQLData() ) { - my ($version) = FetchSQLData(); - print "<BR>" if $br; - print $version; - $br = 1; - } - } else { - print "<FONT COLOR=\"red\">missing</FONT>"; + if (Param('useclassification')) { + CheckClassificationProductNew($classification, $product); + $classification_id = get_classification_id($classification); + $vars->{'classification'} = $classification; } - # - # Adding listing for associated target milestones - matthew@zeroknowledge.com - # + # Extract some data about the product + my $query = q{SELECT classifications.description, + products.description, + products.milestoneurl, + products.disallownew + FROM products + INNER JOIN classifications + ON products.classification_id = classifications.id + WHERE products.id = ?}; + + my ($class_description, + $prod_description, + $milestoneurl, + $disallownew) = $dbh->selectrow_array($query, undef, + $product_id); + + $vars->{'class_description'} = $class_description; + $vars->{'product_id'} = $product_id; + $vars->{'prod_description'} = $prod_description; + $vars->{'milestoneurl'} = $milestoneurl; + $vars->{'disallownew'} = $disallownew; + $vars->{'product_name'} = $product; + + $vars->{'components'} = $dbh->selectall_arrayref(q{ + SELECT name, description FROM components + WHERE product_id = ? ORDER BY name}, {'Slice' => {}}, + $product_id); + + $vars->{'versions'} = $dbh->selectcol_arrayref(q{ + SELECT value FROM versions + WHERE product_id = ? ORDER BY value}, undef, + $product_id); + + # 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), $classhtmlvar, "\">Edit milestones:</A></TH>\n"; - print " <TD>"; - SendSQL("SELECT value - FROM milestones - WHERE product_id=$product_id - 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"; - print " <TD VALIGN=\"top\">"; - SendSQL("SELECT count(bug_id), product_id - FROM bugs " . - $dbh->sql_group_by('product_id') . " - HAVING product_id = $product_id"); - my $bugs = FetchOneColumn(); - print $bugs || 'none'; - - - print "</TD>\n</TR></TABLE>"; - - print "<H2>Confirmation</H2>\n"; - - if ($bugs) { - if (!Param("allowbugdeletion")) { - print "Sorry, there are $bugs bugs outstanding for this product. -You must reassign those bugs to another product 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 product! When you delete this ", - "product, <B><BLINK>ALL</BLINK></B> stored bugs and their history will be ", - "deleted too.\n", - "</TD></TR></TABLE>\n"; + $vars->{'milestones'} = $dbh->selectcol_arrayref(q{ + SELECT value FROM milestones + WHERE product_id = ? + ORDER BY sortkey, value}, undef, $product_id); } - print "<P>Do you really want to delete this product?<P>\n"; - print "<FORM METHOD=POST ACTION=editproducts.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=\"" . - html_quote($product) . "\">\n"; - print "<INPUT TYPE=HIDDEN NAME=\"classification\" VALUE=\"" . - html_quote($classification) . "\">\n"; - print "</FORM>"; - - PutTrailer($localtrailer); + ($vars->{'bug_count'}) = $dbh->selectrow_array(q{ + SELECT COUNT(*) FROM bugs WHERE product_id = ?}, + undef, $product_id) || 0; + + $template->process("admin/products/confirm-delete.html.tmpl", $vars) + || ThrowTemplateError($template->error()); exit; } - - # # action='delete' -> really delete the product # if ($action eq 'delete') { - CheckProduct($product); + + if (!$product) { + ThrowUserError('product_not_specified'); + } + my $product_id = get_product_id($product); + $product_id || ThrowUserError('product_doesnt_exist', + {product => $product}); + + $vars->{'product'} = $product; - my $bug_ids = - $dbh->selectcol_arrayref("SELECT bug_id FROM bugs WHERE product_id = ?", - undef, $product_id); + my $bug_ids = $dbh->selectcol_arrayref(q{ + SELECT bug_id FROM bugs + WHERE product_id = ?}, undef, $product_id); my $nb_bugs = scalar(@$bug_ids); if ($nb_bugs) { @@ -790,47 +728,44 @@ if ($action eq 'delete') { else { ThrowUserError("product_has_bugs", { nb => $nb_bugs }); } + $vars->{'nb_bugs'} = $nb_bugs; } - PutHeader("Deleting product"); - print "All references to deleted bugs removed.<P>\n" if $nb_bugs; - $dbh->bz_lock_tables('products WRITE', 'components WRITE', 'versions WRITE', 'milestones WRITE', 'group_control_map WRITE', 'flaginclusions WRITE', 'flagexclusions WRITE'); - $dbh->do("DELETE FROM components WHERE product_id = ?", undef, $product_id); - print "Components deleted.<BR>\n"; + $dbh->do("DELETE FROM components WHERE product_id = ?", + undef, $product_id); - $dbh->do("DELETE FROM versions WHERE product_id = ?", undef, $product_id); - print "Versions deleted.<BR>\n"; + $dbh->do("DELETE FROM versions WHERE product_id = ?", + undef, $product_id); - $dbh->do("DELETE FROM milestones WHERE product_id = ?", undef, $product_id); - print "Milestones deleted.<P>\n"; + $dbh->do("DELETE FROM milestones WHERE product_id = ?", + undef, $product_id); $dbh->do("DELETE FROM group_control_map WHERE product_id = ?", undef, $product_id); - print "Group controls deleted.<BR>\n"; $dbh->do("DELETE FROM flaginclusions WHERE product_id = ?", undef, $product_id); + $dbh->do("DELETE FROM flagexclusions WHERE product_id = ?", undef, $product_id); - print "Flag inclusions and exclusions deleted.<P>\n"; - - $dbh->do("DELETE FROM products WHERE id = ?", undef, $product_id); - print "Product '$product' deleted.<P>\n"; + + $dbh->do("DELETE FROM products WHERE id = ?", + undef, $product_id); $dbh->bz_unlock_tables(); unlink "$datadir/versioncache"; - PutTrailer($localtrailer); + + $template->process("admin/products/deleted.html.tmpl", $vars) + || ThrowTemplateError($template->error()); exit; } - - # # action='edit' -> present the 'edit product' form # If a product is given with no action associated with it, then edit it. diff --git a/template/en/default/admin/products/confirm-delete.html.tmpl b/template/en/default/admin/products/confirm-delete.html.tmpl new file mode 100644 index 000000000..672f345e9 --- /dev/null +++ b/template/en/default/admin/products/confirm-delete.html.tmpl @@ -0,0 +1,282 @@ +[%# 1.0@bugzilla.org %] +[%# 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. + # + # Contributor(s): Gavin Shelley <bugzilla@chimpychompy.org> + #%] + +[%# INTERFACE: + # product_name: string; The name of the product + # + # prod_description: string; Product description, may be empty + # + # (classification fields available if Param('useclassification') is enabled:) + # + # classification: string; The name of the classification the product is in + # + # class_description: string; Classification description, may be empty + # + # bug_count: number; The number of bugs belonging to the product + # + # milestoneurl: string; milestone url, if milestones are in use, + # may be empty + # + # disallownew: boolean; Are new bugs allowed for the product flag + # + # components: list of hashes, members are: name, description + # + # versions: list of version values. + # + # milestones: list of milestone values. + # + #%] + +[% title = BLOCK %]Delete Product '[% product_name FILTER html %]' +[% END %] + +[% PROCESS global/header.html.tmpl + title = title + style_urls = ['skins/standard/admin.css'] +%] + +[% IF classification %] + [% classification_url_part = BLOCK %]&classification= + [%- classification FILTER url_quote %] + [%- END %] +[% ELSE %] + [% classification_url_part = "" %] +[% END %] + +[% UNLESS class_description %] + [% class_description = '<span style="color: red">missing</span>' %] +[% END %] +[% UNLESS prod_description %] + [% prod_description = '<span style="color: red">missing</span>' %] +[% END %] + +[% IF disallownew %] + [% disallownew = "closed" %] +[% ELSE %] + [% disallownew = "open" %] +[% END %] + +<table border="1" cellpadding="4" cellspacing="0"> + <tr bgcolor="#6666FF"> + <th valign="top" align="left">Field</th> + <th valign="top" align="left">Value</th> + </tr> + + [% IF Param('useclassification') %] + <tr> + <td>Classification:</td> + <td>[% classification FILTER html %]</td> + </tr> + <tr> + <td>Classification Description:</td> + [%# descriptions are intentionally not filtered to allow html content %] + <td>[% class_description FILTER none %]</td> + </tr> + [% END %] + + <tr> + <td valign="top">Product:</td> + <td valign="top"> + <a href="editproducts.cgi?product=[% product_name FILTER url_quote %] + [%- classification_url_part %]"> + [% product_name FILTER html %] + </a> + </td> + </tr> + <tr> + <td valign="top">Description:</td> + [%# descriptions are intentionally not filtered to allow html content %] + <td valign="top">[% prod_description FILTER none %]</td> + </tr> + + [% IF Param('usetargetmilestone') %] + <tr> + <td>Milestone URL:</td> + <td> + [% IF milestoneurl %] + <a href="[% milestoneurl FILTER uri %]"> + [%- milestoneurl FILTER html %] + </a> + [% ELSE %] + none + [% END %] + </td> + </tr> + [% END %] + + <tr> + <td>Closed for [% terms.bugs %]:</td> + <td>[% disallownew FILTER html %]</td> + </tr> + + <tr> + <td> + [% IF components.size > 0 %] + <a href="editcomponents.cgi?product=[% product_name FILTER url_quote %] + [%- classification_url_part %]" + title="Edit components for product '[% product_name FILTER html %]'"> + Components: + </a> + [% ELSE %] + Components: + [% END %] + </td> + <td> + [% IF components.size > 0 %] + <table> + [% FOREACH c = components %] + <tr> + <th align="right">[% c.name FILTER html %]:</th> + [%# descriptions are intentionally not filtered to allow html content %] + <td> + [% IF c.description %] + [% c.description FILTER none %] + [% ELSE %] + <span style="color: red">missing</span> + [% END %] + </td> + </tr> + [% END %] + </table> + [% ELSE %] + none + [% END %] + </td> + </tr> + + <tr> + <td> + [% IF versions.size > 0 %] + <a href="editversions.cgi?product=[%- product_name FILTER url_quote %] + [%- classification_url_part %]"> + Versions: + </a> + [% ELSE %] + Versions: + [% END %] + <td> + [% IF versions.size > 0 %] + [% FOREACH v = versions %] + [% v FILTER html %]<br> + [% END %] + [% ELSE %] + none + [% END %] + </td> + </tr> + + <tr> + <td valign="top"> + [% IF milestones.size > 0 %] + <a href="editmilestones.cgi?product=[%- product_name FILTER url_quote %] + [%- classification_url_part -%]"> + Milestones: + </a> + [% ELSE %] + Milestones: + [% END %] + </td> + <td> + [% IF milestones.size > 0 %] + [% FOREACH m = milestones %] + [% m FILTER html %]<br> + [% END %] + [% ELSE %] + none + [% END %] + </td> + </tr> + + <tr> + <td>[% terms.Bugs %]:</td> + <td> + [% IF bug_count %] + <a href="buglist.cgi?product=[%- product_name FILTER url_quote %] + [%- classification_url_part %]" + title="List of [% terms.bugs %] for product ' + [%- product_name FILTER html %]'"> + [% bug_count %] + </a> + [% ELSE %] + none + [% END %] + </td> + </tr> +</table> + +<h2>Confirmation</h2> + +[% IF bug_count %] + + [% IF !Param("allowbugdeletion") %] + + Sorry, there + + [% IF bug_count > 1 %] + are [% bug_count %] [%+ terms.bugs %] + [% ELSE %] + is 1 [% terms.bug %] + [% END %] + + outstanding for this product. You must reassign + + [% IF bug_count > 1 %] + those [% terms.bugs %] + [% ELSE %] + that [% terms.bug %] + [% END %] + + to another product before you can delete this one. + + [% ELSE %] + + <table border="0" cellpadding="20" width="70%" bgcolor="red"> + <tr> + <td> + There + [% IF bug_count > 1 %] + are [% bug_count %] [%+ terms.bugs %] + [% ELSE %] + is 1 [% terms.bug %] + [% END %] + entered for this product! When you delete this + product, <b><blink>ALL</blink></b> stored [% terms.bugs %] and + their history will be deleted, too. + </td> + </tr> + </table> + + [% END %] + +[% END %] + +[% IF bug_count == 0 || Param('allowbugdeletion') %] + + <p>Do you really want to delete this product?<p> + + <form method="post" action="editproducts.cgi"> + <input type="submit" value="Yes, delete"> + <input type="hidden" name="action" value="delete"> + <input type="hidden" name="product" value="[% product_name FILTER html %]"> + <input type="hidden" name="classification" + value="[% classification FILTER html %]"> + </form> + +[% END %] + +[% PROCESS admin/products/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/products/deleted.html.tmpl b/template/en/default/admin/products/deleted.html.tmpl new file mode 100644 index 000000000..6b31dbb09 --- /dev/null +++ b/template/en/default/admin/products/deleted.html.tmpl @@ -0,0 +1,41 @@ +[%# 1.0@bugzilla.org %] +[%# 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. + # + # Contributor(s): Tiago R. Mello <timello@async.com.br> + # + #%] + +[% PROCESS global/header.html.tmpl + title = 'Deleting product' +%] + +[% IF nb_bugs %] + All references to deleted [% terms.bugs %] removed. +[% END %] + +<p> + Components deleted.<br> + Versions deleted.<br> + Milestones deleted. +</p> + +<p> + Group controls deleted.<br> + Flag inclusions and exclusions deleted. +</p> + +<p> + Product [% product FILTER html %] deleted. +</p> + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl index 39de4fcac..bfa469481 100644 --- a/template/en/default/filterexceptions.pl +++ b/template/en/default/filterexceptions.pl @@ -535,6 +535,11 @@ 'classification_url_part', ], +'admin/products/confirm-delete.html.tmpl' => [ + 'classification_url_part', + 'bug_count', +], + 'admin/products/footer.html.tmpl' => [ 'classification_url_part', 'classification_text', diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 20d8371f4..800257ad9 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -234,6 +234,11 @@ [% title = "Classification Does Not Exist" %] The classification '[% name FILTER html %]' does not exist. + [% ELSIF error == "classification_doesnt_exist_for_product" %] + [% title = "Classification Does Not Exist For Product" %] + The classification '[% classification FILTER html %]' does not exist + for product '[% product FILTER html %]'. + [% ELSIF error == "classification_not_deletable" %] [% title = "Default Classification Can Not Be Deleted" %] You can not delete the default classification |