From 8d91efaa1fe8eb3828e123b7ff3356c5107f3ebd Mon Sep 17 00:00:00 2001 From: "justdave%bugzilla.org" <> Date: Sat, 11 Sep 2004 13:48:13 +0000 Subject: Bug 190224: templatize editmilestones.cgi Patch by GavinS r=jouni, a=justdave --- editmilestones.cgi | 665 +++++++++++---------- t/008filter.t | 2 +- .../admin/milestones/confirm-delete.html.tmpl | 135 +++++ .../en/default/admin/milestones/create.html.tmpl | 59 ++ .../en/default/admin/milestones/created.html.tmpl | 44 ++ .../en/default/admin/milestones/deleted.html.tmpl | 69 +++ .../en/default/admin/milestones/edit.html.tmpl | 67 +++ .../en/default/admin/milestones/footer.html.tmpl | 66 ++ .../en/default/admin/milestones/list.html.tmpl | 77 +++ .../admin/milestones/select-product.html.tmpl | 60 ++ .../en/default/admin/milestones/updated.html.tmpl | 58 ++ template/en/default/filterexceptions.pl | 11 +- template/en/default/global/user-error.html.tmpl | 37 ++ 13 files changed, 1028 insertions(+), 322 deletions(-) create mode 100644 template/en/default/admin/milestones/confirm-delete.html.tmpl create mode 100644 template/en/default/admin/milestones/create.html.tmpl create mode 100644 template/en/default/admin/milestones/created.html.tmpl create mode 100644 template/en/default/admin/milestones/deleted.html.tmpl create mode 100644 template/en/default/admin/milestones/edit.html.tmpl create mode 100644 template/en/default/admin/milestones/footer.html.tmpl create mode 100644 template/en/default/admin/milestones/list.html.tmpl create mode 100644 template/en/default/admin/milestones/select-product.html.tmpl create mode 100644 template/en/default/admin/milestones/updated.html.tmpl diff --git a/editmilestones.cgi b/editmilestones.cgi index aaec24455..ad07b2d61 100755 --- a/editmilestones.cgi +++ b/editmilestones.cgi @@ -11,6 +11,8 @@ # # Matt Masson # +# Contributors : Gavin Shelley +# use strict; @@ -22,6 +24,10 @@ require "globals.pl"; use Bugzilla::Constants; use Bugzilla::Config qw(:DEFAULT $datadir); +use vars qw($template $vars); + +my $cgi = Bugzilla->cgi; + # 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 @@ -29,119 +35,88 @@ use Bugzilla::Config qw(:DEFAULT $datadir); sub TestProduct ($) { - my $prod = shift; + my $product = shift; + + trick_taint($product); # does the product exist? - SendSQL("SELECT name - FROM products - WHERE name=" . SqlQuote($prod)); - return FetchOneColumn(); + my $dbh = Bugzilla->dbh; + my $sth = $dbh->prepare_cached("SELECT name + FROM products + WHERE name = ?"); + $sth->execute($product); + + my ($row) = $sth->fetchrow_array; + + $sth->finish; + + return $row; } sub CheckProduct ($) { - my $prod = shift; + my $product = shift; # do we have a product? - unless ($prod) { - print "Sorry, you haven't specified a product."; - PutTrailer(); + unless ($product) { + &::ThrowUserError('product_not_specified'); exit; } - unless (TestProduct $prod) { - print "Sorry, product '$prod' does not exist."; - PutTrailer(); + # Does it exist in the DB? + unless (TestProduct $product) { + &::ThrowUserError('product_doesnt_exist', + {'product' => $product}); exit; } } sub TestMilestone ($$) { - my ($prod,$mile) = @_; + my ($product, $milestone) = @_; + + my $dbh = Bugzilla->dbh; # does the product exist? - SendSQL("SELECT products.name, value + my $sth = $dbh->prepare_cached(" + SELECT products.name, value FROM milestones, products - WHERE milestones.product_id=products.id AND products.name=" . SqlQuote($prod) . " and value=" . SqlQuote($mile)); - return FetchOneColumn(); -} + WHERE milestones.product_id = products.id + AND products.name = ? + AND value = ?"); -sub CheckMilestone ($$) -{ - my ($prod,$mile) = @_; + trick_taint($product); + trick_taint($milestone); - # do we have the milestone? - unless ($mile) { - print "Sorry, you haven't specified a milestone."; - PutTrailer(); - exit; - } + $sth->execute($product, $milestone); - CheckProduct($prod); - - unless (TestMilestone $prod,$mile) { - print "Sorry, milestone '$mile' for product '$prod' does not exist."; - PutTrailer(); - exit; - } -} + my ($db_milestone) = $sth->fetchrow_array(); + $sth->finish(); -# -# Displays the form to edit a milestone -# + return $db_milestone; +} -sub EmitFormElements ($$$) +sub CheckMilestone ($$) { - my ($product, $milestone, $sortkey) = @_; - - print " Milestone:\n"; - print " \n"; - print "\n"; - print " Sortkey:\n"; - print " \n"; - print " \n"; -} + my ($product, $milestone) = @_; + # do we have the milestone and product combination? + unless ($milestone) { + ThrowUserError('milestone_not_specified'); + exit; + } -# -# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d." -# + CheckProduct($product); -sub PutTrailer (@) -{ - my (@links) = ("Back to the query page", @_); - SendSQL("UNLOCK TABLES"); - - my $count = $#links; - my $num = 0; - print "

\n"; - foreach (@links) { - print $_; - if ($num == $count) { - print ".\n"; - } - elsif ($num == $count-1) { - print " or "; - } - else { - print ", "; - } - $num++; + unless (TestMilestone $product, $milestone) { + ThrowUserError('milestone_not_valid', + {'product' => $product, + 'milestone' => $milestone}); + exit; } - PutFooter(); } - - - - - - # # Preliminary checks: # @@ -151,10 +126,7 @@ Bugzilla->login(LOGIN_REQUIRED); print Bugzilla->cgi->header(); 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(); + ThrowUserError('auth_cant_edit_milestones'); exit; } @@ -162,44 +134,44 @@ unless (UserInGroup("editcomponents")) { # # 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 = "edit more milestones"; -} else { - $localtrailer = "edit more milestones"; -} - - +my $product = trim($cgi->param('product') || ''); +my $milestone = trim($cgi->param('milestone') || ''); +my $sortkey = trim($cgi->param('sortkey') || '0'); +my $action = trim($cgi->param('action') || ''); # # product = '' -> Show nice list of milestones # unless ($product) { - PutHeader("Select product"); - - SendSQL("SELECT products.name,products.description - FROM products - GROUP BY products.name - ORDER BY products.name"); - print "\n"; - print " \n"; - print " \n"; - print ""; - while ( MoreSQLData() ) { - my ($product, $description) = FetchSQLData(); - $description ||= "missing"; - print "\n"; - print " \n"; - print " \n"; + + my @products = (); + + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare_cached('SELECT products.name, products.description + FROM products + ORDER BY products.name'); + + my $data = $dbh->selectall_arrayref($sth); + + foreach my $aref (@$data) { + + my $prod = {}; + + my ($name, $description) = @$aref; + + $prod->{'name'} = $name; + $prod->{'description'} = $description; + + push(@products, $prod); } - print "
Edit milestones of ...Description
$product$description
\n"; - PutTrailer(); + $vars->{'products'} = \@products; + $template->process("admin/milestones/select-product.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } @@ -210,37 +182,39 @@ unless ($product) { # unless ($action) { - PutHeader("Select milestone for $product"); + CheckProduct($product); my $product_id = get_product_id($product); + my @milestones = (); + + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare_cached('SELECT value, sortkey + FROM milestones + WHERE product_id = ? + ORDER BY sortkey, value'); + + my $data = $dbh->selectall_arrayref($sth, + undef, + $product_id); + + foreach my $aref (@$data) { - SendSQL("SELECT value,sortkey - FROM milestones - WHERE product_id=$product_id - ORDER BY sortkey,value"); - - print "\n"; - print " \n"; - #print " \n"; - print " \n"; - print " \n"; - print ""; - while ( MoreSQLData() ) { - my ($milestone,$sortkey,$bugs) = FetchSQLData(); - $bugs ||= 'none'; - print "\n"; - print " \n"; - #print " \n"; - print " \n"; - print " \n"; - print ""; + my $milestone = {}; + my ($name, $sortkey) = @$aref; + + $milestone->{'name'} = $name; + $milestone->{'sortkey'} = $sortkey; + + push(@milestones, $milestone); } - print "\n"; - print " \n"; - print " \n"; - print "
Edit milestone ...BugsSortkeyAction
$milestone$bugs$sortkeyDelete
Add a new milestoneAdd
\n"; - PutTrailer(); + $vars->{'product'} = $product; + $vars->{'milestones'} = \@milestones; + $template->process("admin/milestones/list.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } @@ -254,25 +228,15 @@ unless ($action) { # if ($action eq 'add') { - PutHeader("Add milestone for $product"); + CheckProduct($product); my $product_id = get_product_id($product); - #print "This page lets you add a new milestone to a $::bugzilla_name tracked product.\n"; + $vars->{'product'} = $product; + $template->process("admin/milestones/create.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); - print "

\n"; - print "\n"; - - EmitFormElements($product, $milestone, 0); - - print "
\n
\n"; - print "\n"; - print "\n"; - print "
"; - - my $other = $localtrailer; - $other =~ s/more/other/; - PutTrailer($other); exit; } @@ -283,42 +247,57 @@ if ($action eq 'add') { # if ($action eq 'new') { - PutHeader("Adding new milestone for $product"); + CheckProduct($product); my $product_id = get_product_id($product); # Cleanups and valididy checks - unless ($milestone) { - print "You must enter a text for the new milestone. Please press\n"; - print "Back and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('milestone_blank_name', + {'name' => $milestone}); + exit; + } + + if (length($milestone) > 20) { + ThrowUserError('milestone_name_too_long', + {'name' => $milestone}); exit; } + + # Need to store in case detaint_natural() clears the sortkey + my $stored_sortkey = $sortkey; if (!detaint_natural($sortkey)) { - print "The sortkey for a milestone must be a number. Please press\n"; - print "Back and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('milestone_sortkey_invalid', + {'name' => $milestone, + 'sortkey' => $stored_sortkey}); exit; } - if (TestMilestone($product,$milestone)) { - print "The milestone '$milestone' already exists. Please press\n"; - print "Back and try again.\n"; - PutTrailer($localtrailer); + if (TestMilestone($product, $milestone)) { + ThrowUserError('milestone_already_exists', + {'name' => $milestone, + 'product' => $product}); exit; } # Add the new milestone - SendSQL("INSERT INTO milestones ( " . - "value, product_id, sortkey" . - " ) VALUES ( " . - SqlQuote($milestone) . ", $product_id, $sortkey)"); + my $dbh = Bugzilla->dbh; + trick_taint($milestone); + $dbh->do('INSERT INTO milestones ( value, product_id, sortkey ) + VALUES ( ?, ?, ? )', + undef, + $milestone, + $product_id, + $sortkey); # Make versioncache flush unlink "$datadir/versioncache"; - print "OK, done.

\n"; - PutTrailer("add another milestone or $localtrailer"); + $vars->{'name'} = $milestone; + $vars->{'product'} = $product; + $template->process("admin/milestones/created.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } @@ -332,72 +311,38 @@ if ($action eq 'new') { # if ($action eq 'del') { - PutHeader("Delete milestone of $product"); + CheckMilestone($product, $milestone); my $product_id = get_product_id($product); - SendSQL("SELECT count(bug_id), product_id, target_milestone - FROM bugs - GROUP BY product_id, target_milestone - HAVING product_id=$product_id - AND target_milestone=" . SqlQuote($milestone)); - my $bugs = FetchOneColumn(); - - SendSQL("SELECT defaultmilestone FROM products " . - "WHERE id=$product_id"); - my $defaultmilestone = FetchOneColumn(); - - print "\n"; - print "\n"; - print " \n"; - print " \n"; - - print "\n"; - print " \n"; - print " \n"; - print "\n"; - print " \n"; - print " \n"; - print "\n"; - print " \n"; - print " \n"; - print "
PartValue
Product:$product
Milestone:$milestone
Bugs:", $bugs || 'none' , "
\n"; - - print "

Confirmation

\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 "
\n", - "There are bugs entered for this milestone! When you delete this ", - "milestone, all stored bugs will be deleted, too. ", - "You could not even see the bug history for this milestone anymore!\n", - "
\n"; - } + my $dbh = Bugzilla->dbh; - if ($defaultmilestone eq $milestone) { - print "Sorry; this is the default milestone for this product, and " . - "so it can not be deleted."; - PutTrailer($localtrailer); - exit; - } + my $sth = $dbh->prepare('SELECT count(bug_id), product_id, target_milestone + FROM bugs + GROUP BY product_id, target_milestone + HAVING product_id = ? + AND target_milestone = ?'); + + trick_taint($milestone); + $vars->{'bug_count'} = $dbh->selectrow_array($sth, + undef, + $product_id, + $milestone) || 0; + + $sth = $dbh->prepare('SELECT defaultmilestone + FROM products + WHERE id = ?'); + + $vars->{'default_milestone'} = $dbh->selectrow_array($sth, + undef, + $product_id) || ''; + + $vars->{'name'} = $milestone; + $vars->{'product'} = $product; + $template->process("admin/milestones/confirm-delete.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); - print "

Do you really want to delete this milestone?

\n"; - print "

\n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - print "
"; - - PutTrailer($localtrailer); exit; } @@ -408,55 +353,89 @@ one."; # if ($action eq 'delete') { - PutHeader("Deleting milestone of $product"); + CheckMilestone($product,$milestone); my $product_id = get_product_id($product); + my $dbh = Bugzilla->dbh; + # lock the tables before we start to change everything: - SendSQL("LOCK TABLES attachments WRITE, - bugs WRITE, - bugs_activity WRITE, - milestones WRITE, - dependencies WRITE"); + $dbh->do('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. + # Detaint this here, as we may need it if deleting bugs, but will + # definitely need it detainted whhen we actually delete the + # milestone itself + trick_taint($milestone); + if (Param("allowbugdeletion")) { - SendSQL("SELECT bug_id - FROM bugs - WHERE product_id=$product_id - AND target_milestone=" . SqlQuote($milestone)); - while (MoreSQLData()) { - my $bugid = FetchOneColumn(); - - PushGlobalSQLState(); - SendSQL("DELETE FROM attachments WHERE bug_id=$bugid"); - SendSQL("DELETE FROM bugs_activity WHERE bug_id=$bugid"); - SendSQL("DELETE FROM dependencies WHERE blocked=$bugid"); - PopGlobalSQLState(); + my $deleted_bug_count = 0; + + my $sth = $dbh->prepare_cached('SELECT bug_id + FROM bugs + WHERE product_id = ? + AND target_milestone = ?'); + + my $data = $dbh->selectall_arrayref($sth, + undef, + $product_id, + $milestone); + + foreach my $aref (@$data) { + + my ($bugid) = @$aref; + + $dbh->do('DELETE FROM attachments WHERE bug_id = ?', + undef, + $bugid); + $dbh->do('DELETE FROM bugs_activity WHERE bug_id = ?', + undef, + $bugid); + $dbh->do('DELETE FROM dependencies WHERE blocked = ?', + undef, + $bugid); + + $deleted_bug_count++; } - print "Attachments, bug activity and dependencies deleted.
\n"; + $vars->{'deleted_bug_count'} = $deleted_bug_count; # Deleting the rest is easier: - SendSQL("DELETE FROM bugs - WHERE product_id=$product_id - AND target_milestone=" . SqlQuote($milestone)); - print "Bugs deleted.
\n"; + $dbh->do('DELETE FROM bugs + WHERE product_id = ? + AND target_milestone = ?', + undef, + $product_id, + $milestone); } - SendSQL("DELETE FROM milestones - WHERE product_id=$product_id - AND value=" . SqlQuote($milestone)); - print "Milestone deleted.

\n"; + $dbh->do('DELETE FROM milestones + WHERE product_id = ? + AND value = ?', + undef, + $product_id, + $milestone); + + $dbh->do('UNLOCK TABLES'); unlink "$datadir/versioncache"; - PutTrailer($localtrailer); + + + $vars->{'name'} = $milestone; + $vars->{'product'} = $product; + $template->process("admin/milestones/deleted.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); exit; } @@ -469,33 +448,31 @@ if ($action eq 'delete') { # if ($action eq 'edit') { - PutHeader("Edit milestone of $product"); - CheckMilestone($product,$milestone); + + CheckMilestone($product, $milestone); my $product_id = get_product_id($product); - SendSQL("SELECT sortkey FROM milestones WHERE product_id=$product_id " . - " AND value = " . SqlQuote($milestone)); - my $sortkey = FetchOneColumn(); + my $dbh = Bugzilla->dbh; - print "

\n"; - print "\n"; + my $sth = $dbh->prepare_cached('SELECT sortkey + FROM milestones + WHERE product_id = ? + AND value = ?'); - EmitFormElements($product, $milestone, $sortkey); + trick_taint($milestone); - print "
\n"; + $vars->{'sortkey'} = $dbh->selectrow_array($sth, + undef, + $product_id, + $milestone) || 0; - print "\n"; - print "\n"; - print "\n"; - print "\n"; + $vars->{'name'} = $milestone; + $vars->{'product'} = $product; - print "
"; + $template->process("admin/milestones/edit.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); - my $other = $localtrailer; - $other =~ s/more/other/; - PutTrailer($other); exit; } @@ -506,69 +483,117 @@ if ($action eq 'edit') { # if ($action eq 'update') { - PutHeader("Update milestone of $product"); - my $milestoneold = trim($::FORM{milestoneold} || ''); - my $sortkeyold = trim($::FORM{sortkeyold} || '0'); + my $milestoneold = trim($cgi->param('milestoneold') || ''); + my $sortkeyold = trim($cgi->param('sortkeyold') || '0'); - CheckMilestone($product,$milestoneold); + CheckMilestone($product, $milestoneold); my $product_id = get_product_id($product); - SendSQL("LOCK TABLES bugs WRITE, - milestones WRITE, - products WRITE"); + if (length($milestone) > 20) { + ThrowUserError('milestone_name_too_long', + {'name' => $milestone}); + exit; + } + + my $dbh = Bugzilla->dbh; + + $dbh->do("LOCK TABLES bugs WRITE, + milestones WRITE, + products WRITE"); + # Need to store because detaint_natural() will delete this if + # invalid + my $stored_sortkey = $sortkey; if ($sortkey != $sortkeyold) { if (!detaint_natural($sortkey)) { - print "The sortkey for a milestone must be a number. Please press\n"; - print "Back and try again.\n"; - PutTrailer($localtrailer); + + $dbh->do('UNLOCK TABLES'); + ThrowUserError('milestone_sortkey_invalid', + {'name' => $milestone, + 'sortkey' => $stored_sortkey}); + exit; } - SendSQL("UPDATE milestones SET sortkey=$sortkey - WHERE product_id=" . $product_id . " - AND value=" . SqlQuote($milestoneold)); + + trick_taint($milestoneold); + + $dbh->do('UPDATE milestones SET sortkey = ? + WHERE product_id = ? + AND value = ?', + undef, + $sortkey, + $product_id, + $milestoneold); + unlink "$datadir/versioncache"; - print "Updated sortkey.
\n"; + $vars->{'updated_sortkey'} = 1; + $vars->{'sortkey'} = $sortkey; } + if ($milestone ne $milestoneold) { unless ($milestone) { - print "Sorry, I can't delete the milestone text."; - PutTrailer($localtrailer); + $dbh->do('UNLOCK TABLES'); + ThrowUserError('milestone_blank_name'); exit; } - if (TestMilestone($product,$milestone)) { - print "Sorry, milestone '$milestone' is already in use."; - PutTrailer($localtrailer); + if (TestMilestone($product, $milestone)) { + $dbh->do('UNLOCK TABLES'); + ThrowUserError('milestone_already_exists', + {'name' => $milestone, + 'product' => $product}); exit; } - SendSQL("UPDATE bugs - SET target_milestone=" . SqlQuote($milestone) . ", - delta_ts=delta_ts - WHERE target_milestone=" . SqlQuote($milestoneold) . " - AND product_id=$product_id"); - SendSQL("UPDATE milestones - SET value=" . SqlQuote($milestone) . " - WHERE product_id=$product_id - AND value=" . SqlQuote($milestoneold)); - SendSQL("UPDATE products " . - "SET defaultmilestone = " . SqlQuote($milestone) . - " WHERE id = $product_id" . - " AND defaultmilestone = " . SqlQuote($milestoneold)); + + trick_taint($milestone); + trick_taint($milestoneold); + + $dbh->do('UPDATE bugs + SET target_milestone = ?, + delta_ts = delta_ts + WHERE target_milestone = ? + AND product_id = ?', + undef, + $milestone, + $milestoneold, + $product_id); + + $dbh->do("UPDATE milestones + SET value = ? + WHERE product_id = ? + AND value = ?", + undef, + $milestone, + $product_id, + $milestoneold); + + $dbh->do("UPDATE products + SET defaultmilestone = ? + WHERE id = ? + AND defaultmilestone = ?", + undef, + $milestone, + $product_id, + $milestoneold); + unlink "$datadir/versioncache"; - print "Updated milestone.
\n"; + + $vars->{'updated_name'} = 1; } - PutTrailer($localtrailer); + $dbh->do('UNLOCK TABLES'); + + $vars->{'name'} = $milestone; + $vars->{'product'} = $product; + $template->process("admin/milestones/updated.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } - # # No valid action found # - -PutHeader("Error"); -print "I don't have a clue what you want.
\n"; - +ThrowUserError('milestone_no_action'); diff --git a/t/008filter.t b/t/008filter.t index 5594a26e7..cc5c63f4b 100644 --- a/t/008filter.t +++ b/t/008filter.t @@ -202,7 +202,7 @@ sub directive_ok { return 1 if $directive =~ /^(time2str|GetBugLink|url)\(/; # Safe Template Toolkit virtual methods - return 1 if $directive =~ /\.((size)$|(push))/; + return 1 if $directive =~ /\.(length$|size$|push\()/; # Special Template Toolkit loop variable return 1 if $directive =~ /^loop\.(index|count)$/; diff --git a/template/en/default/admin/milestones/confirm-delete.html.tmpl b/template/en/default/admin/milestones/confirm-delete.html.tmpl new file mode 100644 index 000000000..893b849ae --- /dev/null +++ b/template/en/default/admin/milestones/confirm-delete.html.tmpl @@ -0,0 +1,135 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # name: string; The name of the milestone + # + # default_milestone: string; The default milestone for the product + # + # bug_count: number; The number of bugs targetted at the milestone + # + # product: string; The name of the product + # + #%] + +[% title = BLOCK %]Delete Milestone of Product '[% product FILTER html %]' + [% END %] + +[% PROCESS global/header.html.tmpl + title = title +%] + + + + + + + + + + + + + + + + + + +
FieldValue
Milestone:[% name FILTER html %]
Milestone of Product:[% product FILTER html %]
[% terms.Bugs %]: +[% IF bug_count %] + [% bug_count %] +[% ELSE %] + None +[% END %] +
+ +

Confirmation

+ +[% IF bug_count %] + + [% IF !Param("allowbugdeletion") %] + + Sorry, there + + [% IF bug_count > 1 %] + are [% bug_count %] [%+ terms.bugs %] + [% ELSE %] + is [% bug_count %] [%+ terms.bug %] + [% END %] + + outstanding for this milestone. You must move + + [% IF bug_count > 1 %] + those [% terms.bugs %] + [% ELSE %] + that [% terms.bug %] + [% END %] + + to another milestone before you can delete this one. + + [% ELSE %] + +
+ + There [% IF bug_count > 1 %] + are [% bug_count %] [%+ terms.bugs %] + [% ELSE %] + is 1 [% terms.bug %] + [% END %] + entered for this milestone! When you delete this + milestone, ALL stored [% terms.bugs %] will be deleted, + too. + You could not even see the [% terms.bug %] history for this milestone anymore! +
+ + [% END %] + +[% END %] + +[% IF default_milestone == name %] + +

Sorry, but '[% name FILTER html %]' is the default milestone for product ' + [%- product FILTER html %]', and so it can not be deleted. + + [% ELSE %] + + [% IF bug_count == 0 || Param('allowbugdeletion') %] + +

Do you really want to delete this milestone?

+ +

+ + + + +
+ + [% END %] + +[% END %] + +[% PROCESS admin/milestones/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/create.html.tmpl b/template/en/default/admin/milestones/create.html.tmpl new file mode 100644 index 000000000..ac707c195 --- /dev/null +++ b/template/en/default/admin/milestones/create.html.tmpl @@ -0,0 +1,59 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # product: string; name of the product the milestone is being created for + #%] + +[% title = BLOCK %]Add Milestone to Product '[% product FILTER html %]'[% END %] +[% h2 = BLOCK %]This page allows you to add a new milestone to product + '[% product FILTER html %]'.[% END %] +[% PROCESS global/header.html.tmpl + title = title + h2 = h2 +%] + +
+ + + + + + + + + +
+ + + + +
+ +

+ +[% PROCESS admin/milestones/footer.html.tmpl + no_add_milestone_link = 1 + %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/created.html.tmpl b/template/en/default/admin/milestones/created.html.tmpl new file mode 100644 index 000000000..87e08cebe --- /dev/null +++ b/template/en/default/admin/milestones/created.html.tmpl @@ -0,0 +1,44 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # name: string; the name of the newly created milestone + # + # product: string; the name of the product the milestone belongs to + #%] + +[% title = BLOCK %]Adding new Milestone of Product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +

The milestone ' + [%- name FILTER html %]' has been created.

+ +

+ +[% PROCESS admin/milestones/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/deleted.html.tmpl b/template/en/default/admin/milestones/deleted.html.tmpl new file mode 100644 index 000000000..61abb38e5 --- /dev/null +++ b/template/en/default/admin/milestones/deleted.html.tmpl @@ -0,0 +1,69 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # name: string; the name of the deleted milestone. + # + # product: string; the name of the product the milestone belonged to + # + # deleted_bug_count: number; the number of bugs which were deleted + # (if bug deletion is allowed) + #%] + +[% title = BLOCK %]Deleted Milestone '[% name FILTER html %]' of Product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +

+[% IF deleted_bug_count %] + Attachments, [% terms.bug %] activity and dependencies deleted for + [%+ deleted_bug_count %] + [% IF deleted_bug_count > 1 %] + [%+ terms.bugs %] + [% ELSE %] + [%+ terms.bug %] + [% END %]. + +

+ [% deleted_bug_count %] + [% IF deleted_bug_count > 1 %] + [%+ terms.bugs %] + [% ELSE %] + [%+ terms.bug %] + [% END %] + deleted. + +[% ELSE %] + No [% terms.bugs %] were targetted at the milestone. +[% END %] +

+ +

Milestone '[% name FILTER html %]' deleted.

+ +

+ +[% PROCESS admin/milestones/footer.html.tmpl + no_edit_milestone_link = 1 + %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/edit.html.tmpl b/template/en/default/admin/milestones/edit.html.tmpl new file mode 100644 index 000000000..6b5ec8fb0 --- /dev/null +++ b/template/en/default/admin/milestones/edit.html.tmpl @@ -0,0 +1,67 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # name: string; The name of the milestone + # + # sortkey: number; milestone sortkey + # + # product: string; The product the milestone belongs to + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% title = BLOCK %]Edit Milestone '[% name FILTER html %]' of product ' + [%- product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +

+ + + + + + + + + + + +
+ + + + + + + +
+ +

+ +[% PROCESS admin/milestones/footer.html.tmpl + no_edit_milestone_link = 1 %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/footer.html.tmpl b/template/en/default/admin/milestones/footer.html.tmpl new file mode 100644 index 000000000..8980d642e --- /dev/null +++ b/template/en/default/admin/milestones/footer.html.tmpl @@ -0,0 +1,66 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # name: string; the name of the milestone + # + # product: string; the name of the product which the milestone + # belongs/belonged to + # + # no_XXX_link: boolean; if defined, then don't show the corresponding + # link. Supported parameters are: + # + # no_edit_milestone_link + # no_edit_other_milestones_link + # no_add_milestone_link + #%] + +

+ +


+ +[% UNLESS no_add_milestone_link %] + Add a milestone. +[% END %] + +[% IF name && !no_edit_milestone_link %] + Edit milestone + '[% name FILTER html %]'. +[% END %] + +[% UNLESS no_edit_other_milestones_link %] + Edit other milestones of product '[% product FILTER html %]'. + +[% END %] + + Edit product '[% product FILTER html %]'. + +

diff --git a/template/en/default/admin/milestones/list.html.tmpl b/template/en/default/admin/milestones/list.html.tmpl new file mode 100644 index 000000000..160dcd6da --- /dev/null +++ b/template/en/default/admin/milestones/list.html.tmpl @@ -0,0 +1,77 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # milestones: array of hashes having the following properties: + # - name: string; The name of the milestone. + # - sortkey: number; The sortkey used to order the milestone. + # + # product: string; the name of the product we are editing milestones for + #%] + +[% USE Bugzilla %] +[% cgi = Bugzilla.cgi %] + +[% PROCESS global/variables.none.tmpl %] + +[% title = BLOCK %]Select milestone of product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +[% edit_contentlink = BLOCK %]editmilestones.cgi?action=edit&product= + [%- product FILTER url_quote %]&milestone=%%name%%[% END %] +[% delete_contentlink = BLOCK %]editmilestones.cgi?action=del&product= + [%- product FILTER url_quote %]&milestone=%%name%%[% END %] + + +[% columns = [ + { + name => "name" + heading => "Edit milestone..." + contentlink => edit_contentlink + }, + { + name => "sortkey" + heading => "Sortkey" + }, + ] +%] + +[% columns.push({ + heading => "Action" + content => "Delete" + contentlink => delete_contentlink + }) %] + +[% PROCESS admin/table.html.tmpl + columns = columns + data = milestones +%] + +

+ +[% PROCESS admin/milestones/footer.html.tmpl + no_edit_other_milestones_link = 1 + %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/select-product.html.tmpl b/template/en/default/admin/milestones/select-product.html.tmpl new file mode 100644 index 000000000..b1eee5ecf --- /dev/null +++ b/template/en/default/admin/milestones/select-product.html.tmpl @@ -0,0 +1,60 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley (bugzilla@chimpychompy.org) + # + #%] + +[%# INTERFACE: + # products: array of hashes having the following properties: + # - name: string; The name of the product. + # - description: string; The description of the product. + #%] + +[% USE Bugzilla %] +[% cgi = Bugzilla.cgi %] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS global/header.html.tmpl + title = "Edit milestones for which product?" +%] + +[% bug_count_contentlink = BLOCK %]buglist.cgi?target_milestone=%%name%%&product= + [%- product FILTER url_quote %][% END %] + +[% columns = [ + { + name => "name" + heading => "Edit milestones of..." + contentlink => "editmilestones.cgi?product=%%name%%" + }, + { + name => "description" + heading => "Description" + allow_html_content => 1 + } + ] +%] + +[% PROCESS admin/table.html.tmpl + columns = columns + data = products +%] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/milestones/updated.html.tmpl b/template/en/default/admin/milestones/updated.html.tmpl new file mode 100644 index 000000000..bfc09e210 --- /dev/null +++ b/template/en/default/admin/milestones/updated.html.tmpl @@ -0,0 +1,58 @@ +[%# 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. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Gavin Shelley + #%] + +[%# INTERFACE: + # + # 'updated_XXX' variables are booleans, and are defined if the + # 'XXX' field was updated during the edit just being handled. + # Variables called just 'XXX' are strings, and are the _new_ contents + # of the fields. + # + # name & updated_name: the name of the milestone + # + # sortkey & updated_sortkey: the milestone sortkey + # + # product: string; the name of the product the milestone belongs to + #%] + +[% title = BLOCK %]Updating Milestone '[% name FILTER html %]' of Product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +[% IF updated_name %] +

Updated Milestone name to: '[% name FILTER html %]'.

+[% END %] + +[% IF updated_sortkey %] +

Updated Milestone sortkey to: '[% sortkey FILTER html %]'.

+[% END %] + +[% UNLESS updated_sortkey || updated_name %] +

Nothing changed for milestone '[% name FILTER html %]'. +[% END %] + +

+ +[% PROCESS admin/milestones/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl index 9c8cd3b5b..8d03d1aae 100644 --- a/template/en/default/filterexceptions.pl +++ b/template/en/default/filterexceptions.pl @@ -30,7 +30,8 @@ # Values always used for numbers - [% (i|j|k|n|count) %] # Params - [% Param(... # Safe functions - [% (time2str|GetBugLink)... -# Safe vmethods - [% foo.size %] +# Safe vmethods - [% foo.size %] [% foo.length %] +# [% foo.push() %] # TT loop variables - [% loop.count %] # Already-filtered stuff - [% wibble FILTER html %] # where the filter is one of html|csv|js|url_quote|quoteUrls|time|uri|xml|none @@ -559,6 +560,14 @@ 'cgi.query_string' ], +'admin/milestones/confirm-delete.html.tmpl' => [ + 'bug_count' +], + +'admin/milestones/deleted.html.tmpl' => [ + 'deleted_bug_count' +], + 'account/login.html.tmpl' => [ 'target', ], diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 7638806cf..27e9ec863 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -181,6 +181,11 @@ Sorry, you aren't a member of the 'editcomponents' group, and so you aren't allowed to add, modify or delete components. + [% ELSIF error == "auth_cant_edit_milestones" %] + [% title = "Access Denied" %] + Sorry, you aren't a member of the 'editcomponents' group, and so + you aren't allowed to add, modify or delete milestones. + [% ELSIF error == "component_already_exists" %] [% title = "Component Already Exists" %] A component with the name '[% name FILTER html %]' already exists. @@ -553,6 +558,33 @@ [% title = "Login Name Required" %] You must enter a login name when using your login as a pronoun. + [% ELSIF error == "milestone_already_exists" %] + [% title = "Milestone Already Exists" %] + The milestone '[% name FILTER html %]' already exists for product ' + [%- product FILTER html %]'. + + [% ELSIF error == "milestone_blank_name" %] + [% title = "Blank Milestone Name Not Allowed" %] + You must enter a name for this milestone. + + [% ELSIF error == "milestone_name_too_long" %] + [% title = "Milestone Name Is Too Long" %] + The name of a milestone is limited to 20 characters. + '[% name FILTER html %]' is too long ([% name.length %] characters). + + [% ELSIF error == "milestone_no_action" %] + [% title = "No valid action specified" %] + No valid action was specified when trying to edit milestones. + + [% ELSIF error == "milestone_not_specified" %] + [% title = "No Milestone Specified" %] + No milestone specified when trying to edit milestones. + + [% ELSIF error == "milestone_not_valid" %] + [% title = "Specified Milestone Does Not Exist" %] + The milestone '[% milestone FILTER html %]' for product + '[% product FILTER html %]' does not exist. + [% ELSIF error == "milestone_required" %] [% title = "Milestone Required" %] You must determine a target milestone for [% terms.bug %] @@ -560,6 +592,11 @@ if you are going to accept it. Part of accepting [% terms.abug %] is giving an estimate of when it will be fixed. + [% ELSIF error == "milestone_sortkey_invalid" %] + [% title = "Invalid Milestone Sortkey" %] + The sortkey '[% sortkey FILTER html %]' for milestone ' + [% name FILTER html %]' is not a valid (positive) number. + [% ELSIF error == "misarranged_dates" %] [% title = "Misarranged Dates" %] Your start date ([% datefrom FILTER html %]) is after -- cgit v1.2.3-24-g4f1b