Diff for /loncom/interface/lonsearchcat.pm between versions 1.150 and 1.196

version 1.150, 2002/08/01 14:11:57 version 1.196, 2003/12/22 22:40:37
Line 59  search (on a server basis) is displayed Line 59  search (on a server basis) is displayed
 ###############################################################################  ###############################################################################
 ###############################################################################  ###############################################################################
   
 ###############################################################################  
 ##                                                                           ##  
 ## ORGANIZATION OF THIS PERL MODULE                                          ##  
 ##                                                                           ##  
 ## 1. Modules used by this module                                            ##  
 ## 2. Variables used throughout the module                                   ##  
 ## 3. handler subroutine called via Apache and mod_perl                      ##  
 ## 4. Other subroutines                                                      ##  
 ##                                                                           ##  
 ###############################################################################  
   
 package Apache::lonsearchcat;  package Apache::lonsearchcat;
   
 # ------------------------------------------------- modules used by this module  
 use strict;  use strict;
 use Apache::Constants qw(:common);  use Apache::Constants qw(:common :http);
 use Apache::lonnet();  use Apache::lonnet();
 use Apache::File();  use Apache::File();
 use CGI qw(:standard);  use CGI qw(:standard);
 use Text::Query;  use Text::Query;
 use DBI;  
 use GDBM_File;  use GDBM_File;
 use Apache::loncommon();  use Apache::loncommon();
 use Apache::lonmysql();  use Apache::lonmysql();
   use Apache::lonlocal;
 # ---------------------------------------- variables used throughout the module  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   ##
 =pod   ## Global variables
   ##
 =item Global variables  
   
 =over 4  
   
 =item $importbutton  
   
 button to take the select results and go to group sorting  
   
 =item %groupsearch_db     
   
 Database hash used to save values for the groupsearch RAT interface.  
   
 =item $diropendb   
   
 The full path to the (temporary) search database file.  This is set and  
 used in &handler() and is also used in &output_results().  
   
 =item %Views  
   
 Hash which associates an output view description with the function  
 that produces it.  Adding a new view type should be as easy as  
 adding a line to the definition of this hash and making sure the function  
 takes the proper parameters.  
   
 =back   
   
 =cut  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   my %groupsearch_db;  # Database hash used to save values for the 
 # -- dynamically rendered interface components                       # groupsearch RAT interface.
 my $importbutton; # button to take the selected results and go to group sorting  my %persistent_db;   # gdbm hash which holds data which is supposed to
                        # persist across calls to lonsearchcat.pm
 # -- miscellaneous variables  ## %Views:
 my %groupsearch_db;     # database hash  ## Hash which associates an output view description with the function
 my $diropendb = "";    # db file  ## that produces it.
 #             View Description           Function Pointer  #             View Description/Name      Function Pointer
 my %Views = ("Detailed Citation View" => \&detailed_citation_view,  my %Views = ("Detailed Citation View" => \&detailed_citation_view,
              "Summary View"           => \&summary_view,               "Summary View"           => \&summary_view,
              "Fielded Format"         => \&fielded_format_view,               "Fielded Format"         => \&fielded_format_view,
              "XML/SGML"               => \&xml_sgml_view,               "XML/SGML"               => \&xml_sgml_view,
              "Compact View"           => \&compact_view);               "Compact View"           => \&compact_view);
 my %persistent_db;  
 my $hidden_fields;  
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &handler() - main handler invoked by httpd child  
   
 =item Variables  
   
 =over 4  
   
 =item $hidden  
   
 holds 'hidden' html forms  
   
 =item $scrout  
   
 string that holds portions of the screen output  
   
 =back   
   
 =cut  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub handler {  sub handler {
     my $r = shift;      my $r = shift;
       &set_defaults();
     #      #
       # set form defaults
       #
       my $hidden_fields;# Hold all the hidden fields used to keep track
                         # of the search system state
       my $importbutton; # button to take the selected results and go to group 
                         # sorting
       my $diropendb;    # The full path to the (temporary) search database file.
                         # This is set and used in &handler() and is also used in 
                         # &output_results().
       my $bodytag;  # LON-CAPA standard body tag, gotten from 
                     # &Apache::lonnet::bodytag. 
                     # No title, no table, just a <body> tag.
   
       my $loaderror=&Apache::lonnet::overloaderror($r);
       if ($loaderror) { return $loaderror; }
   
     my $closebutton;  # button that closes the search window       my $closebutton;  # button that closes the search window 
                       # This button is different for the RAT compared to                        # This button is different for the RAT compared to
                       # normal invocation.                        # normal invocation.
     #      #
     $r->content_type('text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
     return OK if $r->header_only;      return OK if $r->header_only;
       ##
       ## Prevent caching of the search interface window.  Hopefully this means
       ## we will get the launch=1 passed in a little more.
       &Apache::loncommon::no_cache($r);
     ##       ## 
     ## Pick up form fields passed in the links.      ## Pick up form fields passed in the links.
     ##      ##
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
              ['catalogmode','launch','acts','mode','form','element','pause',               ['catalogmode','launch','acts','mode','form','element','pause',
               'phase','persistent_db_id','table','start','show']);                'phase','persistent_db_id','table','start','show',
                 'cleargroupsort','titleelement']);
     ##      ##
     ## The following is a trick - we wait a few seconds if asked to so      ## The following is a trick - we wait a few seconds if asked to so
     ##     the daemon running the search can get ahead of the daemon      ##     the daemon running the search can get ahead of the daemon
Line 184  sub handler { Line 141  sub handler {
     ##     this once, so the pause indicator is deleted      ##     this once, so the pause indicator is deleted
     ##      ##
     if (exists($ENV{'form.pause'})) {      if (exists($ENV{'form.pause'})) {
         sleep(3);          sleep(1);
         delete($ENV{'form.pause'});          delete($ENV{'form.pause'});
     }      }
     ##      ##
     ## Initialize global variables      ## Initialize global variables
     ##      ##
     my $domain  = $r->dir_config('lonDefDomain');      my $domain  = $r->dir_config('lonDefDomain');
     $diropendb= "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain).      $diropendb= "/home/httpd/perl/tmp/$ENV{'user.domain'}_$ENV{'user.name'}_searchcat.db";
             "\_".&Apache::lonnet::escape($ENV{'user.name'})."_searchcat.db";  
     #      #
     # set the name of the persistent database      # set the name of the persistent database
     #          $ENV{'form.persistent_db_id'} can only have digits in it.      #          $ENV{'form.persistent_db_id'} can only have digits in it.
Line 201  sub handler { Line 157  sub handler {
         ($ENV{'form.launch'} eq '1')) {          ($ENV{'form.launch'} eq '1')) {
         $ENV{'form.persistent_db_id'} = time;          $ENV{'form.persistent_db_id'} = time;
     }      }
       $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
     my $persistent_db_file = "/home/httpd/perl/tmp/".      my $persistent_db_file = "/home/httpd/perl/tmp/".
         &Apache::lonnet::escape($domain).          &Apache::lonnet::escape($domain).
             '_'.&Apache::lonnet::escape($ENV{'user.name'}).              '_'.&Apache::lonnet::escape($ENV{'user.name'}).
                 '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db';                  '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db';
     ##      ##
     if (! &get_persistent_form_data($r,$persistent_db_file)) {      if (! &get_persistent_form_data($persistent_db_file)) {
         if ($ENV{'form.phase'} =~ /(run_search|results)/) {          if ($ENV{'form.phase'} =~ /(run_search|results)/) {
             &Apache::lonnet::logthis("lonsearchcat:Unable to recover data ".              &Apache::lonnet::logthis("lonsearchcat:Unable to recover data ".
                                      "from $persistent_db_file");                                       "from $persistent_db_file");
             $r->print(<<END);              $r->print(<<END);
 <html>  <html>
 <head><title>LON-CAPA Search Error</title></head>  <head><title>LON-CAPA Search Error</title></head>
 <body>  $bodytag
 We were unable to retrieve data describing your search.  This is a serious  We were unable to retrieve data describing your search.  This is a serious
 error and has been logged.  Please alert your LON-CAPA administrator.  error and has been logged.  Please alert your LON-CAPA administrator.
 </body>  </body>
Line 226  END Line 183  END
     ## Clear out old values from groupsearch database      ## Clear out old values from groupsearch database
     ##      ##
     untie %groupsearch_db if (tied(%groupsearch_db));      untie %groupsearch_db if (tied(%groupsearch_db));
     if ($ENV{'form.launch'} eq '1' &&       if (($ENV{'form.cleargroupsort'} eq '1') || 
         ($ENV{'form.catalogmode'} eq 'groupsearch') &&           (($ENV{'form.launch'} eq '1') && 
         ($ENV{'form.phase'} eq 'results')) {           ($ENV{'form.catalogmode'} eq 'groupsearch'))) {
  if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {   if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {
     &start_fresh_session();      &start_fresh_session();
     untie %groupsearch_db;      untie %groupsearch_db;
               delete($ENV{'form.cleargroupsort'});
  } else {   } else {
     $r->print('<html><head></head><body>Unable to tie hash to db '.              # This is a stupid error to give to the user.  
       'file</body></html>');              # It really tells them nothing.
       $r->print('<html><head></head>'.$bodytag.
                         'Unable to tie hash to db file</body></html>');
     return OK;      return OK;
  }   }
     }      }
Line 255  END Line 215  END
         $hidden_fields .= '<input type="hidden" name="element" value="'.          $hidden_fields .= '<input type="hidden" name="element" value="'.
                 $ENV{'form.element'}.'" />'."\n";                  $ENV{'form.element'}.'" />'."\n";
     }      }
       if (exists($ENV{'form.titleelement'})) {
           $hidden_fields .= '<input type="hidden" name="titleelement" value="'.
                   $ENV{'form.titleelement'}.'" />'."\n";
       }
     if (exists($ENV{'form.mode'})) {      if (exists($ENV{'form.mode'})) {
         $hidden_fields .= '<input type="hidden" name="mode" value="'.          $hidden_fields .= '<input type="hidden" name="mode" value="'.
                 $ENV{'form.mode'}.'" />'."\n";                  $ENV{'form.mode'}.'" />'."\n";
Line 298  END Line 262  END
         }          }
     }      }
     $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'}));      $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'}));
       $ENV{'form.show'} = 20 if (! exists($ENV{'form.show'}));
     ##      ##
     ## Switch on the phase      ## Switch on the phase
     ##      ##
     if ($ENV{'form.phase'} eq 'disp_basic') {      if ($ENV{'form.phase'} eq 'disp_basic') {
         &print_basic_search_form($r,$closebutton);          &print_basic_search_form($r,$closebutton,$hidden_fields);
     } elsif ($ENV{'form.phase'} eq 'disp_adv') {      } elsif ($ENV{'form.phase'} eq 'disp_adv') {
         &print_advanced_search_form($r,$closebutton);          &print_advanced_search_form($r,$closebutton,$hidden_fields);
     } elsif ($ENV{'form.phase'} eq 'results') {      } elsif ($ENV{'form.phase'} eq 'results') {
         &display_results($r,$importbutton,$closebutton);          &display_results($r,$importbutton,$closebutton,$diropendb);
     } elsif($ENV{'form.phase'} eq 'run_search') {      } elsif ($ENV{'form.phase'} =~ /^(sort|run_search)$/) {
         my ($query,$customquery,$customshow,$libraries,$pretty_string) =          my ($query,$customquery,$customshow,$libraries,$pretty_string) =
             &get_persistent_data($persistent_db_file,              &get_persistent_data($persistent_db_file,
                  ['query','customquery','customshow',                   ['query','customquery','customshow',
                   'libraries','pretty_string']);                    'libraries','pretty_string']);
         &run_search($r,$query,$customquery,$customshow,          if ($ENV{'form.phase'} eq 'sort') {
                     $libraries,$pretty_string);              &print_sort_form($r,$pretty_string);
           } elsif ($ENV{'form.phase'} eq 'run_search') {
               &run_search($r,$query,$customquery,$customshow,
                           $libraries,$pretty_string);
           }
       } elsif ($ENV{'form.phase'} eq 'course_search') {
           &course_search($r);
     } elsif(($ENV{'form.phase'} eq 'basic_search') ||      } elsif(($ENV{'form.phase'} eq 'basic_search') ||
             ($ENV{'form.phase'} eq 'adv_search')) {              ($ENV{'form.phase'} eq 'adv_search')) {
           $ENV{'form.searchmode'} = 'basic';
           if ($ENV{'form.phase'} eq 'adv_search') {
               $ENV{'form.searchmode'} = 'advanced';
           }
         # Set up table          # Set up table
         if (! defined(&create_results_table())) {          if (! defined(&create_results_table())) {
             $r->print(<<END);              $r->print(<<END);
 <html><head><title>Search Error</title></head>  <html><head><title>Search Error</title></head>
 <body>  $bodytag
 Unable to create table in which to store search results.    Unable to create table in which to store search results.  
 The search has been aborted.  The search has been aborted.
 </body>  </body>
Line 332  END Line 307  END
         if (! &make_form_data_persistent($r,$persistent_db_file)) {          if (! &make_form_data_persistent($r,$persistent_db_file)) {
             $r->print(<<END);              $r->print(<<END);
 <html><head><title>Search Error</title></head>  <html><head><title>Search Error</title></head>
 <body>  $bodytag
 Unable to properly store search information.  The search has been aborted.  Unable to properly store search information.  The search has been aborted.
 </body>  </body>
 </html>  </html>
Line 345  END Line 320  END
             (undef,undef,undef,undef);              (undef,undef,undef,undef);
         my $pretty_string;          my $pretty_string;
         if ($ENV{'form.phase'} eq 'basic_search') {          if ($ENV{'form.phase'} eq 'basic_search') {
             ($query,$pretty_string) = &parse_basic_search($r,$closebutton);              ($query,$pretty_string,$libraries) = 
                   &parse_basic_search($r,$closebutton,$hidden_fields);
         } else {                      # Advanced search          } else {                      # Advanced search
             ($query,$customquery,$customshow,$libraries,$pretty_string)               ($query,$customquery,$customshow,$libraries,$pretty_string) 
                 = &parse_advanced_search($r,$closebutton);                  = &parse_advanced_search($r,$closebutton,$hidden_fields);
             return OK if (! defined($query));              return OK if (! defined($query));
         }          }
         &make_persistent($r,          &make_persistent({ query => $query,
                          { query => $query,  
                            customquery => $customquery,                             customquery => $customquery,
                            customshow => $customshow,                             customshow => $customshow,
                            libraries => $libraries,                             libraries => $libraries,
Line 368  END Line 343  END
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   ##
   ##   Course Search
   ##
   ######################################################################
   ######################################################################
   {   # Scope the course search to avoid global variables
   #
   # Variables For course search
   my %alreadyseen;
   my %hash;
   my $totalfound;
   
   sub course_search {
       my $r=shift;
       my $bodytag=&Apache::loncommon::bodytag('Course Search');
       my $pretty_search_string = '<b>'.$ENV{'form.courseexp'}.'</b>';
       my $search_string = $ENV{'form.courseexp'};
       my @New_Words;
       if ($ENV{'form.crsrelated'}) {
           ($search_string,@New_Words) = &related_version($ENV{'form.courseexp'});
           if (@New_Words) {
               $pretty_search_string .= " with related words: <b>@New_Words</b>.";
           } else {
               $pretty_search_string .= " with no related words.";
           }
       }
       my $fulltext=$ENV{'form.crsfulltext'};
       my @allwords=($search_string,@New_Words);
       $totalfound=0;
       $r->print('<html><head><title>LON-CAPA Course Search</title></head>'.
         $bodytag.$pretty_search_string);
       $r->rflush();
   # ======================================================= Go through the course
       undef %alreadyseen;
       %alreadyseen=();
       my $c=$r->connection;
       if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.".db",
               &GDBM_READER(),0640)) {
           foreach (keys %hash) {
               if ($c->aborted()) { last; }
               if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) {
                   &checkonthis($r,$hash{$_},0,$hash{'title_'.$1},$fulltext,
                                @allwords);
               }
           }
           untie(%hash);
       }
       unless ($totalfound) {
    $r->print('<p>'.&mt('No resources found').'.</p>');
       }
   # =================================================== Done going through course
       $r->print('</body></html>');
   }
   
   # =============================== This pulls up a resource and its dependencies
   
   sub checkonthis {
       my ($r,$url,$level,$title,$fulltext,@allwords)=@_;
       $alreadyseen{$url}=1;
       $r->rflush();
       my $result=&Apache::lonnet::metadata($url,'title').' '.
                  &Apache::lonnet::metadata($url,'subject').' '.
                  &Apache::lonnet::metadata($url,'abstract').' '.
                  &Apache::lonnet::metadata($url,'keywords');
       if (($url) && ($fulltext)) {
    $result.=&Apache::lonnet::ssi_body($url);
       }
       $result=~s/\s+/ /gs;
       my $applies=0;
       foreach (@allwords) {
           if ($_=~/\w/) {
      if ($result=~/$_/si) {
         $applies++;
              }
          }
       }
   # Does this resource apply?
       if ($applies) {
          $r->print('<br />');
          for (my $i=0;$i<=$level*5;$i++) {
              $r->print('&nbsp;');
          }
          $r->print('<a href="'.$url.'" target="cat">'.
    ($title?$title:$url).'</a><br />');
          $totalfound++;
       } elsif ($fulltext) {
          $r->print(' .');
       }
       $r->rflush();
   # Check also the dependencies of this one
       my $dependencies=
                   &Apache::lonnet::metadata($url,'dependencies');
       foreach (split(/\,/,$dependencies)) {
          if (($_=~/^\/res\//) && (!$alreadyseen{$_})) {
             &checkonthis($r,$_,$level+1,'',$fulltext,@allwords);
          }
       }
   }
   
   sub untiehash {
       if (tied(%hash)) {
           untie(%hash);
       }
   }
   
   } # End of course search scoping
   
   ######################################################################
   ######################################################################
   
 =pod   =pod 
   
Line 381  Returns a scalar which holds html for th Line 465  Returns a scalar which holds html for th
 ######################################################################  ######################################################################
   
 sub print_basic_search_form{  sub print_basic_search_form{
     my ($r,$closebutton) = @_;      my ($r,$closebutton,$hidden_fields) = @_;
       my $bodytag=&Apache::loncommon::bodytag('Search');
     my $scrout=<<"ENDDOCUMENT";      my $scrout=<<"ENDDOCUMENT";
 <html>  <html>
 <head>  <head>
Line 394  sub print_basic_search_form{ Line 479  sub print_basic_search_form{
     }      }
 </script>  </script>
 </head>  </head>
 <body bgcolor="#FFFFFF">  $bodytag
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  ENDDOCUMENT
 <h1>Search Catalog</h1>  if (&Apache::lonnet::allowed('bre',$ENV{'request.role.domain'})) {
 <form method="post" action="/adm/searchcat">      my $CatalogSearch=&mt('Catalog Search');
       my $Statement=&mt('Enter terms or phrases separated by AND, OR, or NOT then press SEARCH below');
       $scrout.=(<<ENDDOCUMENT);
   <h1>$CatalogSearch</h1>
   <form name="loncapa_search" method="post" action="/adm/searchcat">
 <input type="hidden" name="phase" value="basic_search" />  <input type="hidden" name="phase" value="basic_search" />
 $hidden_fields  $hidden_fields
 <h3>Basic Search</h3>  
 <p>  <p>
 Enter terms or phrases separated by AND, OR, or NOT   $Statement.
 then press SEARCH below.  
 </p>  </p>
 <p>  <p>
 <table>  <table>
Line 411  then press SEARCH below. Line 498  then press SEARCH below.
 ENDDOCUMENT  ENDDOCUMENT
     $scrout.='&nbsp;'.&simpletextfield('basicexp',$ENV{'form.basicexp'},40).      $scrout.='&nbsp;'.&simpletextfield('basicexp',$ENV{'form.basicexp'},40).
         '&nbsp;';          '&nbsp;';
     my $checkbox = &simplecheckbox('related',$ENV{'form.related'});      my $relatedcheckbox = &simplecheckbox('related','related',$ENV{'form.related'});
       my $domain = $r->dir_config('lonDefDomain');
       my $domaincheckbox = &simplecheckbox('domains',$domain);
       my $srch=&mt('Search');
       my $header=&mt('Advanced Search');
       my $userelatedwords=&mt('use related words');
       my $onlysearchdomain=&mt('only search domain');
     $scrout.=<<END;      $scrout.=<<END;
 </td><td><a href="/adm/searchcat?phase=disp_adv">Advanced Search</a></td></tr>  </td><td><a
 <tr><td>$checkbox use related words</td><td></td></tr>  href="/adm/searchcat?phase=disp_adv&catalogmode=$ENV{'form.catalogmode'}&launch=$ENV{'form.launch'}&mode=$ENV{'form.mode'}"
   >$header</a></td></tr>
   <tr><td>$relatedcheckbox $userelatedwords</td>
       <td>$domaincheckbox $onlysearchdomain <b>$domain</b></td></tr>
 </table>  </table>
 </p>  </p>
 <p>  <p>
 &nbsp;<input type="submit" name="basicsubmit" value='SEARCH' />&nbsp;  &nbsp;<input type="submit" name="basicsubmit" value='$srch' />&nbsp;
 $closebutton  $closebutton
 END  END
     $scrout.=&selectbox(undef,'viewselect',      $scrout.=&selectbox('View','viewselect',
  $ENV{'form.viewselect'},   $ENV{'form.viewselect'},
  undef,undef,undef,   undef,undef,undef,
  sort(keys(%Views)));   sort(keys(%Views)));
       $scrout.=&selectbox('Per Page','show',
    $ENV{'form.show'},
    undef,undef,undef,
    (10,20,50,100));
     $scrout.=<<ENDDOCUMENT;      $scrout.=<<ENDDOCUMENT;
 <input type="button" value="HELP" onClick="openhelp()" />  
 </p>  </p>
 </form>  </form>
   ENDDOCUMENT
       }
       if ($ENV{'request.course.id'}) {
    my %lt=&Apache::lonlocal::texthash(
      'srch' => 'Search',
                                              'header' => 'Course Search',
    'note' => 'Enter terms or phrases, then press "Search" below',
      );
           $scrout.=(<<ENDCOURSESEARCH);
   <hr />
   <h1>$lt{'header'}</h1>    
   <form name="course_search" method="post" action="/adm/searchcat">
   <input type="hidden" name="phase" value="course_search" />
   $hidden_fields
   <p>
   $lt{'note'}.
   </p>
   <p>
   <table>
   <tr><td>
   ENDCOURSESEARCH
           $scrout.='&nbsp;'.
               &simpletextfield('courseexp',$ENV{'form.courseexp'},40);
           my $crscheckbox = 
               &simplecheckbox('crsfulltext',$ENV{'form.crsfulltext'});
           my $relcheckbox = 
               &simplecheckbox('crsrelated',$ENV{'form.crsrelated'});
           $scrout.=(<<ENDENDCOURSE);
   </td></tr>
   <tr><td>$relcheckbox use related words</td><td></td></tr>
   <tr><td>$crscheckbox fulltext search (time consuming)</td><td></td></tr>
   </table><p>
   &nbsp;<input type="submit" name="coursesubmit" value='$lt{'srch'}' />
   </p>
   ENDENDCOURSE
       }
       $scrout.=(<<ENDDOCUMENT);
 </body>  </body>
 </html>  </html>
 ENDDOCUMENT  ENDDOCUMENT
Line 450  Returns a scalar which holds html for th Line 586  Returns a scalar which holds html for th
 ######################################################################  ######################################################################
   
 sub print_advanced_search_form{  sub print_advanced_search_form{
     my ($r,$closebutton) = @_;      my ($r,$closebutton,$hidden_fields) = @_;
     my $advanced_buttons = <<"END";      my $advanced_buttons = <<"END";
 <p>  <p>
 <input type="submit" name="advancedsubmit" value='SEARCH' />  <input type="submit" name="advancedsubmit" value='SEARCH' />
Line 462  END Line 598  END
     if (!defined($ENV{'form.viewselect'})) {      if (!defined($ENV{'form.viewselect'})) {
         $ENV{'form.viewselect'} ="Detailed Citation View";          $ENV{'form.viewselect'} ="Detailed Citation View";
     }      }
       my $bodytag=&Apache::loncommon::bodytag('Advanced Catalog Search');
     my $scrout=<<"ENDHEADER";      my $scrout=<<"ENDHEADER";
 <html>  <html>
 <head>  <head>
Line 474  END Line 611  END
     }      }
 </script>  </script>
 </head>  </head>
 <body bgcolor="#FFFFFF">  $bodytag
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  
 <h1>Advanced Catalog Search</h1>  
 <hr />  
 Enter terms or phrases separated by search operators   Enter terms or phrases separated by search operators 
 such as AND, OR, or NOT.<br />  such as AND, OR, or NOT.<br />
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
Line 492  ENDHEADER Line 626  ENDHEADER
  $ENV{'form.viewselect'},   $ENV{'form.viewselect'},
  undef,undef,undef,   undef,undef,undef,
  sort(keys(%Views)));   sort(keys(%Views)));
     $scrout.="</td><td>Related<br />Words</td></tr>\n";      $scrout.='&nbsp;';
       $scrout.=&selectbox(undef,'show',
    $ENV{'form.show'},
    undef,undef,undef,
    (10,20,50,100));
       $scrout.='&nbsp;'.
           '<font color="#800000" face="helvetica">'.&mt('Per Page').'</font>';
       $scrout.="</td><td>".&mt('Related').'<br />'.&mt('Words')."</td></tr>\n";
     $scrout.=&searchphrasefield_with_related('title',   'title'   ,      $scrout.=&searchphrasefield_with_related('title',   'title'   ,
                                              $ENV{'form.title'});                                               $ENV{'form.title'});
     $scrout.=&searchphrasefield('author',  'author'  ,$ENV{'form.author'});      $scrout.=&searchphrasefield('author',  'author'  ,$ENV{'form.author'});
Line 507  ENDHEADER Line 648  ENDHEADER
                                              $ENV{'form.abstract'});                                               $ENV{'form.abstract'});
     # Hack - an empty table row.      # Hack - an empty table row.
     $scrout.="<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n";      $scrout.="<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n";
     $scrout.=&searchphrasefield('file<br />extension','mime',      $scrout.=&searchphrasefield('file<br />extension','extension',
                         $ENV{'form.mime'});                          $ENV{'form.extension'});
     $scrout.="<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n";      $scrout.="<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n";
     $scrout.=&searchphrasefield('publisher<br />owner','owner',      $scrout.=&searchphrasefield('publisher<br />owner','owner',
  $ENV{'form.owner'});   $ENV{'form.owner'});
     $scrout.="</table>\n";      $scrout.="</table>\n";
     $ENV{'form.category'}='any' unless length($ENV{'form.category'});      $ENV{'form.category'}='any' if (! defined($ENV{'form.category'}));
     $scrout.=&selectbox('File Category','category',      $scrout.=&selectbox('File Category','category',
  $ENV{'form.category'},   $ENV{'form.category'},
  'any','Any category',   'any','Any category',
Line 534  ENDHEADER Line 675  ENDHEADER
     my @domains =&Apache::loncommon::get_domains();      my @domains =&Apache::loncommon::get_domains();
     # adjust the size of the select box      # adjust the size of the select box
     my $size = 4;      my $size = 4;
     my $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size);      $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size);
     $scrout.="\n".'<font color="#800000" face="helvetica"><b>'.      $scrout.="\n".'<font color="#800000" face="helvetica"><b>'.
         'DOMAINS</b></font><br />'.          'DOMAINS TO BE SEARCHED</b></font><br />'.
             '<select name="domains" size="'.$size.'" multiple>'."\n".              '<select name="domains" size="'.$size.'" multiple>'."\n".
                 '<option name="any" value="any" '.                  '<option name="any" value="any" '.
                     ($domain_hash{'any'}? 'selected ' :'').                      ($domain_hash{'any'}? 'selected ' :'').
Line 549  ENDHEADER Line 690  ENDHEADER
     #----------------------------------------------------------------      #----------------------------------------------------------------
     $scrout.=&selectbox('Limit by language','language',      $scrout.=&selectbox('Limit by language','language',
  $ENV{'form.language'},'any','Any Language',   $ENV{'form.language'},'any','Any Language',
  \&{Apache::loncommon::languagedescription},   \&Apache::loncommon::languagedescription,
  (&Apache::loncommon::languageids),   (&Apache::loncommon::languageids),
  );   );
 # ------------------------------------------------ Compute date selection boxes  # ------------------------------------------------ Compute date selection boxes
Line 596  LASTREVISIONDATEEND Line 737  LASTREVISIONDATEEND
     $scrout.=&selectbox('Limit by copyright/distribution','copyright',      $scrout.=&selectbox('Limit by copyright/distribution','copyright',
  $ENV{'form.copyright'},   $ENV{'form.copyright'},
  'any','Any copyright/distribution',   'any','Any copyright/distribution',
  \&{Apache::loncommon::copyrightdescription},   \&Apache::loncommon::copyrightdescription,
  (&Apache::loncommon::copyrightids),   (&Apache::loncommon::copyrightids),
  );   );
 # ------------------------------------------- Compute customized metadata field  # ------------------------------------------- Compute customized metadata field
     $scrout.=<<CUSTOMMETADATA;  #    $scrout.=<<CUSTOMMETADATA;
 <p>  #<p>
 <font color="#800000" face="helvetica"><b>LIMIT BY SPECIAL METADATA FIELDS:</b>  #<font color="#800000" face="helvetica"><b>LIMIT BY SPECIAL METADATA FIELDS:</b>
 </font>  #</font>
 For resource-specific metadata, enter in an expression in the form of   #For resource-specific metadata, enter in an expression in the form of 
 <i>key</i>=<i>value</i> separated by operators such as AND, OR or NOT.<br />  #<i>key</i>=<i>value</i> separated by operators such as AND, OR or NOT.<br />
 <b>Example:</b> grandmother=75 OR grandfather=85  #<b>Example:</b> grandmother=75 OR grandfather=85
 <br />  #<br />
 CUSTOMMETADATA  #CUSTOMMETADATA
     $scrout.=&simpletextfield('custommetadata',$ENV{'form.custommetadata'});  #    $scrout.=&simpletextfield('custommetadata',$ENV{'form.custommetadata'});
     $scrout.=<<CUSTOMSHOW;  #    $scrout.=<<CUSTOMSHOW;
 <p>  #<p>
 <font color="#800000" face="helvetica"><b>SHOW SPECIAL METADATA FIELDS:</b>  #<font color="#800000" face="helvetica"><b>SHOW SPECIAL METADATA FIELDS:</b>
 </font>  #</font>
 Enter in a space-separated list of special metadata fields to show  #Enter in a space-separated list of special metadata fields to show
 in a fielded listing for each record result.  #in a fielded listing for each record result.
 <br />  #<br />
 CUSTOMSHOW  #CUSTOMSHOW
     $scrout.=&simpletextfield('customshow',$ENV{'form.customshow'});  #    $scrout.=&simpletextfield('customshow',$ENV{'form.customshow'});
     $scrout.=<<ENDDOCUMENT;      $scrout.=<<ENDDOCUMENT;
 $advanced_buttons  $advanced_buttons
 </form>  </form>
Line 651  to them. Line 792  to them.
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub get_persistent_form_data {  sub get_persistent_form_data {
     my $r = shift;  
     my $filename = shift;      my $filename = shift;
     return 0 if (! -e $filename);      return 0 if (! -e $filename);
     return undef if (! tie(%persistent_db,'GDBM_File',$filename,      return undef if (! tie(%persistent_db,'GDBM_File',$filename,
                            &GDBM_READER(),0640));                             &GDBM_READER(),0640));
     #      #
     # These make sure we do not get array references printed out as 'values'.      # These make sure we do not get array references printed out as 'values'.
     my %arrays_allowed = ('form.category'=>1,'form.domains'=>1);      my %arrays_allowed = ('form.domains'=>1);
     #      #
     # Loop through the keys, looking for 'form.'      # Loop through the keys, looking for 'form.'
     foreach my $name (keys(%persistent_db)) {      foreach my $name (keys(%persistent_db)) {
         next if ($name !~ /^form./);          next if ($name !~ /^form./);
           # Kludgification begins!
           if ($name eq 'form.domains' && 
               $ENV{'form.searchmode'} eq 'basic' &&
               $ENV{'form.phase'} ne 'disp_basic') {
               next;
           }
           # End kludge (hopefully)
           next if (exists($ENV{$name}));
         my @values = map {           my @values = map { 
             &Apache::lonnet::unescape($_);              &Apache::lonnet::unescape($_);
         } split(',',$persistent_db{$name});          } split(',',$persistent_db{$name});
         next if (@values <1);          next if (@values <1);
         if (exists($ENV{$name})) {          if ($arrays_allowed{$name}) {
             if (ref($ENV{$name}) eq 'ARRAY') {              $ENV{$name} = [@values];
                 # If it is an array, tack @values on the end of it.  
                 $ENV{$name} = [@$ENV{$name},@values];  
             } elsif (! ref($ENV{$name}) && $arrays_allowed{$name}) {  
                 # if arrays are allowed, turn it into one and add @values  
                 $ENV{$name} = [$ENV{$name},@values];  
             } # otherwise, assume the value in $ENV{$name} is better than ours.  
         } else {          } else {
             if ($arrays_allowed{$name}) {              $ENV{$name} = $values[0] if ($values[0]);
                 $ENV{$name} = [@values];  
             } else {  
                 $ENV{$name} = $values[0] if ($values[0]);  
             }  
         }          }
     }      }
     untie (%persistent_db);      untie (%persistent_db);
     return 1;      return 1;
 }  }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 721  sub get_persistent_data { Line 860  sub get_persistent_data {
         my @values = map {           my @values = map { 
             &Apache::lonnet::unescape($_);              &Apache::lonnet::unescape($_);
         } split(',',$persistent_db{$name});          } split(',',$persistent_db{$name});
         if (@values == 1) {          if (@values <= 1) {
             push @Values,$values[0];              push @Values,$values[0];
         } else {          } else {
             push @Values,\@values;              push @Values,\@values;
Line 749  elements escaped and concatenated in a c Line 888  elements escaped and concatenated in a c
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub make_persistent {  sub make_persistent {
     my $r = shift;  
     my %save = %{shift()};      my %save = %{shift()};
     my $filename = shift;      my $filename = shift;
     return undef if (! tie(%persistent_db,'GDBM_File',      return undef if (! tie(%persistent_db,'GDBM_File',
                            $filename,&GDBM_WRCREAT(),0640));                             $filename,&GDBM_WRCREAT(),0640));
     foreach my $name (keys(%save)) {      foreach my $name (keys(%save)) {
         next if (! exists($save{$name}));  
         next if (! defined($save{$name}) || $save{$name} eq '');  
         my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));          my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
         # We handle array references, but not recursively.          # We handle array references, but not recursively.
         my $store = join(',', map { &Apache::lonnet::escape($_); } @values );          my $store = join(',', map { &Apache::lonnet::escape($_); } @values );
Line 791  sub make_form_data_persistent { Line 927  sub make_form_data_persistent {
         next if (!/^form/ || /submit/);          next if (!/^form/ || /submit/);
         $save{$_} = $ENV{$_};          $save{$_} = $ENV{$_};
     }      }
     return &make_persistent($r,\%save,$filename);      return &make_persistent(\%save,$filename);
 }  }
   
 ######################################################################  ######################################################################
Line 837  sub simpletextfield { Line 973  sub simpletextfield {
   
 =item &simplecheckbox()  =item &simplecheckbox()
   
 Inputs: $name,$value  Inputs: $name,$value,$checked
   
 Returns a simple check box with the given $name.  Returns a simple check box with the given $name.
 If $value eq 'on' the box is checked.  If $value eq 'on' the box is checked.
Line 847  If $value eq 'on' the box is checked. Line 983  If $value eq 'on' the box is checked.
 ###############################################  ###############################################
 ###############################################  ###############################################
   
 sub simplecheckbox {  sub simplecheckbox{
     my ($name,$value)=@_;      my ($name,$value,$checked)=@_;
     my $checked='';      $checked="checked" if ($value eq $checked || $value eq 'on');
     $checked="checked" if $value eq 'on';      return '<input type="checkbox" name="'.$name.'" value="'.$value.'" '.
     return '<input type="checkbox" name="'.$name.'" '. $checked . ' />';          $checked.' />';
 }  }
   
 ###############################################  ###############################################
Line 872  field heading. Line 1008  field heading.
 ###############################################  ###############################################
   
 sub fieldtitle {  sub fieldtitle {
     my $title = uc(shift());      my $title = uc(&mt(shift()));
     return '<font color="#800000" face="helvetica"><b>'.$title.      return '<font color="#800000" face="helvetica"><b>'.$title.
         ':&nbsp;</b></font>';          ':&nbsp;</b></font>';
 }  }
Line 967  END Line 1103  END
     my $i = 1;      my $i = 1;
     foreach (qw/January February March April May June       foreach (qw/January February March April May June 
      July August September October November December /){       July August September October November December /){
  $month .="<option value=\"$i\">$_</option>\n";   $month .="<option value=\"$i\">".&mt($_)."</option>\n";
  $i++;   $i++;
     }      }
     $month.="</select>\n";      $month.="</select>\n";
Line 1044  sub selectbox { Line 1180  sub selectbox {
     my ($title,$name,$default,$anyvalue,$anytag,$functionref,@idlist)=@_;      my ($title,$name,$default,$anyvalue,$anytag,$functionref,@idlist)=@_;
     if (! defined($functionref)) { $functionref = sub { $_[0]}; }      if (! defined($functionref)) { $functionref = sub { $_[0]}; }
     my $selout='';      my $selout='';
       $title=&mt($title);
     if (defined($title)) {      if (defined($title)) {
         my $uctitle=uc($title);          my $uctitle=uc($title);
         $selout="\n".'<p><font color="#800000" face="helvetica">'.          $selout="\n".'<p><font color="#800000" face="helvetica">'.
Line 1054  sub selectbox { Line 1191  sub selectbox {
     foreach (@idlist) {      foreach (@idlist) {
         $selout.='<option value="'.$_.'"';          $selout.='<option value="'.$_.'"';
         if ($_ eq $default and !/^any$/) {          if ($_ eq $default and !/^any$/) {
     $selout.=' selected >'.&{$functionref}($_).'</option>';      $selout.=' selected >'.&mt(&{$functionref}($_)).'</option>';
  }   }
  elsif ($_ eq $default and /^$anyvalue$/) {   elsif ($_ eq $default and /^$anyvalue$/) {
     $selout.=' selected >'.$anytag.'</option>';      $selout.=' selected >'.&mt($anytag).'</option>';
  }   }
         else {$selout.='>'.&{$functionref}($_).'</option>';}          else {$selout.='>'.&mt(&{$functionref}($_)).'</option>';}
     }      }
     return $selout.'</select>'.(defined($title)?'</p>':' ');      return $selout.'</select>'.(defined($title)?'</p>':' ');
 }  }
Line 1101  Parse advanced search form and return th Line 1238  Parse advanced search form and return th
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub parse_advanced_search {  sub parse_advanced_search {
     my ($r,$closebutton)=@_;      my ($r,$closebutton,$hidden_fields)=@_;
     my $fillflag=0;      my $fillflag=0;
     my $pretty_search_string = "<br />\n";      my $pretty_search_string = "<br />\n";
     # Clean up fields for safety      # Clean up fields for safety
Line 1112  sub parse_advanced_search { Line 1249  sub parse_advanced_search {
    'lastrevisiondatestart_month','lastrevisiondatestart_day',     'lastrevisiondatestart_month','lastrevisiondatestart_day',
    'lastrevisiondatestart_year','lastrevisiondateend_month',     'lastrevisiondatestart_year','lastrevisiondateend_month',
    'lastrevisiondateend_day','lastrevisiondateend_year',     'lastrevisiondateend_day','lastrevisiondateend_year',
    'notes','abstract','mime','language','owner',     'notes','abstract','extension','language','owner',
    'custommetadata','customshow','category') {     'custommetadata','customshow','category') {
  $ENV{"form.$field"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $ENV{"form.$field"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
Line 1123  sub parse_advanced_search { Line 1260  sub parse_advanced_search {
  $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
     # Preprocess the category form element.      # Preprocess the category form element.
     if ($ENV{'form.category'} ne 'any') {      $ENV{'form.category'} = 'any' if (! defined($ENV{'form.category'}) ||
         my @extensions = &Apache::loncommon::filecategorytypes                                        ref($ENV{'form.category'}));
             ($ENV{'form.category'});      #
         $ENV{'form.mime'} = join ' OR ',@extensions;  
     }  
     # Check to see if enough information was filled in      # Check to see if enough information was filled in
     for my $field ('title','author','subject','keywords','url','version',      for my $field ('title','author','subject','keywords','url','version',
    'notes','abstract','mime','language','owner',     'notes','abstract','category','extension','language',
    'custommetadata') {                     'owner','custommetadata') {
  if (&filled($ENV{"form.$field"})) {   if (&filled($ENV{"form.$field"})) {
     $fillflag++;      $fillflag++;
  }   }
     }      }
     unless ($fillflag) {      unless ($fillflag) {
  &output_blank_field_error($r,$closebutton);   &output_blank_field_error($r,$closebutton,'phase=disp_adv',$hidden_fields);
  return ;   return ;
     }      }
     # Turn the form input into a SQL-based query      # Turn the form input into a SQL-based query
Line 1146  sub parse_advanced_search { Line 1281  sub parse_advanced_search {
     my $font = '<font color="#800000" face="helvetica">';      my $font = '<font color="#800000" face="helvetica">';
     # Evaluate logical expression AND/OR/NOT phrase fields.      # Evaluate logical expression AND/OR/NOT phrase fields.
     foreach my $field ('title','author','subject','notes','abstract','url',      foreach my $field ('title','author','subject','notes','abstract','url',
        'keywords','version','owner','mime') {         'keywords','version','owner') {
  if ($ENV{'form.'.$field}) {   if ($ENV{'form.'.$field}) {
             my $searchphrase = $ENV{'form.'.$field};              my $searchphrase = $ENV{'form.'.$field};
             $pretty_search_string .= $font."$field</font> contains <b>".              $pretty_search_string .= $font."$field</font> contains <b>".
Line 1165  sub parse_advanced_search { Line 1300  sub parse_advanced_search {
     push @queries,&build_SQL_query($field,$searchphrase);      push @queries,&build_SQL_query($field,$searchphrase);
         }          }
     }      }
     # I dislike the hack below.      #
     if ($ENV{'form.category'}) {      # Make the 'mime' from 'form.category' and 'form.extension'
         $ENV{'form.mime'}='';      #
       my $searchphrase;
       if (exists($ENV{'form.category'})    && 
           $ENV{'form.category'} !~ /^\s*$/ &&
           $ENV{'form.category'} ne 'any')     {
           my @extensions = &Apache::loncommon::filecategorytypes
                                                      ($ENV{'form.category'});
           if (scalar(@extensions) > 0) {
               $searchphrase = join(' OR ',@extensions);
           }
       }
       if (exists($ENV{'form.extension'}) && $ENV{'form.extension'} !~ /^\s*$/) {
           $searchphrase .= ' OR ' if (defined($searchphrase));
           my @extensions = split(/,/,$ENV{'form.extension'});
           $searchphrase .= join(' OR ',@extensions);
       }
       if (defined($searchphrase)) {
           push @queries,&build_SQL_query('mime',$searchphrase);
           $pretty_search_string .=$font.'mime</font> contains <b>'.
               $searchphrase.'</b><br />';
     }      }
       #####
     # Evaluate option lists      # Evaluate option lists
     if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {      if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {
  push @queries,"(language like \"$ENV{'form.language'}\")";   push @queries,"(language like \"$ENV{'form.language'}\")";
Line 1200  sub parse_advanced_search { Line 1355  sub parse_advanced_search {
  );   );
     # Test to see if date windows are legitimate      # Test to see if date windows are legitimate
     if ($datequery=~/^Incorrect/) {      if ($datequery=~/^Incorrect/) {
  &output_date_error($r,$datequery,$closebutton);   &output_date_error($r,$datequery,$closebutton,$hidden_fields);
  return ;   return ;
     } elsif ($datequery) {      } elsif ($datequery) {
         # Here is where you would set up pretty_search_string to output          # Here is where you would set up pretty_search_string to output
Line 1209  sub parse_advanced_search { Line 1364  sub parse_advanced_search {
     }      }
     # Process form information for custom metadata querying      # Process form information for custom metadata querying
     my $customquery=undef;      my $customquery=undef;
     if ($ENV{'form.custommetadata'}) {  #    if ($ENV{'form.custommetadata'}) {
         $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".  #        $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".
             $ENV{'form.custommetadata'}."</b><br />\n";  #            $ENV{'form.custommetadata'}."</b><br />\n";
  $customquery=&build_custommetadata_query('custommetadata',  # $customquery=&build_custommetadata_query('custommetadata',
       $ENV{'form.custommetadata'});  #      $ENV{'form.custommetadata'});
     }  #    }
     my $customshow=undef;      my $customshow=undef;
     if ($ENV{'form.customshow'}) {  #    if ($ENV{'form.customshow'}) {
         $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".  #        $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".
             $ENV{'form.customshow'}."</b><br />\n";  #            $ENV{'form.customshow'}."</b><br />\n";
  $customshow=$ENV{'form.customshow'};  # $customshow=$ENV{'form.customshow'};
  $customshow=~s/[^\w\s]//g;  # $customshow=~s/[^\w\s]//g;
  my @fields=split(/\s+/,$customshow);  # my @fields=split(/\s+/,$customshow);
  $customshow=join(" ",@fields);  # $customshow=join(" ",@fields);
     }  #    }
     ## ---------------------------------------------------------------      ## ---------------------------------------------------------------
     ## Deal with restrictions to given domains      ## Deal with restrictions to given domains
     ##       ## 
       my ($libraries_to_query,$pretty_domains_string) = 
           &parse_domain_restrictions();
       $pretty_search_string .= $pretty_domains_string."<br />\n";
       #
       if (@queries) {
    $query=join(" AND ",@queries);
    $query="select * from metadata where $query";
       } elsif ($customquery) {
           $query = '';
       }
       return ($query,$customquery,$customshow,$libraries_to_query,
               $pretty_search_string);
   }
   
   sub parse_domain_restrictions {
     my $libraries_to_query = undef;      my $libraries_to_query = undef;
     # $ENV{'form.domains'} can be either a scalar or an array reference.      # $ENV{'form.domains'} can be either a scalar or an array reference.
     # We need an array.      # We need an array.
     my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}}       if (! exists($ENV{'form.domains'})) {
                            :  ($ENV{'form.domains'}) );          return (undef,'');
       }
       my @allowed_domains;
       if (ref($ENV{'form.domains'})) {
           @allowed_domains =  @{$ENV{'form.domains'}};
       } else {
           @allowed_domains = ($ENV{'form.domains'});
       }
     my %domain_hash = ();      my %domain_hash = ();
     my $pretty_domains_string;      my $pretty_domains_string;
     foreach (@allowed_domains) {      foreach (@allowed_domains) {
         $domain_hash{$_}++;          $domain_hash{$_}++;
     }      }
     if ($domain_hash{'any'}) {      if ($domain_hash{'any'}) {
         $pretty_domains_string = "Searching all domains.";          $pretty_domains_string = "In all LON-CAPA domains.";
     } else {      } else {
         if (@allowed_domains > 1) {          if (@allowed_domains > 1) {
             $pretty_domains_string = "Searching domains:";              $pretty_domains_string = "In LON-CAPA domains:";
         } else {          } else {
             $pretty_domains_string = "Searching domain ";              $pretty_domains_string = "In LON-CAPA domain ";
         }          }
         foreach (sort @allowed_domains) {          foreach (sort @allowed_domains) {
             $pretty_domains_string .= "<b>$_</b> ";              $pretty_domains_string .= "<b>".$_."</b> ";
         }          }
         foreach (keys(%Apache::lonnet::libserv)) {          foreach (keys(%Apache::lonnet::libserv)) {
             if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {              if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {
Line 1254  sub parse_advanced_search { Line 1431  sub parse_advanced_search {
             }              }
         }          }
     }      }
     $pretty_search_string .= $pretty_domains_string."<br />\n";      return ($libraries_to_query,$pretty_domains_string);
     #  
     if (@queries) {  
  $query=join(" AND ",@queries);  
  $query="select * from metadata where $query";  
     } elsif ($customquery) {  
         $query = '';  
     }  
     return ($query,$customquery,$customshow,$libraries_to_query,  
             $pretty_search_string);  
 }  }
   
 ######################################################################  ######################################################################
Line 1291  sub parse_basic_search { Line 1459  sub parse_basic_search {
  $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});   $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});
  $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
       my ($libraries_to_query,$pretty_domains_string) = 
           &parse_domain_restrictions();
     # Check to see if enough is filled in      # Check to see if enough is filled in
     unless (&filled($ENV{'form.basicexp'})) {      unless (&filled($ENV{'form.basicexp'})) {
  &output_blank_field_error($r,$closebutton);   &output_blank_field_error($r,$closebutton,'phase=disp_basic');
  return OK;   return OK;
     }      }
     my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';      my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';
Line 1310  sub parse_basic_search { Line 1479  sub parse_basic_search {
     }      }
     # Build SQL query string based on form page      # Build SQL query string based on form page
     my $query='';      my $query='';
     my $concatarg=join(',"    ",',      my $concatarg=join(',',
        ('title', 'author', 'subject', 'notes', 'abstract',         ('title', 'author', 'subject', 'notes', 'abstract',
                         'keywords'));                          'keywords'));
     $concatarg='title' if $ENV{'form.titleonly'};      $concatarg='title' if $ENV{'form.titleonly'};
     $query=&build_SQL_query('concat('.$concatarg.')',$search_string);      $query=&build_SQL_query('concat_ws(" ",'.$concatarg.')',$search_string);
       if (defined($pretty_domains_string) && $pretty_domains_string ne '') {
           $pretty_search_string .= ' '.$pretty_domains_string;
       }
     $pretty_search_string .= "<br />\n";      $pretty_search_string .= "<br />\n";
     return 'select * from metadata where '.$query,$pretty_search_string;      my $final_query = 'SELECT * FROM metadata WHERE '.$query;
   #    &Apache::lonnet::logthis($final_query);
       return ($final_query,$pretty_search_string,
               $libraries_to_query);
 }  }
   
   
Line 1429  sub recursive_SQL_query_build { Line 1604  sub recursive_SQL_query_build {
     my @matches=($pattern=~/(\[[^\]|\[]*\])/g);      my @matches=($pattern=~/(\[[^\]|\[]*\])/g);
     return $pattern unless @matches;      return $pattern unless @matches;
     foreach my $match (@matches) {      foreach my $match (@matches) {
  $match=~/\[ (\w+)\s(.*) \]/;          $match=~/\[ (\w+)\s(.*) \]/;
  my ($key,$value)=($1,$2);          my ($key,$value)=($1,$2);
  my $replacement='';          my $replacement='';
  if ($key eq 'literal') {          if ($key eq 'literal') {
     $replacement="($dkey like \"\%$value\%\")";              $replacement="($dkey LIKE \"\%$value\%\")";
  }          } elsif (lc($key) eq 'not') {
  elsif ($key eq 'not') {              $value=~s/LIKE/NOT LIKE/;
     $value=~s/like/not like/;  #          $replacement="($dkey not like $value)";
 #    $replacement="($dkey not like $value)";              $replacement="$value";
     $replacement="$value";          } elsif ($key eq 'and') {
  }              $value=~/(.*[\"|\)]) ([|\(|\^].*)/;
  elsif ($key eq 'and') {              $replacement="($1 AND $2)";
     $value=~/(.*[\"|\)]) ([|\(|\^].*)/;   } elsif ($key eq 'or') {
     $replacement="($1 AND $2)";              $value=~/(.*[\"|\)]) ([|\(|\^].*)/;
  }              $replacement="($1 OR $2)";
  elsif ($key eq 'or') {  
     $value=~/(.*[\"|\)]) ([|\(|\^].*)/;  
     $replacement="($1 OR $2)";  
  }   }
  substr($pattern,   substr($pattern,
        index($pattern,$match),                 index($pattern,$match),
        length($match),                 length($match),
        $replacement                 $replacement);
        );  
     }      }
     &recursive_SQL_query_build($dkey,$pattern);      &recursive_SQL_query_build($dkey,$pattern);
 }  }
Line 1530  sub build_date_queries { Line 1701  sub build_date_queries {
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 sub copyright_check {  sub copyright_check {
     my $Metadata = shift;      my $Metadata = shift;
     # Check copyright tags and skip results the user cannot use      # Check copyright tags and skip results the user cannot use
Line 1550  sub copyright_check { Line 1720  sub copyright_check {
     return 1;      return 1;
 }  }
   
   
   ######################################################################
   ######################################################################
   
   =pod
   
   =item &ensure_db_and_table
   
   Ensure we can get lonmysql to connect to the database and the table we
   need exists.
   
   Inputs: $r, table id
   
   Returns: undef on error, 1 if the table exists.
   
   =cut
   
   ######################################################################
   ######################################################################
   sub ensure_db_and_table {
       my ($r,$table) = @_;
       ##
       ## Sanity check the table id.
       ##
       if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
           $r->print("Unable to retrieve search results.  ".
                     "Unable to determine the table results were stored in.  ".
                     "</body></html>");
           return undef;
       }
       ##
       ## Make sure we can connect and the table exists.
       ##
       my $connection_result = &Apache::lonmysql::connect_to_db();
       if (!defined($connection_result)) {
           $r->print("Unable to connect to the MySQL database where your results".
                     " are stored. </body></html>");
           &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".
                                    " connect to database.");
           &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
           return undef;
       }
       my $table_check = &Apache::lonmysql::check_table($table);
       if (! defined($table_check)) {
           $r->print("A MySQL error has occurred.</form></body></html>");
           &Apache::lonnet::logthis("lonmysql was unable to determine the status".
                                    " of table ".$table);
           return undef;
       } elsif (! $table_check) {
           $r->print("The table of results could not be found.");
           &Apache::lonnet::logthis("The user requested a table, ".$table.
                                    ", that could not be found.");
           return undef;
       }
       return 1;
   }
   
   ######################################################################
   ######################################################################
   
   =pod
   
   =item &print_sort_form
   
   =cut
   
   ######################################################################
   ######################################################################
   sub print_sort_form {
       my ($r,$pretty_query_string) = @_;
       my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
       ##
       my %SortableFields=&Apache::lonlocal::texthash( 
            id        => 'Default',
            title     => 'Title',
            author    => 'Author',
            subject   => 'Subject',
            url       => 'URL',
            version   => 'Version Number',
            mime      => 'Mime type',
            lang      => 'Language',
            owner     => 'Owner/Publisher',
            copyright => 'Copyright',
            hostname  => 'Host',
            creationdate     => 'Creation Date',
            lastrevisiondate => 'Revision Date'
        );
       ##
       my $table = $ENV{'form.table'};
       return if (! &ensure_db_and_table($r,$table));
       ##
       ## Get the number of results 
       ##
       my $total_results = &Apache::lonmysql::number_of_rows($table);
       if (! defined($total_results)) {
           $r->print("A MySQL error has occurred.</form></body></html>");
           &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                                    " of rows in table ".$table);
           &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
           return;
       }
       my $result;
       $result.=<<END;
   <html>
   <head>
   <script>
       function change_sort() {
           var newloc = "/adm/searchcat?phase=results";
           newloc += "&persistent_db_id=$ENV{'form.persistent_db_id'}";
           newloc += "&sortby=";
           newloc += document.forms.statusform.elements.sortby.value;
           parent.resultsframe.location= newloc;
       }
   </script>
   <title>Results</title>
   </head>
   $bodytag
   <form name="statusform" action="" method="post">
   <input type="hidden" name="Queue" value="" />
   END
   
   #<h2>Sort Results</h2>
   #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">
   #    $ENV{'form.sortby'} = 'id' if (! defined($ENV{'form.sortby'}));
   #    foreach (keys(%SortableFields)) {
   #        $result.="<option name=\"$_\"";
   #        if ($_ eq $ENV{'form.sortby'}) {
   #            $result.=" selected ";
   #        }
   #        $result.=" >$SortableFields{$_}</option>\n";
   #    }
   #    $result.="</select>\n";
       my $revise = &revise_button();
       $result.=<<END;
   <p>
   There are $total_results matches to your query. $revise
   </p><p>
   Search:$pretty_query_string
   </p>
   </form>
   </body>
   </html>
   END
       $r->print($result);
       return;
   }
   
 #####################################################################  #####################################################################
 #####################################################################  #####################################################################
   
Line 1564  the following format: Line 1881  the following format:
   
 =cut  =cut
   
 ##  #####################################################################
 ## Restrictions:  #####################################################################
 ##    columns of type 'text' and 'blob' cannot have defaults.  
 ##    columns of type 'enum' cannot be used for FULLTEXT.  
 ##  
 my @DataOrder = qw/id title author subject url keywords version notes  
     abstract mime lang owner copyright creationdate lastrevisiondate hostname/;  
   
 my %Datatypes =   my @Datatypes = 
     ( id        =>{ type         => 'INT',      ( { name => 'id', 
                     restrictions => 'NOT NULL',          type => 'MEDIUMINT',
                     primary_key  => 'yes',          restrictions => 'UNSIGNED NOT NULL',
                     auto_inc     => 'yes'          primary_key  => 'yes',
                     },          auto_inc     => 'yes' },
       title     =>{ type=>'TEXT'},        { name => 'title',     type=>'TEXT'},
       author    =>{ type=>'TEXT'},        { name => 'author',    type=>'TEXT'},
       subject   =>{ type=>'TEXT'},        { name => 'subject',   type=>'TEXT'},
       url       =>{ type=>'TEXT',        { name => 'url',       type=>'TEXT', restrictions => 'NOT NULL' },
                     restrictions => 'NOT NULL' },        { name => 'keywords',  type=>'TEXT'},
       keywords  =>{ type=>'TEXT'},        { name => 'version',   type=>'TEXT'},
       version   =>{ type=>'TEXT'},        { name => 'notes',     type=>'TEXT'},
       notes     =>{ type=>'TEXT'},        { name => 'abstract',  type=>'TEXT'},
       abstract  =>{ type=>'TEXT'},        { name => 'mime',      type=>'TEXT'},
       mime      =>{ type=>'TEXT'},        { name => 'lang',      type=>'TEXT'},
       lang      =>{ type=>'TEXT'},        { name => 'owner',     type=>'TEXT'},
       owner     =>{ type=>'TEXT'},        { name => 'copyright', type=>'TEXT'},
       copyright =>{ type=>'TEXT'},        { name => 'hostname',  type=>'TEXT'},
       hostname  =>{ type=>'TEXT'},  
       #--------------------------------------------------        #--------------------------------------------------
       creationdate     =>{ type=>'DATETIME'},        { name => 'creationdate',     type=>'DATETIME'},
       lastrevisiondate =>{ type=>'DATETIME'},        { name => 'lastrevisiondate', type=>'DATETIME'},
       #--------------------------------------------------        #--------------------------------------------------
       );        );
   
 my @Fullindicies =   my @Fullindicies = 
     qw/title author subject abstract mime language owner copyright/;      qw/title/;
   #    qw/title author subject abstract mime language owner copyright/;
           
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 1621  Returns: the identifier of the table on Line 1933  Returns: the identifier of the table on
 ######################################################################  ######################################################################
 sub create_results_table {  sub create_results_table {
     my $table = &Apache::lonmysql::create_table      my $table = &Apache::lonmysql::create_table
         ( { columns => \%Datatypes,          ( { columns => \@Datatypes,
             column_order => \@DataOrder,              FULLTEXT => [{'columns' => \@Fullindicies},],
             fullindex => \@Fullindicies,  
         } );          } );
     if (defined($table)) {      if (defined($table)) {
         $ENV{'form.table'} = $table;          $ENV{'form.table'} = $table;
Line 1690  sub update_seconds { Line 2001  sub update_seconds {
   
 =pod  =pod
   
   =item &revise_button
   
   Inputs: None
   
   Returns: html string for a 'revise search' button.
   
   =cut
   
   ######################################################################
   ######################################################################
   sub revise_button {
       my $revise_phase = 'disp_basic';
       $revise_phase = 'disp_adv' if ($ENV{'form.searchmode'} eq 'advanced');
       my $newloc = '/adm/searchcat'.
           '?persistent_db_id='.$ENV{'form.persistent_db_id'}.
               '&cleargroupsort=1'.
               '&phase='.$revise_phase;
       my $result = qq{<input type="button" value="Revise search" name="revise"} .
           qq{ onClick="parent.location='$newloc';" /> };
       return $result;
   }
   
   ######################################################################
   ######################################################################
   
   =pod
   
 =item &run_search   =item &run_search 
   
 =cut  =cut
Line 1698  sub update_seconds { Line 2036  sub update_seconds {
 ######################################################################  ######################################################################
 sub run_search {  sub run_search {
     my ($r,$query,$customquery,$customshow,$serverlist,$pretty_string) = @_;      my ($r,$query,$customquery,$customshow,$serverlist,$pretty_string) = @_;
       my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
     my $connection = $r->connection;      my $connection = $r->connection;
     #      #
     # Timing variables      # Timing variables
     #      #
     my $starttime = time;      my $starttime = time;
     my $max_time  = 120;  # seconds for the search to complete      my $max_time  = 30;  # seconds for the search to complete
     #      #
     # Print run_search header      # Print run_search header
     #      #
     $r->print("<html><head><title>Search Status</title></head><body>");      $r->print(<<END);
     $r->print("Search: ".$pretty_string."\n");  <html>
   <head><title>Search Status</title></head>
   $bodytag
   <form name="statusform" action="" method="post">
   <input type="hidden" name="Queue" value="" />
   END
       # Check to see if $pretty_string has more than one carriage return.
       # Assume \n s are following <br /> s and truncate the value.
       # (there is probably a better way)...
       my @Lines = split /<br \/>/,$pretty_string;
       if (@Lines > 2) {
           $pretty_string = join '<br \>',(@Lines[0..2],'....<br />');
       }
       $r->print(&mt("Search").": ".$pretty_string);
     $r->rflush();      $r->rflush();
     #      #
     # Determine the servers we need to contact.      # Determine the servers we need to contact.
     #      #
     my @Servers_to_contact;      my @Servers_to_contact;
     if (defined($serverlist)) {      if (defined($serverlist)) {
         @Servers_to_contact = @$serverlist;          if (ref($serverlist) eq 'ARRAY') {
               @Servers_to_contact = @$serverlist;
           } else {
               @Servers_to_contact = ($serverlist);
           }
     } else {      } else {
         @Servers_to_contact = sort(keys(%Apache::lonnet::libserv));          @Servers_to_contact = sort(keys(%Apache::lonnet::libserv));
     }      }
Line 1746  sub run_search { Line 2102  sub run_search {
     my $hitcountsum;      my $hitcountsum;
     my $server;       my $server; 
     my $status;      my $status;
       my $revise = &revise_button();
     $r->print(<<END);      $r->print(<<END);
 <form name="statusform" action="" method="post">  
 <input type="hidden" name="Queue" value="" />  
 <table>  <table>
 <tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th></tr>  <tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th><th></th></tr>
 <tr>  <tr>
 <td><input type="text" name="status"  value="" size="30" /></td>  <td><input type="text" name="status"  value="" size="30" /></td>
 <td><input type="text" name="count"   value="" size="10" /></td>  <td><input type="text" name="count"   value="" size="10" /></td>
 <td><input type="text" name="seconds" value="" size="8" /></td>  <td><input type="text" name="seconds" value="" size="8" /></td>
   <td>$revise</td>
 </tr>  </tr>
 </table>  </table>
 </form>  </form>
Line 1763  END Line 2119  END
     my $time_remaining = $max_time - (time - $starttime) ;      my $time_remaining = $max_time - (time - $starttime) ;
     my $last_time = $time_remaining;      my $last_time = $time_remaining;
     &update_seconds($r,$time_remaining);      &update_seconds($r,$time_remaining);
     while (($time_remaining > 0) &&       &update_status($r,'contacting '.$Servers_to_contact[0]);
       while (($time_remaining > 0) &&
            ((@Servers_to_contact) || keys(%Server_status))) {             ((@Servers_to_contact) || keys(%Server_status))) {
         # Send out a search request if it needs to be done.          # Send out a search request if it needs to be done.
         if (@Servers_to_contact) {          if (@Servers_to_contact) {
             # Contact one server              # Contact one server
             my $server = shift(@Servers_to_contact);              my $server = shift(@Servers_to_contact);
               &update_status($r,&mt('contacting').' '.$server);
             my $reply=&Apache::lonnet::metadata_query($query,$customquery,              my $reply=&Apache::lonnet::metadata_query($query,$customquery,
                                                       $customshow,[$server]);                                                        $customshow,[$server]);
             ($server) = keys(%$reply);              ($server) = keys(%$reply);
             $Server_status{$server} = $reply->{$server};              $Server_status{$server} = $reply->{$server};
             &update_status($r,'contacting '.$server);  
         } else {          } else {
             # wait a sec. to give time for files to be written              # wait a sec. to give time for files to be written
             # This sleep statement is here instead of outside the else               # This sleep statement is here instead of outside the else 
             # block because we do not want to pause if we have servers              # block because we do not want to pause if we have servers
             # left to contact.                # left to contact.  
               if (scalar (keys(%Server_status))) {
                   &update_status($r,
                          &mt('waiting on').' '.(join(' ',keys(%Server_status))));
               }
             sleep(1)              sleep(1)
         }          }
         &update_status($r,'waiting on '.(join(' ',keys(%Server_status))));          #
           #
           # Loop through the servers we have contacted but do not
           # have results from yet, looking for results.
         while (my ($server,$status) = each(%Server_status)) {          while (my ($server,$status) = each(%Server_status)) {
             last if ($connection->aborted());              last if ($connection->aborted());
             if ($status eq 'con_lost') {              if ($status eq 'con_lost') {
Line 1791  END Line 2155  END
             $status=~/^([\.\w]+)$/;               $status=~/^([\.\w]+)$/; 
            my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1;             my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1;
             if (-e $datafile && ! -e "$datafile.end") {              if (-e $datafile && ! -e "$datafile.end") {
                 &update_status($r,'Receiving results from '.$server);                  &update_status($r,&mt('Receiving results from').' '.$server);
                 next;                  next;
             }              }
             last if ($connection->aborted());              last if ($connection->aborted());
             if (-e "$datafile.end") {              if (-e "$datafile.end") {
                 &update_status($r,'Reading results from '.$server);                  &update_status($r,&mt('Reading results from').' '.$server);
                 if (-z "$datafile") {                  if (-z "$datafile") {
                     delete($Server_status{$server});                      delete($Server_status{$server});
                     next;                      next;
Line 1844  END Line 2208  END
         }          }
         last if ($connection->aborted());          last if ($connection->aborted());
         # Finished looping through the servers          # Finished looping through the servers
           $starttime = time if (@Servers_to_contact);
         $time_remaining = $max_time - (time - $starttime) ;          $time_remaining = $max_time - (time - $starttime) ;
         if ($last_time - $time_remaining > 0) {          if ($last_time - $time_remaining > 0) {
             $last_time = $time_remaining;              $last_time = $time_remaining;
             &update_seconds($r,$time_remaining);              &update_seconds($r,$time_remaining);
         }          }
     }      }
     &update_status($r,'Search Complete'.$server);      &update_status($r,&mt('Search Complete').$server);
       &update_seconds($r,0);
     &Apache::lonmysql::disconnect_from_db();      &Apache::lonmysql::disconnect_from_db();
     # Let the user know  
     #  
     # We have run out of time or run out of servers to talk to and      # We have run out of time or run out of servers to talk to and
     # results to get.        # results to get.  
     $r->print("<b>Search Completed.</b>&nbsp;&nbsp;");  
     if ($hitcountsum) {  
         $r->print($hitcountsum." matches were found.");  
     } else {  
         $r->print("There were no successful matches to your query.");  
     }  
     $r->print("</body></html>");      $r->print("</body></html>");
       if ($ENV{'form.catalogmode'} ne 'groupsearch') {
           $r->print("<script>".
                         "window.location='/adm/searchcat?".
                         "phase=sort&".
                         "persistent_db_id=$ENV{'form.persistent_db_id'}';".
                     "</script>");
       }
     return;      return;
 }  }
   
Line 1883  sub prev_next_buttons { Line 2248  sub prev_next_buttons {
     ##      ##
     ## Prev      ## Prev
     my $prev_min = $current_min - $show;      my $prev_min = $current_min - $show;
     $prev_min = 0 if $prev_min < 0;      $prev_min = 1 if $prev_min < 1;
     if ($prev_min < $current_min) {      if ($prev_min < $current_min) {
         $links .= qq{          $links .= qq{
 <a href="/adm/searchcat?$parms&start=$prev_min&show=$show">prev</a>  <a href="/adm/searchcat?$parms&start=$prev_min&show=$show">prev</a>
Line 1922  sub prev_next_buttons { Line 2287  sub prev_next_buttons {
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub display_results {  sub display_results {
     my ($r,$importbutton,$closebutton) = @_;      my ($r,$importbutton,$closebutton,$diropendb) = @_;
     my $connection = $r->connection;      my $connection = $r->connection;
     $r->print(&search_results_header($importbutton,$closebutton));      $r->print(&search_results_header($importbutton,$closebutton));
     ##      ##
Line 1935  sub display_results { Line 2300  sub display_results {
         return;          return;
     }      }
     ##      ##
       ## $checkbox_num is a count of the number of checkboxes output on the 
       ## page this is used only during catalogmode=groupsearch.
       my $checkbox_num = 0;
       ##
     ## Get the catalog controls setup      ## Get the catalog controls setup
     ##      ##
     my $action = "/adm/searchcat?phase=results";      my $action = "/adm/searchcat?phase=results";
Line 1953  sub display_results { Line 2322  sub display_results {
     ## Prepare the table for querying      ## Prepare the table for querying
     ##      ##
     my $table = $ENV{'form.table'};      my $table = $ENV{'form.table'};
     my $connection_result = &Apache::lonmysql::connect_to_db();      return if (! &ensure_db_and_table($r,$table));
     if (!defined($connection_result)) {  
         $r->print(&Apache::lonmysql::get_error());  
     }  
     my $table_check = &Apache::lonmysql::check_table($table);  
     if (! defined($table_check)) {  
         $r->print("A MySQL error has occurred.</form></body></html>");  
         &Apache::lonnet::logthis("lonmysql was unable to determine the status".  
                                  " of table ".$table);  
         return;  
     } elsif (! $table_check) {  
         $r->print("The table of results could not be found.");  
         &Apache::lonnet::logthis("The user requested a table, ".$table.  
                                  ", that could not be found.");  
         return;  
     }  
     ##      ##
     ## Get the number of results       ## Get the number of results 
     ##      ##
Line 1978  sub display_results { Line 2332  sub display_results {
         &Apache::lonnet::logthis("lonmysql was unable to determine the number".          &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                                  " of rows in table ".$table);                                   " of rows in table ".$table);
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
         &Apache::lonnet::logthis(&Apache::lonmysql::get_debug());  
         return;          return;
     }      }
     ##      ##
     ## Determine how many results we need to get      ## Determine how many results we need to get
     ##      ##
     $ENV{'form.show'} = 20;      $ENV{'form.start'} = 1      if (! exists($ENV{'form.start'}));
     $ENV{'form.start'} = 0      if (! exists($ENV{'form.start'}));      $ENV{'form.show'}  = 'all'  if (! exists($ENV{'form.show'}));
     $ENV{'form.show'}      = 'all'  if (! exists($ENV{'form.show'}));  
     my $min = $ENV{'form.start'};      my $min = $ENV{'form.start'};
     my $max;      my $max;
     if ($ENV{'form.show'} eq 'all') {      if ($ENV{'form.show'} eq 'all') {
         $max = $total_results ;          $max = $total_results ;
     } else {      } else {
         $max = $min + $ENV{'form.show'};          $max = $min + $ENV{'form.show'} - 1;
         $max = $total_results if ($max > $total_results);          $max = $total_results if ($max > $total_results);
     }      }
     ##      ##
Line 2007  sub display_results { Line 2359  sub display_results {
          ."</center>\n"           ."</center>\n"
          );           );
     if ($total_results == 0) {      if ($total_results == 0) {
         $r->print("There are currently no results.\n".          $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="1">'.
                     '<h3>'.&mt('There are currently no results').'.</h3>'.
                   "</form></body></html>");                    "</form></body></html>");
         return;          return;
     } else {      } else {
Line 2018  sub display_results { Line 2371  sub display_results {
     ## Get results from MySQL table      ## Get results from MySQL table
     ##      ##
     my @Results = &Apache::lonmysql::get_rows($table,      my @Results = &Apache::lonmysql::get_rows($table,
                                               'id>'.$min.' AND id<='.$max);                                                'id>='.$min.' AND id<='.$max);
     ##      ##
     ## Loop through the results and output them.      ## Loop through the results and output them.
     ##      ##
     foreach my $row (@Results) {      foreach my $row (@Results) {
         if ($connection->aborted()) {          if ($connection->aborted()) {
             untie %groupsearch_db if (tied(%groupsearch_db));              &cleanup();
             &Apache::lonmysql::disconnect_from_db();  
             return;              return;
         }          }
         my %Fields = %{&parse_row(@$row)};          my %Fields = %{&parse_row(@$row)};
         my $output="<p>\n";          my $output="<p>\n";
         my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'});          my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'},
                                          $Fields{'id'},$checkbox_num++);
         # Render the result into html          # Render the result into html
         $output.= &$viewfunction($prefix,%Fields);          $output.= &$viewfunction($prefix,%Fields);
         # Print them out as they come in.          # Print them out as they come in.
Line 2038  sub display_results { Line 2391  sub display_results {
         $r->rflush();          $r->rflush();
     }      }
     if (@Results < 1) {      if (@Results < 1) {
         $r->print("There were no results matching your query");          $r->print(&mt("There were no results matching your query"));
     } else {      } else {
         $r->print          $r->print
             ('<center>'.              ('<center>'.
Line 2061  sub display_results { Line 2414  sub display_results {
   
 =pod  =pod
   
 =item &catalogmode_output($title,$url)  =item &catalogmode_output($title,$url,$fnum,$checkbox_num)
   
 Returns html needed for the various catalog modes.  Gets inputs from  Returns html needed for the various catalog modes.  Gets inputs from
 $ENV{'form.catalogmode'}.  Stores data in %groupsearch_db and $fnum   $ENV{'form.catalogmode'}.  Stores data in %groupsearch_db.
 (local variable).  
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 {   
 my $fnum = 0;  
   
 sub catalogmode_output {  sub catalogmode_output {
     my $output = '';      my $output = '';
     my ($title,$url) = @_;      my ($title,$url,$fnum,$checkbox_num) = @_;
     if ($ENV{'form.catalogmode'} eq 'interactive') {      if ($ENV{'form.catalogmode'} eq 'interactive') {
         $title=~ s/\'/\\\'/g;          $title=~ s/\'/\\\'/g;
         if ($ENV{'form.catalogmode'} eq 'interactive') {          if ($ENV{'form.catalogmode'} eq 'interactive') {
Line 2092  END Line 2441  END
         $output.=<<END;          $output.=<<END;
 <font size='-1'>  <font size='-1'>
 <input type="checkbox" name="returnvalues" value="SELECT"  <input type="checkbox" name="returnvalues" value="SELECT"
 onClick="javascript:queue($fnum)" />  onClick="javascript:queue($checkbox_num,$fnum)" />
 </font>  </font>
 END  END
         $fnum++;  
     }      }
     return $output;      return $output;
 }  }
   
 }  
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 2118  sub parse_row { Line 2464  sub parse_row {
     my @Row = @_;      my @Row = @_;
     my %Fields;      my %Fields;
     for (my $i=0;$i<=$#Row;$i++) {      for (my $i=0;$i<=$#Row;$i++) {
         $Fields{$DataOrder[$i]}=&Apache::lonnet::unescape($Row[$i]);          $Fields{$Datatypes[$i]->{'name'}}=&Apache::lonnet::unescape($Row[$i]);
     }      }
     $Fields{'language'} =       $Fields{'language'} = 
         &Apache::loncommon::languagedescription($Fields{'lang'});          &Apache::loncommon::languagedescription($Fields{'lang'});
Line 2288  Checked for existance & 'edit' mode. Line 2634  Checked for existance & 'edit' mode.
   
 =item 'form.form'  =item 'form.form'
   
   Contains the name of the form that has the input fields to set
   
 =item 'form.element'  =item 'form.element'
   
   the name of the input field to put the URL into
   
   =item 'form.titleelement'
   
   the name of the input field to put the title into
   
 =back  =back
   
 =cut  =cut
Line 2298  Checked for existance & 'edit' mode. Line 2652  Checked for existance & 'edit' mode.
 ######################################################################  ######################################################################
 sub search_results_header {  sub search_results_header {
     my ($importbutton,$closebutton) = @_;      my ($importbutton,$closebutton) = @_;
       my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
     my $result = '';      my $result = '';
     # output beginning of search page      # output beginning of search page
     # conditional output of script functions dependent on the mode in      # conditional output of script functions dependent on the mode in
Line 2312  sub search_results_header { Line 2667  sub search_results_header {
  parent.close();   parent.close();
     }      }
     function changeTitle(val) {      function changeTitle(val) {
  if (opener.inf.document.forms.resinfo.elements.t) {   if (parent.opener.inf.document.forms.resinfo.elements.t) {
     opener.inf.document.forms.resinfo.elements.t.value=val;      parent.opener.inf.document.forms.resinfo.elements.t.value=val;
  }   }
     }      }
     function changeURL(val) {      function changeURL(val) {
  if (opener.inf.document.forms.resinfo.elements.u) {   if (parent.opener.inf.document.forms.resinfo.elements.u) {
     opener.inf.document.forms.resinfo.elements.u.value=val;      parent.opener.inf.document.forms.resinfo.elements.u.value=val;
  }   }
     }      }
 </script>  </script>
Line 2326  SCRIPT Line 2681  SCRIPT
         } elsif ($ENV{'form.mode'} eq 'edit') {          } elsif ($ENV{'form.mode'} eq 'edit') {
             my $form = $ENV{'form.form'};              my $form = $ENV{'form.form'};
             my $element = $ENV{'form.element'};              my $element = $ENV{'form.element'};
               my $titleelement = $ENV{'form.titleelement'};
       my $changetitle;
       if (!$titleelement) {
    $changetitle='function changeTitle(val) {}';
       } else {
       $changetitle=<<END;
   function changeTitle(val) {
       if (parent.targetwin.document) {
           parent.targetwin.document.forms["$form"].elements["$titleelement"].value=val;
       } else {
    var url = 'forms[\"$form\"].elements[\"$titleelement\"].value';
           alert("Unable to transfer data to "+url);
       }
   }
   END
               }
   
             $result.=<<SCRIPT;              $result.=<<SCRIPT;
 <script type="text/javascript">  <script type="text/javascript">
 function select_data(title,url) {  function select_data(title,url) {
     changeURL(url);      changeURL(url);
       changeTitle(title);
     parent.close();      parent.close();
 }  }
 function changeTitle(val) {  $changetitle
 }  
 function changeURL(val) {  function changeURL(val) {
     if (parent.targetwin.document) {      if (parent.targetwin.document) {
         parent.targetwin.document.forms["$form"].elements["$element"].value=val;          parent.targetwin.document.forms["$form"].elements["$element"].value=val;
Line 2348  SCRIPT Line 2720  SCRIPT
     }      }
     $result.=<<SCRIPT if $ENV{'form.catalogmode'} eq 'groupsearch';      $result.=<<SCRIPT if $ENV{'form.catalogmode'} eq 'groupsearch';
 <script type="text/javascript">  <script type="text/javascript">
     function queue(val) {      function queue(checkbox_num,val) {
         if (document.forms.results.returnvalues[val].checked) {          if (document.forms.results.returnvalues.length != "undefined" &&
             parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';              typeof(document.forms.results.returnvalues.length) == "number") {
               if (document.forms.results.returnvalues[checkbox_num].checked) {
                   parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';
               } else {
                   parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';
               }
         } else {          } else {
             parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';              if (document.forms.results.returnvalues.checked) {
                   parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';
               } else {
                   parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';
               }
         }          }
     }      }
     function select_group() {      function select_group() {
Line 2364  SCRIPT Line 2745  SCRIPT
 SCRIPT  SCRIPT
     $result.=<<END;      $result.=<<END;
 </head>  </head>
   $bodytag
 <form name="results" method="post" action="" >  <form name="results" method="post" action="" >
 <input type="hidden" name="Queue" value="" />  <input type="hidden" name="Queue" value="" />
 $importbutton  $importbutton
Line 2374  END Line 2756  END
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub search_status_header {  sub search_status_header {
       my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
     return <<ENDSTATUS;      return <<ENDSTATUS;
 <html><head><title>Search Status</title></head>  <html><head><title>Search Status</title></head>
 <body>  $bodytag
 <h3>Search Status</h3>  <h3>Search Status</h3>
 Sending search request to LON-CAPA servers.<br />  Sending search request to LON-CAPA servers.<br />
 ENDSTATUS  ENDSTATUS
Line 2386  sub results_link { Line 2769  sub results_link {
     my $basic_link   = "/adm/searchcat?"."&table=".$ENV{'form.table'}.      my $basic_link   = "/adm/searchcat?"."&table=".$ENV{'form.table'}.
         "&persistent_db_id=".$ENV{'form.persistent_db_id'};          "&persistent_db_id=".$ENV{'form.persistent_db_id'};
     my $results_link = $basic_link."&phase=results".      my $results_link = $basic_link."&phase=results".
         "&pause=10"."&start=0"."&show=20";          "&pause=1"."&start=1";
     return $results_link;      return $results_link;
 }  }
   
Line 2403  sub print_frames_interface { Line 2786  sub print_frames_interface {
 <head>  <head>
 <script>  <script>
 var targetwin = opener;  var targetwin = opener;
   var queue = '';
 </script>  </script>
 <title>LON-CAPA Digital Library Search Results</title>  <title>LON-CAPA Digital Library Search Results</title>
 </head>  </head>
Line 2440  extra custom metadata to show. Line 2824  extra custom metadata to show.
 ######################################################################  ######################################################################
 sub detailed_citation_view {  sub detailed_citation_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
       my $icon=&Apache::loncommon::icon($values{'url'});
     my $result=<<END;      my $result=<<END;
 <b>$prefix<a href="http://$ENV{'HTTP_HOST'}$values{'url'}"   <b>$prefix<img src="$icon" /><a href="http://$ENV{'HTTP_HOST'}$values{'url'}" 
     target='search_preview'>$values{'title'}</a></b>      target='search_preview'>$values{'title'}</a></b>
 <p>  <p>
 <b>$values{'author'}</b>, <i>$values{'owner'}</i><br />  <b>$values{'author'}</b>, <i>$values{'owner'}</i><br />
Line 2474  END Line 2859  END
 ######################################################################  ######################################################################
 sub summary_view {  sub summary_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
       my $icon=&Apache::loncommon::icon($values{'url'});
     my $result=<<END;      my $result=<<END;
 $prefix<a href="http://$ENV{'HTTP_HOST'}$values{'url'}"   $prefix<img src="$icon" /><a href="http://$ENV{'HTTP_HOST'}$values{'url'}" 
    target='search_preview'>$values{'author'}</a><br />     target='search_preview'>$values{'author'}</a><br />
 $values{'title'}<br />  $values{'title'}<br />
 $values{'owner'} -- $values{'lastrevisiondate'}<br />  $values{'owner'} -- $values{'lastrevisiondate'}<br />
Line 2500  END Line 2886  END
 ######################################################################  ######################################################################
 sub compact_view {  sub compact_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
       my $icon=&Apache::loncommon::icon($values{'url'});
     my $result=<<END;      my $result=<<END;
 $prefix <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"  target='search_preview'>  $prefix <img src="$icon" /> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"  target='search_preview'>
 $values{'title'}</a>  $values{'title'}</a>
 <b>$values{'author'}</b><br />  <b>$values{'author'}</b><br />
 END  END
Line 2522  END Line 2909  END
 ######################################################################  ######################################################################
 sub fielded_format_view {  sub fielded_format_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
       my $icon=&Apache::loncommon::icon($values{'url'});
     my $result=<<END;      my $result=<<END;
 $prefix  $prefix <img src="$icon" />
 <b>URL: </b> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"   <b>URL: </b> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}" 
               target='search_preview'>$values{'url'}</a>                target='search_preview'>$values{'url'}</a>
 <br />  <br />
Line 2625  sub filled { Line 3013  sub filled {
   
 =item &output_blank_field_error()  =item &output_blank_field_error()
   
   Output a complete page that indicates the user has not filled in enough
   information to do a search.
   
   Inputs: $r (Apache request handle), $closebutton, $parms.
   
   Returns: nothing
   
   $parms is extra information to include in the 'Revise search request' link.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_blank_field_error {  sub output_blank_field_error {
     my ($r,$closebutton)=@_;      my ($r,$closebutton,$parms,$hidden_fields)=@_;
       my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
     $r->print(<<BEGINNING);      $r->print(<<BEGINNING);
 <html>  <html>
Line 2639  sub output_blank_field_error { Line 3037  sub output_blank_field_error {
 BEGINNING  BEGINNING
     $r->print(<<RESULTS);      $r->print(<<RESULTS);
 </head>  </head>
 <body bgcolor="#ffffff">  $bodytag
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  <img align='right' src='/adm/lonIcons/lonlogos.gif' />
 <h1>Search Catalog</h1>  <h1>Search Catalog</h1>
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $hidden_fields  $hidden_fields
 <a href="/adm/searchcat?persistent_db_id=$ENV{'form.persistent_db_id'}"  <a href="/adm/searchcat?$parms&persistent_db_id=$ENV{'form.persistent_db_id'}"
 >Revise search request</a>&nbsp;  >Revise search request</a>&nbsp;
 $closebutton  $closebutton
 <hr />  <hr />
 <h3>Helpful Message</h3>  <h3>Unactionable search query.</h3>
 <p>  <p>
 Incorrect search query due to blank entry fields.  You did not fill in enough information for the search to be started.
 You need to fill in the relevant  You need to fill in relevant fields on the search page in order 
 fields on the search page in order for a query to be  for a query to be processed.
 processed.  
 </p>  </p>
 </body>  </body>
 </html>  </html>
Line 2680  Inputs: Line 3077  Inputs:
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_date_error {  sub output_date_error {
     my ($r,$message,$closebutton)=@_;      my ($r,$message,$closebutton,$hidden_fields)=@_;
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
       my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);
     $r->print(<<RESULTS);      $r->print(<<RESULTS);
 <html>  <html>
 <head>  <head>
 <title>The LearningOnline Network with CAPA</title>  <title>The LearningOnline Network with CAPA</title>
 </head>  </head>
 <body bgcolor="#ffffff">  $bodytag
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  <img align='right' src='/adm/lonIcons/lonlogos.gif' />
 <h1>Search Catalog</h1>  <h1>Search Catalog</h1>
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
Line 2696  $hidden_fields Line 3094  $hidden_fields
 onClick='this.form.submit();' />  onClick='this.form.submit();' />
 $closebutton  $closebutton
 <hr />  <hr />
 <h3>Helpful Message</h3>  <h3>Error</h3>
 <p>  <p>
 $message  $message
 </p>  </p>
Line 2733  sub start_fresh_session { Line 3131  sub start_fresh_session {
   
 1;  1;
   
   sub cleanup {
       if (tied(%groupsearch_db)) {
           unless (untie(%groupsearch_db)) {
     &Apache::lonnet::logthis('Failed cleanup searchcat: groupsearch_db');
           }
       }
       &untiehash();
       &Apache::lonmysql::disconnect_from_db();
   }
   
 __END__  __END__
   
 =pod  =pod

Removed from v.1.150  
changed lines
  Added in v.1.196


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>