| 1293 |
dpurdie |
1 |
###############################################################################
|
|
|
2 |
# Codestriker: Copyright (c) 2001, 2002 David Sitsky. All rights reserved.
|
|
|
3 |
# sits@users.sourceforge.net
|
|
|
4 |
#
|
|
|
5 |
# This program is free software; you can redistribute it and modify it under
|
|
|
6 |
# the terms of the GPL.
|
|
|
7 |
|
|
|
8 |
# Action object for displaying a list of topics.
|
|
|
9 |
|
|
|
10 |
package Codestriker::Action::ListTopics;
|
|
|
11 |
|
|
|
12 |
use strict;
|
|
|
13 |
use Codestriker::Http::Template;
|
|
|
14 |
use Codestriker::Model::Topic;
|
|
|
15 |
|
|
|
16 |
# If the input is valid, list the appropriate topics.
|
|
|
17 |
sub process($$$) {
|
|
|
18 |
my ($type, $http_input, $http_response) = @_;
|
|
|
19 |
|
|
|
20 |
my $query = $http_response->get_query();
|
|
|
21 |
|
|
|
22 |
# Check if this action is allowed.
|
|
|
23 |
if ($Codestriker::allow_searchlist == 0) {
|
|
|
24 |
$http_response->error("This function has been disabled");
|
|
|
25 |
}
|
|
|
26 |
|
|
|
27 |
# Obtain a new URL builder object.
|
|
|
28 |
my $url_builder = Codestriker::Http::UrlBuilder->new($query);
|
|
|
29 |
|
|
|
30 |
my $mode = $http_input->get('mode');
|
|
|
31 |
my $feedback = $http_input->get('feedback');
|
|
|
32 |
my $projectid = $http_input->get('projectid');
|
|
|
33 |
|
|
|
34 |
my ( $sauthor, $sreviewer, $scc, $sbugid,
|
|
|
35 |
$sstate, $sproject, $stext,
|
|
|
36 |
$stitle, $sdescription,
|
|
|
37 |
$scomments, $sbody, $sfilename,
|
|
|
38 |
$sort_order) = get_topic_list_query_params($http_input);
|
|
|
39 |
|
|
|
40 |
# Query the model for the specified data.
|
|
|
41 |
my @topics = Codestriker::Model::Topic->query($sauthor, $sreviewer, $scc, $sbugid,
|
|
|
42 |
$sstate, $sproject, $stext,
|
|
|
43 |
$stitle, $sdescription,
|
|
|
44 |
$scomments, $sbody, $sfilename,
|
|
|
45 |
$sort_order);
|
|
|
46 |
|
|
|
47 |
# Display the data, with each topic title linked to the view topic screen.
|
|
|
48 |
# If only a single project id is being searched over, set that id in the
|
|
|
49 |
# cookie.
|
|
|
50 |
my @project_ids = ();
|
|
|
51 |
if ($sproject ne "") {
|
|
|
52 |
@project_ids = split ',', $sproject;
|
|
|
53 |
}
|
|
|
54 |
my $projectid_cookie = ($#project_ids == 0) ? $project_ids[0] : "";
|
|
|
55 |
|
|
|
56 |
$http_response->generate_header(topic_title=>"Topic List",
|
|
|
57 |
projectid=>$projectid_cookie,
|
|
|
58 |
topicsort=>join(',',@$sort_order),
|
|
|
59 |
reload=>0, cache=>0);
|
|
|
60 |
|
|
|
61 |
# Create the hash for the template variables.
|
|
|
62 |
my $vars = {};
|
|
|
63 |
$vars->{'feedback'} = $feedback;
|
|
|
64 |
|
|
|
65 |
# Store the search parameters, which become hidden fields.
|
|
|
66 |
$vars->{'sauthor'} = $sauthor;
|
|
|
67 |
$vars->{'sreviewer'} = $sreviewer;
|
|
|
68 |
$vars->{'scc'} = $scc;
|
|
|
69 |
$vars->{'sbugid'} = $sbugid;
|
|
|
70 |
$vars->{'stext'} = $stext;
|
|
|
71 |
$vars->{'sstate'} = $sstate;
|
|
|
72 |
$vars->{'stitle'} = $stitle;
|
|
|
73 |
$vars->{'sdescription'} = $sdescription;
|
|
|
74 |
$vars->{'scomments'} = $scomments;
|
|
|
75 |
$vars->{'sbody'} = $sbody;
|
|
|
76 |
$vars->{'sfilename'} = $sfilename;
|
|
|
77 |
|
|
|
78 |
# Collect the comment metric counts that they want to show on the main page.
|
|
|
79 |
my @comment_metric_names;
|
|
|
80 |
foreach my $comment_state_metric (@{$Codestriker::comment_state_metrics}) {
|
|
|
81 |
if (exists($comment_state_metric->{show_on_mainpage})) {
|
|
|
82 |
foreach my $value (@{$comment_state_metric->{show_on_mainpage}}) {
|
|
|
83 |
push @comment_metric_names,
|
|
|
84 |
{ name => $comment_state_metric->{name},
|
|
|
85 |
value => $value };
|
|
|
86 |
}
|
|
|
87 |
}
|
|
|
88 |
}
|
|
|
89 |
|
|
|
90 |
$vars->{'commentmetrics'} = \@comment_metric_names;
|
|
|
91 |
|
|
|
92 |
# The url generated here includes all of the search parameters, so
|
|
|
93 |
# that the current list of topics the user it viewing does not
|
|
|
94 |
# revert back to the default open topic list. The search is
|
|
|
95 |
# applied each time they change the sort order.
|
|
|
96 |
$vars->{'list_sort_url'} =
|
|
|
97 |
$url_builder->list_topics_url($sauthor, $sreviewer, $scc, $sbugid,
|
|
|
98 |
$stext, $stitle,
|
|
|
99 |
$sdescription, $scomments,
|
|
|
100 |
$sbody, $sfilename,
|
|
|
101 |
[ split ',', $sstate] , \@project_ids);
|
|
|
102 |
|
|
|
103 |
$vars->{'list_sort_url_rss'} =
|
|
|
104 |
$url_builder->list_topics_url_rss($sauthor, $sreviewer, $scc, $sbugid,
|
|
|
105 |
$stext, $stitle,
|
|
|
106 |
$sdescription, $scomments,
|
|
|
107 |
$sbody, $sfilename,
|
|
|
108 |
[ split ',', $sstate] , \@project_ids);
|
|
|
109 |
|
|
|
110 |
# The list of topics in the template toolkit.
|
|
|
111 |
my @template_topics;
|
|
|
112 |
|
|
|
113 |
# For each topic, collect all the reviewers, CC, and bugs, and display it
|
|
|
114 |
# as a row in the table. Each bug should be linked appropriately.
|
|
|
115 |
foreach my $topic (@topics) {
|
|
|
116 |
|
|
|
117 |
# do the easy stuff first, 1 to 1 mapping into the template.
|
|
|
118 |
|
|
|
119 |
my $template_topic = {};
|
|
|
120 |
|
|
|
121 |
$template_topic->{'view_topic_url'} =
|
|
|
122 |
$url_builder->view_url($topic->{topicid}, -1, $mode,
|
|
|
123 |
$Codestriker::default_topic_br_mode);
|
|
|
124 |
|
|
|
125 |
$template_topic->{'description'} = $topic->{description};
|
|
|
126 |
|
|
|
127 |
$template_topic->{'created'} =
|
|
|
128 |
Codestriker->format_short_timestamp($topic->{creation_ts});
|
|
|
129 |
|
|
|
130 |
$template_topic->{'id'} = $topic->{topicid};
|
|
|
131 |
$template_topic->{'title'} = $topic->{title};
|
|
|
132 |
|
|
|
133 |
$template_topic->{'version'} = $topic->{version};
|
|
|
134 |
|
|
|
135 |
$template_topic->{'state'} = $Codestriker::topic_states[$topic->{topic_state_id}];
|
|
|
136 |
|
|
|
137 |
# Only include the username part of the email address to save space.
|
|
|
138 |
my $accum_author = $topic->{author};
|
|
|
139 |
$accum_author =~ s/\@.*$//o;
|
|
|
140 |
$template_topic->{'author'} = $accum_author;
|
|
|
141 |
|
|
|
142 |
# cc
|
|
|
143 |
my $cc = $topic->{cc};
|
|
|
144 |
$cc =~ s/\@.*$//o;
|
|
|
145 |
$template_topic->{'cc'} = $cc;
|
|
|
146 |
|
|
|
147 |
# bug ids
|
|
|
148 |
my @accum_bugs = split /, /, $topic->{bug_ids};
|
|
|
149 |
for ( my $index = 0; $index < scalar(@accum_bugs); ++$index) {
|
|
|
150 |
$accum_bugs[$index] =
|
|
|
151 |
$query->a({href=>"$Codestriker::bugtracker$accum_bugs[$index]"},
|
|
|
152 |
$accum_bugs[$index]);
|
|
|
153 |
}
|
|
|
154 |
$template_topic->{'bugids'} = join ', ', @accum_bugs;
|
|
|
155 |
|
|
|
156 |
# do the reviewers
|
|
|
157 |
my @reviewers_vistited =
|
|
|
158 |
$topic->get_metrics()->get_list_of_actual_topic_participants();
|
|
|
159 |
|
|
|
160 |
my @reviewers = split /, /, $topic->{reviewers};
|
|
|
161 |
for ( my $index = 0; $index < scalar(@reviewers); ++$index) {
|
|
|
162 |
|
|
|
163 |
my $reviewer = $reviewers[$index];
|
|
|
164 |
|
|
|
165 |
my $is_visted = 0;
|
|
|
166 |
foreach my $visted (@reviewers_vistited) {
|
|
|
167 |
if ($visted eq $reviewer) {
|
|
|
168 |
$is_visted = 1;
|
|
|
169 |
last;
|
|
|
170 |
}
|
|
|
171 |
}
|
|
|
172 |
|
|
|
173 |
# Output the accumulated information into the row. Only
|
|
|
174 |
# include the username part of an email address for now to
|
|
|
175 |
# save some space. This should be made a dynamic option
|
|
|
176 |
# in the future.
|
|
|
177 |
$reviewer =~ s/\@.*$//o;
|
|
|
178 |
|
|
|
179 |
if ( $is_visted == 0) {
|
|
|
180 |
$reviewer = "(" . $reviewer . ")";
|
|
|
181 |
}
|
|
|
182 |
|
|
|
183 |
$reviewers[$index] = $reviewer;
|
|
|
184 |
}
|
|
|
185 |
|
|
|
186 |
$template_topic->{'reviewer'} = join(", ",@reviewers);
|
|
|
187 |
|
|
|
188 |
my @main_page_comment_metrics = ();
|
|
|
189 |
foreach my $comment_state_metric (@{$Codestriker::comment_state_metrics}) {
|
|
|
190 |
|
|
|
191 |
if ( exists($comment_state_metric->{show_on_mainpage})) {
|
|
|
192 |
foreach my $value (@{$comment_state_metric->{show_on_mainpage}}) {
|
|
|
193 |
|
|
|
194 |
my $count = $topic->get_comment_metric_count($comment_state_metric->{name},$value);
|
|
|
195 |
|
|
|
196 |
my $template_comment_metric =
|
|
|
197 |
{
|
|
|
198 |
name => $comment_state_metric->{name},
|
|
|
199 |
value => $value,
|
|
|
200 |
count => $count
|
|
|
201 |
};
|
|
|
202 |
|
|
|
203 |
push @main_page_comment_metrics,$template_comment_metric;
|
|
|
204 |
}
|
|
|
205 |
}
|
|
|
206 |
}
|
|
|
207 |
|
|
|
208 |
$template_topic->{'commentmetrics'} = \@main_page_comment_metrics;
|
|
|
209 |
|
|
|
210 |
push @template_topics, $template_topic;
|
|
|
211 |
}
|
|
|
212 |
|
|
|
213 |
$vars->{'topics'} = \@template_topics;
|
|
|
214 |
$vars->{'states'} = \@Codestriker::topic_states;
|
|
|
215 |
|
|
|
216 |
$vars->{'list_projects_url'} = $url_builder->list_projects_url();
|
|
|
217 |
$vars->{'view_metrics_url'} = $url_builder->metric_report_url();
|
|
|
218 |
|
|
|
219 |
my $template = Codestriker::Http::Template->new("listtopics");
|
|
|
220 |
$template->process($vars);
|
|
|
221 |
|
|
|
222 |
$http_response->generate_footer();
|
|
|
223 |
}
|
|
|
224 |
|
|
|
225 |
# Process the input and return the parts that will feed into the topic
|
|
|
226 |
# list query. Returns in the same order that the topic query function
|
|
|
227 |
# takes them.
|
|
|
228 |
sub get_topic_list_query_params {
|
|
|
229 |
my ($http_input) = @_;
|
|
|
230 |
|
|
|
231 |
# Check that the appropriate fields have been filled in.
|
|
|
232 |
my $sauthor = $http_input->get('sauthor') || "";
|
|
|
233 |
my $sreviewer = $http_input->get('sreviewer') || "";
|
|
|
234 |
my $scc = $http_input->get('scc') || "";
|
|
|
235 |
my $sbugid = $http_input->get('sbugid') || "";
|
|
|
236 |
my $stext = $http_input->get('stext') || "";
|
|
|
237 |
my $sstate = $http_input->get('sstate');
|
|
|
238 |
my $sproject = $http_input->get('sproject');
|
|
|
239 |
my $stitle = $http_input->get('stitle') || 0;
|
|
|
240 |
my $sdescription = $http_input->get('sdescription') || 0;
|
|
|
241 |
my $scomments = $http_input->get('scomments') || 0;
|
|
|
242 |
my $sbody = $http_input->get('sbody') || 0;
|
|
|
243 |
my $sfilename = $http_input->get('sfilename') || 0;
|
|
|
244 |
my $projectid = $http_input->get('projectid');
|
|
|
245 |
|
|
|
246 |
# If $sproject has been set to -1, then retrieve the value of the projectid
|
|
|
247 |
# from the cookie as the project search value. This is done to facilate
|
|
|
248 |
# integration with other systems, which jump straight to this URL, and
|
|
|
249 |
# set the cookie explicitly.
|
|
|
250 |
if ($sproject eq "-1") {
|
|
|
251 |
$sproject = (defined $projectid) ? $projectid : "";
|
|
|
252 |
}
|
|
|
253 |
|
|
|
254 |
# Only show open topics if codestriker.pl was run without parameters.
|
|
|
255 |
if (defined($http_input->{query}->param) == 0 || !defined($sstate)) {
|
|
|
256 |
$sstate = join(',', @Codestriker::default_states_indexes);
|
|
|
257 |
}
|
|
|
258 |
|
|
|
259 |
# handle the sort order of the topics.
|
|
|
260 |
my @sort_order = get_topic_sort_order($http_input);
|
|
|
261 |
|
|
|
262 |
return ( $sauthor, $sreviewer, $scc, $sbugid,
|
|
|
263 |
$sstate, $sproject, $stext,
|
|
|
264 |
$stitle, $sdescription,
|
|
|
265 |
$scomments, $sbody, $sfilename,
|
|
|
266 |
\@sort_order);
|
|
|
267 |
}
|
|
|
268 |
|
|
|
269 |
# Process the topic_sort_change input request (if any), and the current sort
|
|
|
270 |
# cookie (topicsort), and returns a list that defines the topic sort order
|
|
|
271 |
# that should be used for this request. The function will ensure that
|
|
|
272 |
# column types are not repeated, and will sort in the opposite direction
|
|
|
273 |
# if the user clicks on the same column twice.
|
|
|
274 |
sub get_topic_sort_order {
|
|
|
275 |
my ($http_input) = @_;
|
|
|
276 |
|
|
|
277 |
my $topic_sort_change = $http_input->get('topic_sort_change');
|
|
|
278 |
my $topicsort = $http_input->get('topicsort');
|
|
|
279 |
|
|
|
280 |
my @sort_order = split(/,/,$topicsort); # this is always from the cookie.
|
|
|
281 |
|
|
|
282 |
if ($topic_sort_change ne "") {
|
|
|
283 |
if (scalar(@sort_order) > 0) {
|
|
|
284 |
|
|
|
285 |
# If the user clicked on the same column twice in a row, reverse
|
|
|
286 |
# the direction of the sort.
|
|
|
287 |
|
|
|
288 |
$sort_order[0] =~ s/\+$topic_sort_change/\-$topic_sort_change/ or
|
|
|
289 |
$sort_order[0] =~ s/\-$topic_sort_change/\+$topic_sort_change/ or
|
|
|
290 |
unshift @sort_order, "+" . $topic_sort_change;
|
|
|
291 |
}
|
|
|
292 |
else {
|
|
|
293 |
unshift @sort_order, "+" . $topic_sort_change;
|
|
|
294 |
}
|
|
|
295 |
|
|
|
296 |
# look for duplicate sort keys, and remove
|
|
|
297 |
my %sort_hash;
|
|
|
298 |
|
|
|
299 |
for ( my $index = 0;
|
|
|
300 |
$index < scalar( @sort_order);
|
|
|
301 |
# Incremented in the if...
|
|
|
302 |
) {
|
|
|
303 |
|
|
|
304 |
# chew off the leading +-
|
|
|
305 |
my $current = $sort_order[$index];
|
|
|
306 |
|
|
|
307 |
if ($current =~ s/^[\+\-]//) {
|
|
|
308 |
if (exists $sort_hash{$current}) {
|
|
|
309 |
# remove from the list.
|
|
|
310 |
splice @sort_order, $index,1;
|
|
|
311 |
}
|
|
|
312 |
else {
|
|
|
313 |
# have not seem this before, keep it, and look at the next
|
|
|
314 |
# string.
|
|
|
315 |
++$index;
|
|
|
316 |
}
|
|
|
317 |
|
|
|
318 |
$sort_hash{$current} = 1;
|
|
|
319 |
}
|
|
|
320 |
}
|
|
|
321 |
}
|
|
|
322 |
|
|
|
323 |
# Pull out any elements that are not valid (from a bad cookie or from a bad
|
|
|
324 |
# input.
|
|
|
325 |
|
|
|
326 |
for (my $index = 0; $index < scalar(@sort_order) ; ++$index) {
|
|
|
327 |
|
|
|
328 |
if ($sort_order[$index] ne "+title" && $sort_order[$index] ne "-title" &&
|
|
|
329 |
$sort_order[$index] ne "+author" && $sort_order[$index] ne "-author" &&
|
|
|
330 |
$sort_order[$index] ne "+created" && $sort_order[$index] ne "-created" &&
|
|
|
331 |
$sort_order[$index] ne "+state" && $sort_order[$index] ne "-state") {
|
|
|
332 |
|
|
|
333 |
splice @sort_order,$index,1;
|
|
|
334 |
--$index;
|
|
|
335 |
}
|
|
|
336 |
}
|
|
|
337 |
|
|
|
338 |
return @sort_order;
|
|
|
339 |
}
|
|
|
340 |
|
|
|
341 |
1;
|