--- loncom/interface/lonsearchcat.pm 2002/06/27 14:46:00 1.132
+++ loncom/interface/lonsearchcat.pm 2002/07/16 15:02:06 1.143
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Search Catalog
#
-# $Id: lonsearchcat.pm,v 1.132 2002/06/27 14:46:00 matthew Exp $
+# $Id: lonsearchcat.pm,v 1.143 2002/07/16 15:02:06 matthew Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -40,7 +40,7 @@
=head1 NAME
-lonsearchcat
+lonsearchcat - LONCAPA Search Interface
=head1 SYNOPSIS
@@ -107,17 +107,28 @@ button that closes the search window
=item $importbutton
-button to take the selecte results and go to group sorting
+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
The full path to the (temporary) search database file. This is set and
used in &handler() and is also used in &output_results().
+=item %Views
+
+Hash which associates an output view description with the function
+that produces it. Adding a new view type should be as easy as
+adding a line to the definition of this hash and making sure the function
+takes the proper parameters.
+
+=item $results_db
+
+The name of the database results from searches are put in.
+
=back
=cut
@@ -130,9 +141,16 @@ my $closebutton; # button that closes t
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
+my $results_db = "";
+# 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 );
+
######################################################################
######################################################################
@@ -160,26 +178,29 @@ string that holds portions of the screen
######################################################################
sub handler {
my $r = shift;
- untie %hash;
+ untie %groupsearch_db;
$r->content_type('text/html');
$r->send_http_header;
return OK if $r->header_only;
-
+ ##
+ ## 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";
-
+ $results_db = "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain).
+ '_'.&Apache::lonnet::escape($ENV{'user.name'})."_searchresults.db";
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['catalogmode','launch','acts','mode','form','element',
'reqinterface']);
##
- ## 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');
@@ -212,28 +233,54 @@ END
onClick='javascript:select_group()'>
END
}
- $hidden .= <
-
-
-
-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?
##
- if ($ENV{'form.basicsubmit'} eq 'SEARCH') {
- # Perform basic search and give results
- return &basicsearch($r,$hidden);
- } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {
- # Perform advanced search and give results
- return &advancedsearch($r,$hidden);
- } elsif ($ENV{'form.reqinterface'} eq 'advanced') {
+ my $searchtype;
+ $searchtype = 'Basic' if ($ENV{'form.basicsubmit'} eq 'SEARCH');
+ $searchtype = 'Advanced' if ($ENV{'form.advancedsubmit'} eq 'SEARCH');
+ if ($searchtype) {
+ # We are running a search
+ my ($query,$customquery,$customshow,$libraries) =
+ (undef,undef,undef,undef);
+ my $pretty_string;
+ if ($searchtype eq 'Basic') {
+ ($query,$pretty_string) = &parse_basic_search($r);
+ } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {
+ ($query,$customquery,$customshow,$libraries,$pretty_string)
+ = &parse_advanced_search($r);
+ return OK if (! defined($query));
+ }
+ # 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();
+ # 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).
+ my $reply=&Apache::lonnet::metadata_query($query,$customquery,
+ $customshow,$libraries);
+ $r->rflush();
+ &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
- $r->print(&advanced_search_form($closebutton,$hidden));
- return OK;
- } else {
- # Output normal search interface
- $r->print(&basic_search_form($closebutton,$hidden));
+ if ($ENV{'form.reqinterface'} eq 'advanced') {
+ $r->print(&advanced_search_form($closebutton,$hidden));
+ } else {
+ # Output normal search interface
+ $r->print(&basic_search_form($closebutton,$hidden));
+ }
}
return OK;
}
@@ -284,20 +331,21 @@ ENDDOCUMENT
' ';
# $scrout.=&simplecheckbox('allversions',$ENV{'form.allversions'});
# $scrout.='Search historic archives';
- $scrout.=<
\n";
@@ -395,10 +438,17 @@ ENDHEADER
undef,
(&Apache::loncommon::filecategories()));
$ENV{'form.language'}='any' unless length($ENV{'form.language'});
- #
+ #----------------------------------------------------------------
# Allow restriction to multiple domains.
# I make the crazy assumption that there will never be a domain 'any'.
#
+ $ENV{'form.domains'} = 'any' if (! exists($ENV{'form.domains'}));
+ my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}}
+ : ($ENV{'form.domains'}) );
+ my %domain_hash = ();
+ foreach (@allowed_domains) {
+ $domain_hash{$_}++;
+ }
my @domains =&Apache::loncommon::get_domains();
# adjust the size of the select box
my $size = 4;
@@ -407,18 +457,19 @@ ENDHEADER
if ((scalar @domains) == 1) {
$scrout .=''."\n";
} else {
- $scrout.=''.
+ $scrout.="\n".''.
'DOMAINS '.
'\n";
}
- #
- #
- #
+ #----------------------------------------------------------------
$scrout.=&selectbox('Limit by language','language',
$ENV{'form.language'},'any','Any Language',
\&{Apache::loncommon::languagedescription},
@@ -517,23 +568,26 @@ to be somewhat persistent.
######################################################################
sub make_persistent {
+ my %save = %{shift()};
my $persistent='';
- foreach (keys %ENV) {
- if (/^form\./ && !/submit/) {
- my $name=$_;
- my $key=$name;
- $ENV{$key}=~s/\'//g; # do not mess with html field syntax
+ foreach my $name (keys %save) {
+ if ($name =~ /^form\./ && $name !~ /submit/) {
+ my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
$name=~s/^form\.//;
- $persistent.=<
+ foreach (@values) {
+ s/\"/\'/g; # do not mess with html field syntax
+ next if (! $_ );
+ $persistent.=<
END
+ }
}
}
return $persistent;
}
-
######################################################################
+# HTML form building functions #
######################################################################
=pod
@@ -542,6 +596,13 @@ END
=over 4
+=cut
+
+###############################################
+###############################################
+
+=pod
+
=item &simpletextfield()
Inputs: $name,$value,$size
@@ -549,6 +610,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
@@ -556,91 +634,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 = ".
+ &Apache::loncommon::languagedescription($ENV{'form.language'}).
+ " \n";
}
if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') {
push @queries,"(copyright like \"$ENV{'form.copyright'}\")";
+ $pretty_search_string.=$font."copyright = ".
+ &Apache::loncommon::copyrightdescription($ENV{'form.copyright'}).
+ " \n";
}
+ #
# Evaluate date windows
my $datequery=&build_date_queries(
$ENV{'form.creationdatestart_month'},
@@ -792,25 +993,30 @@ sub advancedsearch {
# Test to see if date windows are legitimate
if ($datequery=~/^Incorrect/) {
&output_date_error($r,$datequery);
- return OK;
- }
- elsif ($datequery) {
+ return ;
+ } elsif ($datequery) {
+ # Here is where you would set up pretty_search_string to output
+ # date query information.
push @queries,$datequery;
}
# Process form information for custom metadata querying
- my $customquery='';
+ my $customquery=undef;
if ($ENV{'form.custommetadata'}) {
+ $pretty_search_string .=$font."Custom Metadata Search: ".
+ $ENV{'form.custommetadata'}." \n";
$customquery=&build_custommetadata_query('custommetadata',
$ENV{'form.custommetadata'});
}
- my $customshow='';
+ my $customshow=undef;
if ($ENV{'form.customshow'}) {
+ $pretty_search_string .=$font."Custom Metadata Display: ".
+ $ENV{'form.customshow'}." \n";
$customshow=$ENV{'form.customshow'};
$customshow=~s/[^\w\s]//g;
my @fields=split(/\s+/,$customshow);
$customshow=join(" ",@fields);
}
- ##
+ ## ---------------------------------------------------------------
## Deal with restrictions to given domains
##
my $libraries_to_query = undef;
@@ -819,52 +1025,37 @@ sub advancedsearch {
my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}}
: ($ENV{'form.domains'}) );
my %domain_hash = ();
+ my $pretty_domains_string;
foreach (@allowed_domains) {
$domain_hash{$_}++;
}
- foreach (keys(%Apache::lonnet::libserv)) {
- if ($_ eq 'any') {
- $libraries_to_query = undef;
- last;
+ if ($domain_hash{'any'}) {
+ $pretty_domains_string = "Searching all domains.";
+ } else {
+ if (@allowed_domains > 1) {
+ $pretty_domains_string = "Searching domains:";
+ } else {
+ $pretty_domains_string = "Searching domain ";
}
- if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {
- push @$libraries_to_query,$_;
+ foreach (sort @allowed_domains) {
+ $pretty_domains_string .= "$_ ";
+ }
+ foreach (keys(%Apache::lonnet::libserv)) {
+ if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {
+ push @$libraries_to_query,$_;
+ }
}
}
- if (defined($libraries_to_query)) {
- &Apache::lonnet::logthis("libraries: @$libraries_to_query");
- } else {
- &Apache::lonnet::logthis("libraries: undef");
- }
+ $pretty_search_string .= $pretty_domains_string." \n";
#
- # 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).
if (@queries) {
$query=join(" AND ",@queries);
$query="select * from metadata where $query";
- my $reply; # reply hash reference
- unless ($customquery or $customshow) {
- $reply=&Apache::lonnet::metadata_query($query,undef,undef,
- $libraries_to_query);
- }
- else {
- $reply=&Apache::lonnet::metadata_query($query,
- $customquery,$customshow,
- $libraries_to_query);
- }
- &output_results('Advanced',$r,$customquery,$reply,$hidden);
- return OK;
} elsif ($customquery) {
- my $reply; # reply hash reference
- $reply=&Apache::lonnet::metadata_query('',
- $customquery,$customshow,
- $libraries_to_query);
- &output_results('Advanced',$r,$customquery,$reply,$hidden);
- return OK;
+ $query = '';
}
- # should not get to this point
- return 'Error. Should not have gone to this point.';
+ return ($query,$customquery,$customshow,$libraries_to_query,
+ $pretty_search_string);
}
######################################################################
@@ -872,16 +1063,16 @@ sub advancedsearch {
=pod
-=item &basicsearch()
+=item &parse_basic_search()
-Parse basic search form.
+Parse the basic search form and return a scalar containing an sql query.
=cut
######################################################################
######################################################################
-sub basicsearch {
- my ($r,$hidden)=@_;
+sub parse_basic_search {
+ my ($r)=@_;
# Clean up fields for safety
for my $field ('basicexp') {
$ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g;
@@ -898,27 +1089,62 @@ sub basicsearch {
&output_blank_field_error($r);
return OK;
}
-
+ my $pretty_search_string = ''.$ENV{'form.basicexp'}.'';
+ my $search_string = $ENV{'form.basicexp'};
+ if ($ENV{'form.related'}) {
+ my @New_Words;
+ ($search_string,@New_Words) = &related_version($ENV{'form.basicexp'});
+ if (@New_Words) {
+ $pretty_search_string .= " with related words: @New_Words.";
+ } else {
+ $pretty_search_string .= " with no related words.";
+ }
+ }
+ &Apache::lonnet::logthis("Search String: $search_string");
# Build SQL query string based on form page
my $query='';
my $concatarg=join('," ",',
('title', 'author', 'subject', 'notes', 'abstract',
'keywords'));
$concatarg='title' if $ENV{'form.titleonly'};
+ $query=&build_SQL_query('concat('.$concatarg.')',$search_string);
+ $pretty_search_string .= " \n";
+ return 'select * from metadata where '.$query,$pretty_search_string;
+}
- $query=&build_SQL_query('concat('.$concatarg.')',$ENV{'form.'.'basicexp'});
- # Get reply (either a hash reference to filehandles or bad connection)
-# &Apache::lonnet::logthis("metadata query started:".time);
- my $reply=&Apache::lonnet::metadata_query('select * from metadata where '.$query);
-# &Apache::lonnet::logthis("metadata query finished:".time);
- # Output search results
+######################################################################
+######################################################################
- &output_results('Basic',$r,$query,$reply,$hidden);
+=pod
- return OK;
-}
+=item &related_version
+
+Modifies an input string to include related words. Words in the string
+are replaced with parenthesized lists of 'OR'd words. For example
+"torque" is replaced with "(torque OR word1 OR word2 OR ...)".
+Note: Using this twice on a string is probably silly.
+
+=cut
+
+######################################################################
+######################################################################
+sub related_version {
+ my $search_string = shift;
+ my $result = $search_string;
+ my %New_Words = ();
+ while ($search_string =~ /(\w+)/cg) {
+ my $word = $1;
+ next if (lc($word) =~ /\b(or|and|not)\b/);
+ my @Words = &Apache::loncommon::get_related_words($word);
+ @Words = ($#Words>4? @Words[0..4] : @Words);
+ foreach (@Words) { $New_Words{$_}++;}
+ my $replacement = join " OR ", ($word,@Words);
+ $result =~ s/(\b)$word(\b)/$1($replacement)$2/g;
+ }
+ return $result,sort(keys(%New_Words));
+}
######################################################################
######################################################################
@@ -1106,20 +1332,29 @@ contacted, etc.)
sub output_results {
# &Apache::lonnet::logthis("output_results:".time);
my $fnum; # search result counter
- my ($mode,$r,$query,$replyref,$hidden)=@_;
+ my ($mode,$r,$replyref,$hidden)=@_;
my %rhash=%{$replyref};
my $compiledresult='';
my $timeremain=300; # (seconds)
my $elapsetime=0;
my $resultflag=0;
my $tflag=1;
- my $viewselect=$ENV{'form.viewselect'};
+ ##
+ ## Set viewing function
+ ##
+ my $viewfunction = $Views{$ENV{'form.viewselect'}};
+ if (!defined($viewfunction)) {
+ $r->print("Internal Error - Bad view selected.\n");
+ $r->rflush();
+ return;
+ }
#
# make query information persistent to allow for subsequent revision
- my $persistent=&make_persistent();
- # spit out the results header
- $r->print(&search_results_header($mode));
+ my $persistent=&make_persistent(\%ENV);
+ #
+ # Begin producing output
$r->rflush();
+ #
# begin showing the cataloged results
my $action = "/adm/searchcat";
if ($mode eq 'Basic') {
@@ -1140,7 +1375,6 @@ $persistent
CATALOGCONTROLS
#
# make the pop-up window for status
- #
$r->print(&make_popwin(%rhash));
$r->rflush();
##
@@ -1217,12 +1451,13 @@ CATALOGCONTROLS
} # 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 ($extrashow,$customfields,$customhash) =
+ &handle_custom_fields(\@results);
my @customfields = @$customfields;
my %customhash = %$customhash;
- untie %hash if (keys %hash);
+ untie %groupsearch_db if (tied %groupsearch_db);
#
- if (! tie(%hash,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) {
+ if (! tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) {
$r->print('Unable to tie hash to db '.
'file');
} else {
@@ -1234,6 +1469,21 @@ CATALOGCONTROLS
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) {
@@ -1255,8 +1505,8 @@ END
}
if ($ENV{'form.catalogmode'} eq 'groupsearch') {
$fnum+=0;
- $hash{"pre_${fnum}_link"}=$Fields{'url'};
- $hash{"pre_${fnum}_title"}=$Fields{'title'};
+ $groupsearch_db{"pre_${fnum}_link"}=$Fields{'url'};
+ $groupsearch_db{"pre_${fnum}_title"}=$Fields{'title'};
$compiledresult.=<
$fnum++;
}
- if ($viewselect eq 'Detailed Citation View') {
- $compiledresult.=&detailed_citation_view
- (%Fields, hostname => $rkey );
- }
- elsif ($viewselect eq 'Summary View') {
- $compiledresult.=&summary_view
- (%Fields, hostname => $rkey );
- }
- elsif ($viewselect eq 'Fielded Format') {
- $compiledresult.=&fielded_format_view
- (%Fields, hostname => $rkey );
- }
- elsif ($viewselect eq 'XML/SGML') {
- $compiledresult.=&xml_sgml_view
- (%Fields, hostname => $rkey );
- }
+ # Render the result into html
+ $compiledresult.= &$viewfunction(%Fields, hostname => $rkey );
if ($compiledresult or $servercount!=$servernum) {
$compiledresult.="";
}
}
- untie %hash;
+ untie %groupsearch_db;
}
if ($compiledresult) {
$resultflag=1;
$r->print($compiledresult);
}
- my $percent=sprintf('%3.0f',($servercount/$servernum*100));
} # 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->rflush();
+ $r->print(''.
+ "\n");
$r->print("\n\n");
+ $r->rflush();
return;
}
@@ -1365,6 +1602,9 @@ sub parse_raw_result {
&Apache::loncommon::copyrightdescription($Fields{'copyright'});
$Fields{'mimetag'} =
&Apache::loncommon::filedescription($Fields{'mime'});
+ if ($Fields{'author'}=~/^(\s*|error)$/) {
+ $Fields{'author'}="Unknown Author";
+ }
# Put spaces in the keyword list, if needed.
$Fields{'keywords'}=~ s/,([A-z])/, $1/g;
if ($Fields{'title'}=~ /^\s*$/ ) {
@@ -1469,7 +1709,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') {
@@ -1571,6 +1811,9 @@ SCRIPT