diff options
author | jocuri%softhome.net <> | 2004-07-31 07:16:36 +0200 |
---|---|---|
committer | jocuri%softhome.net <> | 2004-07-31 07:16:36 +0200 |
commit | e0779526883e06fdd418557d7f5928b3ec443e43 (patch) | |
tree | 4cb03ee0cd71a09faef0a265340993dc037b154d | |
parent | d0b82de8afb79809f8ecc3d39c337b2bcf46b0bc (diff) | |
download | bugzilla-e0779526883e06fdd418557d7f5928b3ec443e43.tar.gz bugzilla-e0779526883e06fdd418557d7f5928b3ec443e43.tar.xz |
Patch for bug 190220: templatize editcomponents.cgi; patch by GavinS <bugzilla@chimpychompy.org>; r=jouni, a=justdave.
24 files changed, 1148 insertions, 442 deletions
diff --git a/editcomponents.cgi b/editcomponents.cgi index 864986d80..28f5b9daf 100755 --- a/editcomponents.cgi +++ b/editcomponents.cgi @@ -35,19 +35,12 @@ use Bugzilla::Constants; use Bugzilla::Config qw(:DEFAULT $datadir); use Bugzilla::Series; -# Shut up misguided -w warnings about "used only once". For some reason, -# "use vars" chokes on me when I try it here. - -sub sillyness { - my $zz; - $zz = $::buffer; -} - - -my $dobugcounts = (defined $::FORM{'dobugcounts'}); +use vars qw($template $vars); my $cgi = Bugzilla->cgi; +my $showbugcounts = (defined $cgi->param('showbugcounts')); + # TestProduct: just returns if the specified product does exists # CheckProduct: same check, optionally emit an error text # TestComponent: just returns if the specified product/component combination exists @@ -60,7 +53,7 @@ sub TestProduct ($) # does the product exist? SendSQL("SELECT name FROM products - WHERE name=" . SqlQuote($prod)); + WHERE name = " . SqlQuote($prod)); return FetchOneColumn(); } @@ -70,130 +63,52 @@ sub CheckProduct ($) # do we have a product? unless ($prod) { - print "Sorry, you haven't specified a product."; - PutTrailer(); + ThrowUserError('product_not_specified'); exit; } unless (TestProduct $prod) { - print "Sorry, product '$prod' does not exist."; - PutTrailer(); + ThrowUserError('product_doesnt_exist', + {'product' => $prod}); exit; } } sub TestComponent ($$) { - my ($prod,$comp) = @_; + my ($prod, $comp) = @_; - # does the product exist? + # does the product/component combination exist? SendSQL("SELECT components.name FROM components, products WHERE products.id = components.product_id - AND products.name=" . SqlQuote($prod) . " AND components.name=" . SqlQuote($comp)); + AND products.name = " . SqlQuote($prod) . " + AND components.name = " . SqlQuote($comp)); return FetchOneColumn(); } sub CheckComponent ($$) { - my ($prod,$comp) = @_; + my ($prod, $comp) = @_; # do we have the component? unless ($comp) { - print "Sorry, you haven't specified a component."; - PutTrailer(); + ThrowUserError('component_not_specified'); exit; } CheckProduct($prod); - unless (TestComponent $prod,$comp) { - print "Sorry, component '$comp' for product '$prod' does not exist."; - PutTrailer(); + unless (TestComponent $prod, $comp) { + ThrowUserError('component_not_valid', + {'product' => $prod, + 'name' => $comp}); exit; } } # -# Displays the form to edit component parameters -# - -sub EmitFormElements ($$$$$) -{ - my ($product, $component, $initialownerid, $initialqacontactid, $description) = @_; - - my ($initialowner, $initialqacontact) = ($initialownerid ? DBID_to_name ($initialownerid) : '', - $initialqacontactid ? DBID_to_name ($initialqacontactid) : ''); - - print " <TH ALIGN=\"right\">Component:</TH>\n"; - print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"component\" VALUE=\"" . - value_quote($component) . "\">\n"; - print " <INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" . - value_quote($product) . "\"></TD>\n"; - - print "</TR><TR>\n"; - print " <TH ALIGN=\"right\">Description:</TH>\n"; - print " <TD><TEXTAREA ROWS=4 COLS=64 WRAP=VIRTUAL NAME=\"description\">" . - value_quote($description) . "</TEXTAREA></TD>\n"; - - print "</TR><TR>\n"; - print " <TH ALIGN=\"right\">Initial owner:</TH>\n"; - print " <TD><INPUT TYPE=TEXT SIZE=64 MAXLENGTH=255 NAME=\"initialowner\" VALUE=\"" . - value_quote($initialowner) . "\"></TD>\n"; - - if (Param('useqacontact')) { - print "</TR><TR>\n"; - print " <TH ALIGN=\"right\">Initial QA contact:</TH>\n"; - print " <TD><INPUT TYPE=TEXT SIZE=64 MAXLENGTH=255 NAME=\"initialqacontact\" VALUE=\"" . - value_quote($initialqacontact) . "\"></TD>\n"; - } -} - - -# -# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d." -# -# XXX This implementation of PutTrailer outputs a default link back to the -# query page instead of the index, which is inconsistent with other -# PutTrailer() implementations. -# - -sub PutTrailer (@) -{ - my (@links) = ("Back to the <A HREF=\"query.cgi\">query page</A>", @_); - SendSQL("UNLOCK TABLES"); - - my $count = $#links; - my $num = 0; - print "<P>\n"; - if (!$dobugcounts) { - print qq{<a href="editcomponents.cgi?dobugcounts=1&$::buffer">}; - print qq{Redisplay table with bug counts (slower)</a><p>\n}; - } - foreach (@links) { - print $_; - if ($num == $count) { - print ".\n"; - } - elsif ($num == $count-1) { - print " or "; - } - else { - print ", "; - } - $num++; - } - PutFooter(); -} - - - - - - - -# # Preliminary checks: # @@ -202,10 +117,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 components.\n"; - PutTrailer(); + ThrowUserError('auth_cant_edit_components'); exit; } @@ -213,15 +125,9 @@ unless (UserInGroup("editcomponents")) { # # often used variables # -my $product = trim($::FORM{product} || ''); -my $component = trim($::FORM{component} || ''); -my $action = trim($::FORM{action} || ''); -my $localtrailer; -if ($product) { - $localtrailer = "<A HREF=\"editcomponents.cgi?product=" . url_quote($product) . "\">edit</A> more components"; -} else { - $localtrailer = "<A HREF=\"editcomponents.cgi\">edit</A> more components"; -} +my $product = trim($cgi->param('product') || ''); +my $component = trim($cgi->param('component') || ''); +my $action = trim($cgi->param('action') || ''); @@ -230,41 +136,40 @@ if ($product) { # unless ($product) { - PutHeader("Select product"); - if ($dobugcounts){ - SendSQL("SELECT products.name,products.description,COUNT(bug_id) - FROM products LEFT JOIN bugs ON products.id = bugs.product_id - GROUP BY products.name - ORDER BY products.name"); + my @products = (); + + if ($showbugcounts){ + SendSQL("SELECT products.name, products.description, COUNT(bug_id) + FROM products LEFT JOIN bugs ON products.id = bugs.product_id + GROUP BY products.name + ORDER BY products.name"); } else { - SendSQL("SELECT products.name,products.description - FROM products - ORDER BY products.name"); + SendSQL("SELECT products.name, products.description + FROM products + ORDER BY products.name"); } - print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n"; - print " <TH ALIGN=\"left\">Edit components of ...</TH>\n"; - print " <TH ALIGN=\"left\">Description</TH>\n"; - if ($dobugcounts) { - print " <TH ALIGN=\"left\">Bugs</TH>\n"; - } - #print " <TH ALIGN=\"left\">Edit</TH>\n"; - print "</TR>"; + while ( MoreSQLData() ) { - my ($product, $description, $bugs) = FetchSQLData(); - $description ||= "<FONT COLOR=\"red\">missing</FONT>"; - print "<TR>\n"; - print " <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n"; - print " <TD VALIGN=\"top\">$description</TD>\n"; - if ($dobugcounts) { - $bugs ||= "none"; - print " <TD VALIGN=\"top\">$bugs</TD>\n"; - } - #print " <TD VALIGN=\"top\"><A HREF=\"editproducts.cgi?action=edit&product=", url_quote($product), "\">Edit</A></TD>\n"; + + my $prod = {}; + + my ($name, $description, $bug_count) = FetchSQLData(); + + $prod->{'name'} = $name; + $prod->{'description'} = $description; + $prod->{'bug_count'} = $bug_count; + + push(@products, $prod); } - print "</TR></TABLE>\n"; - PutTrailer(); + $vars->{'showbugcounts'} = $showbugcounts; + $vars->{'products'} = \@products; + $template->process("admin/components/select-product.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + + exit; } @@ -275,69 +180,53 @@ unless ($product) { # unless ($action) { - PutHeader("Select component of $product"); + CheckProduct($product); my $product_id = get_product_id($product); - - if ($dobugcounts) { - SendSQL("SELECT name,description,initialowner,initialqacontact,COUNT(bug_id) - FROM components LEFT JOIN bugs ON components.id = bugs.component_id - WHERE components.product_id=$product_id - GROUP BY name"); + my @components = (); + + if ($showbugcounts) { + SendSQL("SELECT name,description, initialowner, + initialqacontact, COUNT(bug_id) + FROM components LEFT JOIN bugs ON + components.id = bugs.component_id + WHERE components.product_id = $product_id + GROUP BY name"); } else { - SendSQL("SELECT name,description,initialowner,initialqacontact - FROM components - WHERE product_id=$product_id - GROUP BY name"); + SendSQL("SELECT name, description, initialowner, initialqacontact + FROM components + WHERE product_id = $product_id + GROUP BY name"); } - print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n"; - print " <TH ALIGN=\"left\">Edit component ...</TH>\n"; - print " <TH ALIGN=\"left\">Description</TH>\n"; - print " <TH ALIGN=\"left\">Initial owner</TH>\n"; - print " <TH ALIGN=\"left\">Initial QA contact</TH>\n" - if Param('useqacontact'); - print " <TH ALIGN=\"left\">Bugs</TH>\n" - if $dobugcounts; - print " <TH ALIGN=\"left\">Delete</TH>\n"; - print "</TR>"; - my @data; + while (MoreSQLData()) { - push @data, [FetchSQLData()]; - } - foreach (@data) { - my ($component,$desc,$initialownerid,$initialqacontactid, $bugs) = @$_; - - $desc ||= "<FONT COLOR=\"red\">missing</FONT>"; - my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : "<FONT COLOR=\"red\">missing</FONT>"; - my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : "<FONT COLOR=\"red\">missing</FONT>"; - print "<TR>\n"; - print " <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "&component=", url_quote($component), "&action=edit\"><B>$component</B></A></TD>\n"; - print " <TD VALIGN=\"top\">$desc</TD>\n"; - print " <TD VALIGN=\"top\">$initialowner</TD>\n"; - print " <TD VALIGN=\"top\">$initialqacontact</TD>\n" - if Param('useqacontact'); - if ($dobugcounts) { - $bugs ||= 'none'; - print " <TD VALIGN=\"top\">$bugs</TD>\n"; - } - print " <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "&component=", url_quote($component), "&action=del\"><B>Delete</B></A></TD>\n"; - print "</TR>"; + + my $component = {}; + my ($name, $desc, $initialownerid, $initialqacontactid, $bug_count) + = FetchSQLData(); + + $component->{'name'} = $name; + $component->{'description'} = $desc; + $component->{'initialowner'} = DBID_to_name($initialownerid) + if ($initialownerid); + $component->{'initialqacontact'} = DBID_to_name($initialqacontactid) + if ($initialqacontactid); + $component->{'bug_count'} = $bug_count; + + push(@components, $component); + } - print "<TR>\n"; - my $span = 3; - $span++ if Param('useqacontact'); - $span++ if $dobugcounts; - print " <TD VALIGN=\"top\" COLSPAN=$span>Add a new component</TD>\n"; - print " <TD VALIGN=\"top\" ALIGN=\"middle\"><A HREF=\"editcomponents.cgi?product=", url_quote($product) . "&action=add\">Add</A></TD>\n"; - print "</TR></TABLE>\n"; - - PutTrailer(); - exit; -} + + $vars->{'showbugcounts'} = $showbugcounts; + $vars->{'product'} = $product; + $vars->{'components'} = \@components; + $template->process("admin/components/list.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); -$dobugcounts = 1; # Stupid hack to force further PutTrailer() - # calls to not offer a "bug count" option. + exit; +} # @@ -347,26 +236,15 @@ $dobugcounts = 1; # Stupid hack to force further PutTrailer() # if ($action eq 'add') { - PutHeader("Add component of $product"); - CheckProduct($product); - #print "This page lets you add a new product to bugzilla.\n"; - - print "<FORM METHOD=POST ACTION=editcomponents.cgi>\n"; - print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n"; + CheckProduct($product); - EmitFormElements($product, '', 0, 0, ''); + $vars->{'product'} = $product; + $template->process("admin/components/create.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); - print "</TR></TABLE>\n<HR>\n"; - print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n"; - print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n"; - print "<INPUT TYPE=HIDDEN NAME='open_name' VALUE='All Open'>\n"; - print "<INPUT TYPE=HIDDEN NAME='closed_name' VALUE='All Closed'>\n"; - print "</FORM>"; - my $other = $localtrailer; - $other =~ s/more/other/; - PutTrailer($other); exit; } @@ -377,65 +255,59 @@ if ($action eq 'add') { # if ($action eq 'new') { - PutHeader("Adding new component of $product"); + CheckProduct($product); my $product_id = get_product_id($product); + # Cleanups and valididy checks unless ($component) { - print "You must enter a name for the new component. Please press\n"; - print "<b>Back</b> and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('component_blank_name', + {'name' => $component}); exit; } - if (TestComponent($product,$component)) { - print "The component '$component' already exists. Please press\n"; - print "<b>Back</b> and try again.\n"; - PutTrailer($localtrailer); + if (TestComponent($product, $component)) { + ThrowUserError('component_already_exists', + {'name' => $component}); exit; } if (length($component) > 64) { - print "Sorry, the name of a component is limited to 64 characters."; - PutTrailer($localtrailer); + ThrowUserError('component_name_too_long', + {'name' => $component}); exit; } - my $description = trim($::FORM{description} || ''); + my $description = trim($cgi->param('description') || ''); if ($description eq '') { - print "You must enter a description for the component '$component'. Please press\n"; - print "<b>Back</b> and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('component_blank_description', + {'name' => $component}); exit; } - my $initialowner = trim($::FORM{initialowner} || ''); + my $initialowner = trim($cgi->param('initialowner') || ''); if ($initialowner eq '') { - print "You must enter an initial owner for the component '$component'. Please press\n"; - print "<b>Back</b> and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('component_need_initialowner', + {'name' => $component}); exit; } my $initialownerid = DBname_to_id ($initialowner); if (!$initialownerid) { - print "You must use an existing Bugzilla account as initial owner for the component -'$component'. Please press\n"; - print "<b>Back</b> and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('component_need_valid_initialowner', + {'name' => $component}); exit; - } + } - my $initialqacontact = trim($::FORM{initialqacontact} || ''); + my $initialqacontact = trim($cgi->param('initialqacontact') || ''); my $initialqacontactid = DBname_to_id ($initialqacontact); if (Param('useqacontact')) { if (!$initialqacontactid && $initialqacontact ne '') { - print "You must use an existing Bugzilla account as initial QA contact for the component '$component'. Please press\n"; - print "<b>Back</b> and try again.\n"; - PutTrailer($localtrailer); + ThrowUserError('component_need_valid_initialqacontact', + {'name' => $component}); exit; } } @@ -455,13 +327,14 @@ if ($action eq 'new') { GetVersionTable(); my @series; + my $prodcomp = "&product=$product&component=$component"; # For localisation reasons, we get the title of the queries from the # submitted form. my $open_name = $cgi->param('open_name'); my $closed_name = $cgi->param('closed_name'); - my @openedstatuses = ("UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED"); + my @openedstatuses = OpenStates(); my $statuses = join("&", map { "bug_status=$_" } @openedstatuses) . $prodcomp; my $resolved = "field0-0-0=resolution&type0-0-0=notequals&value0-0-0=---" . $prodcomp; @@ -485,19 +358,12 @@ if ($action eq 'new') { # Make versioncache flush unlink "$datadir/versioncache"; - print "OK, done.<p>\n"; - if ($product) { - PutTrailer("<a href=\"editcomponents.cgi?product=" . - url_quote($product) . "\">edit</a> more components", - "<a href=\"editcomponents.cgi?product=". url_quote($product) . - "&action=add\">add</a> another component", - "<a href=\"editproducts.cgi?action=add\">add</a> a new product"); - } else { - PutTrailer("<a href=\"editcomponents.cgi\">edit</a> more components", - "<a href=\"editcomponents.cgi?action=add\">add</a>" . - "another component", - "<a href=\"editproducts.cgi?action=add\">add</a> a new product"); - } + $vars->{'name'} = $component; + $vars->{'product'} = $product; + $template->process("admin/components/created.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } @@ -510,112 +376,55 @@ if ($action eq 'new') { # if ($action eq 'del') { - PutHeader("Delete component of $product"); + CheckComponent($product, $component); my $component_id = get_component_id(get_product_id($product), $component); # display some data about the component - SendSQL("SELECT products.name,products.description, - products.milestoneurl,products.disallownew, - components.name,components.initialowner, - components.initialqacontact,components.description + SendSQL("SELECT products.name, products.description, + products.milestoneurl, products.disallownew, + components.name, components.initialowner, + components.initialqacontact, components.description FROM products LEFT JOIN components ON products.id = components.product_id WHERE components.id = $component_id"); - my ($product,$pdesc,$milestoneurl,$disallownew, - $component,$initialownerid,$initialqacontactid,$cdesc) = FetchSQLData(); + my ($product, $product_description, $milestoneurl, $disallownew, + $component, $initialownerid, $initialqacontactid, $description) = + FetchSQLData(); - my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : "<FONT COLOR=\"red\">missing</FONT>"; - my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : "<FONT COLOR=\"red\">missing</FONT>"; - my $milestonelink = $milestoneurl ? "<A HREF=\"$milestoneurl\">$milestoneurl</A>" - : "<FONT COLOR=\"red\">missing</FONT>"; - $pdesc ||= "<FONT COLOR=\"red\">missing</FONT>"; - $disallownew = $disallownew ? 'closed' : 'open'; - $cdesc ||= "<FONT COLOR=\"red\">missing</FONT>"; - - print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><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 " <TD VALIGN=\"top\">Component:</TD>\n"; - print " <TD VALIGN=\"top\">$component</TD>"; - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Component description:</TD>\n"; - print " <TD VALIGN=\"top\">$cdesc</TD>"; - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Initial owner:</TD>\n"; - print " <TD VALIGN=\"top\">$initialowner</TD>"; + my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : ''; + my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : ''; + $milestoneurl ||= ''; + $product_description ||= ''; + $disallownew ||= 0; + $description ||= ''; + if (Param('useqacontact')) { - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Initial QA contact:</TD>\n"; - print " <TD VALIGN=\"top\">$initialqacontact</TD>"; + $vars->{'initialqacontact'} = $initialqacontact; } - SendSQL("SELECT count(bug_id) - FROM bugs - WHERE component_id = $component_id"); - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Component of 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\">$pdesc</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"; - - print "</TR><TR>\n"; - print " <TD VALIGN=\"top\">Bugs</TD>\n"; - print " <TD VALIGN=\"top\">"; - 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 component. -You must reassign those bugs to another component 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 component! When you delete this ", - "component, <B><BLINK>all</BLINK></B> stored bugs will be deleted, too. ", - "You could not even see the bug history for this component anymore!\n", - "</TD></TR></TABLE>\n"; + $vars->{'milestoneurl'} = $milestoneurl; } - print "<P>Do you really want to delete this component?<P>\n"; - - print "<FORM METHOD=POST ACTION=editcomponents.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=\"component\" VALUE=\"" . - value_quote($component) . "\">\n"; - print "</FORM>"; + SendSQL("SELECT count(bug_id) + FROM bugs + WHERE component_id = $component_id"); + $vars->{'bug_count'} = FetchOneColumn() || 0; + + $vars->{'name'} = $component; + $vars->{'description'} = $description; + $vars->{'initialowner'} = $initialowner; + $vars->{'product'} = $product; + $vars->{'product_description'} = $product_description; + $vars->{'disallownew'} = $disallownew; + $template->process("admin/components/confirm-delete.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); - PutTrailer($localtrailer); exit; } @@ -626,8 +435,8 @@ one."; # if ($action eq 'delete') { - PutHeader("Deleting component of $product"); - CheckComponent($product,$component); + + CheckComponent($product, $component); my $component_id = get_component_id(get_product_id($product),$component); # lock the tables before we start to change everything: @@ -645,9 +454,11 @@ if ($action eq 'delete') { # in bugs_activies and attachments. if (Param("allowbugdeletion")) { + my $deleted_bug_count = 0; + SendSQL("SELECT bug_id - FROM bugs - WHERE component_id=$component_id"); + FROM bugs + WHERE component_id = $component_id"); while (MoreSQLData()) { my $bugid = FetchOneColumn(); @@ -656,29 +467,36 @@ if ($action eq 'delete') { SendSQL("DELETE FROM bugs_activity WHERE bug_id=$bugid"); SendSQL("DELETE FROM dependencies WHERE blocked=$bugid"); PopGlobalSQLState(); + + $deleted_bug_count++; } - print "Attachments, bug activity and dependencies deleted.<BR>\n"; + $vars->{'deleted_bug_count'} = $deleted_bug_count; # Deleting the rest is easier: SendSQL("DELETE FROM bugs WHERE component_id=$component_id"); - print "Bugs deleted.<BR>\n"; } SendSQL("DELETE FROM flaginclusions WHERE component_id=$component_id"); SendSQL("DELETE FROM flagexclusions WHERE component_id=$component_id"); - print "Flag inclusions and exclusions deleted.<BR>\n"; SendSQL("DELETE FROM components WHERE id=$component_id"); - print "Components deleted.<P>\n"; + + SendSQL("UNLOCK TABLES"); unlink "$datadir/versioncache"; - PutTrailer($localtrailer); + + $vars->{'name'} = $component; + $vars->{'product'} = $product; + $template->process("admin/components/deleted.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } @@ -691,59 +509,40 @@ if ($action eq 'delete') { # if ($action eq 'edit') { - PutHeader("Edit component of $product"); - CheckComponent($product,$component); - my $component_id = get_component_id(get_product_id($product),$component); + + CheckComponent($product, $component); + my $component_id = get_component_id(get_product_id($product), $component); # get data of component - SendSQL("SELECT products.name,products.description, - products.milestoneurl,products.disallownew, - components.name,components.initialowner, - components.initialqacontact,components.description - FROM products LEFT JOIN components ON products.id = components.product_id + SendSQL("SELECT products.name, + components.name, components.initialowner, + components.initialqacontact, components.description + FROM products LEFT JOIN components ON + products.id = components.product_id WHERE components.id = $component_id"); - my ($product,$pdesc,$milestoneurl,$disallownew, - $component,$initialownerid,$initialqacontactid,$cdesc) = FetchSQLData(); + my ($product, $component, $initialownerid, $initialqacontactid, + $description) = FetchSQLData(); my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : ''; my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : ''; - print "<FORM METHOD=POST ACTION=editcomponents.cgi>\n"; - print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n"; + SendSQL("SELECT count(*) + FROM bugs + WHERE component_id = $component_id"); - #+++ display product/product description + $vars->{'bug_count'} = FetchOneColumn() || 0; - EmitFormElements($product, $component, $initialownerid, $initialqacontactid, $cdesc); + $vars->{'name'} = $component; + $vars->{'description'} = $description; + $vars->{'initialowner'} = $initialowner; + $vars->{'initialqacontact'} = $initialqacontact; + $vars->{'product'} = $product; + + $template->process("admin/components/edit.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); - print "</TR><TR>\n"; - print " <TH ALIGN=\"right\">Bugs:</TH>\n"; - print " <TD>"; - SendSQL("SELECT count(*) - FROM bugs - WHERE component_id=$component_id"); - my $bugs = ''; - $bugs = FetchOneColumn() if MoreSQLData(); - print $bugs || 'none'; - - print "</TD>\n</TR></TABLE>\n"; - - print "<INPUT TYPE=HIDDEN NAME=\"componentold\" VALUE=\"" . - value_quote($component) . "\">\n"; - print "<INPUT TYPE=HIDDEN NAME=\"descriptionold\" VALUE=\"" . - value_quote($cdesc) . "\">\n"; - print "<INPUT TYPE=HIDDEN NAME=\"initialownerold\" VALUE=\"" . - value_quote($initialowner) . "\">\n"; - print "<INPUT TYPE=HIDDEN NAME=\"initialqacontactold\" VALUE=\"" . - value_quote($initialqacontact) . "\">\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; } @@ -754,19 +553,18 @@ if ($action eq 'edit') { # if ($action eq 'update') { - PutHeader("Update component of $product"); - my $componentold = trim($::FORM{componentold} || ''); - my $description = trim($::FORM{description} || ''); - my $descriptionold = trim($::FORM{descriptionold} || ''); - my $initialowner = trim($::FORM{initialowner} || ''); - my $initialownerold = trim($::FORM{initialownerold} || ''); - my $initialqacontact = trim($::FORM{initialqacontact} || ''); - my $initialqacontactold = trim($::FORM{initialqacontactold} || ''); + my $componentold = trim($cgi->param('componentold') || ''); + my $description = trim($cgi->param('description') || ''); + my $descriptionold = trim($cgi->param('descriptionold') || ''); + my $initialowner = trim($cgi->param('initialowner') || ''); + my $initialownerold = trim($cgi->param('initialownerold') || ''); + my $initialqacontact = trim($cgi->param('initialqacontact') || ''); + my $initialqacontactold = trim($cgi->param('initialqacontactold') || ''); if (length($component) > 64) { - print "Sorry, the name of a component is limited to 64 characters."; - PutTrailer($localtrailer); + ThrowUserError('component_name_too_long', + {'name' => $component}); exit; } @@ -774,67 +572,74 @@ if ($action eq 'update') { # them, be sure to test for WHERE='$component' or WHERE='$componentold' SendSQL("LOCK TABLES components WRITE, products READ, profiles READ"); - CheckComponent($product,$componentold); + CheckComponent($product, $componentold); my $component_id = get_component_id(get_product_id($product), $componentold); if ($description ne $descriptionold) { unless ($description) { - print "Sorry, I can't delete the description."; - PutTrailer($localtrailer); + SendSQL("UNLOCK TABLES"); + ThrowUserError('component_blank_description', + {'name' => $componentold}); exit; } SendSQL("UPDATE components SET description=" . SqlQuote($description) . " WHERE id=$component_id"); - print "Updated description.<BR>\n"; + + $vars->{'updated_description'} = 1; + $vars->{'description'} = $description; } if ($initialowner ne $initialownerold) { - unless ($initialowner) { - print "Sorry, I can't delete the initial owner."; - PutTrailer($localtrailer); - exit; - } my $initialownerid = DBname_to_id($initialowner); unless ($initialownerid) { - print "Sorry, you must use an existing Bugzilla account as initial owner."; - PutTrailer($localtrailer); + SendSQL("UNLOCK TABLES"); + ThrowUserError('component_need_valid_initialowner', + {'name' => $componentold}); exit; } SendSQL("UPDATE components SET initialowner=" . SqlQuote($initialownerid) . " WHERE id = $component_id"); - print "Updated initial owner.<BR>\n"; + + $vars->{'updated_initialowner'} = 1; + $vars->{'initialowner'} = $initialowner; + } if (Param('useqacontact') && $initialqacontact ne $initialqacontactold) { my $initialqacontactid = DBname_to_id($initialqacontact); if (!$initialqacontactid && $initialqacontact ne '') { - print "Sorry, you must use an existing Bugzilla account as initial QA contact."; - PutTrailer($localtrailer); + SendSQL("UNLOCK TABLES"); + ThrowUserError('component_need_valid_initialqacontact', + {'name' => $componentold}); exit; } SendSQL("UPDATE components SET initialqacontact=" . SqlQuote($initialqacontactid) . " WHERE id = $component_id"); - print "Updated initial QA contact.<BR>\n"; + + $vars->{'updated_initialqacontact'} = 1; + $vars->{'initialqacontact'} = $initialqacontact; } if ($component ne $componentold) { unless ($component) { - print "Sorry, but a component must have a name."; - PutTrailer($localtrailer); + SendSQL("UNLOCK TABLES"); + ThrowUserError('component_must_have_a_name', + {'name' => $componentold}); exit; } - if (TestComponent($product,$component)) { - print "Sorry, component name '$component' is already in use."; - PutTrailer($localtrailer); + if (TestComponent($product, $component)) { + SendSQL("UNLOCK TABLES"); + ThrowUserError('component_already_exists', + {'name' => $component}); exit; } @@ -842,10 +647,18 @@ if ($action eq 'update') { "WHERE id=$component_id"); unlink "$datadir/versioncache"; - print "Updated component name.<BR>\n"; + $vars->{'updated_name'} = 1; + } - PutTrailer($localtrailer); + SendSQL("UNLOCK TABLES"); + + $vars->{'name'} = $component; + $vars->{'product'} = $product; + $template->process("admin/components/updated.html.tmpl", + $vars) + || ThrowTemplateError($template->error()); + exit; } @@ -854,7 +667,4 @@ if ($action eq 'update') { # # No valid action found # - -PutHeader("Error"); -print "I don't have a clue what you want.<BR>\n"; - +ThrowUserError('component_no_action'); diff --git a/t/008filter.t b/t/008filter.t index e3d107bf2..5594a26e7 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)$/; + return 1 if $directive =~ /\.((size)$|(push))/; # Special Template Toolkit loop variable return 1 if $directive =~ /^loop\.(index|count)$/; diff --git a/template/en/default/admin/components/confirm-delete.html.tmpl b/template/en/default/admin/components/confirm-delete.html.tmpl new file mode 100644 index 000000000..a810e026b --- /dev/null +++ b/template/en/default/admin/components/confirm-delete.html.tmpl @@ -0,0 +1,172 @@ +[%# 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: + # name: string; The name of the component + # + # description: string; Component description, may be empty + # + # bug_count: number; The number of bugs belonging to the component + # + # initialowner: string; initial owner, may be empty + # + # initialqacontact: string; if system parameter is set to use the initial + # qa contact field, then this will be it, + # may be empty + # + # milestoneurl: string; milestone url, if milestones are in use, + # may be empty + # + # product: string; The name of the product + # + # disallownew: boolean; Are new bugs allowed for the product flag + # + # product_description: string; Description of product + #%] + +[% title = BLOCK %]Delete Component of Product '[% product FILTER html %]' + [% END %] + +[% PROCESS global/header.html.tmpl + title = title +%] + +<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> +<tr> + <td valign="top">Component:</td> + <td valign="top">[% name FILTER html %]</td> +</tr> +<tr> + <td valign="top">Component Description:</td> + <td valign="top">[% description FILTER html %]</td> +</tr> +<tr> + <td valign="top">Initial owner:</td> + <td valign="top">[% initialowner FILTER html %]</td> + +[% IF Param('useqacontact') %] +</tr> +<tr> + <td valign="top">Initial QA contact:</td> + <td valign="top">[% initialqacontact FILTER html %]</td> +[% END %] + +</tr> +<tr> + <td valign="top">Component of Product:</td> + <td valign="top">[% product FILTER html %]</td> + +[% IF product_description %] +</tr> +<tr> + <td valign="top">Product Description:</td> + <td valign="top">[% product_description FILTER html %]</td> +[% END %] + +[% IF Param('usetargetmilestone') %] +</tr> +<tr> + <td valign="top">Product Milestone URL:</td> + <td valign="top"><a href="[% milestoneurl FILTER uri %]">[% milestoneurl FILTER html %]</a></td> +[% END %] + +</tr> +<tr> + <TD VALIGN="top">Closed for [% terms.bugs %]:</TD> + <TD VALIGN="top">[% IF $disallownew %]Yes[% ELSE %]No[% END %]</td> +</tr> +<tr> + <td valign="top">[% terms.Bugs %]:</td> + <td valign="top"> +[% IF bug_count %] + <a title="List of [% terms.bugs %] for component '[% name FILTER html %]'" + href="buglist.cgi?component=[% name FILTER url_quote %]&product= + [%- product FILTER url_quote %]">[% 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 [% bug_count %] [%+ terms.bug %] + [% END %] + + outstanding for this component. You must reassign + + [% IF bug_count > 1 %] + those [% terms.bugs %] + [% ELSE %] + that [% terms.bug %] + [% END %] + + to another component 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 component! When you delete this + component, <b><blink>ALL</blink></b> stored [% terms.bugs %] will be deleted, + too. + You could not even see the [% terms.bug %] history for this component anymore! + </td></tr></table> + + [% END %] + +[% END %] + +[% IF bug_count == 0 || Param('allowbugdeletion') %] + + <p>Do you really want to delete this component?<p> + + <form method="post" action="editcomponents.cgi"> + <input type="submit" value="Yes, delete"> + <input type="hidden" name="action" value="delete"> + <input type="hidden" name="product" value="[% product FILTER html %]"> + <input type="hidden" name="component" value="[% name FILTER html %]"> + </form> + +[% END %] + +[% PROCESS admin/components/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/confirm-delete.html.tmpl.orig b/template/en/default/admin/components/confirm-delete.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/confirm-delete.html.tmpl.orig diff --git a/template/en/default/admin/components/create.html.tmpl b/template/en/default/admin/components/create.html.tmpl new file mode 100644 index 000000000..0c6a8b335 --- /dev/null +++ b/template/en/default/admin/components/create.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 <bugzilla@chimpychompy.org> + #%] + +[%# INTERFACE: + # product: string; name of product + #%] + +[% title = BLOCK %]Add component to Product '[% product FILTER html %]'[% END %] +[% h2 = BLOCK %]This page allows you to add a new component to product + '[% product FILTER html %]'.[% END %] +[% PROCESS global/header.html.tmpl + title = title + h2 = h2 +%] + +<form method="post" action="editcomponents.cgi"> + <table border="0" cellpadding="4" cellspacing="0"> + <tr> + <th align="right">Component:</th> + <td><input size="64" maxlength="64" name="component" value=""></td> + </tr> + <tr> + <th align="right">Description:</th> + <td> + <textarea rows="4" cols="64" wrap="virtual" + name="description"></textarea> + </td> + </tr> + <tr> + <th align="right">Initial Owner:</th> + <td><input size="64" maxlength="64" name="initialowner" value=""></td> + </tr> +[% IF Param('useqacontact') %] + <tr> + <th align="right">Initial QA Contact:</th> + <td><input size="64" maxlength="64" name="initialqacontact" value=""></td> + </tr> +[% END %] + </table> + <hr> + <input type="submit" value="Add"> + <input type="hidden" name="action" value="new"> + <input type="hidden" name='open_name' value='All Open'> + <input type="hidden" name='closed_name' value='All Closed'> + <input type="hidden" name='product' value="[% product FILTER html %]"> + +</form> + +[% PROCESS admin/components/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/create.html.tmpl.orig b/template/en/default/admin/components/create.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/create.html.tmpl.orig diff --git a/template/en/default/admin/components/created.html.tmpl b/template/en/default/admin/components/created.html.tmpl new file mode 100644 index 000000000..54963065d --- /dev/null +++ b/template/en/default/admin/components/created.html.tmpl @@ -0,0 +1,40 @@ +[%# 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: + # name: string; the name of the newly created component + # + # product: string; the name of the product the component belongs to + #%] + +[% title = BLOCK %]Adding new Component of Product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +<p>The component '<a href="editcomponents.cgi?action=edit&product= + [%- product FILTER url_quote %]&component=[% name FILTER url_quote %]"> + [%- name FILTER html %]</a>' has been created.</p> + +[% PROCESS admin/components/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/created.html.tmpl.orig b/template/en/default/admin/components/created.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/created.html.tmpl.orig diff --git a/template/en/default/admin/components/deleted.html.tmpl b/template/en/default/admin/components/deleted.html.tmpl new file mode 100644 index 000000000..a429e356c --- /dev/null +++ b/template/en/default/admin/components/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 <bugzilla@chimpychompy.org> + #%] + +[%# INTERFACE: + # name: string; the name of the deleted component. + # + # product: string; the name of the product the component belonged to + # + # deleted_bug_count: number; the number of bugs which were deleted + # (if bug deletion is allowed) + #%] + +[% title = BLOCK %]Deleted Component '[% name FILTER html %]' of Product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +<p> +[% IF deleted_bug_count %] + Attachments, [% terms.bug %] activity and dependencies deleted for + [%+ deleted_bug_count %] + [%- IF deleted_bug_count %] + [% terms.bugs %] + [% ELSE %] + [% terms.bug %] + [% END %]. + + </p><p> + [% deleted_bug_count %] + [%- IF deleted_bug_count %] + [% terms.bugs %] + [% ELSE %] + [% terms.bug %] + [% END %] + deleted. + +[% ELSE %] + No [% terms.bugs %] existed for the component. +[% END %] +</p> + +<p>Flag inclusions and exclusions deleted.</p> + +<p>Component '[% name FILTER html %]' deleted.</p> + +[% PROCESS admin/components/footer.html.tmpl + no_edit_component_link = 1 + %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/deleted.html.tmpl.orig b/template/en/default/admin/components/deleted.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/deleted.html.tmpl.orig diff --git a/template/en/default/admin/components/edit.html.tmpl b/template/en/default/admin/components/edit.html.tmpl new file mode 100644 index 000000000..08ecb8f5e --- /dev/null +++ b/template/en/default/admin/components/edit.html.tmpl @@ -0,0 +1,105 @@ +[%# 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: + # name: string; The name of the component. + # + # description: string; Component description, may be empty + # + # initialowner: string; initial owner, may be empty + # + # initialqacontact: string; initial qa contact, may be empty + # + # product: string; The product the component belongs to + # + # bug_count: number; number of bugs belonging to the component + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% title = BLOCK %]Edit Component '[% name FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +<form method="post" action="editcomponents.cgi"> + <table border="0" cellpadding="4" cellspacing="0"> + + <tr> + <td valign="top">Component:</td> + <td><input size="64" maxlength="64" name="component" value=" + [%- name FILTER html %]"></td> + </tr> + <tr> + <td valign="top">Component Description:</td> + <td><textarea rows="4" cols="64" wrap="virtual" + name="description">[% description FILTER html %]</textarea> + </td> + </tr> + <tr> + <td valign="top">Initial owner:</td> + <td><input size="64" maxlength="64" name="initialowner" value=" + [%- initialowner FILTER html %]"></td> + +[% IF Param('useqacontact') %] + </tr> + <tr> + <td valign="top">Initial QA contact:</td> + <td><input size="64" maxlength="64" name="initialqacontact" value=" + [%- initialqacontact FILTER html %]"></td> +[% END %] + + </tr> + <tr> + <td>[% terms.Bugs %]:</td> + <td> +[% IF bug_count > 0 %] + <a title="Bugs in component '[% name FILTER html %]'" + href="buglist.cgi?component= + [%- name FILTER url_quote %]&product= + [%- product FILTER url_quote %]">[% bug_count %]</a> +[% ELSE %] + None +[% END %] + </td> + </tr> + + </table> + + + <input type="hidden" name="componentold" value=" + [%- name FILTER html %]"> + <input type="hidden" name="descriptionold" value=" + [%- description FILTER html %]"> + <input type="hidden" name="initialownerold" value=" + [%- initialowner FILTER html %]"> + <input type="hidden" name="initialqacontactold" value=" + [%- initialqacontact FILTER html %]"> + <input type="hidden" name="action" value="update"> + <input type="hidden" name="product" value="[% product FILTER html %]"> + <input type="submit" value="Update"> + +</form> + +[% PROCESS admin/components/footer.html.tmpl + no_edit_component_link = 1 %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/edit.html.tmpl.orig b/template/en/default/admin/components/edit.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/edit.html.tmpl.orig diff --git a/template/en/default/admin/components/footer.html.tmpl b/template/en/default/admin/components/footer.html.tmpl new file mode 100644 index 000000000..1f58622ae --- /dev/null +++ b/template/en/default/admin/components/footer.html.tmpl @@ -0,0 +1,56 @@ +[%# 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: + # name: string; the name of the component + # + # product: string; the name of the product which the component + # belongs/belonged to + #%] + +<p> + +<hr> +Edit + +[% IF name && !no_edit_component_link %] + component <a + title="Edit Component '[% name FILTER html %]'" + href="editcomponents.cgi?action=edit&product= + [%- product FILTER url_quote %]&component=[% name FILTER url_quote %]"> + '[% name FILTER html %]'</a> + or edit +[% END %] + +[% IF !no_edit_other_components_link %] +other components of product <a + title="Choose a component from product '[% product FILTER html %]' to edit" + href="editcomponents.cgi?product= + [%- product FILTER url_quote %]">'[% product FILTER html %]'</a>, + or edit +[% END %] + +product <a + title="Edit Product '[% product FILTER html %]'" + href="editproducts.cgi?action=edit&product= + [%- product FILTER url_quote %]">'[% product FILTER html %]'</a>. + +</p> diff --git a/template/en/default/admin/components/footer.html.tmpl.orig b/template/en/default/admin/components/footer.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/footer.html.tmpl.orig diff --git a/template/en/default/admin/components/list.html.tmpl b/template/en/default/admin/components/list.html.tmpl new file mode 100644 index 000000000..027e1e028 --- /dev/null +++ b/template/en/default/admin/components/list.html.tmpl @@ -0,0 +1,119 @@ +[%# 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: + # components: array of hashes having the properties: + # - name: string; The name of the component. + # - description: string; The description of the component. + # - initialowner: string; The initial owner of the component. + # - initialqacontact: string; The qa_contact of the component. + # - bug_count: number; The number of bugs in the component + # (if showbugcounts defined). + # + # showbugcounts: if defined, then bug counts should be included in the table + # + # product: string; the name of the product we are editing components for + #%] + +[% USE Bugzilla %] +[% cgi = Bugzilla.cgi %] + +[% PROCESS global/variables.none.tmpl %] + +[% title = BLOCK %]Select component of product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +[% edit_contentlink = BLOCK %]editcomponents.cgi?action=edit&product= + [%- product FILTER url_quote %]&component=%%name%%[% END %] +[% delete_contentlink = BLOCK %]editcomponents.cgi?action=del&product= + [%- product FILTER url_quote %]&component=%%name%%[% END %] +[% bug_count_contentlink = BLOCK %]buglist.cgi?component=%%name%%&product= + [%- product FILTER url_quote %][% END %] + + +[% columns = [ + { + name => "name" + heading => "Edit component..." + contentlink => edit_contentlink + }, + { + name => "description" + heading => "Description" + allow_html_content => 1 + }, + { + name => "initialowner" + heading => "Initial owner" + }, + ] +%] + +[% IF Param('useqacontact') %] + + [% columns.push({ + name => 'initialqacontact' + heading => 'QA Contact' + }) %] + +[% END %] + +[% IF showbugcounts %] + + [% columns.push({ + name => 'bug_count' + heading => "$terms.Bugs" + align => "right" + contentlink => bug_count_contentlink + }) %] + +[% END %] + +[% columns.push({ + heading => "Action" + content => "Delete" + contentlink => delete_contentlink + }) %] + +[% PROCESS admin/table.html.tmpl + columns = columns + data = components + footer = footer_row +%] + +<p><a href="editcomponents.cgi?action=add&product=[% product FILTER url_quote %]">Add</a> + a new component to product '[% product FILTER html %]'</p> + +[% IF ! showbugcounts %] + +<p><a href="editcomponents.cgi?showbugcounts=1&[% cgi.query_string %]"> + Redisplay table with [% terms.bug %] counts (slower)</a></p> + +[% END %] + +[% PROCESS admin/components/footer.html.tmpl + no_edit_other_components_link = 1 + %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/list.html.tmpl.orig b/template/en/default/admin/components/list.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/list.html.tmpl.orig diff --git a/template/en/default/admin/components/select-product.html.tmpl b/template/en/default/admin/components/select-product.html.tmpl new file mode 100644 index 000000000..7e6cb8be5 --- /dev/null +++ b/template/en/default/admin/components/select-product.html.tmpl @@ -0,0 +1,85 @@ +[%# 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 properties: + # - name: string; The name of the product. + # - description: string; The description of the product. + # - bug_count: number; The number of bugs for the product (if + # showbugcounts defined). + # + # showbugcounts: if defined, then bug counts should be included in the table + #%] + +[% USE Bugzilla %] +[% cgi = Bugzilla.cgi %] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS global/header.html.tmpl + title = "Edit components for which product?" +%] + +[% bug_count_contentlink = BLOCK %]buglist.cgi?component=%%name%%&product= + [%- product FILTER url_quote %][% END %] + +[% columns = [ + { + name => "name" + heading => "Edit components of..." + contentlink => "editcomponents.cgi?product=%%name%%" + }, + { + name => "description" + heading => "Description" + allow_html_content => 1 + } + ] +%] + +[% IF showbugcounts %] + +[% columns.push({ + name => 'bug_count' + heading => "$terms.Bugs" + align => "right" + contentlink => bug_count_contentlink + }) %] + +[% END %] + +[% PROCESS admin/table.html.tmpl + columns = columns + data = products + footer = footer_row +%] + +[% IF ! showbugcounts %] + +<p><a href="editcomponents.cgi?showbugcounts=1&[% cgi.query_string %]"> + Redisplay table with [% terms.bug %] counts (slower)</a></p> + +[% END %] + +<p> + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/select-product.html.tmpl.orig b/template/en/default/admin/components/select-product.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/select-product.html.tmpl.orig diff --git a/template/en/default/admin/components/updated.html.tmpl b/template/en/default/admin/components/updated.html.tmpl new file mode 100644 index 000000000..2382814df --- /dev/null +++ b/template/en/default/admin/components/updated.html.tmpl @@ -0,0 +1,82 @@ +[%# 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: + # + # '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 component + # + # description & updated_description: the component description + # + # initialowner & updated_initialowner: the initial owner + # + # initialqacontact & updated_initialqacontact: the initial qa contact + # + # product: string; the name of the product the component belongs to + #%] + +[% title = BLOCK %]Updating Component '[% name FILTER html %]' of Product + '[% product FILTER html %]'[% END %] +[% PROCESS global/header.html.tmpl + title = title +%] + +[% IF updated_description %] + <p> + <table> + <tr> + <td>Updated description to:</td> + <td>'[% description FILTER html %]'</td> + </tr> + </table> +[% END %] + +[% IF updated_initialowner %] + <p>Updated Initial Owner to: '[% initialowner FILTER html %]'.</p> +[% END %] + +[% IF updated_initialqacontact %] + <p> + [% IF initialqacontact %] + Updated Initial QA Contact to '[% initialqacontact FILTER html %]'. + [% ELSE %] + Removed initial QA Contact. + [% END %] + </p> +[% END %] + +[% IF updated_name %] + <p>Updated Component name to: '[% name FILTER html %]'.</p> +[% END %] + +[% UNLESS updated_description || updated_initialowner || + updated_initialqacontact || updated_name %] + <p>Nothing changed for component '[% name FILTER html %]'. +[% END %] + + +[% PROCESS admin/components/footer.html.tmpl %] + +[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/components/updated.html.tmpl.orig b/template/en/default/admin/components/updated.html.tmpl.orig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/template/en/default/admin/components/updated.html.tmpl.orig diff --git a/template/en/default/admin/keywords/list.html.tmpl b/template/en/default/admin/keywords/list.html.tmpl index fbfc92142..113b90433 100755 --- a/template/en/default/admin/keywords/list.html.tmpl +++ b/template/en/default/admin/keywords/list.html.tmpl @@ -22,7 +22,7 @@ #%] [%# INTERFACE: - # keywords: array with keyword objects having the properties: + # keywords: array of hashes having the properties: # - id: number. The ID of the keyword. # - name: string. The name of the keyword. # - description: string. The description of the keyword. @@ -39,7 +39,7 @@ { name => "name" heading => "Edit keyword..." - contentlink => "editkeywords.cgi?action=edit&id=%id%" + contentlink => "editkeywords.cgi?action=edit&id=%%id%%" }, { name => "description" @@ -53,7 +53,7 @@ { heading => "Action" content => "Delete" - contentlink => "editkeywords.cgi?action=delete&id=%id%" + contentlink => "editkeywords.cgi?action=delete&id=%%id%%" } ] %] diff --git a/template/en/default/admin/table.html.tmpl b/template/en/default/admin/table.html.tmpl index 8647aea76..ac4e5a666 100644 --- a/template/en/default/admin/table.html.tmpl +++ b/template/en/default/admin/table.html.tmpl @@ -28,13 +28,15 @@ # name: Name of the field in the data param # heading: The text to print at the header cell # contentlink: URI to which the content of a data cell shall be linked to. - # Expressions of format %xxx% are replaced with value + # Expressions of format %%xxx%% are replaced with value # with the key xxx in data hash of the current row. # content: If specified, the content of this variable is used # instead of the data pulled from the current row. # NOTE: This value is not HTML filtered at output! # align: left/center/right. Controls the horizontal alignment of the # text in the column. + # allow_html_content: if defined, then this column allows html content + # so it will not be filtered # # data: # array of hashes representing the data for the table. @@ -65,9 +67,11 @@ [% IF c.contentlink %] [% link_uri = c.contentlink %] - [% FOREACH m = link_uri.match('%(.+?)%'); %] - [% replacement_value = FILTER url_quote; row.$m; END %] - [% link_uri = link_uri.replace("%$m%", replacement_value) %] + [% FOREACH m = link_uri.match('%%(.+?)%%'); %] + [% IF row.$m %] + [% replacement_value = FILTER url_quote; row.$m; END %] + [% link_uri = link_uri.replace("%%$m%%", replacement_value) %] + [% END %] [% END %] <a href="[% link_uri %]"> [% END %] @@ -75,7 +79,11 @@ [% IF c.content %] [% c.content %] [% ELSE %] - [% row.${c.name} FILTER html %] + [% IF c.allow_html_content %] + [% row.${c.name} FILTER none %] + [% ELSE %] + [% row.${c.name} FILTER html %] + [% END %] [% END %] [% IF c.contentlink %] @@ -87,6 +95,11 @@ </tr> [% END %] +[% IF data.size == 0 %] + <tr><td colspan="[% columns.size %]" align="center"><i><none></i></td></tr> +[% END %] + + [%################### TABLE FOOTER ######################%] </table> diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl index e90037f87..f183461ce 100644 --- a/template/en/default/filterexceptions.pl +++ b/template/en/default/filterexceptions.pl @@ -101,7 +101,6 @@ IF sortvisible', 'column.name', 'column.description', - 'vis_bug_ids.push(bug.id)', 'bug.id', 'bug.count', 'bug.delta', @@ -526,6 +525,27 @@ 'type.flag_count', ], + +'admin/components/confirm-delete.html.tmpl' => [ + 'bug_count' +], + +'admin/components/deleted.html.tmpl' => [ + 'deleted_bug_count' +], + +'admin/components/edit.html.tmpl' => [ + 'bug_count' +], + +'admin/components/list.html.tmpl' => [ + 'cgi.query_string' +], + +'admin/components/select-product.html.tmpl' => [ + 'cgi.query_string' +], + '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 fcd3ca4fd..28002581a 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -20,7 +20,7 @@ #%] [%# INTERFACE: - # header_done: boolean. True if the header has already been printed. + # header_done: boolean. True if the Bugzilla header has already been printed. # error: string. The tag of the error, or the error message to be displayed # (deprecated). May contain HTML if it's an error message. #%] @@ -142,6 +142,72 @@ [% title = "Comment Too Long" %] Comments cannot be longer than 65,535 characters. + [% ELSIF error == "auth_cant_edit_components" %] + [% title = "Access Denied" %] + Sorry, you aren't a member of the 'editcomponents' group, and so + you aren't allowed to add, modify or delete components. + + [% ELSIF error == "component_already_exists" %] + [% title = "Component Already Exists" %] + A component with the name '[% name FILTER html %]' already exists. + + [% ELSIF error == "component_blank_description" %] + [% title = "Blank Component Description Not Allowed" %] + You must enter a non-blank description for component '[% name FILTER html %]'. + + [% ELSIF error == "component_blank_name" %] + [% title = "Blank Component Name Not Allowed" %] + You must enter a name for this new component. + + [% ELSIF error == "component_must_have_a_name" %] + [% title = "Blank Component Name Not Allowed" %] + You cannot delete the component name for component '[% name FILTER html %]'. + + [% ELSIF error == "component_cant_del_description" %] + [% title = "Blank Component Description Not Allowed" %] + You cannot delete the component description for + component '[% name FILTER html %]'. + + [% ELSIF error == "component_name_too_long" %] + [% title = "Component Name Is Too Long" %] + The name of a component is limited to 64 characters. + '[% name FILTER html %]' is too long ([% name.size %] characters). + + [% ELSIF error == "component_need_initialowner" %] + [% title = "Component Requires Initial Owner" %] + You must enter an initial owner for component '[% name FILTER html %]'. + + [% ELSIF error == "component_need_valid_initialowner" %] + [% title = "Component Requires A Valid Initial Owner" %] + You must use an existing [% terms.Bugzilla %] account as initial owner for + component '[% name FILTER html %]'. + + [% ELSIF error == "component_need_valid_initialqacontact" %] + [% title = "Component Requires A Valid Initial QA Contact" %] + You must use an existing [% terms.Bugzilla %] account as initial QA contact for + component '[% name FILTER html %]'. + + [% ELSIF error == "component_no_action" %] + [% title = "No valid action specified" %] + No valid action was specified when trying to edit components. + + [% ELSIF error == "product_not_specified" %] + [% title = "No Product Specified" %] + No product specified when trying to edit components. + + [% ELSIF error == "component_not_specified" %] + [% title = "No Component Specified" %] + No component specified when trying to edit components. + + [% ELSIF error == "component_not_valid" %] + [% title = "Specified Component Does Not Exist" %] + The component '[% name FILTER html %]' for product + '[% product FILTER html %]' does not exist. + + [% ELSIF error == "product_doesnt_exist" %] + [% title = "Specified Product Does Not Exist" %] + The product '[% product FILTER html %]' does not exist. + [% ELSIF error == "dependency_loop_multi" %] [% title = "Dependency Loop Detected" %] The following [% terms.bug %](s) would appear on both the "depends on" |