File:  [LON-CAPA] / loncom / interface / lonsearchcourse.pm
Revision 1.2: download - view: text, annotated - select for diffs
Mon Jan 17 20:43:09 2011 UTC (13 years, 4 months ago) by www
Branches: MAIN
CVS tags: HEAD
Fix breadcrumbs

    1: # The LearningOnline Network with CAPA
    2: # Search Course
    3: #
    4: # $Id: lonsearchcourse.pm,v 1.2 2011/01/17 20:43:09 www Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: ###############################################################################
   29: ###############################################################################
   30: 
   31: package Apache::lonsearchcourse;
   32: 
   33: use strict;
   34: use Apache::Constants qw(:common :http);
   35: use Apache::lonnet;
   36: use GDBM_File;
   37: use Apache::loncommon();
   38: use Apache::lonmeta;
   39: use Apache::lonhtmlcommon;
   40: use Apache::lonlocal;
   41: use LONCAPA::lonmetadata();
   42: use HTML::Entities();
   43: use Apache::lonnavmaps;
   44: use Apache::londocs();
   45: use Apache::lonindexer();
   46: use LONCAPA;
   47: 
   48: # Variables For course search
   49: my %alreadyseen;
   50: my %hash;
   51: my $totalfound;
   52: 
   53: 
   54: sub menu {
   55:     my $scrout='';
   56:     if ($env{'request.course.id'}) {
   57:         my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
   58:                                            'header' => 'Course Search',
   59:          'note' => 'Enter terms or phrases, then press "Search" below',
   60:          'use' => 'use related words',
   61:          'full' =>'fulltext search (time consuming)',
   62:          'disc' => 'search discussion postings (resources and discussion boards)',
   63:                                            );
   64:         $scrout.=(<<ENDCOURSESEARCH);
   65: <form name="loncapa_search" method="post" action="/adm/searchcourse">
   66: <center>
   67: <hr />
   68: <h1>$lt{'header'}</h1>    
   69: <input type="hidden" name="phase" value="results" />
   70: <p>
   71: $lt{'note'}.
   72: </p>
   73: <table>
   74: <tr><td>
   75: ENDCOURSESEARCH
   76:         $scrout.='&nbsp;'.
   77:             &Apache::lonhtmlcommon::textbox('courseexp',
   78:                                   $env{'form.courseexp'},40);
   79:         my $crscheckbox =
   80:             &Apache::lonhtmlcommon::checkbox('crsfulltext',
   81:                                    $env{'form.crsfulltext'});
   82:         my $relcheckbox =
   83:             &Apache::lonhtmlcommon::checkbox('crsrelated',
   84:                                    $env{'form.crsrelated'});
   85:         my $discheckbox =
   86:             &Apache::lonhtmlcommon::checkbox('crsdiscuss',
   87:                                    $env{'form.crsrelated'});
   88:         $scrout.=(<<ENDENDCOURSE);
   89: </td></tr>
   90: <tr><td><label>$relcheckbox $lt{'use'}</label></td><td></td></tr>
   91: <tr><td><label>$crscheckbox $lt{'full'}</label></td><td></td></tr>
   92: <tr><td><label>$discheckbox $lt{'disc'}</label></td><td></td></tr>
   93: </table>
   94: <p>
   95: <input type="submit" name="coursesubmit" value='$lt{'srch'}' />
   96: </p>
   97: </center>
   98: </form>
   99: ENDENDCOURSE
  100:     }
  101:     return $scrout;
  102: }
  103: 
  104: sub make_symb {
  105:     my ($id)=@_;
  106:     my ($mapid,$resid)=split(/\./,$id);
  107:     my $map=$hash{'map_id_'.$mapid};
  108:     my $res=$hash{'src_'.$id};
  109:     my $symb=&Apache::lonnet::encode_symb($map,$resid,$res);
  110:     return $symb;
  111: }
  112: 
  113: sub related_version {
  114:     my ($word) = @_;
  115:     return (undef) if (lc($word) =~ /\b(or|and|not)\b/);
  116:     my @Words = &Apache::loncommon::get_related_words($word);
  117:     # Only use 4 related words
  118:     @Words = ($#Words>4? @Words[0..4] : @Words);
  119:     my $result = join " OR ", ($word,@Words);
  120:     return $result,sort(@Words);
  121: }
  122: 
  123: sub course_search {
  124:     my $r=shift;
  125:     my $pretty_search_string = '<b>'.$env{'form.courseexp'}.'</b>';
  126:     my $search_string = $env{'form.courseexp'};
  127:     my @New_Words;
  128:     undef(%alreadyseen);
  129:     if ($env{'form.crsrelated'}) {
  130:         ($search_string,@New_Words) = &related_version($env{'form.courseexp'});
  131:         if (@New_Words) {
  132:             $pretty_search_string .= ' '.&mt("with related words").": <b>@New_Words</b>.";
  133:         } else {
  134:             $pretty_search_string .= ' '.&mt('with no related words').".";
  135:         }
  136:     }
  137:     my $fulltext=$env{'form.crsfulltext'};
  138:     my $discuss=$env{'form.crsdiscuss'};
  139:     my @allwords=($search_string,@New_Words);
  140:     $totalfound=0;
  141: 
  142:     $r->print(
  143:               '<hr /><center><font size="+2" face="arial">'.
  144:               $pretty_search_string.'</font></center>'.
  145:               '<hr /><b>'.&mt('Course content').':</b><br />');
  146:     $r->rflush();
  147: # ======================================================= Go through the course
  148:     my $c=$r->connection;
  149:     if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db",
  150:             &GDBM_READER(),0640)) {
  151:         foreach (sort(keys(%hash))) {
  152:             if ($c->aborted()) { last; }
  153:             if (($_=~/^src\_(.+)$/)) {
  154:                 if ($hash{'randomout_'.$1} & !$env{'request.role.adv'}) {
  155:                     next;
  156:                 }
  157:                 my $symb=&make_symb($1);
  158:                 &checkonthis($r,$1,$hash{$_},0,&Apache::lonnet::gettitle($symb),
  159:                              $fulltext,$symb,@allwords);
  160:             }
  161:         }
  162:         untie(%hash);
  163:     }
  164:     unless ($totalfound) {
  165:         $r->print('<p class="LC_info">'.&mt('No matches found in resources.').'</p>');
  166:     }
  167: 
  168: # Check discussions if requested
  169:     if ($discuss) {
  170:         my $totaldiscussions = 0;
  171:         $r->print('<br /><br /><b>'.&mt('Discussion postings').':</b><br />');
  172:         my $navmap = Apache::lonnavmaps::navmap->new();
  173:         if (defined($navmap)) {
  174:             my @allres=$navmap->retrieveResources();
  175:             my %discussiontime = &Apache::lonnet::dump('discussiontimes',
  176:                                    $env{'course.'.$env{'request.course.id'}.'.domain'},
  177:                                    $env{'course.'.$env{'request.course.id'}.'.num'});
  178:             foreach my $resource (@allres) {
  179:                 my $result = '';
  180:                 my $applies = 0;
  181:                 my $symb = $resource->symb();
  182:                 my $ressymb = $symb;
  183:                 if ($symb =~ m#(___adm/$LONCAPA::domain_re/$LONCAPA::username_re)/(\d+)/bulletinboard$#) {
  184:                     $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
  185:                     unless ($ressymb =~ m#bulletin___\d+___adm/wrapper#) {
  186:                         $ressymb=~s#(bulletin___\d+___)#$1adm/wrapper/#;
  187:                     }
  188:                 }
  189:                 if (defined($discussiontime{$ressymb})) {
  190:                     my %contrib = &Apache::lonnet::restore($ressymb,$env{'request.course.id'},
  191:                          $env{'course.'.$env{'request.course.id'}.'.domain'},
  192:                          $env{'course.'.$env{'request.course.id'}.'.num'});
  193:                     if ($contrib{'version'}) {
  194:                         for (my $id=1;$id<=$contrib{'version'};$id++) {
  195:                             unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
  196:                                 if ($contrib{$id.':subject'}) {
  197:                                     $result .= $contrib{$id.':subject'};
  198:                                 }
  199:                                 if ($contrib{$id.':message'}) {
  200:                                     $result .= $contrib{$id.':message'};
  201:                                 }
  202:                                 if ($contrib{$id,':attachmenturl'}) {
  203:                                     if ($contrib{$id,':attachmenturl'} =~ m-/([^/]+)$-) {
  204:                                         $result .= $1;
  205:                                     }
  206:                                 }
  207:                                 $applies = &checkwords($result,$applies,@allwords);
  208:                             }
  209:                         }
  210:                     }
  211:                 }
  212: # Does this discussion apply?
  213:                 if ($applies) {
  214:                     my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ressymb);
  215:                     my $disctype = &mt('resource');
  216:                     if ($url =~ m#/bulletinboard$#) {
  217:                         if ($url =~m#^adm/wrapper/adm/.*/bulletinboard$#) {
  218:                             $url =~s#^adm/wrapper##;
  219:                         }
  220:                         $disctype = &mt('discussion board');
  221:                     } else {
  222:                         $url = '/res/'.$url;
  223:                     }
  224:                     if ($url =~ /\?/) {
  225:                         $url .= '&amp;symb=';
  226:                     } else {
  227:                         $url .= '?symb=';
  228:                     }
  229:                     $url .= &escape($resource->symb());
  230:                     my $title = $resource->compTitle();
  231:                     $r->print('<br /><a href="'.$url.'" target="cat">'.
  232:                          ($title?$title:$url).'</a>&nbsp;&nbsp;-&nbsp;'.
  233:                          $disctype.'<br />');
  234:                     $totaldiscussions++;
  235:                 } else {
  236:                     $r->print(' .');
  237:                 }
  238:             }
  239:             unless ($totaldiscussions) {
  240:                 $r->print('<p class="LC_info">'.&mt('No matches found in postings.').'</p>');
  241:             }
  242:         } else {
  243:             $r->print('<div class="LC_error">'.&mt('An error occurred retrieving information about resources in the course.').'<br />'.&mt('It is recommended that you [_1]re-initialize the course[_2] and then try your search again.','<a href="/adm/roles">','</a>').'</div>');
  244:         }
  245:     }
  246: 
  247: # =================================================== Done going through course
  248:     $r->print(&Apache::loncommon::end_page());
  249: }
  250: 
  251: # =============================== This pulls up a resource and its dependencies
  252: 
  253: sub checkonthis {
  254:     my ($r,$id,$url,$level,$title,$fulltext,$symb,@allwords)=@_;
  255:     $alreadyseen{$id}=1;
  256:     if (&Apache::loncommon::connection_aborted($r)) { return; }
  257:     $r->rflush();
  258: 
  259:     my $result=$title.' ';
  260:     if ($env{'request.role.adv'} || !$hash{'encrypted_'.$id}) {
  261:         $result.=&Apache::lonnet::metadata($url,'title').' '.
  262:             &Apache::lonnet::metadata($url,'subject').' '.
  263:             &Apache::lonnet::metadata($url,'abstract').' '.
  264:             &Apache::lonnet::metadata($url,'keywords');
  265:     }
  266:     my ($extension)=($url=~/\.(\w+)$/);
  267:     if (&Apache::loncommon::fileembstyle($extension) eq 'ssi' &&
  268:         ($url) && ($fulltext)) {
  269:         $result.=&Apache::lonnet::ssi_body($url.'?symb='.&escape($symb));
  270:     }
  271:     $result=~s/\s+/ /gs;
  272:     my $applies = 0;
  273:     $applies = &checkwords($result,$applies,@allwords);
  274: # Does this resource apply?
  275:     if ($applies) {
  276:        $r->print('<br />');
  277:        for (my $i=0;$i<=$level*5;$i++) {
  278:            $r->print('&nbsp;');
  279:        }
  280:        my $href=$url;
  281:        if ($hash{'encrypted_'.$id} && !$env{'request.role.adv'}) {
  282:            $href=&Apache::lonenc::encrypted($href)
  283:                .'?symb='.&Apache::lonenc::encrypted($symb);
  284:        } else {
  285:            $href.='?symb='.&escape($symb);
  286:        }
  287:        $r->print('<a href="'.$href.'" target="cat">'.($title?$title:$url).
  288:                  '</a><br />');
  289:        $totalfound++;
  290:     } elsif ($fulltext) {
  291:        $r->print(' .');
  292:     }
  293:     $r->rflush();
  294: # Check also the dependencies of this one
  295:     my $dependencies=
  296:                 &Apache::lonnet::metadata($url,'dependencies');
  297:     foreach (split(/\,/,$dependencies)) {
  298:        if (($_=~/^\/res\//) && (!$alreadyseen{$id})) {
  299:           &checkonthis($r,$id,$_,$level+1,'',$fulltext,undef,@allwords);
  300:        }
  301:     }
  302: }
  303: 
  304: sub checkwords {
  305:     my ($result,$applies,@allwords) = @_;
  306:     foreach (@allwords) {
  307:         if ($_=~/\w/) {
  308:             if ($result=~/$_/si) {
  309:                 $applies++;
  310:             }
  311:         }
  312:     }
  313:     return $applies;
  314: }
  315: 
  316: sub untiehash {
  317:     if (tied(%hash)) {
  318:         untie(%hash);
  319:     }
  320: }
  321: 
  322: sub handler {
  323:     my $r = shift;
  324:     &Apache::loncommon::content_type($r,'text/html');
  325:     $r->send_http_header;
  326:     if ($r->header_only) { return OK; }
  327: 
  328:     my $crstype = &Apache::loncommon::course_type();
  329:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['phase']);
  330:     $r->print(&Apache::loncommon::start_page("$crstype Search"));
  331:     &Apache::lonhtmlcommon::clear_breadcrumbs();
  332:     &Apache::lonhtmlcommon::add_breadcrumb(
  333:             {   href => '/adm/searchcourse',
  334:                 text => "$crstype Search"});
  335:     if ($env{'form.phase'} eq 'results') {
  336:        &Apache::lonhtmlcommon::add_breadcrumb(
  337:             {   href => '/adm/searchcourse?phase=results',
  338:                 text => 'Search Results'});
  339:     }
  340:     $r->print(&Apache::lonhtmlcommon::breadcrumbs("$crstype Search"));
  341:     &Apache::londocs::startContentScreen($r,'coursesearch');
  342:     if ($env{'form.phase'} eq 'results') {
  343:        &course_search($r);
  344:     } else {
  345:        $r->print(&menu());
  346:     }
  347:     &Apache::londocs::endContentScreen($r);
  348:     $r->print(&Apache::loncommon::end_page());
  349:     return OK;
  350: }
  351: 
  352: 1;

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