6 # Hack to work on merkel where suexec is in place
8 if ($ENV{HTTP_HOST} eq 'merkel.debian.org') {
9 unshift @INC, qw(/home/don/perl/usr/share/perl5 /home/don/perl/usr/lib/perl5 /home/don/source);
10 $ENV{DEBBUGS_CONFIG_FILE}="/home/don/config_internal";
17 # use CGI::Alert 'nobody@example.com';
20 use Debbugs::Config qw(:config);
21 use Debbugs::Estraier;
22 use Debbugs::CGI qw(htmlize_packagelinks html_escape cgi_parameters);
23 use HTML::Entities qw(encode_entities);
25 my $q = new CGI::Simple;
27 #my %var_defaults = (attr => 1,);
29 my %cgi_var = cgi_parameters(query => $q,
30 single => [qw(phrase max_results order_field order_operator),
33 default => {phrase => '',
39 $cgi_var{attribute} = parse_attribute(\%cgi_var) || [];
43 if (defined $cgi_var{next}) {
45 $cgi_var{skip} += $cgi_var{max_results};
47 elsif (defined $cgi_var{prev}) {
49 $cgi_var{skip} -= $cgi_var{max_results};
50 $cgi_var{skip} = 0 if $cgi_var{skip} < 0;
54 if (defined $cgi_var{search} and length $cgi_var{phrase}) {
55 # connect to a node if we need to
56 my $node = new Search::Estraier::Node (url => $config{search_estraier}{url},
57 user => $config{search_estraier}{user},
58 passwd => $config{search_estraier}{pass},
60 ) or die "Unable to connect to the node";
61 my $cond = new Search::Estraier::Condition;
62 $cond->set_phrase($cgi_var{phrase});
63 if (defined $cgi_var{order_field} and length $cgi_var{order_field} and
64 defined $cgi_var{order_operator} and length $cgi_var{order_operator}) {
65 $cond->set_order($cgi_var{order_field}.' '.$cgi_var{order_operator});
67 foreach my $attribute (@{$cgi_var{attribute}}) {
68 if (defined $$attribute{field} and defined $$attribute{value} and
69 defined $$attribute{operator} and length $$attribute{value}) {
70 $cond->add_attr(join(' ',map {$$attribute{$_}} qw(field operator value)));
73 $cond->set_skip($cgi_var{skip}) if defined $cgi_var{skip} and $cgi_var{skip} =~ /(\d+)/;
74 $cond->set_max($cgi_var{max_results}) if defined $cgi_var{max_results} and $cgi_var{max_results} =~ /^\d+$/;
75 print STDERR "skip: ".$cond->skip()."\n";
76 print STDERR $node->cond_to_query($cond),qq(\n);
77 $nres = $node->search($cond,0) or
78 die "Unable to search for condition";
81 elsif (defined $cgi_var{add_attribute} and length $cgi_var{add_attribute}) {
82 push @{$cgi_var{attribute}}, {value => ''};
84 elsif (grep /^delete_attribute_\d+$/, keys %cgi_var) {
85 foreach my $delete_key (sort {$b <=> $a} map {/^delete_attribute_(\d+)$/?($1):()} keys %cgi_var) {
86 splice @{$cgi_var{attribute}},$delete_key,1;
90 my $url = 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=';
93 Content-Type: text/html
96 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
97 <HTML><HEAD><TITLE>BTS Search</TITLE>
98 <link rel="stylesheet" href="http://bugs.debian.org/css/bugs.css" type="text/css">
102 <table class="forms">
104 <p>Phrase: <input type="text" name="phrase" value="$cgi_var{phrase}" size="80" id="phrase" title="Input some words for full-text search" tabindex="1" accesskey="a" />
105 <input type="submit" name="search" value="search" title="Perform the search" tabindex="8" accesskey="f" />
106 <input type="hidden" name="skip" value="$cgi_var{skip}"></p>
111 # NUMEQ : is equal to the number or date
112 # NUMNE : is not equal to the number or date
113 # NUMGT : is greater than the number or date
114 # NUMGE : is greater than or equal to the number or date
115 # NUMLT : is less than the number or date
116 # NUMLE : is less than or equal to the number or date
117 # NUMBT : is between the two numbers or dates
118 my @num_operators = (NUMEQ => 'equal to',
119 NUMNE => 'not equal to',
120 NUMGT => 'greater than',
121 NUMGE => 'greater than or equal to',
122 NUMLT => 'less than',
123 NUMLE => 'less than or equal to',
127 # STREQ : is equal to the string
128 # STRNE : is not equal to the string
129 # STRINC : includes the string
130 # STRBW : begins with the string
131 # STREW : ends with the string
132 # STRAND : includes all tokens in the string
133 # STROR : includes at least one token in the string
134 # STROREQ : is equal to at least one token in the string
135 # STRRX : matches regular expressions of the string
136 my @str_operators = (STREQ => 'equal to',
137 STRNE => 'not equal to',
138 STRINC => 'includes',
139 STRBW => 'begins with',
140 STREW => 'ends with',
141 STRAND => 'includes all tokens',
142 STROR => 'includes at least one token',
143 STROREQ => 'is equal to at least one token',
144 STRRX => 'matches regular expression',
147 my @attributes_order = ('@cdate','@title','@author',
148 qw(status subject date submitter package tags severity),
150 my %attributes = ('@cdate' => {name => 'Date',
153 '@title' => {name => 'Message subject',
156 '@author' => {name => 'Author',
159 status => {name => 'Status',
162 subject => {name => 'Bug Title',
165 date => {name => 'Submission date',
168 submitter => {name => 'Bug Submitter',
171 package => {name => 'Package',
174 tags => {name => 'Tags',
177 severity => {name => 'Severity',
182 print qq(<p>Attributes:</p>\n);
183 for my $attribute (@{$cgi_var{attribute}}) {
184 print qq(<select name="attribute_field">\n);
185 foreach my $attr (keys %attributes) {
186 my $selected = (defined $$attribute{field} and $$attribute{field} eq $attr) ? ' selected' : '';
187 print qq(<option value="$attr"$selected>$attributes{$attr}{name}</option>\n);
189 print qq(</select>\n);
190 print qq(<select name="attribute_operator">\n);
193 my @tmp_array = (@num_operators,@str_operators);
194 while (($operator,$name) = splice(@tmp_array,0,2)) {
195 my $type = $operator =~ /^NUM/ ? 'Number' : 'String';
196 my $selected = (defined $$attribute{operator} and $$attribute{operator} eq $operator) ? 'selected' : '';
197 print qq(<option value="$operator"$selected>$name ($type)</option>\n);
199 print qq(</select>\n);
200 $$attribute{value}='' if not defined $$attribute{value};
201 print qq(<input type="text" name="attribute_value" value="$$attribute{value}"><input type="submit" name="delete_attribute_$attr_num" value="Delete"><br>\n);
205 print qq(<input type="submit" name="add_attribute" value="Add Attribute"><br>);
209 # STRA : ascending by string
210 # STRD : descending by string
211 # NUMA : ascending by number or date
212 # NUMD : descending by number or date
214 my @order_operators = (STRA => 'ascending (string)',
215 STRD => 'descending (string)',
216 NUMA => 'ascending (number or date)',
217 NUMD => 'descending (number or date)',
220 print qq(<p>Order by: <select name="order_field">\n);
221 print qq(<option value="">Default</option>);
222 foreach my $attr (keys %attributes) {
223 my $selected = (defined $cgi_var{order_field} and $cgi_var{order_field} eq $attr) ? ' selected' : '';
224 print qq(<option value="$attr"$selected>$attributes{$attr}{name}</option>\n);
226 print qq(</select>\n);
227 print qq(<select name="order_operator">\n);
230 my @tmp_array = (@order_operators);
231 while (($operator,$name) = splice(@tmp_array,0,2)) {
232 my $selected = (defined $cgi_var{order_field} and $cgi_var{order_operator} eq $operator) ? ' selected' : '';
233 print qq(<option value="$operator"$selected>$name</option>\n);
235 print qq(</select></p>\n);
239 print qq(<p>Max results: <select name="max_results">\n);
240 for my $max_results (qw(10 25 50 100 150 200)) {
241 my $selected = (defined $cgi_var{max_results} and $cgi_var{max_results} eq $max_results) ? ' selected' : '';
242 print qq(<option value="$max_results"$selected>$max_results</option>\n);
244 print qq(</select></p>\n);
246 print qq(</tr></table>\n);
251 print "<h2> Results</h2>\n";
252 my $hits = $nres->hits();
253 print "<p>Hits: ".$hits;
254 if (($cgi_var{skip} > 0)) {
255 print q(<input type="submit" name="prev" value="Prev">);
257 if ($hits > ($cgi_var{skip}+$cgi_var{max_results})) {
258 print q(<input type="submit" name="next" value="Next">);
261 print qq(<ul class="msgreceived">\n);
262 for my $rdoc (map {$nres->get_doc($_)} 0.. ($nres->doc_num-1)) {
263 my ($bugnum,$msgnum) = split m#/#,$rdoc->attr('@uri');
264 my %attr = map {($_,$rdoc->attr($_))} $rdoc->attr_names;
265 # initialize any missing variables
266 for my $var ('@title','@author','@cdate','package','severity') {
267 $attr{$var} = '' if not defined $attr{$var};
270 $showseverity = "Severity: <em>$attr{severity}</em>;\n";
272 <li><a href="$url${bugnum}#${msgnum}">#${bugnum}: $attr{'@title'}</a> @{[htmlize_packagelinks($attr{package})]}<br>
274 Sent by: @{[encode_entities($attr{'@author'})]} at $attr{'@cdate'}<br>
276 # Deal with the snippet
277 # make the things that match bits of the phrase bold, the rest normal.
278 my $snippet_mod = html_escape($attr{snippet});
279 $snippet_mod =~ s/\n\n/ . . . /g;
280 for my $phrase_bits (split /\s+/,$cgi_var{phrase}) {
281 $snippet_mod =~ s{\n(\Q$phrase_bits\E)(?:\s+\Q$phrase_bits\E\n)}{'<b>'.$1.'</b>'}gei;
283 print "<p>$snippet_mod</p>\n";
286 if (($cgi_var{skip} > 0)) {
287 print q(<input type="submit" name="prev" value="Prev">);
289 if ($hits > ($cgi_var{skip}+$cgi_var{max_results})) {
290 print q(<input type="submit" name="next" value="Next">);
298 # This CGI should make an abstract method of displaying information
299 # about specific bugs and their messages; the information should be
300 # fairly similar to the way that pkgreport.cgi works, with the
301 # addition of snippit information and links to ajavapureapi/overview-summary.html specific message
304 # For now we'll brute force the display, but methods to display a bug
305 # or a particular bug message should be made common between the two
309 sub parse_attribute {
313 if (ref $$cgi_var{attribute_operator}) {
314 for my $elem (0 ... $#{$$cgi_var{attribute_operator}}) {
315 push @attributes,{map {($_,$$cgi_var{"attribute_$_"}[$elem]);} qw(value field operator)};
318 elsif (defined $$cgi_var{attribute_operator}) {
319 push @attributes,{map {($_,$$cgi_var{"attribute_$_"});} qw(value field operator)};