package GO::Tool::ReferencesTool; use strict; use lib 'go/scratch/tools'; use base 'GO::Tool::GenericGoTool'; ### Various modules required use Data::Dumper; use CGI::Carp qw(fatalsToBrowser); use GO::Object::Reference; use GO::Object::Xref; use GO::TestSet qw(dfv_test); use GO::Utilities qw(:all); use GO::GeneralPurposeParser; use URI::Escape; #use Utility::TSLParser; sub _specification { my $self = shift; return ( 'sort', { test => dfv_test( 'is_in_list_p', { list => [ 'go_ref_id' ], this => 1 } ), default => 'go_ref_id', }, 'id', { view_single => { test => qr/^GO_REF:\d{7}$/, required => 1, allow_multiple => 1, }, }, 'page', { test => qr/^\d+$/, # must be a number default => '1', }, 'page_size', { test => qr/^(\d+|all)$/, # must be a number or all default => 'all', }, # rm => { # test => qr/^view_(all|single)$/, # default => sub { # my $dfvr = shift; # my $input = $dfvr->get_input_data( as_hashref => 1 ); # if ( $input->{id}) # { return 'view_single'; } # else # { return 'view_all'; } # }, # dependencies => { # "view_single" => [ qw( id ) ], # } # }, ); } ### stuff we're going to need ### reference db file my $ref_db = "/Users/gwg/go/doc/GO.references"; ### the references master, official adder of references to the GO references db ### new references will be sent by email to this address for checking my $ref_master = ""; sub setup { my $self = shift; $self->start_mode('view_all'); $self->mode_param(\&set_run_mode); $self->error_mode('die_and_output_error'); $self->run_modes( 'view_all' => 'view_all', 'view_single' => 'view_single', 'fatal_error' => 'die_and_output_error', 'AUTOLOAD' => 'view_all', ); } ## override the default just to speed things up #sub _runmode_specific_data { # my $self = shift; # return [ 'go_ref_id' ]; #} sub set_run_mode { my $self = shift; my %cgi_h = $self->query->Vars; return 'view_single' if exists $cgi_h{id}; return 'view_all'; } # configure the template before we do anything else sub cgiapp_init { my $self = shift; $self->tt_config( TEMPLATE_OPTIONS => { INCLUDE_PATH=> [ qw( /Users/gwg/go/scratch/tools/templates/ /Users/gwg/go/www/) ], TRIM=>1, }, ); } ## stuff to do before we run the page-specific code sub cgiapp_prerun { my $self = shift; $self->startme; $self->debugme("current runmode: ". $self->get_current_runmode); # check the input query, replace dodgy params with the defaults my $results = $self->check_input_query({ replace_with_defaults => 1, spec_profile => $self->get_current_runmode }); if (!$results->success) { # set the mode to 'error' $self->prerun_mode('fatal_error'); # create an error message my $err_str; if ($self->get_current_runmode eq 'view_single' && ! $results->valid('id') ) { if ($results->missing('id')) { $err_str = 'You have not entered a query'; } elsif ($results->invalid('id')) { $err_str = 'You have entered an invalid ID'; } } if (!$err_str) { $err_str = join "
", @{ GO::Utilities::summarize_errors($results) }; } $self->fatal_msg($err_str); } } sub view_single { my $self = shift; return $self->retrieve_data({ single => 1 }); } sub view_all { my $self = shift; return $self->retrieve_data; } =head2 retrieve_data Function to get data from the DB, either for a single ref or the whole lot. input: $self, optional flag which will trigger a search for an ID if present; otherwise, the operation will get all refs. =cut sub retrieve_data { my $self = shift; $self->startme; my $options = shift; my $output; # get the checked query my $query_h = $self->param('validated_query'); # get the parser ready for action my $parser_args = { file => $ref_db, file_separator => "\n\n", inner_parser => { parser => 'multi_field_tag_value', return_record_as_object => 'GO::Object::Reference', check_input => 1, filter_field => qr/^[^!]/, }, }; if ($options->{single}) # this is a single GO REF query { # create the search query using the data in parsed query data # the param we need in the query is id # we should check alt_id too # in case we have more than one go ref, turn the query into a list $query_h->{id} = [ $query_h->{id} ] if ! ref($query_h->{id}); # create the query # check for $query_h->{id} appearing as a go_ref_id or alt_id # ignore any record which doesn't feature $query_h->{id} somewhere $parser_args->{inner_parser}{filter_record} = [ map { qr/(go_ref|alt)_id: $_\b/i } @{$query_h->{id}} ]; } # load the references; dies if no references present my $ref_arr = $self->get_data_from_file($parser_args); # check we found all that we wanted to find if ($options->{single}) { # a query for one (or more) references if (!$ref_arr || scalar @{$query_h->{id}} != scalar @$ref_arr) { my $lost_and_found = GO::Utilities::check_list_for_values({ query_list => $query_h->{id}, results => $ref_arr, test => sub { my ($r, $query) = @_; return 1 if $r->go_ref_id eq $query; return 0 if ! $r->alt_id; if (!ref($r->alt_id)) { return 1 if $r->alt_id eq $query; return 0; } foreach ( $r->alt_id ) { return 1 if $_ eq $query; } return 0; }, }); $self->printerr("lost and found: ".Dumper($lost_and_found)); # let's have a look at our error list. If the last message was the parser # complaining that it had no results, delete it and replace it with # a custom message. my $last_msg = $self->get_last_msg; if ($last_msg && $last_msg->{MSG_CODE} && $last_msg->{MSG_CODE} eq 'no_results') { $self->clear_last_msg; } my $msg; my $last = pop @{$lost_and_found->{missing}}; if (scalar (@{$lost_and_found->{missing}}) != 0) { $msg = "There are no GO references with the IDs " . join(", ", @{$lost_and_found->{missing}}) . " or " . $last . "."; } else { $msg = "There is no GO reference with the ID " . $last . "."; } if (!$ref_arr) { $self->fatal_msg({ MSG_CODE => 'no_results', MSG => $msg }); } else { $self->warning_msg({ MSG => $msg }); } } } elsif (!$ref_arr || !@$ref_arr) { # no results at all. Oh no! $self->printerr("FATAL: No reference data found in $ref_db"); $self->clear_all_msgs; $self->fatal_err("No valid data could be found. Please check $ref_db and try again."); } if ($ref_arr) { # get the sorted list my $sorted_list = GO::Utilities::sort_list({ list => $ref_arr, crit => [ $query_h->{'sort'} ] }); # get the subset of the results, if appropriate my $paged = get_results_chunk($sorted_list, { chunk_n => $query_h->{page}, chunk_size => $query_h->{page_size} }); $output->{ref_arr} = $paged->{subset}; $output->{n_pages} = $paged->{n_chunks}; $output->{page} = $paged->{chunk_n}; } # set up all the other stuff and output the template return $self->tt_process('view_reference.tmpl', $self->set_up_output($output)) || die "Template toolkit messed up, the bastard!: ", $self->tt_obj->error(), "Dying"; } sub set_up_output { my $self = shift; $self->startme; my $tmpl_vars = shift || {}; # the checked query into $output $tmpl_vars->{query_h} = $self->param('validated_query'); $tmpl_vars = { %$tmpl_vars, base_url => 'http://127.0.0.1/cgi-bin/references.cgi', install_dir => 'http://127.0.0.1/go/', }; # $self->debugme("tmpl_vars: ".Dumper($tmpl_vars)); if ($tmpl_vars->{n_pages} && $tmpl_vars->{n_pages} > 1) { ### set up URLs for paging, etc. my $url_h; my $spec = $self->get_spec; foreach my $p (keys %$spec) { # if the parameter is set AND there's no default or the parameter differs # from the default, add the param to the URL if ($tmpl_vars->{query_h}{$p} && (!$spec->{$p}{default} || # no default ($spec->{$p}{default} && # default, param differs from default $spec->{$p}{default} ne $tmpl_vars->{query_h}{$p}) ) ) { $url_h->{$p} = uri_escape($tmpl_vars->{query_h}{$p}); } } # paging URLs: need everything except page number delete $url_h->{page} if $url_h->{page}; $tmpl_vars->{url_for_paging} = join( "&", map { my $k = $_; if (ref($url_h->{$k}) eq 'ARRAY') { join( "&", map { $k . "=" . $_ } @{$url_h->{$k}} ); } else { $k . "=" . $url_h->{$k}; } } keys %$url_h ); $self->debugme("url for paging: ".Dumper($tmpl_vars->{url_for_paging})); } return $tmpl_vars; } 1;