--- loncom/interface/lonsearchcat.pm 2002/07/08 20:35:36 1.139 +++ loncom/interface/lonsearchcat.pm 2002/07/28 20:02:14 1.145 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Search Catalog # -# $Id: lonsearchcat.pm,v 1.139 2002/07/08 20:35:36 matthew Exp $ +# $Id: lonsearchcat.pm,v 1.145 2002/07/28 20:02:14 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -40,7 +40,7 @@ =head1 NAME -lonsearchcat +lonsearchcat - LONCAPA Search Interface =head1 SYNOPSIS @@ -87,8 +87,10 @@ use Apache::lonnet(); use Apache::File(); use CGI qw(:standard); use Text::Query; +use DBI; use GDBM_File; use Apache::loncommon(); +use Apache::lonmysql(); # ---------------------------------------- variables used throughout the module @@ -101,17 +103,13 @@ use Apache::loncommon(); =over 4 -=item $closebutton - -button that closes the search window - =item $importbutton button to take the select results and go to group sorting -=item %hash +=item %groupsearch_db -The ubiquitous database hash +Database hash used to save values for the groupsearch RAT interface. =item $diropendb @@ -133,19 +131,19 @@ takes the proper parameters. ###################################################################### # -- dynamically rendered interface components -my $closebutton; # button that closes the search window my $importbutton; # button to take the selected results and go to group sorting # -- miscellaneous variables -my %hash; # database hash +my %groupsearch_db; # database hash my $diropendb = ""; # db file - # View Description Function Pointer my %Views = ("Detailed Citation View" => \&detailed_citation_view, "Summary View" => \&summary_view, "Fielded Format" => \&fielded_format_view, "XML/SGML" => \&xml_sgml_view ); - +my $persistent_db_file; +my %persistent_db; +my $hidden_fields; ###################################################################### ###################################################################### @@ -173,26 +171,57 @@ string that holds portions of the screen ###################################################################### sub handler { my $r = shift; - untie %hash; - + # + untie %groupsearch_db if (tied(%groupsearch_db)); + # + my $closebutton; # button that closes the search window + # This button is different for the RAT compared to + # normal invocation. + # $r->content_type('text/html'); $r->send_http_header; return OK if $r->header_only; - + ## + ## Pick up form fields passed in the links. + ## + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['catalogmode','launch','acts','mode','form','element', + 'reqinterface','persistent_db_id','table']); + ## + ## Initialize global variables + ## my $domain = $r->dir_config('lonDefDomain'); $diropendb= "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain). "\_".&Apache::lonnet::escape($ENV{'user.name'})."_searchcat.db"; - - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['catalogmode','launch','acts','mode','form','element', - 'reqinterface']); + # + # set the name of the persistent database + # $ENV{'form.persistent_db_id'} can only have digits in it. + if (! exists($ENV{'form.persistent_db_id'}) || + $ENV{'form.persistent_db_id'} =~ /\D/ ) { + $ENV{'form.persistent_db_id'} = time; + } + $persistent_db_file = "/home/httpd/perl/tmp/". + &Apache::lonnet::escape($domain). + '_'.&Apache::lonnet::escape($ENV{'user.name'}). + '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db'; + # + # Read in the database. It should (hopefully) not be catastrophic to + # fail in this exercise. + if (-e $persistent_db_file) { + # Read in the previous values, if we can. + if (tie(%persistent_db,'GDBM_File',$persistent_db_file, + &GDBM_READER,0640)) { + &reconstruct_persistent_form_data($r); + untie (%persistent_db); + } + } ## - ## Clear out old values from database + ## Clear out old values from groupsearch database ## if ($ENV{'form.launch'} eq '1') { - if (tie(%hash,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) { + if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) { &start_fresh_session(); - untie %hash; + untie %groupsearch_db; } else { $r->print('Unable to tie hash to db '. 'file'); @@ -200,23 +229,14 @@ sub handler { } } ## - ## Produce some output, so people know it is working - ## - $r->print("\n"); - $r->rflush; - ## ## Configure dynamic components of interface ## - my $hidden; # Holds 'hidden' html forms + $hidden_fields = ''; if ($ENV{'form.catalogmode'} eq 'interactive') { - $hidden="". - "\n"; $closebutton=""."\n"; } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') { - $hidden=< -END $closebutton=< END @@ -225,50 +245,68 @@ END onClick='javascript:select_group()'> END } - $hidden .= &make_persistent({ "form.mode" => $ENV{'form.mode'}, - "form.form" => $ENV{'form.form'}, - "form.element" => $ENV{'form.element'}, - "form.date" => 2 }); ## - ## What are we doing? + ## Do a search, if needed. ## my $searchtype; $searchtype = 'Basic' if ($ENV{'form.basicsubmit'} eq 'SEARCH'); $searchtype = 'Advanced' if ($ENV{'form.advancedsubmit'} eq 'SEARCH'); if ($searchtype) { + ## + ## make query information persistent to allow for subsequent revision + ## + tie(%persistent_db,'GDBM_File',$persistent_db_file,&GDBM_WRCREAT,0640); + &make_persistent(\%ENV); + untie(%persistent_db); + # # We are running a search my ($query,$customquery,$customshow,$libraries) = (undef,undef,undef,undef); + my $pretty_string; if ($searchtype eq 'Basic') { - $query = &parse_basic_search($r); + ($query,$pretty_string) = &parse_basic_search($r,$closebutton); } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') { - ($query,$customquery,$customshow,$libraries) - = &parse_advanced_search($r); + ($query,$customquery,$customshow,$libraries,$pretty_string) + = &parse_advanced_search($r,$closebutton); return OK if (! defined($query)); } - # Send query statements over the network to be processed by - # either the SQL database or a recursive scheme of 'grep'-like - # actions (for custom metadata). + # Output some information to the user. + $r->print(&search_results_header($searchtype,$pretty_string)); + $r->print("Sending search request to LON-CAPA servers.
\n"); + $r->rflush(); + &run_search($r,$query,$customquery,$customshow,$libraries); + ## + ## Display the results + ## + &display_results($r,$searchtype,$importbutton,$closebutton); $r->rflush(); - my $reply=&Apache::lonnet::metadata_query($query,$customquery, - $customshow,$libraries); - &output_results($searchtype,$r,$reply,$hidden); } else { # - # We need to get information to search on - # # Set the default view if it is not already set. if (!defined($ENV{'form.viewselect'})) { $ENV{'form.viewselect'} ="Detailed Citation View"; } - # Output the advanced interface - if ($ENV{'form.reqinterface'} eq 'advanced') { - $r->print(&advanced_search_form($closebutton,$hidden)); - } else { + # + # remove the requested interface from the environment. + my $interface; + if ($ENV{'form.reqinterface'}) { + $interface = lc($ENV{'form.reqinterface'}); + } else { + $interface = 'basic'; + } + ## + ## Determine course of action + ## + if ($interface eq 'display') { + # &display_results($closebutton)); + } elsif ($interface eq 'advanced') { + $r->print(&advanced_search_form($closebutton)); + } elsif ($interface eq 'basic') { # Output normal search interface - $r->print(&basic_search_form($closebutton,$hidden)); + $r->print(&basic_search_form($closebutton)); } } + untie (%persistent_db); return OK; } @@ -287,7 +325,7 @@ Returns a scalar which holds html for th ###################################################################### sub basic_search_form{ - my ($closebutton,$hidden) = @_; + my ($closebutton) = @_; my $scrout=<<"ENDDOCUMENT"; @@ -304,7 +342,7 @@ sub basic_search_form{

Search Catalog

-$hidden +$hidden_fields

Basic Search

Enter terms or phrases separated by AND, OR, or NOT @@ -318,8 +356,11 @@ ENDDOCUMENT ' '; # $scrout.=&simplecheckbox('allversions',$ENV{'form.allversions'}); # $scrout.='Search historic archives'; + my $checkbox = &simplecheckbox('related',$ENV{'form.related'}); $scrout.=<Advanced Search +Advanced Search +$checkbox use related words +

   @@ -353,7 +394,7 @@ Returns a scalar which holds html for th ###################################################################### sub advanced_search_form{ - my ($closebutton,$hidden) = @_; + my ($closebutton) = @_; my $advanced_buttons = <<"END";

@@ -385,7 +426,7 @@ Enter terms or phrases separated by sear such as AND, OR, or NOT.
$advanced_buttons -$hidden +$hidden_fields \n"; - $scrout.=&searchphrasefield('title', 'title' ,$ENV{'form.title'}); + $scrout.="\n"; + $scrout.=&searchphrasefield_with_related('title', 'title' , + $ENV{'form.title'}); $scrout.=&searchphrasefield('author', 'author' ,$ENV{'form.author'}); - $scrout.=&searchphrasefield('subject', 'subject' ,$ENV{'form.subject'}); - $scrout.=&searchphrasefield('keywords','keywords',$ENV{'form.keywords'}); + $scrout.=&searchphrasefield_with_related('subject', 'subject' , + $ENV{'form.subject'}); + $scrout.=&searchphrasefield_with_related('keywords','keywords', + $ENV{'form.keywords'}); $scrout.=&searchphrasefield('URL', 'url' ,$ENV{'form.url'}); - $scrout.=&searchphrasefield('notes', 'notes' ,$ENV{'form.notes'}); - $scrout.=&searchphrasefield('abstract','abstract',$ENV{'form.abstract'}); + $scrout.=&searchphrasefield_with_related('notes', 'notes' , + $ENV{'form.notes'}); + $scrout.=&searchphrasefield_with_related('abstract','abstract', + $ENV{'form.abstract'}); # Hack - an empty table row. - $scrout.="\n"; + $scrout.="\n"; $scrout.=&searchphrasefield('file
extension','mime', $ENV{'form.mime'}); - $scrout.="\n"; + $scrout.="\n"; $scrout.=&searchphrasefield('publisher
owner','owner', $ENV{'form.owner'}); $scrout.="
VIEW: @@ -394,19 +435,24 @@ ENDHEADER $ENV{'form.viewselect'}, undef,undef,undef, sort(keys(%Views))); - $scrout.="
Related
Words
  
   
  
   
\n"; @@ -432,22 +478,17 @@ ENDHEADER # adjust the size of the select box my $size = 4; my $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size); - # standalone machines do not get to choose a domain to search. - if ((scalar @domains) == 1) { - $scrout .=''."\n"; - } else { - $scrout.="\n".''. - 'DOMAINS
'. - ''."\n". + ''."\n"; - foreach my $dom (sort @domains) { - $scrout.="\n"; - } - $scrout.="\n"; + foreach my $dom (sort @domains) { + $scrout.="\n"; } + $scrout.="\n"; #---------------------------------------------------------------- $scrout.=&selectbox('Limit by language','language', $ENV{'form.language'},'any','Any Language', @@ -535,39 +576,73 @@ ENDDOCUMENT =pod -=item &make_persistent() +=item &reconstruct_persistent_form_data -Returns a scalar which holds the current ENV{'form.*'} values in -a 'hidden' html input tag. This allows search interface information -to be somewhat persistent. +This function is the reverse of &make_persistent(); +Retrieve persistent data from %persistent_db. Retrieved items will have their +values unescaped. If the item contains commas (before unescaping), the +returned value will be an array pointer. Items will be returned in the +environment in $ENV{"form.$name"}. =cut ###################################################################### ###################################################################### - -sub make_persistent { - my %save = %{shift()}; - my $persistent=''; - foreach (keys %save) { - if (/^form\./ && !/submit/) { - my $name=$_; - my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name})); - $name=~s/^form\.//; - foreach (@values) { - s/\"/\'/g; # do not mess with html field syntax - $persistent.=< -END +sub reconstruct_persistent_form_data { + foreach my $name (keys %persistent_db) { + # &Apache::lonnet::logthis("Reconstructing $name = $persistent_db{$name}"); + my @Values = split(',',$persistent_db{$name}); + my @value = map { &Apache::lonnet::unescape($_) } @Values; + $name = 'form.'.$name; + if (exists($ENV{$name})) { + if (ref($ENV{$name})) { + # Assume it is an array reference + $ENV{$name} = [@{$ENV{$name}},@value]; + } else { + $ENV{$name} = [$ENV{$name},@value]; + } + } else { + if (@value > 1) { + $ENV{$name} = [@value]; + } else { + $ENV{$name} = $value[0]; } } } - return $persistent; + return; } +###################################################################### +###################################################################### + +=pod + +=item &make_persistent() + +Store (environment) variables away to the %persistent_db. +Values will be escaped. Values that are array pointers will have their +elements escaped and concatenated in a comma seperated string. + +=cut ###################################################################### ###################################################################### +sub make_persistent { + my %save = %{shift()}; + foreach my $name (keys %save) { + next if ($name !~ /^form\./ || $name =~ /submit/); + my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name})); + # We handle array references, but not recursively. + my $store = join(',', map { &Apache::lonnet::escape($_); } @values ); + $name=~s/^form\.//; + $persistent_db{$name} = $store; + } + return ''; +} + +###################################################################### +# HTML form building functions # +###################################################################### =pod @@ -575,6 +650,13 @@ END =over 4 +=cut + +############################################### +############################################### + +=pod + =item &simpletextfield() Inputs: $name,$value,$size @@ -582,6 +664,23 @@ Inputs: $name,$value,$size Returns a text input field with the given name, value, and size. If size is not specified, a value of 20 is used. +=cut + +############################################### +############################################### + +sub simpletextfield { + my ($name,$value,$size)=@_; + $size = 20 if (! defined($size)); + return ''; +} + +############################################### +############################################### + +=pod + =item &simplecheckbox() Inputs: $name,$value @@ -589,92 +688,106 @@ Inputs: $name,$value Returns a simple check box with the given $name. If $value eq 'on' the box is checked. -=item &searchphrasefield() +=cut -Inputs: $title,$name,$value +############################################### +############################################### -Returns html for a title line and an input field for entering search terms. -the instructions "Enter terms or phrases separated by search operators such -as AND, OR, or NOT." are given following the title. The entry field (which -is where the $name and $value are used) is an 80 column simpletextfield. +sub simplecheckbox { + my ($name,$value)=@_; + my $checked=''; + $checked="checked" if $value eq 'on'; + return ''; +} -=item &dateboxes() +############################################### +############################################### -Returns html selection form elements for the specification of -the day, month, and year. +=pod -=item &selectbox() +=item &fieldtitle() -Returns a scalar containing an html tag. +=pod -=item $default +=item &searchphrasefield() -The default value of the form. Can be $anyvalue, or in @idlist. +Inputs: $title,$name,$value -=item $anyvalue +Returns html for a title line and an input field for entering search terms. +The entry field (which is where the $name and $value are used) is a 50 column +simpletextfield. The html returned is for a row in a three column table. -The

".$string."
\n"); + $r->rflush(); + return; +} + +###################################################################### +###################################################################### + +=pod + +=item &run_search + +=cut + +###################################################################### +###################################################################### +sub run_search { + my ($r,$query,$customquery,$customshow,$serverlist) = @_; + # + # Timing variables + # + my $starttime = time; + my $max_time = 120; # seconds for the search to complete + # + # Determine the servers we need to contact. + # + my @Servers_to_contact; + if (defined($serverlist)) { + @Servers_to_contact = @$serverlist; + } else { + @Servers_to_contact = sort(keys(%Apache::lonnet::libserv)); + } + my %Server_status; + # + # Create Table + # + my $table = &Apache::lonmysql::create_table + ( { columns => \%Datatypes, + column_order => \@DataOrder, + } ); + if (! defined($table)) { + # What do I do now? Print out an error page. + &Apache::lonnet::logthis("lonmysql attempted to create a table ". + "and this was the result:". + &Apache::lonmysql::get_error()); + $r->print("An internal error occured with the database.
". + "The error has been logged, but you should probably alert". + " your system administrator."); + return; + } + ## + ## form.table needs to be stored in the persistent database... + ## + $ENV{'form.table'}=$table; + # + # Prepare for the big loop. + # + my $hitcountsum; + my $server; + my $status; + while ((time - $starttime < $max_time) && + ((@Servers_to_contact) || keys(%Server_status))) { + # Send out a search request if it needs to be done. + if (@Servers_to_contact) { + # Contact one server + my $server = shift(@Servers_to_contact); + my $reply=&Apache::lonnet::metadata_query($query,$customquery, + $customshow,[$server]); + ($server) = keys(%$reply); + $Server_status{$server} = $reply->{$server}; + # &write_status($r,"Contacted:$server:reply:". + # $Server_status{$server}); + if ($max_time - (time - $starttime) < 20) { + # If there are less than 20 seconds to go in the search, + # give the newly contacted servers 20 more seconds to + # respond.... + $max_time += 20; + } + } else { + sleep(1); # wait a sec. to give time for files to be written + } + while (my ($server,$status) = each(%Server_status)) { + if ($status eq 'con_lost') { + delete ($Server_status{$server}); + # &write_status($r,"server $server is not responding."); + next; + } + $status=~/^([\.\w]+)$/; + my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1; + if (-e $datafile && ! -e "$datafile.end") { + # Let the user know we are receiving data from the server + # &write_status($r,"$server:Receiving file"); + next; + } + if (-e "$datafile.end") { + if (-z "$datafile") { + delete($Server_status{$server}); + next; + } + my $fh; + if (!($fh=Apache::File->new($datafile))) { + # Error opening file... + # Tell the user and exit...? + # Should I give up on opening it? + &write_status("Unable to open search results file for ". + "server $server. Omitting from search"); + next; + } + # Read in the whole file. + while (my $result = <$fh>) { + # handle custom fields? Someday we will! + chomp($result); + next unless $result; + # Parse the result. + my %Fields = &parse_raw_result($result,$server); + $Fields{'hostname'} = $server; + next if (! ©right_check(\%Fields)); + # Store the result in the mysql database + my $result = &Apache::lonmysql::store_row($table,\%Fields); + if (! defined($result)) { + &write_status($r,&Apache::lonmysql::get_error()); + } + # &write_status($r,&Apache::lonmysql::get_debug()); + $hitcountsum ++; + } # End of foreach (@results) + $fh->close(); + # $server is only deleted if the results file has been + # found and (successfully) opened. This may be a bad idea. + delete($Server_status{$server}); + #&write_status($r,"Received $new_count more results from ". + # $server."."); + } + } + # Finished looping through the servers + } + &Apache::lonmysql::disconnect_from_db(); + # Let the user know + # + # We have run out of time or run out of servers to talk to and + # results to get. + &write_status($r,"Search completed."); + if ($hitcountsum) { + &write_status($r,$hitcountsum." successful matches to your query."); + } else { + &write_status($r,"There were no successful matches to your query."); + } + return; +} + +###################################################################### +###################################################################### +=pod + +=item &display_buttons =cut ###################################################################### ###################################################################### -sub output_results { -# &Apache::lonnet::logthis("output_results:".time); - my $fnum; # search result counter - my ($mode,$r,$replyref,$hidden)=@_; - my %rhash=%{$replyref}; - my $compiledresult=''; - my $timeremain=300; # (seconds) - my $elapsetime=0; - my $resultflag=0; - my $tflag=1; +sub display_buttons { + my ($current_min,$show,$total,$parms) = @_; + return '' if ($show eq 'all'); # No links if you get them all at once. + my $links; + ## + ## Prev + my $prev_min = $current_min - $show; + $prev_min = 0 if $prev_min < 0; + if ($prev_min < $current_min) { + $links .= qq{ +prev +}; + } + ## + ## Pages.... Someday. + ## + + ## + ## Next + my $next_min = $current_min + $show; + my $next_min = $current_min if ($next_min > $total); + if ($next_min != $current_min) { + $links .= qq{ +next +}; + } + return $links; +} +###################################################################### +###################################################################### + +=pod + +=item &display_results + +=cut + +###################################################################### +###################################################################### +sub display_results { + my ($r,$mode,$importbutton,$closebutton) = @_; ## ## Set viewing function ## @@ -1142,15 +1676,9 @@ sub output_results { $r->rflush(); return; } - # - # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(\%ENV); - # - # Begin producing output - $r->print(&search_results_header($mode)); - $r->rflush(); - # - # begin showing the cataloged results + ## + ## Get the catalog controls setup + ## my $action = "/adm/searchcat"; if ($mode eq 'Basic') { $action .= "?reqinterface=basic"; @@ -1159,182 +1687,173 @@ sub output_results { } $r->print(< -$hidden +$hidden_fields $importbutton $closebutton -$persistent
CATALOGCONTROLS - # - # make the pop-up window for status - $r->print(&make_popwin(%rhash)); - $r->rflush(); + if (! tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) { + $r->print('Unable to tie hash to db file'); + $r->rflush(); + return; + } ## - ## Prepare for the main loop below + ## Prepare the table for querying ## - my $servercount=0; - my $hitcountsum=0; - my $servernum=(keys %rhash); - my $serversleft=$servernum; - ## - ## Run until we run out of time or we run out of servers - ## - while($serversleft && $timeremain) { - ## - ## %rhash has servers deleted from it as results come in - ## (within the foreach loop below). - ## - foreach my $rkey (sort keys %rhash) { -# &Apache::lonnet::logthis("Server $rkey:".time); - $servercount++; - $compiledresult=''; - my $reply=$rhash{$rkey}; - my @results; - if ($reply eq 'con_lost') { - &popwin_imgupdate($r,$rkey,"srvbad.gif"); - $serversleft--; - delete $rhash{$rkey}; - } else { - # must do since 'use strict' checks for tainting - $reply=~/^([\.\w]+)$/; - my $replyfile=$r->dir_config('lonDaemons').'/tmp/'.$1; - $reply=~/(.*?)\_/; - for (my $counter=0;$counter<2;$counter++) { - if (-e $replyfile && ! -e "$replyfile.end") { - &popwin_imgupdate($r,$rkey,"srvhalf.gif"); - &popwin_js($r,'popwin.hc["'.$rkey.'"]='. - '"still transferring..."'.';'); - } - # Are we finished transferring data? - if (-e "$replyfile.end") { - $serversleft--; - delete $rhash{$rkey}; - if (-s $replyfile) { - &popwin_imgupdate($r,$rkey,"srvgood.gif"); - my $fh; - unless ($fh=Apache::File->new($replyfile)){ - # Is it really appropriate to die on this error? - $r->print('ERROR: file '. - $replyfile.' cannot be opened'); - return OK; - } - @results=<$fh> if $fh; - my $hits =@results; - &popwin_js($r,'popwin.hc["'.$rkey.'"]='. - $hits.';'); - $hitcountsum+=$hits; - &popwin_js($r,'popwin.document.forms.popremain.'. - 'numhits.value='.$hitcountsum.';'); - } else { - &popwin_imgupdate($r,$rkey,"srvempty.gif"); - &popwin_js($r,'popwin.hc["'.$rkey.'"]=0;'); - } - last; - } # end of if ( -e "$replyfile.end") - last unless $timeremain; - sleep 1; # wait for daemons to write files? - $timeremain--; - $elapsetime++; - &popwin_js($r,"popwin.document.popremain.". - "elapsetime.value=$elapsetime;"); - } - &popwin_js($r,'popwin.document.whirly.'. - 'src="/adm/lonIcons/lonanimend.gif";'); - } # end of if ($reply eq 'con_lost') else statement - my %Fields = undef; # Holds the data to be sent to the various - # *_view routines. - my ($extrashow,$customfields,$customhash) = - &handle_custom_fields(\@results); - my @customfields = @$customfields; - my %customhash = %$customhash; - untie %hash if (keys %hash); - # - if (! tie(%hash,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) { - $r->print('Unable to tie hash to db '. - 'file'); - } else { - if ($ENV{'form.launch'} eq '1') { - &start_fresh_session(); - } - foreach my $result (@results) { - next if $result=~/^custom\=/; - chomp $result; - next unless $result; - %Fields = &parse_raw_result($result,$rkey); - # - # Check copyright tags and skip results the user cannot use - my (undef,undef,$resdom,$resname) = split('/',$Fields{'url'}); - # Check for priv - if (($Fields{'copyright'} eq 'priv') && - (($ENV{'user.name'} ne $resname) && - ($ENV{'user.domain'} ne $resdom))) { - next; - } - # Check for domain - if (($Fields{'copyright'} eq 'domain') && - ($ENV{'user.domain'} ne $resdom)) { - next; - } - # - $Fields{'extrashow'}=$extrashow; - if ($extrashow) { - foreach my $field (@customfields) { - my $value=''; - $value = $1 if ($customhash{$Fields{'url'}}=~/\<{$field}[^\>]*\>(.*?)\<\/{$field}[^\>]*\>/s); - $Fields{'extrashow'}=~s/\<\!\-\- $field \-\-\>/ $value/g; - } - } - $compiledresult.="\n

\n"; - if ($ENV{'form.catalogmode'} eq 'interactive') { - my $titleesc=$Fields{'title'}; - $titleesc=~s/\'/\\'/; # ' - $compiledresult.=<print("A MySQL error has occurred."); + &Apache::lonnet::logthis("lonmysql was unable to determine the status". + " of table ".$table); + return; + } elsif (! $table_check) { + $r->print("The table of results could not be found."); + &Apache::lonnet::logthis("The user requested a table, ".$table. + ", that could not be found."); + return; + } + ## + ## Get the number of results + ## + my $total_results = &Apache::lonmysql::number_of_rows($table); + if (! defined($total_results)) { + $r->print("A MySQL error has occurred."); + &Apache::lonnet::logthis("lonmysql was unable to determine the number". + " of rows in table ".$table); + &Apache::lonnet::logthis(&Apache::lonmysql::get_error()); + &Apache::lonnet::logthis(&Apache::lonmysql::get_debug()); + return; + } + if ($total_results == 0) { + $r->print("There were no results matching your query.\n". + ""); + return; + } + ## + ## Determine how many results we need to get + ## + $ENV{'form.startwith'} = 0 if (! exists($ENV{'form.startwith'})); + $ENV{'form.show'} = 'all' if (! exists($ENV{'form.show'})); + my $min = $ENV{'form.startwith'}; + my $max; + if ($ENV{'form.show'} eq 'all') { + $max = $total_results ; + } else { + $max = $min + $ENV{'form.show'}; + } + ## + ## Output links (if necessary) for 'prev' and 'next' pages. + ## + + ## + ## Get results from MySQL table + ## + my @Results = &Apache::lonmysql::get_rows($table, + 'id>'.$min.' AND id<='.$max); + ## + ## Loop through the results and output them. + ## + foreach my $row (@Results) { + my %Fields = %{&parse_row(@$row)}; + my $output="

\n"; + $output.=&catalogmode_output($Fields{'title'},$Fields{'url'}); + # Render the result into html + $output.= &$viewfunction(%Fields); + $output.="

\n
"; + # Print them out as they come in. + $r->print($output); + $r->rflush(); + } + if (@Results < 1) { + $r->print("There were no results matching your query"); + } + $r->print(""); + $r->rflush(); + untie %groupsearch_db; + return; +} + +###################################################################### +###################################################################### + +=pod + +=item &catalogmode_output($title,$url) + +Returns html needed for the various catalog modes. Gets inputs from +$ENV{'form.catalogmode'}. Stores data in %groupsearch_db and $fnum +(local variable). + +=cut + +###################################################################### +###################################################################### +{ +my $fnum; + +sub catalogmode_output { + my $output = ''; + my ($title,$url) = @_; + if ($ENV{'form.catalogmode'} eq 'interactive') { + $title=~ s/\'/\\'/g; # ' Escape single quotes. + if ($ENV{'form.catalogmode'} eq 'interactive') { + $output.=< +onClick="javascript:select_data('$title','$url')"> -
END - } - if ($ENV{'form.catalogmode'} eq 'groupsearch') { - $fnum+=0; - $hash{"pre_${fnum}_link"}=$Fields{'url'}; - $hash{"pre_${fnum}_title"}=$Fields{'title'}; - $compiledresult.=< -
END -# -# - $fnum++; - } - # Render the result into html - $compiledresult.= &$viewfunction(%Fields, hostname => $rkey ); - if ($compiledresult or $servercount!=$servernum) { - $compiledresult.="
"; - } - } - untie %hash; - } - if ($compiledresult) { - $resultflag=1; - $r->print($compiledresult); - } - } # End of foreach loop over servers remaining - } # End of big loop - while($serversleft && $timeremain) - unless ($resultflag) { - $r->print("\nThere were no results that matched your query\n"); - } - $r->print(''. - "\n"); - $r->print("\n\n"); - $r->rflush(); - return; + $fnum++; + } + return $output; +} + +} +###################################################################### +###################################################################### + +=pod + +=item &parse_row + +Parse a row returned from the database. + +=cut + +###################################################################### +###################################################################### +sub parse_row { + my @Row = @_; + my %Fields; + for (my $i=0;$i<=$#Row;$i++) { + $Fields{$DataOrder[$i]}=&Apache::lonnet::unescape($Row[$i]); + } + $Fields{'language'} = + &Apache::loncommon::languagedescription($Fields{'lang'}); + $Fields{'copyrighttag'} = + &Apache::loncommon::copyrightdescription($Fields{'copyright'}); + $Fields{'mimetag'} = + &Apache::loncommon::filedescription($Fields{'mime'}); + return \%Fields; } ########################################################### @@ -1406,6 +1925,7 @@ sub parse_raw_result { $Fields{'title'}='Untitled'; } unless ($ENV{'user.adv'}) { + # What is this anyway? $Fields{'keywords'} = '- not displayed -'; $Fields{'notes'} = '- not displayed -'; $Fields{'abstract'} = '- not displayed -'; @@ -1504,7 +2024,7 @@ Checked for existance & 'edit' mode. ###################################################################### ###################################################################### sub search_results_header { - my ($mode) = @_; + my ($mode,$pretty_query) = @_; $mode = lc($mode); my $title; if ($mode eq 'advanced') { @@ -1606,99 +2126,9 @@ SCRIPT

$title

END - return $result; -} - -###################################################################### -###################################################################### - -=pod - -=item &make_popwin() - -Returns html with javascript in it to open up the status window. - -=cut - -###################################################################### -###################################################################### -sub make_popwin { - my %rhash = @_; - my $servernum=(keys %rhash); - my $hcinit; - my $grid="'
'+\n"; - # $sn is the server number, used ONLY to make sure we have - # rows of 10 each. No longer used to index images. - my $sn=1; - foreach my $sk (sort keys %rhash) { - $grid.="''+ - $grid.="'+\"'\"+')\">'+"; - $grid.="\n"; - $grid.="'\"".$sk.'+\n"; - $grid.="'
'+\n" unless $sn%10; - $sn++; + if ($pretty_query) { + $result .= "

Search query: $pretty_query

"; } - my $result.=< - popwin=open('','popwin','scrollbars=1,width=400,height=220'); - popwin.focus(); - popwin.document.writeln('<'+'html>'); - popwin.document.writeln('<'+'head>'); - popwin.document.writeln('<'+'script>'); - popwin.document.writeln('hc=new Array();$hcinit'); - popwin.document.writeln('<'+'/script>'); - popwin.document.writeln('<'+'/head>'+ - '<'+'body bgcolor="#FFFFFF">'+ - '<'+'image name="whirly" align="right" src="/adm/lonIcons/'+ - 'lonanim.gif" '+ - 'alt="animated logo" />'+ - '<'+'h3>Search Results Progress<'+'/h3>'+ - '<'+'form name="popremain">'+ - '<'+'tt>'+ - '<'+'br clear="all"/>PLEASE BE PATIENT'+ - '<'+'br />SCANNING $servernum SERVERS'+ - '<'+'br clear="all" />Number of record hits found '+ - '<'+'input type="text" size="10" name="numhits"'+ - ' value="0" />'+ - '<'+'br clear="all" />Time elapsed '+ - '<'+'input type="text" size="10" name="elapsetime"'+ - ' value="0" />'+ - '<'+'br />'+ - 'SERVER GRID (click on any cell for details)'+ - $grid - '<'+'br />'+ - 'Server details '+ - '<'+'input type="text" size="35" name="sdetails"'+ - ' value="" />'+ - '<'+'br />'+ - ' <'+'input type="button" name="button"'+ - ' value="close this window" '+ - ' onClick="javascript:opener.abortsearch()" />'+ - ' <'+'input type="button" name="button"'+ - ' value="help" onClick="javascript:opener.openhelp()" />'+ - '<'+'/tt>'+ - '<'+'/form>'+ - '<'+'/body><'+'/html>'); - popwin.document.close(); - -ENDPOP return $result; } @@ -1888,10 +2318,8 @@ sub filled { ###################################################################### ###################################################################### sub output_blank_field_error { - my ($r)=@_; + my ($r,$closebutton)=@_; # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(\%ENV); - $r->print(< @@ -1903,7 +2331,7 @@ BEGINNING

Search Catalog

-$persistent +$hidden_fields $closebutton @@ -1929,15 +2357,19 @@ RESULTS Output a full html page with an error message. +Inputs: + + $r, the request pointer. + $message, the error message for the user. + $closebutton, the specialized close button needed for groupsearch. + =cut ###################################################################### ###################################################################### sub output_date_error { - my ($r,$message)=@_; + my ($r,$message,$closebutton)=@_; # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(\%ENV); - $r->print(< @@ -1947,7 +2379,7 @@ sub output_date_error {

Search Catalog

-$persistent +$hidden_fields $closebutton @@ -1968,7 +2400,7 @@ RESULTS =item &start_fresh_session() -Cleans the global %hash by removing all fields which begin with +Cleans the global %groupsearch_db by removing all fields which begin with 'pre_' or 'store'. =cut @@ -1976,62 +2408,17 @@ Cleans the global %hash by removing all ###################################################################### ###################################################################### sub start_fresh_session { - delete $hash{'mode_catalog'}; - foreach (keys %hash) { + delete $groupsearch_db{'mode_catalog'}; + foreach (keys %groupsearch_db) { if ($_ =~ /^pre_/) { - delete $hash{$_}; + delete $groupsearch_db{$_}; } if ($_ =~ /^store/) { - delete $hash{$_}; + delete $groupsearch_db{$_}; } } } -###################################################################### -###################################################################### - -=pod - -=item &popwin_js() send javascript to popwin - -=cut - -###################################################################### -###################################################################### -sub popwin_js { - # Print javascript out to popwin, but make sure we dont generate - # any javascript errors in doing so. - my ($r,$text) = @_; - $r->print(<<"END"); - -END - $r->rflush(); -} - -###################################################################### -###################################################################### - -=pod - -=item &popwin_imgupdate() - -Send a given image (and its location) out to the browser. Takes as -input $r, loncapa server id, and an icon URL. - -=cut - -###################################################################### -###################################################################### -sub popwin_imgupdate { - my ($r,$server,$icon) = @_; - &popwin_js($r,'popwin.document.img_'.$Apache::lonnet::hostdom{$server}. - '_'.$server.'.'.'src="/adm/lonIcons/'.$icon.'";'); -} - 1; __END__