--- loncom/interface/lonsearchcat.pm 2001/03/15 19:23:10 1.25
+++ loncom/interface/lonsearchcat.pm 2001/12/17 00:56:48 1.113
@@ -1,88 +1,181 @@
-# The LearningOnline Network
+# The LearningOnline Network with CAPA
# Search Catalog
#
-# 03/08/2001 Scott Harrison
+# $Id: lonsearchcat.pm,v 1.113 2001/12/17 00:56:48 harris41 Exp $
#
+# Copyright Michigan State University Board of Trustees
+#
+# 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/
+#
+# YEAR=2001
+# 3/8, 3/12, 3/13, 3/14, 3/15, 3/19 Scott Harrison
+# 3/20, 3/21, 3/22, 3/26, 3/27, 4/2, 8/15, 8/24, 8/25 Scott Harrison
+# 10/12,10/14,10/15,10/16,11/28,11/29,12/10,12/12,12/16 Scott Harrison
+#
+###
+
+###############################################################################
+## ##
+## ORGANIZATION OF THIS PERL MODULE ##
+## ##
+## 1. Modules used by this module ##
+## 2. Choices for different output views (detailed, summary, xml, etc) ##
+## 3. BEGIN block (to be run once after compilation) ##
+## 4. Handling routine called via Apache and mod_perl ##
+## 5. Other subroutines ##
+## ##
+###############################################################################
+
package Apache::lonsearchcat;
+# ------------------------------------------------- modules used by this module
use strict;
use Apache::Constants qw(:common);
use Apache::lonnet();
use Apache::File();
use CGI qw(:standard);
+use Text::Query;
+use GDBM_File;
+use Apache::loncommon();
+
+# ---------------------------------------- variables used throughout the module
+
+# -- information holders
+my %hostdomains; # matches host name to host domain
+my %hostips; # matches host name to host ip
+my %hitcount; # stores number of hits per host
+
+# -- 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 $scrout; # string that holds portions of the screen output
+my $yourself; # allows for quickly limiting to oneself
+my %hash;
+
+# ------------------------------------------ choices for different output views
+# Detailed Citation View ---> sub detailed_citation_view
+# Summary View ---> sub summary_view
+# Fielded Format ---> sub fielded_format_view
+# XML/SGML ---> sub xml_sgml_view
+my $basicviewselect=<
+
+
+
+
+
+END
+my $advancedviewselect=<
+
+
+
+
+
+END
-my %language;
-my $scrout;
-my %metadatafields;
-my %cprtag;
-my %mimetag;
+# ----------------------------------------------------------------------- BEGIN
+sub BEGIN {
+ {
+ my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
+ '/hosts.tab');
+ while (<$fh>) {
+ $_=~/(\w+?)\:(\w+?)\:(\w+?)\:(.*)/; chomp;
+ if ($3 eq 'library') {
+ $hostdomains{$1}=$2;
+ $hostips{$1}=$4;
+ }
+ }
+ }
+}
+
+my $diropendb = "";
+my $domain = "";
+# ----------------------------- Handling routine called via Apache and mod_perl
sub handler {
my $r = shift;
-
-# -------------------------------------- see if called from an interactive mode
- map {
- my ($name, $value) = split(/=/,$_);
- $value =~ tr/+/ /;
- $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
- if ($name eq 'catalogmode') {
- $ENV{'form.'.$name}=$value;
- }
- } (split(/&/,$ENV{'QUERY_STRING'}));
+ untie %hash;
+ &get_unprocessed_cgi();
$r->content_type('text/html');
$r->send_http_header;
return OK if $r->header_only;
- %metadatafields=();
-
- my $hidden='';
- $hidden=<
-END
+ $domain = $r->dir_config('lonDefDomain');
-# ------------------------------------------------ First, check out environment
- $metadatafields{'owner'}=$ENV{'user.name'}.'@'.$ENV{'user.domain'};
+ $diropendb= "/home/httpd/perl/tmp/$domain\_$ENV{'user.name'}_searchcat.db";
-# --------------------------------- Compute various listings of metadata values
-
- %language=();
- $language{'any'}='Any language';
- {
- my $fh=Apache::File->new($r->dir_config('lonTabDir').'/language.tab');
- map {
- $_=~/(\w+)\s+([\w\s\-]+)/;
- $language{$1}=$2;
- } <$fh>;
+ if ($ENV{'form.launch'} eq '1') {
+ if (tie(%hash,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) {
+ &start_fresh_session();
+ untie %hash;
+ }
+ else {
+ $r->print('Unable to tie hash to db '.
+ 'file');
+ return OK;
+ }
}
- %cprtag=();
- $cprtag{'any'}='Any copyright/distribution';
- {
- my $fh=Apache::File->new($r->dir_config('lonIncludes').'/copyright.tab');
- map {
- $_=~/(\w+)\s+([\w\s\-]+)/;
- $cprtag{$1}=$2;
- } <$fh>;
+# ----------------------------------- configure dynamic components of interface
+ my $hidden='';
+ if ($ENV{'form.catalogmode'} eq 'interactive') {
+ $hidden="".
+ "\n";
+ $closebutton=""."\n";
}
-
- %mimetag=();
- $mimetag{'any'}='Any type';
- {
- my $fh=Apache::File->new($r->dir_config('lonTabDir').'/filetypes.tab');
- map {
- $_=~/(\w+)\s+(\w+)\s+([\w\s\-]+)/;
- $mimetag{$1}=".$1 $3";
- } <$fh>;
+ elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {
+ $hidden=<
+END
+ $closebutton=<
+END
+ $importbutton=<
+END
}
+# ------------------------------------------------------ Determine current user
+ $yourself=$ENV{'user.name'}.'@'.$ENV{'user.domain'};
+
+# --- Now, depending on the interface actions, do one of three things here:
+# --- 1. a basic search
+# --- 2. an advanced search
+# --- 3. output a search interface
+
+# ----------------------------------- See if a search invocation should be done
if ($ENV{'form.basicsubmit'} eq 'SEARCH') {
- return &basicsearch($r,\%ENV);
+ untie %hash; return &basicsearch($r,\%ENV);
}
elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {
- return &advancedsearch($r,\%ENV);
+ untie %hash; return &advancedsearch($r,\%ENV);
}
+# ----------------------------- Else, begin building search interface to output
$scrout=''; # building a part of screen output
$scrout.=&searchphrasefield('Limit by title','title',
$ENV{'form.title'});
@@ -99,8 +192,8 @@ END
$scrout.=&searchphrasefield('Limit by URL','url',
$ENV{'form.url'});
- $scrout.=&searchphrasefield('Limit by version','version',
- $ENV{'form.version'});
+# $scrout.=&searchphrasefield('Limit by version','version',
+# $ENV{'form.version'});
$scrout.=&searchphrasefield('Limit by notes','notes',
$ENV{'form.notes'});
@@ -108,22 +201,27 @@ END
$scrout.=&searchphrasefield('Limit by abstract','abstract',
$ENV{'form.abstract'});
- $ENV{'form.mime'}='notxxx' unless length($ENV{'form.mime'});
+ $ENV{'form.mime'}='any' unless length($ENV{'form.mime'});
$scrout.=&selectbox('Limit by MIME type','mime',
- $ENV{'form.mime'},%mimetag);
+ $ENV{'form.mime'},
+ 'any','Any type',
+ \&{Apache::loncommon::filedescriptionex},
+ (&Apache::loncommon::fileextensions));
$ENV{'form.language'}='any' unless length($ENV{'form.language'});
$scrout.=&selectbox('Limit by language','language',
- $ENV{'form.language'},%language);
-
+ $ENV{'form.language'},'any','Any Language',
+ \&{Apache::loncommon::languagedescription},
+ (&Apache::loncommon::languageids),
+ );
# ------------------------------------------------ Compute date selection boxes
$scrout.=<LIMIT BY CREATION DATE RANGE:
-
+
between:
CREATIONDATESTART
$scrout.=&dateboxes('creationdatestart',1,1,1976,
@@ -145,7 +243,7 @@ CREATIONDATEEND
LIMIT BY LAST REVISION DATE RANGE:
- between:
+ between:
LASTREVISIONDATESTART
$scrout.=&dateboxes('lastrevisiondatestart',1,1,1976,
$ENV{'form.lastrevisiondatestart_month'},
@@ -164,64 +262,89 @@ LASTREVISIONDATEEND
$scrout.=&searchphrasefield('Limit by publisher/owner','owner',
$ENV{'form.owner'});
-# $metadatafields{'owner'});
$ENV{'form.copyright'}='any' unless length($ENV{'form.copyright'});
$scrout.=&selectbox('Limit by copyright/distribution','copyright',
- $ENV{'form.copyright'},%cprtag);
+ $ENV{'form.copyright'},
+ 'any','Any copyright/distribution',
+ \&{Apache::loncommon::copyrightdescription},
+ (&Apache::loncommon::copyrightids),
+ );
# ------------------------------------------- Compute customized metadata field
$scrout.=<
-LIMIT BY OTHER METADATA FIELDS:
+LIMIT BY SPECIAL METADATA FIELDS:
-For author-specific metadata, enter in an expression in the form of
-key=value separated by operators such as AND or OR.
+For resource-specific metadata, enter in an expression in the form of
+key=value separated by operators such as AND, OR or NOT. 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';
+ $scrout.=<
+SHOW SPECIAL METADATA FIELDS:
+
+Enter in a space-separated list of special metadata fields to show
+in a fielded listing for each record result.
+
+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(<The LearningOnline Network with CAPA
+
-
+
Search Catalog
-
-
-
-
+
+
+
+$closebutton
+$basicviewselect
+
-
+
Advanced Search
$scrout
-
-
-
+
+
+$closebutton
+$advancedviewselect
+
@@ -230,36 +353,61 @@ ENDDOCUMENT
return OK;
}
-# --------------------------------------------------------- Various form fields
+# ----------- grab unprocessed CGI variables that may have been appended to URL
+sub get_unprocessed_cgi {
+ foreach (split(/&/,$ENV{'QUERY_STRING'})) {
+ my ($name, $value) = split(/=/,$_);
+ $value =~ tr/+/ /;
+ $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
+ if ($name eq 'catalogmode' or $name eq 'launch' or $name eq 'acts') {
+ $ENV{'form.'.$name}=$value;
+ }
+ }
+}
-sub textfield {
- my ($title,$name,$value)=@_;
- return "\n
$title: ".
- '';
+# ------------------------------------------------------------- make persistent
+sub make_persistent {
+ my $persistent='';
+
+ foreach (keys %ENV) {
+ if (/^form\./ && !/submit/) {
+ my $name=$_;
+ my $key=$name;
+ $ENV{$key}=~s/\'//g; # do not mess with html field syntax
+ $name=~s/^form\.//;
+ $persistent.=<
+END
+ }
+ }
+ return $persistent;
}
+# --------------------------------------------------------- Various form fields
+
sub simpletextfield {
my ($name,$value)=@_;
- return '';
+ return '';
}
sub simplecheckbox {
my ($name,$value)=@_;
my $checked='';
$checked="CHECKED" if $value eq 'on';
- return '';
+ return '';
}
sub searchphrasefield {
my ($title,$name,$value)=@_;
my $instruction=<$uctitle:".
- " $instruction ".
- '';
+ " $instruction ".
+ '';
}
sub dateboxes {
@@ -407,217 +555,1204 @@ END
}
sub selectbox {
- my ($title,$name,$value,%options)=@_;
+ my ($title,$name,$value,$anyvalue,$anytag,$functionref,@idlist)=@_;
my $uctitle=uc($title);
my $selout="\n
$uctitle:".
- " ".'
-
-
RESULTS
-}
-
-# ----------------------------- format and output results based on a reply list
-sub output_results {
- my ($r,$envhash,@replylist)=@_;
- my %ENV=%{$envhash};
- foreach my $reply (@replylist) {
+ }
+ elsif ($mode eq 'Advanced') {
+ $r->print(<
+Advanced search
+$query
+
+RESULTS
+ }
+ $r->print('
Search Results
');
+ $r->rflush();
+ my $servernum=(keys %rhash)+0;
+
+ # define server grid (shows status of multiple machines)
+ my $hcinit;
+ my $grid="' '+";
+ $grid.="\n";
+ my $sn=1;
+ for my $sk (sort keys %rhash) {
+ # ''+
+ $grid.="'+\"'\"+')\">'+";
+ $grid.="\n";
+ $grid.="''+\n";
+ $grid.="' '+\n" unless $sn%10;
+ $sn++;
+ }
+ $r->print(<
+ popwin=open('','popwin','scrollbars=1,width=400,height=200');
+ 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="25" name="sdetails"'+
+ ' value="" />'+
+ '<'+'br />'+
+ ' <'+'input type="button" name="button"'+
+ ' value="abort search and view current results" '+
+ ' onClick="javascript:opener.abortsearch()" />'+
+ ' <'+'input type="button" name="button"'+
+ ' value="help" onClick="javascript:opener.openhelp()" />'+
+ '<'+'/tt>'+
+ '<'+'/form>'+
+ '<'+'/body><'+'/html>');
+ popwin.document.close();
+
+ENDPOP
+ $r->rflush();
+ my $servercount=0;
+ my $hitcountsum=0;
+ my $bloop=$servernum;
+ my %orkey;
+ BLOOP: while(1) {
+ my $sn=0;
+ last BLOOP unless $bloop;
+ last BLOOP unless $timeremain;
+ RLOOP: foreach my $rkey (sort keys %rhash) {
+ $sn++;
+ next RLOOP if $orkey{$rkey};
+ $servercount++;
+ $tflag=1;
+ $compiledresult='';
+ my $hostname=$rkey;
+ my $reply=$rhash{$rkey};
my @results;
-
+
my $replyfile='';
- $reply=~/^([\.\w]+)$/; # must do since 'use strict' checks for tainting
- $replyfile=$r->dir_config('lonDaemons').'/tmp/'.$1;
- $reply=~/(.*?)\_/;
- my $hostname=$1;
-
- {
- while (1) {
- last if -e $replyfile;
- sleep 1;
+
+ if ($reply eq 'con_lost') {
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ $bloop--;
+ $orkey{$rkey}=1;
+ }
+ else {
+ $reply=~/^([\.\w]+)$/; # must do since 'use strict' checks for tainting
+ $replyfile=$r->dir_config('lonDaemons').'/tmp/'.$1;
+ $reply=~/(.*?)\_/;
+ {
+ my $temp=0;
+ WLOOP: while (1) {
+ if (-e $replyfile && $tflag) {
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ $tflag=0;
+ }
+ if (-e "$replyfile.end") {
+ $bloop--;
+ $orkey{$rkey}=1;
+ if (-s $replyfile) {
+ $r->print(''."\n");
+ $r->rflush();
+ my $fh=Apache::File->new($replyfile) or
+ ($r->print('ERROR: file '.
+ $replyfile.' cannot be opened') and
+ return OK);
+ @results=<$fh> if $fh;
+ $hitcount{$rkey}=@results+0;
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ $hitcountsum+=$hitcount{$rkey};
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ }
+ else {
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ $r->print(''.
+ "\n");
+ $r->rflush();
+ }
+ last WLOOP;
+ }
+ if ($temp>1) {
+ sleep 1;
+ $timeremain--;
+ $elapsetime++;
+ last WLOOP;
+ }
+ last WLOOP unless $timeremain;
+ sleep 1;
+ $timeremain--;
+ $elapsetime++;
+ $r->print(''."\n");
+ $r->rflush();
+ $temp++;
+ }
}
- # QUESTION: how should I handle this error condition..
- # I'm sure there is syntax elsewhere I can use..
- my $fh=Apache::File->new($replyfile) or
- ($r->print('file cannot be opened') and return OK);
- @results=<$fh>;
+ $r->print(''."\n");
+ $r->rflush();
}
-
- my $compiledresult='';
-
+ my $customshow='';
+ my $extrashow='';
+ my @customfields;
+ if ($ENV{'form.customshow'}) {
+ $customshow=$ENV{'form.customshow'};
+ $customshow=~s/[^\w\s]//g;
+ my @fields=map {"$_:"}
+ split(/\s+/,$customshow);
+ @customfields=split(/\s+/,$customshow);
+ if ($customshow) {
+ $extrashow="
".join("
",@fields)."
\n";
+ }
+ }
+ my $customdata='';
+ my %customhash;
foreach my $result (@results) {
- my ($title,$author,$subject,$url,$keywords,$version,
- $notes,$abstract,$mime,$lang,
- $creationdate,$lastrevisiondate,$owner,$copyright
- )=map {&Apache::lonnet::unescape($_)} (split(/\,/,$result));
- my $shortabstract=$abstract;
- $shortabstract=substr($abstract,0,200) if length($abstract)>200;
- $compiledresult.=<- not displayed -';
+ $fields[4]=$keywords;
+ $notes='- not displayed -';
+ $fields[6]=$notes;
+ $abstract='- not displayed -';
+ $fields[7]=$abstract;
+ $subject='- not displayed -';
+ $fields[2]=$subject;
+ }
+
+ my $shortabstract=$abstract;
+ $shortabstract=substr($abstract,0,200).'...' if length($abstract)>200;
+ $fields[7]=$shortabstract;
+ my $shortkeywords=$keywords;
+ $shortkeywords=substr($keywords,0,200).'...' if length($keywords)>200;
+ $fields[4]=$shortkeywords;
+
+ my $extrashow2=$extrashow;
+ if ($extrashow) {
+ foreach my $field (@customfields) {
+ my $value='';
+ if ($customhash{$url}=~/\<${field}[^\>]*\>(.*?)\<\/${field}[^\>]*\>/s) {
+ $value=$1;
+ }
+ $extrashow2=~s/\<\!\-\- $field \-\-\>/ $value/g;
+ }
+ }
+
+ $compiledresult.=<
+END
+ $compiledresult.=<
END
- $compiledresult.=<
-
+
END
- $compiledresult.=<URL: $url
-
-Title: $title
-Author(s): $author
-Subject: $subject
-Keyword(s): $keywords
-Notes: $notes
-Abstract: $shortabstract
-MIME Type: $mimetag{$mime}
-Language: $language{$lang}
-Creation Date: $creationdate
-Last Revision Date: $lastrevisiondate
-Publisher/Owner: $owner
-Copyright/Distribution: $copyright
-Repository Location: $hostname
-
+ if ($ENV{'form.catalogmode'} eq 'groupsearch') {
+ $fnum+=0;
+ $hash{"pre_${fnum}_link"}=$url;
+ $hash{"pre_${fnum}_title"}=$title;
+ $compiledresult.=<
+
+
END
- }
+#
+#
+ $fnum++;
+ }
+ my $httphost=$ENV{'HTTP_HOST'};
+
+ 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,$httphost,
+ $extrashow2);
+ }
+ elsif ($viewselect eq 'Summary View') {
+ $compiledresult.=&summary_view(@fields,$hostname,$httphost,
+ $extrashow2);
+ }
+ elsif ($viewselect eq 'Fielded Format') {
+ $compiledresult.=&fielded_format_view(@fields,$hostname,
+ $httphost,$extrashow2);
+ }
+ elsif ($viewselect eq 'XML/SGML') {
+ $compiledresult.=&xml_sgml_view(@fields,$hostname,$httphost,
+ $extrashow2);
+ }
+
+ }
- unless ($compiledresult) {
- $compiledresult="There were no results that matched your query";
+ untie %hash;
+ }
+ else {
+ $r->print('Unable to tie hash to db '.
+ 'file');
}
+ if ($compiledresult) {
+ $resultflag=1;
+ }
+
+ $r->print(<print("\nThere were no results that matched your query\n");
+ }
+# $r->print(''."\n"); $r->rflush();
+ $r->print(<
+