File:  [LON-CAPA] / loncom / interface / loncommon.pm
Revision 1.30: download - view: text, annotated - select for diffs
Thu Mar 28 22:15:56 2002 UTC (22 years, 2 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
- must used defined(), since if $ENV{'form.'$name} had a value of 0 it would get pasted over.

    1: # The LearningOnline Network with CAPA
    2: # a pile of common routines
    3: #
    4: # $Id: loncommon.pm,v 1.30 2002/03/28 22:15:56 albertel 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: # YEAR=2001
   29: # 2/13-12/7 Guy Albertelli
   30: # 12/11,12/12,12/17 Scott Harrison
   31: # 12/21 Gerd Kortemeyer
   32: # 12/21 Scott Harrison
   33: # 12/25,12/28 Gerd Kortemeyer
   34: # YEAR=2002
   35: # 1/4 Gerd Kortemeyer
   36: 
   37: # Makes a table out of the previous attempts
   38: # Inputs result_from_symbread, user, domain, course_id
   39: # Reads in non-network-related .tab files
   40: 
   41: package Apache::loncommon;
   42: 
   43: use strict;
   44: use Apache::lonnet();
   45: use POSIX qw(strftime);
   46: use Apache::Constants qw(:common);
   47: use Apache::lonmsg();
   48: 
   49: my $readit;
   50: 
   51: # ----------------------------------------------- Filetypes/Languages/Copyright
   52: my %language;
   53: my %cprtag;
   54: my %fe; my %fd;
   55: my %fc;
   56: 
   57: # -------------------------------------------------------------- Thesaurus data
   58: my @therelated;
   59: my @theword;
   60: my @thecount;
   61: my %theindex;
   62: my $thetotalcount;
   63: my $thefuzzy=2;
   64: my $thethreshold=0.1/$thefuzzy;
   65: my $theavecount;
   66: 
   67: # ----------------------------------------------------------------------- BEGIN
   68: BEGIN {
   69: 
   70:     unless ($readit) {
   71: # ------------------------------------------------------------------- languages
   72:     {
   73: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
   74: 				 '/language.tab');
   75: 	if ($fh) {
   76: 	    while (<$fh>) {
   77: 		next if /^\#/;
   78: 		chomp;
   79: 		my ($key,$val)=(split(/\s+/,$_,2));
   80: 		$language{$key}=$val;
   81: 	    }
   82: 	}
   83:     }
   84: # ------------------------------------------------------------------ copyrights
   85:     {
   86: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonIncludes'}.
   87: 				  '/copyright.tab');
   88: 	if ($fh) {
   89: 	    while (<$fh>) {
   90: 		next if /^\#/;
   91: 		chomp;
   92: 		my ($key,$val)=(split(/\s+/,$_,2));
   93: 		$cprtag{$key}=$val;
   94: 	    }
   95: 	}
   96:     }
   97: # ------------------------------------------------------------- file categories
   98:     {
   99: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
  100: 				  '/filecategories.tab');
  101: 	if ($fh) {
  102: 	    while (<$fh>) {
  103: 		next if /^\#/;
  104: 		chomp;
  105: 		my ($key,$val)=(split(/\s+/,$_,2));
  106: 		push @{$fc{$key}},$val;
  107: 	    }
  108: 	}
  109:     }
  110: # ------------------------------------------------------------------ file types
  111:     {
  112: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
  113: 	       '/filetypes.tab');
  114: 	if ($fh) {
  115:             while (<$fh>) {
  116: 		next if (/^\#/);
  117: 		chomp;
  118: 		my ($ending,$emb,$descr)=split(/\s+/,$_,3);
  119: 		if ($descr ne '') { 
  120: 		    $fe{$ending}=lc($emb);
  121: 		    $fd{$ending}=$descr;
  122: 		}
  123: 	    }
  124: 	}
  125:     }
  126: # -------------------------------------------------------------- Thesaurus data
  127:     {
  128: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
  129: 	       '/thesaurus.dat');
  130: 	if ($fh) {
  131:             while (<$fh>) {
  132:                my ($tword,$tindex,$tcount,$trelated)=split(/\@/,$_);
  133:                $theindex{$tword}=$tindex;
  134:                $theword[$tindex]=$tword;
  135:                $thecount[$tindex]=$tcount;
  136:                $thetotalcount+=$tcount;
  137:                $therelated[$tindex]=$trelated;
  138: 	   }
  139:         }
  140:         $theavecount=$thetotalcount/$#thecount;
  141:     }
  142:     &Apache::lonnet::logthis(
  143:               "<font color=yellow>INFO: Read file types and thesaurus</font>");
  144:     $readit=1;
  145: }
  146: 
  147: }
  148: # ============================================================= END BEGIN BLOCK
  149: 
  150: 
  151: # ---------------------------------------------------------- Is this a keyword?
  152: 
  153: sub keyword {
  154:     my $newword=shift;
  155:     $newword=~s/\W//g;
  156:     $newword=~tr/A-Z/a-z/;
  157:     my $tindex=$theindex{$newword};
  158:     if ($tindex) {
  159:         if ($thecount[$tindex]>$theavecount) {
  160:            return 1;
  161:         }
  162:     }
  163:     return 0;
  164: }
  165: # -------------------------------------------------------- Return related words
  166: 
  167: sub related {
  168:     my $newword=shift;
  169:     $newword=~s/\W//g;
  170:     $newword=~tr/A-Z/a-z/;
  171:     my $tindex=$theindex{$newword};
  172:     if ($tindex) {
  173:         my %found=();
  174:         foreach (split(/\,/,$therelated[$tindex])) {
  175: # - Related word found
  176:             my ($ridx,$rcount)=split(/\:/,$_);
  177: # - Direct relation index
  178:             my $directrel=$rcount/$thecount[$tindex];
  179:             if ($directrel>$thethreshold) {
  180:                foreach (split(/\,/,$therelated[$ridx])) {
  181:                   my ($rridx,$rrcount)=split(/\:/,$_);
  182:                   if ($rridx==$tindex) {
  183: # - Determine reverse relation index
  184:                      my $revrel=$rrcount/$thecount[$ridx];
  185: # - Calculate full index
  186:                      $found{$ridx}=$directrel*$revrel;
  187:                      if ($found{$ridx}>$thethreshold) {
  188:                         foreach (split(/\,/,$therelated[$ridx])) {
  189:                             my ($rrridx,$rrrcount)=split(/\:/,$_);
  190:                             unless ($found{$rrridx}) {
  191:                                my $revrevrel=$rrrcount/$thecount[$ridx];
  192:                                if (
  193:                           $directrel*$revrel*$revrevrel>$thethreshold
  194:                                ) {
  195:                                   $found{$rrridx}=
  196:                                        $directrel*$revrel*$revrevrel;
  197:                                }
  198:                             }
  199:                         }
  200:                      }
  201:                   }
  202:                }
  203:             }
  204:         }
  205:     }
  206:     return ();
  207: }
  208: 
  209: # ---------------------------------------------------------------- Language IDs
  210: sub languageids {
  211:     return sort(keys(%language));
  212: }
  213: 
  214: # -------------------------------------------------------- Language Description
  215: sub languagedescription {
  216:     return $language{shift(@_)};
  217: }
  218: 
  219: # --------------------------------------------------------------- Copyright IDs
  220: sub copyrightids {
  221:     return sort(keys(%cprtag));
  222: }
  223: 
  224: # ------------------------------------------------------- Copyright Description
  225: sub copyrightdescription {
  226:     return $cprtag{shift(@_)};
  227: }
  228: 
  229: # ------------------------------------------------------------- File Categories
  230: sub filecategories {
  231:     return sort(keys(%fc));
  232: }
  233: 
  234: # -------------------------------------- File Types within a specified category
  235: sub filecategorytypes {
  236:     return @{$fc{lc(shift(@_))}};
  237: }
  238: 
  239: # ------------------------------------------------------------------ File Types
  240: sub fileextensions {
  241:     return sort(keys(%fe));
  242: }
  243: 
  244: # ------------------------------------------------------------- Embedding Style
  245: sub fileembstyle {
  246:     return $fe{lc(shift(@_))};
  247: }
  248: 
  249: # ------------------------------------------------------------ Description Text
  250: sub filedescription {
  251:     return $fd{lc(shift(@_))};
  252: }
  253: 
  254: # ------------------------------------------------------------ Description Text
  255: sub filedescriptionex {
  256:     my $ex=shift;
  257:     return '.'.$ex.' '.$fd{lc($ex)};
  258: }
  259: 
  260: sub get_previous_attempt {
  261:   my ($symb,$username,$domain,$course)=@_;
  262:   my $prevattempts='';
  263:   if ($symb) {
  264:     my (%returnhash)=
  265:       &Apache::lonnet::restore($symb,$course,$domain,$username);
  266:     if ($returnhash{'version'}) {
  267:       my %lasthash=();
  268:       my $version;
  269:       for ($version=1;$version<=$returnhash{'version'};$version++) {
  270:         foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
  271: 	  $lasthash{$_}=$returnhash{$version.':'.$_};
  272:         }
  273:       }
  274:       $prevattempts='<table border=2></tr><th>History</th>';
  275:       foreach (sort(keys %lasthash)) {
  276:         $prevattempts.='<th>'.$_.'</th>';
  277:       }
  278:       for ($version=1;$version<=$returnhash{'version'};$version++) {
  279:         $prevattempts.='</tr><tr><th>Attempt '.$version.'</th>';
  280:         foreach (sort(keys %lasthash)) {
  281: 	  my $value;
  282: 	  if ($_ =~ /timestamp/) {
  283: 	    $value=scalar(localtime($returnhash{$version.':'.$_}));
  284: 	  } else {
  285: 	    $value=$returnhash{$version.':'.$_};
  286: 	  }
  287: 	  $prevattempts.='<td>'.$value.'</td>';   
  288:         }
  289:       }
  290:       $prevattempts.='</tr><tr><th>Current</th>';
  291:       foreach (sort(keys %lasthash)) {
  292: 	my $value;
  293: 	if ($_ =~ /timestamp/) {
  294: 	  $value=scalar(localtime($lasthash{$_}));
  295: 	} else {
  296: 	  $value=$lasthash{$_};
  297: 	}
  298: 	$prevattempts.='<td>'.$value.'</td>';
  299:       }
  300:       $prevattempts.='</tr></table>';
  301:     } else {
  302:       $prevattempts='Nothing submitted - no attempts.';
  303:     }
  304:   } else {
  305:     $prevattempts='No data.';
  306:   }
  307: }
  308: 
  309: sub get_student_view {
  310:   my ($symb,$username,$domain,$courseid) = @_;
  311:   my ($map,$id,$feedurl) = split(/___/,$symb);
  312:   my (%old,%moreenv);
  313:   my @elements=('symb','courseid','domain','username');
  314:   foreach my $element (@elements) {
  315:     $old{$element}=$ENV{'form.grade_'.$element};
  316:     $moreenv{'form.grade_'.$element}=eval '$'.$element #'
  317:   }
  318:   &Apache::lonnet::appenv(%moreenv);
  319:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
  320:   &Apache::lonnet::delenv('form.grade_');
  321:   foreach my $element (@elements) {
  322:     $ENV{'form.grade_'.$element}=$old{$element};
  323:   }
  324:   $userview=~s/\<body[^\>]*\>//gi;
  325:   $userview=~s/\<\/body\>//gi;
  326:   $userview=~s/\<html\>//gi;
  327:   $userview=~s/\<\/html\>//gi;
  328:   $userview=~s/\<head\>//gi;
  329:   $userview=~s/\<\/head\>//gi;
  330:   $userview=~s/action\s*\=/would_be_action\=/gi;
  331:   return $userview;
  332: }
  333: 
  334: sub get_student_answers {
  335:   my ($symb,$username,$domain,$courseid) = @_;
  336:   my ($map,$id,$feedurl) = split(/___/,$symb);
  337:   my (%old,%moreenv);
  338:   my @elements=('symb','courseid','domain','username');
  339:   foreach my $element (@elements) {
  340:     $old{$element}=$ENV{'form.grade_'.$element};
  341:     $moreenv{'form.grade_'.$element}=eval '$'.$element #'
  342:   }
  343:   $moreenv{'form.grade_target'}='answer';
  344:   &Apache::lonnet::appenv(%moreenv);
  345:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
  346:   &Apache::lonnet::delenv('form.grade_');
  347:   foreach my $element (@elements) {
  348:     $ENV{'form.grade_'.$element}=$old{$element};
  349:   }
  350:   $userview=~s/\<body[^\>]*\>//gi;
  351:   $userview=~s/\<\/body\>//gi;
  352:   $userview=~s/\<html\>//gi;
  353:   $userview=~s/\<\/html\>//gi;
  354:   $userview=~s/\<head\>//gi;
  355:   $userview=~s/\<\/head\>//gi;
  356:   $userview=~s/action\s*\=/would_be_action\=/gi;
  357:   return $userview;
  358: }
  359: 
  360: sub get_unprocessed_cgi {
  361:   my ($query,$possible_names)= @_;
  362:   # $Apache::lonxml::debug=1;
  363:   foreach (split(/&/,$query)) {
  364:     my ($name, $value) = split(/=/,$_);
  365:     $name = &Apache::lonnet::unescape($name);
  366:     if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
  367:       $value =~ tr/+/ /;
  368:       $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
  369:       &Apache::lonxml::debug("Seting :$name: to :$value:");
  370:       unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
  371:     }
  372:   }
  373: }
  374: 
  375: sub cacheheader {
  376:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
  377:   my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
  378:   my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
  379:                 <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
  380:                 <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
  381:   return $output;
  382: }
  383: 
  384: sub no_cache {
  385:   my ($r) = @_;
  386:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
  387:   #my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
  388:   $r->no_cache(1);
  389:   $r->header_out("Pragma" => "no-cache");
  390:   #$r->header_out("Expires" => $date);
  391: }
  392: 
  393: sub add_to_env {
  394:   my ($name,$value)=@_;
  395:   if (defined($ENV{$name})) {
  396:     if (ref($ENV{$name})) {
  397:       #already have multiple values
  398:       push(@{ $ENV{$name} },$value);
  399:     } else {
  400:       #first time seeing multiple values, convert hash entry to an arrayref
  401:       my $first=$ENV{$name};
  402:       undef($ENV{$name});
  403:       push(@{ $ENV{$name} },$first,$value);
  404:     }
  405:   } else {
  406:     $ENV{$name}=$value;
  407:   }
  408: }
  409: 1;
  410: __END__;
  411: 
  412: 
  413: =head1 NAME
  414: 
  415: Apache::loncommon - pile of common routines
  416: 
  417: =head1 SYNOPSIS
  418: 
  419: Referenced by other mod_perl Apache modules.
  420: 
  421: Invocation:
  422:  &Apache::loncommon::SUBROUTINENAME(ARGUMENTS);
  423: 
  424: =head1 INTRODUCTION
  425: 
  426: Common collection of used subroutines.  This collection helps remove
  427: redundancy from other modules and increase efficiency of memory usage.
  428: 
  429: Current things done:
  430: 
  431:  Makes a table out of the previous homework attempts
  432:  Inputs result_from_symbread, user, domain, course_id
  433:  Reads in non-network-related .tab files
  434: 
  435: This is part of the LearningOnline Network with CAPA project
  436: described at http://www.lon-capa.org.
  437: 
  438: =head1 HANDLER SUBROUTINE
  439: 
  440: There is no handler subroutine.
  441: 
  442: =head1 OTHER SUBROUTINES
  443: 
  444: =over 4
  445: 
  446: =item *
  447: 
  448: BEGIN() : initialize values from language.tab, copyright.tab, filetypes.tab,
  449: and filecategories.tab.
  450: 
  451: =item *
  452: 
  453: languageids() : returns list of all language ids
  454: 
  455: =item *
  456: 
  457: languagedescription() : returns description of a specified language id
  458: 
  459: =item *
  460: 
  461: copyrightids() : returns list of all copyrights
  462: 
  463: =item *
  464: 
  465: copyrightdescription() : returns description of a specified copyright id
  466: 
  467: =item *
  468: 
  469: filecategories() : returns list of all file categories
  470: 
  471: =item *
  472: 
  473: filecategorytypes() : returns list of file types belonging to a given file
  474: category
  475: 
  476: =item *
  477: 
  478: fileembstyle() : returns embedding style for a specified file type
  479: 
  480: =item *
  481: 
  482: filedescription() : returns description for a specified file type
  483: 
  484: =item *
  485: 
  486: filedescriptionex() : returns description for a specified file type with
  487: extra formatting
  488: 
  489: =item *
  490: 
  491: get_previous_attempt() : return string with previous attempt on problem
  492: 
  493: =item *
  494: 
  495: get_student_view() : show a snapshot of what student was looking at
  496: 
  497: =item *
  498: 
  499: get_student_answers() : show a snapshot of how student was answering problem
  500: 
  501: =item *
  502: 
  503: get_unprocessed_cgi() : get unparsed CGI parameters
  504: 
  505: =item *
  506: 
  507: cacheheader() : returns cache-controlling header code
  508: 
  509: =item *
  510: 
  511: nocache() : specifies header code to not have cache
  512: 
  513: =item *
  514: 
  515: add_to_env($name,$value) : adds $name to the %ENV hash with value
  516: $value, if $name already exists, the entry is converted to an array
  517: reference and $value is added to the array.
  518: 
  519: =back
  520: 
  521: =cut

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