--- loncom/interface/lonsearchcat.pm 2001/04/02 16:57:38 1.92
+++ loncom/interface/lonsearchcat.pm 2006/03/15 20:56:16 1.256
@@ -1,1190 +1,3733 @@
-# The LearningOnline Network
+# The LearningOnline Network with CAPA
# Search Catalog
#
-# 03/08/2001 Scott Harrison
-# Scott Harrison: 03/12/2001, 03/13/2001, 03/14/2001, 03/15/2001, 03/19/2001
-# Scott Harrison: 03/20/2001, 03/21/2001, 03/22/2001, 03/26/2001, 03/27/2001
-# Scott Harrison: 04/02/2001
+# $Id: lonsearchcat.pm,v 1.256 2006/03/15 20:56:16 albertel Exp $
#
-# Functions
+# Copyright Michigan State University Board of Trustees
#
-# handler(server reference) : interacts with the Apache server layer
-# (for /adm/searchcat URLs)
-# simpletextfield(name,value) : returns HTML formatted string for simple text
-# field
-# simplecheckbox(name,value) : returns HTML formatted string for simple
-# checkbox
-# searchphrasefield(title,name,value) : returns HTML formatted string for
-# a search expression phrase field
-# dateboxes(name, defaultmonth, defaultday, defaultyear) : returns HTML
-# formatted string
-# for a calendar date
-# selectbox(title,name,value,%HASH=options) : returns HTML formatted string for
-# a selection box field
-# advancedsearch(server reference, environment reference) : perform a complex
-# multi-field logical query
-# filled(field) : determines whether a given field has been filled
-# basicsearch(server reference, environment reference) : perform a simple
-# single-field logical query
-# output_blank_field_error(server reference) : outputs a message saying that
-# more fields need to be filled in
-# output_results(output mode,
-# server reference,
-# environment reference,
-# reply list reference) : outputs results from search
-# build_SQL_query(field name, logic) : builds a SQL query string from a
-# logical expression with AND/OR keywords
-# recursive_SQL_query_build(field name, reverse notation expression) :
-# builds a SQL query string from a reverse notation expression
-# logical expression with AND/OR keywords
-# build_custommetadata_query(field_name, logic_statement) : builds a perl
-# regular expression from a logical expression with AND/OR
-# keywords
-# detailed_citation_view, summary_view, fielded_format_view, xml_sgml_view:
-# four different ways to view metadata records. Outputs a HTML-ified string.
-# Input arguments are title, author, subject, url, keywords, version, notes,
-# short abstract, mime, language, creation date, last revision date, owner,
-# copyright, hostname, httphost, and extra custom metadata to show.
-# build_date_queries(cmonth1, cday1, cyear1, cmonth2, cday2, cyear2,
-# lmonth1, lday1, lyear1, lmonth2, lday2, lyear2) :
-# Builds a SQL logic query to check time/date entries.
-# output_date_error(server reference, error message) : outputs
-# an error message specific to bad date format.
-# make_persistent() : makes a set of hidden HTML fields to make
-# SQL search interface information to be persistent
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
+###############################################################################
+###############################################################################
+
+=pod
+
+=head1 NAME
+
+lonsearchcat - LONCAPA Search Interface
+
+=head1 SYNOPSIS
+
+Search interface to LON-CAPAs digital library
+
+=head1 DESCRIPTION
+
+This module enables searching for a distributed browseable catalog.
+
+This is part of the LearningOnline Network with CAPA project
+described at http://www.lon-capa.org.
+
+lonsearchcat presents the user with an interface to search the LON-CAPA
+digital library. lonsearchcat also initiates the execution of a search
+by sending the search parameters to LON-CAPA servers. The progress of
+search (on a server basis) is displayed to the user in a separate window.
+
+=head1 Internals
+
+=over 4
+
+=cut
+
+###############################################################################
+###############################################################################
package Apache::lonsearchcat;
use strict;
-use Apache::Constants qw(:common);
-use Apache::lonnet();
+use Apache::Constants qw(:common :http);
+use Apache::lonnet;
use Apache::File();
use CGI qw(:standard);
use Text::Query;
+use GDBM_File;
+use Apache::loncommon();
+use Apache::lonmysql();
+use Apache::lonmeta;
+use Apache::lonhtmlcommon;
+use Apache::lonlocal;
+use LONCAPA::lonmetadata();
+use HTML::Entities();
+use Parse::RecDescent;
+use Apache::lonnavmaps;
+use Apache::lonindexer();
+
+######################################################################
+######################################################################
+##
+## Global variables
+##
+######################################################################
+######################################################################
+my %groupsearch_db; # Database hash used to save values for the
+ # groupsearch RAT interface.
+my %persistent_db; # gdbm hash which holds data which is supposed to
+ # persist across calls to lonsearchcat.pm
+
+# The different view modes and associated functions
+
+my %Views = ("detailed" => \&detailed_citation_view,
+ "detailedpreview" => \&detailed_citation_preview,
+ "summary" => \&summary_view,
+ "summarypreview" => \&summary_preview,
+ "fielded" => \&fielded_format_view,
+ "xml" => \&xml_sgml_view,
+ "compact" => \&compact_view);
-# ---------------------------------------- variables used throughout the module
-my %language;
-my $scrout;
-my %metadatafields;
-my %cprtag;
-my %mimetag;
-my $closebutton;
-
-# ------ form selection elements that allow for choosing different output views
-# Detailed Citation View ---> sub detailed_citationview
-# Summary View ---> sub summary_view
-# Fielded Format ---> sub fielded_format_view
-# XML/SGML ---> sub xml_sgml_view
-my $basicviewselect=< '.&mt('No matches found in resources').'. '.&mt('No matches found in postings').'.
-LIMIT BY CREATION DATE RANGE:
-
-
-LIMIT BY LAST REVISION DATE RANGE:
-
-
+
+
'.&mt('Course content').':
');
+ $r->rflush();
+# ======================================================= Go through the course
+ my $c=$r->connection;
+ if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db",
+ &GDBM_READER(),0640)) {
+ foreach (sort(keys(%hash))) {
+ if ($c->aborted()) { last; }
+ if (($_=~/^src\_(.+)$/)) {
+ if ($hash{'randomout_'.$1} & !$env{'request.role.adv'}) {
+ next;
+ }
+ my $symb=&make_symb($1);
+ &checkonthis($r,$1,$hash{$_},0,&Apache::lonnet::gettitle($symb),
+ $fulltext,$symb,@allwords);
+ }
+ }
+ untie(%hash);
}
- elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {
- return &advancedsearch($r,\%ENV);
+ unless ($totalfound) {
+ $r->print('
'.&mt('Discussion postings').':
');
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ my @allres=$navmap->retrieveResources();
+ my %discussiontime = &Apache::lonnet::dump('discussiontimes',
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+ foreach my $resource (@allres) {
+ my $result = '';
+ my $applies = 0;
+ my $symb = $resource->symb();
+ my $ressymb = $symb;
+ if ($symb =~ m#(___adm/\w+/\w+)/(\d+)/bulletinboard$#) {
+ $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
+ unless ($ressymb =~ m#bulletin___\d+___adm/wrapper#) {
+ $ressymb=~s#(bulletin___\d+___)#$1adm/wrapper/#;
+ }
+ }
+ if (defined($discussiontime{$ressymb})) {
+ my %contrib = &Apache::lonnet::restore($ressymb,$env{'request.course.id'},
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+ if ($contrib{'version'}) {
+ for (my $id=1;$id<=$contrib{'version'};$id++) {
+ unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
+ if ($contrib{$id.':subject'}) {
+ $result .= $contrib{$id.':subject'};
+ }
+ if ($contrib{$id.':message'}) {
+ $result .= $contrib{$id.':message'};
+ }
+ if ($contrib{$id,':attachmenturl'}) {
+ if ($contrib{$id,':attachmenturl'} =~ m-/([^/]+)$-) {
+ $result .= $1;
+ }
+ }
+ $applies = &checkwords($result,$applies,@allwords);
+ }
+ }
+ }
+ }
+# Does this discussion apply?
+ if ($applies) {
+ my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ressymb);
+ my $disctype = &mt('resource');
+ if ($url =~ m#/bulletinboard$#) {
+ if ($url =~m#^adm/wrapper/adm/.*/bulletinboard$#) {
+ $url =~s#^adm/wrapper##;
+ }
+ $disctype = &mt('bulletin board');
+ } else {
+ $url = '/res/'.$url;
+ }
+ if ($url =~ /\?/) {
+ $url .= '&symb=';
+ } else {
+ $url .= '?symb=';
+ }
+ $url .= &Apache::lonnet::escape($resource->symb());
+ my $title = $resource->compTitle();
+ $r->print('
'.
+ ($title?$title:$url).' - '.$disctype.'
');
+ $totaldiscussions++;
+ } else {
+ $r->print(' .');
+ }
+ }
+ unless ($totaldiscussions) {
+ $r->print('
');
+ for (my $i=0;$i<=$level*5;$i++) {
+ $r->print(' ');
+ }
+ my $href=$url;
+ if ($hash{'encrypted_'.$id} && !$env{'request.role.adv'}) {
+ $href=&Apache::lonenc::encrypted($href)
+ .'?symb='.&Apache::lonenc::encrypted($symb);
+ } else {
+ $href.='?symb='.&Apache::lonnet::escape($symb);
+ }
+ $r->print(''.($title?$title:$url).
+ '
');
+ $totalfound++;
+ } elsif ($fulltext) {
+ $r->print(' .');
+ }
+ $r->rflush();
+# Check also the dependencies of this one
+ my $dependencies=
+ &Apache::lonnet::metadata($url,'dependencies');
+ foreach (split(/\,/,$dependencies)) {
+ if (($_=~/^\/res\//) && (!$alreadyseen{$id})) {
+ &checkonthis($r,$id,$_,$level+1,'',$fulltext,undef,@allwords);
+ }
+ }
+}
- $scrout.=&searchphrasefield('Limit by version','version',
- $ENV{'form.version'});
+sub checkwords {
+ my ($result,$applies,@allwords) = @_;
+ foreach (@allwords) {
+ if ($_=~/\w/) {
+ if ($result=~/$_/si) {
+ $applies++;
+ }
+ }
+ }
+ return $applies;
+}
- $scrout.=&searchphrasefield('Limit by notes','notes',
- $ENV{'form.notes'});
+sub untiehash {
+ if (tied(%hash)) {
+ untie(%hash);
+ }
+}
- $scrout.=&searchphrasefield('Limit by abstract','abstract',
- $ENV{'form.abstract'});
+} # End of course search scoping
- $ENV{'form.mime'}='notxxx' unless length($ENV{'form.mime'});
- $scrout.=&selectbox('Limit by MIME type','mime',
- $ENV{'form.mime'},%mimetag);
- $ENV{'form.language'}='any' unless length($ENV{'form.language'});
+######################################################################
+######################################################################
- $scrout.=&selectbox('Limit by language','language',
- $ENV{'form.language'},%language);
-
+=pod
-# ------------------------------------------------ Compute date selection boxes
- $scrout.=<
+$lt{'header'}
+
+$hidden_fields
-between:
-CREATIONDATESTART
- $scrout.=&dateboxes('creationdatestart',1,1,1976,
- $ENV{'form.creationdatestart_month'},
- $ENV{'form.creationdatestart_day'},
- $ENV{'form.creationdatestart_year'},
- );
- $scrout.=<
between:
-LASTREVISIONDATESTART
- $scrout.=&dateboxes('lastrevisiondatestart',1,1,1976,
- $ENV{'form.lastrevisiondatestart_month'},
- $ENV{'form.lastrevisiondatestart_day'},
- $ENV{'form.lastrevisiondatestart_year'},
- );
- $scrout.=<
+
+
+ENDCOURSESEARCH
+ $scrout.=' '.
+ &Apache::lonhtmlcommon::textbox('courseexp',
+ $env{'form.courseexp'},40);
+ my $crscheckbox =
+ &Apache::lonhtmlcommon::checkbox('crsfulltext',
+ $env{'form.crsfulltext'});
+ my $relcheckbox =
+ &Apache::lonhtmlcommon::checkbox('crsrelated',
+ $env{'form.crsrelated'});
+ my $discheckbox =
+ &Apache::lonhtmlcommon::checkbox('crsdiscuss',
+ $env{'form.crsrelated'});
+ $scrout.=(<
+
+
+
-Example: grandmother=75 OR grandfather=85
-
-CUSTOMMETADATA
-$scrout.=&simpletextfield('custommetadata',$ENV{'form.custommetadata'});
-$scrout.=' initial users of this system do not need to worry about this option';
+=pod
- $scrout.=<
-CUSTOMSHOW
-$scrout.=&simpletextfield('customshow',$ENV{'form.customshow'});
-$scrout.=' initial users of this system do not need to worry about this option';
-
-# ---------------------------------------------------------------- Print screen
- $r->print(<Search Catalog
-
'. + (' 'x2).&searchhelp()." | |||
'.&titlefield($fields{$field}).' | '. + &Apache::lonmeta::prettyinput($field, + $env{'form.'.$field}, + $field, + 'advsearch', + $related_word_search{$field}, + ' | ', + $env{'form.'.$field.'_related'}, + 50); + if ($related_word_search{$field}) { + $scrout .= 'related words'; + } else { + $scrout .= ' | '; + } + $scrout .= ' |
'.&titlefield($fields{$field}).' | '. + ''. + &Apache::lonmeta::prettyinput($field, + $env{'form.'.$field}, + $field, + 'advsearch', + 0). + ' | ||
'. + &titlefield(&mt('MIME Type Category')).' | '. + &Apache::loncommon::filecategoryselect('category', + $env{'form.category'}). + ' | ||
'. + &titlefield(&mt('Domains')).' | '.
+ &Apache::loncommon::domain_select('domains',
+ $env{'form.domains'},1).
+ ' | ||
'. + &titlefield(&mt('Copyright/Distribution')).' | '. + &Apache::lonmeta::selectbox('copyright', + $env{'form.copyright'}, + \&Apache::loncommon::copyrightdescription, + ( undef, + &Apache::loncommon::copyrightids) + ).' | ||
'. + &titlefield(&mt('Language')).' | '. + &Apache::lonmeta::selectbox('language', + $env{'form.language'}, + \&Apache::loncommon::languagedescription, + ('any',&Apache::loncommon::languageids) + ).' |
'.&mt('Minimum').' | '. + ''.&mt('Maximum').' | |
'. + &titlefield(&mt($statistic->{'description'})). + ' | '. + ''. + ' | '. + ''. + ' |
'.&mt('Minimum').' | '. + ''.&mt('Maximum').' | |
'. + &titlefield(&mt($evaluation->{'description'})). + ' | '. + ''. + ' | '. + ''. + ' |
Created between | '. + '[_1] |
and | '. + '[_2] |
Last modified between | '. + '[_1] |
and | '. + '[_2] |
$uctitle:".
- "
".'';
-}
-
-# ----------------------------------------------- Performing an advanced search
-sub advancedsearch {
- my ($r,$envhash)=@_;
- my %ENV=%{$envhash};
+######################################################################
+######################################################################
+
+=pod
+
+=item &get_persistent_data()
+
+Inputs: filename of database, ref to array of values to recover.
+
+Outputs: array of values. Returns undef on error.
+
+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.
+
+=cut
+
+######################################################################
+######################################################################
+sub get_persistent_data {
+ my $filename = shift;
+ my @Vars = @{shift()};
+ my @Values; # Return array
+ return undef if (! -e $filename);
+ return undef if (! tie(%persistent_db,'GDBM_File',$filename,
+ &GDBM_READER(),0640));
+ foreach my $name (@Vars) {
+ if (! exists($persistent_db{$name})) {
+ push @Values, undef;
+ next;
+ }
+ my @values = map {
+ &Apache::lonnet::unescape($_);
+ } split(',',$persistent_db{$name});
+ if (@values <= 1) {
+ push @Values,$values[0];
+ } else {
+ push @Values,\@values;
+ }
+ }
+ untie (%persistent_db);
+ return @Values;
+}
+
+######################################################################
+######################################################################
+
+=pod
+
+=item &make_persistent()
+
+Inputs: Hash of values to save, filename of persistent database.
+
+Store 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 separated string.
+
+=cut
+
+######################################################################
+######################################################################
+sub make_persistent {
+ my %save = %{shift()};
+ my $filename = shift;
+ return undef if (! tie(%persistent_db,'GDBM_File',
+ $filename,&GDBM_WRCREAT(),0640));
+ foreach my $name (keys(%save)) {
+ my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
+ # We handle array references, but not recursively.
+ my $store = join(',', map { &Apache::lonnet::escape($_); } @values );
+ $persistent_db{$name} = $store;
+ }
+ untie(%persistent_db);
+ return 1;
+}
+
+######################################################################
+######################################################################
+
+=pod
+
+=item &make_form_data_persistent()
+Inputs: filename of persistent database.
+
+Store most form 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 separated string.
+
+=cut
+
+######################################################################
+######################################################################
+sub make_form_data_persistent {
+ my $r = shift;
+ my $filename = shift;
+ my %save;
+ foreach (keys(%env)) {
+ next if (!/^form/ || /submit/);
+ $save{$_} = $env{$_};
+ }
+ return &make_persistent(\%save,$filename);
+}
+
+######################################################################
+######################################################################
+
+=pod
+
+=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.
+
+=item $customshow Scalar containing commands to show custom metadata.
+
+=item $libraries_to_query Reference to array of domains to search.
+
+=back
+
+=cut
+
+######################################################################
+######################################################################
+sub parse_advanced_search {
+ my ($r,$closebutton,$hidden_fields)=@_;
+ my @BasicFields = ('title','author','subject','keywords','url','version',
+ 'notes','abstract','extension','owner','authorspace',
+# 'custommetadata','customshow',
+ 'modifyinguser','standards','mime');
+ my @StatsFields = &statfields();
+ my @EvalFields = &evalfields();
my $fillflag=0;
+ my $pretty_search_string = "";
# Clean up fields for safety
- for my $field ('title','author','subject','keywords','url','version',
- 'creationdatestart_month','creationdatestart_day',
+ for my $field (@BasicFields,
+ 'creationdatestart_month','creationdatestart_day',
'creationdatestart_year','creationdateend_month',
'creationdateend_day','creationdateend_year',
'lastrevisiondatestart_month','lastrevisiondatestart_day',
'lastrevisiondatestart_year','lastrevisiondateend_month',
- 'lastrevisiondateend_day','lastrevisiondateend_year',
- 'notes','abstract','mime','language','owner',
- 'custommetadata','customshow') {
- $ENV{"form.$field"}=~s/[^\w\s\(\)\=\-\"\']//g;
+ 'lastrevisiondateend_day','lastrevisiondateend_year') {
+ $env{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\']//g;
}
-
+ foreach ('mode','form','element') {
+ # is this required? Hmmm.
+ next if (! exists($env{'form.'.$_}));
+ $env{'form.'.$_}=&Apache::lonnet::unescape($env{'form.'.$_});
+ $env{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g;
+ }
+ # Preprocess the category form element.
+ $env{'form.category'} = 'any' if (! defined($env{'form.category'}) ||
+ ref($env{'form.category'}));
+ #
# Check to see if enough information was filled in
- for my $field ('title','author','subject','keywords','url','version',
- 'notes','abstract','mime','language','owner',
- 'custommetadata') {
- if (&filled($ENV{"form.$field"})) {
+ foreach my $field (@BasicFields) {
+ if (&filled($env{'form.'.$field})) {
$fillflag++;
}
}
- unless ($fillflag) {
- &output_blank_field_error($r);
- return OK;
+ foreach my $field (@StatsFields,@EvalFields) {
+ if (&filled($env{'form.'.$field.'_max'})) {
+ $fillflag++;
+ }
+ if (&filled($env{'form.'.$field.'_min'})) {
+ $fillflag++;
+ }
}
-
+ for my $field ('lowestgradelevel','highestgradelevel') {
+ if ( $env{'form.'.$field} =~ /^\d+$/ &&
+ $env{'form.'.$field} > 0) {
+ $fillflag++;
+ }
+ }
+ if (! $fillflag) {
+ &output_blank_field_error($r,$closebutton,
+ 'phase=disp_adv',$hidden_fields);
+ return ;
+ }
# Turn the form input into a SQL-based query
my $query='';
-
my @queries;
+ my $font = '';
# Evaluate logical expression AND/OR/NOT phrase fields.
- foreach my $field ('title','author','subject','notes','abstract','url',
- 'keywords','version','owner') {
- if ($ENV{'form.'.$field}) {
- push @queries,&build_SQL_query($field,$ENV{'form.'.$field});
- }
+ foreach my $field (@BasicFields) {
+ next if (!defined($env{'form.'.$field}) || $env{'form.'.$field} eq '');
+ my ($error,$SQLQuery) =
+ &process_phrase_input($env{'form.'.$field},
+ $env{'form.'.$field.'_related'},$field);
+ if (defined($error)) {
+ &output_unparsed_phrase_error($r,$closebutton,'phase=disp_adv',
+ $hidden_fields,$field);
+ return;
+ } else {
+ $pretty_search_string .=
+ $font.$field.': '.$env{'form.'.$field};
+ if ($env{'form.'.$field.'_related'}) {
+ my @Words =
+ &Apache::loncommon::get_related_words
+ ($env{'form.'.$field});
+ if (@Words) {
+ $pretty_search_string.= ' with related words: '.
+ join(', ',@Words[0..4]);
+ } else {
+ $pretty_search_string.= ' with related words.';
+ }
+ }
+ $pretty_search_string .= '
';
+ push (@queries,$SQLQuery);
+ }
}
- # Evaluate option lists
- if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {
- push @queries,"(language like \"$ENV{'form.language'}\")";
+ #
+ # Make the 'mime' from 'form.category' and 'form.extension'
+ #
+ my $searchphrase;
+ if (exists($env{'form.category'}) &&
+ $env{'form.category'} !~ /^\s*$/ &&
+ $env{'form.category'} ne 'any') {
+ my @extensions = &Apache::loncommon::filecategorytypes
+ ($env{'form.category'});
+ if (scalar(@extensions) > 0) {
+ $searchphrase = join(' OR ',@extensions);
+ }
}
- if ($ENV{'form.mime'} and $ENV{'form.mime'} ne 'any') {
- push @queries,"(mime like \"$ENV{'form.mime'}\")";
+ if (defined($searchphrase)) {
+ my ($error,$SQLsearch) = &process_phrase_input($searchphrase,0,'mime');
+ push @queries,$SQLsearch;
+ $pretty_search_string .=$font.'mime contains '.
+ $searchphrase.'
';
}
- if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') {
- push @queries,"(copyright like \"$ENV{'form.copyright'}\")";
+ #
+ # Evaluate option lists
+ if ($env{'form.lowestgradelevel'} &&
+ $env{'form.lowestgradelevel'} ne '0' &&
+ $env{'form.lowestgradelevel'} =~ /^\d+$/) {
+ push(@queries,
+ '(lowestgradelevel>='.$env{'form.lowestgradelevel'}.')');
+ $pretty_search_string.="lowestgradelevel>=".
+ $env{'form.lowestgradelevel'}."
\n";
+ }
+ if ($env{'form.highestgradelevel'} &&
+ $env{'form.highestgradelevel'} ne '0' &&
+ $env{'form.highestgradelevel'} =~ /^\d+$/) {
+ push(@queries,
+ '(highestgradelevel<='.$env{'form.highestgradelevel'}.')');
+ $pretty_search_string.="highestgradelevel<=".
+ $env{'form.highestgradelevel'}."
\n";
+ }
+ if ($env{'form.language'} and $env{'form.language'} ne 'any') {
+ push @queries,"(language like \"$env{'form.language'}\")";
+ $pretty_search_string.=$font."language= ".
+ &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";
+ }
+ #
+ # Statistics
+ foreach my $field (@StatsFields,@EvalFields) {
+ my ($min,$max);
+ if (exists($env{'form.'.$field.'_min'}) &&
+ $env{'form.'.$field.'_min'} ne '') {
+ $min = $env{'form.'.$field.'_min'};
+ }
+ if (exists($env{'form.'.$field.'_max'}) &&
+ $env{'form.'.$field.'_max'} ne '') {
+ $max = $env{'form.'.$field.'_max'};
+ }
+ next if (! defined($max) && ! defined($min));
+ if (defined($min) && defined($max)) {
+ ($min,$max) = sort {$a <=>$b} ($min,$max);
+ }
+ if (defined($min) && $min =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
+ push(@queries,'('.$field.'>'.$min.')');
+ $pretty_search_string.=$font.$field.'>'.$min.'
';
+ }
+ if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
+ push(@queries,'('.$field.'<'.$max.')');
+ $pretty_search_string.=$font.$field.'<'.$max.'
';
+ }
}
+ #
# Evaluate date windows
- my $datequery=&build_date_queries(
- $ENV{'form.creationdatestart_month'},
- $ENV{'form.creationdatestart_day'},
- $ENV{'form.creationdatestart_year'},
- $ENV{'form.creationdateend_month'},
- $ENV{'form.creationdateend_day'},
- $ENV{'form.creationdateend_year'},
- $ENV{'form.lastrevisiondatestart_month'},
- $ENV{'form.lastrevisiondatestart_day'},
- $ENV{'form.lastrevisiondatestart_year'},
- $ENV{'form.lastrevisiondateend_month'},
- $ENV{'form.lastrevisiondateend_day'},
- $ENV{'form.lastrevisiondateend_year'},
- );
- # Test to see if date windows are legitimate
- if ($datequery=~/^Incorrect/) {
- &output_date_error($r,$datequery);
- return OK;
- }
- elsif ($datequery) {
+ my $cafter =
+ &Apache::lonhtmlcommon::get_date_from_form('creationdate1');
+ my $cbefore =
+ &Apache::lonhtmlcommon::get_date_from_form('creationdate2');
+ if ($cafter > $cbefore) {
+ my $tmp = $cafter;
+ $cafter = $cbefore;
+ $cbefore = $tmp;
+ }
+ my $mafter =
+ &Apache::lonhtmlcommon::get_date_from_form('revisiondate1');
+ my $mbefore =
+ &Apache::lonhtmlcommon::get_date_from_form('revisiondate2');
+ if ($mafter > $mbefore) {
+ my $tmp = $mafter;
+ $mafter = $mbefore;
+ $mbefore = $tmp;
+ }
+ my ($datequery,$error,$prettydate)=&build_date_queries($cafter,$cbefore,
+ $mafter,$mbefore);
+ if (defined($error)) {
+ &output_date_error($r,$error,$closebutton,$hidden_fields);
+ } elsif (defined($datequery)) {
+ # Here is where you would set up pretty_search_string to output
+ # date query information.
+ $pretty_search_string .= '
'.$prettydate.'
';
push @queries,$datequery;
}
-
+ #
# Process form information for custom metadata querying
- my $customquery='';
- if ($ENV{'form.custommetadata'}) {
- $customquery=&build_custommetadata_query('custommetadata',
- $ENV{'form.custommetadata'});
+ my $customquery=undef;
+ ##
+ ## The custom metadata search was removed q long time ago mostly
+ ## because I was unable to figureout exactly how it worked and could
+ ## not imagine people actually using it. MH
+ ##
+ # 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=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,$pretty_domains_string) = &parse_domain_restrictions();
+ if ($pretty_domains_string) {
+ $pretty_search_string .= $pretty_domains_string."
\n";
}
- my $customshow='';
- 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).
+ #
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);
+ $query="SELECT * FROM metadata WHERE (".join(") AND (",@queries).')';
+ } elsif ($customquery) {
+ $query = '';
+ }
+ #&Apache::lonnet::logthis('advanced query = '.$/.$query);
+ return ($query,$customquery,$customshow,$libraries_to_query,
+ $pretty_search_string);
+}
+
+sub parse_domain_restrictions {
+ my $libraries_to_query = undef;
+ # $env{'form.domains'} can be either a scalar or an array reference.
+ # We need an array.
+ if (! exists($env{'form.domains'}) || $env{'form.domains'} eq '') {
+ return (undef,'',undef);
+ }
+ my @allowed_domains = &Apache::loncommon::get_env_multiple('form.domains');
+ #
+ my %domain_hash = ();
+ my $pretty_domains_string;
+ foreach (@allowed_domains) {
+ $domain_hash{$_}++;
+ }
+ if ($domain_hash{'any'}) {
+ $pretty_domains_string = "In all LON-CAPA domains.";
+ } else {
+ if (@allowed_domains > 1) {
+ $pretty_domains_string = "In LON-CAPA domains:";
+ } else {
+ $pretty_domains_string = "In LON-CAPA domain ";
+ }
+ foreach (sort @allowed_domains) {
+ $pretty_domains_string .= "".$_." ";
+ }
+ foreach (keys(%Apache::lonnet::libserv)) {
+ if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {
+ push @$libraries_to_query,$_;
+ }
+ }
}
- elsif ($customquery) {
- my $reply; # reply hash reference
- $reply=&Apache::lonnet::metadata_query('',
- $customquery,$customshow);
- &output_results('Advanced',$r,$envhash,$customquery,$reply);
+ return ($libraries_to_query,
+ $pretty_domains_string);
+}
+
+######################################################################
+######################################################################
+
+=pod
+
+=item &parse_basic_search()
+
+Parse the basic search form and return a scalar containing an sql query.
+
+=cut
+
+######################################################################
+######################################################################
+sub parse_basic_search {
+ my ($r,$closebutton)=@_;
+ #
+ # Clean up fields for safety
+ for my $field ('basicexp') {
+ $env{"form.$field"}=~s/[^\w\s\'\"\!\(\)\-]//g;
+ }
+ foreach ('mode','form','element') {
+ # is this required? Hmmm.
+ next unless (exists($env{"form.$_"}));
+ $env{"form.$_"}=&Apache::lonnet::unescape($env{"form.$_"});
+ $env{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
+ }
+ my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
+ #
+ # Check to see if enough of a query is filled in
+ my $search_string = $env{'form.basicexp'};
+ if (! &filled($search_string)) {
+ &output_blank_field_error($r,$closebutton,'phase=disp_basic');
+ return OK;
}
- # should not get to this point
- return 'Error. Should not have gone to this point.';
+ my $pretty_search_string=$search_string;
+ my @Queries;
+ my $searchfield = 'concat_ws(" ",'.join(',',
+ ('title','author','subject',
+ 'notes','abstract','keywords')
+ ).')';
+ my ($error,$SQLQuery) = &process_phrase_input($search_string,
+ $env{'form.related'},
+ $searchfield);
+ if ($error) {
+ &output_unparsed_phrase_error($r,$closebutton,'phase=disp_basic',
+ '','basicexp');
+ return;
+ }
+ push(@Queries,$SQLQuery);
+ #foreach my $q (@Queries) {
+ # &Apache::lonnet::logthis(' '.$q);
+ #}
+ my $final_query = 'SELECT * FROM metadata WHERE '.join(" AND ",@Queries);
+ #
+ if (defined($pretty_domains_string) && $pretty_domains_string ne '') {
+ $pretty_search_string .= ' '.$pretty_domains_string;
+ }
+ $pretty_search_string .= "
\n";
+ $pretty_search_string =~ s:^
and ::;
+ #&Apache::lonnet::logthis('simple search final query = '.$/.$final_query);
+ return ($final_query,$pretty_search_string,
+ $libraries_to_query);
}
-# ---------------------------------------------------- see if a field is filled
-sub filled {
- my ($field)=@_;
- if ($field=~/\S/ && $field ne 'any') {
- return 1;
+
+###############################################################
+###############################################################
+
+my @Phrases;
+
+sub concat {
+ my ($item) = @_;
+ my $results = '';
+ foreach (@$item) {
+ if (ref($_) eq 'ARRAY') {
+ $results .= join(' ',@$_);
+ }
}
- else {
- return 0;
+ return $results;
+}
+
+sub process_phrase_input {
+ my ($phrase,$related,$field)=@_;
+ #&Apache::lonnet::logthis('phrase = :'.$phrase.':');
+ my $grammar = <<'ENDGRAMMAR';
+ searchphrase:
+ expression /^\Z/ {
+ # &Apache::lonsearchcat::print_item(\@item,0);
+ [@item];
+ }
+ expression:
+ phrase(s) {
+ [@item];
+ }
+ phrase:
+ orword {
+ [@item];
+ }
+ | andword {
+ [@item];
+ }
+ | minusword {
+ unshift(@::Phrases,$item[1]->[0]);
+ unshift(@::Phrases,$item[1]->[1]);
+ [@item];
+ }
+ | word {
+ unshift(@::Phrases,$item[1]);
+ [@item];
+ }
+ #
+ orword:
+ word 'OR' phrase {
+ unshift(@::Phrases,'OR');
+ unshift(@::Phrases,$item[1]);
+ [@item];
+ }
+ | word 'or' phrase {
+ unshift(@::Phrases,'OR');
+ unshift(@::Phrases,$item[1]);
+ [@item];
+ }
+ | minusword 'OR' phrase {
+ unshift(@::Phrases,'OR');
+ unshift(@::Phrases,$item[1]->[0]);
+ unshift(@::Phrases,$item[1]->[1]);
+ [@item];
+ }
+ | minusword 'or' phrase {
+ unshift(@::Phrases,'OR');
+ unshift(@::Phrases,$item[1]->[0]);
+ unshift(@::Phrases,$item[1]->[1]);
+ [@item];
+ }
+ andword:
+ word phrase {
+ unshift(@::Phrases,'AND');
+ unshift(@::Phrases,$item[1]);
+ [@item];
+ }
+ | minusword phrase {
+ unshift(@::Phrases,'AND');
+ unshift(@::Phrases,$item[1]->[0]);
+ unshift(@::Phrases,$item[1]->[1]);
+ [@item];
+ }
+ #
+ minusword:
+ '-' word {
+ [$item[2],'NOT'];
+ }
+ word:
+ "'" term(s) "'" {
+ &Apache::lonsearchcat::concat(\@item);
+ }
+ | '"' term(s) '"' {
+ &Apache::lonsearchcat::concat(\@item);
+ }
+ | term {
+ $item[1];
+ }
+ term:
+ /[\w\Q:!@#$%^&*()+_=|{}<>,.;\\\/?\E]+/ {
+ $item[1];
+ }
+ENDGRAMMAR
+ #
+ # The end result of parsing the phrase with the grammar is an array
+ # @::Phrases.
+ # $phrase = "gene splicing" or cat -> "gene splicing","OR","cat"
+ # $phrase = "genetic engineering" -dna ->
+ # "genetic engineering","AND","NOT","dna"
+ # $phrase = cat or dog -poodle -> "cat","OR","dog","AND","NOT","poodle"
+ undef(@::Phrases);
+ my $p = new Parse::RecDescent($grammar);
+ if (! defined($p->searchphrase($phrase))) {
+ &Apache::lonnet::logthis('lonsearchcat:unable to process:'.$phrase);
+ return 'Unable to process phrase '.$phrase;
+ }
+ #
+ # Go through the phrases and make sense of them.
+ # Apply modifiers NOT OR and AND to the phrases.
+ my @NewPhrases;
+ while(@::Phrases) {
+ my $phrase = shift(@::Phrases);
+ # &Apache::lonnet::logthis('phrase = '.$phrase);
+ my $phrasedata;
+ if ($phrase =~ /^(NOT|OR|AND)$/) {
+ if ($phrase eq 'OR') {
+ $phrasedata->{'or'}++;
+ if (! @::Phrases) { $phrasedata = undef; last; }
+ $phrase = shift(@::Phrases);
+ } elsif ($phrase eq 'AND') {
+ $phrasedata->{'and'}++;
+ if (! @::Phrases) { $phrasedata = undef; last; }
+ $phrase = shift(@::Phrases);
+ }
+ if ($phrase eq 'NOT') {
+ $phrasedata->{'negate'}++;
+ if (! @::Phrases) { $phrasedata = undef; last; }
+ $phrase = shift(@::Phrases);
+ }
+ }
+ $phrasedata->{'phrase'} = $phrase;
+ if ($related) {
+ my @NewWords;
+ (undef,@NewWords) = &related_version($phrasedata->{'phrase'});
+ $phrasedata->{'related_words'} = \@NewWords;
+ }
+ push(@NewPhrases,$phrasedata);
}
+ #
+ # Actually build the sql query from the phrases
+ my $SQLQuery;
+ foreach my $phrase (@NewPhrases) {
+ my $query;
+ if ($phrase->{'negate'}) {
+ $query .= $field.' NOT LIKE "%'.$phrase->{'phrase'}.'%"';
+ } else {
+ $query .= $field.' LIKE "%'.$phrase->{'phrase'}.'%"';
+ }
+ foreach my $related (@{$phrase->{'related_words'}}) {
+ if ($phrase->{'negate'}) {
+ $query .= ' AND '.$field.' NOT LIKE "%'.$related.'%"';
+ } else {
+ $query .= ' OR '.$field.' LIKE "%'.$related.'%"';
+ }
+ }
+ if ($SQLQuery) {
+ if ($phrase->{'or'}) {
+ $SQLQuery .= ' OR ('.$query.')';
+ } else {
+ $SQLQuery .= ' AND ('.$query.')';
+ }
+ } else {
+ $SQLQuery = '('.$query.')';
+ }
+ }
+ #
+ # &Apache::lonnet::logthis("SQLQuery = $SQLQuery");
+ #
+ return undef,$SQLQuery;
}
-# --------------------------------------------------- Performing a basic search
-sub basicsearch {
- my ($r,$envhash)=@_;
- my %ENV=%{$envhash};
+######################################################################
+######################################################################
- # Clean up fields for safety
- for my $field ('basicexp') {
- $ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g;
+=pod
+
+=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 ($word) = @_;
+ return (undef) if (lc($word) =~ /\b(or|and|not)\b/);
+ my @Words = &Apache::loncommon::get_related_words($word);
+ # Only use 4 related words
+ @Words = ($#Words>4? @Words[0..4] : @Words);
+ my $result = join " OR ", ($word,@Words);
+ return $result,sort(@Words);
+}
+
+
+######################################################################
+######################################################################
+
+=pod
+
+=item &build_custommetadata_query()
+
+Constructs a custom metadata query using a rather heinous regular
+expression.
+
+=cut
+
+######################################################################
+######################################################################
+sub build_custommetadata_query {
+ my ($field_name,$logic_statement)=@_;
+ my $q=new Text::Query('abc',
+ -parse => 'Text::Query::ParseAdvanced',
+ -build => 'Text::Query::BuildAdvancedString');
+ $q->prepare($logic_statement);
+ my $matchexp=${$q}{'-parse'}{'-build'}{'matchstring'};
+ # quick fix to change literal into xml tag-matching
+ # will eventually have to write a separate builder module
+ # wordone=wordtwo becomes\
' if (defined($pretty_string));
+ $pretty_string .=
+ &mt('created between [_1] and [_2]',
+ &Apache::lonlocal::locallocaltime($cafter),
+ &Apache::lonlocal::locallocaltime($cbefore+24*60*60-1));
+ push(@queries,$cquery);
+ $pretty_string =~ s/ 00:00:00//g;
+ }
+ if (defined($mbefore) && defined($mafter)) {
+ my (undef,undef,undef,$maday,$mamon,$mayear) = localtime($mafter);
+ my (undef,undef,undef,$mbday,$mbmon,$mbyear) = localtime($mbefore);
+ # Correct for year being relative to 1900
+ $mayear+=1900; $mbyear+=1900;
+ my $mquery=
+ '(lastrevisiondate BETWEEN '.
+ "'".$mayear.'-'.$mamon.'-'.$maday."'".
+ ' AND '.
+ "'".$mbyear.'-'.$mbmon.'-'.$mbday." 23:59:59')";
+ push(@queries,$mquery);
+ $pretty_string .= '
' if (defined($pretty_string));
+ $pretty_string .=
+ &mt('last revised between [_1] and [_2]',
+ &Apache::lonlocal::locallocaltime($mafter),
+ &Apache::lonlocal::locallocaltime($mbefore+24*60*60-1));
+ $pretty_string =~ s/ 00:00:00//g;
+ }
+ if (@queries) {
+ $result .= join(" AND ",@queries);
+ }
}
+ return ($result,$error,$pretty_string);
+}
- # Check to see if enough is filled in
- unless (&filled($ENV{'form.basicexp'})) {
- &output_blank_field_error($r);
- return OK;
+######################################################################
+######################################################################
+
+=pod
+
+=item ©right_check()
+
+Inputs: $Metadata, a hash pointer of metadata for a resource.
+
+Returns: 1 if the resource is available to the user making the query,
+ 0 otherwise.
+
+=cut
+
+######################################################################
+######################################################################
+sub copyright_check {
+ my $Metadata = shift;
+ # Check copyright tags and skip results the user cannot use
+ my (undef,undef,$resdom,$resname) = split('/',
+ $Metadata->{'url'});
+ # Check for priv
+ if (($Metadata->{'copyright'} eq 'priv') &&
+ (($env{'user.name'} ne $resname) &&
+ ($env{'user.domain'} ne $resdom))) {
+ return 0;
+ }
+ # Check for domain
+ if (($Metadata->{'copyright'} eq 'domain') &&
+ ($env{'user.domain'} ne $resdom)) {
+ return 0;
}
+ return 1;
+}
- # Build SQL query string based on form page
- my $query='';
- my $concatarg=join('," ",',
- ('title', 'author', 'subject', 'notes', 'abstract'));
- $query='select * from metadata where concat(' . $concatarg . ') like %' .
- $ENV{'form.basicexp'} . '%';
+######################################################################
+######################################################################
- # Get reply (either a hash reference to filehandles or bad connection)
- my $reply=&Apache::lonnet::metadata_query($query);
+=pod
- # Output search results
- &output_results('Basic',$r,$envhash,$query,$reply);
+=item &ensure_db_and_table()
- return OK;
+Ensure we can get lonmysql to connect to the database and the table we
+need exists.
+
+Inputs: $r, table id
+
+Returns: undef on error, 1 if the table exists.
+
+=cut
+
+######################################################################
+######################################################################
+sub ensure_db_and_table {
+ my ($r,$table) = @_;
+ ##
+ ## Sanity check the table id.
+ ##
+ if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
+ $r->print("Unable to retrieve search results. ".
+ "Unable to determine the table results were stored in. ".
+ &Apache::loncommon::end_page());
+ return undef;
+ }
+ ##
+ ## Make sure we can connect and the table exists.
+ ##
+ my $connection_result = &Apache::lonmysql::connect_to_db();
+ if (!defined($connection_result)) {
+ $r->print("Unable to connect to the MySQL database where your results".
+ " are stored.".
+ &Apache::loncommon::end_page());
+ &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".
+ " connect to database.");
+ &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
+ return undef;
+ }
+ my $table_check = &Apache::lonmysql::check_table($table);
+ if (! defined($table_check)) {
+ $r->print("A MySQL error has occurred.".
+ &Apache::loncommon::end_page());
+ &Apache::lonnet::logthis("lonmysql was unable to determine the status".
+ " of table ".$table);
+ return undef;
+ } 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 undef;
+ }
+ return 1;
}
-# ---------------- Message to output when there are not enough fields filled in
-sub output_blank_field_error {
- my ($r)=@_;
- # make query information persistent to allow for subsequent revision
- my $persistent=&make_persistent();
+######################################################################
+######################################################################
- $r->print(<Search Catalog
-".
+ &Apache::loncommon::end_page());
+ &Apache::lonnet::logthis("lonmysql was unable to determine the number".
+ " of rows in table ".$table);
+ &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
+ return;
+ }
+ my $result;
+ my $html = &Apache::lonxml::xmlbegin();
+ my $head = &Apache::lonxml::headtag('Results');
+ my $end_head = &Apache::loncommon::endheadtag();
+ $result.=<
+Search:$pretty_query_string
- - -RESULTS + +END + $r->print($result.&Apache::loncommon::end_page()); + return; } -# ----------------------------- format and output results based on a reply list -sub output_results { - my ($mode,$r,$envhash,$query,$replyref)=@_; - my %ENV=%{$envhash}; - my %rhash=%{$replyref}; - my $compiledresult=''; - my $timeremain=30; - $r->print(<'.
+ ' | '. + &prev_next_buttons($min,$env{'form.show'},$total_results). + ' | '. + &viewoptions().' |
\n"; + if (! defined($Fields{'title'}) || $Fields{'title'} eq '') { + $Fields{'title'} = 'Untitled'; + } + my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'}, + $Fields{'id'},$checkbox_num++); + # Render the result into html + $output.= &$viewfunction($prefix,%Fields); + # Print them out as they come in. + $r->print($output); + $r->rflush(); + } + if (@Results < 1) { + $r->print(&mt("There were no results matching your query")); + } else { + $r->print + ('
-Subject: $subject
-Keyword(s): $keywords
-Notes: $notes
-MIME Type: $mimetag{$mime}
-Language: $language{$lang}
-Copyright/Distribution: $cprtag{$copyright}
-
-$shortabstract -
-END + my ($prefix,%values) = @_; + my $result; + my $jumpurl=$values{'url'}; + $jumpurl=~s/^\/ext\//http\:\/\//; + $result .= ''.$prefix. + ''.' '. + ''.$values{'title'}."\n"; + $result .= "\n";
+ $result .= ''.$values{'author'}.','.
+ ' '.$values{'owner'}.'
';
+ foreach my $field
+ (
+ { name=>'url',
+ translate => 'URL: [_1]',
+ special => 'url link',},
+ { name=>'subject',
+ translate => 'Subject: [_1]',},
+ { name=>'keywords',
+ translate => 'Keywords: [_1]',},
+ { name=>'notes',
+ translate => 'Notes: [_1]',},
+ { name=>'mimetag',
+ translate => 'MIME Type: [_1]',},
+ { name=>'standards',
+ translate => 'Standards:[_1]',},
+ { name=>'copyrighttag',
+ translate => 'Copyright/Distribution: [_1]',},
+ { name=>'count',
+ format => "%d",
+ translate => 'Access Count: [_1]',},
+ { name=>'stdno',
+ format => "%d",
+ translate => 'Number of Students: [_1]',},
+ { name=>'avetries',
+ format => "%.2f",
+ translate => 'Average Tries: [_1]',},
+ { name=>'disc',
+ format => "%.2f",
+ translate => 'Degree of Discrimination: [_1]',},
+ { name=>'difficulty',
+ format => "%.2f",
+ translate => 'Degree of Difficulty: [_1]',},
+ { name=>'clear',
+ format => "%.2f",
+ translate => 'Clear: [_1]',},
+ { name=>'depth',
+ format => "%.2f",
+ translate => 'Depth: [_1]',},
+ { name=>'helpful',
+ format => "%.2f",
+ translate => 'Helpful: [_1]',},
+ { name=>'correct',
+ format => "%.2f",
+ translate => 'Correct: [_1]',},
+ { name=>'technical',
+ format => "%.2f",
+ translate => 'Technical: [_1]',},
+ { name=>'comefrom_list',
+ type => 'list',
+ translate => 'Resources that lead up to this resource in maps',},
+ { name=>'goto_list',
+ type => 'list',
+ translate => 'Resources that follow this resource in maps',},
+ { name=>'sequsage_list',
+ type => 'list',
+ translate => 'Resources using or importing resource',},
+ ) {
+ next if (! exists($values{$field->{'name'}}) ||
+ $values{$field->{'name'}} eq '');
+ if (exists($field->{'type'}) && $field->{'type'} eq 'list') {
+ $result .= ''.&mt($field->{'translate'}).'
'.$values{'extrashow'}.'
'; + } + if (exists($values{'shortabstract'}) && $values{'shortabstract'} ne '') { + $result .= ''.$values{'shortabstract'}.'
'; + } + $result .= ''. + &detailed_citation_view($prefix,%values). + ' | '. + &Apache::lonindexer::showpreview($values{'url'}). + ' |
'. + &summary_view($prefix,%values). + ' | '. + &Apache::lonindexer::showpreview($values{'url'}). + ' |
+$errorstring +
++$revise +
+$end_page +ENDPAGE } +###################################################################### +###################################################################### + +=pod + +=item &output_blank_field_error() + +Output a complete page that indicates the user has not filled in enough +information to do a search. + +Inputs: $r (Apache request handle), $closebutton, $parms. + +Returns: nothing + +$parms is extra information to include in the 'Revise search request' link. + +=cut + +###################################################################### +###################################################################### +sub output_blank_field_error { + my ($r,$closebutton,$parms,$hidden_fields)=@_; + my $bodytag=&Apache::loncommon::bodytag('Search'); + my $errormsg = &mt('You did not fill in enough information for the search to be started. You need to fill in relevant fields on the search page in order for a query to be processed.'); + my $revise = &mt('Revise Search Request'); + my $heading = &mt('Unactionable Search Queary'); + my $start_page = &Apache::loncommon::start_page('Search'); + my $end_page = &Apache::loncommon::end_page(); + $r->print(<+$errormsg +
++$revise +
+$end_page +ENDPAGE + return; +} + +###################################################################### +###################################################################### + +=pod + +=item &output_date_error() + +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,$hidden_fields)=@_; # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(); - - $r->print(<