diff options
-rw-r--r-- | Bugzilla/Product.pm | 23 | ||||
-rwxr-xr-x | editproducts.cgi | 628 | ||||
-rw-r--r-- | template/en/default/admin/products/confirm-delete.html.tmpl | 131 | ||||
-rw-r--r-- | template/en/default/admin/products/create.html.tmpl | 11 | ||||
-rw-r--r-- | template/en/default/admin/products/created.html.tmpl | 9 | ||||
-rw-r--r-- | template/en/default/admin/products/deleted.html.tmpl | 9 | ||||
-rw-r--r-- | template/en/default/admin/products/edit-common.html.tmpl | 7 | ||||
-rw-r--r-- | template/en/default/admin/products/edit.html.tmpl | 66 | ||||
-rw-r--r-- | template/en/default/admin/products/footer.html.tmpl | 31 | ||||
-rw-r--r-- | template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl | 6 | ||||
-rw-r--r-- | template/en/default/admin/products/groupcontrol/edit.html.tmpl | 14 | ||||
-rw-r--r-- | template/en/default/admin/products/groupcontrol/updated.html.tmpl | 8 | ||||
-rw-r--r-- | template/en/default/admin/products/list.html.tmpl | 48 | ||||
-rw-r--r-- | template/en/default/admin/products/updated.html.tmpl | 112 | ||||
-rw-r--r-- | template/en/default/filterexceptions.pl | 3 |
15 files changed, 441 insertions, 665 deletions
diff --git a/Bugzilla/Product.pm b/Bugzilla/Product.pm index 1bf1d4e56..f55b5dd67 100644 --- a/Bugzilla/Product.pm +++ b/Bugzilla/Product.pm @@ -187,6 +187,20 @@ sub bug_count { return $self->{'bug_count'}; } +sub bug_ids { + my $self = shift; + my $dbh = Bugzilla->dbh; + + if (!defined $self->{'bug_ids'}) { + $self->{'bug_ids'} = + $dbh->selectcol_arrayref(q{SELECT bug_id FROM bugs + WHERE product_id = ?}, + undef, $self->id); + } + return $self->{'bug_ids'}; +} + + ############################### #### Accessors ###### ############################### @@ -253,6 +267,7 @@ Bugzilla::Product - Bugzilla product class. my @milestones = $product->milestones(); my @versions = $product->versions(); my $bugcount = $product->bug_count(); + my $bug_ids = $product->bug_ids(); my $id = $product->id; my $name = $product->name; @@ -330,6 +345,14 @@ Product.pm represents a product object. Returns: Integer with the number of bugs. +=item C<bug_ids()> + + Description: Returns the IDs of bugs that belong to the product. + + Params: none. + + Returns: An array of integer. + =back =head1 SUBROUTINES diff --git a/editproducts.cgi b/editproducts.cgi index 82ce7433d..9b188f231 100755 --- a/editproducts.cgi +++ b/editproducts.cgi @@ -38,94 +38,14 @@ require "globals.pl"; use Bugzilla::Bug; use Bugzilla::Series; use Bugzilla::Config qw(:DEFAULT $datadir); +use Bugzilla::Product; +use Bugzilla::Classification; +use Bugzilla::Milestone; # Shut up misguided -w warnings about "used only once". "use vars" just # doesn't work for me. use vars qw(@legal_bug_status @legal_resolution); -# TestProduct: just returns if the specified product does exists -# CheckProduct: same check, optionally emit an error text - -sub TestProduct -{ - my $prod = shift; - - # does the product exist? - SendSQL("SELECT name - FROM products - WHERE name=" . SqlQuote($prod)); - return FetchOneColumn(); -} - -sub CheckProduct -{ - my $prod = shift; - - # do we have a product? - unless ($prod) { - ThrowUserError('product_not_specified'); - } - - unless (TestProduct($prod)) { - ThrowUserError('product_doesnt_exist', - {'product' => $prod}); - } -} - - -# TestClassification: just returns if the specified classification does exists -# CheckClassification: same check, optionally emit an error text - -sub TestClassification -{ - my $cl = shift; - - # does the classification exist? - SendSQL("SELECT name - FROM classifications - WHERE name=" . SqlQuote($cl)); - return FetchOneColumn(); -} - -sub CheckClassification -{ - my $cl = shift; - - # do we have a classification? - unless ($cl) { - ThrowUserError('classification_not_specified'); - } - - unless (TestClassification($cl)) { - ThrowUserError('classification_doesnt_exist', - {'name' => $cl}); - } -} - -sub CheckClassificationProduct -{ - my ($cl, $prod) = @_; - my $dbh = Bugzilla->dbh; - - CheckClassification($cl); - - trick_taint($prod); - trick_taint($cl); - - my ($res) = $dbh->selectrow_array(q{ - SELECT products.name - FROM products - INNER JOIN classifications - ON products.classification_id = classifications.id - WHERE products.name = ? AND classifications.name = ?}, - undef, ($prod, $cl)); - - unless ($res) { - ThrowUserError('classification_doesnt_exist_for_product', - { product => $prod, classification => $cl }); - } -} - # # Preliminary checks: # @@ -144,8 +64,8 @@ $user->in_group('editcomponents') # # often used variables # -my $classification = trim($cgi->param('classification') || ''); -my $product = trim($cgi->param('product') || ''); +my $classification_name = trim($cgi->param('classification') || ''); +my $product_name = trim($cgi->param('product') || ''); my $action = trim($cgi->param('action') || ''); my $dbh = Bugzilla->dbh; @@ -155,23 +75,14 @@ my $dbh = Bugzilla->dbh; # if (Param('useclassification') - && !$classification - && !$product) + && !$classification_name + && !$product_name) { - my $query = - "SELECT classifications.name, classifications.description, - COUNT(classification_id) AS product_count - FROM classifications - LEFT JOIN products - ON classifications.id = products.classification_id " . - $dbh->sql_group_by('classifications.id', - 'classifications.name, - classifications.description') . " - ORDER BY name"; - - $vars->{'classifications'} = $dbh->selectall_arrayref($query, - {'Slice' => {}}); - + my @classifications = + Bugzilla::Classification::get_all_classifications(); + + $vars->{'classifications'} = \@classifications; + $template->process("admin/products/list-classifications.html.tmpl", $vars) || ThrowTemplateError($template->error()); @@ -185,50 +96,21 @@ if (Param('useclassification') # is already specified (then edit it) # -if (!$action && !$product) { - - if (Param('useclassification')) { - CheckClassification($classification); - } - - my @execute_params = (); - my @products = (); - - my $query = "SELECT products.name, - COALESCE(products.description,'') AS description, - disallownew = 0 AS status, - votesperuser, maxvotesperbug, votestoconfirm, - COUNT(bug_id) AS bug_count - FROM products"; +if (!$action && !$product_name) { + my @products; if (Param('useclassification')) { - $query .= " INNER JOIN classifications " . - "ON classifications.id = products.classification_id"; - } - - $query .= " LEFT JOIN bugs ON products.id = bugs.product_id"; - - if (Param('useclassification')) { - $query .= " WHERE classifications.name = ? "; - - # trick_taint is OK because we use this in a placeholder in a SELECT - trick_taint($classification); + my $classification = + Bugzilla::Classification::check_classification($classification_name); - push(@execute_params, - $classification); + @products = @{$classification->products}; + $vars->{'classification'} = $classification; + } else { + @products = Bugzilla::Product::get_all_products; } - $query .= " " . $dbh->sql_group_by('products.name', - 'products.description, disallownew, - votesperuser, maxvotesperbug, - votestoconfirm'); - $query .= " ORDER BY products.name"; - - $vars->{'products'} = $dbh->selectall_arrayref($query, - {'Slice' => {}}, - @execute_params); + $vars->{'products'} = \@products; - $vars->{'classification'} = $classification; $template->process("admin/products/list.html.tmpl", $vars) || ThrowTemplateError($template->error()); @@ -248,9 +130,10 @@ if (!$action && !$product) { if ($action eq 'add') { if (Param('useclassification')) { - CheckClassification($classification); + my $classification = + Bugzilla::Classification::check_classification($classification_name); + $vars->{'classification'} = $classification; } - $vars->{'classification'} = $classification; $template->process("admin/products/create.html.tmpl", $vars) || ThrowTemplateError($template->error()); @@ -268,30 +151,31 @@ if ($action eq 'new') { my $classification_id = 1; if (Param('useclassification')) { - CheckClassification($classification); - $classification_id = get_classification_id($classification); + my $classification = + Bugzilla::Classification::check_classification($classification_name); + $classification_id = $classification->id; $vars->{'classification'} = $classification; } - unless ($product) { + unless ($product_name) { ThrowUserError("product_blank_name"); } - my $existing_product = TestProduct($product); + my $product = new Bugzilla::Product({name => $product_name}); - if ($existing_product) { + if ($product) { # Check for exact case sensitive match: - if ($existing_product eq $product) { + if ($product->name eq $product_name) { ThrowUserError("prod_name_already_in_use", - {'product' => $product}); + {'product' => $product->name}); } # Next check for a case-insensitive match: - if (lc($existing_product) eq lc($product)) { + if (lc($product->name) eq lc($product_name)) { ThrowUserError("prod_name_diff_in_case", - {'product' => $product, - 'existing_product' => $existing_product}); + {'product' => $product_name, + 'existing_product' => $product->name}); } } @@ -299,14 +183,14 @@ if ($action eq 'new') { if ($version eq '') { ThrowUserError("product_must_have_version", - {'product' => $product}); + {'product' => $product_name}); } my $description = trim($cgi->param('description') || ''); if ($description eq '') { ThrowUserError('product_must_have_description', - {'product' => $product}); + {'product' => $product_name}); } my $milestoneurl = trim($cgi->param('milestoneurl') || ''); @@ -325,7 +209,7 @@ if ($action eq 'new') { "name, description, milestoneurl, disallownew, votesperuser, " . "maxvotesperbug, votestoconfirm, defaultmilestone, classification_id" . " ) VALUES ( " . - SqlQuote($product) . "," . + SqlQuote($product_name) . "," . SqlQuote($description) . "," . SqlQuote($milestoneurl) . "," . # had tainting issues under cygwin, IIS 5.0, perl -T %s %s @@ -339,22 +223,23 @@ if ($action eq 'new') { SqlQuote($votestoconfirm) . "," . SqlQuote($defaultmilestone) . "," . SqlQuote($classification_id) . ")"); - my $product_id = $dbh->bz_last_key('products', 'id'); + $product = new Bugzilla::Product({name => $product_name}); + SendSQL("INSERT INTO versions ( " . "value, product_id" . " ) VALUES ( " . SqlQuote($version) . "," . - $product_id . ")" ); + $product->id . ")" ); SendSQL("INSERT INTO milestones (product_id, value) VALUES (" . - $product_id . ", " . SqlQuote($defaultmilestone) . ")"); + $product->id . ", " . SqlQuote($defaultmilestone) . ")"); # If we're using bug groups, then we need to create a group for this # product as well. -JMR, 2/16/00 if (Param("makeproductgroups")) { # Next we insert into the groups table - my $productgroup = $product; + my $productgroup = $product->name; while (GroupExists($productgroup)) { $productgroup .= '_'; } @@ -362,7 +247,8 @@ if ($action eq 'new') { "(name, description, isbuggroup, last_changed) " . "VALUES (" . SqlQuote($productgroup) . ", " . - SqlQuote("Access to bugs in the $product product") . ", 1, NOW())"); + SqlQuote("Access to bugs in the " . $product->name . + " product") . ", 1, NOW())"); my $gid = $dbh->bz_last_key('groups', 'id'); my $admin = GroupNameToId('admin'); # If we created a new group, give the "admin" group priviledges @@ -378,7 +264,8 @@ if ($action eq 'new') { SendSQL("INSERT INTO group_control_map " . "(group_id, product_id, entry, " . "membercontrol, othercontrol, canedit) VALUES " . - "($gid, $product_id, " . Param("useentrygroupdefault") . + "($gid, " . $product->id . ", " . + Param("useentrygroupdefault") . ", " . CONTROLMAPDEFAULT . ", " . CONTROLMAPNA . ", 0)"); } @@ -392,7 +279,6 @@ if ($action eq 'new') { # and never used again here, so we can trick_taint them. my $open_name = $cgi->param('open_name'); trick_taint($open_name); - trick_taint($product); my @series; @@ -415,10 +301,11 @@ if ($action eq 'new') { push(@series, [$open_name, $query]); foreach my $sdata (@series) { - my $series = new Bugzilla::Series(undef, $product, + my $series = new Bugzilla::Series(undef, $product->name, scalar $cgi->param('subcategory'), $sdata->[0], $::userid, 1, - $sdata->[1] . "&product=" . url_quote($product), 1); + $sdata->[1] . "&product=" . + url_quote($product->name), 1); $series->writeToDatabase(); } } @@ -426,6 +313,7 @@ if ($action eq 'new') { unlink "$datadir/versioncache"; $vars->{'product'} = $product; + $template->process("admin/products/created.html.tmpl", $vars) || ThrowTemplateError($template->error()); exit; @@ -439,68 +327,21 @@ if ($action eq 'new') { if ($action eq 'del') { - if (!$product) { - ThrowUserError('product_not_specified'); - } - - my $product_id = get_product_id($product); - $product_id || ThrowUserError('product_doesnt_exist', - {product => $product}); - - my $classification_id = 1; + my $product = Bugzilla::Product::check_product($product_name); if (Param('useclassification')) { - CheckClassificationProduct($classification, $product); - $classification_id = get_classification_id($classification); + my $classification = + Bugzilla::Classification::check_classification($classification_name); + if ($classification->id != $product->classification_id) { + ThrowUserError('classification_doesnt_exist_for_product', + { product => $product->name, + classification => $classification->name }); + } $vars->{'classification'} = $classification; } - # Extract some data about the product - my $query = q{SELECT classifications.description, - products.description, - products.milestoneurl, - products.disallownew - FROM products - INNER JOIN classifications - ON products.classification_id = classifications.id - WHERE products.id = ?}; - - my ($class_description, - $prod_description, - $milestoneurl, - $disallownew) = $dbh->selectrow_array($query, undef, - $product_id); - - $vars->{'class_description'} = $class_description; - $vars->{'product_id'} = $product_id; - $vars->{'prod_description'} = $prod_description; - $vars->{'milestoneurl'} = $milestoneurl; - $vars->{'disallownew'} = $disallownew; - $vars->{'product_name'} = $product; - - $vars->{'components'} = $dbh->selectall_arrayref(q{ - SELECT name, description FROM components - WHERE product_id = ? ORDER BY name}, {'Slice' => {}}, - $product_id); - - $vars->{'versions'} = $dbh->selectcol_arrayref(q{ - SELECT value FROM versions - WHERE product_id = ? ORDER BY value}, undef, - $product_id); - - # Adding listing for associated target milestones - - # matthew@zeroknowledge.com - if (Param('usetargetmilestone')) { - $vars->{'milestones'} = $dbh->selectcol_arrayref(q{ - SELECT value FROM milestones - WHERE product_id = ? - ORDER BY sortkey, value}, undef, $product_id); - } + $vars->{'product'} = $product; - ($vars->{'bug_count'}) = $dbh->selectrow_array(q{ - SELECT COUNT(*) FROM bugs WHERE product_id = ?}, - undef, $product_id) || 0; - $template->process("admin/products/confirm-delete.html.tmpl", $vars) || ThrowTemplateError($template->error()); exit; @@ -512,33 +353,32 @@ if ($action eq 'del') { if ($action eq 'delete') { - if (!$product) { - ThrowUserError('product_not_specified'); - } - - my $product_id = get_product_id($product); - $product_id || ThrowUserError('product_doesnt_exist', - {product => $product}); - + my $product = Bugzilla::Product::check_product($product_name); + $vars->{'product'} = $product; - $vars->{'classification'} = $classification; - my $bug_ids = $dbh->selectcol_arrayref(q{ - SELECT bug_id FROM bugs - WHERE product_id = ?}, undef, $product_id); + if (Param('useclassification')) { + my $classification = + Bugzilla::Classification::check_classification($classification_name); + if ($classification->id != $product->classification_id) { + ThrowUserError('classification_doesnt_exist_for_product', + { product => $product->name, + classification => $classification->name }); + } + $vars->{'classification'} = $classification; + } - my $nb_bugs = scalar(@$bug_ids); - if ($nb_bugs) { + if ($product->bug_count) { if (Param("allowbugdeletion")) { - foreach my $bug_id (@$bug_ids) { + foreach my $bug_id (@{$product->bug_ids}) { my $bug = new Bugzilla::Bug($bug_id, $whoid); $bug->remove_from_db(); } } else { - ThrowUserError("product_has_bugs", { nb => $nb_bugs }); + ThrowUserError("product_has_bugs", + { nb => $product->bug_count }); } - $vars->{'nb_bugs'} = $nb_bugs; } $dbh->bz_lock_tables('products WRITE', 'components WRITE', @@ -547,25 +387,25 @@ if ($action eq 'delete') { 'flaginclusions WRITE', 'flagexclusions WRITE'); $dbh->do("DELETE FROM components WHERE product_id = ?", - undef, $product_id); + undef, $product->id); $dbh->do("DELETE FROM versions WHERE product_id = ?", - undef, $product_id); + undef, $product->id); $dbh->do("DELETE FROM milestones WHERE product_id = ?", - undef, $product_id); + undef, $product->id); $dbh->do("DELETE FROM group_control_map WHERE product_id = ?", - undef, $product_id); + undef, $product->id); $dbh->do("DELETE FROM flaginclusions WHERE product_id = ?", - undef, $product_id); + undef, $product->id); $dbh->do("DELETE FROM flagexclusions WHERE product_id = ?", - undef, $product_id); + undef, $product->id); $dbh->do("DELETE FROM products WHERE id = ?", - undef, $product_id); + undef, $product->id); $dbh->bz_unlock_tables(); @@ -583,74 +423,28 @@ if ($action eq 'delete') { # (next action would be 'update') # -if ($action eq 'edit' || (!$action && $product)) { - CheckProduct($product); - trick_taint($product); - my $product_id = get_product_id($product); - my $classification_id=1; +if ($action eq 'edit' || (!$action && $product_name)) { + + my $product = Bugzilla::Product::check_product($product_name); + if (Param('useclassification')) { - # If a product has been given with no classification associated - # with it, take this information from the DB - if ($classification) { - CheckClassificationProduct($classification, $product); + my $classification; + if (!$classification_name) { + $classification = + new Bugzilla::Classification($product->classification_id); } else { - $classification = - $dbh->selectrow_array("SELECT classifications.name - FROM products, classifications - WHERE products.name = ? - AND classifications.id = products.classification_id", - undef, $product); + $classification = + Bugzilla::Classification::check_classification($classification_name); + if ($classification->id != $product->classification_id) { + ThrowUserError('classification_doesnt_exist_for_product', + { product => $product->name, + classification => $classification->name }); + } } - $classification_id = get_classification_id($classification); - } - - $vars->{'classification'} = $classification; - - # get data of product - $vars->{'product'} = $dbh->selectrow_hashref(qq{ - SELECT id, name, classification_id, description, - milestoneurl, disallownew, votesperuser, - maxvotesperbug, votestoconfirm, defaultmilestone - FROM products - WHERE id = ?}, undef, $product_id); - - - $vars->{'components'} = $dbh->selectall_arrayref(qq{ - SELECT name, description - FROM components - WHERE product_id = ? - ORDER BY name}, {'Slice' => {}},$product_id); - - - $vars->{'versions'} = $dbh->selectcol_arrayref(q{ - SELECT value FROM versions - WHERE product_id = ? - ORDER BY value}, undef, $product_id); - - if (Param('usetargetmilestone')) { - $vars->{'milestones'} = $dbh->selectcol_arrayref(q{ - SELECT value - FROM milestones - WHERE product_id = ? - ORDER BY sortkey, value}, - undef, $product_id); + $vars->{'classification'} = $classification; } + my $group_controls = $product->group_controls; - my $query = qq{SELECT - groups.id, groups.name, groups.isactive, - group_control_map.entry, - group_control_map.membercontrol, - group_control_map.othercontrol, - group_control_map.canedit - FROM groups - INNER JOIN group_control_map - ON groups.id = group_control_map.group_id - WHERE group_control_map.product_id = ? - AND groups.isbuggroup != 0 - ORDER BY groups.name}; - my $groups = $dbh->selectall_arrayref($query, {'Slice' => {}}, - $product_id); - # Convert Group Controls(membercontrol and othercontrol) from # integer to string to display Membercontrol/Othercontrol names # at the template. <gabriel@async.com.br> @@ -660,19 +454,16 @@ if ($action eq 'edit' || (!$action && $product)) { (CONTROLMAPDEFAULT) => 'Default', (CONTROLMAPMANDATORY) => 'Mandatory'}; - foreach my $group (@$groups) { - $group->{'membercontrol'} = - $constants->{$group->{'membercontrol'}}; - $group->{'othercontrol'} = - $constants->{$group->{'othercontrol'}}; + foreach my $group (keys(%$group_controls)) { + foreach my $control ('membercontrol', 'othercontrol') { + $group_controls->{$group}->{$control} = + $constants->{$group_controls->{$group}->{$control}}; + } } - - $vars->{'groups'} = $groups; - - $vars->{'bug_count'} = $dbh->selectrow_array(qq{ - SELECT COUNT(*) FROM bugs - WHERE product_id = ?}, undef, $product_id); - + $vars->{'group_controls'} = $group_controls; + + $vars->{'product'} = $product; + $template->process("admin/products/edit.html.tmpl", $vars) || ThrowTemplateError($template->error()); @@ -684,7 +475,8 @@ if ($action eq 'edit' || (!$action && $product)) { # if ($action eq 'updategroupcontrols') { - my $product_id = get_product_id($product); + + my $product = Bugzilla::Product::check_product($product_name); my @now_na = (); my @now_mandatory = (); foreach my $f ($cgi->param()) { @@ -705,7 +497,7 @@ if ($action eq 'updategroupcontrols') { WHERE groups.id IN(" . join(', ', @now_na) . ") AND bug_group_map.group_id = groups.id AND bug_group_map.bug_id = bugs.bug_id - AND bugs.product_id = $product_id " . + AND bugs.product_id = " . $product->id . " " . $dbh->sql_group_by('groups.name')); while (MoreSQLData()) { my ($groupname, $bugcount) = FetchSQLData(); @@ -725,7 +517,7 @@ if ($action eq 'updategroupcontrols') { INNER JOIN groups ON bug_group_map.group_id = groups.id WHERE groups.id IN(" . join(', ', @now_mandatory) . ") - AND bugs.product_id = $product_id + AND bugs.product_id = " . $product->id . " AND bug_group_map.bug_id IS NULL " . $dbh->sql_group_by('groups.name')); while (MoreSQLData()) { @@ -775,8 +567,8 @@ if ($action eq 'updategroupcontrols') { SendSQL("SELECT id, name, entry, membercontrol, othercontrol, canedit " . "FROM groups " . "LEFT JOIN group_control_map " . - "ON group_control_map.group_id = id AND product_id = $product_id " . - "WHERE isbuggroup != 0 AND isactive != 0"); + "ON group_control_map.group_id = id AND product_id = " . + $product->id . " WHERE isbuggroup != 0 AND isactive != 0"); while (MoreSQLData()) { my ($groupid, $groupname, $entry, $membercontrol, $othercontrol, $canedit) = FetchSQLData(); @@ -800,7 +592,7 @@ if ($action eq 'updategroupcontrols') { "(group_id, product_id, entry, " . "membercontrol, othercontrol, canedit) " . "VALUES " . - "($groupid, $product_id, $newentry, " . + "($groupid, " . $product->id . ", $newentry, " . "$newmembercontrol, $newothercontrol, $newcanedit)"); PopGlobalSQLState(); } elsif (($newentry != $entry) @@ -814,7 +606,7 @@ if ($action eq 'updategroupcontrols') { "othercontrol = $newothercontrol, " . "canedit = $newcanedit " . "WHERE group_id = $groupid " . - "AND product_id = $product_id"); + "AND product_id = " . $product->id); PopGlobalSQLState(); } @@ -823,7 +615,7 @@ if ($action eq 'updategroupcontrols') { PushGlobalSQLState(); SendSQL("DELETE FROM group_control_map " . "WHERE group_id = $groupid " . - "AND product_id = $product_id"); + "AND product_id = " . $product->id); PopGlobalSQLState(); } } @@ -836,7 +628,7 @@ if ($action eq 'updategroupcontrols') { FROM bugs, bug_group_map WHERE group_id = $groupid AND bug_group_map.bug_id = bugs.bug_id - AND bugs.product_id = $product_id + AND bugs.product_id = " . $product->id . " ORDER BY bugs.bug_id"); while (MoreSQLData()) { my ($bugid, $mailiscurrent) = FetchSQLData(); @@ -871,7 +663,7 @@ if ($action eq 'updategroupcontrols') { LEFT JOIN bug_group_map ON bug_group_map.bug_id = bugs.bug_id AND group_id = $groupid - WHERE bugs.product_id = $product_id + WHERE bugs.product_id = " . $product->id . " AND bug_group_map.bug_id IS NULL ORDER BY bugs.bug_id"); while (MoreSQLData()) { @@ -903,8 +695,6 @@ if ($action eq 'updategroupcontrols') { $vars->{'added_mandatory'} = \@added_mandatory; - $vars->{'classification'} = $classification; - $vars->{'product'} = $product; $template->process("admin/products/groupcontrol/updated.html.tmpl", $vars) @@ -917,28 +707,45 @@ if ($action eq 'updategroupcontrols') { # if ($action eq 'update') { - $vars->{'classification'} = $classification; - - my $productold = trim($cgi->param('productold') || ''); + my $product_old_name = trim($cgi->param('product_old_name') || ''); my $description = trim($cgi->param('description') || ''); - my $descriptionold = trim($cgi->param('descriptionold') || ''); my $disallownew = trim($cgi->param('disallownew') || ''); - my $disallownewold = trim($cgi->param('disallownewold') || ''); my $milestoneurl = trim($cgi->param('milestoneurl') || ''); - my $milestoneurlold = trim($cgi->param('milestoneurlold') || ''); my $votesperuser = trim($cgi->param('votesperuser') || 0); - my $votesperuserold = trim($cgi->param('votesperuserold') || 0); my $maxvotesperbug = trim($cgi->param('maxvotesperbug') || 0); - my $maxvotesperbugold = trim($cgi->param('maxvotesperbugold') || 0); my $votestoconfirm = trim($cgi->param('votestoconfirm') || 0); - my $votestoconfirmold = trim($cgi->param('votestoconfirmold') || 0); my $defaultmilestone = trim($cgi->param('defaultmilestone') || '---'); - my $defaultmilestoneold = trim($cgi->param('defaultmilestoneold') || '---'); my $checkvotes = 0; - CheckProduct($productold); - my $product_id = get_product_id($productold); + my $product_old = Bugzilla::Product::check_product($product_old_name); + + if (Param('useclassification')) { + my $classification; + if (!$classification_name) { + $classification = + new Bugzilla::Classification($product_old->classification_id); + } else { + $classification = + Bugzilla::Classification::check_classification($classification_name); + if ($classification->id != $product_old->classification_id) { + ThrowUserError('classification_doesnt_exist_for_product', + { product => $product_old->name, + classification => $classification->name }); + } + } + $vars->{'classification'} = $classification; + } + + unless ($product_name) { + ThrowUserError('prod_cant_delete_name', + {product => $product_old->name}); + } + + unless ($description) { + ThrowUserError('prod_cant_delete_description', + {product => $product_old->name}); + } my $stored_maxvotesperbug = $maxvotesperbug; if (!detaint_natural($maxvotesperbug)) { @@ -958,9 +765,6 @@ if ($action eq 'update') { {votestoconfirm => $stored_votestoconfirm}); } - # Note that we got the $product_id using $productold above so it will - # remain static even after we rename the product in the database. - $dbh->bz_lock_tables('products WRITE', 'versions READ', 'groups WRITE', @@ -968,120 +772,87 @@ if ($action eq 'update') { 'profiles WRITE', 'milestones READ'); - if ($disallownew ne $disallownewold) { - $disallownew = $disallownew ? 1 : 0; + my $testproduct = + new Bugzilla::Product({name => $product_name}); + if (lc($product_name) ne lc($product_old->name) && + $testproduct) { + ThrowUserError('prod_name_already_in_use', + {product => $product_name}); + } + + my $milestone = new Bugzilla::Milestone($product_old->id, + $defaultmilestone); + if (!$milestone) { + ThrowUserError('prod_must_define_defaultmilestone', + {product => $product_old->name, + defaultmilestone => $defaultmilestone, + classification => $classification_name}); + } + + $disallownew = $disallownew ? 1 : 0; + if ($disallownew ne $product_old->disallow_new) { SendSQL("UPDATE products SET disallownew=$disallownew - WHERE id=$product_id"); - $vars->{'updated_bugsubmitstatus'} = 1; - $vars->{'new_bugsubmitstatus'} = $disallownew; + WHERE id = " . $product_old->id); } - if ($description ne $descriptionold) { - unless ($description) { - ThrowUserError('prod_cant_delete_description', - {product => $productold}); - } + if ($description ne $product_old->description) { SendSQL("UPDATE products SET description=" . SqlQuote($description) . " - WHERE id=$product_id"); - $vars->{'updated_description'} = 1; - $vars->{'old_description'} = $descriptionold; - $vars->{'new_description'} = $description; + WHERE id = " . $product_old->id); } if (Param('usetargetmilestone') - && ($milestoneurl ne $milestoneurlold)) { + && ($milestoneurl ne $product_old->milestone_url)) { SendSQL("UPDATE products SET milestoneurl=" . SqlQuote($milestoneurl) . " - WHERE id=$product_id"); - $vars->{'updated_milestoneurl'} = 1; - $vars->{'old_milestoneurl'} = $milestoneurlold; - $vars->{'new_milestoneurl'} = $milestoneurl; + WHERE id = " . $product_old->id); } - if ($votesperuser ne $votesperuserold) { + if ($votesperuser ne $product_old->votes_per_user) { SendSQL("UPDATE products SET votesperuser=$votesperuser - WHERE id=$product_id"); - $vars->{'updated_votesperuser'} = 1; - $vars->{'old_votesperuser'} = $votesperuserold; - $vars->{'new_votesperuser'} = $votesperuser; - + WHERE id = " . $product_old->id); $checkvotes = 1; } - if ($maxvotesperbug ne $maxvotesperbugold) { + if ($maxvotesperbug ne $product_old->max_votes_per_bug) { SendSQL("UPDATE products SET maxvotesperbug=$maxvotesperbug - WHERE id=$product_id"); - $vars->{'updated_maxvotesperbug'} = 1; - $vars->{'old_maxvotesperbug'} = $maxvotesperbugold; - $vars->{'new_maxvotesperbug'} = $maxvotesperbug; - + WHERE id = " . $product_old->id); $checkvotes = 1; } - if ($votestoconfirm ne $votestoconfirmold) { + if ($votestoconfirm ne $product_old->votes_to_confirm) { SendSQL("UPDATE products SET votestoconfirm=$votestoconfirm - WHERE id=$product_id"); - - $vars->{'updated_votestoconfirm'} = 1; - $vars->{'old_votestoconfirm'} = $votestoconfirmold; - $vars->{'new_votestoconfirm'} = $votestoconfirm; + WHERE id = " . $product_old->id); $checkvotes = 1; } - if ($defaultmilestone ne $defaultmilestoneold) { - SendSQL("SELECT value FROM milestones " . - "WHERE value = " . SqlQuote($defaultmilestone) . - " AND product_id = $product_id"); - if (!FetchOneColumn()) { - ThrowUserError('prod_must_define_defaultmilestone', - {product => $productold, - defaultmilestone => $defaultmilestone, - classification => $classification}); - } + if ($defaultmilestone ne $product_old->default_milestone) { SendSQL("UPDATE products " . "SET defaultmilestone = " . SqlQuote($defaultmilestone) . - "WHERE id=$product_id"); + "WHERE id = " . $product_old->id); - $vars->{'updated_defaultmilestone'} = 1; - $vars->{'old_defaultmilestone'} = $defaultmilestoneold; - $vars->{'new_defaultmilestone'} = $defaultmilestone; } - my $qp = SqlQuote($product); - my $qpold = SqlQuote($productold); - - if ($product ne $productold) { - unless ($product) { - ThrowUserError('prod_cant_delete_name', - {product => $productold}); - } - - if (lc($product) ne lc($productold) && - TestProduct($product)) { - ThrowUserError('prod_name_already_in_use', - {product => $product}); - } - - SendSQL("UPDATE products SET name=$qp WHERE id=$product_id"); + my $qp = SqlQuote($product_name); - $vars->{'updated_product'} = 1; - $vars->{'old_product'} = $productold; - $vars->{'new_product'} = $product; + if ($product_name ne $product_old->name) { + SendSQL("UPDATE products SET name=$qp WHERE id= ".$product_old->id); } $dbh->bz_unlock_tables(); unlink "$datadir/versioncache"; + my $product = new Bugzilla::Product({name => $product_name}); + if ($checkvotes) { $vars->{'checkvotes'} = 1; @@ -1092,7 +863,7 @@ if ($action eq 'update') { SendSQL("SELECT votes.who, votes.bug_id " . "FROM votes, bugs " . "WHERE bugs.bug_id = votes.bug_id " . - " AND bugs.product_id = $product_id " . + " AND bugs.product_id = " . $product->id . " AND votes.vote_count > $maxvotesperbug"); my @list; while (MoreSQLData()) { @@ -1122,7 +893,7 @@ if ($action eq 'update') { SendSQL("SELECT votes.who, votes.vote_count FROM votes, bugs " . "WHERE bugs.bug_id = votes.bug_id " . - " AND bugs.product_id = $product_id"); + " AND bugs.product_id = " . $product->id); my %counts; while (MoreSQLData()) { my ($who, $count) = (FetchSQLData()); @@ -1137,7 +908,7 @@ if ($action eq 'update') { if ($counts{$who} > $votesperuser) { SendSQL("SELECT votes.bug_id FROM votes, bugs " . "WHERE bugs.bug_id = votes.bug_id " . - " AND bugs.product_id = $product_id " . + " AND bugs.product_id = " . $product->id . " AND votes.who = $who"); while (MoreSQLData()) { my ($id) = FetchSQLData(); @@ -1157,7 +928,7 @@ if ($action eq 'update') { WHERE product_id = ? AND bug_status = 'UNCONFIRMED' AND votes >= ?", - undef, ($product_id, $votestoconfirm)); + undef, ($product->id, $votestoconfirm)); my @updated_bugs = (); foreach my $bug_id (@$bug_list) { @@ -1170,7 +941,9 @@ if ($action eq 'update') { } - $vars->{'name'} = $product; + $vars->{'old_product'} = $product_old; + $vars->{'product'} = $product; + $template->process("admin/products/updated.html.tmpl", $vars) || ThrowTemplateError($template->error()); @@ -1182,22 +955,20 @@ if ($action eq 'update') { # if ($action eq 'editgroupcontrols') { - my $product_id = get_product_id($product); - $product_id - || ThrowUserError("invalid_product_name", { product => $product }); + my $product = Bugzilla::Product::check_product($product_name); # Display a group if it is either enabled or has bugs for this product. SendSQL("SELECT id, name, entry, membercontrol, othercontrol, canedit, " . "isactive, COUNT(bugs.bug_id) " . "FROM groups " . "LEFT JOIN group_control_map " . "ON group_control_map.group_id = id " . - "AND group_control_map.product_id = $product_id " . - "LEFT JOIN bug_group_map " . + "AND group_control_map.product_id = " . $product->id . + " LEFT JOIN bug_group_map " . "ON bug_group_map.group_id = groups.id " . "LEFT JOIN bugs " . "ON bugs.bug_id = bug_group_map.bug_id " . - "AND bugs.product_id = $product_id " . - "WHERE isbuggroup != 0 " . + "AND bugs.product_id = " . $product->id . + " WHERE isbuggroup != 0 " . "AND (isactive != 0 OR entry IS NOT NULL " . "OR bugs.bug_id IS NOT NULL) " . $dbh->sql_group_by('name', 'id, entry, membercontrol, @@ -1218,8 +989,9 @@ if ($action eq 'editgroupcontrols') { push @groups,\%group; } $vars->{'product'} = $product; - $vars->{'classification'} = $classification; + $vars->{'groups'} = \@groups; + $vars->{'const'} = { 'CONTROLMAPNA' => CONTROLMAPNA, 'CONTROLMAPSHOWN' => CONTROLMAPSHOWN, diff --git a/template/en/default/admin/products/confirm-delete.html.tmpl b/template/en/default/admin/products/confirm-delete.html.tmpl index 672f345e9..9358974de 100644 --- a/template/en/default/admin/products/confirm-delete.html.tmpl +++ b/template/en/default/admin/products/confirm-delete.html.tmpl @@ -15,32 +15,16 @@ #%] [%# INTERFACE: - # product_name: string; The name of the product - # - # prod_description: string; Product description, may be empty + # product: Bugzilla::Product object; The product # # (classification fields available if Param('useclassification') is enabled:) # - # classification: string; The name of the classification the product is in - # - # class_description: string; Classification description, may be empty - # - # bug_count: number; The number of bugs belonging to the product - # - # milestoneurl: string; milestone url, if milestones are in use, - # may be empty - # - # disallownew: boolean; Are new bugs allowed for the product flag - # - # components: list of hashes, members are: name, description - # - # versions: list of version values. - # - # milestones: list of milestone values. + # classification: Bugzilla::Classification object; The classification + # the product is in # #%] -[% title = BLOCK %]Delete Product '[% product_name FILTER html %]' +[% title = BLOCK %]Delete Product '[% product.name FILTER html %]' [% END %] [% PROCESS global/header.html.tmpl @@ -50,25 +34,12 @@ [% IF classification %] [% classification_url_part = BLOCK %]&classification= - [%- classification FILTER url_quote %] + [%- classification.name FILTER url_quote %] [%- END %] [% ELSE %] [% classification_url_part = "" %] [% END %] -[% UNLESS class_description %] - [% class_description = '<span style="color: red">missing</span>' %] -[% END %] -[% UNLESS prod_description %] - [% prod_description = '<span style="color: red">missing</span>' %] -[% END %] - -[% IF disallownew %] - [% disallownew = "closed" %] -[% ELSE %] - [% disallownew = "open" %] -[% END %] - <table border="1" cellpadding="4" cellspacing="0"> <tr bgcolor="#6666FF"> <th valign="top" align="left">Field</th> @@ -78,37 +49,49 @@ [% IF Param('useclassification') %] <tr> <td>Classification:</td> - <td>[% classification FILTER html %]</td> + <td>[% classification.name FILTER html %]</td> </tr> <tr> <td>Classification Description:</td> [%# descriptions are intentionally not filtered to allow html content %] - <td>[% class_description FILTER none %]</td> + <td> + [% IF classification.description %] + [% classification.description FILTER none %] + [% ELSE %] + <span style="color: red">missing</span> + [% END %] + </td> </tr> [% END %] <tr> <td valign="top">Product:</td> <td valign="top"> - <a href="editproducts.cgi?product=[% product_name FILTER url_quote %] + <a href="editproducts.cgi?product=[% product.name FILTER url_quote %] [%- classification_url_part %]"> - [% product_name FILTER html %] + [% product.name FILTER html %] </a> </td> </tr> <tr> <td valign="top">Description:</td> [%# descriptions are intentionally not filtered to allow html content %] - <td valign="top">[% prod_description FILTER none %]</td> + <td valign="top"> + [% IF product.description %] + [% product.description FILTER none %] + [% ELSE %] + <span style="color: red">missing</span> + [% END %] + </td> </tr> [% IF Param('usetargetmilestone') %] <tr> <td>Milestone URL:</td> <td> - [% IF milestoneurl %] - <a href="[% milestoneurl FILTER uri %]"> - [%- milestoneurl FILTER html %] + [% IF product.milestone_url %] + <a href="[% product.milestone_url FILTER uri %]"> + [%- product.milestone_url FILTER html %] </a> [% ELSE %] none @@ -119,15 +102,21 @@ <tr> <td>Closed for [% terms.bugs %]:</td> - <td>[% disallownew FILTER html %]</td> + <td> + [% IF product.disallownew %] + closed + [% ELSE %] + open + [% END %] + </td> </tr> <tr> <td> - [% IF components.size > 0 %] - <a href="editcomponents.cgi?product=[% product_name FILTER url_quote %] + [% IF product.components.size > 0 %] + <a href="editcomponents.cgi?product=[% product.name FILTER url_quote %] [%- classification_url_part %]" - title="Edit components for product '[% product_name FILTER html %]'"> + title="Edit components for product '[% product.name FILTER html %]'"> Components: </a> [% ELSE %] @@ -135,9 +124,9 @@ [% END %] </td> <td> - [% IF components.size > 0 %] + [% IF product.components.size > 0 %] <table> - [% FOREACH c = components %] + [% FOREACH c = product.components %] <tr> <th align="right">[% c.name FILTER html %]:</th> [%# descriptions are intentionally not filtered to allow html content %] @@ -159,8 +148,8 @@ <tr> <td> - [% IF versions.size > 0 %] - <a href="editversions.cgi?product=[%- product_name FILTER url_quote %] + [% IF product.versions.size > 0 %] + <a href="editversions.cgi?product=[%- product.name FILTER url_quote %] [%- classification_url_part %]"> Versions: </a> @@ -168,9 +157,9 @@ Versions: [% END %] <td> - [% IF versions.size > 0 %] - [% FOREACH v = versions %] - [% v FILTER html %]<br> + [% IF product.versions.size > 0 %] + [% FOREACH v = product.versions %] + [% v.name FILTER html %]<br> [% END %] [% ELSE %] none @@ -180,8 +169,8 @@ <tr> <td valign="top"> - [% IF milestones.size > 0 %] - <a href="editmilestones.cgi?product=[%- product_name FILTER url_quote %] + [% IF product.milestones.size > 0 %] + <a href="editmilestones.cgi?product=[%- product.name FILTER url_quote %] [%- classification_url_part -%]"> Milestones: </a> @@ -190,9 +179,9 @@ [% END %] </td> <td> - [% IF milestones.size > 0 %] - [% FOREACH m = milestones %] - [% m FILTER html %]<br> + [% IF product.milestones.size > 0 %] + [% FOREACH m = product.milestones %] + [% m.name FILTER html %]<br> [% END %] [% ELSE %] none @@ -203,12 +192,12 @@ <tr> <td>[% terms.Bugs %]:</td> <td> - [% IF bug_count %] - <a href="buglist.cgi?product=[%- product_name FILTER url_quote %] + [% IF product.bug_count %] + <a href="buglist.cgi?product=[%- product.name FILTER url_quote %] [%- classification_url_part %]" title="List of [% terms.bugs %] for product ' - [%- product_name FILTER html %]'"> - [% bug_count %] + [%- product.name FILTER html %]'"> + [% product.bug_count FILTER html %] </a> [% ELSE %] none @@ -219,21 +208,21 @@ <h2>Confirmation</h2> -[% IF bug_count %] +[% IF product.bug_count %] [% IF !Param("allowbugdeletion") %] Sorry, there - [% IF bug_count > 1 %] - are [% bug_count %] [%+ terms.bugs %] + [% IF product.bug_count > 1 %] + are [% product.bug_count FILTER html %] [%+ terms.bugs %] [% ELSE %] is 1 [% terms.bug %] [% END %] outstanding for this product. You must reassign - [% IF bug_count > 1 %] + [% IF product.bug_count > 1 %] those [% terms.bugs %] [% ELSE %] that [% terms.bug %] @@ -247,8 +236,8 @@ <tr> <td> There - [% IF bug_count > 1 %] - are [% bug_count %] [%+ terms.bugs %] + [% IF product.bug_count > 1 %] + are [% product.bug_count FILTER html %] [%+ terms.bugs %] [% ELSE %] is 1 [% terms.bug %] [% END %] @@ -263,16 +252,16 @@ [% END %] -[% IF bug_count == 0 || Param('allowbugdeletion') %] +[% IF product.bug_count == 0 || Param('allowbugdeletion') %] <p>Do you really want to delete this product?<p> <form method="post" action="editproducts.cgi"> <input type="submit" value="Yes, delete"> <input type="hidden" name="action" value="delete"> - <input type="hidden" name="product" value="[% product_name FILTER html %]"> + <input type="hidden" name="product" value="[% product.name FILTER html %]"> <input type="hidden" name="classification" - value="[% classification FILTER html %]"> + value="[% classification.name FILTER html %]"> </form> [% END %] diff --git a/template/en/default/admin/products/create.html.tmpl b/template/en/default/admin/products/create.html.tmpl index 8dc6615b4..dc60299b8 100644 --- a/template/en/default/admin/products/create.html.tmpl +++ b/template/en/default/admin/products/create.html.tmpl @@ -15,8 +15,9 @@ #%] [%# INTERFACE: - # classification: string; name of the classification in which the new - # product is created. + # classification: Bugzilla::Classification object; If classifications + # are enabled, then this is + # the currently selected classification # #%] @@ -56,9 +57,11 @@ <input type="hidden" name="open_name" value="All Open"> <input type="hidden" name="action" value="new"> <input type="hidden" name="classification" - value="[% classification FILTER html %]"> + value="[% classification.name FILTER html %]"> </form> -[% PROCESS "admin/products/footer.html.tmpl" no_add_product_link = 1 %] +[% PROCESS "admin/products/footer.html.tmpl" + no_add_product_link = 1 + no_edit_product_link = 1 %] [% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/products/created.html.tmpl b/template/en/default/admin/products/created.html.tmpl index e4229f8a2..f19854200 100644 --- a/template/en/default/admin/products/created.html.tmpl +++ b/template/en/default/admin/products/created.html.tmpl @@ -14,18 +14,23 @@ # Contributor(s): Gabriel S. Oliveira <gabriel@async.com.br> #%] +[%# INTERFACE: + # product: Bugzilla::Product object; the Product created. + # + #%] + [% PROCESS global/header.html.tmpl title = 'New Product Created' %] <br> <div style='border: 1px red solid; padding: 1ex;'> <b>You will need to - <a href="editcomponents.cgi?action=add&product=[% product FILTER url_quote %]"> + <a href="editcomponents.cgi?action=add&product=[% product.name FILTER url_quote %]"> add at least one component </a> before you can enter [% terms.bugs %] against this product </b> </div> -[% PROCESS "admin/products/footer.html.tmpl" name = product %] +[% PROCESS "admin/products/footer.html.tmpl" %] [% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/products/deleted.html.tmpl b/template/en/default/admin/products/deleted.html.tmpl index 3252f97c9..049bcae0b 100644 --- a/template/en/default/admin/products/deleted.html.tmpl +++ b/template/en/default/admin/products/deleted.html.tmpl @@ -15,11 +15,16 @@ # #%] +[%# INTERFACE: + # product: Bugzilla::Product object; The product + # + #%] + [% PROCESS global/header.html.tmpl title = 'Deleting product' %] -[% IF nb_bugs %] +[% IF product.bug_count %] All references to deleted [% terms.bugs %] removed. [% END %] @@ -35,7 +40,7 @@ </p> <p> - Product [% product FILTER html %] deleted. + Product [% product.name FILTER html %] deleted. </p> [% PROCESS admin/products/footer.html.tmpl diff --git a/template/en/default/admin/products/edit-common.html.tmpl b/template/en/default/admin/products/edit-common.html.tmpl index cbbbd8232..f6b0d53ce 100644 --- a/template/en/default/admin/products/edit-common.html.tmpl +++ b/template/en/default/admin/products/edit-common.html.tmpl @@ -17,14 +17,15 @@ #%] [%# INTERFACE: - # classification: string; name of classification product is in. - # product: array; an array of product objects. + # product: Bugzilla::Product object; The product + # + # classification: Bugzilla::Classifiation object; classification product is in. #%] [% IF Param('useclassification') %] <tr> <th align="right"><b>Classification:</b></th> - <td><b>[% classification FILTER html %]</b></td> + <td><b>[% classification.name FILTER html %]</b></td> </tr> [% END %] diff --git a/template/en/default/admin/products/edit.html.tmpl b/template/en/default/admin/products/edit.html.tmpl index 15843bb44..089ce4c8d 100644 --- a/template/en/default/admin/products/edit.html.tmpl +++ b/template/en/default/admin/products/edit.html.tmpl @@ -17,13 +17,14 @@ #%] [%# INTERFACE: - # classification: string; name of classification product is in. - # product: an array of product objects. - # components: an array of component object(s) related to the product. - # groups: an array of group objects related to the product. - # versions: an array of version objects related to product. - # milestones: an array of milestones objects related to product. - # bug_count: integer; number of bugs in this product. + # product: Bugzilla::Product object; The product + # + # (classification fields available if Param('useclassification') is enabled:) + # + # classification: Bugzilla::Classification object; The classification + # the product is in + # + # groups_controls: a hash of group controls related to the product. #%] [% title = BLOCK %]Edit Product[% END %] @@ -44,8 +45,8 @@ </a> </th> <td> - [% IF components.size -%] - [% FOREACH component = components %] + [% IF product.components.size -%] + [% FOREACH component = product.components %] <b>[% component.name FILTER html %]:</b> [% IF component.description %] [% component.description FILTER none %] @@ -65,9 +66,9 @@ versions:</a> </th> <td> - [%- IF versions.size -%] - [% FOREACH v = versions %] - [% v FILTER html %] + [%- IF product.versions.size -%] + [% FOREACH v = product.versions %] + [% v.name FILTER html %] <br> [% END %] [% ELSE %] @@ -82,9 +83,9 @@ versions:</a> Edit milestones:</a> </th> <td> - [%- IF milestones.size -%] - [%- FOREACH m = milestones -%] - [% m FILTER html %] + [%- IF product.milestones.size -%] + [%- FOREACH m = product.milestones -%] + [% m.name FILTER html %] <br> [% END %] [% ELSE %] @@ -97,15 +98,15 @@ versions:</a> <th align="right" valign="top"> <a href="editproducts.cgi?action=editgroupcontrols&product= [%- product.name FILTER url_quote %]&classification= - [%- classification FILTER url_quote %]"> + [%- classification.name FILTER url_quote %]"> Edit Group Access Controls: </a> </th> <td> - [% IF groups.size %] - [% FOREACH g = groups %] - <b>[% g.name FILTER html %]:</b> - [% IF g.isactive %] + [% IF group_controls.size %] + [% FOREACH g = group_controls.values %] + <b>[% g.group.name FILTER html %]:</b> + [% IF g.group.isactive %] [% g.membercontrol FILTER html %]/ [% g.othercontrol FILTER html %] [% IF g.entry %], ENTRY[% END %] @@ -122,32 +123,21 @@ versions:</a> </tr> <tr> <th align="right">[% terms.Bugs %]:</th> - <td>[% bug_count FILTER html %]</td> + <td><a href="buglist.cgi?product=[% product.name FILTER url_quote %]"> + [% product.bug_count FILTER html %]</a></td> </tr> </table> - <input type="hidden" name="productold" + <input type="hidden" name="product_old_name" value="[% product.name FILTER html %]"> - <input type="hidden" name="descriptionold" - value="[% product.description FILTER html %]"> - <input type="hidden" name="milestoneurlold" - value="[% product.milestoneurl FILTER html %]"> - <input type="hidden" name="disallownewold" - value="[% product.disallownew FILTER html %]"> - <input type="hidden" name="votesperuserold" - value="[% product.votesperuser FILTER html %]"> - <input type="hidden" name="maxvotesperbugold" - value="[% product.maxvotesperbug FILTER html %]"> - <input type="hidden" name="votestoconfirmold" - value="[% product.votestoconfirm FILTER html %]"> - <input type="hidden" name="defaultmilestoneold" - value="[% product.defaultmilestone FILTER html %]"> <input type="hidden" name="action" value="update"> <input type="hidden" name="classification" - value="[% classification FILTER html %]"> + value="[% classification.name FILTER html %]"> <input type="submit" name="submit" value="Update"> </form> -[% PROCESS "admin/products/footer.html.tmpl" no_add_product_link = 1 %] +[% PROCESS "admin/products/footer.html.tmpl" + no_add_product_link = 1 + no_edit_product_link = 1 %] [% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/products/footer.html.tmpl b/template/en/default/admin/products/footer.html.tmpl index 531e6c48e..480868abd 100644 --- a/template/en/default/admin/products/footer.html.tmpl +++ b/template/en/default/admin/products/footer.html.tmpl @@ -15,10 +15,11 @@ #%] [%# INTERFACE: - # name: string; the name of the product + # product: Bugzilla::Product Object; the product # - # classification: string; If classifications are enabled, then this is - # the currently selected classification + # classification: Bugzilla::Classification object ; If classifications + # are enabled, then this is the currently + # selected classification # # no_XXX_link: boolean; if defined, then don't show the corresponding # link. Supported parameters are: @@ -30,13 +31,13 @@ [% IF Param('useclassification') && classification %] [% classification_url_part = BLOCK %]&classification= - [%- classification FILTER url_quote %] + [%- classification.name FILTER url_quote %] [% END %] [% classification_url_part_start = BLOCK %]classification= - [%- classification FILTER url_quote %] + [%- classification.name FILTER url_quote %] [% END %] [% classification_text = BLOCK %] - of classification '[% classification FILTER html %]' + of classification '[% classification.name FILTER html %]' [% END %] [% END %] @@ -51,20 +52,22 @@ classification if they are enabled, but I'm just being paranoid %] [% IF Param('useclassification') && classification %] (<a title="Add a product to classification ' - [%- classification FILTER html %]'" + [%- classification.name FILTER html %]'" href="editproducts.cgi?action=add [%- classification_url_part %]">to - classification '[% classification FILTER html %]'</a>) + classification '[% classification.name FILTER html %]' + </a>) [% END %]. [% END %] -[% IF name && !no_edit_product_link %] +[% IF product && !no_edit_product_link %] Edit product <a - title="Edit Product '[% name FILTER html %]' - [% classification_text %]" + title="Edit Product '[% product.name FILTER html %]' + [%- classification_text %]" href="editproducts.cgi?action=edit&product= - [%- name FILTER url_quote %][% classification_url_part %]"> - '[% name FILTER html %]'</a>. + [%- product.name FILTER url_quote %] + [%- classification_url_part %]"> + '[% product.name FILTER html %]'</a>. [% END %] @@ -80,7 +83,7 @@ [% IF Param('useclassification') && classification %] Edit classification <a href="editclassifications.cgi?action=edit [%- classification_url_part %]">' - [%- classification FILTER html %]'</a>. + [%- classification.name FILTER html %]'</a>. [% END %] diff --git a/template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl b/template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl index 006189c13..f8d55c397 100644 --- a/template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl +++ b/template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl @@ -21,9 +21,11 @@ #%] [% PROCESS global/variables.none.tmpl %] +[% title = BLOCK %] + Confirm Group Control Change for product '[%- product.name FILTER html %]' +[% END %] -[% PROCESS global/header.html.tmpl title="Confirm Group Control Change for product \'$product\'" %] - +[% PROCESS global/header.html.tmpl title = title %] [% FOREACH group = mandatory_groups %] <P> group '[% group.name FILTER html %]' impacts [% group.count %] diff --git a/template/en/default/admin/products/groupcontrol/edit.html.tmpl b/template/en/default/admin/products/groupcontrol/edit.html.tmpl index 4f13e6f22..174d15869 100644 --- a/template/en/default/admin/products/groupcontrol/edit.html.tmpl +++ b/template/en/default/admin/products/groupcontrol/edit.html.tmpl @@ -21,16 +21,18 @@ [% PROCESS global/variables.none.tmpl %] -[% filt_product = product FILTER html %] -[% filt_classification = classification FILTER html %] -[% PROCESS global/header.html.tmpl - title = "Edit Group Controls for '$filt_product'" +[% title = BLOCK %] + Edit Group Controls for [% product.name FILTER html %] +[% END %] +[% PROCESS global/header.html.tmpl + title = title %] <form method="post" action="editproducts.cgi"> <input type="hidden" name="action" value="updategroupcontrols"> - <input type="hidden" name="product" value="[% filt_product %]"> - <input type="hidden" name="classification" value="[% filt_classification %]"> + <input type="hidden" name="product" value="[% product.name FILTER html %]"> + <input type="hidden" name="classification" + value="[% classification.name FILTER html %]"> <table id="form" cellspacing="0" cellpadding="4" border="1"> <tr bgcolor="#6666ff"> diff --git a/template/en/default/admin/products/groupcontrol/updated.html.tmpl b/template/en/default/admin/products/groupcontrol/updated.html.tmpl index 71ae0d7eb..5719bc6e6 100644 --- a/template/en/default/admin/products/groupcontrol/updated.html.tmpl +++ b/template/en/default/admin/products/groupcontrol/updated.html.tmpl @@ -18,12 +18,12 @@ [%# INTERFACE: # removed_na: array of hashes; groups not applicable for the product. # added_mandatory: array of hashes; groups mandatory for the product. - # classification: string; product classification name. - # product: string; name of the product. + # classification: Bugzilla::Classification object; product classification. + # product: Bugzilla::Product object; the product. #%] [% title = BLOCK %] - Update group access controls for [% product FILTER html %] + Update group access controls for [% product.name FILTER html %] [% END %] [% PROCESS global/header.html.tmpl @@ -48,6 +48,6 @@ Group control updates done<p> -[% PROCESS admin/products/footer.html.tmpl name = product %] +[% PROCESS admin/products/footer.html.tmpl %] [% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/products/list.html.tmpl b/template/en/default/admin/products/list.html.tmpl index 98676e198..17eb61c0d 100644 --- a/template/en/default/admin/products/list.html.tmpl +++ b/template/en/default/admin/products/list.html.tmpl @@ -15,19 +15,10 @@ #%] [%# INTERFACE: - # products: array of hashes having the following properties: - # - name: string; The name of the product - # - description: string; The product description (html allowed) - # - status: boolean; Can new bugs be created for the product? - # - votesperuser: number; The number of votes a user is allowed - # in the product - # - maxvotersperbug: number; Maximum votes allowed per bug in this - # product - # - votestoconfirm: number; The number of votes that are needed to - # auto-confirm a bug in this product - # - bug_count: number; The number of bugs in this product + # products: array of Bugzilla::Product objects # - # classification: string; If classifications are enabled, then this is + # classification: Bugzilla::Classification object; If classifications + # are enabled, then this is # the currently selected classification #%] @@ -35,10 +26,10 @@ [% IF classification %] [% classification_url_part = BLOCK %]&classification= - [%- classification FILTER url_quote %] + [%- classification.name FILTER url_quote %] [%- END %] [% classification_title = BLOCK %] - in classification '[% classification FILTER html %]' + in classification '[% classification.name FILTER html %]' [% END %] [% END %] @@ -54,7 +45,7 @@ editproducts.cgi?action=del&product=%%name%% [%- classification_url_part %] [% END %] -[% bug_count_contentlink = BLOCK %]buglist.cgi?product=%%name%%& +[% bug_count_contentlink = BLOCK %]buglist.cgi?product=%%name%% [%- classification_url_part %][% END %] @@ -70,9 +61,8 @@ allow_html_content => 1 }, { - name => "status" + name => "disallow_new" heading => "Open For New $terms.Bugs" - yesno_field => 1 }, { name => "votesperuser" @@ -95,15 +85,27 @@ align => 'right' contentlink => bug_count_contentlink }, + { + heading => "Action" + content => "Delete" + contentlink => delete_contentlink + }, ] %] -[% columns.push({ - heading => "Action" - content => "Delete" - contentlink => delete_contentlink - }) -%] +[% overrides.disallow_new = [ { + match_value => "1" + match_field => 'disallow_new' + override_content => 1 + content => "No" + }, + { + match_value => 0 + match_field => 'disallow_new' + override_content => 1 + content => "Yes" + }] +%] [% PROCESS admin/table.html.tmpl columns = columns diff --git a/template/en/default/admin/products/updated.html.tmpl b/template/en/default/admin/products/updated.html.tmpl index 7c00c4ae5..993a27ed9 100644 --- a/template/en/default/admin/products/updated.html.tmpl +++ b/template/en/default/admin/products/updated.html.tmpl @@ -21,33 +21,10 @@ [%# INTERFACE: # - # updated_XXX : boolean; is true when the 'XXX' field has been updated. - # old_XXX : ... string; old value of the field 'XXX'. - # new_XXX : ... string; new value of the field 'XXX'. + # old_product : Bugzilla::Product Object; old product. + # product : Bugzilla::Product Object; new product. # - # updated_product: boolean; the name of the product was updated - # - # updated_description: boolean; the product description was updated - # - # updated_milestoneurl: boolean; the product milestone URL was updated - # - # updated_votesperuser: boolean; the votes per user was updated - # - # updated_maxvotesperbug: boolean; the max votes per bug was updated - # - # updated_votestoconfirm: boolean; the votes to confirm a bug was updated - # - # updated_defaultmilestone: boolean; the default milestone was updated - # - # updated_bugsubmitstatus: boolean; the open/closed for new bugs status - # was updated (no 'old_XXX' value) - # - # classification: string; The product classification (may be empty or missing) - # - # changer: string; user id of the user making the changes, used for mailing - # bug changes if necessary - # - # name: string; the product name + # classification: Bugzilla::Classification Object; The product classification (may be empty or missing) # # checkvotes: boolean; is true if vote related fields have changed. If so, # then the following parameters will be specified: @@ -62,105 +39,110 @@ # # confirmedbugs: list of bug ids, which were confirmed by votes # + # changer: string; user id of the user making the changes, used for mailing + # bug changes if necessary + # #%] [% IF classification %] [% classification_url_part = BLOCK %]&classification= - [%- classification FILTER url_quote %] + [%- classification.name FILTER url_quote %] [% END %] [% classification_text = BLOCK %] - of classification '[% classification FILTER html %]' + of classification '[% classification.name FILTER html %]' [% END %] [% END %] -[% title = BLOCK %]Updating Product '[% name FILTER html %]' +[% title = BLOCK %]Updating Product '[% product.name FILTER html %]' [% classification_text FILTER none %][% END %] [% PROCESS global/header.html.tmpl title = title style_urls = ['skins/standard/admin.css'] %] +[% updated = 0 %] -[% IF updated_product %] +[% IF product.name != old_product.name %] <p> - Updated product name from '[% old_product FILTER html %]' to + Updated product name from '[% old_product.name FILTER html %]' to <a href="editproducts.cgi?action=edit&product= - [%- new_product FILTER url_quote %] - [%- classification_url_part FILTER none %]">[% new_product FILTER html %]</a>. + [%- product.name FILTER url_quote %] + [%- classification_url_part FILTER none %]">[% product.name FILTER html %]</a>. + [% updated = 1 %] [% END %] -[% IF updated_description %] +[% IF product.description != old_product.description %] <p> Updated description to:</p> </p> - <p style="margin: 1em 3em 1em 3em">[% new_description FILTER html %]</p> + <p style="margin: 1em 3em 1em 3em">[% product.description FILTER html %]</p> + [% updated = 1 %] [% END %] -[% IF updated_bugsubmitstatus %] +[% IF product.disallow_new != old_product.disallow_new %] <p> Product is now - [% IF new_bugsubmitstatus %] + [% IF product.disallow_new %] closed to [% ELSE %] open for [% END %] new [% terms.bugs %]. + [% updated = 1 %] [% END %] -[% IF updated_milestoneurl %] +[% IF product.milestone_url != old_product.milestone_url %] <p> Updated milestone URL - [% IF old_milestoneurl != '' %] - from<br> <a href="[%- old_milestoneurl FILTER html %]">' - [%- old_milestoneurl FILTER html %]'</a> + [% IF old_product.milestone_url != '' %] + from<br> <a href="[%- old_product.milestone_url FILTER html %]">' + [%- old_product.milestone_url FILTER html %]'</a> [% END %] to - [% IF new_milestoneurl != '' %] - <br><a href="[%- new_milestoneurl FILTER html %]">' - [%- new_milestoneurl FILTER html %]'</a>. + [% IF product.milestone_url != '' %] + <br><a href="[%- product.milestone_url FILTER html %]">' + [%- product.milestone_url FILTER html %]'</a>. [% ELSE %] be empty. [% END %] </p> + [% updated = 1 %] [% END %] -[% IF updated_defaultmilestone %] +[% IF product.default_milestone != old_product.default_milestone %] <p> - Updated default milestone from '[% old_defaultmilestone FILTER html %]' to - '[% new_defaultmilestone FILTER html %]'. + Updated default milestone from '[% old_product.default_milestone FILTER html %]' to + '[% product.default_milestone FILTER html %]'. </p> + [% updated = 1 %] [% END %] -[% IF updated_votesperuser %] +[% IF product.votes_per_user != old_product.votes_per_user %] <p> Updated votes per user from - [%+ old_votesperuser FILTER html %] to - [%+ new_votesperuser FILTER html %]. + [%+ old_product.votes_per_user FILTER html %] to + [%+ product.votes_per_user FILTER html %]. + [% updated = 1 %] [% END %] -[% IF updated_maxvotesperbug %] +[% IF product.max_votes_per_bug != old_product.max_votes_per_bug %] <p> Updated maximum votes per [% terms.bug %] from - [%+ old_maxvotesperbug FILTER html %] to - [%+ new_maxvotesperbug FILTER html %]. + [%+ old_product.max_votes_per_bug FILTER html %] to + [%+ product.max_votes_per_bug FILTER html %]. + [% updated = 1 %] [% END %] -[% IF updated_votestoconfirm %] +[% IF product.votes_to_confirm != old_product.votes_to_confirm %] <p> Updated number of votes needed to confirm a [% terms.bug %] from - [%+ old_votestoconfirm FILTER html %] to - [%+ new_votestoconfirm FILTER html %]. + [%+ old_product.votes_to_confirm FILTER html %] to + [%+ product.votes_to_confirm FILTER html %]. + [% updated = 1 %] [% END %] -[% UNLESS updated_bugsubmitstatus || - updated_description || - updated_milestoneurl || - updated_votesperuser || - updated_maxvotesperbug || - updated_votestoconfirm || - updated_defaultmilestone || - updated_product %] - <p>Nothing changed for product '[% name FILTER html %]'. +[% UNLESS updated %] + <p>Nothing changed for product '[% product.name FILTER html %]'. [% END %] [%# Note that this display of changed votes and/or confirmed bugs is diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl index e0a811a48..eb0368c0c 100644 --- a/template/en/default/filterexceptions.pl +++ b/template/en/default/filterexceptions.pl @@ -506,8 +506,6 @@ ], 'admin/products/groupcontrol/edit.html.tmpl' => [ - 'filt_classification', - 'filt_product', 'group.bugcount', 'group.id', 'const.CONTROLMAPNA', @@ -522,7 +520,6 @@ 'admin/products/confirm-delete.html.tmpl' => [ 'classification_url_part', - 'bug_count', ], 'admin/products/footer.html.tmpl' => [ |