--- loncom/interface/lonsearchcat.pm 2002/06/25 15:08:59 1.129 +++ loncom/interface/lonsearchcat.pm 2002/07/08 20:35:36 1.139 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Search Catalog # -# $Id: lonsearchcat.pm,v 1.129 2002/06/25 15:08:59 matthew Exp $ +# $Id: lonsearchcat.pm,v 1.139 2002/07/08 20:35:36 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -107,7 +107,7 @@ 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 @@ -118,6 +118,13 @@ The ubiquitous database hash 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. + =back =cut @@ -133,6 +140,12 @@ my $importbutton; # button to take the s my %hash; # 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 ); + ###################################################################### ###################################################################### @@ -212,28 +225,49 @@ 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,\%ENV,$hidden); - } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') { - # Perform advanced search and give results - return &advancedsearch($r,\%ENV,$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); + if ($searchtype eq 'Basic') { + $query = &parse_basic_search($r); + } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') { + ($query,$customquery,$customshow,$libraries) + = &parse_advanced_search($r); + 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). + $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 - $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; } @@ -273,7 +307,7 @@ sub basic_search_form{ $hidden

Basic Search

-Enter terms or quoted phrases separated by AND, OR, or NOT +Enter terms or phrases separated by AND, OR, or NOT then press SEARCH below.

@@ -284,21 +318,18 @@ ENDDOCUMENT ' '; # $scrout.=&simplecheckbox('allversions',$ENV{'form.allversions'}); # $scrout.='Search historic archives'; - $scrout.=<Advanced Search

   $closebutton - - - +END + $scrout.=&selectbox(undef,'viewselect', + $ENV{'form.viewselect'}, + undef,undef,undef, + sort(keys(%Views))); + $scrout.=<

@@ -328,18 +359,12 @@ sub advanced_search_form{ $closebutton - - -

END + if (!defined($ENV{'form.viewselect'})) { + $ENV{'form.viewselect'} ="Detailed Citation View"; + } my $scrout=<<"ENDHEADER"; @@ -356,28 +381,27 @@ END

Advanced Catalog Search


-Enter terms or quoted phrases separated by search operators +Enter terms or phrases separated by search operators such as AND, OR, or NOT.
+
$advanced_buttons $hidden + +\n"; + $scrout.=&searchphrasefield('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('URL', 'url' ,$ENV{'form.url'}); + $scrout.=&searchphrasefield('notes', 'notes' ,$ENV{'form.notes'}); + $scrout.=&searchphrasefield('abstract','abstract',$ENV{'form.abstract'}); # Hack - an empty table row. $scrout.="\n"; $scrout.=&searchphrasefield('file
extension','mime', @@ -386,13 +410,45 @@ ENDHEADER $scrout.=&searchphrasefield('publisher
owner','owner', $ENV{'form.owner'}); $scrout.="
VIEW: ENDHEADER - $scrout.=&searchphrasefield('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('URL','url', - $ENV{'form.url'}); -# $scrout.=&searchphrasefield('Limit by version','version', -# $ENV{'form.version'}); - $scrout.=&searchphrasefield('notes','notes', - $ENV{'form.notes'}); - $scrout.=&searchphrasefield('abstract','abstract', - $ENV{'form.abstract'}); + $scrout.=&selectbox(undef,'viewselect', + $ENV{'form.viewselect'}, + undef,undef,undef, + sort(keys(%Views))); + $scrout.="
  
\n"; -# $ENV{'form.mime'}='any' unless length($ENV{'form.mime'}); -# $scrout.=&selectbox('Limit by MIME type','mime', -# $ENV{'form.mime'}, -# 'any','Any type', -# \&{Apache::loncommon::filedescriptionex}, -# (&Apache::loncommon::fileextensions)); + $ENV{'form.category'}='any' unless length($ENV{'form.category'}); + $scrout.=&selectbox('File Category','category', + $ENV{'form.category'}, + 'any','Any category', + 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; + 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"; + } + #---------------------------------------------------------------- $scrout.=&selectbox('Limit by language','language', $ENV{'form.language'},'any','Any Language', \&{Apache::loncommon::languagedescription}, @@ -491,16 +547,19 @@ to be somewhat persistent. ###################################################################### sub make_persistent { + my %save = %{shift()}; my $persistent=''; - foreach (keys %ENV) { + foreach (keys %save) { if (/^form\./ && !/submit/) { my $name=$_; - my $key=$name; - $ENV{$key}=~s/\'//g; # do not mess with html field syntax + my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name})); $name=~s/^form\.//; - $persistent.=< + foreach (@values) { + s/\"/\'/g; # do not mess with html field syntax + $persistent.=< END + } } } return $persistent; @@ -554,7 +613,8 @@ Inputs: =item $title -Printed above the select box, in uppercase. +Printed above the select box, in uppercase. If undefined, only a select +box will be returned, with no additional html. =item $name @@ -562,12 +622,12 @@ The name element of the '; - foreach ($anyvalue,@idlist) { + my $selout=''; + if (defined($title)) { + my $uctitle=uc($title); + $selout="\n".'

'. + ''.$uctitle.': '; + } + $selout .= '

'; + return $selout.''.(defined($title)?'

':' '); } ###################################################################### @@ -684,17 +749,28 @@ sub selectbox { =pod -=item &advancedsearch() +=item &parse_advanced_search() + +Parse advanced search form and return the following: + +=over 4 + +=item $query Scalar containing an SQL query. + +=item $customquery Scalar containing a custom query. -Parse advanced search results. +=item $customshow Scalar containing commands to show custom metadata. + +=item $libraries_to_query Reference to array of domains to search. + +=back =cut ###################################################################### ###################################################################### -sub advancedsearch { - my ($r,$envhash,$hidden)=@_; - my %ENV=%{$envhash}; +sub parse_advanced_search { + my ($r)=@_; my $fillflag=0; # Clean up fields for safety for my $field ('title','author','subject','keywords','url','version', @@ -705,7 +781,7 @@ sub advancedsearch { 'lastrevisiondatestart_year','lastrevisiondateend_month', 'lastrevisiondateend_day','lastrevisiondateend_year', 'notes','abstract','mime','language','owner', - 'custommetadata','customshow') { + 'custommetadata','customshow','category') { $ENV{"form.$field"}=~s/[^\w\/\s\(\)\=\-\"\']//g; } foreach ('mode','form','element') { @@ -714,6 +790,12 @@ sub advancedsearch { $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"}); $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g; } + # Preprocess the category form element. + if ($ENV{'form.category'} ne 'any') { + my @extensions = &Apache::loncommon::filecategorytypes + ($ENV{'form.category'}); + $ENV{'form.mime'} = join ' OR ',@extensions; + } # Check to see if enough information was filled in for my $field ('title','author','subject','keywords','url','version', 'notes','abstract','mime','language','owner', @@ -724,7 +806,7 @@ sub advancedsearch { } unless ($fillflag) { &output_blank_field_error($r); - return OK; + return ; } # Turn the form input into a SQL-based query my $query=''; @@ -734,15 +816,16 @@ sub advancedsearch { 'keywords','version','owner','mime') { if ($ENV{'form.'.$field}) { push @queries,&build_SQL_query($field,$ENV{'form.'.$field}); - } + } + } + # I dislike the hack below. + if ($ENV{'form.category'}) { + $ENV{'form.mime'}=''; } # Evaluate option lists if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') { push @queries,"(language like \"$ENV{'form.language'}\")"; } -# if ($ENV{'form.mime'} and $ENV{'form.mime'} ne 'any') { -# push @queries,"(mime like \"$ENV{'form.mime'}\")"; -# } if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') { push @queries,"(copyright like \"$ENV{'form.copyright'}\")"; } @@ -764,49 +847,53 @@ sub advancedsearch { # Test to see if date windows are legitimate if ($datequery=~/^Incorrect/) { &output_date_error($r,$datequery); - return OK; + return ; } elsif ($datequery) { push @queries,$datequery; } # Process form information for custom metadata querying - my $customquery=''; + my $customquery=undef; if ($ENV{'form.custommetadata'}) { $customquery=&build_custommetadata_query('custommetadata', $ENV{'form.custommetadata'}); } - my $customshow=''; + my $customshow=undef; if ($ENV{'form.customshow'}) { $customshow=$ENV{'form.customshow'}; $customshow=~s/[^\w\s]//g; my @fields=split(/\s+/,$customshow); $customshow=join(" ",@fields); } - # 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). + ## --------------------------------------------------------------- + ## Deal with restrictions to given domains + ## + my $libraries_to_query = undef; + # $ENV{'form.domains'} can be either a scalar or an array reference. + # We need an array. + my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}} + : ($ENV{'form.domains'}) ); + my %domain_hash = (); + foreach (@allowed_domains) { + $domain_hash{$_}++; + } + foreach (keys(%Apache::lonnet::libserv)) { + if ($_ eq 'any') { + $libraries_to_query = undef; + last; + } + if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) { + push @$libraries_to_query,$_; + } + } + # 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); - } - else { - $reply=&Apache::lonnet::metadata_query($query, - $customquery,$customshow); - } - &output_results('Advanced',$r,$envhash,$customquery,$reply,$hidden); - return OK; } elsif ($customquery) { - my $reply; # reply hash reference - $reply=&Apache::lonnet::metadata_query('', - $customquery,$customshow); - &output_results('Advanced',$r,$envhash,$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); } ###################################################################### @@ -814,17 +901,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,$envhash,$hidden)=@_; - my %ENV=%{$envhash}; +sub parse_basic_search { + my ($r)=@_; # Clean up fields for safety for my $field ('basicexp') { $ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g; @@ -850,16 +936,7 @@ sub basicsearch { $concatarg='title' if $ENV{'form.titleonly'}; $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,$envhash,$query,$reply,$hidden); - - return OK; + return 'select * from metadata where '.$query; } @@ -1049,27 +1126,31 @@ contacted, etc.) sub output_results { # &Apache::lonnet::logthis("output_results:".time); my $fnum; # search result counter - my ($mode,$r,$envhash,$query,$replyref,$hidden)=@_; - my %ENV=%{$envhash}; + my ($mode,$r,$replyref,$hidden)=@_; my %rhash=%{$replyref}; my $compiledresult=''; my $timeremain=300; # (seconds) my $elapsetime=0; my $resultflag=0; my $tflag=1; + ## + ## 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 generic header - $r->print(&search_results_header()); + my $persistent=&make_persistent(\%ENV); + # + # Begin producing output + $r->print(&search_results_header($mode)); $r->rflush(); + # # begin showing the cataloged results - $r->print(< - - -

Search Catalog

-CATALOGBEGIN my $action = "/adm/searchcat"; if ($mode eq 'Basic') { $action .= "?reqinterface=basic"; @@ -1086,21 +1167,9 @@ $importbutton $closebutton $persistent
-

Search Query

CATALOGCONTROLS # - # Remind them what they searched for - # - if ($mode eq 'Basic') { - $r->print('

Basic search: '.$ENV{'form.basicexp'}.'

'); - } elsif ($mode eq 'Advanced') { - $r->print('

Advanced search '.$query.'

'); - } - $r->print('

Search Results

'); - $r->rflush(); - # # make the pop-up window for status - # $r->print(&make_popwin(%rhash)); $r->rflush(); ## @@ -1177,7 +1246,8 @@ 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); @@ -1194,6 +1264,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) { @@ -1202,9 +1287,6 @@ CATALOGCONTROLS $Fields{'extrashow'}=~s/\<\!\-\- $field \-\-\>/ $value/g; } } - if ($compiledresult or $servercount!=$servernum) { - $compiledresult.="
"; - } $compiledresult.="\n

\n"; if ($ENV{'form.catalogmode'} eq 'interactive') { my $titleesc=$Fields{'title'}; @@ -1231,29 +1313,11 @@ END # $fnum++; } - my $viewselect; - if ($mode eq 'Basic') { - $viewselect=$ENV{'form.basicviewselect'}; - } - elsif ($mode eq 'Advanced') { - $viewselect=$ENV{'form.advancedviewselect'}; - } - 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; } @@ -1261,14 +1325,15 @@ END $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; } @@ -1332,6 +1397,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*$/ ) { @@ -1402,10 +1470,18 @@ sub handle_custom_fields { =item &search_results_header -Output the proper javascript code to deal with different calling modes. +Output the proper html headers and javascript code to deal with different +calling modes. + +Takes most inputs directly from %ENV, except $mode. -Takes inputs directly from from %ENV. The following environment variables -are checked: +=over 4 + +=item $mode is either (at this writing) 'Basic' or 'Advanced' + +=back + +The following environment variables are checked: =over 4 @@ -1428,12 +1504,20 @@ Checked for existance & 'edit' mode. ###################################################################### ###################################################################### sub search_results_header { + my ($mode) = @_; + $mode = lc($mode); + my $title; + if ($mode eq 'advanced') { + $title = "Advanced Search Results"; + } elsif ($mode eq 'basic') { + $title = "Basic Search Results"; + } my $result = ''; # output beginning of search page $result.=< -The LearningOnline Network with CAPA +$title BEGINNING # conditional output of script functions dependent on the mode in # which the search was invoked @@ -1516,6 +1600,12 @@ SCRIPT } SCRIPT + $result.=< + + +

$title

+END return $result; } @@ -1541,16 +1631,13 @@ sub make_popwin { # rows of 10 each. No longer used to index images. my $sn=1; foreach my $sk (sort keys %rhash) { - # '$values{'owner'}, last revised $values{'lastrevisiondate'}

$values{'title'}

-

$values{'author'}

-

-Subject: $values{'subject'}
-Keyword(s): $values{'keywords'}
-Notes: $values{'notes'}
-MIME Type: -END - $result.=&Apache::loncommon::filedescription($values{'mime'}); - $result.=< -Language: -END - $result.=&Apache::loncommon::languagedescription($values{'lang'}); - $result.=< -Copyright/Distribution: -END - $result.=&Apache::loncommon::copyrightdescription($values{'copyright'}); - $result.=< +$values{'author'}, $values{'owner'}
+ +Subject: $values{'subject'}
+Keyword(s): $values{'keywords'}
+Notes: $values{'notes'}
+MIME Type: $values{'mimetag'}
+Language: $values{'language'}
+Copyright/Distribution: $values{'cprtag'}

$values{'extrashow'}

@@ -1816,7 +1890,7 @@ sub filled { sub output_blank_field_error { my ($r)=@_; # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(); + my $persistent=&make_persistent(\%ENV); $r->print(< @@ -1862,7 +1936,7 @@ Output a full html page with an error me sub output_date_error { my ($r,$message)=@_; # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(); + my $persistent=&make_persistent(\%ENV); $r->print(<