Commit fde6d4aa authored by Max Kanat-Alexander's avatar Max Kanat-Alexander

Bug 514970: Clean up duplicates.cgi and make it use Bug objects

r=LpSolit, a=LpSolit
parent cf2e1cc0
......@@ -134,7 +134,8 @@ sub check {
# We don't want to override the normal template "user" object if
# "user" is one of the params.
delete $param->{user};
ThrowUserError('object_does_not_exist', { %$param, class => $class });
my $error = delete $param->{_error} || 'object_does_not_exist';
ThrowUserError($error, { %$param, class => $class });
}
return $obj;
}
......
......@@ -913,6 +913,17 @@ sub check_product {
return $product;
}
sub check {
my ($class, $params) = @_;
$params = { name => $params } if !ref $params;
$params->{_error} = 'product_access_denied';
my $product = $class->SUPER::check($params);
if (!Bugzilla->user->can_access_product($product)) {
ThrowUserError('product_access_denied', $params);
}
return $product;
}
1;
__END__
......
......@@ -810,8 +810,8 @@ sub get_enterable_products {
}
sub can_access_product {
my ($self, $product_name) = @_;
my ($self, $product) = @_;
my $product_name = blessed($product) ? $product->name : $product;
return scalar(grep {$_->name eq $product_name} @{$self->get_accessible_products});
}
......@@ -2055,10 +2055,11 @@ the database again. Used mostly by L<Bugzilla::Product>.
Returns: an array of product objects.
=item C<can_access_product(product_name)>
=item C<can_access_product($product)>
Returns 1 if the user can search or enter bugs into the specified product,
and 0 if the user should not be aware of the existence of the product.
Returns 1 if the user can search or enter bugs into the specified product
(either a L<Bugzilla::Product> or a product name), and 0 if the user should
not be aware of the existence of the product.
=item C<get_accessible_products>
......
......@@ -434,7 +434,7 @@ sub legal_values {
defined $id || ThrowCodeError('param_required',
{ function => 'Bug.legal_values', param => 'product_id' });
grep($_->id eq $id, @{Bugzilla->user->get_accessible_products})
|| ThrowUserError('product_access_denied', { product => $id });
|| ThrowUserError('product_access_denied', { id => $id });
my $product = new Bugzilla::Product($id);
my @objects;
......
......@@ -10,25 +10,40 @@
*
* The Original Code is the Bugzilla Bug Tracking System.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
* The Initial Developer of the Original Code is Everything Solved, Inc.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Myk Melez <myk@mozilla.org>
* Contributor(s):
* Max Kanat-Alexander <mkanat@bugzilla.org>
*/
tree#results-tree {
margin-right: 0px;
border-right-width: 0px;
margin-left: 0px;
border-left-width: 0px;
#duplicates_table {
border-collapse: collapse;
}
treechildren:-moz-tree-cell-text(resolution-FIXED) {
text-decoration: line-through;
#duplicates_table .resolved {
background-color: #d9d9d9;
color: black;
}
treecol#id_column { width: 6em; }
treecol#duplicate_count_column { width: 5em; }
treecol#duplicate_delta_column { width: 5em; }
#duplicates_table thead tr {
background-color: #ccc;
color: black;
}
#duplicates_table thead tr th {
vertical-align: middle;
}
#duplicates_table td, #duplicates_table th {
border: 1px solid black;
padding: .1em .25em;
}
#duplicates_table tbody td {
text-align: center;
}
#duplicates_table tbody td.short_desc {
text-align: left;
}
......@@ -92,20 +92,6 @@
'request.attach_id',
],
'reports/duplicates-table.html.tmpl' => [
'column.name',
'column.description',
'bug.count',
'bug.delta',
],
'reports/duplicates.html.tmpl' => [
'bug_ids_string',
'maxrows',
'changedsince',
'reverse',
],
'reports/keywords.html.tmpl' => [
'keyword.bug_count',
],
......
......@@ -1301,8 +1301,13 @@
Try splitting your patch into several pieces.
[% ELSIF error == "product_access_denied" %]
Either the product '[% product FILTER html %]' does not exist or
you don't have access to it.
Either the product
[%+ IF id.defined %]
with the id [% id FILTER html %]
[% ELSE %]
'[% name FILTER html %]'
[% END %]
does not exist or you don't have access to it.
[% ELSIF error == "product_doesnt_exist" %]
[% title = "Specified Product Does Not Exist" %]
......
......@@ -15,7 +15,9 @@
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
# Contributor(s):
# Gervase Markham <gerv@gerv.net>
# Max Kanat-Alexander <mkanat@bugzilla.org>
#%]
[%# INTERFACE:
......@@ -24,8 +26,9 @@
[% PROCESS global/variables.none.tmpl %]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
[% IF product %]
[% title = "Most Frequently Reported $terms.Bugs for $product" %]
[% ELSE %]
......@@ -39,5 +42,4 @@
<body>
[% PROCESS "reports/duplicates-table.html.tmpl" %]
</body>
</html>
......@@ -15,21 +15,16 @@
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
# Contributor(s):
# Gervase Markham <gerv@gerv.net>
# Max Kanat-Alexander <mkanat@bugzilla.org>
#%]
[%# INTERFACE:
# bugs: list of hashes. May be empty. Each hash has nine members:
# id: integer. The bug number
# bugs: list of hashes. May be empty. Each hash has three members:
# bug: A Bugzilla::Bug object
# count: integer. The number of dupes
# delta: integer. The change in count in the last $changedsince days
# component: string. The bug's component
# bug_severity: string. The bug's severity.
# op_sys: string. The bug's reported OS.
# target_milestone: string. The bug's TM.
# short_desc: string. The bug's summary.
# bug_status: string. The bug's status.
# resolution: string. The bug's resolution, if any.
#
# bug_ids: list of integers. May be empty. The IDs of the bugs in $bugs.
#
......@@ -38,99 +33,89 @@
# maxrows: integer. Max number of rows to display.
# changedsince: integer. The number of days ago for the changedsince column.
# openonly: boolean. True if we are only showing open bugs.
# query_products: list of strings. Restrict to these products only.
# product: array of strings. Restrict to these products only.
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS "global/field-descs.none.tmpl" %]
[%# *** Column Headers *** %]
[% IF bug_ids.size > 0 %]
<table border>
<thead>
<tr bgcolor="#CCCCCC">
[% FOREACH column = [ { name => "id", description => "$terms.Bug #" },
{ name => "count", description => "Dupe<br>Count" },
{ name => "delta",
description => "Change in last<br>$changedsince day(s)" },
{ name => "component", description => "Component" },
{ name => "bug_severity", description => "Severity" },
{ name => "op_sys", description => "Op Sys" },
{ name => "target_milestone",
description => "Target<br>Milestone" },
{ name => "short_desc", description => "Summary" } ]
%]
[% SET columns = [
{ name => "id", description => "$terms.Bug #" },
{ name => "count", description => "Dupe<br>Count" },
{ name => "delta",
description => "Change in last<br>$changedsince day(s)" },
{ name => "component", description => field_descs.component },
{ name => "bug_severity", description => field_descs.bug_severity },
{ name => "op_sys", description => field_descs.op_sys },
{ name => "target_milestone", description => field_descs.target_milestone },
{ name => "short_desc", description => field_descs.short_desc },
] %]
<th>
[% bug_ids_string = bug_ids.join(',') %]
<a href="duplicates.cgi?sortby=[% column.name %]
[% IF sortby == column.name %]
[% "&amp;reverse=1" IF NOT reverse %]
[% ELSE %]
[%-# Some columns start off reversed %]
[% "&amp;reverse=1" IF column.name.match('delta|count') %]
[% END %]
[% IF maxrows %]&amp;maxrows=[% maxrows FILTER html %][% END %]
[% IF changedsince %]&amp;changedsince=[% changedsince FILTER html %][% END %]
[% "&amp;openonly=1" IF openonly %]
[% FOREACH p = query_products %]&amp;product=[% p FILTER html %][% END %]
[% IF format %]&amp;format=[% format FILTER html %][% END %]
[% IF sortvisible %]&amp;bug_id=[% bug_ids_string FILTER html %]&amp;sortvisible=1[% END %]">
[% column.description %]</a>
[% SET base_args = [] %]
[% FOREACH param = ['maxrows', 'openonly', 'format', 'sortvisible',
'changedsince', 'product']
%]
[% NEXT IF NOT ${param}.defined %]
[% FOREACH value = ${param} %]
[% filtered_value = value FILTER url_quote %]
[% base_args.push("$param=$filtered_value") %]
[% END %]
[% END %]
[% IF sortvisible %]
[% bug_ids_string = bug_ids.nsort.join(',') FILTER url_quote %]
[% base_args.push("bug_id=$bug_ids_string") %]
[% END %]
[% base_args_string = base_args.join('&amp;') %]
[% IF bugs.size %]
<table id="duplicates_table" cellpadding="0" cellspacing="0">
<thead>
<tr>
[% FOREACH column = columns %]
[% IF column.name == sortby %]
[%# We add this to the column object so it doesn't affect future
# iterations of the loop.
#%]
[% column.reverse_sort = reverse ? 0 : 1 %]
[% END %]
<th class="[% column.name FILTER html %]">
<a href="duplicates.cgi?sortby=[% column.name FILTER url_quote %]
[% IF column.reverse_sort.defined %]
[%- %]&amp;reverse=[% column.reverse_sort FILTER url_quote %]
[% END %]
[% IF base_args_string %]
[% "&amp;$base_args_string" FILTER none %]
[% END %]"
>[% column.description FILTER none %]</a>
</th>
[% END %]
</tr>
</thead>
[% IF NOT sortby %]
[% sortby = "count"; reverse = "1" %]
[% END %]
[% IF sortby == "id" OR sortby == "count" OR sortby == "delta" %]
[%# Numeric sort %]
[% sortedbugs = bugs.nsort(sortby) %]
[% ELSE %]
[% sortedbugs = bugs.sort(sortby) %]
[% END %]
[% IF reverse %]
[% bugs = sortedbugs.reverse %]
[% ELSE %]
[% bugs = sortedbugs %]
[% END %]
[%# *** Buglist *** %]
<tbody>
[%# We need to keep track of the bug IDs we are actually displaying, because
# if the user decides to sort the visible list, we need to know what that
# list actually is. %]
[% vis_bug_ids = [] %]
[% FOREACH bug = bugs %]
[% LAST IF loop.index() >= maxrows %]
[% vis_bug_ids.push(bug.id) %]
<tr [% "class='resolved'" IF bug.resolution != "" %]>
<td>
<center>
[% bug.id FILTER bug_link(bug.id) FILTER none %]
</center>
<tbody>
[% FOREACH item = bugs %]
[% SET bug = item.bug %]
<tr [% " class='resolved'" IF NOT bug.isopened %]>
<td class="id">
[% bug.id FILTER bug_link(bug) FILTER none %]
</td>
<td>
<center>
[% bug.count %]
</center>
<td class="count">[% item.count FILTER html %]</td>
<td class="delta">[% item.delta FILTER html %]</td>
<td class="component">[% bug.component FILTER html %]</td>
<td class="bug_severity">
[%- display_value('bug_severity', bug.bug_severity) FILTER html %]
</td>
<td><center>[% bug.delta %]</center></td>
<td>[% bug.component FILTER html %]</td>
<td><center>[% display_value("bug_severity", bug.bug_severity ) FILTER html %]</center></td>
<td><center>[% display_value("op_sys", bug.op_sys ) FILTER html %]</center></td>
<td><center>[% display_value("target_milestone", bug.target_milestone) FILTER html %]</center></td>
<td>[% bug.short_desc FILTER html %]</td>
<td class="op_sys">
[%- display_value('op_sys', bug.op_sys) FILTER html %]
</td>
<td class="target_milestone">
[% display_value('target_milestone',
bug.target_milestone) FILTER html %]
</td>
<td class="short_desc">[% bug.short_desc FILTER html %]</td>
</tr>
[% END %]
</tbody>
......
......@@ -19,14 +19,12 @@
#%]
[%# INTERFACE:
# products: an array of product objects this user can see.
#
# sortby: string. the column on which we are sorting the buglist.
# reverse: boolean. True if we are reversing the current sort.
# maxrows: integer. Max number of rows to display.
# changedsince: integer. The number of days ago for the changedsince column.
# openonly: boolean. True if we are only showing open bugs.
# query_products: list of strings. The set of products we check for dups.
# product: array of strings. The set of products we check for dups.
#
# Additionally, you need to fulfill the interface to
# duplicates-table.html.tmpl.
......@@ -34,9 +32,10 @@
[% PROCESS global/variables.none.tmpl %]
[% IF query_products.size %]
[% IF product.size %]
[% title = BLOCK %]
Most Frequently Reported [% terms.Bugs %] for [% query_products.join(', ') FILTER html %]
Most Frequently Reported [% terms.Bugs %] for
[%+ product.join(', ') FILTER html %]
[% END %]
[% ELSE %]
[% title = "Most Frequently Reported $terms.Bugs" %]
......@@ -44,7 +43,7 @@
[% PROCESS global/header.html.tmpl
title = title
style = ".resolved { background-color: #d9d9d9; color: #000000; }"
style_urls = ['skins/standard/duplicates.css']
%]
<p>
......@@ -57,27 +56,26 @@
[%# *** Parameters *** %]
[% bug_ids_string = vis_bug_ids.join(',') %]
[% bug_ids_string = bug_ids.join(',') %]
<h3><a name="params">Change Parameters</a></h3>
<form method="get" action="duplicates.cgi">
<input type="hidden" name="sortby" value="[% sortby FILTER html %]">
<input type="hidden" name="reverse" value="[% reverse %]">
<input type="hidden" name="bug_id" value="[% bug_ids_string %]">
<input type="hidden" name="reverse" value="[% reverse FILTER html %]">
<input type="hidden" name="bug_id" value="[% bug_ids_string FILTER html %]">
<table>
<tr>
<td>When sorting or restricting,
work with:</td>
<td>When sorting or restricting, work with:</td>
<td>
<input type="radio" name="sortvisible" id="entirelist" value="0"
[%+ "checked" IF NOT sortvisible %]>
[% ' checked="checked"' IF NOT sortvisible %]>
<label for="entirelist">
entire list
</label>
<br>
<input type="radio" name="sortvisible" id="visiblelist" value="1"
[%+ "checked" IF sortvisible %]>
[% ' checked="checked"' IF sortvisible %]>
<label for="visiblelist">
currently visible list
</label>
......@@ -85,9 +83,9 @@
<td rowspan="4" valign="top">Restrict to products:</td>
<td rowspan="4" valign="top">
<select name="product" size="5" multiple="multiple">
[% FOREACH p = products %]
[% FOREACH p = user.get_selectable_products %]
<option name="[% p.name FILTER html %]"
[% " selected" IF lsearch(query_products, p.name) != -1 %]
[% ' selected="selected"' IF product.contains(p.name) %]
>[% p.name FILTER html %]</option>
[% END %]
</select>
......@@ -95,16 +93,20 @@
</tr>
<tr>
<td>Max rows:</td>
<td><label for="maxrows">Max rows:</label></td>
<td>
<input size="4" name="maxrows" value="[% maxrows %]">
<input size="4" name="maxrows" id="maxrows"
value="[% maxrows FILTER html %]">
</td>
</tr>
<tr>
<td>Change column is change in the last:</td>
<td>
<input size="4" name="changedsince" value="[% changedsince %]"> days
<label for="changedsince">Change column is change in the last:</label>
</td>
<td>
<input size="4" name="changedsince" id="changedsince"
value="[% changedsince FILTER html %]"> days
</td>
</tr>
......@@ -116,7 +118,7 @@
</td>
<td>
<input type="checkbox" name="openonly" id="openonly" value="1"
[%+ "checked" IF openonly %]>
[% ' checked="checked"' IF openonly %]>
</td>
</tr>
......@@ -126,10 +128,9 @@
</form>
<form method="post" action="buglist.cgi">
<input type="hidden" name="bug_id" value="[% bug_ids_string %]">
<input type="hidden" name="order" value="Reuse same sort as last time">
<input type="hidden" name="bug_id" value="[% bug_ids_string FILTER html %]">
Or just give this to me as a <input type="submit" id="list"
value="[% terms.bug %] list">.
value="[% terms.bug %] list">.
(Note: the order may not be the same.)
</form>
......@@ -139,15 +140,15 @@
<a name="explanation">What are "Most Frequently Reported [% terms.Bugs %]"?</a>
</b>
<blockquote>
The Most Frequent [% terms.Bugs %] page lists the known open [% terms.bugs %] which
are reported most frequently. It is
automatically generated from the [% terms.Bugzilla %] database every 24 hours, by
<p>
The Most Frequent [% terms.Bugs %] page lists the known open
[%+ terms.bugs %] which are reported most frequently,
counting the number of direct and indirect duplicates of [% terms.bugs %].
This information is provided in order to assist in minimizing
the amount of duplicate [% terms.bugs %] entered into [% terms.Bugzilla %], which
saves time for Quality Assurance engineers who have to triage the [% terms.bugs %].
</blockquote>
the amount of duplicate [% terms.bugs %] entered into [% terms.Bugzilla %],
which saves time for Quality Assurance engineers who have to triage
the [% terms.bugs %].
</p>
<b>How do I use this list?</b>
......@@ -166,11 +167,12 @@
<ul>
<li><a href="query.cgi">Try and locate a similar [% terms.bug %]</a>
that has already been filed.</li>
that has already been filed.</li>
<li>If you find your [% terms.bug %] in [% terms.Bugzilla %],
feel free to comment with any new or additional data you may have.</li>
<li>If you cannot find your problem already documented in [% terms.Bugzilla %],
<a href="enter_bug.cgi">file a new [% terms.bug %]</a>.</li>
feel free to comment with any new or additional data you may have.</li>
<li>If you cannot find your problem already documented in
[%+ terms.Bugzilla %],
<a href="enter_bug.cgi">file a new [% terms.bug %]</a>.</li>
</ul>
</ul>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment