Annotation of loncom/interface/lonsearchcat.pm, revision 1.333

1.98      harris41    1: # The LearningOnline Network with CAPA
1.108     harris41    2: # Search Catalog
                      3: #
1.333   ! raeburn     4: # $Id: lonsearchcat.pm,v 1.332 2012/12/07 18:16:33 bisitz 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.243     albertel   66: use Apache::lonnet;
1.6       harris41   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.228     matthew    78: use Parse::RecDescent;
1.231     raeburn    79: use Apache::lonnavmaps;
1.255     www        80: use Apache::lonindexer();
1.328     wenzelju   81: use Apache::lonwishlist();
1.265     www        82: use LONCAPA;
1.1       www        83: 
1.121     matthew    84: ######################################################################
                     85: ######################################################################
1.196     matthew    86: ##
                     87: ## Global variables
                     88: ##
1.121     matthew    89: ######################################################################
                     90: ######################################################################
1.196     matthew    91: my %groupsearch_db;  # Database hash used to save values for the 
                     92:                      # groupsearch RAT interface.
                     93: my %persistent_db;   # gdbm hash which holds data which is supposed to
                     94:                      # persist across calls to lonsearchcat.pm
1.121     matthew    95: 
1.200     www        96: # The different view modes and associated functions
                     97: 
                     98: my %Views = ("detailed" => \&detailed_citation_view,
1.255     www        99:              "detailedpreview" => \&detailed_citation_preview,
1.200     www       100: 	     "summary"  => \&summary_view,
1.255     www       101:              "summarypreview" => \&summary_preview,
1.200     www       102: 	     "fielded"  => \&fielded_format_view,
                    103: 	     "xml"      => \&xml_sgml_view,
                    104: 	     "compact"  => \&compact_view);
1.101     harris41  105: 
1.121     matthew   106: ######################################################################
                    107: ######################################################################
1.98      harris41  108: sub handler {
                    109:     my $r = shift;
1.197     www       110: #    &set_defaults();
1.196     matthew   111:     #
                    112:     # set form defaults
1.145     matthew   113:     #
1.196     matthew   114:     my $hidden_fields;# Hold all the hidden fields used to keep track
                    115:                       # of the search system state
                    116:     my $importbutton; # button to take the selected results and go to group 
                    117:                       # sorting
                    118:     my $diropendb;    # The full path to the (temporary) search database file.
                    119:                       # This is set and used in &handler() and is also used in 
                    120:                       # &output_results().
1.157     www       121: 
1.221     matthew   122:     #
1.145     matthew   123:     my $closebutton;  # button that closes the search window 
                    124:                       # This button is different for the RAT compared to
                    125:                       # normal invocation.
                    126:     #
1.186     www       127:     &Apache::loncommon::content_type($r,'text/html');
1.98      harris41  128:     $r->send_http_header;
                    129:     return OK if $r->header_only;
1.156     matthew   130:     ##
                    131:     ## Prevent caching of the search interface window.  Hopefully this means
                    132:     ## we will get the launch=1 passed in a little more.
                    133:     &Apache::loncommon::no_cache($r);
1.145     matthew   134:     ## 
                    135:     ## Pick up form fields passed in the links.
                    136:     ##
                    137:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.146     matthew   138:              ['catalogmode','launch','acts','mode','form','element','pause',
1.158     matthew   139:               'phase','persistent_db_id','table','start','show',
1.288     albertel  140:               'cleargroupsort','titleelement','area','inhibitmenu']);
1.146     matthew   141:     ##
                    142:     ## The following is a trick - we wait a few seconds if asked to so
                    143:     ##     the daemon running the search can get ahead of the daemon
                    144:     ##     printing the results.  We only need (theoretically) to do
                    145:     ##     this once, so the pause indicator is deleted
                    146:     ##
1.243     albertel  147:     if (exists($env{'form.pause'})) {
1.181     matthew   148:         sleep(1);
1.243     albertel  149:         delete($env{'form.pause'});
1.146     matthew   150:     }
1.143     matthew   151:     ##
                    152:     ## Initialize global variables
                    153:     ##
1.121     matthew   154:     my $domain  = $r->dir_config('lonDefDomain');
1.330     foxr      155:     my $temp_file_dir = LONCAPA::tempdir();
                    156:     $diropendb= $temp_file_dir .
1.266     www       157:         "$env{'user.domain'}_$env{'user.name'}_sel_res.db";
1.145     matthew   158:     #
                    159:     # set the name of the persistent database
1.243     albertel  160:     #          $env{'form.persistent_db_id'} can only have digits in it.
                    161:     if (! exists($env{'form.persistent_db_id'}) ||
                    162:         ($env{'form.persistent_db_id'} =~ /\D/) ||
                    163:         ($env{'form.launch'} eq '1')) {
                    164:         $env{'form.persistent_db_id'} = time;
1.145     matthew   165:     }
1.257     albertel  166: 
1.330     foxr      167:     my $persistent_db_file = $temp_file_dir .
1.265     www       168:         &escape($domain).
                    169:             '_'.&escape($env{'user.name'}).
1.243     albertel  170:                 '_'.$env{'form.persistent_db_id'}.'_persistent_search.db';
1.146     matthew   171:     ##
1.209     matthew   172:     &Apache::lonhtmlcommon::clear_breadcrumbs();
1.277     raeburn   173: 
                    174:     my @allowed_searches = ('portfolio');
                    175:     if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
                    176:         push(@allowed_searches,'res');
                    177:     } 
                    178:     my $crumb_text = 'Portfolio Search';
1.327     www       179:     if (@allowed_searches ==2) {
                    180:        $crumb_text = 'Portfolio and Catalog Search'; 
1.277     raeburn   181:     }
                    182:     &Apache::lonhtmlcommon::add_breadcrumb
                    183:        ({href=>'/adm/searchcat?'.
1.288     albertel  184: 	       &Apache::loncommon::inhibit_menu_check().
1.309     bisitz    185:                '&catalogmode='.$env{'form.catalogmode'}.
                    186:                '&launch='.$env{'form.launch'}.
                    187:                '&mode='.$env{'form.mode'},
1.277     raeburn   188:               text=>"$crumb_text",
1.227     matthew   189:               target=>'_top',
1.209     matthew   190:               bug=>'Searching',});
                    191:     #
1.243     albertel  192:     if ($env{'form.phase'} !~ m/(basic|adv|course)_search/) {
1.221     matthew   193:         if (! &get_persistent_form_data($persistent_db_file)) {
1.243     albertel  194:             if ($env{'form.phase'} =~ /(run_search|results)/) {
1.221     matthew   195:                 &Apache::lonnet::logthis('lonsearchcat:'.
                    196:                                          'Unable to recover data from '.
                    197:                                          $persistent_db_file);
1.256     albertel  198: 		my $msg =
                    199: 		    'We were unable to retrieve data describing your search. '.
                    200: 		    'This is a serious error and has been logged. '.
                    201: 		    'Please alert your LON-CAPA administrator.';
1.261     albertel  202: 		&Apache::loncommon::simple_error_page($r,'Search Error',
                    203: 						      $msg);
                    204: 		return OK;
1.221     matthew   205:             }
1.150     matthew   206:         }
1.221     matthew   207:     } else {
                    208:         &clean_up_environment();
1.147     matthew   209:     }
1.124     matthew   210:     ##
1.143     matthew   211:     ## Clear out old values from groupsearch database
1.124     matthew   212:     ##
1.146     matthew   213:     untie %groupsearch_db if (tied(%groupsearch_db));
1.243     albertel  214:     if (($env{'form.cleargroupsort'} eq '1') || 
                    215:         (($env{'form.launch'} eq '1') && 
1.267     www       216:          ($env{'form.catalogmode'} eq 'import'))) {
1.148     matthew   217: 	if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {
1.101     harris41  218: 	    &start_fresh_session();
1.142     matthew   219: 	    untie %groupsearch_db;
1.243     albertel  220:             delete($env{'form.cleargroupsort'});
1.122     matthew   221: 	} else {
1.155     matthew   222:             # This is a stupid error to give to the user.  
                    223:             # It really tells them nothing.
1.256     albertel  224: 	    my $msg = 'Unable to tie hash to db file.';
1.261     albertel  225: 	    &Apache::loncommon::simple_error_page($r,'Search Error',
                    226: 						  $msg);
                    227: 	    return OK;
1.101     harris41  228: 	}
                    229:     }
1.124     matthew   230:     ##
1.150     matthew   231:     ## Configure hidden fields
1.124     matthew   232:     ##
1.145     matthew   233:     $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.
1.243     albertel  234:         $env{'form.persistent_db_id'}.'" />'."\n";
                    235:     if (exists($env{'form.catalogmode'})) {
1.223     matthew   236:         $hidden_fields .= &hidden_field('catalogmode');
1.150     matthew   237:     }
1.243     albertel  238:     if (exists($env{'form.form'})) {
1.223     matthew   239:         $hidden_fields .= &hidden_field('form');
1.150     matthew   240:     }
1.243     albertel  241:     if (exists($env{'form.element'})) {
1.223     matthew   242:         $hidden_fields .= &hidden_field('element');
1.150     matthew   243:     }
1.243     albertel  244:     if (exists($env{'form.titleelement'})) {
1.223     matthew   245:         $hidden_fields .= &hidden_field('titleelement');
1.191     albertel  246:     }
1.243     albertel  247:     if (exists($env{'form.mode'})) {
1.223     matthew   248:         $hidden_fields .= &hidden_field('mode');
1.150     matthew   249:     }
1.276     raeburn   250:     if (exists($env{'form.area'})) {
                    251:         $hidden_fields .= &hidden_field('area');
                    252:     }
1.288     albertel  253:     if (exists($env{'form.inhibitmenu'})) {
                    254:         $hidden_fields .= &hidden_field('inhibitmenu');
                    255:     }
1.150     matthew   256:     ##
                    257:     ## Configure dynamic components of interface
1.146     matthew   258:     ##
1.243     albertel  259:     if ($env{'form.catalogmode'} eq 'interactive') {
1.313     bisitz    260:         $closebutton="<input type='button' name='close' value='".&mt('Close')."' ";
1.243     albertel  261:         if ($env{'form.phase'} =~ /(results|run_search)/) {
1.315     bisitz    262:             $closebutton .="onclick='parent.close()'";
1.150     matthew   263:         } else {
1.313     bisitz    264:             $closebutton .="onclick='self.close()'";
1.150     matthew   265:         }
1.315     bisitz    266:         $closebutton .=" />\n";
1.267     www       267:     } elsif ($env{'form.catalogmode'} eq 'import') {
1.313     bisitz    268:         $closebutton="<input type='button' name='close' value='".&mt('Close')."' ";
1.243     albertel  269:         if ($env{'form.phase'} =~ /(results|run_search)/) {
1.315     bisitz    270:             $closebutton .="onclick='parent.close()'";
1.150     matthew   271:         } else {
1.313     bisitz    272:             $closebutton .="onclick='self.close()'";
1.150     matthew   273:         }
1.315     bisitz    274:         $closebutton .= " />";
1.297     bisitz    275:         my $txt_import = &mt('IMPORT');
1.98      harris41  276:         $importbutton=<<END;
1.297     bisitz    277: <input type='button' name='import' value='$txt_import'
1.315     bisitz    278: onclick='javascript:select_group()' />
1.98      harris41  279: END
1.146     matthew   280:     } else {
                    281:         $closebutton = '';
                    282:         $importbutton = '';
1.98      harris41  283:     }
1.124     matthew   284:     ##
1.146     matthew   285:     ## Sanity checks on form elements
1.124     matthew   286:     ##
1.243     albertel  287:     if (!defined($env{'form.viewselect'})) {
1.248     www       288: 	$env{'form.viewselect'} ="summary";
1.146     matthew   289:     }
1.243     albertel  290:     $env{'form.phase'} = 'disp_basic' if (! exists($env{'form.phase'}));
                    291:     $env{'form.show'} = 20 if (! exists($env{'form.show'}));
1.209     matthew   292:     #
1.243     albertel  293:     $env{'form.searchmode'} = 'basic' if (! exists($env{'form.searchmode'}));
                    294:     if ($env{'form.phase'} eq 'adv_search' ||
                    295:         $env{'form.phase'} eq 'disp_adv') {
                    296:         $env{'form.searchmode'} = 'advanced';
1.209     matthew   297:     }
                    298:     #
1.243     albertel  299:     if ($env{'form.searchmode'} eq 'advanced') {
1.277     raeburn   300:         my $srchtype = 'Catalog';
                    301:         if ($env{'form.area'} eq 'portfolio') {
                    302:             $srchtype = 'Portfolio';
                    303:         }
1.209     matthew   304:         &Apache::lonhtmlcommon::add_breadcrumb
1.288     albertel  305:             ({href=>'/adm/searchcat?'.&Apache::loncommon::inhibit_menu_check().
1.309     bisitz    306:                   '&amp;phase=disp_adv'.
                    307:                   '&amp;catalogmode='.$env{'form.catalogmode'}.
                    308:                   '&amp;launch='.$env{'form.launch'}.
                    309:                   '&amp;mode='.$env{'form.mode'},
1.277     raeburn   310:                   text=>"Advanced $srchtype Search",
1.209     matthew   311:                   bug=>'Searching',});
1.327     www       312:     } 
1.146     matthew   313:     ##
                    314:     ## Switch on the phase
                    315:     ##
1.243     albertel  316:     if ($env{'form.phase'} eq 'disp_basic') {
1.196     matthew   317:         &print_basic_search_form($r,$closebutton,$hidden_fields);
1.243     albertel  318:     } elsif ($env{'form.phase'} eq 'disp_adv') {
1.196     matthew   319:         &print_advanced_search_form($r,$closebutton,$hidden_fields);
1.243     albertel  320:     } elsif ($env{'form.phase'} eq 'results') {
1.276     raeburn   321:         &display_results($r,$importbutton,$closebutton,$diropendb,
                    322:                          $env{'form.area'});
1.243     albertel  323:     } elsif ($env{'form.phase'} =~ /^(sort|run_search)$/) {
1.146     matthew   324:         my ($query,$customquery,$customshow,$libraries,$pretty_string) =
                    325:             &get_persistent_data($persistent_db_file,
                    326:                  ['query','customquery','customshow',
                    327:                   'libraries','pretty_string']);
1.243     albertel  328:         if ($env{'form.phase'} eq 'sort') {
1.151     matthew   329:             &print_sort_form($r,$pretty_string);
1.243     albertel  330:         } elsif ($env{'form.phase'} eq 'run_search') {
1.151     matthew   331:             &run_search($r,$query,$customquery,$customshow,
1.276     raeburn   332:                         $libraries,$pretty_string,$env{'form.area'});
1.151     matthew   333:         }
1.243     albertel  334:     } elsif(($env{'form.phase'} eq 'basic_search') ||
                    335:             ($env{'form.phase'} eq 'adv_search')) {
1.228     matthew   336:         #
                    337:         # We are running a search, try to parse it
                    338:         my ($query,$customquery,$customshow,$libraries) = 
                    339:             (undef,undef,undef,undef);
                    340:         my $pretty_string;
1.243     albertel  341:         if ($env{'form.phase'} eq 'basic_search') {
1.228     matthew   342:             ($query,$pretty_string,$libraries) = 
                    343:                 &parse_basic_search($r,$closebutton,$hidden_fields);
                    344:             return OK if (! defined($query));
1.243     albertel  345:             &make_persistent({ basicexp => $env{'form.basicexp'}},
1.228     matthew   346:                              $persistent_db_file);
                    347:         } else {                      # Advanced search
                    348:             ($query,$customquery,$customshow,$libraries,$pretty_string) 
                    349:                 = &parse_advanced_search($r,$closebutton,$hidden_fields);
                    350:             return OK if (! defined($query));
                    351:         }
                    352:         &make_persistent({ query => $query,
                    353:                            customquery => $customquery,
                    354:                            customshow => $customshow,
                    355:                            libraries => $libraries,
                    356:                            pretty_string => $pretty_string },
                    357:                          $persistent_db_file);
                    358:         #
1.146     matthew   359:         # Set up table
1.276     raeburn   360:         if (! defined(&create_results_table($env{'form.area'}))) {
1.198     www       361: 	    my $errorstring=&Apache::lonmysql::get_error();
1.211     matthew   362:             &Apache::lonnet::logthis('lonsearchcat.pm: Unable to create '.
                    363:                                      'needed table.  lonmysql error:'.
                    364:                                      $errorstring);
1.256     albertel  365: 
                    366: 	    my $msg = 
1.286     albertel  367: 		'Unable to create table in which to save search results. '.
1.256     albertel  368: 		'The search has been aborted.';
1.261     albertel  369: 	    &Apache::loncommon::simple_error_page($r,'Search Error',
                    370: 						  $msg);
                    371: 	    return OK;
1.146     matthew   372:         }
1.243     albertel  373:         delete($env{'form.launch'});
1.146     matthew   374:         if (! &make_form_data_persistent($r,$persistent_db_file)) {
1.256     albertel  375: 	    my $msg=
1.286     albertel  376: 		'Unable to properly save search information. '.
1.256     albertel  377: 		'The search has been aborted.';
1.261     albertel  378: 	    &Apache::loncommon::simple_error_page($r,'Search Error',
                    379: 						  $msg);
                    380: 	    return OK;
1.256     albertel  381: 	}
1.145     matthew   382:         ##
1.146     matthew   383:         ## Print out the frames interface
1.145     matthew   384:         ##
1.228     matthew   385:         if (defined($query)) {
                    386:             &print_frames_interface($r);
                    387:         }
1.124     matthew   388:     }
                    389:     return OK;
                    390: } 
1.98      harris41  391: 
1.221     matthew   392: #
                    393: # The mechanism used to store values away and retrieve them does not
                    394: # handle the case of missing environment variables being significant.
                    395: #
                    396: # This routine sets non existant checkbox form elements to ''.
                    397: #
                    398: sub clean_up_environment {
1.243     albertel  399:     if ($env{'form.phase'} eq 'basic_search') {
                    400:         if (! exists($env{'form.related'})) {
                    401:             $env{'form.related'} = '';
1.221     matthew   402:         }
1.243     albertel  403:         if (! exists($env{'form.domains'})) {
                    404:             $env{'form.domains'} = '';
1.221     matthew   405:         }
1.243     albertel  406:     } elsif ($env{'form.phase'} eq 'adv_search') {
1.221     matthew   407:         foreach my $field ('title','keywords','notes',
                    408:                            'abstract','standards','mime') {
1.243     albertel  409:             if (! exists($env{'form.'.$field.'_related'})) {
                    410:                 $env{'form.'.$field.'_related'} = '';
1.221     matthew   411:             }
                    412:         }
1.243     albertel  413:     } elsif ($env{'form.phase'} eq 'course_search') {
                    414:         if (! exists($env{'form.crsrelated'})) {
                    415:             $env{'form.crsrelated'} = '';
1.221     matthew   416:         }
                    417:     }
                    418: }
                    419: 
1.223     matthew   420: sub hidden_field {
                    421:     my ($name,$value) = @_;
                    422:     if (! defined($value)) {
1.243     albertel  423:         $value = $env{'form.'.$name};
1.223     matthew   424:     }
                    425:     return '<input type="hidden" name="'.$name.'" value="'.$value.'" />'.$/;
                    426: }
                    427: 
1.124     matthew   428: ######################################################################
1.167     www       429: 
1.124     matthew   430: =pod 
                    431: 
1.146     matthew   432: =item &print_basic_search_form() 
1.124     matthew   433: 
1.204     matthew   434: Prints the form for the basic search.  Sorry the name is so cryptic.
1.124     matthew   435: 
                    436: =cut
                    437: 
                    438: ######################################################################
                    439: ######################################################################
1.204     matthew   440: sub print_basic_search_form {
1.196     matthew   441:     my ($r,$closebutton,$hidden_fields) = @_;
1.267     www       442:     my $result = ($env{'form.catalogmode'} ne 'import');
1.256     albertel  443:     my $bread_crumb =
1.263     albertel  444:         &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Basic',
1.267     www       445: 					    $env{'form.catalogmode'} ne 'import');
1.305     schafran  446:     my $scrout = &Apache::loncommon::start_page('Content Library').$bread_crumb;
1.276     raeburn   447: # Search form for resource space 
1.243     albertel  448:     if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
1.276     raeburn   449:         $scrout .= &setup_basic_search($r,'res',$hidden_fields,$closebutton);
                    450:         $scrout .= '<hr /><br />';
1.180     matthew   451:     }
1.276     raeburn   452: # Search form for accessible portfolio files
                    453:     $scrout.= &setup_basic_search($r,'portfolio',$hidden_fields,$closebutton);
1.256     albertel  454:     $scrout .= &Apache::loncommon::end_page();
1.146     matthew   455:     $r->print($scrout);
                    456:     return;
1.124     matthew   457: }
1.276     raeburn   458: 
                    459: sub setup_basic_search {
                    460:     my ($r,$area,$hidden_fields,$closebutton) = @_;
                    461:     # Define interface components
                    462:     my %lt = &Apache::lonlocal::texthash (
                    463:                               res => 'LON-CAPA Catalog Search',
                    464:                               portfolio => 'Portfolio Search',
                    465:     );
                    466:     my ($userelatedwords,$onlysearchdomain,$inclext,$adv_search_link,$scrout);
1.318     bisitz    467: 
                    468:     $userelatedwords = '<label>'
                    469:                       .&Apache::lonhtmlcommon::checkbox(
                    470:                            'related',
                    471:                            $env{'form.related'},
                    472:                            'related')
                    473:                       .' '
                    474:                      .&mt('use related words')
                    475:                      .'</label>';
                    476: 
                    477:     $onlysearchdomain = '<label>'
                    478:                        .&Apache::lonhtmlcommon::checkbox(
                    479:                            'domains',
                    480:                            $env{'form.domains'},
                    481:                            $r->dir_config('lonDefDomain'))
                    482:                        .' '
                    483:                        .&mt('only search domain [_1]'
                    484:                                ,'<b>'.$r->dir_config('lonDefDomain').'</b>')
                    485:                        .'</label>';
                    486: 
1.276     raeburn   487:     $adv_search_link = '<a href="/adm/searchcat?'.
1.288     albertel  488: 	               &Apache::loncommon::inhibit_menu_check().
1.309     bisitz    489: 		       '&amp;phase=disp_adv'.
                    490:                        '&amp;catalogmode='.$env{'form.catalogmode'}.
                    491:                        '&amp;launch='.$env{'form.launch'}.
                    492:                        '&amp;mode='.$env{'form.mode'}.
                    493:                        '&amp;area='.$area.
                    494:                        '&amp;form='.$env{'form.form'}.
                    495:                        '&amp;titleelement='.$env{'form.titleelement'}.
                    496:                        '&amp;element='.$env{'form.element'}.
1.276     raeburn   497:                        '">'.&mt('Advanced Search').'</a>';
                    498:     #
                    499:     $scrout.='<form name="loncapa_search" method="post" '.
                    500:              'action="/adm/searchcat">'.
                    501:              '<input type="hidden" name="phase" value="basic_search" />'.
                    502:              $hidden_fields;
                    503:              if (!exists($env{'form.area'})) {
                    504:                  $scrout .= '<input type="hidden" name="area" value="'.$area.'" />';
                    505:              }
                    506:     #
1.313     bisitz    507:     $scrout .= '<div align="center">'.$/;
1.276     raeburn   508: #    if ($env{'request.course.id'}) {
                    509:         $scrout .= '<h1>'.$lt{$area}.'</h1>';
                    510: #    } else {
                    511:         # No need to tell them they are searching
                    512: #        $scrout.= ('<br />'x2);
                    513: #    }
                    514:     $scrout.='<table>'.
                    515:              '<tr><td align="center" valign="top">'.
                    516:              &Apache::lonhtmlcommon::textbox('basicexp',
                    517:                                              $env{'form.basicexp'},50).
                    518:              '<br />'.
1.313     bisitz    519:             '<span class="LC_fontsize_small">'.&searchhelp().'</span>'.'</td>'.
                    520:             '<td>'.
1.301     bisitz    521:             '<span class="LC_nobreak">'.('&nbsp;'x3).$adv_search_link.'</span>'.'<br />'.
                    522:             '<span class="LC_nobreak">'.('&nbsp;'x1).$userelatedwords.'</span>'.'<br />'.
                    523:             '<span class="LC_nobreak">'.('&nbsp;'x1).$onlysearchdomain.'</span>'.'<br />'.
                    524:             '<span class="LC_nobreak">'.('&nbsp;'x1).$inclext.'</span>'.'<br />'.
1.313     bisitz    525:              '</td>'.
                    526:             '</tr>'.
                    527:             '</table>'.$/;
                    528:     #
                    529:     $scrout .= '<p>'
                    530:               .&viewoptions()
                    531:               .'</p>'
                    532:               .'<p>'
                    533:               .'<input type="submit" name="basicsubmit" '
                    534:               .'value="'.&mt('Search').'" />'
                    535:               .' '
                    536:               .$closebutton
                    537:               .'</p>';
1.276     raeburn   538:     #
1.313     bisitz    539:     $scrout .= '</div>'.'</form>';
1.276     raeburn   540:     return $scrout;
                    541: } 
                    542: 
1.124     matthew   543: ######################################################################
                    544: ######################################################################
                    545: 
                    546: =pod 
                    547: 
                    548: =item &advanced_search_form() 
                    549: 
1.204     matthew   550: Prints the advanced search form.
1.124     matthew   551: 
                    552: =cut
                    553: 
                    554: ######################################################################
                    555: ######################################################################
1.146     matthew   556: sub print_advanced_search_form{
1.196     matthew   557:     my ($r,$closebutton,$hidden_fields) = @_;
1.256     albertel  558:     my $bread_crumb = 
1.263     albertel  559:         &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Advanced',
1.267     www       560: 					    $env{'form.catalogmode'} ne 'import');
1.200     www       561:     my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
                    562: 				       'reset' => 'Reset',
                    563: 				       'help' => 'Help');
1.217     matthew   564:     my $advanced_buttons=<<"END";
1.314     bisitz    565: <p>
1.200     www       566: <input type="submit" name="advancedsubmit" value='$lt{"srch"}' />
                    567: <input type="reset" name="reset" value='$lt{"reset"}' />
1.129     matthew   568: $closebutton
1.314     bisitz    569: </p>
1.129     matthew   570: END
1.277     raeburn   571:     my $srchtype = 'Catalog';
1.279     raeburn   572:     my $jscript;
1.277     raeburn   573:     if ($env{'form.area'} eq 'portfolio') {
                    574:         $srchtype = 'Portfolio';
1.279     raeburn   575:         $jscript = '<script type="text/javascript">
1.313     bisitz    576: // <![CDATA[
1.279     raeburn   577: function additional_metadata() {
                    578:     if (document.advsearch.newfield.checked) {
                    579:         document.advsearch.phase.value = "disp_adv";
                    580:         document.advsearch.numaddedfields.value = parseInt(document.advsearch.numaddedfields.value) +1;
                    581:         document.advsearch.submit();
1.277     raeburn   582:     }
1.279     raeburn   583: }
1.313     bisitz    584: // ]]>
1.279     raeburn   585: </script>';
                    586:     }
                    587:     my $scrout= &Apache::loncommon::start_page("Advanced $srchtype Search",
                    588:                                                $jscript);
1.314     bisitz    589:     $scrout .= $bread_crumb;
                    590: 
                    591:     $scrout .= '<form method="post" action="/adm/searchcat" name="advsearch">'
                    592:               .$hidden_fields 
                    593:               .'<input type="hidden" name="phase" value="adv_search" />';
                    594: 
                    595:     $scrout .= '<fieldset>'."\n"
                    596:               .'<legend>'.&mt('Display Options').'</legend>'."\n"
                    597:               .&viewoptions()
                    598:               .'</fieldset>';
                    599: 
                    600:     $scrout .= $advanced_buttons;
                    601: 
                    602:     $scrout .= &Apache::lonhtmlcommon::start_pick_box();
                    603: 
1.200     www       604:     my %fields=&Apache::lonmeta::fieldnames();
1.314     bisitz    605: 
                    606:     # Standard Metadata
                    607:     $scrout .= &Apache::lonhtmlcommon::row_headline()
                    608:               .'<h3>'.&mt("Standard $srchtype Metadata").'</h3>'
                    609:               .&searchhelp()
                    610:               .&Apache::lonhtmlcommon::row_closure();
1.208     matthew   611:     my %related_word_search = 
1.217     matthew   612:         ('title'    => 1,
                    613:          'author'   => 0,
                    614:          'owner'    => 0,
                    615:          'authorspace'  => 0,
                    616:          'modifyinguser'=> 0,
                    617:          'keywords' => 1,
                    618:          'notes'    => 1,
                    619:          'abstract' => 1,
                    620:          'standards'=> 1,
                    621:          'mime'     => 1,
1.314     bisitz    622:          'subject'  => 1,
1.208     matthew   623:          );
1.209     matthew   624:     #
1.246     albertel  625:     foreach my $field ('title','author','subject','owner','authorspace',
1.314     bisitz    626:                        'modifyinguser','keywords','notes','abstract',
                    627:                        'standards','mime') {
                    628:         $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield($fields{$field}))
                    629:                   .&Apache::lonmeta::prettyinput($field,
1.243     albertel  630:                                           $env{'form.'.$field},
1.208     matthew   631:                                           $field,
                    632:                                           'advsearch',
1.314     bisitz    633:                                           $related_word_search{$field},
                    634:                                           '',
1.243     albertel  635:                                           $env{'form.'.$field.'_related'},
1.208     matthew   636:                                           50);
                    637:         if ($related_word_search{$field}) {
1.289     bisitz    638:             $scrout .= &mt('related words');
1.208     matthew   639:         } else {
1.314     bisitz    640:             $scrout .= '';
1.208     matthew   641:         }
1.314     bisitz    642:         $scrout .= &Apache::lonhtmlcommon::row_closure();
1.208     matthew   643:     }
                    644:     foreach my $field ('lowestgradelevel','highestgradelevel') {
1.314     bisitz    645:         $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield($fields{$field}))
                    646:                   .&Apache::lonmeta::prettyinput($field,
1.243     albertel  647:                                           $env{'form.'.$field},
1.208     matthew   648:                                           $field,
                    649:                                           'advsearch',
1.314     bisitz    650:                                           0)
                    651:                   .&Apache::lonhtmlcommon::row_closure();
1.200     www       652:     }
1.314     bisitz    653: 
                    654:     $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('MIME Type Category')))
                    655:               .&Apache::loncommon::filecategoryselect('category',
                    656:                    $env{'form.category'})
                    657:               .&Apache::lonhtmlcommon::row_closure();
                    658: 
                    659:     $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('Domains')))
                    660:               .&Apache::loncommon::domain_select('domains',
                    661:                    $env{'form.domains'},1)
                    662:               .&Apache::lonhtmlcommon::row_closure();
                    663: 
1.217     matthew   664:     # Misc metadata
1.276     raeburn   665:     if ($env{'form.area'} ne 'portfolio') {
1.314     bisitz    666:         $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('Copyright/Distribution')))
                    667:                   .&Apache::lonmeta::selectbox('copyright',
1.276     raeburn   668:                                              $env{'form.copyright'},
                    669:                                 \&Apache::loncommon::copyrightdescription,
                    670:                                        ( undef,
                    671:                                         &Apache::loncommon::copyrightids)
1.314     bisitz    672:                                 )
                    673:                   .&Apache::lonhtmlcommon::row_closure();
1.276     raeburn   674:     }
1.314     bisitz    675: 
                    676:     $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('Language')))
                    677:               .&Apache::lonmeta::selectbox('language',
1.243     albertel  678:                                     $env{'form.language'},
1.217     matthew   679:                                     \&Apache::loncommon::languagedescription,
                    680:                                     ('any',&Apache::loncommon::languageids)
1.314     bisitz    681:                                     )
                    682:               .&Apache::lonhtmlcommon::row_closure();
1.276     raeburn   683:     
1.314     bisitz    684:     # Portfolio Metadata
1.276     raeburn   685:     if ($env{'form.area'} eq 'portfolio') {
                    686:         # Added fields
1.279     raeburn   687:         my $curnumadd = $env{'form.numaddedfields'};
                    688:         if ($curnumadd eq '') {
                    689:             $curnumadd = 1;
                    690:         }
1.314     bisitz    691:         $scrout .= &Apache::lonhtmlcommon::row_headline()
                    692:                   .'<h3>'.&mt('Custom Metadata fields').'</h3>'
                    693:                   .&Apache::lonhtmlcommon::row_closure()
                    694:                   .&Apache::lonhtmlcommon::row_title('')
                    695:                   .&mt('Field Name').' | '.&mt('Field Value(s)')
                    696:                   .&Apache::lonhtmlcommon::row_closure();
1.279     raeburn   697: 
                    698:         for (my $j=0; $j<$curnumadd; $j++) {
1.276     raeburn   699:             my $num = $j+1;
1.314     bisitz    700:             $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Custom metadata [_1]',$num))
                    701:                       .'<input type="text"'
                    702:                       .' name="addedfield_'.$j.'" size="10"'
                    703:                       .' value="'.$env{'form.addedfield_'.$j}.'" />'
                    704:                       .' '
                    705:                       .'<input type="text" '
                    706:                       .'name="addedvalues_'.$j.'" size="15"'
                    707:                       .' value="'.$env{'form.addedvalues_'.$j}.'" />'
                    708:                       .&Apache::lonhtmlcommon::row_closure();
                    709:         }
                    710:         $scrout .= &Apache::lonhtmlcommon::row_title('')
                    711:                   .'<label>'
                    712:                   .'<input type="checkbox" name="newfield"'
                    713:                   .' value="1" onclick="javascript:additional_metadata()" />'
                    714:                   .&mt('Another custom field/value pair?').'</label>'
                    715:                   .'<input type="hidden" name="numaddedfields"'
                    716:                   .' value="'.$curnumadd.'" />'
                    717:                   .&Apache::lonhtmlcommon::row_closure();
                    718: } else {
1.276     raeburn   719:         #
                    720:         # Dynamic metadata
1.314     bisitz    721:         $scrout .= &Apache::lonhtmlcommon::row_headline()
                    722:                   .'<h3>'.&mt('Problem Statistics').'</h3>'
                    723:                   .&Apache::lonhtmlcommon::row_closure();
                    724:         $scrout .= &Apache::lonhtmlcommon::row_title('')
                    725:                   .&mt('Minimum').' | '.&mt('Maximum')
                    726:                   .&Apache::lonhtmlcommon::row_closure();
1.276     raeburn   727:         foreach my $statistic 
                    728:             ({ name=>'count',
                    729:                description=>'Network-wide number of accesses (hits)',},
                    730:              { name=>'stdno',
                    731:                description=>
1.285     www       732:                'Statistics calculated for number of students',},
1.276     raeburn   733:              { name => 'avetries',
                    734:                description=>'Average number of tries till solved',},
                    735:              { name => 'difficulty',
                    736:                description=>'Degree of difficulty',},
                    737:              { name => 'disc',
                    738:                description=>'Degree of discrimination'}) {
1.314     bisitz    739:               $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt($statistic->{'description'})))
                    740:                         .'<input type="text" name="'.$statistic->{'name'}
                    741:                         .'_min" value="" size="6" />'
                    742:                         .' '
                    743:                         .'<input type="text" name="'.$statistic->{'name'}
                    744:                         .'_max" value="" size="6" />'
                    745:                         .&Apache::lonhtmlcommon::row_closure();
                    746:         }
                    747: 
                    748:         $scrout .= &Apache::lonhtmlcommon::row_headline()
                    749:                   .'<h3>'.&mt('Evaluation Data').'</h3>'
                    750:                   .&Apache::lonhtmlcommon::row_closure();
                    751:         $scrout .= &Apache::lonhtmlcommon::row_title('')
                    752:                   .&mt('Minimum').' | '.&mt('Maximum')
                    753:                   .&Apache::lonhtmlcommon::row_closure();
1.276     raeburn   754:         foreach my $evaluation
                    755:             ( { name => 'clear',
                    756:                 description => 'Material presented in clear way'},
                    757:               { name =>'depth',
                    758:                 description => 'Material covered with sufficient depth'},
                    759:               { name => 'helpful',
                    760:                 description => 'Material is helpful'},
                    761:               { name => 'correct',
                    762:                 description => 'Material appears to be correct'},
                    763:               { name => 'technical',
                    764:                 description => 'Resource is technically correct'}){
1.314     bisitz    765:             $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt($evaluation->{'description'})))
                    766:                       .'<input type="text" name="'
                    767:                       .$evaluation->{'name'}.'_min" value="" size="6" />'
                    768:                       .' '
                    769:                       .'<input type="text" name="'
                    770:                       .$evaluation->{'name'}.'_max" value="" size="6" />'
                    771:                       .&Apache::lonhtmlcommon::row_closure();
1.276     raeburn   772:         }
1.217     matthew   773:     }
1.216     matthew   774:     #
                    775:     # Creation/Modification date limits
1.314     bisitz    776:     $scrout .= &Apache::lonhtmlcommon::row_headline()
                    777:               .'<h3>'.&mt('Creation and Modification dates').'</h3>'
                    778:               .&Apache::lonhtmlcommon::row_closure();
                    779:     $scrout .= &Apache::lonhtmlcommon::row_title('')
                    780:               .&mt('Month[_1]Day[_2]Year','&nbsp;'x14,'&nbsp;'x6)
                    781:               .&Apache::lonhtmlcommon::row_closure();
                    782: 
1.216     matthew   783:     my $cafter = 
                    784:         &Apache::lonhtmlcommon::date_setter('advsearch',         # formname
                    785:                                             'creationdate1', # fieldname
                    786:                                             0,           # current value
                    787:                                             '',          # special 
                    788:                                             1,           # includeempty
                    789:                                             '',          # state
                    790:                                             1,           # no_hh_mm_ss
                    791:                                             );
                    792:     my $cbefore = 
                    793:         &Apache::lonhtmlcommon::date_setter('advsearch',         # formname
                    794:                                             'creationdate2', # fieldname
                    795:                                             0,           # current value
                    796:                                             '',          # special 
                    797:                                             1,           # includeempty
                    798:                                             '',          # state
                    799:                                             1,           # no_hh_mm_ss
                    800:                                             );
1.314     bisitz    801:     $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Created between'))
                    802:               .$cafter
                    803:               .&Apache::lonhtmlcommon::row_closure(1)
                    804:               .&Apache::lonhtmlcommon::row_title(&mt('and'))
                    805:               .$cbefore
                    806:               .&Apache::lonhtmlcommon::row_closure();
                    807: 
1.216     matthew   808:     my $lafter = 
                    809:         &Apache::lonhtmlcommon::date_setter('advsearch',
                    810:                                             'revisiondate1', 
                    811:                                             0,           # current value
                    812:                                             '',          # special 
                    813:                                             1,           # includeempty
                    814:                                             '',          # state
                    815:                                             1,           # no_hh_mm_ss
                    816:                                             );
                    817:     my $lbefore = 
                    818:         &Apache::lonhtmlcommon::date_setter('advsearch',
                    819:                                             'revisiondate2',
                    820:                                             0,           # current value
                    821:                                             '',          # special 
                    822:                                             1,           # includeempty
                    823:                                             '',          # state
                    824:                                             1,           # no_hh_mm_ss
                    825:                                             );
1.314     bisitz    826:     $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Last modified between'))
                    827:               .$lafter
                    828:               .&Apache::lonhtmlcommon::row_closure(1)
                    829:               .&Apache::lonhtmlcommon::row_title(&mt('and'))
                    830:               .$lbefore
                    831:               .&Apache::lonhtmlcommon::row_closure(1); # Last row of total pick_box
                    832: 
                    833:     $scrout .= &Apache::lonhtmlcommon::end_pick_box();
                    834: 
                    835:     $scrout .= $advanced_buttons
                    836:               .'</form>';
                    837: 
1.256     albertel  838:     $scrout .= &Apache::loncommon::end_page();
1.146     matthew   839:     $r->print($scrout);
                    840:     return;
1.124     matthew   841: }
1.204     matthew   842: 
1.200     www       843: ######################################################################
                    844: ######################################################################
                    845: 
                    846: =pod 
                    847: 
1.204     matthew   848: =item &titlefield()
1.200     www       849: 
                    850: Inputs: title text
                    851: 
                    852: Outputs: titletext with font wrapper
                    853: 
                    854: =cut
                    855: 
                    856: ######################################################################
                    857: ######################################################################
                    858: sub titlefield {
                    859:     my $title=shift;
1.208     matthew   860:     return $title;
1.200     www       861: }
1.204     matthew   862: 
1.200     www       863: ######################################################################
                    864: ######################################################################
                    865: 
                    866: =pod 
                    867: 
1.204     matthew   868: =item viewoptiontext()
1.200     www       869: 
                    870: Inputs: codename for view option
                    871: 
                    872: Outputs: displayed text
                    873: 
                    874: =cut
                    875: 
                    876: ######################################################################
                    877: ######################################################################
                    878: sub viewoptiontext {
                    879:     my $code=shift;
1.204     matthew   880:     my %desc=&Apache::lonlocal::texthash
                    881:         ('detailed' => "Detailed Citation View",
                    882:          'xml' => 'XML/SGML',
                    883:          'compact' => 'Compact View',
                    884:          'fielded' => 'Fielded Format',
1.255     www       885:          'summary' => 'Summary View',
                    886:          'summarypreview' => 'Summary Preview',
                    887:          'detailedpreview' => 'Detailed Citation Preview');
1.200     www       888:     return $desc{$code};
                    889: }
1.204     matthew   890: 
                    891: ######################################################################
1.200     www       892: ######################################################################
                    893: 
                    894: =pod 
                    895: 
1.204     matthew   896: =item viewoptions()
1.200     www       897: 
                    898: Inputs: none
                    899: 
                    900: Outputs: text for box with view options
                    901: 
                    902: =cut
                    903: 
                    904: ######################################################################
                    905: ######################################################################
                    906: sub viewoptions {
1.313     bisitz    907:     my $scrout;
1.243     albertel  908:     if (! defined($env{'form.viewselect'})) { 
                    909:         $env{'form.viewselect'}='detailed'; 
1.208     matthew   910:     }
1.313     bisitz    911:     $scrout .= '<span class="LC_nobreak">'
                    912:               .&mt('Type:').' '
                    913:               .&Apache::lonmeta::selectbox('viewselect',
                    914:                    $env{'form.viewselect'},
                    915:                    \&viewoptiontext,
                    916:                    sort(keys(%Views)))
                    917:               .'</span>';
1.214     matthew   918:     my $countselect = &Apache::lonmeta::selectbox('show',
1.243     albertel  919:                                                   $env{'form.show'},
1.214     matthew   920:                                                   undef,
                    921:                                                   (10,20,50,100,1000,10000));
1.313     bisitz    922:     $scrout .= ' <span class="LC_nobreak">'
                    923:               .&mt('Records per Page:').' '.$countselect
1.301     bisitz    924:               .'</span>'.$/;
1.200     www       925:     return $scrout;
1.201     www       926: }
                    927: 
                    928: ######################################################################
1.204     matthew   929: ######################################################################
1.201     www       930: 
                    931: =pod 
                    932: 
1.204     matthew   933: =item searchhelp()
1.201     www       934: 
                    935: Inputs: none
                    936: 
                    937: Outputs: return little blurb on how to enter searches
                    938: 
                    939: =cut
                    940: 
                    941: ######################################################################
                    942: ######################################################################
                    943: sub searchhelp {
1.228     matthew   944:     return &mt('Enter words and quoted phrases');
1.200     www       945: }
1.8       harris41  946: 
1.121     matthew   947: ######################################################################
                    948: ######################################################################
                    949: 
                    950: =pod 
                    951: 
1.204     matthew   952: =item &get_persistent_form_data()
1.145     matthew   953: 
1.146     matthew   954: Inputs: filename of database
                    955: 
                    956: Outputs: returns undef on database errors.
                    957: 
                    958: This function is the reverse of &make_persistent() for form data.
1.145     matthew   959: Retrieve persistent data from %persistent_db.  Retrieved items will have their
1.243     albertel  960: values unescaped.  If a form value already exists in $env, it will not be
1.146     matthew   961: overwritten.  Form values that are array references may have values appended
                    962: to them.
1.145     matthew   963: 
                    964: =cut
                    965: 
                    966: ######################################################################
                    967: ######################################################################
1.146     matthew   968: sub get_persistent_form_data {
                    969:     my $filename = shift;
1.147     matthew   970:     return 0 if (! -e $filename);
1.146     matthew   971:     return undef if (! tie(%persistent_db,'GDBM_File',$filename,
1.148     matthew   972:                            &GDBM_READER(),0640));
1.146     matthew   973:     #
                    974:     # These make sure we do not get array references printed out as 'values'.
1.161     matthew   975:     my %arrays_allowed = ('form.domains'=>1);
1.146     matthew   976:     #
                    977:     # Loop through the keys, looking for 'form.'
                    978:     foreach my $name (keys(%persistent_db)) {
                    979:         next if ($name !~ /^form./);
1.182     matthew   980:         # Kludgification begins!
                    981:         if ($name eq 'form.domains' && 
1.243     albertel  982:             $env{'form.searchmode'} eq 'basic' &&
                    983:             $env{'form.phase'} ne 'disp_basic') {
1.182     matthew   984:             next;
                    985:         }
                    986:         # End kludge (hopefully)
1.243     albertel  987:         next if (exists($env{$name}));
1.146     matthew   988:         my @values = map { 
1.265     www       989:             &unescape($_);
1.146     matthew   990:         } split(',',$persistent_db{$name});
                    991:         next if (@values <1);
1.152     matthew   992:         if ($arrays_allowed{$name}) {
1.243     albertel  993:             $env{$name} = [@values];
1.146     matthew   994:         } else {
1.243     albertel  995:             $env{$name} = $values[0] if ($values[0]);
1.146     matthew   996:         }
                    997:     }
                    998:     untie (%persistent_db);
                    999:     return 1;
                   1000: }
1.181     matthew  1001: 
1.146     matthew  1002: ######################################################################
                   1003: ######################################################################
                   1004: 
                   1005: =pod 
                   1006: 
1.204     matthew  1007: =item &get_persistent_data()
1.146     matthew  1008: 
                   1009: Inputs: filename of database, ref to array of values to recover.
                   1010: 
                   1011: Outputs: array of values.  Returns undef on error.
                   1012: 
                   1013: This function is the reverse of &make_persistent();
                   1014: Retrieve persistent data from %persistent_db.  Retrieved items will have their
                   1015: values unescaped.  If the item contains commas (before unescaping), the
                   1016: returned value will be an array pointer. 
                   1017: 
                   1018: =cut
                   1019: 
                   1020: ######################################################################
                   1021: ######################################################################
                   1022: sub get_persistent_data {
                   1023:     my $filename = shift;
                   1024:     my @Vars = @{shift()};
                   1025:     my @Values;   # Return array
                   1026:     return undef if (! -e $filename);
                   1027:     return undef if (! tie(%persistent_db,'GDBM_File',$filename,
1.148     matthew  1028:                            &GDBM_READER(),0640));
1.146     matthew  1029:     foreach my $name (@Vars) {
                   1030:         if (! exists($persistent_db{$name})) {
                   1031:             push @Values, undef;
                   1032:             next;
                   1033:         }
                   1034:         my @values = map { 
1.265     www      1035:             &unescape($_);
1.146     matthew  1036:         } split(',',$persistent_db{$name});
1.152     matthew  1037:         if (@values <= 1) {
1.146     matthew  1038:             push @Values,$values[0];
1.145     matthew  1039:         } else {
1.146     matthew  1040:             push @Values,\@values;
1.145     matthew  1041:         }
                   1042:     }
1.146     matthew  1043:     untie (%persistent_db);
                   1044:     return @Values;
1.145     matthew  1045: }
                   1046: 
                   1047: ######################################################################
                   1048: ######################################################################
                   1049: 
                   1050: =pod 
                   1051: 
1.121     matthew  1052: =item &make_persistent() 
                   1053: 
1.146     matthew  1054: Inputs: Hash of values to save, filename of persistent database.
                   1055: 
                   1056: Store variables away to the %persistent_db.
1.145     matthew  1057: Values will be escaped.  Values that are array pointers will have their
1.205     www      1058: elements escaped and concatenated in a comma separated string.  
1.122     matthew  1059: 
1.121     matthew  1060: =cut
                   1061: 
                   1062: ######################################################################
                   1063: ######################################################################
1.98      harris41 1064: sub make_persistent {
1.133     matthew  1065:     my %save = %{shift()};
1.146     matthew  1066:     my $filename = shift;
                   1067:     return undef if (! tie(%persistent_db,'GDBM_File',
1.148     matthew  1068:                            $filename,&GDBM_WRCREAT(),0640));
1.146     matthew  1069:     foreach my $name (keys(%save)) {
1.145     matthew  1070:         my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
                   1071:         # We handle array references, but not recursively.
1.265     www      1072:         my $store = join(',', map { &escape($_); } @values );
1.145     matthew  1073:         $persistent_db{$name} = $store;
1.109     harris41 1074:     }
1.146     matthew  1075:     untie(%persistent_db);
                   1076:     return 1;
                   1077: }
                   1078: 
                   1079: ######################################################################
                   1080: ######################################################################
                   1081: 
                   1082: =pod 
                   1083: 
                   1084: =item &make_form_data_persistent() 
                   1085: 
                   1086: Inputs: filename of persistent database.
                   1087: 
                   1088: Store most form variables away to the %persistent_db.
                   1089: Values will be escaped.  Values that are array pointers will have their
1.205     www      1090: elements escaped and concatenated in a comma separated string.  
1.146     matthew  1091: 
                   1092: =cut
                   1093: 
                   1094: ######################################################################
                   1095: ######################################################################
                   1096: sub make_form_data_persistent {
                   1097:     my $r = shift;
                   1098:     my $filename = shift;
                   1099:     my %save;
1.243     albertel 1100:     foreach (keys(%env)) {
1.150     matthew  1101:         next if (!/^form/ || /submit/);
1.243     albertel 1102:         $save{$_} = $env{$_};
1.146     matthew  1103:     }
1.152     matthew  1104:     return &make_persistent(\%save,$filename);
1.98      harris41 1105: }
                   1106: 
1.122     matthew  1107: ######################################################################
                   1108: ######################################################################
                   1109: 
                   1110: =pod 
                   1111: 
1.134     matthew  1112: =item &parse_advanced_search()
                   1113: 
                   1114: Parse advanced search form and return the following:
                   1115: 
                   1116: =over 4
                   1117: 
                   1118: =item $query Scalar containing an SQL query.
1.126     matthew  1119: 
1.134     matthew  1120: =item $customquery Scalar containing a custom query.
                   1121: 
                   1122: =item $customshow Scalar containing commands to show custom metadata.
                   1123: 
                   1124: =item $libraries_to_query Reference to array of domains to search.
                   1125: 
                   1126: =back
1.122     matthew  1127: 
                   1128: =cut
                   1129: 
                   1130: ######################################################################
                   1131: ######################################################################
1.134     matthew  1132: sub parse_advanced_search {
1.196     matthew  1133:     my ($r,$closebutton,$hidden_fields)=@_;
1.216     matthew  1134:     my @BasicFields = ('title','author','subject','keywords','url','version',
1.227     matthew  1135:                        'notes','abstract','extension','owner','authorspace',
1.216     matthew  1136: #                       'custommetadata','customshow',
                   1137:                        'modifyinguser','standards','mime');
1.222     matthew  1138:     my @StatsFields = &statfields();
                   1139:     my @EvalFields = &evalfields();
1.32      harris41 1140:     my $fillflag=0;
1.230     matthew  1141:     my $pretty_search_string = "";
1.64      harris41 1142:     # Clean up fields for safety
1.216     matthew  1143:     for my $field (@BasicFields,
                   1144:                    'creationdatestart_month','creationdatestart_day',
1.64      harris41 1145: 		   'creationdatestart_year','creationdateend_month',
                   1146: 		   'creationdateend_day','creationdateend_year',
                   1147: 		   'lastrevisiondatestart_month','lastrevisiondatestart_day',
                   1148: 		   'lastrevisiondatestart_year','lastrevisiondateend_month',
1.216     matthew  1149: 		   'lastrevisiondateend_day','lastrevisiondateend_year') {
1.300     raeburn  1150: 	$env{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\'.\*]//g;
1.64      harris41 1151:     }
1.117     matthew  1152:     foreach ('mode','form','element') {
                   1153: 	# is this required?  Hmmm.
1.243     albertel 1154: 	next if (! exists($env{'form.'.$_}));
1.265     www      1155: 	$env{'form.'.$_}=&unescape($env{'form.'.$_});
1.243     albertel 1156: 	$env{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g;
1.117     matthew  1157:     }
1.131     matthew  1158:     # Preprocess the category form element.
1.243     albertel 1159:     $env{'form.category'} = 'any' if (! defined($env{'form.category'}) ||
                   1160:                                       ref($env{'form.category'}));
1.161     matthew  1161:     #
1.90      harris41 1162:     # Check to see if enough information was filled in
1.222     matthew  1163:     foreach my $field (@BasicFields) {
1.243     albertel 1164: 	if (&filled($env{'form.'.$field})) {
1.32      harris41 1165: 	    $fillflag++;
                   1166: 	}
                   1167:     }
1.222     matthew  1168:     foreach my $field (@StatsFields,@EvalFields) {
1.243     albertel 1169:         if (&filled($env{'form.'.$field.'_max'})) {
1.222     matthew  1170:             $fillflag++;
                   1171:         }
1.243     albertel 1172:         if (&filled($env{'form.'.$field.'_min'})) {
1.222     matthew  1173:             $fillflag++;
                   1174:         }
                   1175:     }
                   1176: 
1.216     matthew  1177:     for my $field ('lowestgradelevel','highestgradelevel') {
1.243     albertel 1178:         if ( $env{'form.'.$field} =~ /^\d+$/ &&
                   1179:              $env{'form.'.$field} > 0) {
1.216     matthew  1180:             $fillflag++;
                   1181:         }
                   1182:     }
1.279     raeburn  1183:     if ($env{'form.area'} eq 'portfolio') {
                   1184:         # Added metadata fields
                   1185:         for (my $i=0; $i<$env{'form.numaddedfields'} ; $i++) {
                   1186:             my $field = $env{'form.addedfield_'.$i};
                   1187:             $field =~ s/^\s*(\S*)\s*$/$1/;
                   1188:             $field =~ s/\W/_/g;
                   1189:             if ($field ne '') {
                   1190:                 $fillflag++;
                   1191:             }
                   1192:         }
                   1193:     }
1.212     matthew  1194:     if (! $fillflag) {
1.204     matthew  1195: 	&output_blank_field_error($r,$closebutton,
                   1196:                                   'phase=disp_adv',$hidden_fields);
1.134     matthew  1197: 	return ;
1.32      harris41 1198:     }
1.90      harris41 1199:     # Turn the form input into a SQL-based query
1.39      harris41 1200:     my $query='';
1.45      harris41 1201:     my @queries;
1.143     matthew  1202:     my $font = '<font color="#800000" face="helvetica">';
1.90      harris41 1203:     # Evaluate logical expression AND/OR/NOT phrase fields.
1.216     matthew  1204:     foreach my $field (@BasicFields) {
1.243     albertel 1205: 	next if (!defined($env{'form.'.$field}) || $env{'form.'.$field} eq '');
1.228     matthew  1206:         my ($error,$SQLQuery) = 
1.243     albertel 1207:             &process_phrase_input($env{'form.'.$field},
                   1208:                                   $env{'form.'.$field.'_related'},$field);
1.228     matthew  1209:         if (defined($error)) {
                   1210:             &output_unparsed_phrase_error($r,$closebutton,'phase=disp_adv',
                   1211:                                          $hidden_fields,$field);
                   1212:             return;
                   1213:         } else {
                   1214:             $pretty_search_string .= 
1.243     albertel 1215:                 $font.$field.'</font>: '.$env{'form.'.$field};
                   1216:             if ($env{'form.'.$field.'_related'}) {
1.228     matthew  1217:                 my @Words = 
                   1218:                     &Apache::loncommon::get_related_words
1.243     albertel 1219:                     ($env{'form.'.$field});
1.228     matthew  1220:                 if (@Words) {
                   1221:                     $pretty_search_string.= ' with related words: '.
                   1222:                         join(', ',@Words[0..4]);
1.143     matthew  1223:                 } else {
1.228     matthew  1224:                     $pretty_search_string.= ' with related words.';
1.143     matthew  1225:                 }
1.142     matthew  1226:             }
1.228     matthew  1227:             $pretty_search_string .= '<br />';
                   1228:             push (@queries,$SQLQuery);
1.131     matthew  1229:         }
1.44      harris41 1230:     }
1.161     matthew  1231:     #
                   1232:     # Make the 'mime' from 'form.category' and 'form.extension'
                   1233:     #
                   1234:     my $searchphrase;
1.243     albertel 1235:     if (exists($env{'form.category'})    && 
                   1236:         $env{'form.category'} !~ /^\s*$/ &&
                   1237:         $env{'form.category'} ne 'any')     {
1.161     matthew  1238:         my @extensions = &Apache::loncommon::filecategorytypes
1.243     albertel 1239:                                                    ($env{'form.category'});
1.161     matthew  1240:         if (scalar(@extensions) > 0) {
                   1241:             $searchphrase = join(' OR ',@extensions);
                   1242:         }
                   1243:     }
                   1244:     if (defined($searchphrase)) {
1.228     matthew  1245:         my ($error,$SQLsearch) = &process_phrase_input($searchphrase,0,'mime');
                   1246:         push @queries,$SQLsearch;
1.161     matthew  1247:         $pretty_search_string .=$font.'mime</font> contains <b>'.
                   1248:             $searchphrase.'</b><br />';
1.135     matthew  1249:     }
1.204     matthew  1250:     #
1.90      harris41 1251:     # Evaluate option lists
1.243     albertel 1252:     if ($env{'form.lowestgradelevel'}        &&
                   1253:         $env{'form.lowestgradelevel'} ne '0' &&
                   1254:         $env{'form.lowestgradelevel'} =~ /^\d+$/) {
1.216     matthew  1255: 	push(@queries,
1.243     albertel 1256:              '(lowestgradelevel>='.$env{'form.lowestgradelevel'}.')');
1.216     matthew  1257:         $pretty_search_string.="lowestgradelevel>=".
1.243     albertel 1258:             $env{'form.lowestgradelevel'}."<br />\n";
1.216     matthew  1259:     }
1.243     albertel 1260:     if ($env{'form.highestgradelevel'}        &&
                   1261:         $env{'form.highestgradelevel'} ne '0' &&
                   1262:         $env{'form.highestgradelevel'} =~ /^\d+$/) {
1.216     matthew  1263: 	push(@queries,
1.243     albertel 1264:              '(highestgradelevel<='.$env{'form.highestgradelevel'}.')');
1.216     matthew  1265:         $pretty_search_string.="highestgradelevel<=".
1.243     albertel 1266:             $env{'form.highestgradelevel'}."<br />\n";
1.216     matthew  1267:     }
1.243     albertel 1268:     if ($env{'form.language'} and $env{'form.language'} ne 'any') {
                   1269: 	push @queries,"(language like \"$env{'form.language'}\")";
1.143     matthew  1270:         $pretty_search_string.=$font."language</font>= ".
1.243     albertel 1271:             &Apache::loncommon::languagedescription($env{'form.language'}).
1.143     matthew  1272:                 "<br />\n";
1.58      harris41 1273:     }
1.243     albertel 1274:     if ($env{'form.copyright'} and $env{'form.copyright'} ne 'any') {
                   1275: 	push @queries,"(copyright like \"$env{'form.copyright'}\")";
1.143     matthew  1276:         $pretty_search_string.=$font."copyright</font> = ".
1.243     albertel 1277:             &Apache::loncommon::copyrightdescription($env{'form.copyright'}).
1.230     matthew  1278:                 "<br />\n";
1.58      harris41 1279:     }
1.276     raeburn  1280:     if ($env{'form.area'} eq 'portfolio') {
                   1281:         #
                   1282:         # Added metadata fields
                   1283:         for (my $i=0; $i<$env{'form.numaddedfields'} ; $i++) {
1.279     raeburn  1284:             my $field = $env{'form.addedfield_'.$i};
                   1285:             $field =~ s/^\s*(\S*)\s*$/$1/;
                   1286:             $field =~ s/\W/_/g;
                   1287:             $field =~ tr/A-Z/a-z/; 
                   1288:             if ($field ne '') {
                   1289:                 my $value = $env{'form.addedvalues_'.$i};
                   1290:                 if ($value ne '') {
1.280     albertel 1291:                     $value =~ s/'/''/g; #' stupid emacs
1.279     raeburn  1292:                     my ($error,$query) = 
                   1293:                         &process_phrase_input($value,0,'pf.value');
                   1294:                     if (!defined($error)) {
                   1295:                         push(@queries,"pf.field = '$field' AND $query");
                   1296:                         $pretty_search_string .=
                   1297:                             $font.$field.'</font>: '.
                   1298:                             $env{'form.addedvalues_'.$i}.'<br />';
                   1299:                     }
                   1300:                 } else {
                   1301:                     push(@queries,"pf.field = '$field' AND pf.value IS NULL");
                   1302:                 }
1.276     raeburn  1303:             }
                   1304:         }
                   1305:     } else {
                   1306:         #
                   1307:         # Statistics
                   1308:         foreach my $field (@StatsFields,@EvalFields) {
                   1309:             my ($min,$max);
                   1310:             if (exists($env{'form.'.$field.'_min'}) && 
                   1311:                 $env{'form.'.$field.'_min'} ne '') {
                   1312:                 $min = $env{'form.'.$field.'_min'};
                   1313:             }
                   1314:             if (exists($env{'form.'.$field.'_max'}) &&
                   1315:                 $env{'form.'.$field.'_max'} ne '') {
                   1316:                 $max = $env{'form.'.$field.'_max'};
                   1317:             }
                   1318:             next if (! defined($max) && ! defined($min));
                   1319:             if (defined($min) && defined($max)) {
                   1320:                 ($min,$max) = sort {$a <=>$b} ($min,$max);
                   1321:             }
                   1322:             if (defined($min) && $min =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
                   1323:                 push(@queries,'('.$field.'>'.$min.')');
                   1324:                 $pretty_search_string.=$font.$field.'</font>&gt;'.$min.'<br />';
                   1325:             }
                   1326:             if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
                   1327:                 push(@queries,'('.$field.'<'.$max.')');
                   1328:                 $pretty_search_string.=$font.$field.'</font>&lt;'.$max.'<br />';
                   1329:             }
1.217     matthew  1330:         }
                   1331:     }
                   1332:     #
1.90      harris41 1333:     # Evaluate date windows
1.216     matthew  1334:     my $cafter =
                   1335:         &Apache::lonhtmlcommon::get_date_from_form('creationdate1');
                   1336:     my $cbefore = 
                   1337:         &Apache::lonhtmlcommon::get_date_from_form('creationdate2');
                   1338:     if ($cafter > $cbefore) {
                   1339:         my $tmp = $cafter;
                   1340:         $cafter = $cbefore;
                   1341:         $cbefore = $tmp;
                   1342:     }
                   1343:     my $mafter = 
                   1344:         &Apache::lonhtmlcommon::get_date_from_form('revisiondate1');
                   1345:     my $mbefore =
                   1346:         &Apache::lonhtmlcommon::get_date_from_form('revisiondate2');
                   1347:     if ($mafter > $mbefore) {
                   1348:         my $tmp = $mafter;
                   1349:         $mafter = $mbefore;
                   1350:         $mbefore = $tmp;
                   1351:     }
                   1352:     my ($datequery,$error,$prettydate)=&build_date_queries($cafter,$cbefore,
                   1353:                                                            $mafter,$mbefore);
                   1354:     if (defined($error)) {
                   1355:         &output_date_error($r,$error,$closebutton,$hidden_fields);
                   1356:     } elsif (defined($datequery)) {
1.143     matthew  1357:         # Here is where you would set up pretty_search_string to output
                   1358:         # date query information.
1.216     matthew  1359:         $pretty_search_string .= '<br />'.$prettydate.'<br />';
1.60      harris41 1360: 	push @queries,$datequery;
                   1361:     }
1.204     matthew  1362:     #
1.90      harris41 1363:     # Process form information for custom metadata querying
1.134     matthew  1364:     my $customquery=undef;
1.204     matthew  1365:     ##
                   1366:     ## The custom metadata search was removed q long time ago mostly 
                   1367:     ## because I was unable to figureout exactly how it worked and could
                   1368:     ## not imagine people actually using it.  MH
                   1369:     ##
1.243     albertel 1370:     # if ($env{'form.custommetadata'}) {
1.204     matthew  1371:     #    $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".
1.243     albertel 1372:     #    $env{'form.custommetadata'}."</b><br />\n";
1.204     matthew  1373:     #    $customquery=&build_custommetadata_query('custommetadata',
1.243     albertel 1374:     #                                             $env{'form.custommetadata'});
1.204     matthew  1375:     # }
1.134     matthew  1376:     my $customshow=undef;
1.243     albertel 1377:     # if ($env{'form.customshow'}) {
1.204     matthew  1378:     # $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".
1.243     albertel 1379:     #                         $env{'form.customshow'}."</b><br />\n";
                   1380:     #    $customshow=$env{'form.customshow'};
1.204     matthew  1381:     #    $customshow=~s/[^\w\s]//g;
                   1382:     #    my @fields=split(/\s+/,$customshow);
                   1383:     #    $customshow=join(" ",@fields);
                   1384:     # }
                   1385:     ##
1.132     matthew  1386:     ## Deal with restrictions to given domains
                   1387:     ## 
1.254     www      1388:     my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
                   1389:     if ($pretty_domains_string) {
1.251     www      1390:        $pretty_search_string .= $pretty_domains_string."<br />\n";
                   1391:     }
1.180     matthew  1392:     #
                   1393:     if (@queries) {
1.277     raeburn  1394:         if ($env{'form.area'} eq 'portfolio') {
1.300     raeburn  1395:             $query ="SELECT pm.*,pa.keynum,pa.scope FROM portfolio_metadata pm, portfolio_access pa, portfolio_addedfields pf WHERE (pm.url = pa.url AND pf.url = pm.url AND (pa.start < UTC_TIMESTAMP() AND (pa.end IS NULL OR pa.end > UTC_TIMESTAMP())) AND (".join(') AND (',@queries).'))';
1.277     raeburn  1396:         } else {
                   1397: 	    $query="SELECT * FROM metadata WHERE (".join(") AND (",@queries).')';
                   1398:         }
1.180     matthew  1399:     } elsif ($customquery) {
                   1400:         $query = '';
                   1401:     }
1.241     matthew  1402:     #&Apache::lonnet::logthis('advanced query = '.$/.$query);
1.180     matthew  1403:     return ($query,$customquery,$customshow,$libraries_to_query,
                   1404:             $pretty_search_string);
                   1405: }
                   1406: 
                   1407: sub parse_domain_restrictions {
1.132     matthew  1408:     my $libraries_to_query = undef;
1.243     albertel 1409:     # $env{'form.domains'} can be either a scalar or an array reference.
1.132     matthew  1410:     # We need an array.
1.243     albertel 1411:     if (! exists($env{'form.domains'}) || $env{'form.domains'} eq '') {
1.240     matthew  1412:         return (undef,'',undef);
1.180     matthew  1413:     }
1.245     albertel 1414:     my @allowed_domains = &Apache::loncommon::get_env_multiple('form.domains');
1.204     matthew  1415:     #
1.132     matthew  1416:     my %domain_hash = ();
1.143     matthew  1417:     my $pretty_domains_string;
1.132     matthew  1418:     foreach (@allowed_domains) {
                   1419:         $domain_hash{$_}++;
                   1420:     }
1.143     matthew  1421:     if ($domain_hash{'any'}) {
1.273     www      1422:         $pretty_domains_string = &mt("in all LON-CAPA domains.");
1.143     matthew  1423:     } else {
                   1424:         if (@allowed_domains > 1) {
1.273     www      1425:             $pretty_domains_string = &mt("in LON-CAPA domains:");
1.143     matthew  1426:         } else {
1.273     www      1427:             $pretty_domains_string = &mt("in LON-CAPA domain ");
1.143     matthew  1428:         }
                   1429:         foreach (sort @allowed_domains) {
1.152     matthew  1430:             $pretty_domains_string .= "<b>".$_."</b> ";
1.132     matthew  1431:         }
1.322     droeschl 1432: 	my %servers = &Apache::lonnet::get_unique_servers(\@allowed_domains,
1.280     albertel 1433: 						   'library');
                   1434: 	$libraries_to_query = [keys(%servers)];
1.132     matthew  1435:     }
1.239     matthew  1436:     return ($libraries_to_query,
1.254     www      1437:             $pretty_domains_string);
1.18      harris41 1438: }
                   1439: 
1.122     matthew  1440: ######################################################################
                   1441: ######################################################################
                   1442: 
                   1443: =pod 
                   1444: 
1.134     matthew  1445: =item &parse_basic_search() 
1.122     matthew  1446: 
1.134     matthew  1447: Parse the basic search form and return a scalar containing an sql query.
1.126     matthew  1448: 
1.122     matthew  1449: =cut
                   1450: 
                   1451: ######################################################################
                   1452: ######################################################################
1.134     matthew  1453: sub parse_basic_search {
1.145     matthew  1454:     my ($r,$closebutton)=@_;
1.204     matthew  1455:     #
1.64      harris41 1456:     # Clean up fields for safety
                   1457:     for my $field ('basicexp') {
1.300     raeburn  1458: 	$env{"form.$field"}=~s/[^\w\s\'\"\!\(\)\-\*]//g;
1.64      harris41 1459:     }
1.117     matthew  1460:     foreach ('mode','form','element') {
                   1461: 	# is this required?  Hmmm.
1.243     albertel 1462: 	next unless (exists($env{"form.$_"}));
1.265     www      1463: 	$env{"form.$_"}=&unescape($env{"form.$_"});
1.243     albertel 1464: 	$env{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
1.117     matthew  1465:     }
1.254     www      1466:     my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
1.204     matthew  1467:     #
                   1468:     # Check to see if enough of a query is filled in
1.243     albertel 1469:     my $search_string = $env{'form.basicexp'};
1.220     matthew  1470:     if (! &filled($search_string)) {
1.151     matthew  1471: 	&output_blank_field_error($r,$closebutton,'phase=disp_basic');
1.24      harris41 1472: 	return OK;
                   1473:     }
1.228     matthew  1474:     my $pretty_search_string=$search_string;
1.224     matthew  1475:     my @Queries;
1.276     raeburn  1476:     my @fields = ('title','author','subject','notes','abstract','keywords');
                   1477:     my $searchfield;
                   1478:     if ($env{'form.area'} eq 'portfolio') {
                   1479:         $searchfield = 'concat_ws(" ",pm.'.join(',pm.',@fields).')';
                   1480:     } else {
                   1481:         $searchfield = 'concat_ws(" ",'.join(',',@fields).')';
                   1482:     }
1.228     matthew  1483:     my ($error,$SQLQuery) = &process_phrase_input($search_string,
1.243     albertel 1484:                                                     $env{'form.related'},
1.228     matthew  1485:                                                     $searchfield);
                   1486:     if ($error) {
                   1487:         &output_unparsed_phrase_error($r,$closebutton,'phase=disp_basic',
                   1488:                                       '','basicexp');
                   1489:         return;
1.141     matthew  1490:     }
1.228     matthew  1491:     push(@Queries,$SQLQuery);
                   1492:     #foreach my $q (@Queries) {
                   1493:     #    &Apache::lonnet::logthis('    '.$q);
                   1494:     #}
1.276     raeburn  1495:     my $final_query;
                   1496:     if ($env{'form.area'} eq 'portfolio') {
1.300     raeburn  1497:         $final_query = 'SELECT pm.*,pa.keynum,pa.scope FROM portfolio_metadata pm, portfolio_access pa  WHERE (pm.url = pa.url AND (pa.start < UTC_TIMESTAMP() AND (pa.end IS NULL OR pa.end > UTC_TIMESTAMP())) AND '.join(" AND ",@Queries).')';
1.276     raeburn  1498:     } else {
                   1499:         $final_query = 'SELECT * FROM metadata WHERE '.join(" AND ",@Queries);
                   1500:     }
1.204     matthew  1501:     #
1.273     www      1502:     if ($env{'form.related'}) {
                   1503: 	$pretty_search_string.=' '.&mt('(including related words)');
                   1504:     }
1.180     matthew  1505:     if (defined($pretty_domains_string) && $pretty_domains_string ne '') {
                   1506:         $pretty_search_string .= ' '.$pretty_domains_string;
                   1507:     }
1.143     matthew  1508:     $pretty_search_string .= "<br />\n";
1.225     matthew  1509:     $pretty_search_string =~ s:^<br /> and ::;
1.276     raeburn  1510:     &Apache::lonnet::logthis('simple search final query = '.$/.$final_query);
1.183     matthew  1511:     return ($final_query,$pretty_search_string,
1.180     matthew  1512:             $libraries_to_query);
1.22      harris41 1513: }
                   1514: 
1.228     matthew  1515: 
                   1516: ###############################################################
                   1517: ###############################################################
                   1518: 
                   1519: my @Phrases;
                   1520: 
                   1521: sub concat {
                   1522:     my ($item) = @_;
                   1523:     my $results = '';
                   1524:     foreach (@$item) {
                   1525:         if (ref($_) eq 'ARRAY') {
                   1526:             $results .= join(' ',@$_);
                   1527:         }
                   1528:     }
                   1529:     return $results;
                   1530: }
                   1531: 
1.224     matthew  1532: sub process_phrase_input {
1.228     matthew  1533:     my ($phrase,$related,$field)=@_;
                   1534:     #&Apache::lonnet::logthis('phrase = :'.$phrase.':');
                   1535:     my $grammar = <<'ENDGRAMMAR';
                   1536:     searchphrase:
                   1537:         expression /^\Z/ {
                   1538:             # &Apache::lonsearchcat::print_item(\@item,0);
                   1539:             [@item];
                   1540:         }
                   1541:     expression:
                   1542:         phrase(s)   {
                   1543:             [@item];
                   1544:         }
                   1545:     phrase:
                   1546:         orword {
                   1547:             [@item];
                   1548:         }
                   1549:       | andword {
                   1550:             [@item];
                   1551:         }
                   1552:       | minusword {
                   1553:             unshift(@::Phrases,$item[1]->[0]);
                   1554:             unshift(@::Phrases,$item[1]->[1]);
                   1555:             [@item];
                   1556:         }
                   1557:       | word {
                   1558:             unshift(@::Phrases,$item[1]);
                   1559:             [@item];
                   1560:         } 
                   1561:     #
                   1562:     orword:
                   1563:         word 'OR' phrase {
                   1564:             unshift(@::Phrases,'OR');
                   1565:             unshift(@::Phrases,$item[1]);
                   1566:             [@item];
                   1567:         }
                   1568:         | word 'or' phrase {
                   1569:             unshift(@::Phrases,'OR');
                   1570:             unshift(@::Phrases,$item[1]);
                   1571:             [@item];
                   1572:         }    
                   1573:         | minusword 'OR' phrase {
                   1574:             unshift(@::Phrases,'OR');
                   1575:             unshift(@::Phrases,$item[1]->[0]);
                   1576:             unshift(@::Phrases,$item[1]->[1]);
                   1577:             [@item];
                   1578:         }
                   1579:         | minusword 'or' phrase {
                   1580:             unshift(@::Phrases,'OR');
                   1581:             unshift(@::Phrases,$item[1]->[0]);
                   1582:             unshift(@::Phrases,$item[1]->[1]);
                   1583:             [@item];
                   1584:         }    
                   1585:     andword:
                   1586:         word phrase {
                   1587:             unshift(@::Phrases,'AND');
                   1588:             unshift(@::Phrases,$item[1]);
                   1589:             [@item];
                   1590:         }
                   1591:         | minusword phrase {
                   1592:             unshift(@::Phrases,'AND');
                   1593:             unshift(@::Phrases,$item[1]->[0]);
                   1594:             unshift(@::Phrases,$item[1]->[1]);
                   1595:             [@item];
                   1596:         }
                   1597:     #
                   1598:     minusword:
                   1599:         '-' word {
                   1600:             [$item[2],'NOT'];
                   1601:         }
                   1602:     word:
                   1603:         "'" term(s) "'" {
                   1604:           &Apache::lonsearchcat::concat(\@item);
                   1605:         }
                   1606:       | '"' term(s) '"' {
                   1607:           &Apache::lonsearchcat::concat(\@item);
                   1608:         }
                   1609:       | term {
                   1610:             $item[1];
                   1611:         }
                   1612:     term:
1.284     albertel 1613:         /[\w\Q:!@#$%^&*()+_=|{}<>,.;\\\/?\E\-]+/ {
1.228     matthew  1614:             $item[1];
                   1615:         }
                   1616: ENDGRAMMAR
                   1617:     #
                   1618:     # The end result of parsing the phrase with the grammar is an array
                   1619:     # @::Phrases.
                   1620:     # $phrase = "gene splicing" or cat -> "gene splicing","OR","cat"
                   1621:     # $phrase = "genetic engineering" -dna ->
                   1622:     #                      "genetic engineering","AND","NOT","dna"
                   1623:     # $phrase = cat or dog -poodle -> "cat","OR","dog","AND","NOT","poodle"
                   1624:     undef(@::Phrases);
                   1625:     my $p = new Parse::RecDescent($grammar);
                   1626:     if (! defined($p->searchphrase($phrase))) {
                   1627:         &Apache::lonnet::logthis('lonsearchcat:unable to process:'.$phrase);
                   1628:         return 'Unable to process phrase '.$phrase;
                   1629:     }
                   1630:     #
                   1631:     # Go through the phrases and make sense of them.  
                   1632:     # Apply modifiers NOT OR and AND to the phrases.
                   1633:     my @NewPhrases;
                   1634:     while(@::Phrases) {
                   1635:         my $phrase = shift(@::Phrases);
                   1636:         # &Apache::lonnet::logthis('phrase = '.$phrase);
                   1637:         my $phrasedata;
                   1638:         if ($phrase =~ /^(NOT|OR|AND)$/) {
                   1639:             if ($phrase eq 'OR') {
                   1640:                 $phrasedata->{'or'}++;
                   1641:                 if (! @::Phrases) { $phrasedata = undef; last; }
                   1642:                 $phrase = shift(@::Phrases);
                   1643:             } elsif ($phrase eq 'AND') {
                   1644:                 $phrasedata->{'and'}++;
                   1645:                 if (! @::Phrases) { $phrasedata = undef; last; }
                   1646:                 $phrase = shift(@::Phrases);
1.224     matthew  1647:             }
1.228     matthew  1648:             if ($phrase eq 'NOT') {
                   1649:                 $phrasedata->{'negate'}++;
                   1650:                 if (! @::Phrases) { $phrasedata = undef; last; }
                   1651:                 $phrase = shift(@::Phrases);
1.224     matthew  1652:             }
1.228     matthew  1653:         }
                   1654:         $phrasedata->{'phrase'} = $phrase;
                   1655:         if ($related) {
                   1656:             my @NewWords;
                   1657:             (undef,@NewWords) = &related_version($phrasedata->{'phrase'});
                   1658:             $phrasedata->{'related_words'} = \@NewWords;
                   1659:         }
                   1660:         push(@NewPhrases,$phrasedata);
                   1661:     }
                   1662:     #
                   1663:     # Actually build the sql query from the phrases
                   1664:     my $SQLQuery;
                   1665:     foreach my $phrase (@NewPhrases) {
                   1666:         my $query;
                   1667:         if ($phrase->{'negate'}) {
                   1668:             $query .= $field.' NOT LIKE "%'.$phrase->{'phrase'}.'%"';
1.224     matthew  1669:         } else {
1.228     matthew  1670:             $query .= $field.' LIKE "%'.$phrase->{'phrase'}.'%"';
                   1671:         }
                   1672:         foreach my $related (@{$phrase->{'related_words'}}) {
                   1673:             if ($phrase->{'negate'}) {
                   1674:                 $query .= ' AND '.$field.' NOT LIKE "%'.$related.'%"';
                   1675:             } else {
                   1676:                 $query .= ' OR '.$field.' LIKE "%'.$related.'%"';
                   1677:             }
                   1678:         }
                   1679:         if ($SQLQuery) {
                   1680:             if ($phrase->{'or'}) {
                   1681:                 $SQLQuery .= ' OR ('.$query.')';
                   1682:             } else {
                   1683:                 $SQLQuery .= ' AND ('.$query.')';
1.224     matthew  1684:             }
1.228     matthew  1685:         } else {
                   1686:             $SQLQuery = '('.$query.')';
1.224     matthew  1687:         }
                   1688:     }
                   1689:     #
1.228     matthew  1690:     # &Apache::lonnet::logthis("SQLQuery = $SQLQuery");
1.224     matthew  1691:     #
1.228     matthew  1692:     return undef,$SQLQuery;
1.224     matthew  1693: }
                   1694: 
1.122     matthew  1695: ######################################################################
                   1696: ######################################################################
                   1697: 
                   1698: =pod 
                   1699: 
1.204     matthew  1700: =item &related_version()
1.142     matthew  1701: 
                   1702: Modifies an input string to include related words.  Words in the string
                   1703: are replaced with parenthesized lists of 'OR'd words.  For example
                   1704: "torque" is replaced with "(torque OR word1 OR word2 OR ...)".  
                   1705: 
                   1706: Note: Using this twice on a string is probably silly.
                   1707: 
                   1708: =cut
                   1709: 
                   1710: ######################################################################
                   1711: ######################################################################
                   1712: sub related_version {
1.224     matthew  1713:     my ($word) = @_;
                   1714:     return (undef) if (lc($word) =~ /\b(or|and|not)\b/);
                   1715:     my @Words = &Apache::loncommon::get_related_words($word);
                   1716:     # Only use 4 related words
                   1717:     @Words = ($#Words>4? @Words[0..4] : @Words);
                   1718:     my $result = join " OR ", ($word,@Words);
                   1719:     return $result,sort(@Words);
1.142     matthew  1720: }
                   1721: 
1.98      harris41 1722: 
1.122     matthew  1723: ######################################################################
                   1724: ######################################################################
                   1725: 
                   1726: =pod 
                   1727: 
                   1728: =item &build_custommetadata_query() 
                   1729: 
1.126     matthew  1730: Constructs a custom metadata query using a rather heinous regular
                   1731: expression.
                   1732: 
1.122     matthew  1733: =cut
                   1734: 
                   1735: ######################################################################
                   1736: ######################################################################
1.98      harris41 1737: sub build_custommetadata_query {
                   1738:     my ($field_name,$logic_statement)=@_;
                   1739:     my $q=new Text::Query('abc',
                   1740: 			  -parse => 'Text::Query::ParseAdvanced',
                   1741: 			  -build => 'Text::Query::BuildAdvancedString');
                   1742:     $q->prepare($logic_statement);
                   1743:     my $matchexp=${$q}{'-parse'}{'-build'}{'matchstring'};
                   1744:     # quick fix to change literal into xml tag-matching
                   1745:     # will eventually have to write a separate builder module
1.122     matthew  1746:     # wordone=wordtwo becomes\<wordone\>[^\<] *wordtwo[^\<]*\<\/wordone\>
                   1747:     $matchexp =~ s/(\w+)\\=([\w\\\+]+)?# wordone=wordtwo is changed to 
                   1748:                  /\\<$1\\>?#           \<wordone\>
                   1749:                    \[\^\\<\]?#        [^\<]         
                   1750:                    \*$2\[\^\\<\]?#           *wordtwo[^\<]
                   1751:                    \*\\<\\\/$1\\>?#                        *\<\/wordone\>
                   1752:                    /g;
1.98      harris41 1753:     return $matchexp;
                   1754: }
                   1755: 
1.22      harris41 1756: 
1.122     matthew  1757: ######################################################################
                   1758: ######################################################################
                   1759: 
                   1760: =pod 
                   1761: 
                   1762: =item &build_date_queries() 
                   1763: 
1.126     matthew  1764: Builds a SQL logic query to check time/date entries.
                   1765: Also reports errors (check for /^Incorrect/).
                   1766: 
1.122     matthew  1767: =cut
                   1768: 
                   1769: ######################################################################
                   1770: ######################################################################
1.98      harris41 1771: sub build_date_queries {
1.216     matthew  1772:     my ($cafter,$cbefore,$mafter,$mbefore) = @_;
                   1773:     my ($result,$error,$pretty_string);
                   1774:     #
                   1775:     # Verify the input
                   1776:     if (! defined($cafter) && ! defined($cbefore) &&
                   1777:         ! defined($mafter) && ! defined($mbefore)) {
                   1778:         # This is an okay situation, so return undef for the error
                   1779:         return (undef,undef,undef);
                   1780:     }
                   1781:     if ((defined($cafter)  && ! defined($cbefore)) ||
                   1782:         (defined($cbefore) && ! defined($cafter))) {
                   1783:         # This is bad, so let them know
1.333   ! raeburn  1784:         $error = &mt('Incorrect entry for the creation date. '.
1.216     matthew  1785:                     'You must specify both the beginning and ending dates.');
                   1786:     }
                   1787:     if (! defined($error) && 
                   1788:         ((defined($mafter)  && ! defined($mbefore)) ||
                   1789:         (defined($mbefore) && ! defined($mafter)))) {
                   1790:         # This is also bad, so let them know
1.333   ! raeburn  1791:         $error = &mt('Incorrect entry for the last revision date. '.
1.216     matthew  1792:                      'You must specify both the beginning and ending dates.');
1.98      harris41 1793:     }
1.216     matthew  1794:     if (! defined($error)) {
                   1795:         #
                   1796:         # Build the queries
                   1797:         my @queries;
                   1798:         if (defined($cbefore) && defined($cafter)) {
                   1799:             my (undef,undef,undef,$caday,$camon,$cayear) = localtime($cafter);
                   1800:             my (undef,undef,undef,$cbday,$cbmon,$cbyear) = localtime($cbefore);
                   1801:             # Correct for year being relative to 1900
                   1802:             $cayear+=1900; $cbyear+=1900;
                   1803:             my $cquery=
                   1804:                 '(creationdate BETWEEN '.
                   1805:                 "'".$cayear.'-'.$camon.'-'.$caday."'".
                   1806:                 ' AND '.
                   1807:                 "'".$cbyear.'-'.$cbmon.'-'.$cbday." 23:59:59')";
                   1808:             $pretty_string .= '<br />' if (defined($pretty_string));
                   1809:             $pretty_string .= 
                   1810:                 &mt('created between [_1] and [_2]',
                   1811:                     &Apache::lonlocal::locallocaltime($cafter),
                   1812:                     &Apache::lonlocal::locallocaltime($cbefore+24*60*60-1));
                   1813:             push(@queries,$cquery);
                   1814:             $pretty_string =~ s/ 00:00:00//g;
                   1815:         }
                   1816:         if (defined($mbefore) && defined($mafter)) {
                   1817:             my (undef,undef,undef,$maday,$mamon,$mayear) = localtime($mafter);
                   1818:             my (undef,undef,undef,$mbday,$mbmon,$mbyear) = localtime($mbefore);
                   1819:             # Correct for year being relative to 1900
                   1820:             $mayear+=1900; $mbyear+=1900;
                   1821:             my $mquery=
                   1822:                 '(lastrevisiondate BETWEEN '.
                   1823:                 "'".$mayear.'-'.$mamon.'-'.$maday."'".
                   1824:                 ' AND '.
                   1825:                 "'".$mbyear.'-'.$mbmon.'-'.$mbday." 23:59:59')";
                   1826:             push(@queries,$mquery);
                   1827:             $pretty_string .= '<br />' if (defined($pretty_string));
                   1828:             $pretty_string .= 
                   1829:                 &mt('last revised between [_1] and [_2]',
                   1830:                     &Apache::lonlocal::locallocaltime($mafter),
                   1831:                     &Apache::lonlocal::locallocaltime($mbefore+24*60*60-1));
                   1832:             $pretty_string =~ s/ 00:00:00//g;
                   1833:         }
                   1834:         if (@queries) {
                   1835:             $result .= join(" AND ",@queries);
                   1836:         }
1.98      harris41 1837:     }
1.216     matthew  1838:     return ($result,$error,$pretty_string);
1.18      harris41 1839: }
1.6       harris41 1840: 
1.122     matthew  1841: ######################################################################
                   1842: ######################################################################
                   1843: 
1.144     matthew  1844: =pod
                   1845: 
                   1846: =item &copyright_check()
                   1847: 
1.204     matthew  1848: Inputs: $Metadata, a hash pointer of metadata for a resource.
                   1849: 
                   1850: Returns: 1 if the resource is available to the user making the query, 
                   1851:          0 otherwise.
                   1852: 
1.144     matthew  1853: =cut
                   1854: 
                   1855: ######################################################################
                   1856: ######################################################################
                   1857: sub copyright_check {
                   1858:     my $Metadata = shift;
                   1859:     # Check copyright tags and skip results the user cannot use
                   1860:     my (undef,undef,$resdom,$resname) = split('/',
                   1861:                                               $Metadata->{'url'});
                   1862:     # Check for priv
                   1863:     if (($Metadata->{'copyright'} eq 'priv') && 
1.243     albertel 1864:         (($env{'user.name'} ne $resname) &&
                   1865:          ($env{'user.domain'} ne $resdom))) {
1.144     matthew  1866:         return 0;
                   1867:     }
                   1868:     # Check for domain
                   1869:     if (($Metadata->{'copyright'} eq 'domain') &&
1.243     albertel 1870:         ($env{'user.domain'} ne $resdom)) {
1.144     matthew  1871:         return 0;
                   1872:     }
1.294     www      1873:     # Check for custom rights
                   1874:     if ($Metadata->{'copyright'} eq 'custom') {
1.296     raeburn  1875:        return &Apache::lonnet::customaccess('bre',$Metadata->{'url'});
1.294     www      1876:     }
1.144     matthew  1877:     return 1;
                   1878: }
                   1879: 
1.151     matthew  1880: ######################################################################
                   1881: ######################################################################
                   1882: 
                   1883: =pod
                   1884: 
1.204     matthew  1885: =item &ensure_db_and_table()
1.151     matthew  1886: 
                   1887: Ensure we can get lonmysql to connect to the database and the table we
                   1888: need exists.
                   1889: 
                   1890: Inputs: $r, table id
                   1891: 
                   1892: Returns: undef on error, 1 if the table exists.
                   1893: 
                   1894: =cut
                   1895: 
                   1896: ######################################################################
                   1897: ######################################################################
                   1898: sub ensure_db_and_table {
                   1899:     my ($r,$table) = @_;
                   1900:     ##
                   1901:     ## Sanity check the table id.
                   1902:     ##
                   1903:     if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
1.313     bisitz   1904:         $r->print(&Apache::loncommon::start_page(&mt('Error'))
                   1905: . '<p>table: |'.$table.'|</p>' # SB
                   1906:                  .'<p class="LC_error">'
                   1907:                  .&mt('Unable to retrieve search results. '
                   1908:                      .'Unable to determine the table results were saved in.')
                   1909:                  .&Apache::loncommon::end_page()
                   1910:         );
1.151     matthew  1911:         return undef;
                   1912:     }
                   1913:     ##
                   1914:     ## Make sure we can connect and the table exists.
                   1915:     ##
                   1916:     my $connection_result = &Apache::lonmysql::connect_to_db();
                   1917:     if (!defined($connection_result)) {
1.332     bisitz   1918:         $r->print(
                   1919:             '<p class="LC_error">'
                   1920:            .&mt('Unable to connect to the MySQL database where your results are saved.')
                   1921:            .'</p>'
                   1922:            .&Apache::loncommon::end_page()
                   1923:         );
1.151     matthew  1924:         &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".
                   1925:                                  " connect to database.");
                   1926:         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
                   1927:         return undef;
                   1928:     }
                   1929:     my $table_check = &Apache::lonmysql::check_table($table);
                   1930:     if (! defined($table_check)) {
1.332     bisitz   1931:         $r->print(
                   1932:             '<p class="LC_error">'
                   1933:            .&mt('A MySQL error has occurred.')
                   1934:            .'</p></form>'
                   1935:            .&Apache::loncommon::end_page());
1.151     matthew  1936:         &Apache::lonnet::logthis("lonmysql was unable to determine the status".
                   1937:                                  " of table ".$table);
                   1938:         return undef;
                   1939:     } elsif (! $table_check) {
1.332     bisitz   1940:         $r->print(
                   1941:             '<p class="LC_error">'
                   1942:            .&mt('The table of results could not be found.')
                   1943:            .'</p>'
                   1944:         );
1.151     matthew  1945:         &Apache::lonnet::logthis("The user requested a table, ".$table.
                   1946:                                  ", that could not be found.");
                   1947:         return undef;
                   1948:     }
                   1949:     return 1;
                   1950: }
                   1951: 
                   1952: ######################################################################
                   1953: ######################################################################
                   1954: 
                   1955: =pod
                   1956: 
1.204     matthew  1957: =item &print_sort_form()
                   1958: 
                   1959: The sort feature is not implemented at this time.  This form just prints 
                   1960: a link to change the search query.
1.151     matthew  1961: 
                   1962: =cut
                   1963: 
                   1964: ######################################################################
                   1965: ######################################################################
                   1966: sub print_sort_form {
                   1967:     my ($r,$pretty_query_string) = @_;
1.224     matthew  1968: 
1.151     matthew  1969:     ##
1.187     www      1970:     my %SortableFields=&Apache::lonlocal::texthash( 
                   1971:          id        => 'Default',
1.151     matthew  1972:          title     => 'Title',
                   1973:          author    => 'Author',
                   1974:          subject   => 'Subject',
                   1975:          url       => 'URL',
                   1976:          version   => 'Version Number',
                   1977:          mime      => 'Mime type',
                   1978:          lang      => 'Language',
                   1979:          owner     => 'Owner/Publisher',
                   1980:          copyright => 'Copyright',
                   1981:          hostname  => 'Host',
                   1982:          creationdate     => 'Creation Date',
1.187     www      1983:          lastrevisiondate => 'Revision Date'
1.151     matthew  1984:      );
                   1985:     ##
1.243     albertel 1986:     my $table = $env{'form.table'};
1.151     matthew  1987:     return if (! &ensure_db_and_table($r,$table));
                   1988:     ##
                   1989:     ## Get the number of results 
                   1990:     ##
                   1991:     my $total_results = &Apache::lonmysql::number_of_rows($table);
                   1992:     if (! defined($total_results)) {
1.256     albertel 1993:         $r->print("A MySQL error has occurred.</form>".
                   1994: 		  &Apache::loncommon::end_page());
1.151     matthew  1995:         &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                   1996:                                  " of rows in table ".$table);
                   1997:         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
                   1998:         return;
                   1999:     }
1.257     albertel 2000:     my $js =<<END;
                   2001: <script type="text/javascript">
1.313     bisitz   2002: // <![CDATA[
1.151     matthew  2003:     function change_sort() {
                   2004:         var newloc = "/adm/searchcat?phase=results";
1.323     bisitz   2005:         newloc += "&persistent_db_id=$env{'form.persistent_db_id'}";
                   2006:         newloc += "&sortby=";
1.151     matthew  2007:         newloc += document.forms.statusform.elements.sortby.value;
                   2008:         parent.resultsframe.location= newloc;
                   2009:     }
1.313     bisitz   2010: // ]]>
1.151     matthew  2011: </script>
1.257     albertel 2012: END
                   2013: 
1.307     bisitz   2014:     my $start_page = &Apache::loncommon::start_page('Results',$js);
1.257     albertel 2015:     my $breadcrumbs=
1.263     albertel 2016:         &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
1.267     www      2017: 					    $env{'form.catalogmode'} ne 'import');
1.257     albertel 2018: 
                   2019:     my $result = <<END;
                   2020: $start_page
                   2021: $breadcrumbs
1.267     www      2022: <form name="statusform" action="" method="post" target="_top">
1.268     www      2023: <input type="hidden" name="catalogmode" value="import" />
1.270     www      2024: <input type="hidden" name="acts" value="" />
1.151     matthew  2025: END
                   2026: 
                   2027: #<h2>Sort Results</h2>
                   2028: #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">
1.243     albertel 2029: #    $env{'form.sortby'} = 'id' if (! defined($env{'form.sortby'}));
1.151     matthew  2030: #    foreach (keys(%SortableFields)) {
                   2031: #        $result.="<option name=\"$_\"";
1.243     albertel 2032: #        if ($_ eq $env{'form.sortby'}) {
1.151     matthew  2033: #            $result.=" selected ";
                   2034: #        }
                   2035: #        $result.=" >$SortableFields{$_}</option>\n";
                   2036: #    }
                   2037: #    $result.="</select>\n";
                   2038:     my $revise = &revise_button();
1.289     bisitz   2039:     $result.='<p>'
                   2040:             .&mt('There are [_1] matches to your query.',$total_results)
                   2041:             .' '.$revise.'</p>'
                   2042:             .'<p>'.&mt('Search: ').$pretty_query_string
                   2043:             .'</p></form>';
1.256     albertel 2044:     $r->print($result.&Apache::loncommon::end_page());
1.151     matthew  2045:     return;
                   2046: }
                   2047: 
1.144     matthew  2048: #####################################################################
                   2049: #####################################################################
                   2050: 
                   2051: =pod
                   2052: 
                   2053: =item MySQL Table Description
                   2054: 
                   2055: MySQL table creation requires a precise description of the data to be
                   2056: stored.  The use of the correct types to hold data is vital to efficient
                   2057: storage and quick retrieval of records.  The columns must be described in
                   2058: the following format:
                   2059: 
                   2060: =cut
                   2061: 
1.170     matthew  2062: #####################################################################
                   2063: #####################################################################
1.204     matthew  2064: #
                   2065: # These should probably be scoped but I don't have time right now...
                   2066: #
                   2067: my @Datatypes;
                   2068: my @Fullindicies;
1.147     matthew  2069:     
1.144     matthew  2070: ######################################################################
                   2071: ######################################################################
                   2072: 
                   2073: =pod
                   2074: 
1.146     matthew  2075: =item &create_results_table()
                   2076: 
                   2077: Creates the table of search results by calling lonmysql.  Stores the
1.243     albertel 2078: table id in $env{'form.table'}
1.146     matthew  2079: 
1.276     raeburn  2080: Inputs: search area - either res or portfolio 
1.146     matthew  2081: 
                   2082: Returns: the identifier of the table on success, undef on error.
                   2083: 
                   2084: =cut
                   2085: 
                   2086: ######################################################################
                   2087: ######################################################################
1.204     matthew  2088: sub set_up_table_structure {
1.276     raeburn  2089:     my ($tabletype) = @_;
1.204     matthew  2090:     my ($datatypes,$fullindicies) = 
1.276     raeburn  2091:         &LONCAPA::lonmetadata::describe_metadata_storage($tabletype);
1.212     matthew  2092:     # Copy the table description before modifying it...
                   2093:     @Datatypes = @{$datatypes};
                   2094:     unshift(@Datatypes,{name => 'id',  
1.204     matthew  2095:         type => 'MEDIUMINT',
                   2096:         restrictions => 'UNSIGNED NOT NULL',
                   2097:         primary_key  => 'yes',
                   2098:         auto_inc     => 'yes' });
                   2099:     @Fullindicies = @{$fullindicies};
                   2100:     return;
                   2101: }
                   2102: 
1.146     matthew  2103: sub create_results_table {
1.276     raeburn  2104:     my ($area) = @_;
                   2105:     if ($area eq 'portfolio') {
                   2106:         &set_up_table_structure('portfolio_search');
                   2107:     } else {
                   2108:         &set_up_table_structure('metadata');
                   2109:     }
1.146     matthew  2110:     my $table = &Apache::lonmysql::create_table
1.170     matthew  2111:         ( { columns => \@Datatypes,
1.172     matthew  2112:             FULLTEXT => [{'columns' => \@Fullindicies},],
1.146     matthew  2113:         } );
                   2114:     if (defined($table)) {
1.243     albertel 2115:         $env{'form.table'} = $table;
1.146     matthew  2116:         return $table;
                   2117:     } 
                   2118:     return undef; # Error...
                   2119: }
1.148     matthew  2120: 
1.146     matthew  2121: ######################################################################
                   2122: ######################################################################
                   2123: 
                   2124: =pod
                   2125: 
1.150     matthew  2126: =item Search Status update functions
1.144     matthew  2127: 
1.150     matthew  2128: Each of the following functions changes the values of one of the
                   2129: input fields used to display the search status to the user.  The names
                   2130: should be explanatory.
1.144     matthew  2131: 
1.150     matthew  2132: Inputs: Apache request handler ($r), text to display.
1.148     matthew  2133: 
1.150     matthew  2134: Returns: Nothing.
1.148     matthew  2135: 
                   2136: =over 4
                   2137: 
                   2138: =item &update_count_status()
                   2139: 
1.150     matthew  2140: =item &update_status()
1.148     matthew  2141: 
1.150     matthew  2142: =item &update_seconds()
1.148     matthew  2143: 
                   2144: =back
                   2145: 
                   2146: =cut
                   2147: 
                   2148: ######################################################################
                   2149: ######################################################################
                   2150: sub update_count_status {
                   2151:     my ($r,$text) = @_;
                   2152:     $text =~ s/\'/\\\'/g;
1.313     bisitz   2153:     $r->print(<<SCRIPT);
                   2154: <script type="text/javascript">
                   2155: // <![CDATA[
                   2156: document.statusform.count.value = ' $text'
                   2157: // ]]>
                   2158: </script>
                   2159: SCRIPT
                   2160: 
1.148     matthew  2161:     $r->rflush();
                   2162: }
                   2163: 
1.150     matthew  2164: sub update_status {
1.148     matthew  2165:     my ($r,$text) = @_;
                   2166:     $text =~ s/\'/\\\'/g;
1.313     bisitz   2167:     $r->print(<<SCRIPT);
                   2168: <script type="text/javascript">
                   2169: // <![CDATA[
                   2170: document.statusform.status.value = ' $text'
                   2171: // ]]>
                   2172: </script>
                   2173: SCRIPT
                   2174: 
1.148     matthew  2175:     $r->rflush();
                   2176: }
                   2177: 
1.214     matthew  2178: {
1.250     www      2179:     my $max_time  = 300;  # seconds for the search to complete
1.214     matthew  2180:     my $start_time = 0;
                   2181:     my $last_time = 0;
                   2182: 
                   2183: sub reset_timing {
                   2184:     $start_time = 0;
                   2185:     $last_time = 0;
                   2186: }
                   2187: 
                   2188: sub time_left {
                   2189:     if ($start_time == 0) {
                   2190:         $start_time = time;
                   2191:     }
                   2192:     my $time_left = $max_time - (time - $start_time);
                   2193:     $time_left = 0 if ($time_left < 0);
                   2194:     return $time_left;
                   2195: }
                   2196: 
1.150     matthew  2197: sub update_seconds {
1.214     matthew  2198:     my ($r) = @_;
                   2199:     my $time = &time_left();
                   2200:     if (($last_time-$time) > 0) {
1.313     bisitz   2201:         $r->print(<<SCRIPT);
                   2202: <script type="text/javascript">
                   2203: // <![CDATA[
                   2204: document.statusform.seconds.value = '$time'
                   2205: // ]]>
                   2206: </script>
                   2207: SCRIPT
                   2208: 
1.214     matthew  2209:         $r->rflush();
                   2210:     }
                   2211:     $last_time = $time;
                   2212: }
                   2213: 
1.148     matthew  2214: }
                   2215: 
                   2216: ######################################################################
                   2217: ######################################################################
                   2218: 
                   2219: =pod
                   2220: 
1.204     matthew  2221: =item &revise_button()
1.151     matthew  2222: 
                   2223: Inputs: None
                   2224: 
                   2225: Returns: html string for a 'revise search' button.
                   2226: 
                   2227: =cut
                   2228: 
                   2229: ######################################################################
                   2230: ######################################################################
                   2231: sub revise_button {
1.289     bisitz   2232:     my $revisetext = &mt('Revise search');
1.151     matthew  2233:     my $revise_phase = 'disp_basic';
1.243     albertel 2234:     $revise_phase = 'disp_adv' if ($env{'form.searchmode'} eq 'advanced');
1.151     matthew  2235:     my $newloc = '/adm/searchcat'.
1.243     albertel 2236:         '?persistent_db_id='.$env{'form.persistent_db_id'}.
1.309     bisitz   2237:             '&amp;cleargroupsort=1'.
                   2238:             '&amp;phase='.$revise_phase;
1.289     bisitz   2239:     my $result = qq{<input type="button" value="$revisetext" name="revise"} .
1.313     bisitz   2240:         qq{ onclick="parent.location='$newloc';" /> };
1.151     matthew  2241:     return $result;
                   2242: }
                   2243: 
                   2244: ######################################################################
                   2245: ######################################################################
                   2246: 
                   2247: =pod
                   2248: 
1.204     matthew  2249: =item &run_search()
                   2250: 
                   2251: Executes a search query by sending it the the other servers and putting the
                   2252: results into MySQL.
1.144     matthew  2253: 
                   2254: =cut
                   2255: 
                   2256: ######################################################################
                   2257: ######################################################################
                   2258: sub run_search {
1.276     raeburn  2259:     my ($r,$query,$customquery,$customshow,$serverlist,
                   2260:         $pretty_string,$area) = @_;
                   2261:     my $tabletype = 'metadata';
                   2262:     if ($area eq 'portfolio') {
                   2263:         $tabletype = 'portfolio_search';
                   2264:     }
1.150     matthew  2265:     my $connection = $r->connection;
1.144     matthew  2266:     #
1.146     matthew  2267:     # Print run_search header
                   2268:     #
1.307     bisitz   2269:     my $start_page = &Apache::loncommon::start_page('Search Status',undef);
1.263     albertel 2270:     my $breadcrumbs =
                   2271: 	&Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
1.267     www      2272: 					    $env{'form.catalogmode'} ne 'import');
1.151     matthew  2273:     $r->print(<<END);
1.257     albertel 2274: $start_page
                   2275: $breadcrumbs
1.151     matthew  2276: END
1.230     matthew  2277:     # Remove leading and trailing <br />
                   2278:     $pretty_string =~ s:^\s*<br />::i;
                   2279:     $pretty_string =~ s:(<br />)*\s*$::im;
                   2280:     my @Lines = split("<br />",$pretty_string);
                   2281:     # I keep getting blank items at the end of the list, hence the following:
                   2282:     while ($Lines[-1] =~ /^\s*$/ && @Lines) {
                   2283:         pop(@Lines);
                   2284:     }
1.152     matthew  2285:     if (@Lines > 2) {
1.298     bisitz   2286:         $pretty_string = join '<br />',(@Lines[0..2],'...<br />');
1.151     matthew  2287:     }
1.214     matthew  2288:     $r->print(&mt("Search: [_1]",$pretty_string));
1.146     matthew  2289:     $r->rflush();
                   2290:     #
1.145     matthew  2291:     # Determine the servers we need to contact.
1.144     matthew  2292:     my @Servers_to_contact;
                   2293:     if (defined($serverlist)) {
1.152     matthew  2294:         if (ref($serverlist) eq 'ARRAY') {
                   2295:             @Servers_to_contact = @$serverlist;
                   2296:         } else {
                   2297:             @Servers_to_contact = ($serverlist);
                   2298:         }
1.144     matthew  2299:     } else {
1.322     droeschl 2300: 	my %all_library_servers = &Apache::lonnet::unique_library();
1.281     albertel 2301:         @Servers_to_contact = sort(keys(%all_library_servers));
1.144     matthew  2302:     }
                   2303:     my %Server_status;
1.214     matthew  2304:     #
                   2305:     # Check on the mysql table we will use to store results.
1.243     albertel 2306:     my $table =$env{'form.table'};
1.150     matthew  2307:     if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
1.286     albertel 2308:         $r->print("Unable to determine table id to save search results in.".
1.256     albertel 2309:                   "The search has been aborted.".
                   2310: 		  &Apache::loncommon::end_page());
1.147     matthew  2311:         return;
                   2312:     }
                   2313:     my $table_status = &Apache::lonmysql::check_table($table);
                   2314:     if (! defined($table_status)) {
1.256     albertel 2315:         $r->print("Unable to determine status of table.".
                   2316: 		  &Apache::loncommon::end_page());
1.147     matthew  2317:         &Apache::lonnet::logthis("Bogus table id of $table for ".
1.243     albertel 2318:                                  "$env{'user.name'} @ $env{'user.domain'}");
1.147     matthew  2319:         &Apache::lonnet::logthis("lonmysql error = ".
1.144     matthew  2320:                                  &Apache::lonmysql::get_error());
1.147     matthew  2321:         return;
                   2322:     }
                   2323:     if (! $table_status) {
1.204     matthew  2324:         &Apache::lonnet::logthis("lonmysql error = ".
                   2325:                                  &Apache::lonmysql::get_error());
                   2326:         &Apache::lonnet::logthis("lonmysql debug = ".
                   2327:                                  &Apache::lonmysql::get_debug());
                   2328:         &Apache::lonnet::logthis('table status = "'.$table_status.'"');
1.147     matthew  2329:         $r->print("The table id,$table, we tried to use is invalid.".
1.256     albertel 2330:                   "The search has been aborted.".
                   2331: 		  &Apache::loncommon::end_page());
1.144     matthew  2332:         return;
                   2333:     }
1.145     matthew  2334:     ##
1.146     matthew  2335:     ## Prepare for the big loop.
1.144     matthew  2336:     my $hitcountsum;
1.276     raeburn  2337:     my %matches;
1.144     matthew  2338:     my $server; 
                   2339:     my $status;
1.151     matthew  2340:     my $revise = &revise_button();
1.299     raeburn  2341:     $r->print('<form name="statusform" action="" method="post">'."\n".
                   2342:               '<input type="hidden" name="acts" value="" />'."\n".
                   2343:               '<table border="0"><tr><td>'."\n".
                   2344:               &Apache::loncommon::start_data_table());
1.298     bisitz   2345:     $r->print(&Apache::loncommon::start_data_table_header_row()
                   2346:              .'<th>'.&mt('Status').'</th>'
                   2347:              .'<th>'.&mt('Total Matches').'</th>'
                   2348:              .'<th>'.&mt('Time Remaining').'</th>'
1.299     raeburn  2349:              .&Apache::loncommon::end_data_table_header_row()
                   2350:              .&Apache::loncommon::start_data_table_row()
1.298     bisitz   2351:              .'<td><input type="text" name="status"  value="" size="50" readonly="readonly" /></td>'
                   2352:              .'<td><input type="text" name="count"   value="" size="10" readonly="readonly" /></td>'
                   2353:              .'<td><input type="text" name="seconds" value="" size="8" readonly="readonly" /></td>'
1.299     raeburn  2354:              .&Apache::loncommon::end_data_table_row()
                   2355:              .&Apache::loncommon::end_data_table()
                   2356:              .'</td><td>&nbsp;</td><td>'.$revise.'</td></tr></table></form>');
1.148     matthew  2357:     $r->rflush();
1.214     matthew  2358:     &reset_timing();
                   2359:     &update_seconds($r);
                   2360:     &update_status($r,&mt('contacting [_1]',$Servers_to_contact[0]));
                   2361:     while (&time_left() &&
1.144     matthew  2362:            ((@Servers_to_contact) || keys(%Server_status))) {
1.214     matthew  2363:         &update_seconds($r);
                   2364:         #
                   2365:         # Send out a search request
1.144     matthew  2366:         if (@Servers_to_contact) {
                   2367:             # Contact one server
                   2368:             my $server = shift(@Servers_to_contact);
1.214     matthew  2369:             &update_status($r,&mt('contacting [_1]',$server));
1.144     matthew  2370:             my $reply=&Apache::lonnet::metadata_query($query,$customquery,
                   2371:                                                       $customshow,[$server]);
                   2372:             ($server) = keys(%$reply);
                   2373:             $Server_status{$server} = $reply->{$server};
                   2374:         } else {
1.150     matthew  2375:             # wait a sec. to give time for files to be written
                   2376:             # This sleep statement is here instead of outside the else 
                   2377:             # block because we do not want to pause if we have servers
                   2378:             # left to contact.  
1.183     matthew  2379:             if (scalar (keys(%Server_status))) {
                   2380:                 &update_status($r,
1.214     matthew  2381:                        &mt('waiting on [_1]',join(' ',keys(%Server_status))));
1.183     matthew  2382:             }
1.150     matthew  2383:             sleep(1)1.144     matthew  2384:         }
1.159     matthew  2385:         #
                   2386:         # Loop through the servers we have contacted but do not
                   2387:         # have results from yet, looking for results.
1.228     matthew  2388:         foreach my $server (keys(%Server_status)) {
1.150     matthew  2389:             last if ($connection->aborted());
1.214     matthew  2390:             &update_seconds($r);
1.228     matthew  2391:             my $status = $Server_status{$server};
1.144     matthew  2392:             if ($status eq 'con_lost') {
                   2393:                 delete ($Server_status{$server});
                   2394:                 next;
                   2395:             }
1.276     raeburn  2396:             $status=~s|/||g;
1.330     foxr     2397: 
                   2398: 
                   2399: 
                   2400:        	    my $datafile=LONCAPA::tempdir().$status;
1.144     matthew  2401:             if (-e $datafile && ! -e "$datafile.end") {
1.214     matthew  2402:                 &update_status($r,&mt('Receiving results from [_1]',$server));
1.144     matthew  2403:                 next;
                   2404:             }
1.150     matthew  2405:             last if ($connection->aborted());
1.144     matthew  2406:             if (-e "$datafile.end") {
1.214     matthew  2407:                 &update_status($r,&mt('Reading results from [_1]',$server));
1.144     matthew  2408:                 if (-z "$datafile") {
                   2409:                     delete($Server_status{$server});
                   2410:                     next;
                   2411:                 }
                   2412:                 my $fh;
                   2413:                 if (!($fh=Apache::File->new($datafile))) { 
1.146     matthew  2414:                     $r->print("Unable to open search results file for ".
1.145     matthew  2415:                                   "server $server.  Omitting from search");
1.150     matthew  2416:                     delete($Server_status{$server}); 
                   2417:                    next;
1.144     matthew  2418:                 }
                   2419:                 # Read in the whole file.
                   2420:                 while (my $result = <$fh>) {
1.150     matthew  2421:                     last if ($connection->aborted());
1.214     matthew  2422:                     #
                   2423:                     # Records are stored one per line
1.144     matthew  2424:                     chomp($result);
1.214     matthew  2425:                     next if (! $result);
                   2426:                     #
1.144     matthew  2427:                     # Parse the result.
1.276     raeburn  2428:                     my %Fields = &parse_raw_result($result,$server,$tabletype);
1.144     matthew  2429:                     $Fields{'hostname'} = $server;
1.214     matthew  2430:                     #
                   2431:                     # Skip based on copyright
1.144     matthew  2432:                     next if (! &copyright_check(\%Fields));
1.248     www      2433: 
1.276     raeburn  2434:                     if ($area eq 'portfolio') {
                   2435:                         next if (defined($matches{$Fields{'url'}}));
                   2436:                         # Skip if inaccessible
                   2437:                         next if (!&Apache::lonnet::portfolio_access($Fields{'url'}));
                   2438:                         $matches{$Fields{'url'}} = 1; 
                   2439:                     }
1.214     matthew  2440:                     #
1.144     matthew  2441:                     # Store the result in the mysql database
                   2442:                     my $result = &Apache::lonmysql::store_row($table,\%Fields);
                   2443:                     if (! defined($result)) {
1.146     matthew  2444:                         $r->print(&Apache::lonmysql::get_error());
1.144     matthew  2445:                     }
1.214     matthew  2446:                     #
1.144     matthew  2447:                     $hitcountsum ++;
1.214     matthew  2448:                     &update_seconds($r);
1.150     matthew  2449:                     if ($hitcountsum % 50 == 0) {
                   2450:                         &update_count_status($r,$hitcountsum);
                   2451:                     }
1.214     matthew  2452:                 }
1.144     matthew  2453:                 $fh->close();
                   2454:                 # $server is only deleted if the results file has been 
                   2455:                 # found and (successfully) opened.  This may be a bad idea.
                   2456:                 delete($Server_status{$server});
                   2457:             }
1.150     matthew  2458:             last if ($connection->aborted());
1.148     matthew  2459:             &update_count_status($r,$hitcountsum);
1.144     matthew  2460:         }
1.150     matthew  2461:         last if ($connection->aborted());
1.214     matthew  2462:         &update_seconds($r);
1.144     matthew  2463:     }
1.313     bisitz   2464:     &update_status($r,&mt('Search Complete on Server [_1]',$server));
1.214     matthew  2465:     &update_seconds($r);
1.204     matthew  2466:     #
1.214     matthew  2467:     &Apache::lonmysql::disconnect_from_db(); # This is unneccessary
1.204     matthew  2468:     #
1.144     matthew  2469:     # We have run out of time or run out of servers to talk to and
1.214     matthew  2470:     # results to get, so let the client know the top frame needs to be
                   2471:     # loaded from /adm/searchcat
1.256     albertel 2472:     $r->print(&Apache::loncommon::end_page());
1.267     www      2473: #    if ($env{'form.catalogmode'} ne 'import') {
1.313     bisitz   2474:          $r->print(<<SCRIPT);
                   2475: <script>
                   2476: window.location='/adm/searchcat?phase=sort&persistent_db_id=$env{'form.persistent_db_id'}';
                   2477: </script>
                   2478: SCRIPT
1.224     matthew  2479: #    }
1.144     matthew  2480:     return;
                   2481: }
                   2482: 
                   2483: ######################################################################
                   2484: ######################################################################
1.204     matthew  2485: 
1.144     matthew  2486: =pod
                   2487: 
1.204     matthew  2488: =item &prev_next_buttons()
                   2489: 
                   2490: Returns html for the previous and next buttons on the search results page.
1.144     matthew  2491: 
                   2492: =cut
                   2493: 
                   2494: ######################################################################
                   2495: ######################################################################
1.146     matthew  2496: sub prev_next_buttons {
1.145     matthew  2497:     my ($current_min,$show,$total,$parms) = @_;
                   2498:     return '' if ($show eq 'all'); # No links if you get them all at once.
1.214     matthew  2499:     #
1.223     matthew  2500:     # Create buttons
1.313     bisitz   2501:     return '<p class="LC_nobreak">'
                   2502:           .'<input type="submit" name="prev" value="&lt;"'
                   2503:           .' title="'.&mt('Previous').'" />'
                   2504:           .' '
                   2505:           .'<input type="submit" name="reload" value="'.&mt('Reload').'" />'
                   2506:           .' '
                   2507:           .'<input type="submit" name="next" value="&gt;"'
                   2508:           .' title="'.&mt('Next').'" />'
                   2509:           .'</p>';
1.144     matthew  2510: }
1.204     matthew  2511: 
1.144     matthew  2512: ######################################################################
                   2513: ######################################################################
                   2514: 
                   2515: =pod
                   2516: 
1.204     matthew  2517: =item &display_results()
                   2518: 
                   2519: Prints the results out for selection and perusal.
1.144     matthew  2520: 
                   2521: =cut
                   2522: 
                   2523: ######################################################################
                   2524: ######################################################################
                   2525: sub display_results {
1.276     raeburn  2526:     my ($r,$importbutton,$closebutton,$diropendb,$area) = @_;
1.150     matthew  2527:     my $connection = $r->connection;
                   2528:     $r->print(&search_results_header($importbutton,$closebutton));
1.144     matthew  2529:     ##
                   2530:     ## Set viewing function
                   2531:     ##
1.243     albertel 2532:     my $viewfunction = $Views{$env{'form.viewselect'}};
1.144     matthew  2533:     if (!defined($viewfunction)) {
1.312     bisitz   2534:         $r->print('<p class="LC_error">'
                   2535:                  .&mt('Internal Error - Bad view selected.')
                   2536:                  .'</p>'."\n");
1.144     matthew  2537:         $r->rflush();
                   2538:         return;
                   2539:     }
                   2540:     ##
1.158     matthew  2541:     ## $checkbox_num is a count of the number of checkboxes output on the 
1.267     www      2542:     ## page this is used only during catalogmode=import.
1.158     matthew  2543:     my $checkbox_num = 0;
                   2544:     ##
1.144     matthew  2545:     ## Get the catalog controls setup
                   2546:     ##
1.146     matthew  2547:     my $action = "/adm/searchcat?phase=results";
                   2548:     ##
1.267     www      2549:     ## Deal with import by opening the import db file.
                   2550:     if ($env{'form.catalogmode'} eq 'import') {
1.146     matthew  2551:         if (! tie(%groupsearch_db,'GDBM_File',$diropendb,
1.148     matthew  2552:                   &GDBM_WRCREAT(),0640)) {
1.312     bisitz   2553:             $r->print('<p class="LC_error">'.
                   2554:               &mt('Unable to save import results.').
                   2555:               '</p>'.
                   2556:               '</form>'.
1.256     albertel 2557: 		      &Apache::loncommon::end_page());
1.146     matthew  2558:             $r->rflush();
                   2559:             return;
                   2560:         } 
1.144     matthew  2561:     }
1.145     matthew  2562:     ##
                   2563:     ## Prepare the table for querying
1.243     albertel 2564:     my $table = $env{'form.table'};
1.151     matthew  2565:     return if (! &ensure_db_and_table($r,$table));
1.145     matthew  2566:     ##
                   2567:     ## Get the number of results 
                   2568:     my $total_results = &Apache::lonmysql::number_of_rows($table);
                   2569:     if (! defined($total_results)) {
1.312     bisitz   2570:         $r->print('<p class="LC_error">'.
                   2571:           &mt('A MySQL error has occurred.').
                   2572:           '</p>'.
                   2573:           '</form>'.
1.256     albertel 2574: 		  &Apache::loncommon::end_page());
1.145     matthew  2575:         &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                   2576:                                  " of rows in table ".$table);
                   2577:         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
                   2578:         return;
                   2579:     }
                   2580:     ##
                   2581:     ## Determine how many results we need to get
1.243     albertel 2582:     $env{'form.start'} = 1  if (! exists($env{'form.start'}));
                   2583:     $env{'form.show'}  = 20 if (! exists($env{'form.show'}));
                   2584:     if (exists($env{'form.prev'})) {
                   2585:         $env{'form.start'} -= $env{'form.show'};
                   2586:     } elsif (exists($env{'form.next'})) {
                   2587:         $env{'form.start'} += $env{'form.show'};
                   2588:     }
                   2589:     $env{'form.start'} = 1 if ($env{'form.start'}<1);
                   2590:     $env{'form.start'} = $total_results if ($env{'form.start'}>$total_results);
                   2591:     my $min = $env{'form.start'};
1.145     matthew  2592:     my $max;
1.243     albertel 2593:     if ($env{'form.show'} eq 'all') {
1.145     matthew  2594:         $max = $total_results ;
                   2595:     } else {
1.243     albertel 2596:         $max = $min + $env{'form.show'} - 1;
1.146     matthew  2597:         $max = $total_results if ($max > $total_results);
1.145     matthew  2598:     }
                   2599:     ##
1.223     matthew  2600:     ## Output form elements
                   2601:     $r->print(&hidden_field('table').
                   2602:               &hidden_field('phase').
                   2603:               &hidden_field('persistent_db_id').
1.276     raeburn  2604:               &hidden_field('start').
                   2605:               &hidden_field('area')
1.223     matthew  2606:               );
1.232     matthew  2607:     #
                   2608:     # Build sorting selector
1.241     matthew  2609:     my @fields = 
                   2610:         (
                   2611:          {key=>'default' },
                   2612:          {key=>'title' },
                   2613:          {key =>'author' },
                   2614:          {key =>'subject'},
                   2615:          {key =>'url',desc=>'URL'},
                   2616:          {key =>'keywords'},
                   2617:          {key =>'language'},
                   2618:          {key =>'creationdate'},
                   2619:          {key =>'lastrevisiondate'},
                   2620:          {key =>'owner'},
                   2621:          {key =>'copyright'},
                   2622:          {key =>'authorspace'},
                   2623:          {key =>'lowestgradelevel'},
                   2624:          {key =>'highestgradelevel'},
                   2625:          {key =>'standards',desc=>'Standards'},
1.276     raeburn  2626:         );
                   2627:     if ($area eq 'portfolio') {
                   2628:         push(@fields,
                   2629:        (
                   2630:          {key => 'scope'},
                   2631:          {key => 'keynum'},
                   2632:        ));
                   2633:     } else {
                   2634:         push(@fields,
                   2635:        (
1.241     matthew  2636:          {key =>'count',desc=>'Number of accesses'},
                   2637:          {key =>'stdno',desc=>'Students Attempting'},
                   2638:          {key =>'avetries',desc=>'Average Number of Tries'},
                   2639:          {key =>'difficulty',desc=>'Mean Degree of Difficulty'},
                   2640:          {key =>'disc',desc=>'Mean Degree of Discrimination'},
                   2641:          {key =>'clear',desc=>'Evaluation: Clear'},
                   2642:          {key =>'technical',desc=>'Evaluation: Technically Correct'},
                   2643:          {key =>'correct',desc=>'Evaluation: Material is Correct'},
                   2644:          {key =>'helpful',desc=>'Evaluation: Material is Helpful'},
                   2645:          {key =>'depth',desc=>'Evaluation: Material has Depth'},
1.276     raeburn  2646:        ));
                   2647:     }
1.241     matthew  2648:     my %fieldnames = &Apache::lonmeta::fieldnames();
                   2649:     my @field_order;
                   2650:     foreach my $field_data (@fields) {
                   2651:         push(@field_order,$field_data->{'key'});
                   2652:         if (! exists($field_data->{'desc'})) {
                   2653:             $field_data->{'desc'}=$fieldnames{$field_data->{'key'}};
                   2654:         } else {
                   2655:             if (! defined($field_data->{'desc'})) {
                   2656:                 $field_data->{'desc'} = ucfirst($field_data->{'key'});
                   2657:             }
                   2658:             $field_data->{'desc'} = &mt($field_data->{'desc'});
                   2659:         }
                   2660:     }
                   2661:     my %sort_fields = map {$_->{'key'},$_->{'desc'}} @fields;
                   2662:     $sort_fields{'select_form_order'} = \@field_order;
1.248     www      2663:     $env{'form.sortorder'} = 'desc' if (! exists($env{'form.sortorder'}));
1.276     raeburn  2664:     if (! exists($env{'form.sortfield'})) {
                   2665:         if ($area eq 'portfolio') {
                   2666:             $env{'form.sortfield'} = 'owner';
                   2667:         } else {
                   2668:             $env{'form.sortfield'} = 'count';
                   2669:         }
                   2670:     }
1.248     www      2671:     if (! exists($env{'form.sortorder'})) {
                   2672: 	if ($env{'form.sortfield'}=~/^(count|stdno|disc|clear|technical|correct|helpful)$/) {
                   2673: 	    $env{'form.sortorder'}='desc';
                   2674: 	} else {
                   2675: 	    $env{'form.sortorder'}='asc';
                   2676: 	}
                   2677:     }
1.313     bisitz   2678:     my $sortform = '<span class="LC_nobreak">'
                   2679:                   .&mt('Sort by:').' '
                   2680:                   .&Apache::loncommon::select_form($env{'form.sortfield'},
1.232     matthew  2681:                                                       'sortfield',
1.324     raeburn  2682:                                                       \%sort_fields)
1.313     bisitz   2683:                   .' '
                   2684:                   .&Apache::loncommon::select_form($env{'form.sortorder'},
1.241     matthew  2685:                                                       'sortorder',
1.324     raeburn  2686:                                                       {asc =>&mt('Ascending'),
1.241     matthew  2687:                                                        desc=>&mt('Descending')
1.324     raeburn  2688:                                                        })
1.313     bisitz   2689:                   .'</span>';
1.223     matthew  2690:     ##
1.313     bisitz   2691:     ## Display links for 'prev' and 'next' pages (if necessary) and Display Options
                   2692:     $r->print('<fieldset>'."\n"
                   2693:              .'<legend>'.&mt('Display Options').'</legend>'."\n"
                   2694:              .$sortform
                   2695:              .' '
                   2696:              .&viewoptions()
                   2697:              .'</fieldset>'
                   2698:              .&prev_next_buttons($min,$env{'form.show'},$total_results)
                   2699:     );
                   2700: 
1.150     matthew  2701:     if ($total_results == 0) {
1.256     albertel 2702:         $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2" />'.
1.313     bisitz   2703:                   '<p class="LC_info">'.&mt('There are currently no results.').'</p>'.
1.256     albertel 2704:                   "</form>".
                   2705: 		  &Apache::loncommon::end_page());
1.150     matthew  2706:         return;
                   2707:     } else {
1.312     bisitz   2708:         $r->print('<div>'.
1.232     matthew  2709:                   mt('Results [_1] to [_2] out of [_3]',
                   2710:                      $min,$max,$total_results).
1.312     bisitz   2711:                   "</div>\n");
1.150     matthew  2712:     }
1.145     matthew  2713:     ##
                   2714:     ## Get results from MySQL table
1.232     matthew  2715:     my $sort_command  = 'id>='.$min.' AND id<='.$max;
1.241     matthew  2716:     my $order;
1.244     albertel 2717:     if (exists($env{'form.sortorder'})) {
                   2718:         if ($env{'form.sortorder'} eq 'asc') {
1.241     matthew  2719:             $order = 'ASC';
1.244     albertel 2720:         } elsif ($env{'form.sortorder'} eq 'desc') {
1.241     matthew  2721:             $order = 'DESC';
                   2722:         } else {
                   2723:             $order = '';
                   2724:         }
                   2725:     } else {
                   2726:         $order = '';
                   2727:     }
1.244     albertel 2728:     if ($env{'form.sortfield'} ne 'default' && 
                   2729:         exists($sort_fields{$env{'form.sortfield'}})) {
                   2730:         $sort_command = $env{'form.sortfield'}.' IS NOT NULL '.
                   2731:             'ORDER BY '.$env{'form.sortfield'}.' '.$order.
1.249     www      2732:             '  LIMIT '.($min-1).','.($max-$min+1);
1.232     matthew  2733:     }
                   2734:     my @Results = &Apache::lonmysql::get_rows($table,$sort_command);
1.145     matthew  2735:     ##
                   2736:     ## Loop through the results and output them.
1.276     raeburn  2737:     my $tabletype = 'metadata';
                   2738:     if ($area eq 'portfolio') {
                   2739:         $tabletype = 'portfolio_search';
                   2740:     }
1.312     bisitz   2741:     $r->print(&Apache::loncommon::start_data_table());
1.144     matthew  2742:     foreach my $row (@Results) {
1.150     matthew  2743:         if ($connection->aborted()) {
1.162     www      2744:             &cleanup();
1.150     matthew  2745:             return;
                   2746:         }
1.276     raeburn  2747:         my %Fields = %{&parse_row($tabletype,@$row)};
1.312     bisitz   2748:         my $output;
1.210     matthew  2749:         if (! defined($Fields{'title'}) || $Fields{'title'} eq '') {
                   2750:             $Fields{'title'} = 'Untitled';
                   2751:         }
1.158     matthew  2752:         my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'},
                   2753:                                        $Fields{'id'},$checkbox_num++);
1.144     matthew  2754:         # Render the result into html
1.150     matthew  2755:         $output.= &$viewfunction($prefix,%Fields);
1.145     matthew  2756:         # Print them out as they come in.
1.312     bisitz   2757:         $r->print(&Apache::loncommon::start_data_table_row()
                   2758:                  .'<td>'
                   2759:                  .$output
                   2760:                  .'</td>'
                   2761:                  .&Apache::loncommon::end_data_table_row()
                   2762:         );
1.144     matthew  2763:         $r->rflush();
                   2764:     }
1.312     bisitz   2765:     $r->print(&Apache::loncommon::end_data_table());
1.144     matthew  2766:     if (@Results < 1) {
1.312     bisitz   2767:         $r->print('<p class="LC_info">'
                   2768:                  .&mt('There were no results matching your query.')
                   2769:                  .'</p>');
1.147     matthew  2770:     } else {
1.313     bisitz   2771:         $r->print(
                   2772:             &prev_next_buttons($min,$env{'form.show'},$total_results,
1.243     albertel 2773:                                 "table=".$env{'form.table'}.
1.309     bisitz   2774:                                 "&amp;phase=results".
                   2775:                                 "&amp;persistent_db_id=".
1.243     albertel 2776:                                 $env{'form.persistent_db_id'})
1.313     bisitz   2777:         );
1.144     matthew  2778:     }
1.256     albertel 2779:     $r->print("</form>".&Apache::loncommon::end_page());
1.144     matthew  2780:     $r->rflush();
1.150     matthew  2781:     untie %groupsearch_db if (tied(%groupsearch_db));
1.144     matthew  2782:     return;
                   2783: }
                   2784: 
                   2785: ######################################################################
                   2786: ######################################################################
                   2787: 
                   2788: =pod
                   2789: 
1.158     matthew  2790: =item &catalogmode_output($title,$url,$fnum,$checkbox_num)
1.145     matthew  2791: 
                   2792: Returns html needed for the various catalog modes.  Gets inputs from
1.243     albertel 2793: $env{'form.catalogmode'}.  Stores data in %groupsearch_db.
1.145     matthew  2794: 
                   2795: =cut
                   2796: 
                   2797: ######################################################################
                   2798: ######################################################################
                   2799: sub catalogmode_output {
                   2800:     my $output = '';
1.158     matthew  2801:     my ($title,$url,$fnum,$checkbox_num) = @_;
1.243     albertel 2802:     if ($env{'form.catalogmode'} eq 'interactive') {
1.150     matthew  2803:         $title=~ s/\'/\\\'/g;
1.243     albertel 2804:         if ($env{'form.catalogmode'} eq 'interactive') {
1.145     matthew  2805:             $output.=<<END 
1.287     albertel 2806: <font size='-1'><input type="button" name="returnvalues" value="select"
1.313     bisitz   2807: onclick="javascript:select_data('$title','$url')" />
1.145     matthew  2808: </font>
                   2809: END
                   2810:         }
1.267     www      2811:     } elsif ($env{'form.catalogmode'} eq 'import') {
1.145     matthew  2812:         $groupsearch_db{"pre_${fnum}_link"}=$url;
                   2813:         $groupsearch_db{"pre_${fnum}_title"}=$title;
                   2814:         $output.=<<END;
                   2815: <font size='-1'>
1.287     albertel 2816: <input type="checkbox" name="returnvalues" value="select"
1.313     bisitz   2817: onclick="javascript:queue($checkbox_num,$fnum)" />
1.145     matthew  2818: </font>
                   2819: END
                   2820:     }
                   2821:     return $output;
                   2822: }
                   2823: ######################################################################
                   2824: ######################################################################
                   2825: 
                   2826: =pod
                   2827: 
1.204     matthew  2828: =item &parse_row()
1.144     matthew  2829: 
                   2830: Parse a row returned from the database.
                   2831: 
                   2832: =cut
                   2833: 
                   2834: ######################################################################
                   2835: ######################################################################
                   2836: sub parse_row {
1.276     raeburn  2837:     my ($tabletype,@Row) = @_;
1.144     matthew  2838:     my %Fields;
1.204     matthew  2839:     if (! scalar(@Datatypes)) {
1.276     raeburn  2840:         &set_up_table_structure($tabletype);
1.204     matthew  2841:     }
1.144     matthew  2842:     for (my $i=0;$i<=$#Row;$i++) {
1.265     www      2843:         $Fields{$Datatypes[$i]->{'name'}}=&unescape($Row[$i]);
1.144     matthew  2844:     }
                   2845:     $Fields{'language'} = 
1.198     www      2846:         &Apache::loncommon::languagedescription($Fields{'language'});
1.144     matthew  2847:     $Fields{'copyrighttag'} =
                   2848:         &Apache::loncommon::copyrightdescription($Fields{'copyright'});
                   2849:     $Fields{'mimetag'} =
                   2850:         &Apache::loncommon::filedescription($Fields{'mime'});
                   2851:     return \%Fields;
                   2852: }
1.126     matthew  2853: 
                   2854: ###########################################################
                   2855: ###########################################################
                   2856: 
                   2857: =pod
                   2858: 
                   2859: =item &parse_raw_result()
                   2860: 
                   2861: Takes a line from the file of results and parse it.  Returns a hash 
1.198     www      2862: with keys according to column labels
1.126     matthew  2863: 
                   2864: In addition, the following tags are set by calling the appropriate 
1.198     www      2865: lonnet function: 'language', 'copyrighttag', 'mimetag'.
1.126     matthew  2866: 
                   2867: The 'title' field is set to "Untitled" if the title field is blank.
                   2868: 
                   2869: 'abstract' and 'keywords' are truncated to 200 characters.
                   2870: 
                   2871: =cut
                   2872: 
                   2873: ###########################################################
                   2874: ###########################################################
                   2875: sub parse_raw_result {
1.276     raeburn  2876:     my ($result,$hostname,$tabletype) = @_;
1.204     matthew  2877:     # conclude from self to others regarding fields
1.206     matthew  2878:     my %Fields=&LONCAPA::lonmetadata::metadata_col_to_hash
1.276     raeburn  2879:         ($tabletype,
                   2880:          map {
1.265     www      2881:             &unescape($_);
1.276     raeburn  2882:          } (split(/\,/,$result)) );
1.126     matthew  2883:     return %Fields;
                   2884: }
                   2885: 
                   2886: ###########################################################
                   2887: ###########################################################
                   2888: 
                   2889: =pod
                   2890: 
                   2891: =item &handle_custom_fields()
                   2892: 
                   2893: =cut
                   2894: 
                   2895: ###########################################################
                   2896: ###########################################################
                   2897: sub handle_custom_fields {
                   2898:     my @results = @{shift()};
                   2899:     my $customshow='';
                   2900:     my $extrashow='';
                   2901:     my @customfields;
1.243     albertel 2902:     if ($env{'form.customshow'}) {
                   2903:         $customshow=$env{'form.customshow'};
1.126     matthew  2904:         $customshow=~s/[^\w\s]//g;
                   2905:         my @fields=map {
                   2906:             "<font color=\"#008000\">$_:</font><!-- $_ -->";
                   2907:         } split(/\s+/,$customshow);
                   2908:         @customfields=split(/\s+/,$customshow);
                   2909:         if ($customshow) {
                   2910:             $extrashow="<ul><li>".join("</li><li>",@fields)."</li></ul>\n";
                   2911:         }
                   2912:     }
                   2913:     my $customdata='';
                   2914:     my %customhash;
                   2915:     foreach my $result (@results) {
                   2916:         if ($result=~/^(custom\=.*)$/) { # grab all custom metadata
                   2917:             my $tmp=$result;
                   2918:             $tmp=~s/^custom\=//;
1.265     www      2919:             my ($k,$v)=map {&unescape($_);
1.126     matthew  2920:                         } split(/\,/,$tmp);
                   2921:             $customhash{$k}=$v;
                   2922:         }
                   2923:     }
                   2924:     return ($extrashow,\@customfields,\%customhash);
1.41      harris41 2925: }
                   2926: 
1.122     matthew  2927: ######################################################################
                   2928: ######################################################################
                   2929: 
1.125     matthew  2930: =pod
                   2931: 
1.204     matthew  2932: =item &search_results_header()
1.125     matthew  2933: 
1.130     matthew  2934: Output the proper html headers and javascript code to deal with different 
                   2935: calling modes.
                   2936: 
1.243     albertel 2937: Takes most inputs directly from %env, except $mode.  
1.130     matthew  2938: 
                   2939: =over 4
                   2940: 
                   2941: =item $mode is either (at this writing) 'Basic' or 'Advanced'
                   2942: 
                   2943: =back
1.126     matthew  2944: 
1.130     matthew  2945: The following environment variables are checked:
1.126     matthew  2946: 
                   2947: =over 4
                   2948: 
                   2949: =item 'form.catalogmode' 
                   2950: 
1.267     www      2951: Checked for 'interactive' and 'import'.
1.126     matthew  2952: 
                   2953: =item 'form.mode'
                   2954: 
                   2955: Checked for existance & 'edit' mode.
                   2956: 
                   2957: =item 'form.form'
                   2958: 
1.191     albertel 2959: Contains the name of the form that has the input fields to set
                   2960: 
1.126     matthew  2961: =item 'form.element'
                   2962: 
1.191     albertel 2963: the name of the input field to put the URL into
                   2964: 
                   2965: =item 'form.titleelement'
                   2966: 
                   2967: the name of the input field to put the title into
                   2968: 
1.126     matthew  2969: =back
                   2970: 
1.125     matthew  2971: =cut
                   2972: 
                   2973: ######################################################################
                   2974: ######################################################################
                   2975: sub search_results_header {
1.150     matthew  2976:     my ($importbutton,$closebutton) = @_;
1.256     albertel 2977: 
1.257     albertel 2978:     my $js;
1.125     matthew  2979:     # output beginning of search page
                   2980:     # conditional output of script functions dependent on the mode in
                   2981:     # which the search was invoked
1.243     albertel 2982:     if ($env{'form.catalogmode'} eq 'interactive'){
                   2983: 	if (! exists($env{'form.mode'}) || $env{'form.mode'} ne 'edit') {
1.257     albertel 2984:             $js.=<<SCRIPT;
1.125     matthew  2985: <script type="text/javascript">
1.313     bisitz   2986: // <![CDATA[
1.125     matthew  2987:     function select_data(title,url) {
                   2988: 	changeTitle(title);
                   2989: 	changeURL(url);
1.150     matthew  2990: 	parent.close();
1.125     matthew  2991:     }
                   2992:     function changeTitle(val) {
1.153     matthew  2993: 	if (parent.opener.inf.document.forms.resinfo.elements.t) {
                   2994: 	    parent.opener.inf.document.forms.resinfo.elements.t.value=val;
1.125     matthew  2995: 	}
                   2996:     }
                   2997:     function changeURL(val) {
1.153     matthew  2998: 	if (parent.opener.inf.document.forms.resinfo.elements.u) {
                   2999: 	    parent.opener.inf.document.forms.resinfo.elements.u.value=val;
1.125     matthew  3000: 	}
                   3001:     }
1.313     bisitz   3002: // ]]>
1.125     matthew  3003: </script>
                   3004: SCRIPT
1.243     albertel 3005:         } elsif ($env{'form.mode'} eq 'edit') {
                   3006:             my $form = $env{'form.form'};
                   3007:             my $element = $env{'form.element'};
                   3008:             my $titleelement = $env{'form.titleelement'};
1.191     albertel 3009: 	    my $changetitle;
                   3010: 	    if (!$titleelement) {
                   3011: 		$changetitle='function changeTitle(val) {}';
                   3012: 	    } else {
                   3013: 		    $changetitle=<<END;
                   3014: function changeTitle(val) {
                   3015:     if (parent.targetwin.document) {
                   3016:         parent.targetwin.document.forms["$form"].elements["$titleelement"].value=val;
                   3017:     } else {
                   3018: 	var url = 'forms[\"$form\"].elements[\"$titleelement\"].value';
                   3019:         alert("Unable to transfer data to "+url);
                   3020:     }
                   3021: }
                   3022: END
                   3023:             }
                   3024: 
1.257     albertel 3025:             $js.=<<SCRIPT;
1.125     matthew  3026: <script type="text/javascript">
1.313     bisitz   3027: // <![CDATA[
1.125     matthew  3028: function select_data(title,url) {
                   3029:     changeURL(url);
1.191     albertel 3030:     changeTitle(title);
1.150     matthew  3031:     parent.close();
1.125     matthew  3032: }
1.191     albertel 3033: $changetitle
1.125     matthew  3034: function changeURL(val) {
1.150     matthew  3035:     if (parent.targetwin.document) {
                   3036:         parent.targetwin.document.forms["$form"].elements["$element"].value=val;
1.125     matthew  3037:     } else {
                   3038: 	var url = 'forms[\"$form\"].elements[\"$element\"].value';
                   3039:         alert("Unable to transfer data to "+url);
                   3040:     }
                   3041: }
1.313     bisitz   3042: // ]]>
1.125     matthew  3043: </script>
                   3044: SCRIPT
                   3045:         }
                   3046:     }
1.288     albertel 3047:     my $inhibit_menu = "&".&Apache::loncommon::inhibit_menu_check();
1.267     www      3048:     $js.=<<SCRIPT if $env{'form.catalogmode'} eq 'import';
1.125     matthew  3049: <script type="text/javascript">
1.313     bisitz   3050: // <![CDATA[
1.158     matthew  3051:     function queue(checkbox_num,val) {
1.185     matthew  3052:         if (document.forms.results.returnvalues.length != "undefined" &&
                   3053:             typeof(document.forms.results.returnvalues.length) == "number") {
                   3054:             if (document.forms.results.returnvalues[checkbox_num].checked) {
1.270     www      3055:                 parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b';
1.185     matthew  3056:             } else {
1.270     www      3057:                 parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b';
1.185     matthew  3058:             }
1.150     matthew  3059:         } else {
1.185     matthew  3060:             if (document.forms.results.returnvalues.checked) {
1.270     www      3061:                 parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b';
1.185     matthew  3062:             } else {
1.270     www      3063:                 parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b';
1.185     matthew  3064:             }
1.150     matthew  3065:         }
1.125     matthew  3066:     }
                   3067:     function select_group() {
1.150     matthew  3068: 	parent.window.location=
1.323     bisitz   3069:     "/adm/groupsort?mode=$env{'form.mode'}&catalogmode=import$inhibit_menu&acts="+
1.270     www      3070: 	    parent.statusframe.document.forms.statusform.elements.acts.value;
1.125     matthew  3071:     }
1.313     bisitz   3072: // ]]>
1.125     matthew  3073: </script>
                   3074: SCRIPT
1.256     albertel 3075: 
1.257     albertel 3076:     my $start_page  = &Apache::loncommon::start_page(undef,$js,
1.331     www      3077: 						     {'only_body' =>1,
                   3078:                                                       'add_wishlist' =>1});
1.258     albertel 3079:     my $result=<<END;
1.257     albertel 3080: $start_page
1.267     www      3081: <form name="results" method="post" action="/adm/searchcat">
1.150     matthew  3082: $importbutton
1.130     matthew  3083: END
1.125     matthew  3084:     return $result;
                   3085: }
                   3086: 
1.150     matthew  3087: sub results_link {
1.309     bisitz   3088:     my $basic_link   = "/adm/searchcat?"."&amp;table=".$env{'form.table'}.
                   3089:         "&amp;persistent_db_id=".$env{'form.persistent_db_id'};
                   3090:     my $results_link = $basic_link."&amp;phase=results".
                   3091:         "&amp;pause=1"."&amp;start=1";
1.150     matthew  3092:     return $results_link;
                   3093: }
                   3094: 
1.146     matthew  3095: ######################################################################
                   3096: ######################################################################
                   3097: sub print_frames_interface {
                   3098:     my $r = shift;
1.309     bisitz   3099:     my $basic_link = "/adm/searchcat?"."&amp;table=".$env{'form.table'}.
                   3100:         "&amp;persistent_db_id=".$env{'form.persistent_db_id'};
                   3101:     my $run_search_link = $basic_link."&amp;phase=run_search";
1.150     matthew  3102:     my $results_link = &results_link();
1.260     albertel 3103:     my $js = <<JS;
                   3104: <script type="text/javascript">
1.313     bisitz   3105: // <![CDATA[
1.260     albertel 3106: var targetwin = opener;
                   3107: var queue = '';
1.313     bisitz   3108: // ]]>
1.260     albertel 3109: </script>
                   3110: JS
1.262     albertel 3111: 
                   3112:     my $start_page =
                   3113:         &Apache::loncommon::start_page('LON-CAPA Digital Library Search Results',
                   3114: 				       $js,
                   3115: 				       {'frameset'    => 1,
                   3116: 					'add_entries' => {
                   3117: 					    'rows' => "150,*",},});
                   3118:     my $end_page =
                   3119:         &Apache::loncommon::end_page({'frameset' => 1});
                   3120: 
1.146     matthew  3121:     my $result = <<"ENDFRAMES";
1.262     albertel 3122: $start_page
1.146     matthew  3123:     <frame name="statusframe"  src="$run_search_link">
                   3124:     <frame name="resultsframe" src="$results_link">
1.262     albertel 3125: $end_page
1.146     matthew  3126: ENDFRAMES
                   3127: 
                   3128:     $r->print($result);
                   3129:     return;
                   3130: }
                   3131: 
                   3132: ######################################################################
                   3133: ######################################################################
1.125     matthew  3134: 
1.224     matthew  3135: sub has_stat_data {
                   3136:     my ($values) = @_;
                   3137:     if ( (defined($values->{'count'})      && $values->{'count'}      ne '') ||
                   3138:          (defined($values->{'stdno'})      && $values->{'stdno'}      ne '') ||
                   3139:          (defined($values->{'disc'})       && $values->{'disc'}       ne '') ||
                   3140:          (defined($values->{'avetries'})   && $values->{'avetries'}   ne '') ||
                   3141:          (defined($values->{'difficulty'}) && $values->{'difficulty'} ne '')) {
                   3142:         return 1;
                   3143:     }
                   3144:     return 0;
                   3145: }
                   3146: 
                   3147: sub statfields {
                   3148:     return ('count','stdno','disc','avetries','difficulty');
                   3149: }
                   3150: 
                   3151: sub has_eval_data {
                   3152:     my ($values) = @_;
                   3153:     if ( (defined($values->{'clear'})     && $values->{'clear'}     ne '') ||
                   3154:          (defined($values->{'technical'}) && $values->{'technical'} ne '') ||
                   3155:          (defined($values->{'correct'})   && $values->{'correct'}   ne '') ||
                   3156:          (defined($values->{'helpful'})   && $values->{'helpful'}   ne '') ||
                   3157:          (defined($values->{'depth'})     && $values->{'depth'}     ne '')) {
                   3158:         return 1;
                   3159:     }
                   3160:     return 0;
                   3161: }
                   3162: 
                   3163: sub evalfields { 
                   3164:     return ('clear','technical','correct','helpful','depth');
                   3165: }
                   3166: 
                   3167: ######################################################################
                   3168: ######################################################################
                   3169: 
1.332     bisitz   3170: sub display_tools {
                   3171:     my ($title, $jumpurl) = @_;
                   3172:     my $result;
                   3173:     # Metadata
                   3174:     $result.=
                   3175:         &Apache::loncommon::modal_link(
                   3176:             $jumpurl.'.meta?inhibitmenu=yes',
                   3177:             '<img class="LC_icon" src="/res/adm/pages/catalog.png" alt="Info" />',
                   3178:             500,500,'_blank',undef,&mt('Metadata'));
                   3179:     # Stored Links
                   3180:     $result.=
                   3181:         ' <a href="javascript:;"'.
                   3182:         ' onclick="set_wishlistlink('."'$title','$jumpurl'".')" '.
                   3183:         'title="'.&mt('Save a link for this resource in your personal Stored Links repository').'">'.
                   3184:         '<img class="LC_icon" src="/res/adm/pages/wishlist.png" '.
                   3185:         'alt="Stored Links" style="width:22px;"/></a>';
                   3186:     return $result;
                   3187: }
                   3188: 
                   3189: ######################################################################
                   3190: ######################################################################
                   3191: 
1.122     matthew  3192: =pod 
                   3193: 
                   3194: =item Metadata Viewing Functions
                   3195: 
                   3196: Output is a HTML-ified string.
1.204     matthew  3197: 
1.122     matthew  3198: Input arguments are title, author, subject, url, keywords, version,
                   3199: notes, short abstract, mime, language, creation date,
1.126     matthew  3200: last revision date, owner, copyright, hostname, and
1.122     matthew  3201: extra custom metadata to show.
                   3202: 
                   3203: =over 4
                   3204: 
                   3205: =item &detailed_citation_view() 
                   3206: 
                   3207: =cut
                   3208: 
                   3209: ######################################################################
                   3210: ######################################################################
1.50      harris41 3211: sub detailed_citation_view {
1.150     matthew  3212:     my ($prefix,%values) = @_;
1.218     matthew  3213:     my $result;
1.247     www      3214:     my $jumpurl=$values{'url'};
1.275     albertel 3215:     $jumpurl=~s|^/ext/|http://|;
1.332     bisitz   3216:     $result .=
                   3217:         '<b>'.$prefix.
1.312     bisitz   3218:         '<img src="'.&Apache::loncommon::icon($values{'url'}).'" alt="" />'.'&nbsp;'.
1.288     albertel 3219:         '<a href="'.$jumpurl.'?inhibitmenu=yes" '.
1.325     wenzelju 3220:         'target="preview">'.$values{'title'}."</a></b>\n".
1.332     bisitz   3221:         &display_tools($values{'title'}, $jumpurl).
                   3222:         "<p>\n".
                   3223:         '<b>'.$values{'author'}.'</b>,'.
1.218     matthew  3224:         ' <i>'.$values{'owner'}.'</i><br />';
                   3225:     foreach my $field 
                   3226:         (
1.223     matthew  3227:          { name=>'url',
                   3228:            translate => '<b>URL:</b>&nbsp;[_1]',
                   3229:            special => 'url link',},
1.218     matthew  3230:          { name=>'subject',
                   3231:            translate => '<b>Subject:</b>&nbsp;[_1]',},
                   3232:          { name=>'keywords',
                   3233:            translate => '<b>Keywords:</b>&nbsp;[_1]',},
                   3234:          { name=>'notes',
                   3235:            translate => '<b>Notes:</b>&nbsp;[_1]',},
                   3236:          { name=>'mimetag',
                   3237:            translate => '<b>MIME Type:</b>&nbsp;[_1]',},
                   3238:          { name=>'standards',
                   3239:            translate => '<b>Standards:</b>[_1]',},
                   3240:          { name=>'copyrighttag',
                   3241:            translate => '<b>Copyright/Distribution:</b>&nbsp;[_1]',},
1.223     matthew  3242:          { name=>'count',
1.225     matthew  3243:            format => "%d",
1.223     matthew  3244:            translate => '<b>Access Count:</b>&nbsp;[_1]',},
1.218     matthew  3245:          { name=>'stdno',
1.225     matthew  3246:            format => "%d",
1.218     matthew  3247:            translate => '<b>Number of Students:</b>&nbsp;[_1]',},
                   3248:          { name=>'avetries',
1.225     matthew  3249:            format => "%.2f",
1.218     matthew  3250:            translate => '<b>Average Tries:</b>&nbsp;[_1]',},
                   3251:          { name=>'disc',
1.225     matthew  3252:            format => "%.2f",
1.218     matthew  3253:            translate => '<b>Degree of Discrimination:</b>&nbsp;[_1]',},
                   3254:          { name=>'difficulty',
1.225     matthew  3255:            format => "%.2f",
1.218     matthew  3256:            translate => '<b>Degree of Difficulty:</b>&nbsp;[_1]',},
                   3257:          { name=>'clear',
1.225     matthew  3258:            format => "%.2f",
1.218     matthew  3259:            translate => '<b>Clear:</b>&nbsp;[_1]',},
                   3260:          { name=>'depth',
1.225     matthew  3261:            format => "%.2f",
1.218     matthew  3262:            translate => '<b>Depth:</b>&nbsp;[_1]',},
                   3263:          { name=>'helpful',
1.225     matthew  3264:            format => "%.2f",
1.218     matthew  3265:            translate => '<b>Helpful:</b>&nbsp;[_1]',},
                   3266:          { name=>'correct',
1.225     matthew  3267:            format => "%.2f",
1.224     matthew  3268:            translate => '<b>Correct:</b>&nbsp;[_1]',},
1.218     matthew  3269:          { name=>'technical',
1.225     matthew  3270:            format => "%.2f",
1.218     matthew  3271:            translate => '<b>Technical:</b>&nbsp;[_1]',},
1.225     matthew  3272:          { name=>'comefrom_list',
                   3273:            type => 'list',
                   3274:            translate => 'Resources that lead up to this resource in maps',},
                   3275:          { name=>'goto_list',
                   3276:            type => 'list',
                   3277:            translate => 'Resources that follow this resource in maps',},
1.226     matthew  3278:          { name=>'sequsage_list',
1.225     matthew  3279:            type => 'list',
                   3280:            translate => 'Resources using or importing resource',},
1.218     matthew  3281:          ) {
1.225     matthew  3282:         next if (! exists($values{$field->{'name'}}) ||
                   3283:                  $values{$field->{'name'}} eq '');
                   3284:         if (exists($field->{'type'}) && $field->{'type'} eq 'list') {
1.267     www      3285:             $result .= '<b>'.&mt($field->{'translate'}).'</b>';
1.225     matthew  3286:             foreach my $item (split(',',$values{$field->{'name'}})){
1.287     albertel 3287:                 $item = &Apache::lonnet::clutter($item);
1.319     bisitz   3288:                 $result .= '<br />'.&display_url($item,1).'<br />';
1.225     matthew  3289:             }
                   3290:         } elsif (exists($field->{'format'}) && $field->{'format'} ne ''){
                   3291:             $result.= &mt($field->{'translate'},
                   3292:                           sprintf($field->{'format'},
1.230     matthew  3293:                                   $values{$field->{'name'}}))."<br />\n";
1.225     matthew  3294:         } else {
1.223     matthew  3295:             if ($field->{'special'} eq 'url link') {
1.319     bisitz   3296:                 $result .= '<br />'.&display_url($jumpurl,1).'<br />';
1.223     matthew  3297:             } else {
                   3298:                 $result.= &mt($field->{'translate'},
                   3299:                               $values{$field->{'name'}});
                   3300:             }
                   3301:             $result .= "<br />\n";
1.225     matthew  3302:         }
1.223     matthew  3303:     }
                   3304:     $result .= "</p>";
                   3305:     if (exists($values{'extrashow'}) && $values{'extrashow'} ne '') {
                   3306:         $result .= '<p>'.$values{'extrashow'}.'</p>';
                   3307:     }
                   3308:     if (exists($values{'shortabstract'}) && $values{'shortabstract'} ne '') {
                   3309:         $result .= '<p>'.$values{'shortabstract'}.'</p>';
1.218     matthew  3310:     }
1.50      harris41 3311:     return $result;
1.222     matthew  3312: }
                   3313: 
1.255     www      3314: sub detailed_citation_preview {
                   3315:     my ($prefix,%values)=@_;
1.312     bisitz   3316:     return &detailed_citation_view($prefix,%values).
1.255     www      3317:            '</td><td>'.
1.312     bisitz   3318:            &Apache::lonindexer::showpreview($values{'url'});
1.255     www      3319: }
                   3320: 
                   3321: 
1.222     matthew  3322: ######################################################################
                   3323: ######################################################################
                   3324: 
1.122     matthew  3325: =pod 
                   3326: 
                   3327: =item &summary_view() 
                   3328: 
                   3329: =cut
                   3330: ######################################################################
                   3331: ######################################################################
1.50      harris41 3332: sub summary_view {
1.150     matthew  3333:     my ($prefix,%values) = @_;
1.192     albertel 3334:     my $icon=&Apache::loncommon::icon($values{'url'});
1.312     bisitz   3335:     my $result=qq{$prefix<img src="$icon" alt="" />};
1.244     albertel 3336:     if (exists($env{'form.sortfield'}) && 
                   3337:         $env{'form.sortfield'} !~ /^(default|
1.241     matthew  3338:                                      author|
                   3339:                                      url|
                   3340:                                      title|
                   3341:                                      owner|
                   3342:                                      lastrevisiondate|
                   3343:                                      copyright)$/x) {
1.244     albertel 3344:         my $tmp = $values{$env{'form.sortfield'}};
1.241     matthew  3345:         if (! defined($tmp)) { $tmp = 'undefined'; }
                   3346:         $result .= '&nbsp;'.$tmp.'&nbsp;';
                   3347:     }
1.247     www      3348:     my $jumpurl=$values{'url'};
1.287     albertel 3349:     $jumpurl=~s|^/ext/|http://|;
1.319     bisitz   3350:     my $link = '<br />'.&display_url($jumpurl,1).'<br />';
1.332     bisitz   3351:     $result .=
                   3352:         '<a href="'.$jumpurl.'?inhibitmenu=yes"'.
                   3353:         ' target="preview">'.$values{'title'}.'</a>'.
                   3354:         &display_tools($values{'title'}, $jumpurl).<<END;
1.325     wenzelju 3355: <br />
1.312     bisitz   3356: $link<br />
1.241     matthew  3357: $values{'author'}, $values{'owner'} -- $values{'lastrevisiondate'}<br />
1.126     matthew  3358: $values{'copyrighttag'}<br />
                   3359: $values{'extrashow'}
1.50      harris41 3360: END
                   3361:     return $result;
                   3362: }
                   3363: 
1.255     www      3364: sub summary_preview {
                   3365:     my ($prefix,%values)=@_;
1.312     bisitz   3366:     return &summary_view($prefix,%values).
1.255     www      3367:            '</td><td>'.
1.312     bisitz   3368:            &Apache::lonindexer::showpreview($values{'url'});
1.255     www      3369: }
                   3370: 
1.122     matthew  3371: ######################################################################
                   3372: ######################################################################
                   3373: 
                   3374: =pod 
                   3375: 
1.150     matthew  3376: =item &compact_view() 
                   3377: 
                   3378: =cut
                   3379: 
                   3380: ######################################################################
                   3381: ######################################################################
                   3382: sub compact_view {
                   3383:     my ($prefix,%values) = @_;
1.247     www      3384:     my $jumpurl=$values{'url'};
1.287     albertel 3385:     $jumpurl=~s|^/ext/|http://|;
                   3386: 
1.319     bisitz   3387:     my $link = &display_url($jumpurl,1);
1.287     albertel 3388:     
1.223     matthew  3389:     my $result = 
1.306     bisitz   3390:         $prefix.'<img src="'.&Apache::loncommon::icon($values{'url'}).'" alt="" />';
1.244     albertel 3391:     if (exists($env{'form.sortfield'}) && 
                   3392:         $env{'form.sortfield'} !~ /^(default|author|url|title)$/) {
                   3393:         my $tmp = $values{$env{'form.sortfield'}};
1.241     matthew  3394:         if (! defined($tmp)) { $tmp = 'undefined'; }
                   3395:         $result .= '&nbsp;'.$tmp.'&nbsp;';
                   3396:     }
1.287     albertel 3397:     $jumpurl = &HTML::Entities::encode($jumpurl,'<>&"');
                   3398:     $result.=' <span class="LC_nobreak">'.
1.288     albertel 3399: 	'<a href="'.$jumpurl.'?inhibitmenu=yes" target="preview">'.
1.287     albertel 3400:         &HTML::Entities::encode($values{'title'},'<>&"').'</a></span> '.
1.332     bisitz   3401:         &display_tools($values{'title'}, $jumpurl).
1.312     bisitz   3402: 	$link.' <b>'.$values{'author'}.'</b> ('.$values{'domain'}.')';
1.150     matthew  3403:     return $result;
                   3404: }
                   3405: 
1.287     albertel 3406: sub display_url {
1.319     bisitz   3407:     my ($url,$skiplast) = @_;
1.287     albertel 3408:     my $link;
                   3409:     if ($url=~m|^/ext/|) {
                   3410: 	$url=~s|^/ext/|http://|;
                   3411: 	$link='<span class="LC_filename">'.$url.'</span>';
                   3412:     } elsif ($url=~m{^(http://|/uploaded/)}) {
                   3413: 	$link='<span class="LC_filename">'.$url.'</span>';
                   3414:     } else {
1.319     bisitz   3415:         $link=&Apache::lonhtmlcommon::crumbs(
                   3416:                   $url,
                   3417:                   'preview',
                   3418:                   '',
                   3419:                   (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),
                   3420:                   $skiplast).' ';
1.287     albertel 3421:     }
                   3422:     return $link;
                   3423: }
1.150     matthew  3424: 
                   3425: ######################################################################
                   3426: ######################################################################
                   3427: 
                   3428: =pod 
                   3429: 
1.122     matthew  3430: =item &fielded_format_view() 
                   3431: 
                   3432: =cut
                   3433: 
                   3434: ######################################################################
                   3435: ######################################################################
1.50      harris41 3436: sub fielded_format_view {
1.150     matthew  3437:     my ($prefix,%values) = @_;
1.192     albertel 3438:     my $icon=&Apache::loncommon::icon($values{'url'});
1.222     matthew  3439:     my %Translated = &Apache::lonmeta::fieldnames();
1.247     www      3440:     my $jumpurl=$values{'url'};
1.275     albertel 3441:     $jumpurl=~s|^/ext/|http://|;
1.247     www      3442: 
1.50      harris41 3443:     my $result=<<END;
1.312     bisitz   3444: $prefix <img src="$icon" alt="" />
1.222     matthew  3445: <dl>
                   3446: <dt>URL:</dt>
1.288     albertel 3447:     <dd><a href="$jumpurl?inhibitmenu=yes" 
1.325     wenzelju 3448:          target='preview'>$values{'url'}</a>
1.50      harris41 3449: END
1.332     bisitz   3450:     $result .=
                   3451:         &display_tools($values{'title'}, $jumpurl).'
                   3452:     </dd>';
1.239     matthew  3453:     foreach my $field ('title','author','domain','subject','keywords','notes',
1.222     matthew  3454:                        'mimetag','language','creationdate','lastrevisiondate',
                   3455:                        'owner','copyrighttag','hostname','abstract') {
                   3456:         $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
                   3457:             (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
                   3458:     }
                   3459:     if (&has_stat_data(\%values)) {
                   3460:         foreach my $field (&statfields()) {
                   3461:             $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
                   3462:                 (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
                   3463:         }
                   3464:     }
                   3465:     if (&has_eval_data(\%values)) {
                   3466:         foreach my $field (&evalfields()) {
                   3467:             $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
                   3468:                 (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
                   3469:         }
                   3470:     }
                   3471:     $result .= "</dl>\n";
                   3472:     $result .= $values{'extrashow'};
1.50      harris41 3473:     return $result;
                   3474: }
                   3475: 
1.122     matthew  3476: ######################################################################
                   3477: ######################################################################
                   3478: 
                   3479: =pod 
                   3480: 
                   3481: =item &xml_sgml_view() 
                   3482: 
                   3483: =back 
                   3484: 
                   3485: =cut
                   3486: 
                   3487: ######################################################################
                   3488: ######################################################################
1.50      harris41 3489: sub xml_sgml_view {
1.150     matthew  3490:     my ($prefix,%values) = @_;
1.222     matthew  3491:     my $xml = '<LonCapaResource>'."\n";
                   3492:     # The usual suspects
1.239     matthew  3493:     foreach my $field ('url','title','author','subject','keywords','notes','domain') {
1.222     matthew  3494:         $xml .= qq{<$field>$values{$field}</$field>}."\n";
                   3495:     }
                   3496:     #
                   3497:     $xml .= "<mimeInfo>\n";
                   3498:     foreach my $field ('mime','mimetag') {
                   3499:         $xml .= qq{<$field>$values{$field}</$field>}."\n";
                   3500:     }
                   3501:     $xml .= "</mimeInfo>\n";
                   3502:     #
                   3503:     $xml .= "<languageInfo>\n";
                   3504:     foreach my $field ('language','languagetag') {
                   3505:         $xml .= qq{<$field>$values{$field}</$field>}."\n";
                   3506:     }
                   3507:     $xml .= "</languageInfo>\n";
                   3508:     #
                   3509:     foreach my $field ('creationdate','lastrevisiondate','owner') {
                   3510:         $xml .= qq{<$field>$values{$field}</$field>}."\n";
                   3511:     }
                   3512:     #
                   3513:     $xml .= "<copyrightInfo>\n";
                   3514:     foreach my $field ('copyright','copyrighttag') {
                   3515:         $xml .= qq{<$field>$values{$field}</$field>}."\n";
                   3516:     }
                   3517:     $xml .= "</copyrightInfo>\n";
                   3518:     $xml .= qq{<repositoryLocation>$values{'hostname'}</repositoryLocation>}.
                   3519:         "\n";
                   3520:     $xml .= qq{<shortabstract>$values{'shortabstract'}</shortabstract>}."\n";
                   3521:     #
                   3522:     if (&has_stat_data(\%values)){
                   3523:         $xml .= "<problemstatistics>\n";
                   3524:         foreach my $field (&statfields()) {
                   3525:             $xml .= qq{<$field>$values{$field}</$field>}."\n";            
                   3526:         }
                   3527:         $xml .= "</problemstatistics>\n";
                   3528:     }
                   3529:     #
                   3530:     if (&has_eval_data(\%values)) {
                   3531:         $xml .= "<evaluation>\n";
                   3532:         foreach my $field (&evalfields) {
                   3533:             $xml .= qq{<$field>$values{$field}</$field>}."\n";            
                   3534:         }
                   3535:         $xml .= "</evaluation>\n";
                   3536:     }    
                   3537:     #
                   3538:     $xml .= "</LonCapaResource>\n";
1.212     matthew  3539:     $xml = &HTML::Entities::encode($xml,'<>&');
1.50      harris41 3540:     my $result=<<END;
1.150     matthew  3541: $prefix
1.56      harris41 3542: <pre>
1.212     matthew  3543: $xml
1.56      harris41 3544: </pre>
1.126     matthew  3545: $values{'extrashow'}
1.50      harris41 3546: END
                   3547:     return $result;
1.60      harris41 3548: }
                   3549: 
1.122     matthew  3550: ######################################################################
                   3551: ######################################################################
                   3552: 
                   3553: =pod 
                   3554: 
                   3555: =item &filled() see if field is filled.
                   3556: 
                   3557: =cut
                   3558: 
                   3559: ######################################################################
                   3560: ######################################################################
1.98      harris41 3561: sub filled {
                   3562:     my ($field)=@_;
                   3563:     if ($field=~/\S/ && $field ne 'any') {
1.204     matthew  3564:         return 1;
                   3565:     } else {
                   3566:         return 0;
1.61      harris41 3567:     }
1.60      harris41 3568: }
                   3569: 
1.122     matthew  3570: ######################################################################
                   3571: ######################################################################
                   3572: 
                   3573: =pod 
                   3574: 
1.228     matthew  3575: =item &output_unparsed_phrase_error()
                   3576: 
                   3577: =cut
                   3578: 
                   3579: ######################################################################
                   3580: ######################################################################
                   3581: sub output_unparsed_phrase_error {
                   3582:     my ($r,$closebutton,$parms,$hidden_fields,$field)=@_;
                   3583:     my $errorstring;
                   3584:     if ($field eq 'basicexp') {
1.312     bisitz   3585:         $errorstring = &mt('Unable to understand the search phrase [_1]. Please modify your search.'
                   3586:                            ,'<i>'.$env{'form.basicexp'}.'</i>');
1.228     matthew  3587:     } else {
1.312     bisitz   3588:         $errorstring = &mt('Unable to understand the search phrase [_1]: [_2]'
                   3589:                            ,'<i>'.$field.'</i>'
                   3590:                            ,$env{'form.'.$field});
1.228     matthew  3591:     }
                   3592:     my $heading = &mt('Unparsed Field');
                   3593:     my $revise  = &mt('Revise search request');
                   3594:     # make query information persistent to allow for subsequent revision
1.256     albertel 3595:     my $start_page = &Apache::loncommon::start_page('Search');
                   3596:     my $end_page   = &Apache::loncommon::end_page();
1.228     matthew  3597:     $r->print(<<ENDPAGE);
1.256     albertel 3598: $start_page
1.228     matthew  3599: <form method="post" action="/adm/searchcat">
                   3600: $hidden_fields
                   3601: $closebutton
                   3602: <hr />
                   3603: <h2>$heading</h2>
1.312     bisitz   3604: <p class="LC_warning">
1.228     matthew  3605: $errorstring
                   3606: </p>
                   3607: <p>
1.309     bisitz   3608: <a href="/adm/searchcat?$parms&amp;persistent_db_id=$env{'form.persistent_db_id'}">$revise</a>
1.228     matthew  3609: </p>
1.256     albertel 3610: $end_page
1.228     matthew  3611: ENDPAGE
                   3612: }
                   3613: 
                   3614: ######################################################################
                   3615: ######################################################################
                   3616: 
                   3617: =pod 
                   3618: 
1.122     matthew  3619: =item &output_blank_field_error()
                   3620: 
1.151     matthew  3621: Output a complete page that indicates the user has not filled in enough
                   3622: information to do a search.
                   3623: 
                   3624: Inputs: $r (Apache request handle), $closebutton, $parms.
                   3625: 
                   3626: Returns: nothing
                   3627: 
                   3628: $parms is extra information to include in the 'Revise search request' link.
                   3629: 
1.122     matthew  3630: =cut
                   3631: 
                   3632: ######################################################################
                   3633: ######################################################################
1.98      harris41 3634: sub output_blank_field_error {
1.196     matthew  3635:     my ($r,$closebutton,$parms,$hidden_fields)=@_;
1.312     bisitz   3636:     my $errormsg = &mt('You did not fill in enough information for the search to be started. You need to fill in relevant fields on the search page in order for a query to be processed.');
1.228     matthew  3637:     my $revise = &mt('Revise Search Request');
1.315     bisitz   3638:     my $heading = &mt('Unactionable Search Query');
1.256     albertel 3639:     my $start_page = &Apache::loncommon::start_page('Search');
                   3640:     my $end_page   = &Apache::loncommon::end_page();
1.315     bisitz   3641:     if ($closebutton) {
                   3642:         $closebutton = '<p>'.$closebutton.'</p><hr />';
                   3643:     } else {
                   3644:         &Apache::lonhtmlcommon::add_breadcrumb
                   3645:             ({href=>'',
                   3646:               text=>$heading,});
                   3647:         $start_page .= &Apache::lonhtmlcommon::breadcrumbs();
                   3648:     }
                   3649: 
1.228     matthew  3650:     $r->print(<<ENDPAGE);
1.256     albertel 3651: $start_page
1.98      harris41 3652: <form method="post" action="/adm/searchcat">
1.145     matthew  3653: $hidden_fields
1.98      harris41 3654: $closebutton
1.315     bisitz   3655: </form>
1.228     matthew  3656: <h2>$heading</h2>
1.312     bisitz   3657: <p class="LC_warning">
1.228     matthew  3658: $errormsg
                   3659: </p>
                   3660: <p>
1.315     bisitz   3661: <a href="/adm/searchcat?$parms&amp;persistent_db_id=$env{'form.persistent_db_id'}">$revise</a>
1.98      harris41 3662: </p>
1.256     albertel 3663: $end_page
1.228     matthew  3664: ENDPAGE
                   3665:     return;
1.98      harris41 3666: }
                   3667: 
1.122     matthew  3668: ######################################################################
                   3669: ######################################################################
                   3670: 
                   3671: =pod 
                   3672: 
                   3673: =item &output_date_error()
                   3674: 
                   3675: Output a full html page with an error message.
                   3676: 
1.145     matthew  3677: Inputs: 
                   3678: 
                   3679:     $r, the request pointer.
                   3680:     $message, the error message for the user.
                   3681:     $closebutton, the specialized close button needed for groupsearch.
                   3682: 
1.122     matthew  3683: =cut
                   3684: 
                   3685: ######################################################################
                   3686: ######################################################################
1.60      harris41 3687: sub output_date_error {
1.196     matthew  3688:     my ($r,$message,$closebutton,$hidden_fields)=@_;
1.60      harris41 3689:     # make query information persistent to allow for subsequent revision
1.256     albertel 3690:     my $start_page = &Apache::loncommon::start_page('Search');
                   3691:     my $end_page   = &Apache::loncommon::end_page();
1.312     bisitz   3692:     my $heading = &mt('Error');
1.122     matthew  3693:     $r->print(<<RESULTS);
1.256     albertel 3694: $start_page
1.60      harris41 3695: <form method="post" action="/adm/searchcat">
1.145     matthew  3696: $hidden_fields
1.60      harris41 3697: <input type='button' value='Revise search request'
1.313     bisitz   3698: onclick='this.form.submit();' />
1.60      harris41 3699: $closebutton
1.312     bisitz   3700: </form>
1.98      harris41 3701: <hr />
1.312     bisitz   3702: <h3>$heading</h3>
                   3703: <p class="LC_error">
1.60      harris41 3704: $message
                   3705: </p>
1.256     albertel 3706: $end_page
1.60      harris41 3707: RESULTS
1.101     harris41 3708: }
                   3709: 
1.122     matthew  3710: ######################################################################
                   3711: ######################################################################
                   3712: 
                   3713: =pod 
                   3714: 
                   3715: =item &start_fresh_session()
                   3716: 
1.142     matthew  3717: Cleans the global %groupsearch_db by removing all fields which begin with
1.122     matthew  3718: 'pre_' or 'store'.
                   3719: 
                   3720: =cut
                   3721: 
                   3722: ######################################################################
                   3723: ######################################################################
1.101     harris41 3724: sub start_fresh_session {
1.142     matthew  3725:     delete $groupsearch_db{'mode_catalog'};
                   3726:     foreach (keys %groupsearch_db) {
1.101     harris41 3727:         if ($_ =~ /^pre_/) {
1.142     matthew  3728:             delete $groupsearch_db{$_};
1.101     harris41 3729:         }
                   3730:         if ($_ =~ /^store/) {
1.142     matthew  3731: 	    delete $groupsearch_db{$_};
1.101     harris41 3732: 	}
1.109     harris41 3733:     }
1.3       harris41 3734: }
1.1       www      3735: 
                   3736: 1;
1.162     www      3737: 
                   3738: sub cleanup {
1.163     www      3739:     if (tied(%groupsearch_db)) {
                   3740:         unless (untie(%groupsearch_db)) {
                   3741: 	  &Apache::lonnet::logthis('Failed cleanup searchcat: groupsearch_db');
                   3742:         }
                   3743:     }
1.167     www      3744:     &untiehash();
1.162     www      3745:     &Apache::lonmysql::disconnect_from_db();
1.252     albertel 3746:     return OK;
1.162     www      3747: }
1.98      harris41 3748: 
1.1       www      3749: __END__
1.105     harris41 3750: 
1.121     matthew  3751: =pod
1.105     harris41 3752: 
1.121     matthew  3753: =back 
1.105     harris41 3754: 
                   3755: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.