aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Product.pm23
-rwxr-xr-xeditproducts.cgi628
-rw-r--r--template/en/default/admin/products/confirm-delete.html.tmpl131
-rw-r--r--template/en/default/admin/products/create.html.tmpl11
-rw-r--r--template/en/default/admin/products/created.html.tmpl9
-rw-r--r--template/en/default/admin/products/deleted.html.tmpl9
-rw-r--r--template/en/default/admin/products/edit-common.html.tmpl7
-rw-r--r--template/en/default/admin/products/edit.html.tmpl66
-rw-r--r--template/en/default/admin/products/footer.html.tmpl31
-rw-r--r--template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl6
-rw-r--r--template/en/default/admin/products/groupcontrol/edit.html.tmpl14
-rw-r--r--template/en/default/admin/products/groupcontrol/updated.html.tmpl8
-rw-r--r--template/en/default/admin/products/list.html.tmpl48
-rw-r--r--template/en/default/admin/products/updated.html.tmpl112
-rw-r--r--template/en/default/filterexceptions.pl3
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 %]&amp;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>&nbsp;
[% 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>&nbsp;
- [% IF g.isactive %]
+ [% IF group_controls.size %]
+ [% FOREACH g = group_controls.values %]
+ <b>[% g.group.name FILTER html %]:</b>&nbsp;
+ [% 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 %]&amp;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&amp;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 %]&amp;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&amp;product=%%name%%
[%- classification_url_part %]
[% END %]
-[% bug_count_contentlink = BLOCK %]buglist.cgi?product=%%name%%&amp;
+[% 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 %]&amp;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&amp;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' => [