Merge pull request #5205 from solgenomics/topic/generic_trial_upload
[sgn.git] / lib / SGN / Controller / Bulk / Display.pm
blob9dfba2d94567a9244c5b39e7d0b6c9a3f24df61c
2 =head1 NAME
4 /bulk/display.pl
6 =head1 DESCRIPTION
8 This perl script is used on the bulk download page. It determines the format
9 of the data given back to the user (submitted to download.pl). This includes
10 the format of the the html pages that display the data as well as determining
11 the fasta format and the text format.
13 =cut
15 package SGN::Controller::Bulk::Display;
17 use Moose;
19 use Cache::File;
20 use File::Spec::Functions;
21 use File::Slurp qw | read_file |;
22 use CXGN::Page::FormattingHelpers qw | html_break_string |;
23 BEGIN { extends 'Catalyst::Controller' };
25 =head2 display_page
27 Desc: sub display_page
28 Args: default
29 Ret : page
31 Calls summary page to be displayed. Determines what page to render depending
32 on the outout type the user selects.
34 =cut
36 sub display_page : Path('/tools/bulk/display') :Args(0) {
37 my $self = shift;
38 my $c = shift;
40 # define some constants
41 $self->{pagesize} = 50;
42 $self->{content} = "";
43 $self->{tempdir} = $c->path_to( $c->tempfiles_subdir('bulk') );
45 # get cgi arguments
46 $self->{dumpfile} = $c->req->param("dumpfile");
47 $self->{page_number} = $c->req->param("page_number") || 1;
48 $self->{page_size} = $c->req->param("page_size");
49 $self->{outputType} = $c->req->param("outputType");
50 $self->{seq_type} = $c->req->param("seq_type");
51 $self->{idType} = $c->req->param("idType");
52 $self->{summary} = $c->req->param("summary");
53 $self->{download} = $c->req->param("download");
54 $self->{lines_read} = $c->req->param("lines_read");
55 $self->{outputType} = $c->req->param("outputType");
56 $self->{unigene_seq} = $c->req->param("unigene_seq");
57 $self->{est_seq} = $c->req->param("est_seq");
59 $c->stash->{summary_data} = {
60 dumpfile => $self->{dumpfile},
62 tempdir => $c->path_to($c->tempfiles_subdir("bulk")),
63 page_number => $self->{page_number},
64 page_size => $self->{page_size},
65 outputType => $self->{outputType},
66 seq_type => $self->{seq_type},
67 idType => $self->{idType},
68 summary => $self->{summary},
69 download => $self->{download},
70 lines_read => $self->{lines_read},
71 outputType => $self->{outputType},
73 $c->stash->{data} = $c->stash->{summary_data};
74 # if summary switch is set, display summary page
75 if ( $self->{summary} ) {
77 $c->stash->{template} = '/tools/bulk/display/summary_page.mas';
78 return;
81 elsif ( $self->{outputType} =~ /html/i ) {
82 #$self->render_html_table_page();
83 $c->stash->{template} = '/tools/bulk/display/browse_html.mas';
85 elsif ( $self->{outputType} =~ /text/i ) {
86 $self->render_text_page($c);
88 elsif ( $self->{outputType} =~ /fasta/i ) {
89 $self->render_fasta_page($c);
91 elsif ( $self->{outputType} =~ /notfound/i ) {
92 $self->display_ids_notfound($c);
94 else {
95 #$c->stash->{template} = '/tools/bulk/display/browse_html.mas';
96 die "NEED OUTPUT TYPE";
100 =head2 display_summary_page
102 Desc: sub display_summary_page
103 Args: default
104 Ret : n/a
106 Opens temp file created in download.pl then opens a filehandle and prints the
107 data to that file.
109 =cut
111 sub display_summary_page : Path('/tools/bulk/summary') Args(1){
112 my $self = shift;
113 my $c = shift;
114 my $dumpfile = shift;
116 print STDERR "DUMPFILE = $dumpfile\n";
117 my $cache_root = catfile($c->config->{basepath}, $c->tempfiles_subdir("bulk"), $dumpfile.".summary");;
118 print STDERR "CACHE_ROOT: $cache_root\n";
119 my $cache = Cache::File->new( cache_root =>$cache_root);
121 my $summary_data = {};
122 foreach my $k (qw | fastalink fastadownload fastamessage missing_ids_message file total query_time filesize numlines lines_read idType |) {
123 $summary_data->{$k} = $cache->get($k);
126 $c->stash->{summary_data} = $summary_data;
127 $c->stash->{template} = '/tools/bulk/display/summary_page.mas';
132 =head2 render_fasta_page
134 Desc: sub render_fasta_page
135 Args: default
136 Ret : n/a
138 Determines the format of the fasta page (in a similar way as
139 render_html_table_page). No trailing spaces or new lines should be present
140 after this subroutine is called for fasta pages.
142 =cut
144 sub render_fasta_page {
145 my $self = shift;
146 my $c = shift;
148 my $fasta = "";
150 open( F, "< :encoding(UTF-8)" . $self->{tempdir} . "/" . $self->{dumpfile} )
151 || $self->{page}->error_page( "Can't open " . $self->{dumpfile} );
153 # read column definitions
154 my @output_fields;
155 my $defs = <F>;
156 if ($defs) { chomp($defs); @output_fields = split /\t/, $defs; }
158 while (<F>) {
159 chomp;
160 my @f = split /\t/;
162 #convert to hash
163 for ( my $i = 0 ; $i < @output_fields ; $i++ ) {
164 $self->{ $output_fields[$i] } = $f[$i];
166 if ( ( join " ", @output_fields ) =~ /est_seq/i ) {
167 $self->{seq_type} = "est_seq";
169 elsif ( ( join " ", @output_fields ) =~ /unigene_seq/i ) {
170 $self->{seq_type} = "unigene_seq";
172 elsif ( ( join " ", @output_fields ) =~ /^protein_seq$/i ) {
173 $self->{seq_type} = "protein_seq";
174 } #added for protein
175 elsif ( ( join " ", @output_fields ) =~ /estscan_seq/i ) {
176 $self->{seq_type} = "estscan_seq";
178 elsif ( ( join " ", @output_fields ) =~ /longest6frame_seq/i ) {
179 $self->{seq_type} = "longest6frame_seq";
181 elsif ( ( join " ", @output_fields ) =~ /preferred_protein_seq/i ) {
182 $self->{seq_type} = "preferred_protein_seq";
185 my $breakspace_num = 60;
187 my $seq = "";
188 # quality values
189 my $qual = "";
190 if ( $self->{qual_value_seq} ) {
191 $qual = $self->{qual_value_seq};
193 else {
194 $self->{qual_value_seq} = "";
196 my @qual = split /\s+/, $qual;
197 $self->{qual_value_seq} = "\n";
198 while ( my @a = splice( @qual, 0, $breakspace_num ) ) {
199 $self->{qual_value_seq} .= join( " ", @a ) . "\n";
201 if ( $self->{qual_value_seq} ) {
202 $seq = $self->{qual_value_seq};
203 $self->{qual_value_seq} = "";
206 # bac end sequences
207 # only print sequence if both quality value and sequence selected
208 if ( $self->{bac_end_sequence} ) {
209 $seq = "\n"
210 . html_break_string( $self->{bac_end_sequence}, $breakspace_num,
211 "\n" )
212 . "\n";
213 $self->{bac_end_sequence} = "";
215 else {
216 $self->{bac_end_sequence} = "";
219 # est vs. unigene seq
220 $self->{est_seq} =
221 html_break_string( $self->{est_seq}, $breakspace_num, "\n" )
222 if defined( $self->{est_seq} );
223 $self->{unigene_seq} =
224 html_break_string( $self->{unigene_seq}, $breakspace_num, "\n" )
225 if defined( $self->{unigene_seq} );
226 $self->{protein_seq} =
227 html_break_string( $self->{protein_seq}, $breakspace_num, "\n" )
228 if defined( $self->{protein_seq} );
229 $self->{estscan_seq} =
230 html_break_string( $self->{estscan_seq}, $breakspace_num, "\n" )
231 if defined( $self->{estscan_seq} );
232 $self->{longest6frame_seq} =
233 html_break_string( $self->{longest6frame_seq}, $breakspace_num, "\n" )
234 if defined( $self->{longest6frame_seq} );
235 $self->{preferred_protein_seq} =
236 html_break_string( $self->{preferred_protein_seq},
237 $breakspace_num, "\n" )
238 if defined( $self->{preferred_protein_seq} );
240 if ( $self->{seq_type} eq "est_seq" ) {
241 $seq = "\n" . $self->{est_seq} . "\n";
242 warn "NOTE: est sequence given, seq_type: "
243 . $self->{seq_type} . "\n";
244 $self->{est_seq} = "";
246 elsif ( $self->{seq_type} eq "unigene_seq" ) {
247 $seq = "\n" . $self->{unigene_seq} . "\n";
248 warn "NOTE: unigene sequence given, seq_type: "
249 . $self->{seq_type} . "\n";
250 $self->{unigene_seq} = "";
253 #added for protein
254 elsif ( $self->{seq_type} eq "protein_seq" ) {
255 $seq = "\n" . $self->{protein_seq} . "\n";
256 warn "NOTE: protein sequence given, seq_type: "
257 . $self->{seq_type} . "\n";
258 $self->{protein_seq} = "";
260 elsif ( $self->{seq_type} eq "estscan_seq" ) {
261 $seq = "\n" . $self->{estscan_seq} . "\n";
262 $self->{estscan_seq} = "";
264 elsif ( $self->{seq_type} eq "preferred_protein_seq" ) {
265 $seq = "\n" . $self->{preferred_protein_seq} . "\n";
266 $self->{preferred_protein_seq} = "";
268 elsif ( $self->{seq_type} eq "longest6frame_seq" ) {
269 $seq = "\n" . $self->{longest6frame_seq} . "\n";
270 $self->{longest6frame_seq} = "";
273 # output
274 my $output = "";
275 foreach my $o (@output_fields) {
276 if ( exists( $self->{$o} ) && $self->{$o} ne "" ) {
277 $output .= "$o:$self->{$o}\t";
281 s/ +/ /g foreach ( $output . $seq );
282 $output =~ s/.*?\://
283 ; # remove the first label (>SGN_U:SGN_U738473 becomes simply >SGN_U738473)
285 $fasta .= ">$output$seq"; # do not add new lines to this string
288 close(F);
290 # print header
292 if ( $self->{download} ) {
293 $c->res->content_type("application/data");
294 $c->res->headers()->header("Content-Disposition: filename=sgn_bulk_download.fasta");
296 else {
297 $c->res->content_type("text/plain");
299 $c->res->body($fasta);
304 =head2 buttons
306 Desc: sub buttons
307 Args: default
308 Ret : n/a
310 Calls subtroutines for buttons that will display on the html display pages.
312 =cut
314 sub buttons {
315 my $self = shift;
316 my $pages = ( int( $self->{line_count} / $self->{page_size} ) ) + 1;
317 $self->{content} .= "<br />Page" . $self->{page_number} . " of $pages | ";
318 $self->previousButton();
319 $self->{content} .= " | ";
320 $self->summaryButton();
321 $self->{content} .= " | ";
322 $self->newSearchButton();
323 $self->{content} .= " | ";
324 $self->nextButton();
325 $self->{content} .= "<br /><br />";
328 =head2 nextButtons
330 Desc: sub nextButtons
331 Args: default
332 Ret : n/a
334 Determines the next button that will display on the html display pages.
336 =cut
338 sub nextButton {
339 my $self = shift;
341 # add next page button if there is a next page
342 if ( ( $self->{line_count} + $self->{page_size} ) >
343 ( ( $self->{page_number} + 1 ) * $self->{page_size} ) )
345 $self->{content} .=
346 "<a href=\"display.pl?dumpfile="
347 . ( $self->{dumpfile} )
348 . "&amp;page_number="
349 . ( $self->{page_number} + 1 )
350 . "\">Next Page</a>";
352 else {
353 $self->{content} .= "Next Page";
357 =head2 previousButtons
359 Desc: sub previousButtons
360 Args: default
361 Ret : n/a
363 Determines the previous button that will display on the html display pages.
365 =cut
367 sub previousButton {
368 my $self = shift;
369 if ( ( $self->{page_number} - 1 ) > 0 ) {
370 $self->{content} .=
371 "<a href=\"display.pl?dumpfile="
372 . ( $self->{dumpfile} )
373 . "&amp;page_number="
374 . ( $self->{page_number} - 1 )
375 . "\">Previous Page</a>";
377 else {
378 $self->{content} .= "Previous Page";
382 =head2 summaryButtons
384 Desc: sub summaryButtons
385 Args: default
386 Ret : n/a
388 Determines the summary button that will display on the html display pages.
390 =cut
392 sub summaryButton {
393 my $self = shift;
394 $self->{content} .=
395 "<a href=\"/tools/bulk/display?summary=1&amp;dumpfile="
396 . ( $self->{dumpfile} )
397 . "&amp;idType="
398 . ( $self->{idType} )
399 . "\">Summary Page</a>";
402 =head2 newSearchButtons
404 Desc: sub newSearchButtons
405 Args: default
406 Ret : n/a
408 Determines the new search button that will display on the html display pages.
410 =cut
412 sub newSearchButton {
413 my $self = shift;
414 $self->{content} .= "<a href=\"input.pl\">New Search</a>";
417 =head2 getFileLines
419 Desc: sub getFileLines
420 Args: file; example. $self -> getFileLines($self->{tempdir});
421 Ret : $list[0];
423 Counts file lines (used on temp directories).
425 =cut
427 sub getFileLines {
428 my $self = shift;
429 my $file = shift;
430 open my $f, '< :encoding(UTF-8)', $file or die "$! reading $file";
431 my $cnt = 0;
432 $cnt++ while <$f>;
433 return $cnt;
436 =head2 render_text_page
438 Desc: sub render_text_page
439 Args: $c
440 Ret : n/a
442 Opens dumpfile and displays it (this is the text file).
444 =cut
446 sub render_text_page {
447 my $self = shift;
448 my $c = shift;
449 print STDERR "TEMPDIR = $self->{tempdir}\n\n";
450 $self->dumptextfile($c, $self->{tempdir} . "/" . $self->{dumpfile} );
453 =head2 display_ids_notfound
455 Desc: sub display_ids_notfound
456 Args: default;
457 Ret : n/a
459 Opens dumpfile and counts the lines, then compares to the number of IDs
460 submitted to get the count of the IDs that were not found in the database.
462 =cut
464 sub display_ids_notfound {
465 my $self = shift;
466 my $c = shift;
467 my $file = $self->{tempdir} . "/" . $self->{dumpfile} . ".notfound";
468 my $count = $self->getFileLines($file);
469 $self->dumptextfile($c, $file, "IDs not found in the database: $count" );
472 =head2 dumptextfile
474 Desc: sub dumptextfile
475 Args: default;
476 Ret : n/a
478 Cleans up and closes dumpfile.
480 =cut
482 sub dumptextfile {
483 my $self = shift;
484 my $c = shift;
485 my $file = shift;
486 my $message = shift;
487 if ( $self->{download} ) {
488 #"Pragma: \"no-cache\"\nContent-Disposition: filename=sgn_dump.txt\nContent-type: application/data\n\n";
489 $c->res->content_type("application/data");
490 $c->res->headers()->header("Content-Disposition: filename=sgn_bulk_download.fasta");
491 #no-cache\nContent-Disposition: filename=sgn_dump.txt\nContent-type: application/data\n\n");
493 else {
494 $c->res->content_type("text/plain");
497 my $contents = read_file($file);
499 $c->res->body($message . $contents);
502 =head2 debug
504 Desc: sub debug
505 Args: string; example. $self -> debug("input_ok: Input is NOT OK!");
506 Ret : n/a
508 Function for printing adds break and new line to messages.
510 =cut
512 sub debug {
513 my $self = shift;
514 my $message = shift;
515 if ( $self->{debug} ) { $self->{content} .= "$message<br />\n"; }
518 =head2 no_data_error_page
520 Desc: sub no_data_error_page
521 Args: n/a
522 Ret : n/a
524 Displays message when file can no longer be opened.
526 =cut
528 sub no_data_error_page {
529 print
530 "The results of that search or not available anymore. Please repeat your search.";
535 =head1 BUGS
537 None known.
539 =head1 AUTHOR
541 Lukas Mueller, August 12, 2003
542 Modified and documented by Caroline Nyenke, August, 11, 2005
544 =head1 SEE ALSO
546 /bulk/download.pl
547 /bulk/input.pl
549 =cut