Annotation of loncom/interface/lonsearchcat.pm, revision 1.221
1.98 harris41 1: # The LearningOnline Network with CAPA
1.108 harris41 2: # Search Catalog
3: #
1.221 ! matthew 4: # $Id: lonsearchcat.pm,v 1.220 2004/05/03 19:24:14 matthew Exp $
1.108 harris41 5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: #
10: # LON-CAPA is free software; you can redistribute it and/or modify
11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
1.98 harris41 14: #
1.108 harris41 15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
1.1 www 27: #
1.121 matthew 28: ###############################################################################
29: ###############################################################################
30:
31: =pod
32:
33: =head1 NAME
34:
1.140 matthew 35: lonsearchcat - LONCAPA Search Interface
1.121 matthew 36:
37: =head1 SYNOPSIS
38:
39: Search interface to LON-CAPAs digital library
40:
41: =head1 DESCRIPTION
42:
43: This module enables searching for a distributed browseable catalog.
1.104 harris41 44:
1.121 matthew 45: This is part of the LearningOnline Network with CAPA project
46: described at http://www.lon-capa.org.
47:
48: lonsearchcat presents the user with an interface to search the LON-CAPA
49: digital library. lonsearchcat also initiates the execution of a search
50: by sending the search parameters to LON-CAPA servers. The progress of
1.205 www 51: search (on a server basis) is displayed to the user in a separate window.
1.121 matthew 52:
53: =head1 Internals
54:
55: =over 4
56:
57: =cut
58:
59: ###############################################################################
1.98 harris41 60: ###############################################################################
1.121 matthew 61:
1.1 www 62: package Apache::lonsearchcat;
63:
64: use strict;
1.167 www 65: use Apache::Constants qw(:common :http);
1.6 harris41 66: use Apache::lonnet();
67: use Apache::File();
1.7 harris41 68: use CGI qw(:standard);
1.41 harris41 69: use Text::Query;
1.101 harris41 70: use GDBM_File;
1.112 harris41 71: use Apache::loncommon();
1.144 matthew 72: use Apache::lonmysql();
1.200 www 73: use Apache::lonmeta;
74: use Apache::lonhtmlcommon;
1.186 www 75: use Apache::lonlocal;
1.204 matthew 76: use LONCAPA::lonmetadata();
1.212 matthew 77: use HTML::Entities();
1.1 www 78:
1.121 matthew 79: ######################################################################
80: ######################################################################
1.196 matthew 81: ##
82: ## Global variables
83: ##
1.121 matthew 84: ######################################################################
85: ######################################################################
1.196 matthew 86: my %groupsearch_db; # Database hash used to save values for the
87: # groupsearch RAT interface.
88: my %persistent_db; # gdbm hash which holds data which is supposed to
89: # persist across calls to lonsearchcat.pm
1.121 matthew 90:
1.200 www 91: # The different view modes and associated functions
92:
93: my %Views = ("detailed" => \&detailed_citation_view,
94: "summary" => \&summary_view,
95: "fielded" => \&fielded_format_view,
96: "xml" => \&xml_sgml_view,
97: "compact" => \&compact_view);
1.101 harris41 98:
1.121 matthew 99: ######################################################################
100: ######################################################################
1.98 harris41 101: sub handler {
102: my $r = shift;
1.197 www 103: # &set_defaults();
1.196 matthew 104: #
105: # set form defaults
1.145 matthew 106: #
1.196 matthew 107: my $hidden_fields;# Hold all the hidden fields used to keep track
108: # of the search system state
109: my $importbutton; # button to take the selected results and go to group
110: # sorting
111: my $diropendb; # The full path to the (temporary) search database file.
112: # This is set and used in &handler() and is also used in
113: # &output_results().
114: my $bodytag; # LON-CAPA standard body tag, gotten from
115: # &Apache::lonnet::bodytag.
116: # No title, no table, just a <body> tag.
1.157 www 117:
118: my $loaderror=&Apache::lonnet::overloaderror($r);
119: if ($loaderror) { return $loaderror; }
1.221 ! matthew 120: #
1.145 matthew 121: my $closebutton; # button that closes the search window
122: # This button is different for the RAT compared to
123: # normal invocation.
124: #
1.186 www 125: &Apache::loncommon::content_type($r,'text/html');
1.98 harris41 126: $r->send_http_header;
127: return OK if $r->header_only;
1.156 matthew 128: ##
129: ## Prevent caching of the search interface window. Hopefully this means
130: ## we will get the launch=1 passed in a little more.
131: &Apache::loncommon::no_cache($r);
1.145 matthew 132: ##
133: ## Pick up form fields passed in the links.
134: ##
135: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.146 matthew 136: ['catalogmode','launch','acts','mode','form','element','pause',
1.158 matthew 137: 'phase','persistent_db_id','table','start','show',
1.191 albertel 138: 'cleargroupsort','titleelement']);
1.146 matthew 139: ##
140: ## The following is a trick - we wait a few seconds if asked to so
141: ## the daemon running the search can get ahead of the daemon
142: ## printing the results. We only need (theoretically) to do
143: ## this once, so the pause indicator is deleted
144: ##
145: if (exists($ENV{'form.pause'})) {
1.181 matthew 146: sleep(1);
1.146 matthew 147: delete($ENV{'form.pause'});
148: }
1.143 matthew 149: ##
150: ## Initialize global variables
151: ##
1.121 matthew 152: my $domain = $r->dir_config('lonDefDomain');
1.213 matthew 153: $diropendb= "/home/httpd/perl/tmp/".
154: "$ENV{'user.domain'}_$ENV{'user.name'}_searchcat.db";
1.145 matthew 155: #
156: # set the name of the persistent database
1.146 matthew 157: # $ENV{'form.persistent_db_id'} can only have digits in it.
1.145 matthew 158: if (! exists($ENV{'form.persistent_db_id'}) ||
1.147 matthew 159: ($ENV{'form.persistent_db_id'} =~ /\D/) ||
160: ($ENV{'form.launch'} eq '1')) {
1.145 matthew 161: $ENV{'form.persistent_db_id'} = time;
162: }
1.155 matthew 163: $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.146 matthew 164: my $persistent_db_file = "/home/httpd/perl/tmp/".
1.145 matthew 165: &Apache::lonnet::escape($domain).
166: '_'.&Apache::lonnet::escape($ENV{'user.name'}).
167: '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db';
1.146 matthew 168: ##
1.209 matthew 169: &Apache::lonhtmlcommon::clear_breadcrumbs();
170: if (exists($ENV{'request.course.id'}) && $ENV{'request.course.id'} ne '') {
171: &Apache::lonhtmlcommon::add_breadcrumb
172: ({href=>'/adm/searchcat?'.
173: 'catalogmode='.$ENV{'form.catalogmode'}.
174: '&launch='.$ENV{'form.launch'}.
175: '&mode='.$ENV{'form.mode'},
176: text=>"Course and Catalog Search",
177: bug=>'Searching',});
178: } else {
179: &Apache::lonhtmlcommon::add_breadcrumb
180: ({href=>'/adm/searchcat?'.
181: 'catalogmode='.$ENV{'form.catalogmode'}.
182: '&launch='.$ENV{'form.launch'}.
183: '&mode='.$ENV{'form.mode'},
184: text=>"Catalog Search",
185: bug=>'Searching',});
186: }
187: #
1.221 ! matthew 188: if ($ENV{'form.phase'} !~ m/(basic|adv|course)_search/) {
! 189: if (! &get_persistent_form_data($persistent_db_file)) {
! 190: if ($ENV{'form.phase'} =~ /(run_search|results)/) {
! 191: &Apache::lonnet::logthis('lonsearchcat:'.
! 192: 'Unable to recover data from '.
! 193: $persistent_db_file);
! 194: $r->print(<<END);
1.150 matthew 195: <html>
196: <head><title>LON-CAPA Search Error</title></head>
1.155 matthew 197: $bodytag
1.150 matthew 198: We were unable to retrieve data describing your search. This is a serious
199: error and has been logged. Please alert your LON-CAPA administrator.
200: </body>
201: </html>
202: END
1.221 ! matthew 203: return OK;
! 204: }
1.150 matthew 205: }
1.221 ! matthew 206: } else {
! 207: &clean_up_environment();
1.147 matthew 208: }
1.124 matthew 209: ##
1.143 matthew 210: ## Clear out old values from groupsearch database
1.124 matthew 211: ##
1.146 matthew 212: untie %groupsearch_db if (tied(%groupsearch_db));
1.158 matthew 213: if (($ENV{'form.cleargroupsort'} eq '1') ||
214: (($ENV{'form.launch'} eq '1') &&
215: ($ENV{'form.catalogmode'} eq 'groupsearch'))) {
1.148 matthew 216: if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {
1.101 harris41 217: &start_fresh_session();
1.142 matthew 218: untie %groupsearch_db;
1.158 matthew 219: delete($ENV{'form.cleargroupsort'});
1.122 matthew 220: } else {
1.155 matthew 221: # This is a stupid error to give to the user.
222: # It really tells them nothing.
223: $r->print('<html><head></head>'.$bodytag.
224: 'Unable to tie hash to db file</body></html>');
1.101 harris41 225: return OK;
226: }
227: }
1.124 matthew 228: ##
1.150 matthew 229: ## Configure hidden fields
1.124 matthew 230: ##
1.145 matthew 231: $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.
1.150 matthew 232: $ENV{'form.persistent_db_id'}.'" />'."\n";
233: if (exists($ENV{'form.catalogmode'})) {
234: $hidden_fields .= '<input type="hidden" name="catalogmode" value="'.
235: $ENV{'form.catalogmode'}.'" />'."\n";
236: }
237: if (exists($ENV{'form.form'})) {
238: $hidden_fields .= '<input type="hidden" name="form" value="'.
239: $ENV{'form.form'}.'" />'."\n";
240: }
241: if (exists($ENV{'form.element'})) {
242: $hidden_fields .= '<input type="hidden" name="element" value="'.
243: $ENV{'form.element'}.'" />'."\n";
244: }
1.191 albertel 245: if (exists($ENV{'form.titleelement'})) {
246: $hidden_fields .= '<input type="hidden" name="titleelement" value="'.
247: $ENV{'form.titleelement'}.'" />'."\n";
248: }
1.150 matthew 249: if (exists($ENV{'form.mode'})) {
250: $hidden_fields .= '<input type="hidden" name="mode" value="'.
251: $ENV{'form.mode'}.'" />'."\n";
252: }
253: ##
254: ## Configure dynamic components of interface
1.146 matthew 255: ##
1.98 harris41 256: if ($ENV{'form.catalogmode'} eq 'interactive') {
1.150 matthew 257: $closebutton="<input type='button' name='close' value='CLOSE' ";
258: if ($ENV{'form.phase'} =~ /(results|run_search)/) {
259: $closebutton .="onClick='parent.close()'";
260: } else {
261: $closebutton .="onClick='self.close()'";
262: }
263: $closebutton .=">\n";
1.124 matthew 264: } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {
1.150 matthew 265: $closebutton="<input type='button' name='close' value='CLOSE' ";
266: if ($ENV{'form.phase'} =~ /(results|run_search)/) {
267: $closebutton .="onClick='parent.close()'";
268: } else {
269: $closebutton .="onClick='self.close()'";
270: }
271: $closebutton .= ">";
1.98 harris41 272: $importbutton=<<END;
273: <input type='button' name='import' value='IMPORT'
274: onClick='javascript:select_group()'>
275: END
1.146 matthew 276: } else {
277: $closebutton = '';
278: $importbutton = '';
1.98 harris41 279: }
1.124 matthew 280: ##
1.146 matthew 281: ## Sanity checks on form elements
1.124 matthew 282: ##
1.146 matthew 283: if (!defined($ENV{'form.viewselect'})) {
1.150 matthew 284: if (($ENV{'form.catalogmode'} eq 'groupsearch') ||
285: ($ENV{'form.catalogmode'} eq 'interactive')) {
286: $ENV{'form.viewselect'} ="Compact View";
287: } else {
288: $ENV{'form.viewselect'} ="Detailed Citation View";
289: }
1.146 matthew 290: }
1.149 matthew 291: $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'}));
1.151 matthew 292: $ENV{'form.show'} = 20 if (! exists($ENV{'form.show'}));
1.209 matthew 293: #
1.219 matthew 294: $ENV{'form.searchmode'} = 'basic' if (! exists($ENV{'form.searchmode'}));
1.209 matthew 295: if ($ENV{'form.phase'} eq 'adv_search' ||
296: $ENV{'form.phase'} eq 'disp_adv') {
297: $ENV{'form.searchmode'} = 'advanced';
298: } elsif ($ENV{'form.phase'} eq 'course_search') {
299: $ENV{'form.searchmode'} = 'course_search';
300: }
301: #
302: if ($ENV{'form.searchmode'} eq 'advanced') {
303: &Apache::lonhtmlcommon::add_breadcrumb
304: ({href=>'/adm/searchcat?phase=disp_adv&'.
305: 'catalogmode='.$ENV{'form.catalogmode'}.
306: '&launch='.$ENV{'form.launch'}.
307: '&mode='.$ENV{'form.mode'},
308: text=>"Advanced Search",
309: bug=>'Searching',});
310: } elsif ($ENV{'form.searchmode'} eq 'course search') {
311: &Apache::lonhtmlcommon::add_breadcrumb
312: ({href=>'/adm/searchcat?phase=disp_adv&'.
313: 'catalogmode='.$ENV{'form.catalogmode'}.
314: '&launch='.$ENV{'form.launch'}.
315: '&mode='.$ENV{'form.mode'},
316: text=>"Course Search",
317: bug=>'Searching',});
318: }
1.146 matthew 319: ##
320: ## Switch on the phase
321: ##
322: if ($ENV{'form.phase'} eq 'disp_basic') {
1.196 matthew 323: &print_basic_search_form($r,$closebutton,$hidden_fields);
1.146 matthew 324: } elsif ($ENV{'form.phase'} eq 'disp_adv') {
1.196 matthew 325: &print_advanced_search_form($r,$closebutton,$hidden_fields);
1.146 matthew 326: } elsif ($ENV{'form.phase'} eq 'results') {
1.196 matthew 327: &display_results($r,$importbutton,$closebutton,$diropendb);
1.151 matthew 328: } elsif ($ENV{'form.phase'} =~ /^(sort|run_search)$/) {
1.146 matthew 329: my ($query,$customquery,$customshow,$libraries,$pretty_string) =
330: &get_persistent_data($persistent_db_file,
331: ['query','customquery','customshow',
332: 'libraries','pretty_string']);
1.151 matthew 333: if ($ENV{'form.phase'} eq 'sort') {
334: &print_sort_form($r,$pretty_string);
335: } elsif ($ENV{'form.phase'} eq 'run_search') {
336: &run_search($r,$query,$customquery,$customshow,
337: $libraries,$pretty_string);
338: }
1.167 www 339: } elsif ($ENV{'form.phase'} eq 'course_search') {
340: &course_search($r);
1.146 matthew 341: } elsif(($ENV{'form.phase'} eq 'basic_search') ||
342: ($ENV{'form.phase'} eq 'adv_search')) {
343: # Set up table
344: if (! defined(&create_results_table())) {
1.198 www 345: my $errorstring=&Apache::lonmysql::get_error();
1.211 matthew 346: &Apache::lonnet::logthis('lonsearchcat.pm: Unable to create '.
347: 'needed table. lonmysql error:'.
348: $errorstring);
1.147 matthew 349: $r->print(<<END);
350: <html><head><title>Search Error</title></head>
1.155 matthew 351: $bodytag
1.147 matthew 352: Unable to create table in which to store search results.
353: The search has been aborted.
354: </body>
355: </html>
356: END
357: return OK;
1.146 matthew 358: }
1.147 matthew 359: delete($ENV{'form.launch'});
1.146 matthew 360: if (! &make_form_data_persistent($r,$persistent_db_file)) {
1.147 matthew 361: $r->print(<<END);
362: <html><head><title>Search Error</title></head>
1.155 matthew 363: $bodytag
1.147 matthew 364: Unable to properly store search information. The search has been aborted.
365: </body>
366: </html>
367: END
368: return OK;
1.146 matthew 369: }
1.145 matthew 370: #
1.139 matthew 371: # We are running a search
1.134 matthew 372: my ($query,$customquery,$customshow,$libraries) =
373: (undef,undef,undef,undef);
1.143 matthew 374: my $pretty_string;
1.146 matthew 375: if ($ENV{'form.phase'} eq 'basic_search') {
1.180 matthew 376: ($query,$pretty_string,$libraries) =
1.196 matthew 377: &parse_basic_search($r,$closebutton,$hidden_fields);
1.146 matthew 378: } else { # Advanced search
1.143 matthew 379: ($query,$customquery,$customshow,$libraries,$pretty_string)
1.196 matthew 380: = &parse_advanced_search($r,$closebutton,$hidden_fields);
1.134 matthew 381: return OK if (! defined($query));
382: }
1.152 matthew 383: &make_persistent({ query => $query,
1.146 matthew 384: customquery => $customquery,
385: customshow => $customshow,
386: libraries => $libraries,
387: pretty_string => $pretty_string },
388: $persistent_db_file);
1.145 matthew 389: ##
1.146 matthew 390: ## Print out the frames interface
1.145 matthew 391: ##
1.146 matthew 392: &print_frames_interface($r);
1.124 matthew 393: }
394: return OK;
395: }
1.98 harris41 396:
1.221 ! matthew 397: #
! 398: # The mechanism used to store values away and retrieve them does not
! 399: # handle the case of missing environment variables being significant.
! 400: #
! 401: # This routine sets non existant checkbox form elements to ''.
! 402: #
! 403: sub clean_up_environment {
! 404: if ($ENV{'form.phase'} eq 'basic_search') {
! 405: if (! exists($ENV{'form.related'})) {
! 406: $ENV{'form.related'} = '';
! 407: }
! 408: if (! exists($ENV{'form.domains'})) {
! 409: $ENV{'form.domains'} = '';
! 410: }
! 411: } elsif ($ENV{'form.phase'} eq 'adv_search') {
! 412: foreach my $field ('title','keywords','notes',
! 413: 'abstract','standards','mime') {
! 414: if (! exists($ENV{'form.'.$field.'_related'})) {
! 415: $ENV{'form.'.$field.'_related'} = '';
! 416: }
! 417: }
! 418: } elsif ($ENV{'form.phase'} eq 'course_search') {
! 419: if (! exists($ENV{'form.crsrelated'})) {
! 420: $ENV{'form.crsrelated'} = '';
! 421: }
! 422: }
! 423: }
! 424:
1.124 matthew 425: ######################################################################
426: ######################################################################
1.196 matthew 427: ##
428: ## Course Search
429: ##
430: ######################################################################
431: ######################################################################
432: { # Scope the course search to avoid global variables
433: #
434: # Variables For course search
435: my %alreadyseen;
436: my %hash;
437: my $totalfound;
1.124 matthew 438:
1.167 www 439: sub course_search {
440: my $r=shift;
1.217 matthew 441: my $bodytag=&Apache::loncommon::bodytag('Course Search');
1.167 www 442: my $pretty_search_string = '<b>'.$ENV{'form.courseexp'}.'</b>';
443: my $search_string = $ENV{'form.courseexp'};
444: my @New_Words;
445: if ($ENV{'form.crsrelated'}) {
446: ($search_string,@New_Words) = &related_version($ENV{'form.courseexp'});
447: if (@New_Words) {
1.200 www 448: $pretty_search_string .= ' '.&mt("with related words").": <b>@New_Words</b>.";
1.167 www 449: } else {
1.200 www 450: $pretty_search_string .= ' '.&mt('with no related words').".";
1.167 www 451: }
452: }
453: my $fulltext=$ENV{'form.crsfulltext'};
454: my @allwords=($search_string,@New_Words);
1.169 www 455: $totalfound=0;
1.167 www 456: $r->print('<html><head><title>LON-CAPA Course Search</title></head>'.
1.203 www 457: $bodytag.'<hr /><center><font size="+2" face="arial">'.$pretty_search_string.'</font></center><hr />');
1.167 www 458: $r->rflush();
459: # ======================================================= Go through the course
1.196 matthew 460: undef %alreadyseen;
461: %alreadyseen=();
1.169 www 462: my $c=$r->connection;
1.196 matthew 463: if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.".db",
464: &GDBM_READER(),0640)) {
465: foreach (keys %hash) {
466: if ($c->aborted()) { last; }
467: if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) {
468: &checkonthis($r,$hash{$_},0,$hash{'title_'.$1},$fulltext,
469: @allwords);
470: }
471: }
472: untie(%hash);
473: }
1.169 www 474: unless ($totalfound) {
1.187 www 475: $r->print('<p>'.&mt('No resources found').'.</p>');
1.169 www 476: }
1.167 www 477: # =================================================== Done going through course
478: $r->print('</body></html>');
479: }
480:
481: # =============================== This pulls up a resource and its dependencies
482:
483: sub checkonthis {
1.168 www 484: my ($r,$url,$level,$title,$fulltext,@allwords)=@_;
1.167 www 485: $alreadyseen{$url}=1;
486: $r->rflush();
487: my $result=&Apache::lonnet::metadata($url,'title').' '.
488: &Apache::lonnet::metadata($url,'subject').' '.
489: &Apache::lonnet::metadata($url,'abstract').' '.
490: &Apache::lonnet::metadata($url,'keywords');
491: if (($url) && ($fulltext)) {
1.168 www 492: $result.=&Apache::lonnet::ssi_body($url);
1.167 www 493: }
494: $result=~s/\s+/ /gs;
495: my $applies=0;
496: foreach (@allwords) {
497: if ($_=~/\w/) {
498: if ($result=~/$_/si) {
499: $applies++;
500: }
501: }
502: }
503: # Does this resource apply?
504: if ($applies) {
505: $r->print('<br />');
506: for (my $i=0;$i<=$level*5;$i++) {
507: $r->print(' ');
508: }
509: $r->print('<a href="'.$url.'" target="cat">'.
1.169 www 510: ($title?$title:$url).'</a><br />');
511: $totalfound++;
512: } elsif ($fulltext) {
513: $r->print(' .');
1.167 www 514: }
1.169 www 515: $r->rflush();
1.167 www 516: # Check also the dependencies of this one
517: my $dependencies=
518: &Apache::lonnet::metadata($url,'dependencies');
519: foreach (split(/\,/,$dependencies)) {
520: if (($_=~/^\/res\//) && (!$alreadyseen{$_})) {
1.168 www 521: &checkonthis($r,$_,$level+1,'',$fulltext,@allwords);
1.167 www 522: }
523: }
524: }
525:
1.196 matthew 526: sub untiehash {
527: if (tied(%hash)) {
528: untie(%hash);
529: }
530: }
531:
532: } # End of course search scoping
533:
1.207 matthew 534: sub search_html_header {
535: my $Str = <<ENDHEADER;
536: <html>
537: <head>
538: <title>The LearningOnline Network with CAPA</title>
539: </head>
540: ENDHEADER
541: return $Str;
542: }
543:
1.167 www 544: ######################################################################
545: ######################################################################
546:
1.124 matthew 547: =pod
548:
1.146 matthew 549: =item &print_basic_search_form()
1.124 matthew 550:
1.204 matthew 551: Prints the form for the basic search. Sorry the name is so cryptic.
1.124 matthew 552:
553: =cut
554:
555: ######################################################################
556: ######################################################################
1.204 matthew 557: sub print_basic_search_form {
1.196 matthew 558: my ($r,$closebutton,$hidden_fields) = @_;
1.203 www 559: my $bodytag=&Apache::loncommon::bodytag('Search').
1.217 matthew 560: &Apache::lonhtmlcommon::breadcrumbs(undef,'Searching','Searching',
1.209 matthew 561: undef,undef,! $ENV{'form.launch'});
1.207 matthew 562: my $scrout = &search_html_header().$bodytag;
563: if (&Apache::lonnet::allowed('bre',$ENV{'request.role.domain'})) {
1.213 matthew 564: # Define interface components
565: my $userelatedwords=
566: &mt('[_1] use related words',
567: &Apache::lonhtmlcommon::checkbox
1.221 ! matthew 568: ('related',$ENV{'form.related'},'related'));
1.213 matthew 569: my $onlysearchdomain=
570: &mt('[_1] only search domain [_2]',
1.221 ! matthew 571: &Apache::lonhtmlcommon::checkbox('domains',
! 572: $ENV{'form.domains'},
! 573: $r->dir_config('lonDefDomain')
! 574: ),
! 575: $r->dir_config('lonDefDomain')
! 576: );
1.213 matthew 577: my $adv_search_link =
578: '<a href="/adm/searchcat?'.
579: 'phase=disp_adv&'.
580: 'catalogmode='.$ENV{'form.catalogmode'}.
581: '&launch='.$ENV{'form.launch'}.
582: '&mode='.$ENV{'form.mode'}.
583: '">'.&mt('Advanced Search').'</a>';
584: #
585: $scrout.='<form name="loncapa_search" method="post" '.
586: 'action="/adm/searchcat">'.
587: '<input type="hidden" name="phase" value="basic_search" />'.
588: $hidden_fields;
589: #
590: $scrout .= '<center>'.$/;
591: if ($ENV{'request.course.id'}) {
592: $scrout .= '<h1>'.&mt('LON-CAPA Catalog Search').'</h1>';
593: } else {
594: # No need to tell them they are searching
595: $scrout.= ('<br />'x2);
596: }
597: $scrout.='<table>'.
598: '<tr><td align="center" valign="top">'.
1.208 matthew 599: &Apache::lonhtmlcommon::textbox('basicexp',
1.213 matthew 600: $ENV{'form.basicexp'},50).'<br />'.
601: '<font size="-1">'.&searchhelp().'</font>'.'</td>'.
602: '<td><font size="-1">'.
603: '<nobr>'.(' 'x3).$adv_search_link.'</nobr>'.'<br />'.
604: '<nobr>'.(' 'x1).$userelatedwords.'</nobr>'.'<br />'.
605: '<nobr>'.(' 'x1).$onlysearchdomain.'</nobr>'.'<br />'.
606: '</font></td>'.
607: '</tr>'.$/;
608: #
609: # $scrout .= '<tr><td align="center">'.
610: # '<font size="-1">'.
611: # $userelatedwords.(' 'x3).
612: # $onlysearchdomain.(' 'x2).$adv_search_link.
613: # '</font>'.
614: # '</td></tr>'.$/;
615: $scrout .= '<tr><td align="center" colspan="2">'.
616: '<font size="-1">'.
617: '<input type="submit" name="basicsubmit" '.
618: 'value="'.&mt('Search').'" />'.
619: (' 'x2).$closebutton.(' 'x2).&viewoptions().
620: '</font>'.
621: '</td></tr>'.$/;
622: $scrout .= '</table>'.$/.'</center>'.'</form>';
1.180 matthew 623: }
624: if ($ENV{'request.course.id'}) {
1.213 matthew 625: my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
1.187 www 626: 'header' => 'Course Search',
627: 'note' => 'Enter terms or phrases, then press "Search" below',
1.200 www 628: 'use' => 'use related words',
629: 'full' =>'fulltext search (time consuming)'
1.187 www 630: );
1.180 matthew 631: $scrout.=(<<ENDCOURSESEARCH);
1.213 matthew 632: <form name="loncapa_search" method="post" action="/adm/searchcat">
633: <center>
1.180 matthew 634: <hr />
1.187 www 635: <h1>$lt{'header'}</h1>
1.167 www 636: <input type="hidden" name="phase" value="course_search" />
637: $hidden_fields
638: <p>
1.187 www 639: $lt{'note'}.
1.167 www 640: </p>
641: <p>
642: <table>
643: <tr><td>
644: ENDCOURSESEARCH
1.180 matthew 645: $scrout.=' '.
1.200 www 646: &Apache::lonhtmlcommon::textbox('courseexp',
647: $ENV{'form.courseexp'},40);
1.180 matthew 648: my $crscheckbox =
1.200 www 649: &Apache::lonhtmlcommon::checkbox('crsfulltext',
650: $ENV{'form.crsfulltext'});
1.180 matthew 651: my $relcheckbox =
1.200 www 652: &Apache::lonhtmlcommon::checkbox('crsrelated',
653: $ENV{'form.crsrelated'});
1.180 matthew 654: $scrout.=(<<ENDENDCOURSE);
1.167 www 655: </td></tr>
1.200 www 656: <tr><td>$relcheckbox $lt{'use'}</td><td></td></tr>
657: <tr><td>$crscheckbox $lt{'full'}</td><td></td></tr>
1.167 www 658: </table><p>
1.187 www 659: <input type="submit" name="coursesubmit" value='$lt{'srch'}' />
1.167 www 660: </p>
1.213 matthew 661: </center>
662: </form>
1.167 www 663: ENDENDCOURSE
1.180 matthew 664: }
1.167 www 665: $scrout.=(<<ENDDOCUMENT);
1.124 matthew 666: </body>
667: </html>
668: ENDDOCUMENT
1.146 matthew 669: $r->print($scrout);
670: return;
1.124 matthew 671: }
672: ######################################################################
673: ######################################################################
674:
675: =pod
676:
677: =item &advanced_search_form()
678:
1.204 matthew 679: Prints the advanced search form.
1.124 matthew 680:
681: =cut
682:
683: ######################################################################
684: ######################################################################
1.146 matthew 685: sub print_advanced_search_form{
1.196 matthew 686: my ($r,$closebutton,$hidden_fields) = @_;
1.217 matthew 687: my $bodytag=&Apache::loncommon::bodytag('Advanced Catalog Search').
688: &Apache::lonhtmlcommon::breadcrumbs(undef,'Searching',
689: 'Searching',
690: undef,undef,
691: ! $ENV{'form.launch'});
692:
1.200 www 693: my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
694: 'reset' => 'Reset',
695: 'help' => 'Help');
1.217 matthew 696: my $advanced_buttons=<<"END";
1.200 www 697: <input type="submit" name="advancedsubmit" value='$lt{"srch"}' />
698: <input type="reset" name="reset" value='$lt{"reset"}' />
1.129 matthew 699: $closebutton
700: END
1.207 matthew 701: my $scrout=&search_html_header();
702: $scrout .= <<"ENDHEADER";
1.154 www 703: $bodytag
1.200 www 704: <form method="post" action="/adm/searchcat" name="advsearch">
1.217 matthew 705: <p>
1.129 matthew 706: $advanced_buttons
1.124 matthew 707: ENDHEADER
1.208 matthew 708: $scrout.=(' 'x2).&viewoptions().'</p>'.$hidden_fields.
709: '<input type="hidden" name="phase" value="adv_search" />';
1.200 www 710: my %fields=&Apache::lonmeta::fieldnames();
1.208 matthew 711: #
1.217 matthew 712: $scrout .= '<h3>'.&mt('Standard Metadata').'</h3>';
713: $scrout .= "<table>\n";
714: $scrout .= '<tr><td> </td><td colspan="2"><font size="-1">'.
715: (' 'x2).&searchhelp()."</font></td></tr>\n";
1.208 matthew 716: my %related_word_search =
1.217 matthew 717: ('title' => 1,
718: 'author' => 0,
719: 'owner' => 0,
720: 'authorspace' => 0,
721: 'modifyinguser'=> 0,
722: 'keywords' => 1,
723: 'notes' => 1,
724: 'abstract' => 1,
725: 'standards'=> 1,
726: 'mime' => 1,
1.208 matthew 727: );
1.209 matthew 728: #
1.208 matthew 729: foreach my $field ('title','author','owner','authorspace','modifyinguser',
730: 'keywords','notes','abstract','standards','mime') {
731: $scrout.='<tr><td align="right">'.&titlefield($fields{$field}).'</td><td>'.
732: &Apache::lonmeta::prettyinput($field,
733: $ENV{'form.'.$field},
734: $field,
735: 'advsearch',
736: $related_word_search{$field},
737: '</td><td align="left">',
738: $ENV{'form.'.$field.'_related'},
739: 50);
740: if ($related_word_search{$field}) {
741: $scrout .= 'related words';
742: } else {
743: $scrout .= '</td><td> ';
744: }
745: $scrout .= '</td></tr>'.$/;
746: }
747: foreach my $field ('lowestgradelevel','highestgradelevel') {
748: $scrout.='<tr>'.
749: '<td align="right">'.&titlefield($fields{$field}).'</td>'.
750: '<td colspan="2">'.
751: &Apache::lonmeta::prettyinput($field,
752: $ENV{'form.'.$field},
753: $field,
754: 'advsearch',
755: 0).
756: '</td></tr>'.$/;
1.200 www 757: }
1.208 matthew 758: $scrout.='<tr><td align="right">'.
759: &titlefield(&mt('MIME Type Category')).'</td><td colspan="2">'.
1.202 www 760: &Apache::loncommon::filecategoryselect('category',
761: $ENV{'form.category'}).
1.208 matthew 762: '</td></tr>'.$/;
763: $scrout.='<tr><td align="right" valign="top">'.
764: &titlefield(&mt('Domains')).'</td><td colspan="2">'.
1.202 www 765: &Apache::loncommon::domain_select('domains',
766: $ENV{'form.domains'},1).
1.208 matthew 767: '</td></tr>'.$/;
1.217 matthew 768: #
769: # Misc metadata
770: $scrout.='<tr><td align="right" valign="top">'.
771: &titlefield(&mt('Copyright/Distribution')).'</td><td colspan="2">'.
772: &Apache::lonmeta::selectbox('copyright',
773: '',,
774: \&Apache::loncommon::copyrightdescription,
775: ( undef,
776: &Apache::loncommon::copyrightids)
777: ).'</td></tr>'.$/;
778: $scrout.='<tr><td align="right" valign="top">'.
779: &titlefield(&mt('Language')).'</td><td colspan="2">'.
780: &Apache::lonmeta::selectbox('language',
781: 'notset',,
782: \&Apache::loncommon::languagedescription,
783: ('any',&Apache::loncommon::languageids)
784: ).'</td></tr>';
785: $scrout .= "</table>\n";
786: #
787: # Dynamic metadata
788: $scrout .= '<h3>'.&mt('Problem Statistics').'</h3>';
789: $scrout .= "<table>\n";
790: $scrout .= '<tr><td> </td><td align="center">'.&mt('Minimum').'</td>'.
791: '<td align="center">'.&mt('Maximum').'</td></tr>'."\n";
792: foreach my $statistic
793: ({ name=>'stdno',
794: description=>'Number of Students',},
795: { name => 'avetries',
796: description=>'Average tries to answer correctly',},
797: { name => 'difficulty',
798: description=>'Degree of difficulty',},
799: { name => 'disc',
800: description=>'Degree of discrimination'}) {
801: $scrout .= '<tr><td align="right">'.
802: &titlefield(&mt($statistic->{'description'})).
803: '</td><td align="center">'.
804: '<input type="text" name="'.$statistic->{'name'}.'_min" '.
805: 'value="" size="6" />'.
806: '</td><td align="center">'.
807: '<input type="text" name="'.$statistic->{'name'}.'_max" '.
808: 'value="" size="6" />'.
809: '</td></tr>'.$/;
810: }
811: $scrout .= "</table>\n";
812: $scrout .= '<h3>'.&mt('Evaluation Data').'</h3>';
813: $scrout .= "<table>\n";
814: $scrout .= '<tr><td> </td><td align="center">'.&mt('Minimum').'</td>'.
815: '<td align="center">'.&mt('Maximum').'</td></tr>'."\n";
816: foreach my $evaluation
817: ( { name => 'clear',
818: description => 'Material presented in clear way'},
819: { name =>'depth',
820: description => 'Material covered with sufficient depth'},
821: { name => 'helpful',
822: description => 'Material is helpful'},
823: { name => 'correct',
824: description => 'Material appears to be correct'},
825: { name => 'technical',
826: description => 'Resource is technically correct'}){
827: $scrout .= '<tr><td align="right">'.
828: &titlefield(&mt($evaluation->{'description'})).
829: '</td><td align="center">'.
830: '<input type="text" name="'.$evaluation->{'name'}.'_min" '.
831: 'value="" size="6" />'.
832: '</td><td align="center">'.
833: '<input type="text" name="'.$evaluation->{'name'}.'_max" '.
834: 'value="" size="6" />'.
835: '</td></tr>'.$/;
836: }
837: $scrout .= "</table>\n";
1.216 matthew 838: #
839: # Creation/Modification date limits
1.217 matthew 840: $scrout .= '<h3>'.&mt('Creation and Modification dates').'</h3>';
1.216 matthew 841: $scrout .= "\n<table>\n";
842: my $cafter =
843: &Apache::lonhtmlcommon::date_setter('advsearch', # formname
844: 'creationdate1', # fieldname
845: 0, # current value
846: '', # special
847: 1, # includeempty
848: '', # state
849: 1, # no_hh_mm_ss
850: );
851: my $cbefore =
852: &Apache::lonhtmlcommon::date_setter('advsearch', # formname
853: 'creationdate2', # fieldname
854: 0, # current value
855: '', # special
856: 1, # includeempty
857: '', # state
858: 1, # no_hh_mm_ss
859: );
860: $scrout .= &mt('<tr><td align="right">Created between</td>'.
861: '<td>[_1]</td></tr>'.
862: '<tr><td align="right">and </td>'.
863: '<td>[_2]</td></tr>',$cafter,$cbefore);
864: my $lafter =
865: &Apache::lonhtmlcommon::date_setter('advsearch',
866: 'revisiondate1',
867: 0, # current value
868: '', # special
869: 1, # includeempty
870: '', # state
871: 1, # no_hh_mm_ss
872: );
873: my $lbefore =
874: &Apache::lonhtmlcommon::date_setter('advsearch',
875: 'revisiondate2',
876: 0, # current value
877: '', # special
878: 1, # includeempty
879: '', # state
880: 1, # no_hh_mm_ss
881: );
882: $scrout .= &mt('<tr><td align="right">Last modified between </td>'.
883: '<td>[_1]</td></tr>'.
884: '<tr><td align="right">and</td>'.
885: '<td>[_2]</td></tr>',$lafter,$lbefore);
1.202 www 886: $scrout.="</table>\n";
1.124 matthew 887: $scrout.=<<ENDDOCUMENT;
1.129 matthew 888: $advanced_buttons
1.8 harris41 889: </form>
890: </body>
891: </html>
892: ENDDOCUMENT
1.146 matthew 893: $r->print($scrout);
894: return;
1.124 matthew 895: }
1.204 matthew 896:
1.200 www 897: ######################################################################
898: ######################################################################
899:
900: =pod
901:
1.204 matthew 902: =item &titlefield()
1.200 www 903:
904: Inputs: title text
905:
906: Outputs: titletext with font wrapper
907:
908: =cut
909:
910: ######################################################################
911: ######################################################################
912: sub titlefield {
913: my $title=shift;
1.208 matthew 914: return $title;
1.200 www 915: }
1.204 matthew 916:
1.200 www 917: ######################################################################
918: ######################################################################
919:
920: =pod
921:
1.204 matthew 922: =item viewoptiontext()
1.200 www 923:
924: Inputs: codename for view option
925:
926: Outputs: displayed text
927:
928: =cut
929:
930: ######################################################################
931: ######################################################################
932: sub viewoptiontext {
933: my $code=shift;
1.204 matthew 934: my %desc=&Apache::lonlocal::texthash
935: ('detailed' => "Detailed Citation View",
936: 'xml' => 'XML/SGML',
937: 'compact' => 'Compact View',
938: 'fielded' => 'Fielded Format',
939: 'summary' => 'Summary View');
1.200 www 940: return $desc{$code};
941: }
1.204 matthew 942:
943: ######################################################################
1.200 www 944: ######################################################################
945:
946: =pod
947:
1.204 matthew 948: =item viewoptions()
1.200 www 949:
950: Inputs: none
951:
952: Outputs: text for box with view options
953:
954: =cut
955:
956: ######################################################################
957: ######################################################################
958: sub viewoptions {
1.208 matthew 959: my $scrout="\n".'<nobr>';
960: if (! defined($ENV{'form.viewselect'})) {
961: $ENV{'form.viewselect'}='detailed';
962: }
1.200 www 963: $scrout.=&Apache::lonmeta::selectbox('viewselect',
964: $ENV{'form.viewselect'},
965: \&viewoptiontext,
966: sort(keys(%Views)));
1.208 matthew 967: $scrout.= ' ';
1.214 matthew 968: my $countselect = &Apache::lonmeta::selectbox('show',
969: $ENV{'form.show'},
970: undef,
971: (10,20,50,100,1000,10000));
972: $scrout .= (' 'x2).&mt('[_1] Records per Page',$countselect).
973: '</nobr>'.$/;
1.200 www 974: return $scrout;
1.201 www 975: }
976:
977: ######################################################################
1.204 matthew 978: ######################################################################
1.201 www 979:
980: =pod
981:
1.204 matthew 982: =item searchhelp()
1.201 www 983:
984: Inputs: none
985:
986: Outputs: return little blurb on how to enter searches
987:
988: =cut
989:
990: ######################################################################
991: ######################################################################
992: sub searchhelp {
993: return &mt('Enter terms or phrases separated by AND, OR, or NOT');
1.200 www 994: }
1.8 harris41 995:
1.121 matthew 996: ######################################################################
997: ######################################################################
998:
999: =pod
1000:
1.204 matthew 1001: =item &get_persistent_form_data()
1.145 matthew 1002:
1.146 matthew 1003: Inputs: filename of database
1004:
1005: Outputs: returns undef on database errors.
1006:
1007: This function is the reverse of &make_persistent() for form data.
1.145 matthew 1008: Retrieve persistent data from %persistent_db. Retrieved items will have their
1.146 matthew 1009: values unescaped. If a form value already exists in $ENV, it will not be
1010: overwritten. Form values that are array references may have values appended
1011: to them.
1.145 matthew 1012:
1013: =cut
1014:
1015: ######################################################################
1016: ######################################################################
1.146 matthew 1017: sub get_persistent_form_data {
1018: my $filename = shift;
1.147 matthew 1019: return 0 if (! -e $filename);
1.146 matthew 1020: return undef if (! tie(%persistent_db,'GDBM_File',$filename,
1.148 matthew 1021: &GDBM_READER(),0640));
1.146 matthew 1022: #
1023: # These make sure we do not get array references printed out as 'values'.
1.161 matthew 1024: my %arrays_allowed = ('form.domains'=>1);
1.146 matthew 1025: #
1026: # Loop through the keys, looking for 'form.'
1027: foreach my $name (keys(%persistent_db)) {
1028: next if ($name !~ /^form./);
1.182 matthew 1029: # Kludgification begins!
1030: if ($name eq 'form.domains' &&
1031: $ENV{'form.searchmode'} eq 'basic' &&
1032: $ENV{'form.phase'} ne 'disp_basic') {
1033: next;
1034: }
1035: # End kludge (hopefully)
1.152 matthew 1036: next if (exists($ENV{$name}));
1.146 matthew 1037: my @values = map {
1038: &Apache::lonnet::unescape($_);
1039: } split(',',$persistent_db{$name});
1040: next if (@values <1);
1.152 matthew 1041: if ($arrays_allowed{$name}) {
1042: $ENV{$name} = [@values];
1.146 matthew 1043: } else {
1.152 matthew 1044: $ENV{$name} = $values[0] if ($values[0]);
1.146 matthew 1045: }
1046: }
1047: untie (%persistent_db);
1048: return 1;
1049: }
1.181 matthew 1050:
1.146 matthew 1051: ######################################################################
1052: ######################################################################
1053:
1054: =pod
1055:
1.204 matthew 1056: =item &get_persistent_data()
1.146 matthew 1057:
1058: Inputs: filename of database, ref to array of values to recover.
1059:
1060: Outputs: array of values. Returns undef on error.
1061:
1062: This function is the reverse of &make_persistent();
1063: Retrieve persistent data from %persistent_db. Retrieved items will have their
1064: values unescaped. If the item contains commas (before unescaping), the
1065: returned value will be an array pointer.
1066:
1067: =cut
1068:
1069: ######################################################################
1070: ######################################################################
1071: sub get_persistent_data {
1072: my $filename = shift;
1073: my @Vars = @{shift()};
1074: my @Values; # Return array
1075: return undef if (! -e $filename);
1076: return undef if (! tie(%persistent_db,'GDBM_File',$filename,
1.148 matthew 1077: &GDBM_READER(),0640));
1.146 matthew 1078: foreach my $name (@Vars) {
1079: if (! exists($persistent_db{$name})) {
1080: push @Values, undef;
1081: next;
1082: }
1083: my @values = map {
1084: &Apache::lonnet::unescape($_);
1085: } split(',',$persistent_db{$name});
1.152 matthew 1086: if (@values <= 1) {
1.146 matthew 1087: push @Values,$values[0];
1.145 matthew 1088: } else {
1.146 matthew 1089: push @Values,\@values;
1.145 matthew 1090: }
1091: }
1.146 matthew 1092: untie (%persistent_db);
1093: return @Values;
1.145 matthew 1094: }
1095:
1096: ######################################################################
1097: ######################################################################
1098:
1099: =pod
1100:
1.121 matthew 1101: =item &make_persistent()
1102:
1.146 matthew 1103: Inputs: Hash of values to save, filename of persistent database.
1104:
1105: Store variables away to the %persistent_db.
1.145 matthew 1106: Values will be escaped. Values that are array pointers will have their
1.205 www 1107: elements escaped and concatenated in a comma separated string.
1.122 matthew 1108:
1.121 matthew 1109: =cut
1110:
1111: ######################################################################
1112: ######################################################################
1.98 harris41 1113: sub make_persistent {
1.133 matthew 1114: my %save = %{shift()};
1.146 matthew 1115: my $filename = shift;
1116: return undef if (! tie(%persistent_db,'GDBM_File',
1.148 matthew 1117: $filename,&GDBM_WRCREAT(),0640));
1.146 matthew 1118: foreach my $name (keys(%save)) {
1.145 matthew 1119: my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
1120: # We handle array references, but not recursively.
1121: my $store = join(',', map { &Apache::lonnet::escape($_); } @values );
1122: $persistent_db{$name} = $store;
1.109 harris41 1123: }
1.146 matthew 1124: untie(%persistent_db);
1125: return 1;
1126: }
1127:
1128: ######################################################################
1129: ######################################################################
1130:
1131: =pod
1132:
1133: =item &make_form_data_persistent()
1134:
1135: Inputs: filename of persistent database.
1136:
1137: Store most form variables away to the %persistent_db.
1138: Values will be escaped. Values that are array pointers will have their
1.205 www 1139: elements escaped and concatenated in a comma separated string.
1.146 matthew 1140:
1141: =cut
1142:
1143: ######################################################################
1144: ######################################################################
1145: sub make_form_data_persistent {
1146: my $r = shift;
1147: my $filename = shift;
1148: my %save;
1149: foreach (keys(%ENV)) {
1.150 matthew 1150: next if (!/^form/ || /submit/);
1.146 matthew 1151: $save{$_} = $ENV{$_};
1152: }
1.152 matthew 1153: return &make_persistent(\%save,$filename);
1.98 harris41 1154: }
1155:
1.122 matthew 1156: ######################################################################
1157: ######################################################################
1158:
1159: =pod
1160:
1.134 matthew 1161: =item &parse_advanced_search()
1162:
1163: Parse advanced search form and return the following:
1164:
1165: =over 4
1166:
1167: =item $query Scalar containing an SQL query.
1.126 matthew 1168:
1.134 matthew 1169: =item $customquery Scalar containing a custom query.
1170:
1171: =item $customshow Scalar containing commands to show custom metadata.
1172:
1173: =item $libraries_to_query Reference to array of domains to search.
1174:
1175: =back
1.122 matthew 1176:
1177: =cut
1178:
1179: ######################################################################
1180: ######################################################################
1.134 matthew 1181: sub parse_advanced_search {
1.196 matthew 1182: my ($r,$closebutton,$hidden_fields)=@_;
1.216 matthew 1183: my @BasicFields = ('title','author','subject','keywords','url','version',
1.217 matthew 1184: 'notes','abstract','extension','owner',
1.216 matthew 1185: # 'custommetadata','customshow',
1186: 'modifyinguser','standards','mime');
1.217 matthew 1187: my @StatsFields = ('stdno','avetries','difficulty','disc');
1188: my @EvalFields = ('clear','depth','helpful','correct','technical');
1.32 harris41 1189: my $fillflag=0;
1.143 matthew 1190: my $pretty_search_string = "<br />\n";
1.64 harris41 1191: # Clean up fields for safety
1.216 matthew 1192: for my $field (@BasicFields,
1193: 'creationdatestart_month','creationdatestart_day',
1.64 harris41 1194: 'creationdatestart_year','creationdateend_month',
1195: 'creationdateend_day','creationdateend_year',
1196: 'lastrevisiondatestart_month','lastrevisiondatestart_day',
1197: 'lastrevisiondatestart_year','lastrevisiondateend_month',
1.216 matthew 1198: 'lastrevisiondateend_day','lastrevisiondateend_year') {
1199: $ENV{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\']//g;
1.220 matthew 1200: $ENV{'form.'.$field}=~s/(not\s*$|^\s*(and|or)|)//gi;
1.64 harris41 1201: }
1.117 matthew 1202: foreach ('mode','form','element') {
1203: # is this required? Hmmm.
1.216 matthew 1204: next if (! exists($ENV{'form.'.$_}));
1205: $ENV{'form.'.$_}=&Apache::lonnet::unescape($ENV{'form.'.$_});
1206: $ENV{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g;
1.117 matthew 1207: }
1.131 matthew 1208: # Preprocess the category form element.
1.161 matthew 1209: $ENV{'form.category'} = 'any' if (! defined($ENV{'form.category'}) ||
1210: ref($ENV{'form.category'}));
1211: #
1.90 harris41 1212: # Check to see if enough information was filled in
1.216 matthew 1213: for my $field (@BasicFields) {
1214: if (&filled($ENV{'form.'.$field})) {
1.32 harris41 1215: $fillflag++;
1216: }
1217: }
1.216 matthew 1218: for my $field ('lowestgradelevel','highestgradelevel') {
1219: if ( $ENV{'form.'.$field} =~ /^\d+$/ &&
1220: $ENV{'form.'.$field} > 0) {
1221: $fillflag++;
1222: }
1223: }
1.212 matthew 1224: if (! $fillflag) {
1.204 matthew 1225: &output_blank_field_error($r,$closebutton,
1226: 'phase=disp_adv',$hidden_fields);
1.134 matthew 1227: return ;
1.32 harris41 1228: }
1.90 harris41 1229: # Turn the form input into a SQL-based query
1.39 harris41 1230: my $query='';
1.45 harris41 1231: my @queries;
1.143 matthew 1232: my $font = '<font color="#800000" face="helvetica">';
1.90 harris41 1233: # Evaluate logical expression AND/OR/NOT phrase fields.
1.216 matthew 1234: foreach my $field (@BasicFields) {
1.44 harris41 1235: if ($ENV{'form.'.$field}) {
1.142 matthew 1236: my $searchphrase = $ENV{'form.'.$field};
1.143 matthew 1237: $pretty_search_string .= $font."$field</font> contains <b>".
1238: $searchphrase."</b>";
1.142 matthew 1239: if ($ENV{'form.'.$field.'_related'}) {
1.143 matthew 1240: my @New_Words;
1241: ($searchphrase,@New_Words) = &related_version($searchphrase);
1242: if (@New_Words) {
1243: $pretty_search_string .= " with related words: ".
1244: "<b>@New_Words</b>.";
1245: } else {
1246: $pretty_search_string .= " with no related words.";
1247: }
1.142 matthew 1248: }
1.143 matthew 1249: $pretty_search_string .= "<br />\n";
1.142 matthew 1250: push @queries,&build_SQL_query($field,$searchphrase);
1.131 matthew 1251: }
1.44 harris41 1252: }
1.161 matthew 1253: #
1254: # Make the 'mime' from 'form.category' and 'form.extension'
1255: #
1256: my $searchphrase;
1257: if (exists($ENV{'form.category'}) &&
1258: $ENV{'form.category'} !~ /^\s*$/ &&
1259: $ENV{'form.category'} ne 'any') {
1260: my @extensions = &Apache::loncommon::filecategorytypes
1261: ($ENV{'form.category'});
1262: if (scalar(@extensions) > 0) {
1263: $searchphrase = join(' OR ',@extensions);
1264: }
1265: }
1266: if (defined($searchphrase)) {
1267: push @queries,&build_SQL_query('mime',$searchphrase);
1268: $pretty_search_string .=$font.'mime</font> contains <b>'.
1269: $searchphrase.'</b><br />';
1.135 matthew 1270: }
1.204 matthew 1271: #
1.90 harris41 1272: # Evaluate option lists
1.216 matthew 1273: if ($ENV{'form.lowestgradelevel'} &&
1274: $ENV{'form.lowestgradelevel'} ne '0' &&
1275: $ENV{'form.lowestgradelevel'} =~ /^\d+$/) {
1276: push(@queries,
1277: '(lowestgradelevel>='.$ENV{'form.lowestgradelevel'}.')');
1278: $pretty_search_string.="lowestgradelevel>=".
1279: $ENV{'form.lowestgradelevel'}."<br />\n";
1280: }
1281: if ($ENV{'form.highestgradelevel'} &&
1282: $ENV{'form.highestgradelevel'} ne '0' &&
1283: $ENV{'form.highestgradelevel'} =~ /^\d+$/) {
1284: push(@queries,
1285: '(highestgradelevel<='.$ENV{'form.highestgradelevel'}.')');
1286: $pretty_search_string.="highestgradelevel<=".
1287: $ENV{'form.highestgradelevel'}."<br />\n";
1288: }
1.58 harris41 1289: if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {
1.90 harris41 1290: push @queries,"(language like \"$ENV{'form.language'}\")";
1.143 matthew 1291: $pretty_search_string.=$font."language</font>= ".
1292: &Apache::loncommon::languagedescription($ENV{'form.language'}).
1293: "<br />\n";
1.58 harris41 1294: }
1295: if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') {
1.90 harris41 1296: push @queries,"(copyright like \"$ENV{'form.copyright'}\")";
1.143 matthew 1297: $pretty_search_string.=$font."copyright</font> = ".
1298: &Apache::loncommon::copyrightdescription($ENV{'form.copyright'}).
1299: "<br \>\n";
1.58 harris41 1300: }
1.143 matthew 1301: #
1.217 matthew 1302: # Statistics
1303: foreach my $field (@StatsFields,@EvalFields) {
1304: my ($min,$max);
1305: if (exists($ENV{'form.'.$field.'_min'}) &&
1306: $ENV{'form.'.$field.'_min'} ne '') {
1307: $min = $ENV{'form.'.$field.'_min'};
1308: }
1309: if (exists($ENV{'form.'.$field.'_max'}) &&
1310: $ENV{'form.'.$field.'_max'} ne '') {
1311: $max = $ENV{'form.'.$field.'_max'};
1312: }
1313: next if (! defined($max) && ! defined($min));
1314: if (defined($min) && defined($max)) {
1315: ($min,$max) = sort {$a <=>$b} ($min,$max);
1316: }
1317: if (defined($min) && $min =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
1318: push(@queries,'('.$field.'>'.$min.')');
1319: $pretty_search_string.=$font.$field.'</font>>'.$min.'<br />';
1320: }
1321: if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
1322: push(@queries,'('.$field.'<'.$max.')');
1323: $pretty_search_string.=$font.$field.'</font><'.$max.'<br />';
1324: }
1325: }
1326: #
1.90 harris41 1327: # Evaluate date windows
1.216 matthew 1328: my $cafter =
1329: &Apache::lonhtmlcommon::get_date_from_form('creationdate1');
1330: my $cbefore =
1331: &Apache::lonhtmlcommon::get_date_from_form('creationdate2');
1332: if ($cafter > $cbefore) {
1333: my $tmp = $cafter;
1334: $cafter = $cbefore;
1335: $cbefore = $tmp;
1336: }
1337: my $mafter =
1338: &Apache::lonhtmlcommon::get_date_from_form('revisiondate1');
1339: my $mbefore =
1340: &Apache::lonhtmlcommon::get_date_from_form('revisiondate2');
1341: if ($mafter > $mbefore) {
1342: my $tmp = $mafter;
1343: $mafter = $mbefore;
1344: $mbefore = $tmp;
1345: }
1346: my ($datequery,$error,$prettydate)=&build_date_queries($cafter,$cbefore,
1347: $mafter,$mbefore);
1348: if (defined($error)) {
1349: &output_date_error($r,$error,$closebutton,$hidden_fields);
1350: } elsif (defined($datequery)) {
1.143 matthew 1351: # Here is where you would set up pretty_search_string to output
1352: # date query information.
1.216 matthew 1353: $pretty_search_string .= '<br />'.$prettydate.'<br />';
1.60 harris41 1354: push @queries,$datequery;
1355: }
1.204 matthew 1356: #
1.90 harris41 1357: # Process form information for custom metadata querying
1.134 matthew 1358: my $customquery=undef;
1.204 matthew 1359: ##
1360: ## The custom metadata search was removed q long time ago mostly
1361: ## because I was unable to figureout exactly how it worked and could
1362: ## not imagine people actually using it. MH
1363: ##
1364: # if ($ENV{'form.custommetadata'}) {
1365: # $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".
1366: # $ENV{'form.custommetadata'}."</b><br />\n";
1367: # $customquery=&build_custommetadata_query('custommetadata',
1368: # $ENV{'form.custommetadata'});
1369: # }
1.134 matthew 1370: my $customshow=undef;
1.204 matthew 1371: # if ($ENV{'form.customshow'}) {
1372: # $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".
1373: # $ENV{'form.customshow'}."</b><br />\n";
1374: # $customshow=$ENV{'form.customshow'};
1375: # $customshow=~s/[^\w\s]//g;
1376: # my @fields=split(/\s+/,$customshow);
1377: # $customshow=join(" ",@fields);
1378: # }
1379: ##
1.132 matthew 1380: ## Deal with restrictions to given domains
1381: ##
1.180 matthew 1382: my ($libraries_to_query,$pretty_domains_string) =
1383: &parse_domain_restrictions();
1384: $pretty_search_string .= $pretty_domains_string."<br />\n";
1385: #
1386: if (@queries) {
1.216 matthew 1387: $query="select * from metadata where ".join(" AND ",@queries);
1.180 matthew 1388: } elsif ($customquery) {
1389: $query = '';
1390: }
1.217 matthew 1391: # &Apache::lonnet::logthis('query = '.$/.$query);
1.180 matthew 1392: return ($query,$customquery,$customshow,$libraries_to_query,
1393: $pretty_search_string);
1394: }
1395:
1396: sub parse_domain_restrictions {
1.132 matthew 1397: my $libraries_to_query = undef;
1398: # $ENV{'form.domains'} can be either a scalar or an array reference.
1399: # We need an array.
1.221 ! matthew 1400: if (! exists($ENV{'form.domains'}) || $ENV{'form.domains'} eq '') {
1.180 matthew 1401: return (undef,'');
1402: }
1403: my @allowed_domains;
1404: if (ref($ENV{'form.domains'})) {
1405: @allowed_domains = @{$ENV{'form.domains'}};
1406: } else {
1407: @allowed_domains = ($ENV{'form.domains'});
1408: }
1.204 matthew 1409: #
1.132 matthew 1410: my %domain_hash = ();
1.143 matthew 1411: my $pretty_domains_string;
1.132 matthew 1412: foreach (@allowed_domains) {
1413: $domain_hash{$_}++;
1414: }
1.143 matthew 1415: if ($domain_hash{'any'}) {
1.152 matthew 1416: $pretty_domains_string = "In all LON-CAPA domains.";
1.143 matthew 1417: } else {
1418: if (@allowed_domains > 1) {
1.152 matthew 1419: $pretty_domains_string = "In LON-CAPA domains:";
1.143 matthew 1420: } else {
1.152 matthew 1421: $pretty_domains_string = "In LON-CAPA domain ";
1.143 matthew 1422: }
1423: foreach (sort @allowed_domains) {
1.152 matthew 1424: $pretty_domains_string .= "<b>".$_."</b> ";
1.132 matthew 1425: }
1.143 matthew 1426: foreach (keys(%Apache::lonnet::libserv)) {
1427: if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {
1428: push @$libraries_to_query,$_;
1429: }
1.132 matthew 1430: }
1431: }
1.180 matthew 1432: return ($libraries_to_query,$pretty_domains_string);
1.18 harris41 1433: }
1434:
1.122 matthew 1435: ######################################################################
1436: ######################################################################
1437:
1438: =pod
1439:
1.134 matthew 1440: =item &parse_basic_search()
1.122 matthew 1441:
1.134 matthew 1442: Parse the basic search form and return a scalar containing an sql query.
1.126 matthew 1443:
1.122 matthew 1444: =cut
1445:
1446: ######################################################################
1447: ######################################################################
1.134 matthew 1448: sub parse_basic_search {
1.145 matthew 1449: my ($r,$closebutton)=@_;
1.204 matthew 1450: #
1.64 harris41 1451: # Clean up fields for safety
1452: for my $field ('basicexp') {
1453: $ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g;
1454: }
1.117 matthew 1455: foreach ('mode','form','element') {
1456: # is this required? Hmmm.
1457: next unless (exists($ENV{"form.$_"}));
1458: $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});
1459: $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
1460: }
1.180 matthew 1461: my ($libraries_to_query,$pretty_domains_string) =
1462: &parse_domain_restrictions();
1.204 matthew 1463: #
1464: # Check to see if enough of a query is filled in
1.220 matthew 1465: my $search_string = $ENV{'form.basicexp'};
1466: $search_string =~ s/(not\s*$|^\s*(and|or)|)//gi;
1467: if (! &filled($search_string)) {
1.151 matthew 1468: &output_blank_field_error($r,$closebutton,'phase=disp_basic');
1.24 harris41 1469: return OK;
1470: }
1.143 matthew 1471: my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';
1.141 matthew 1472: if ($ENV{'form.related'}) {
1.143 matthew 1473: my @New_Words;
1474: ($search_string,@New_Words) = &related_version($ENV{'form.basicexp'});
1475: if (@New_Words) {
1476: $pretty_search_string .= " with related words: <b>@New_Words</b>.";
1477: } else {
1478: $pretty_search_string .= " with no related words.";
1479: }
1.141 matthew 1480: }
1.204 matthew 1481: #
1.90 harris41 1482: # Build SQL query string based on form page
1.39 harris41 1483: my $query='';
1.178 matthew 1484: my $concatarg=join(',',
1.124 matthew 1485: ('title', 'author', 'subject', 'notes', 'abstract',
1486: 'keywords'));
1.95 harris41 1487: $concatarg='title' if $ENV{'form.titleonly'};
1.178 matthew 1488: $query=&build_SQL_query('concat_ws(" ",'.$concatarg.')',$search_string);
1.180 matthew 1489: if (defined($pretty_domains_string) && $pretty_domains_string ne '') {
1490: $pretty_search_string .= ' '.$pretty_domains_string;
1491: }
1.143 matthew 1492: $pretty_search_string .= "<br />\n";
1.183 matthew 1493: my $final_query = 'SELECT * FROM metadata WHERE '.$query;
1.204 matthew 1494: # &Apache::lonnet::logthis($final_query);
1.183 matthew 1495: return ($final_query,$pretty_search_string,
1.180 matthew 1496: $libraries_to_query);
1.22 harris41 1497: }
1498:
1.122 matthew 1499: ######################################################################
1500: ######################################################################
1501:
1502: =pod
1503:
1.204 matthew 1504: =item &related_version()
1.142 matthew 1505:
1506: Modifies an input string to include related words. Words in the string
1507: are replaced with parenthesized lists of 'OR'd words. For example
1508: "torque" is replaced with "(torque OR word1 OR word2 OR ...)".
1509:
1510: Note: Using this twice on a string is probably silly.
1511:
1512: =cut
1513:
1514: ######################################################################
1515: ######################################################################
1516: sub related_version {
1517: my $search_string = shift;
1518: my $result = $search_string;
1.143 matthew 1519: my %New_Words = ();
1.142 matthew 1520: while ($search_string =~ /(\w+)/cg) {
1521: my $word = $1;
1522: next if (lc($word) =~ /\b(or|and|not)\b/);
1523: my @Words = &Apache::loncommon::get_related_words($word);
1.143 matthew 1524: @Words = ($#Words>4? @Words[0..4] : @Words);
1525: foreach (@Words) { $New_Words{$_}++;}
1526: my $replacement = join " OR ", ($word,@Words);
1.142 matthew 1527: $result =~ s/(\b)$word(\b)/$1($replacement)$2/g;
1528: }
1.143 matthew 1529: return $result,sort(keys(%New_Words));
1.142 matthew 1530: }
1531:
1532: ######################################################################
1533: ######################################################################
1534:
1535: =pod
1536:
1.122 matthew 1537: =item &build_SQL_query()
1538:
1.126 matthew 1539: Builds a SQL query string from a logical expression with AND/OR keywords
1540: using Text::Query and &recursive_SQL_query_builder()
1541:
1.122 matthew 1542: =cut
1543:
1544: ######################################################################
1545: ######################################################################
1.98 harris41 1546: sub build_SQL_query {
1547: my ($field_name,$logic_statement)=@_;
1548: my $q=new Text::Query('abc',
1549: -parse => 'Text::Query::ParseAdvanced',
1550: -build => 'Text::Query::Build');
1551: $q->prepare($logic_statement);
1552: my $matchexp=${$q}{'matchexp'}; chomp $matchexp;
1553: my $sql_query=&recursive_SQL_query_build($field_name,$matchexp);
1554: return $sql_query;
1555: }
1556:
1.122 matthew 1557: ######################################################################
1558: ######################################################################
1559:
1560: =pod
1561:
1562: =item &build_custommetadata_query()
1563:
1.126 matthew 1564: Constructs a custom metadata query using a rather heinous regular
1565: expression.
1566:
1.122 matthew 1567: =cut
1568:
1569: ######################################################################
1570: ######################################################################
1.98 harris41 1571: sub build_custommetadata_query {
1572: my ($field_name,$logic_statement)=@_;
1573: my $q=new Text::Query('abc',
1574: -parse => 'Text::Query::ParseAdvanced',
1575: -build => 'Text::Query::BuildAdvancedString');
1576: $q->prepare($logic_statement);
1577: my $matchexp=${$q}{'-parse'}{'-build'}{'matchstring'};
1578: # quick fix to change literal into xml tag-matching
1579: # will eventually have to write a separate builder module
1.122 matthew 1580: # wordone=wordtwo becomes\<wordone\>[^\<] *wordtwo[^\<]*\<\/wordone\>
1581: $matchexp =~ s/(\w+)\\=([\w\\\+]+)?# wordone=wordtwo is changed to
1582: /\\<$1\\>?# \<wordone\>
1583: \[\^\\<\]?# [^\<]
1584: \*$2\[\^\\<\]?# *wordtwo[^\<]
1585: \*\\<\\\/$1\\>?# *\<\/wordone\>
1586: /g;
1.98 harris41 1587: return $matchexp;
1588: }
1589:
1.122 matthew 1590: ######################################################################
1591: ######################################################################
1592:
1593: =pod
1594:
1595: =item &recursive_SQL_query_build()
1596:
1.126 matthew 1597: Recursively constructs an SQL query. Takes as input $dkey and $pattern.
1598:
1.122 matthew 1599: =cut
1600:
1601: ######################################################################
1602: ######################################################################
1.98 harris41 1603: sub recursive_SQL_query_build {
1604: my ($dkey,$pattern)=@_;
1605: my @matches=($pattern=~/(\[[^\]|\[]*\])/g);
1606: return $pattern unless @matches;
1607: foreach my $match (@matches) {
1.173 matthew 1608: $match=~/\[ (\w+)\s(.*) \]/;
1609: my ($key,$value)=($1,$2);
1610: my $replacement='';
1611: if ($key eq 'literal') {
1.178 matthew 1612: $replacement="($dkey LIKE \"\%$value\%\")";
1613: } elsif (lc($key) eq 'not') {
1614: $value=~s/LIKE/NOT LIKE/;
1.173 matthew 1615: # $replacement="($dkey not like $value)";
1616: $replacement="$value";
1617: } elsif ($key eq 'and') {
1618: $value=~/(.*[\"|\)]) ([|\(|\^].*)/;
1619: $replacement="($1 AND $2)";
1620: } elsif ($key eq 'or') {
1621: $value=~/(.*[\"|\)]) ([|\(|\^].*)/;
1622: $replacement="($1 OR $2)";
1.98 harris41 1623: }
1624: substr($pattern,
1.173 matthew 1625: index($pattern,$match),
1626: length($match),
1627: $replacement);
1.98 harris41 1628: }
1629: &recursive_SQL_query_build($dkey,$pattern);
1630: }
1.22 harris41 1631:
1.122 matthew 1632: ######################################################################
1633: ######################################################################
1634:
1635: =pod
1636:
1637: =item &build_date_queries()
1638:
1.126 matthew 1639: Builds a SQL logic query to check time/date entries.
1640: Also reports errors (check for /^Incorrect/).
1641:
1.122 matthew 1642: =cut
1643:
1644: ######################################################################
1645: ######################################################################
1.98 harris41 1646: sub build_date_queries {
1.216 matthew 1647: my ($cafter,$cbefore,$mafter,$mbefore) = @_;
1648: my ($result,$error,$pretty_string);
1649: #
1650: # Verify the input
1651: if (! defined($cafter) && ! defined($cbefore) &&
1652: ! defined($mafter) && ! defined($mbefore)) {
1653: # This is an okay situation, so return undef for the error
1654: return (undef,undef,undef);
1655: }
1656: if ((defined($cafter) && ! defined($cbefore)) ||
1657: (defined($cbefore) && ! defined($cafter))) {
1658: # This is bad, so let them know
1659: $error = &mt('Incorrect entry for the creation date. '.
1660: 'You must specify both the beginning and ending dates.');
1661: }
1662: if (! defined($error) &&
1663: ((defined($mafter) && ! defined($mbefore)) ||
1664: (defined($mbefore) && ! defined($mafter)))) {
1665: # This is also bad, so let them know
1666: $error = &mt('Incorrect entry for the last revision date. '.
1667: 'You must specify both the beginning and ending dates.');
1.98 harris41 1668: }
1.216 matthew 1669: if (! defined($error)) {
1670: #
1671: # Build the queries
1672: my @queries;
1673: if (defined($cbefore) && defined($cafter)) {
1674: my (undef,undef,undef,$caday,$camon,$cayear) = localtime($cafter);
1675: my (undef,undef,undef,$cbday,$cbmon,$cbyear) = localtime($cbefore);
1676: # Correct for year being relative to 1900
1677: $cayear+=1900; $cbyear+=1900;
1678: my $cquery=
1679: '(creationdate BETWEEN '.
1680: "'".$cayear.'-'.$camon.'-'.$caday."'".
1681: ' AND '.
1682: "'".$cbyear.'-'.$cbmon.'-'.$cbday." 23:59:59')";
1683: $pretty_string .= '<br />' if (defined($pretty_string));
1684: $pretty_string .=
1685: &mt('created between [_1] and [_2]',
1686: &Apache::lonlocal::locallocaltime($cafter),
1687: &Apache::lonlocal::locallocaltime($cbefore+24*60*60-1));
1688: push(@queries,$cquery);
1689: $pretty_string =~ s/ 00:00:00//g;
1690: }
1691: if (defined($mbefore) && defined($mafter)) {
1692: my (undef,undef,undef,$maday,$mamon,$mayear) = localtime($mafter);
1693: my (undef,undef,undef,$mbday,$mbmon,$mbyear) = localtime($mbefore);
1694: # Correct for year being relative to 1900
1695: $mayear+=1900; $mbyear+=1900;
1696: my $mquery=
1697: '(lastrevisiondate BETWEEN '.
1698: "'".$mayear.'-'.$mamon.'-'.$maday."'".
1699: ' AND '.
1700: "'".$mbyear.'-'.$mbmon.'-'.$mbday." 23:59:59')";
1701: push(@queries,$mquery);
1702: $pretty_string .= '<br />' if (defined($pretty_string));
1703: $pretty_string .=
1704: &mt('last revised between [_1] and [_2]',
1705: &Apache::lonlocal::locallocaltime($mafter),
1706: &Apache::lonlocal::locallocaltime($mbefore+24*60*60-1));
1707: $pretty_string =~ s/ 00:00:00//g;
1708: }
1709: if (@queries) {
1710: $result .= join(" AND ",@queries);
1711: }
1.98 harris41 1712: }
1.216 matthew 1713: return ($result,$error,$pretty_string);
1.18 harris41 1714: }
1.6 harris41 1715:
1.122 matthew 1716: ######################################################################
1717: ######################################################################
1718:
1.144 matthew 1719: =pod
1720:
1721: =item ©right_check()
1722:
1.204 matthew 1723: Inputs: $Metadata, a hash pointer of metadata for a resource.
1724:
1725: Returns: 1 if the resource is available to the user making the query,
1726: 0 otherwise.
1727:
1.144 matthew 1728: =cut
1729:
1730: ######################################################################
1731: ######################################################################
1732: sub copyright_check {
1733: my $Metadata = shift;
1734: # Check copyright tags and skip results the user cannot use
1735: my (undef,undef,$resdom,$resname) = split('/',
1736: $Metadata->{'url'});
1737: # Check for priv
1738: if (($Metadata->{'copyright'} eq 'priv') &&
1739: (($ENV{'user.name'} ne $resname) &&
1740: ($ENV{'user.domain'} ne $resdom))) {
1741: return 0;
1742: }
1743: # Check for domain
1744: if (($Metadata->{'copyright'} eq 'domain') &&
1745: ($ENV{'user.domain'} ne $resdom)) {
1746: return 0;
1747: }
1748: return 1;
1749: }
1750:
1.151 matthew 1751: ######################################################################
1752: ######################################################################
1753:
1754: =pod
1755:
1.204 matthew 1756: =item &ensure_db_and_table()
1.151 matthew 1757:
1758: Ensure we can get lonmysql to connect to the database and the table we
1759: need exists.
1760:
1761: Inputs: $r, table id
1762:
1763: Returns: undef on error, 1 if the table exists.
1764:
1765: =cut
1766:
1767: ######################################################################
1768: ######################################################################
1769: sub ensure_db_and_table {
1770: my ($r,$table) = @_;
1771: ##
1772: ## Sanity check the table id.
1773: ##
1774: if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
1775: $r->print("Unable to retrieve search results. ".
1776: "Unable to determine the table results were stored in. ".
1777: "</body></html>");
1778: return undef;
1779: }
1780: ##
1781: ## Make sure we can connect and the table exists.
1782: ##
1783: my $connection_result = &Apache::lonmysql::connect_to_db();
1784: if (!defined($connection_result)) {
1785: $r->print("Unable to connect to the MySQL database where your results".
1786: " are stored. </body></html>");
1787: &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".
1788: " connect to database.");
1789: &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
1790: return undef;
1791: }
1792: my $table_check = &Apache::lonmysql::check_table($table);
1793: if (! defined($table_check)) {
1794: $r->print("A MySQL error has occurred.</form></body></html>");
1795: &Apache::lonnet::logthis("lonmysql was unable to determine the status".
1796: " of table ".$table);
1797: return undef;
1798: } elsif (! $table_check) {
1799: $r->print("The table of results could not be found.");
1800: &Apache::lonnet::logthis("The user requested a table, ".$table.
1801: ", that could not be found.");
1802: return undef;
1803: }
1804: return 1;
1805: }
1806:
1807: ######################################################################
1808: ######################################################################
1809:
1810: =pod
1811:
1.204 matthew 1812: =item &print_sort_form()
1813:
1814: The sort feature is not implemented at this time. This form just prints
1815: a link to change the search query.
1.151 matthew 1816:
1817: =cut
1818:
1819: ######################################################################
1820: ######################################################################
1821: sub print_sort_form {
1822: my ($r,$pretty_query_string) = @_;
1.196 matthew 1823: my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.151 matthew 1824: ##
1.187 www 1825: my %SortableFields=&Apache::lonlocal::texthash(
1826: id => 'Default',
1.151 matthew 1827: title => 'Title',
1828: author => 'Author',
1829: subject => 'Subject',
1830: url => 'URL',
1831: version => 'Version Number',
1832: mime => 'Mime type',
1833: lang => 'Language',
1834: owner => 'Owner/Publisher',
1835: copyright => 'Copyright',
1836: hostname => 'Host',
1837: creationdate => 'Creation Date',
1.187 www 1838: lastrevisiondate => 'Revision Date'
1.151 matthew 1839: );
1840: ##
1841: my $table = $ENV{'form.table'};
1842: return if (! &ensure_db_and_table($r,$table));
1843: ##
1844: ## Get the number of results
1845: ##
1846: my $total_results = &Apache::lonmysql::number_of_rows($table);
1847: if (! defined($total_results)) {
1848: $r->print("A MySQL error has occurred.</form></body></html>");
1849: &Apache::lonnet::logthis("lonmysql was unable to determine the number".
1850: " of rows in table ".$table);
1851: &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
1852: return;
1853: }
1854: my $result;
1855: $result.=<<END;
1856: <html>
1857: <head>
1858: <script>
1859: function change_sort() {
1860: var newloc = "/adm/searchcat?phase=results";
1861: newloc += "&persistent_db_id=$ENV{'form.persistent_db_id'}";
1862: newloc += "&sortby=";
1863: newloc += document.forms.statusform.elements.sortby.value;
1864: parent.resultsframe.location= newloc;
1865: }
1866: </script>
1867: <title>Results</title>
1868: </head>
1.155 matthew 1869: $bodytag
1.151 matthew 1870: <form name="statusform" action="" method="post">
1.153 matthew 1871: <input type="hidden" name="Queue" value="" />
1.151 matthew 1872: END
1873:
1874: #<h2>Sort Results</h2>
1875: #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">
1876: # $ENV{'form.sortby'} = 'id' if (! defined($ENV{'form.sortby'}));
1877: # foreach (keys(%SortableFields)) {
1878: # $result.="<option name=\"$_\"";
1879: # if ($_ eq $ENV{'form.sortby'}) {
1880: # $result.=" selected ";
1881: # }
1882: # $result.=" >$SortableFields{$_}</option>\n";
1883: # }
1884: # $result.="</select>\n";
1885: my $revise = &revise_button();
1886: $result.=<<END;
1887: <p>
1888: There are $total_results matches to your query. $revise
1889: </p><p>
1890: Search:$pretty_query_string
1891: </p>
1892: </form>
1893: </body>
1894: </html>
1895: END
1896: $r->print($result);
1897: return;
1898: }
1899:
1.144 matthew 1900: #####################################################################
1901: #####################################################################
1902:
1903: =pod
1904:
1905: =item MySQL Table Description
1906:
1907: MySQL table creation requires a precise description of the data to be
1908: stored. The use of the correct types to hold data is vital to efficient
1909: storage and quick retrieval of records. The columns must be described in
1910: the following format:
1911:
1912: =cut
1913:
1.170 matthew 1914: #####################################################################
1915: #####################################################################
1.204 matthew 1916: #
1917: # These should probably be scoped but I don't have time right now...
1918: #
1919: my @Datatypes;
1920: my @Fullindicies;
1.147 matthew 1921:
1.144 matthew 1922: ######################################################################
1923: ######################################################################
1924:
1925: =pod
1926:
1.146 matthew 1927: =item &create_results_table()
1928:
1929: Creates the table of search results by calling lonmysql. Stores the
1930: table id in $ENV{'form.table'}
1931:
1932: Inputs: none.
1933:
1934: Returns: the identifier of the table on success, undef on error.
1935:
1936: =cut
1937:
1938: ######################################################################
1939: ######################################################################
1.204 matthew 1940: sub set_up_table_structure {
1941: my ($datatypes,$fullindicies) =
1942: &LONCAPA::lonmetadata::describe_metadata_storage();
1.212 matthew 1943: # Copy the table description before modifying it...
1944: @Datatypes = @{$datatypes};
1945: unshift(@Datatypes,{name => 'id',
1.204 matthew 1946: type => 'MEDIUMINT',
1947: restrictions => 'UNSIGNED NOT NULL',
1948: primary_key => 'yes',
1949: auto_inc => 'yes' });
1950: @Fullindicies = @{$fullindicies};
1951: return;
1952: }
1953:
1.146 matthew 1954: sub create_results_table {
1.204 matthew 1955: &set_up_table_structure();
1.146 matthew 1956: my $table = &Apache::lonmysql::create_table
1.170 matthew 1957: ( { columns => \@Datatypes,
1.172 matthew 1958: FULLTEXT => [{'columns' => \@Fullindicies},],
1.146 matthew 1959: } );
1960: if (defined($table)) {
1961: $ENV{'form.table'} = $table;
1962: return $table;
1963: }
1964: return undef; # Error...
1965: }
1.148 matthew 1966:
1.146 matthew 1967: ######################################################################
1968: ######################################################################
1969:
1970: =pod
1971:
1.150 matthew 1972: =item Search Status update functions
1.144 matthew 1973:
1.150 matthew 1974: Each of the following functions changes the values of one of the
1975: input fields used to display the search status to the user. The names
1976: should be explanatory.
1.144 matthew 1977:
1.150 matthew 1978: Inputs: Apache request handler ($r), text to display.
1.148 matthew 1979:
1.150 matthew 1980: Returns: Nothing.
1.148 matthew 1981:
1982: =over 4
1983:
1984: =item &update_count_status()
1985:
1.150 matthew 1986: =item &update_status()
1.148 matthew 1987:
1.150 matthew 1988: =item &update_seconds()
1.148 matthew 1989:
1990: =back
1991:
1992: =cut
1993:
1994: ######################################################################
1995: ######################################################################
1996: sub update_count_status {
1997: my ($r,$text) = @_;
1998: $text =~ s/\'/\\\'/g;
1999: $r->print
2000: ("<script>document.statusform.count.value = ' $text'</script>\n");
2001: $r->rflush();
2002: }
2003:
1.150 matthew 2004: sub update_status {
1.148 matthew 2005: my ($r,$text) = @_;
2006: $text =~ s/\'/\\\'/g;
2007: $r->print
1.150 matthew 2008: ("<script>document.statusform.status.value = ' $text'</script>\n");
1.148 matthew 2009: $r->rflush();
2010: }
2011:
1.214 matthew 2012: {
2013: my $max_time = 40; # seconds for the search to complete
2014: my $start_time = 0;
2015: my $last_time = 0;
2016:
2017: sub reset_timing {
2018: $start_time = 0;
2019: $last_time = 0;
2020: }
2021:
2022: sub time_left {
2023: if ($start_time == 0) {
2024: $start_time = time;
2025: }
2026: my $time_left = $max_time - (time - $start_time);
2027: $time_left = 0 if ($time_left < 0);
2028: return $time_left;
2029: }
2030:
1.150 matthew 2031: sub update_seconds {
1.214 matthew 2032: my ($r) = @_;
2033: my $time = &time_left();
2034: if (($last_time-$time) > 0) {
2035: $r->print("<script>".
2036: "document.statusform.seconds.value = '$time'".
2037: "</script>\n");
2038: $r->rflush();
2039: }
2040: $last_time = $time;
2041: }
2042:
1.148 matthew 2043: }
2044:
2045: ######################################################################
2046: ######################################################################
2047:
2048: =pod
2049:
1.204 matthew 2050: =item &revise_button()
1.151 matthew 2051:
2052: Inputs: None
2053:
2054: Returns: html string for a 'revise search' button.
2055:
2056: =cut
2057:
2058: ######################################################################
2059: ######################################################################
2060: sub revise_button {
2061: my $revise_phase = 'disp_basic';
2062: $revise_phase = 'disp_adv' if ($ENV{'form.searchmode'} eq 'advanced');
2063: my $newloc = '/adm/searchcat'.
2064: '?persistent_db_id='.$ENV{'form.persistent_db_id'}.
1.158 matthew 2065: '&cleargroupsort=1'.
1.151 matthew 2066: '&phase='.$revise_phase;
2067: my $result = qq{<input type="button" value="Revise search" name="revise"} .
2068: qq{ onClick="parent.location='$newloc';" /> };
2069: return $result;
2070: }
2071:
2072: ######################################################################
2073: ######################################################################
2074:
2075: =pod
2076:
1.204 matthew 2077: =item &run_search()
2078:
2079: Executes a search query by sending it the the other servers and putting the
2080: results into MySQL.
1.144 matthew 2081:
2082: =cut
2083:
2084: ######################################################################
2085: ######################################################################
2086: sub run_search {
1.146 matthew 2087: my ($r,$query,$customquery,$customshow,$serverlist,$pretty_string) = @_;
1.196 matthew 2088: my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.150 matthew 2089: my $connection = $r->connection;
1.144 matthew 2090: #
1.146 matthew 2091: # Print run_search header
2092: #
1.151 matthew 2093: $r->print(<<END);
2094: <html>
2095: <head><title>Search Status</title></head>
1.155 matthew 2096: $bodytag
1.151 matthew 2097: <form name="statusform" action="" method="post">
2098: <input type="hidden" name="Queue" value="" />
2099: END
2100: # Check to see if $pretty_string has more than one carriage return.
2101: # Assume \n s are following <br /> s and truncate the value.
2102: # (there is probably a better way)...
1.152 matthew 2103: my @Lines = split /<br \/>/,$pretty_string;
2104: if (@Lines > 2) {
2105: $pretty_string = join '<br \>',(@Lines[0..2],'....<br />');
1.151 matthew 2106: }
1.214 matthew 2107: $r->print(&mt("Search: [_1]",$pretty_string));
1.146 matthew 2108: $r->rflush();
2109: #
1.145 matthew 2110: # Determine the servers we need to contact.
1.144 matthew 2111: my @Servers_to_contact;
2112: if (defined($serverlist)) {
1.152 matthew 2113: if (ref($serverlist) eq 'ARRAY') {
2114: @Servers_to_contact = @$serverlist;
2115: } else {
2116: @Servers_to_contact = ($serverlist);
2117: }
1.144 matthew 2118: } else {
2119: @Servers_to_contact = sort(keys(%Apache::lonnet::libserv));
2120: }
2121: my %Server_status;
1.214 matthew 2122: #
2123: # Check on the mysql table we will use to store results.
1.146 matthew 2124: my $table =$ENV{'form.table'};
1.150 matthew 2125: if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
1.147 matthew 2126: $r->print("Unable to determine table id to store search results in.".
1.148 matthew 2127: "The search has been aborted.</body></html>");
1.147 matthew 2128: return;
2129: }
2130: my $table_status = &Apache::lonmysql::check_table($table);
2131: if (! defined($table_status)) {
2132: $r->print("Unable to determine status of table.</body></html>");
2133: &Apache::lonnet::logthis("Bogus table id of $table for ".
2134: "$ENV{'user.name'} @ $ENV{'user.domain'}");
2135: &Apache::lonnet::logthis("lonmysql error = ".
1.144 matthew 2136: &Apache::lonmysql::get_error());
1.147 matthew 2137: return;
2138: }
2139: if (! $table_status) {
1.204 matthew 2140: &Apache::lonnet::logthis("lonmysql error = ".
2141: &Apache::lonmysql::get_error());
2142: &Apache::lonnet::logthis("lonmysql debug = ".
2143: &Apache::lonmysql::get_debug());
2144: &Apache::lonnet::logthis('table status = "'.$table_status.'"');
1.147 matthew 2145: $r->print("The table id,$table, we tried to use is invalid.".
1.148 matthew 2146: "The search has been aborted.</body></html>");
1.144 matthew 2147: return;
2148: }
1.145 matthew 2149: ##
1.146 matthew 2150: ## Prepare for the big loop.
1.144 matthew 2151: my $hitcountsum;
2152: my $server;
2153: my $status;
1.151 matthew 2154: my $revise = &revise_button();
1.148 matthew 2155: $r->print(<<END);
2156: <table>
1.151 matthew 2157: <tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th><th></th></tr>
1.148 matthew 2158: <tr>
1.150 matthew 2159: <td><input type="text" name="status" value="" size="30" /></td>
2160: <td><input type="text" name="count" value="" size="10" /></td>
2161: <td><input type="text" name="seconds" value="" size="8" /></td>
1.151 matthew 2162: <td>$revise</td>
1.148 matthew 2163: </tr>
2164: </table>
2165: </form>
2166: END
2167: $r->rflush();
1.214 matthew 2168: &reset_timing();
2169: &update_seconds($r);
2170: &update_status($r,&mt('contacting [_1]',$Servers_to_contact[0]));
2171: while (&time_left() &&
1.144 matthew 2172: ((@Servers_to_contact) || keys(%Server_status))) {
1.214 matthew 2173: &update_seconds($r);
2174: #
2175: # Send out a search request
1.144 matthew 2176: if (@Servers_to_contact) {
2177: # Contact one server
2178: my $server = shift(@Servers_to_contact);
1.214 matthew 2179: &update_status($r,&mt('contacting [_1]',$server));
1.144 matthew 2180: my $reply=&Apache::lonnet::metadata_query($query,$customquery,
2181: $customshow,[$server]);
2182: ($server) = keys(%$reply);
2183: $Server_status{$server} = $reply->{$server};
2184: } else {
1.150 matthew 2185: # wait a sec. to give time for files to be written
2186: # This sleep statement is here instead of outside the else
2187: # block because we do not want to pause if we have servers
2188: # left to contact.
1.183 matthew 2189: if (scalar (keys(%Server_status))) {
2190: &update_status($r,
1.214 matthew 2191: &mt('waiting on [_1]',join(' ',keys(%Server_status))));
1.183 matthew 2192: }
1.150 matthew 2193: sleep(1);
1.144 matthew 2194: }
1.159 matthew 2195: #
2196: # Loop through the servers we have contacted but do not
2197: # have results from yet, looking for results.
1.144 matthew 2198: while (my ($server,$status) = each(%Server_status)) {
1.150 matthew 2199: last if ($connection->aborted());
1.214 matthew 2200: &update_seconds($r);
1.144 matthew 2201: if ($status eq 'con_lost') {
2202: delete ($Server_status{$server});
2203: next;
2204: }
2205: $status=~/^([\.\w]+)$/;
2206: my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1;
2207: if (-e $datafile && ! -e "$datafile.end") {
1.214 matthew 2208: &update_status($r,&mt('Receiving results from [_1]',$server));
1.144 matthew 2209: next;
2210: }
1.150 matthew 2211: last if ($connection->aborted());
1.144 matthew 2212: if (-e "$datafile.end") {
1.214 matthew 2213: &update_status($r,&mt('Reading results from [_1]',$server));
1.144 matthew 2214: if (-z "$datafile") {
2215: delete($Server_status{$server});
2216: next;
2217: }
2218: my $fh;
2219: if (!($fh=Apache::File->new($datafile))) {
1.146 matthew 2220: $r->print("Unable to open search results file for ".
1.145 matthew 2221: "server $server. Omitting from search");
1.150 matthew 2222: delete($Server_status{$server});
2223: next;
1.144 matthew 2224: }
2225: # Read in the whole file.
2226: while (my $result = <$fh>) {
1.150 matthew 2227: last if ($connection->aborted());
1.214 matthew 2228: #
2229: # Records are stored one per line
1.144 matthew 2230: chomp($result);
1.214 matthew 2231: next if (! $result);
2232: #
1.144 matthew 2233: # Parse the result.
2234: my %Fields = &parse_raw_result($result,$server);
2235: $Fields{'hostname'} = $server;
1.214 matthew 2236: #
2237: # Skip based on copyright
1.144 matthew 2238: next if (! ©right_check(\%Fields));
1.214 matthew 2239: #
1.144 matthew 2240: # Store the result in the mysql database
2241: my $result = &Apache::lonmysql::store_row($table,\%Fields);
2242: if (! defined($result)) {
1.146 matthew 2243: $r->print(&Apache::lonmysql::get_error());
1.144 matthew 2244: }
1.214 matthew 2245: #
1.144 matthew 2246: $hitcountsum ++;
1.214 matthew 2247: &update_seconds($r);
1.150 matthew 2248: if ($hitcountsum % 50 == 0) {
2249: &update_count_status($r,$hitcountsum);
2250: }
1.214 matthew 2251: }
1.144 matthew 2252: $fh->close();
2253: # $server is only deleted if the results file has been
2254: # found and (successfully) opened. This may be a bad idea.
2255: delete($Server_status{$server});
2256: }
1.150 matthew 2257: last if ($connection->aborted());
1.148 matthew 2258: &update_count_status($r,$hitcountsum);
1.144 matthew 2259: }
1.150 matthew 2260: last if ($connection->aborted());
1.214 matthew 2261: &update_seconds($r);
1.144 matthew 2262: }
1.214 matthew 2263: &update_status($r,&mt('Search Complete [_1]',$server));
2264: &update_seconds($r);
1.204 matthew 2265: #
1.214 matthew 2266: &Apache::lonmysql::disconnect_from_db(); # This is unneccessary
1.204 matthew 2267: #
1.144 matthew 2268: # We have run out of time or run out of servers to talk to and
1.214 matthew 2269: # results to get, so let the client know the top frame needs to be
2270: # loaded from /adm/searchcat
1.146 matthew 2271: $r->print("</body></html>");
1.153 matthew 2272: if ($ENV{'form.catalogmode'} ne 'groupsearch') {
2273: $r->print("<script>".
2274: "window.location='/adm/searchcat?".
2275: "phase=sort&".
2276: "persistent_db_id=$ENV{'form.persistent_db_id'}';".
2277: "</script>");
2278: }
1.144 matthew 2279: return;
2280: }
2281:
2282: ######################################################################
2283: ######################################################################
1.204 matthew 2284:
1.144 matthew 2285: =pod
2286:
1.204 matthew 2287: =item &prev_next_buttons()
2288:
2289: Returns html for the previous and next buttons on the search results page.
1.144 matthew 2290:
2291: =cut
2292:
2293: ######################################################################
2294: ######################################################################
1.146 matthew 2295: sub prev_next_buttons {
1.145 matthew 2296: my ($current_min,$show,$total,$parms) = @_;
2297: return '' if ($show eq 'all'); # No links if you get them all at once.
1.214 matthew 2298: #
2299: # Create links
1.145 matthew 2300: my $prev_min = $current_min - $show;
1.151 matthew 2301: $prev_min = 1 if $prev_min < 1;
1.214 matthew 2302: my $prevlink =
2303: qq{<a href="/adm/searchcat?$parms&start=$prev_min&show=$show">};
2304: #
1.145 matthew 2305: my $next_min = $current_min + $show;
1.146 matthew 2306: $next_min = $current_min if ($next_min > $total);
1.214 matthew 2307: my $nextlink =
2308: qq{<a href="/adm/searchcat?$parms&start=$next_min&show=$show">};
2309: my $reloadlink =
2310: qq{<a href="/adm/searchcat?$parms&start=$current_min&$show=$show">};
2311: #
2312: # Determine which parameters to pass
2313: my $String = '[_1]prev[_2] [_3]reload[_4] [_5]next[_6]';
2314: if ($prev_min == $current_min) {
2315: $String =~ s:\[_[12]\]::g;
2316: }
2317: if ($next_min == $current_min) {
2318: $String =~ s:\[_[56]\]::g;
2319: }
2320: my $links = &mt($String,
2321: $prevlink, '</a>',
2322: $reloadlink,'</a>',
2323: $nextlink, '</a>');
1.145 matthew 2324: return $links;
1.144 matthew 2325: }
1.204 matthew 2326:
1.144 matthew 2327: ######################################################################
2328: ######################################################################
2329:
2330: =pod
2331:
1.204 matthew 2332: =item &display_results()
2333:
2334: Prints the results out for selection and perusal.
1.144 matthew 2335:
2336: =cut
2337:
2338: ######################################################################
2339: ######################################################################
2340: sub display_results {
1.196 matthew 2341: my ($r,$importbutton,$closebutton,$diropendb) = @_;
1.150 matthew 2342: my $connection = $r->connection;
2343: $r->print(&search_results_header($importbutton,$closebutton));
1.144 matthew 2344: ##
2345: ## Set viewing function
2346: ##
2347: my $viewfunction = $Views{$ENV{'form.viewselect'}};
2348: if (!defined($viewfunction)) {
2349: $r->print("Internal Error - Bad view selected.\n");
2350: $r->rflush();
2351: return;
2352: }
2353: ##
1.158 matthew 2354: ## $checkbox_num is a count of the number of checkboxes output on the
2355: ## page this is used only during catalogmode=groupsearch.
2356: my $checkbox_num = 0;
2357: ##
1.144 matthew 2358: ## Get the catalog controls setup
2359: ##
1.146 matthew 2360: my $action = "/adm/searchcat?phase=results";
2361: ##
1.204 matthew 2362: ## Deal with groupsearch by opening the groupsearch db file.
1.146 matthew 2363: if ($ENV{'form.catalogmode'} eq 'groupsearch') {
2364: if (! tie(%groupsearch_db,'GDBM_File',$diropendb,
1.148 matthew 2365: &GDBM_WRCREAT(),0640)) {
1.150 matthew 2366: $r->print('Unable to store import results.</form></body></html>');
1.146 matthew 2367: $r->rflush();
2368: return;
2369: }
1.144 matthew 2370: }
1.145 matthew 2371: ##
2372: ## Prepare the table for querying
1.144 matthew 2373: my $table = $ENV{'form.table'};
1.151 matthew 2374: return if (! &ensure_db_and_table($r,$table));
1.145 matthew 2375: ##
2376: ## Get the number of results
2377: my $total_results = &Apache::lonmysql::number_of_rows($table);
2378: if (! defined($total_results)) {
1.150 matthew 2379: $r->print("A MySQL error has occurred.</form></body></html>");
1.145 matthew 2380: &Apache::lonnet::logthis("lonmysql was unable to determine the number".
2381: " of rows in table ".$table);
2382: &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
2383: return;
2384: }
2385: ##
2386: ## Determine how many results we need to get
1.151 matthew 2387: $ENV{'form.start'} = 1 if (! exists($ENV{'form.start'}));
2388: $ENV{'form.show'} = 'all' if (! exists($ENV{'form.show'}));
1.146 matthew 2389: my $min = $ENV{'form.start'};
1.145 matthew 2390: my $max;
2391: if ($ENV{'form.show'} eq 'all') {
2392: $max = $total_results ;
2393: } else {
1.151 matthew 2394: $max = $min + $ENV{'form.show'} - 1;
1.146 matthew 2395: $max = $total_results if ($max > $total_results);
1.145 matthew 2396: }
2397: ##
2398: ## Output links (if necessary) for 'prev' and 'next' pages.
1.146 matthew 2399: $r->print
1.148 matthew 2400: ('<center>'.
1.146 matthew 2401: &prev_next_buttons($min,$ENV{'form.show'},$total_results,
2402: "table=".$ENV{'form.table'}.
2403: "&phase=results".
2404: "&persistent_db_id=".$ENV{'form.persistent_db_id'})
1.148 matthew 2405: ."</center>\n"
1.146 matthew 2406: );
1.150 matthew 2407: if ($total_results == 0) {
1.214 matthew 2408: $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2">'.
1.187 www 2409: '<h3>'.&mt('There are currently no results').'.</h3>'.
1.150 matthew 2410: "</form></body></html>");
2411: return;
2412: } else {
2413: $r->print
2414: ("<center>Results $min to $max out of $total_results</center>\n");
2415: }
1.145 matthew 2416: ##
2417: ## Get results from MySQL table
2418: my @Results = &Apache::lonmysql::get_rows($table,
1.151 matthew 2419: 'id>='.$min.' AND id<='.$max);
1.145 matthew 2420: ##
2421: ## Loop through the results and output them.
1.144 matthew 2422: foreach my $row (@Results) {
1.150 matthew 2423: if ($connection->aborted()) {
1.162 www 2424: &cleanup();
1.150 matthew 2425: return;
2426: }
1.144 matthew 2427: my %Fields = %{&parse_row(@$row)};
1.145 matthew 2428: my $output="<p>\n";
1.210 matthew 2429: if (! defined($Fields{'title'}) || $Fields{'title'} eq '') {
2430: $Fields{'title'} = 'Untitled';
2431: }
1.158 matthew 2432: my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'},
2433: $Fields{'id'},$checkbox_num++);
1.144 matthew 2434: # Render the result into html
1.150 matthew 2435: $output.= &$viewfunction($prefix,%Fields);
1.145 matthew 2436: # Print them out as they come in.
1.144 matthew 2437: $r->print($output);
2438: $r->rflush();
2439: }
2440: if (@Results < 1) {
1.187 www 2441: $r->print(&mt("There were no results matching your query"));
1.147 matthew 2442: } else {
2443: $r->print
1.148 matthew 2444: ('<center>'.
1.147 matthew 2445: &prev_next_buttons($min,$ENV{'form.show'},$total_results,
2446: "table=".$ENV{'form.table'}.
2447: "&phase=results".
2448: "&persistent_db_id=".
2449: $ENV{'form.persistent_db_id'})
1.148 matthew 2450: ."</center>\n"
1.147 matthew 2451: );
1.144 matthew 2452: }
1.150 matthew 2453: $r->print("</form></body></html>");
1.144 matthew 2454: $r->rflush();
1.150 matthew 2455: untie %groupsearch_db if (tied(%groupsearch_db));
1.144 matthew 2456: return;
2457: }
2458:
2459: ######################################################################
2460: ######################################################################
2461:
2462: =pod
2463:
1.158 matthew 2464: =item &catalogmode_output($title,$url,$fnum,$checkbox_num)
1.145 matthew 2465:
2466: Returns html needed for the various catalog modes. Gets inputs from
1.158 matthew 2467: $ENV{'form.catalogmode'}. Stores data in %groupsearch_db.
1.145 matthew 2468:
2469: =cut
2470:
2471: ######################################################################
2472: ######################################################################
2473: sub catalogmode_output {
2474: my $output = '';
1.158 matthew 2475: my ($title,$url,$fnum,$checkbox_num) = @_;
1.145 matthew 2476: if ($ENV{'form.catalogmode'} eq 'interactive') {
1.150 matthew 2477: $title=~ s/\'/\\\'/g;
1.145 matthew 2478: if ($ENV{'form.catalogmode'} eq 'interactive') {
2479: $output.=<<END
2480: <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"
2481: onClick="javascript:select_data('$title','$url')">
2482: </font>
2483: END
2484: }
1.150 matthew 2485: } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {
1.145 matthew 2486: $groupsearch_db{"pre_${fnum}_link"}=$url;
2487: $groupsearch_db{"pre_${fnum}_title"}=$title;
2488: $output.=<<END;
2489: <font size='-1'>
2490: <input type="checkbox" name="returnvalues" value="SELECT"
1.158 matthew 2491: onClick="javascript:queue($checkbox_num,$fnum)" />
1.145 matthew 2492: </font>
2493: END
2494: }
2495: return $output;
2496: }
2497: ######################################################################
2498: ######################################################################
2499:
2500: =pod
2501:
1.204 matthew 2502: =item &parse_row()
1.144 matthew 2503:
2504: Parse a row returned from the database.
2505:
2506: =cut
2507:
2508: ######################################################################
2509: ######################################################################
2510: sub parse_row {
2511: my @Row = @_;
2512: my %Fields;
1.204 matthew 2513: if (! scalar(@Datatypes)) {
2514: &set_up_table_structure();
2515: }
1.144 matthew 2516: for (my $i=0;$i<=$#Row;$i++) {
1.170 matthew 2517: $Fields{$Datatypes[$i]->{'name'}}=&Apache::lonnet::unescape($Row[$i]);
1.144 matthew 2518: }
2519: $Fields{'language'} =
1.198 www 2520: &Apache::loncommon::languagedescription($Fields{'language'});
1.144 matthew 2521: $Fields{'copyrighttag'} =
2522: &Apache::loncommon::copyrightdescription($Fields{'copyright'});
2523: $Fields{'mimetag'} =
2524: &Apache::loncommon::filedescription($Fields{'mime'});
2525: return \%Fields;
2526: }
1.126 matthew 2527:
2528: ###########################################################
2529: ###########################################################
2530:
2531: =pod
2532:
2533: =item &parse_raw_result()
2534:
2535: Takes a line from the file of results and parse it. Returns a hash
1.198 www 2536: with keys according to column labels
1.126 matthew 2537:
2538: In addition, the following tags are set by calling the appropriate
1.198 www 2539: lonnet function: 'language', 'copyrighttag', 'mimetag'.
1.126 matthew 2540:
2541: The 'title' field is set to "Untitled" if the title field is blank.
2542:
2543: 'abstract' and 'keywords' are truncated to 200 characters.
2544:
2545: =cut
2546:
2547: ###########################################################
2548: ###########################################################
2549: sub parse_raw_result {
2550: my ($result,$hostname) = @_;
1.204 matthew 2551: # conclude from self to others regarding fields
1.206 matthew 2552: my %Fields=&LONCAPA::lonmetadata::metadata_col_to_hash
2553: (map {
2554: &Apache::lonnet::unescape($_);
2555: } (split(/\,/,$result)) );
1.126 matthew 2556: return %Fields;
2557: }
2558:
2559: ###########################################################
2560: ###########################################################
2561:
2562: =pod
2563:
2564: =item &handle_custom_fields()
2565:
2566: =cut
2567:
2568: ###########################################################
2569: ###########################################################
2570: sub handle_custom_fields {
2571: my @results = @{shift()};
2572: my $customshow='';
2573: my $extrashow='';
2574: my @customfields;
2575: if ($ENV{'form.customshow'}) {
2576: $customshow=$ENV{'form.customshow'};
2577: $customshow=~s/[^\w\s]//g;
2578: my @fields=map {
2579: "<font color=\"#008000\">$_:</font><!-- $_ -->";
2580: } split(/\s+/,$customshow);
2581: @customfields=split(/\s+/,$customshow);
2582: if ($customshow) {
2583: $extrashow="<ul><li>".join("</li><li>",@fields)."</li></ul>\n";
2584: }
2585: }
2586: my $customdata='';
2587: my %customhash;
2588: foreach my $result (@results) {
2589: if ($result=~/^(custom\=.*)$/) { # grab all custom metadata
2590: my $tmp=$result;
2591: $tmp=~s/^custom\=//;
2592: my ($k,$v)=map {&Apache::lonnet::unescape($_);
2593: } split(/\,/,$tmp);
2594: $customhash{$k}=$v;
2595: }
2596: }
2597: return ($extrashow,\@customfields,\%customhash);
1.41 harris41 2598: }
2599:
1.122 matthew 2600: ######################################################################
2601: ######################################################################
2602:
1.125 matthew 2603: =pod
2604:
1.204 matthew 2605: =item &search_results_header()
1.125 matthew 2606:
1.130 matthew 2607: Output the proper html headers and javascript code to deal with different
2608: calling modes.
2609:
2610: Takes most inputs directly from %ENV, except $mode.
2611:
2612: =over 4
2613:
2614: =item $mode is either (at this writing) 'Basic' or 'Advanced'
2615:
2616: =back
1.126 matthew 2617:
1.130 matthew 2618: The following environment variables are checked:
1.126 matthew 2619:
2620: =over 4
2621:
2622: =item 'form.catalogmode'
2623:
2624: Checked for 'interactive' and 'groupsearch'.
2625:
2626: =item 'form.mode'
2627:
2628: Checked for existance & 'edit' mode.
2629:
2630: =item 'form.form'
2631:
1.191 albertel 2632: Contains the name of the form that has the input fields to set
2633:
1.126 matthew 2634: =item 'form.element'
2635:
1.191 albertel 2636: the name of the input field to put the URL into
2637:
2638: =item 'form.titleelement'
2639:
2640: the name of the input field to put the title into
2641:
1.126 matthew 2642: =back
2643:
1.125 matthew 2644: =cut
2645:
2646: ######################################################################
2647: ######################################################################
2648: sub search_results_header {
1.150 matthew 2649: my ($importbutton,$closebutton) = @_;
1.196 matthew 2650: my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.125 matthew 2651: my $result = '';
2652: # output beginning of search page
2653: # conditional output of script functions dependent on the mode in
2654: # which the search was invoked
2655: if ($ENV{'form.catalogmode'} eq 'interactive'){
2656: if (! exists($ENV{'form.mode'}) || $ENV{'form.mode'} ne 'edit') {
2657: $result.=<<SCRIPT;
2658: <script type="text/javascript">
2659: function select_data(title,url) {
2660: changeTitle(title);
2661: changeURL(url);
1.150 matthew 2662: parent.close();
1.125 matthew 2663: }
2664: function changeTitle(val) {
1.153 matthew 2665: if (parent.opener.inf.document.forms.resinfo.elements.t) {
2666: parent.opener.inf.document.forms.resinfo.elements.t.value=val;
1.125 matthew 2667: }
2668: }
2669: function changeURL(val) {
1.153 matthew 2670: if (parent.opener.inf.document.forms.resinfo.elements.u) {
2671: parent.opener.inf.document.forms.resinfo.elements.u.value=val;
1.125 matthew 2672: }
2673: }
2674: </script>
2675: SCRIPT
2676: } elsif ($ENV{'form.mode'} eq 'edit') {
2677: my $form = $ENV{'form.form'};
2678: my $element = $ENV{'form.element'};
1.191 albertel 2679: my $titleelement = $ENV{'form.titleelement'};
2680: my $changetitle;
2681: if (!$titleelement) {
2682: $changetitle='function changeTitle(val) {}';
2683: } else {
2684: $changetitle=<<END;
2685: function changeTitle(val) {
2686: if (parent.targetwin.document) {
2687: parent.targetwin.document.forms["$form"].elements["$titleelement"].value=val;
2688: } else {
2689: var url = 'forms[\"$form\"].elements[\"$titleelement\"].value';
2690: alert("Unable to transfer data to "+url);
2691: }
2692: }
2693: END
2694: }
2695:
1.125 matthew 2696: $result.=<<SCRIPT;
2697: <script type="text/javascript">
2698: function select_data(title,url) {
2699: changeURL(url);
1.191 albertel 2700: changeTitle(title);
1.150 matthew 2701: parent.close();
1.125 matthew 2702: }
1.191 albertel 2703: $changetitle
1.125 matthew 2704: function changeURL(val) {
1.150 matthew 2705: if (parent.targetwin.document) {
2706: parent.targetwin.document.forms["$form"].elements["$element"].value=val;
1.125 matthew 2707: } else {
2708: var url = 'forms[\"$form\"].elements[\"$element\"].value';
2709: alert("Unable to transfer data to "+url);
2710: }
2711: }
2712: </script>
2713: SCRIPT
2714: }
2715: }
2716: $result.=<<SCRIPT if $ENV{'form.catalogmode'} eq 'groupsearch';
2717: <script type="text/javascript">
1.158 matthew 2718: function queue(checkbox_num,val) {
1.185 matthew 2719: if (document.forms.results.returnvalues.length != "undefined" &&
2720: typeof(document.forms.results.returnvalues.length) == "number") {
2721: if (document.forms.results.returnvalues[checkbox_num].checked) {
2722: parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';
2723: } else {
2724: parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';
2725: }
1.150 matthew 2726: } else {
1.185 matthew 2727: if (document.forms.results.returnvalues.checked) {
2728: parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';
2729: } else {
2730: parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';
2731: }
1.150 matthew 2732: }
1.125 matthew 2733: }
2734: function select_group() {
1.150 matthew 2735: parent.window.location=
1.125 matthew 2736: "/adm/groupsort?mode=$ENV{'form.mode'}&catalogmode=groupsearch&acts="+
1.150 matthew 2737: parent.statusframe.document.forms.statusform.elements.Queue.value;
1.125 matthew 2738: }
2739: </script>
2740: SCRIPT
1.130 matthew 2741: $result.=<<END;
2742: </head>
1.155 matthew 2743: $bodytag
1.150 matthew 2744: <form name="results" method="post" action="" >
2745: <input type="hidden" name="Queue" value="" />
2746: $importbutton
1.130 matthew 2747: END
1.125 matthew 2748: return $result;
2749: }
2750:
2751: ######################################################################
2752: ######################################################################
1.146 matthew 2753: sub search_status_header {
1.196 matthew 2754: my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.146 matthew 2755: return <<ENDSTATUS;
2756: <html><head><title>Search Status</title></head>
1.155 matthew 2757: $bodytag
1.146 matthew 2758: <h3>Search Status</h3>
2759: Sending search request to LON-CAPA servers.<br />
2760: ENDSTATUS
2761: }
2762:
1.150 matthew 2763: sub results_link {
2764: my $basic_link = "/adm/searchcat?"."&table=".$ENV{'form.table'}.
2765: "&persistent_db_id=".$ENV{'form.persistent_db_id'};
2766: my $results_link = $basic_link."&phase=results".
1.151 matthew 2767: "&pause=1"."&start=1";
1.150 matthew 2768: return $results_link;
2769: }
2770:
1.146 matthew 2771: ######################################################################
2772: ######################################################################
2773: sub print_frames_interface {
2774: my $r = shift;
2775: my $basic_link = "/adm/searchcat?"."&table=".$ENV{'form.table'}.
2776: "&persistent_db_id=".$ENV{'form.persistent_db_id'};
2777: my $run_search_link = $basic_link."&phase=run_search";
1.150 matthew 2778: my $results_link = &results_link();
1.146 matthew 2779: my $result = <<"ENDFRAMES";
2780: <html>
2781: <head>
1.150 matthew 2782: <script>
2783: var targetwin = opener;
1.158 matthew 2784: var queue = '';
1.150 matthew 2785: </script>
1.146 matthew 2786: <title>LON-CAPA Digital Library Search Results</title>
2787: </head>
1.176 www 2788: <frameset rows="150,*">
1.146 matthew 2789: <frame name="statusframe" src="$run_search_link">
2790: <frame name="resultsframe" src="$results_link">
2791: </frameset>
2792: </html>
2793: ENDFRAMES
2794:
2795: $r->print($result);
2796: return;
2797: }
2798:
2799: ######################################################################
2800: ######################################################################
1.125 matthew 2801:
1.122 matthew 2802: =pod
2803:
2804: =item Metadata Viewing Functions
2805:
2806: Output is a HTML-ified string.
1.204 matthew 2807:
1.122 matthew 2808: Input arguments are title, author, subject, url, keywords, version,
2809: notes, short abstract, mime, language, creation date,
1.126 matthew 2810: last revision date, owner, copyright, hostname, and
1.122 matthew 2811: extra custom metadata to show.
2812:
2813: =over 4
2814:
2815: =item &detailed_citation_view()
2816:
2817: =cut
2818:
2819: ######################################################################
2820: ######################################################################
1.50 harris41 2821: sub detailed_citation_view {
1.150 matthew 2822: my ($prefix,%values) = @_;
1.218 matthew 2823: my $icon=
2824: my $result;
2825: $result .= '<b>'.$prefix.
2826: '<img src="'.&Apache::loncommon::icon($values{'url'}).' " />'.
2827: '<a href="http://'.$ENV{'HTTP_HOST'}.$values{'url'}.'" '.
2828: 'target="search_preview">'.$values{'title'}."</a></b>\n";
2829: $result .= "<p>\n";
2830: $result .= '<b>'.$values{'author'}.'</b>,'.
2831: ' <i>'.$values{'owner'}.'</i><br />';
2832: foreach my $field
2833: (
2834: { name=>'subject',
2835: translate => '<b>Subject:</b> [_1]',},
2836: { name=>'keywords',
2837: translate => '<b>Keywords:</b> [_1]',},
2838: { name=>'notes',
2839: translate => '<b>Notes:</b> [_1]',},
2840: { name=>'mimetag',
2841: translate => '<b>MIME Type:</b> [_1]',},
2842: { name=>'standards',
2843: translate => '<b>Standards:</b>[_1]',},
2844: { name=>'copyrighttag',
2845: translate => '<b>Copyright/Distribution:</b> [_1]',},
2846: { name=>'stdno',
2847: translate => '<b>Number of Students:</b> [_1]',},
2848: { name=>'avetries',
2849: translate => '<b>Average Tries:</b> [_1]',},
2850: { name=>'disc',
2851: translate => '<b>Degree of Discrimination:</b> [_1]',},
2852: { name=>'difficulty',
2853: translate => '<b>Degree of Difficulty:</b> [_1]',},
2854: { name=>'clear',
2855: translate => '<b>Clear:</b> [_1]',},
2856: { name=>'depth',
2857: translate => '<b>Depth:</b> [_1]',},
2858: { name=>'helpful',
2859: translate => '<b>Helpful:</b> [_1]',},
2860: { name=>'correct',
2861: translate => '<b>Correcy:</b> [_1]',},
2862: { name=>'technical',
2863: translate => '<b>Technical:</b> [_1]',},
2864: ) {
2865: $result.= &mt($field->{'translate'},$values{$field->{'name'}}).
2866: "<br />\n";
2867: }
2868: $result .= "</p>".$values{'extrashow'}.
2869: '<p>'.$values{'shortabstract'}.'</p>';
2870: $result .= '<hr align="left" width="200" noshade />'."\n";
1.50 harris41 2871: return $result;
2872: }
2873:
1.122 matthew 2874: ######################################################################
2875: ######################################################################
2876:
2877: =pod
2878:
2879: =item &summary_view()
2880:
2881: =cut
2882: ######################################################################
2883: ######################################################################
1.50 harris41 2884: sub summary_view {
1.150 matthew 2885: my ($prefix,%values) = @_;
1.192 albertel 2886: my $icon=&Apache::loncommon::icon($values{'url'});
1.50 harris41 2887: my $result=<<END;
1.192 albertel 2888: $prefix<img src="$icon" /><a href="http://$ENV{'HTTP_HOST'}$values{'url'}"
1.126 matthew 2889: target='search_preview'>$values{'author'}</a><br />
2890: $values{'title'}<br />
2891: $values{'owner'} -- $values{'lastrevisiondate'}<br />
2892: $values{'copyrighttag'}<br />
2893: $values{'extrashow'}
1.50 harris41 2894: </p>
1.150 matthew 2895: <hr align='left' width='200' noshade />
1.50 harris41 2896: END
2897: return $result;
2898: }
2899:
1.122 matthew 2900: ######################################################################
2901: ######################################################################
2902:
2903: =pod
2904:
1.150 matthew 2905: =item &compact_view()
2906:
2907: =cut
2908:
2909: ######################################################################
2910: ######################################################################
2911: sub compact_view {
2912: my ($prefix,%values) = @_;
1.192 albertel 2913: my $icon=&Apache::loncommon::icon($values{'url'});
1.150 matthew 2914: my $result=<<END;
1.192 albertel 2915: $prefix <img src="$icon" /> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}" target='search_preview'>
1.150 matthew 2916: $values{'title'}</a>
2917: <b>$values{'author'}</b><br />
2918: END
2919: return $result;
2920: }
2921:
2922:
2923: ######################################################################
2924: ######################################################################
2925:
2926: =pod
2927:
1.122 matthew 2928: =item &fielded_format_view()
2929:
2930: =cut
2931:
2932: ######################################################################
2933: ######################################################################
1.50 harris41 2934: sub fielded_format_view {
1.150 matthew 2935: my ($prefix,%values) = @_;
1.192 albertel 2936: my $icon=&Apache::loncommon::icon($values{'url'});
1.50 harris41 2937: my $result=<<END;
1.192 albertel 2938: $prefix <img src="$icon" />
1.126 matthew 2939: <b>URL: </b> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"
2940: target='search_preview'>$values{'url'}</a>
1.56 harris41 2941: <br />
1.126 matthew 2942: <b>Title:</b> $values{'title'}<br />
2943: <b>Author(s):</b> $values{'author'}<br />
2944: <b>Subject:</b> $values{'subject'}<br />
2945: <b>Keyword(s):</b> $values{'keywords'}<br />
2946: <b>Notes:</b> $values{'notes'}<br />
2947: <b>MIME Type:</b> $values{'mimetag'}<br />
2948: <b>Language:</b> $values{'language'}<br />
2949: <b>Creation Date:</b> $values{'creationdate'}<br />
2950: <b>Last Revision Date:</b> $values{'lastrevisiondate'}<br />
2951: <b>Publisher/Owner:</b> $values{'owner'}<br />
2952: <b>Copyright/Distribution:</b> $values{'copyrighttag'}<br />
2953: <b>Repository Location:</b> $values{'hostname'}<br />
2954: <b>Abstract:</b> $values{'shortabstract'}<br />
2955: $values{'extrashow'}
1.50 harris41 2956: </p>
1.150 matthew 2957: <hr align='left' width='200' noshade />
1.50 harris41 2958: END
2959: return $result;
2960: }
2961:
1.122 matthew 2962: ######################################################################
2963: ######################################################################
2964:
2965: =pod
2966:
2967: =item &xml_sgml_view()
2968:
2969: =back
2970:
2971: =cut
2972:
2973: ######################################################################
2974: ######################################################################
1.50 harris41 2975: sub xml_sgml_view {
1.150 matthew 2976: my ($prefix,%values) = @_;
1.212 matthew 2977: my $xml = <<END;
2978: <LonCapaResource>
2979: <url>$values{'url'}</url>
2980: <title>$values{'title'}</title>
2981: <author>$values{'author'}</author>
2982: <subject>$values{'subject'}</subject>
2983: <keywords>$values{'keywords'}</keywords>
2984: <notes>$values{'notes'}</notes>
2985: <mimeInfo>
2986: <mime>$values{'mime'}</mime>
2987: <mimetag>$values{'mimetag'}</mimetag>
2988: </mimeInfo>
2989: <languageInfo>
2990: <language>$values{'language'}</language>
2991: <languagetag>$values{'languagetag'}</languagetag>
2992: </languageInfo>
2993: <creationdate>$values{'creationdate'}</creationdate>
2994: <lastrevisiondate>$values{'lastrevisiondate'}</lastrevisiondate>
2995: <owner>$values{'owner'}</owner>
2996: <copyrightInfo>
2997: <copyright>$values{'copyright'}</copyright>
2998: <copyrighttag>$values{'copyrighttag'}</copyrighttag>
2999: </copyrightInfo>
3000: <repositoryLocation>$values{'hostname'}</repositoryLocation>
3001: <shortabstract>$values{'shortabstract'}</shortabstract>
3002: </LonCapaResource>
3003: END
3004: $xml = &HTML::Entities::encode($xml,'<>&');
1.50 harris41 3005: my $result=<<END;
1.150 matthew 3006: $prefix
1.56 harris41 3007: <pre>
1.212 matthew 3008: $xml
1.56 harris41 3009: </pre>
1.126 matthew 3010: $values{'extrashow'}
1.150 matthew 3011: <hr align='left' width='200' noshade />
1.50 harris41 3012: END
3013: return $result;
1.60 harris41 3014: }
3015:
1.122 matthew 3016: ######################################################################
3017: ######################################################################
3018:
3019: =pod
3020:
3021: =item &filled() see if field is filled.
3022:
3023: =cut
3024:
3025: ######################################################################
3026: ######################################################################
1.98 harris41 3027: sub filled {
3028: my ($field)=@_;
3029: if ($field=~/\S/ && $field ne 'any') {
1.204 matthew 3030: return 1;
3031: } else {
3032: return 0;
1.61 harris41 3033: }
1.60 harris41 3034: }
3035:
1.122 matthew 3036: ######################################################################
3037: ######################################################################
3038:
3039: =pod
3040:
3041: =item &output_blank_field_error()
3042:
1.151 matthew 3043: Output a complete page that indicates the user has not filled in enough
3044: information to do a search.
3045:
3046: Inputs: $r (Apache request handle), $closebutton, $parms.
3047:
3048: Returns: nothing
3049:
3050: $parms is extra information to include in the 'Revise search request' link.
3051:
1.122 matthew 3052: =cut
3053:
3054: ######################################################################
3055: ######################################################################
1.98 harris41 3056: sub output_blank_field_error {
1.196 matthew 3057: my ($r,$closebutton,$parms,$hidden_fields)=@_;
3058: my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.98 harris41 3059: # make query information persistent to allow for subsequent revision
3060: $r->print(<<BEGINNING);
3061: <html>
3062: <head>
3063: <title>The LearningOnline Network with CAPA</title>
3064: BEGINNING
3065: $r->print(<<RESULTS);
3066: </head>
1.155 matthew 3067: $bodytag
1.98 harris41 3068: <img align='right' src='/adm/lonIcons/lonlogos.gif' />
3069: <h1>Search Catalog</h1>
3070: <form method="post" action="/adm/searchcat">
1.145 matthew 3071: $hidden_fields
1.151 matthew 3072: <a href="/adm/searchcat?$parms&persistent_db_id=$ENV{'form.persistent_db_id'}"
1.146 matthew 3073: >Revise search request</a>
1.98 harris41 3074: $closebutton
3075: <hr />
1.151 matthew 3076: <h3>Unactionable search query.</h3>
1.98 harris41 3077: <p>
1.151 matthew 3078: You did not fill in enough information for the search to be started.
3079: You need to fill in relevant fields on the search page in order
3080: for a query to be processed.
1.98 harris41 3081: </p>
3082: </body>
3083: </html>
3084: RESULTS
3085: }
3086:
1.122 matthew 3087: ######################################################################
3088: ######################################################################
3089:
3090: =pod
3091:
3092: =item &output_date_error()
3093:
3094: Output a full html page with an error message.
3095:
1.145 matthew 3096: Inputs:
3097:
3098: $r, the request pointer.
3099: $message, the error message for the user.
3100: $closebutton, the specialized close button needed for groupsearch.
3101:
1.122 matthew 3102: =cut
3103:
3104: ######################################################################
3105: ######################################################################
1.60 harris41 3106: sub output_date_error {
1.196 matthew 3107: my ($r,$message,$closebutton,$hidden_fields)=@_;
1.60 harris41 3108: # make query information persistent to allow for subsequent revision
1.196 matthew 3109: my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
1.122 matthew 3110: $r->print(<<RESULTS);
1.60 harris41 3111: <html>
3112: <head>
3113: <title>The LearningOnline Network with CAPA</title>
3114: </head>
1.155 matthew 3115: $bodytag
1.98 harris41 3116: <img align='right' src='/adm/lonIcons/lonlogos.gif' />
1.60 harris41 3117: <h1>Search Catalog</h1>
3118: <form method="post" action="/adm/searchcat">
1.145 matthew 3119: $hidden_fields
1.60 harris41 3120: <input type='button' value='Revise search request'
1.98 harris41 3121: onClick='this.form.submit();' />
1.60 harris41 3122: $closebutton
1.98 harris41 3123: <hr />
1.151 matthew 3124: <h3>Error</h3>
1.60 harris41 3125: <p>
3126: $message
3127: </p>
3128: </body>
3129: </html>
3130: RESULTS
1.101 harris41 3131: }
3132:
1.122 matthew 3133: ######################################################################
3134: ######################################################################
3135:
3136: =pod
3137:
3138: =item &start_fresh_session()
3139:
1.142 matthew 3140: Cleans the global %groupsearch_db by removing all fields which begin with
1.122 matthew 3141: 'pre_' or 'store'.
3142:
3143: =cut
3144:
3145: ######################################################################
3146: ######################################################################
1.101 harris41 3147: sub start_fresh_session {
1.142 matthew 3148: delete $groupsearch_db{'mode_catalog'};
3149: foreach (keys %groupsearch_db) {
1.101 harris41 3150: if ($_ =~ /^pre_/) {
1.142 matthew 3151: delete $groupsearch_db{$_};
1.101 harris41 3152: }
3153: if ($_ =~ /^store/) {
1.142 matthew 3154: delete $groupsearch_db{$_};
1.101 harris41 3155: }
1.109 harris41 3156: }
1.3 harris41 3157: }
1.1 www 3158:
3159: 1;
1.162 www 3160:
3161: sub cleanup {
1.163 www 3162: if (tied(%groupsearch_db)) {
3163: unless (untie(%groupsearch_db)) {
3164: &Apache::lonnet::logthis('Failed cleanup searchcat: groupsearch_db');
3165: }
3166: }
1.167 www 3167: &untiehash();
1.162 www 3168: &Apache::lonmysql::disconnect_from_db();
3169: }
1.98 harris41 3170:
1.1 www 3171: __END__
1.105 harris41 3172:
1.121 matthew 3173: =pod
1.105 harris41 3174:
1.121 matthew 3175: =back
1.105 harris41 3176:
3177: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>