File:  [LON-CAPA] / loncom / interface / loncommon.pm
Revision 1.33: download - view: text, annotated - select for diffs
Mon Apr 22 18:04:19 2002 UTC (22 years, 1 month ago) by matthew
Branches: MAIN
CVS tags: HEAD
Moved home server list generating code to loncommon from loncreateuser.

    1: # The LearningOnline Network with CAPA
    2: # a pile of common routines
    3: #
    4: # $Id: loncommon.pm,v 1.33 2002/04/22 18:04:19 matthew 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: ##        Home server <option> list generating code          ##
  151: ###############################################################
  152: sub get_home_servers {
  153:     my $domain = shift;
  154:     my %home_servers;
  155:     foreach (keys(%Apache::lonnet::libserv)) {
  156:         if ($Apache::lonnet::hostdom{$_} eq $domain) {
  157:             $home_servers{$_} = $Apache::lonnet::hostname{$_};
  158:         }
  159:     }
  160:     return %home_servers;
  161: }
  162: 
  163: sub home_server_option_list {
  164:     my $domain = shift;
  165:     my %servers = &get_home_servers($domain);
  166:     my $result = '';
  167:     foreach (sort keys(%servers)) {
  168:         $result.=
  169:             '<option value="'.$_.'">'.$_.' '.$servers{$_}."</option>\n";
  170:     }
  171:     return $result;
  172: }
  173: ###############################################################
  174: ##    End of home server <option> list generating code       ##
  175: ###############################################################
  176: 
  177: ###############################################################
  178: ##    Authentication changing form generation subroutines    ##
  179: ###############################################################
  180: ##
  181: ## All of the authform_xxxxxxx subroutines take their inputs in a
  182: ## hash, and have reasonable default values.
  183: ##
  184: ##    formname = the name given in the <form> tag.
  185: sub authform_header{  
  186:     my %in = (
  187:         formname => 'cu',
  188:         kerb_def_dom => 'MSU.EDU',
  189:         @_,
  190:     );
  191:     $in{'formname'} = 'document.' . $in{'formname'};
  192:     my $result='';
  193:     $result.=<<"END";
  194: var current = new Object();
  195: current.radiovalue = 'nochange';
  196: current.argfield = null;
  197: 
  198: function changed_radio(choice,currentform) {
  199:     var choicearg = choice + 'arg';
  200:     // If a radio button in changed, we need to change the argfield
  201:     if (current.radiovalue != choice) {
  202:         current.radiovalue = choice;
  203:         if (current.argfield != null) {
  204:             currentform.elements[current.argfield].value = '';
  205:         }
  206:         if (choice == 'nochange') {
  207:             current.argfield = null;
  208:         } else {
  209:             current.argfield = choicearg;
  210:             switch(choice) {
  211:                 case 'krb': 
  212:                     currentform.elements[current.argfield].value = 
  213:                         "$in{'kerb_def_dom'}";
  214:                 break;
  215:               default:
  216:                 break;
  217:             }
  218:         }
  219:     }
  220:     return;
  221: }
  222: 
  223: function changed_text(choice,currentform) {
  224:     var choicearg = choice + 'arg';
  225:     if (currentform.elements[choicearg].value !='') {
  226:         switch (choice) {
  227:             case 'krb': currentform.elements[choicearg].value =
  228:                 currentform.elements[choicearg].value.toUpperCase();
  229:                 break;
  230:             default:
  231:         }
  232:         // clear old field
  233:         if ((current.argfield != choicearg) && (current.argfield != null)) {
  234:             currentform.elements[current.argfield].value = '';
  235:         }
  236:         current.argfield = choicearg;
  237:     }
  238:     set_auth_radio_buttons(choice,currentform);
  239:     return;
  240: }
  241: 
  242: function set_auth_radio_buttons(newvalue,currentform) {
  243:     var i=0;
  244:     while (i < currentform.login.length) {
  245:         if (currentform.login[i].value == newvalue) { break; }
  246:         i++;
  247:     }
  248:     if (i == currentform.login.length) {
  249:         return;
  250:     }
  251:     current.radiovalue = newvalue;
  252:     currentform.login[i].checked = true;
  253:     return;
  254: }
  255: END
  256:     return $result;
  257: }
  258: 
  259: sub authform_authorwarning{
  260:     my $result='';
  261:     $result=<<"END";
  262: <i>As a general rule, only authors or co-authors should be filesystem
  263: authenticated (which allows access to the server filesystem).</i>
  264: END
  265:     return $result;
  266: }
  267: 
  268: sub authform_nochange{  
  269:     my %in = (
  270:               formname => 'document.cu',
  271:               kerb_def_dom => 'MSU.EDU',
  272:               @_,
  273:           );
  274:     my $result='';
  275:     $result.=<<"END";
  276: <input type="radio" name="login" value="nochange" checked="checked"
  277:        onclick="javascript:changed_radio('nochange',$in{'formname'});">
  278: Do not change login data
  279: END
  280:     return $result;
  281: }
  282: 
  283: sub authform_kerberos{  
  284:     my %in = (
  285:               formname => 'document.cu',
  286:               kerb_def_dom => 'MSU.EDU',
  287:               @_,
  288:               );
  289:     my $result='';
  290:     $result.=<<"END";
  291: <input type="radio" name="login" value="krb" 
  292:        onclick="javascript:changed_radio('krb',$in{'formname'});"
  293:        onchange="javascript:changed_radio('krb',$in{'formname'});">
  294: Kerberos authenticated with domain
  295: <input type="text" size="10" name="krbarg" value=""
  296:        onchange="javascript:changed_text('krb',$in{'formname'});">
  297: END
  298:     return $result;
  299: }
  300: 
  301: sub authform_internal{  
  302:     my %args = (
  303:                 formname => 'document.cu',
  304:                 kerb_def_dom => 'MSU.EDU',
  305:                 @_,
  306:                 );
  307:     my $result='';
  308:     $result.=<<"END";
  309: <input type="radio" name="login" value="int"
  310:        onchange="javascript:changed_radio('int',$args{'formname'});"
  311:        onclick="javascript:changed_radio('int',$args{'formname'});">
  312: Internally authenticated (with initial password 
  313: <input type="text" size="10" name="intarg" value=""
  314:        onchange="javascript:changed_text('int',$args{'formname'});">
  315: END
  316:     return $result;
  317: }
  318: 
  319: sub authform_local{  
  320:     my %in = (
  321:               formname => 'document.cu',
  322:               kerb_def_dom => 'MSU.EDU',
  323:               @_,
  324:               );
  325:     my $result='';
  326:     $result.=<<"END";
  327: <input type="radio" name="login" value="loc"
  328:        onchange="javascript:changed_radio('loc',$in{'formname'});"
  329:        onclick="javascript:changed_radio('loc',$in{'formname'});"> 
  330: Local Authentication with argument
  331: <input type="text" size="10" name="locarg" value=""
  332:        onchange="javascript:changed_text('loc',$in{'formname'});">
  333: END
  334:     return $result;
  335: }
  336: 
  337: sub authform_filesystem{  
  338:     my %in = (
  339:               formname => 'document.cu',
  340:               kerb_def_dom => 'MSU.EDU',
  341:               @_,
  342:               );
  343:     my $result='';
  344:     $result.=<<"END";
  345: <input type="radio" name="login" value="fsys" 
  346:        onchange="javascript:changed_radio('fsys',$in{'formname'});"
  347:        onclick="javascript:changed_radio('fsys',$in{'formname'});"> 
  348: Filesystem authenticated (with initial password 
  349: <input type="text" size="10" name="fsysarg" value=""
  350:        onchange="javascript:changed_text('fsys',$in{'formname'});">
  351: END
  352:     return $result;
  353: }
  354: 
  355: ###############################################################
  356: ##   End Authentication changing form generation functions   ##
  357: ###############################################################
  358: 
  359: 
  360: 
  361: # ---------------------------------------------------------- Is this a keyword?
  362: 
  363: sub keyword {
  364:     my $newword=shift;
  365:     $newword=~s/\W//g;
  366:     $newword=~tr/A-Z/a-z/;
  367:     my $tindex=$theindex{$newword};
  368:     if ($tindex) {
  369:         if ($thecount[$tindex]>$theavecount) {
  370:            return 1;
  371:         }
  372:     }
  373:     return 0;
  374: }
  375: # -------------------------------------------------------- Return related words
  376: 
  377: sub related {
  378:     my $newword=shift;
  379:     $newword=~s/\W//g;
  380:     $newword=~tr/A-Z/a-z/;
  381:     my $tindex=$theindex{$newword};
  382:     if ($tindex) {
  383:         my %found=();
  384:         foreach (split(/\,/,$therelated[$tindex])) {
  385: # - Related word found
  386:             my ($ridx,$rcount)=split(/\:/,$_);
  387: # - Direct relation index
  388:             my $directrel=$rcount/$thecount[$tindex];
  389:             if ($directrel>$thethreshold) {
  390:                foreach (split(/\,/,$therelated[$ridx])) {
  391:                   my ($rridx,$rrcount)=split(/\:/,$_);
  392:                   if ($rridx==$tindex) {
  393: # - Determine reverse relation index
  394:                      my $revrel=$rrcount/$thecount[$ridx];
  395: # - Calculate full index
  396:                      $found{$ridx}=$directrel*$revrel;
  397:                      if ($found{$ridx}>$thethreshold) {
  398:                         foreach (split(/\,/,$therelated[$ridx])) {
  399:                             my ($rrridx,$rrrcount)=split(/\:/,$_);
  400:                             unless ($found{$rrridx}) {
  401:                                my $revrevrel=$rrrcount/$thecount[$ridx];
  402:                                if (
  403:                           $directrel*$revrel*$revrevrel>$thethreshold
  404:                                ) {
  405:                                   $found{$rrridx}=
  406:                                        $directrel*$revrel*$revrevrel;
  407:                                }
  408:                             }
  409:                         }
  410:                      }
  411:                   }
  412:                }
  413:             }
  414:         }
  415:     }
  416:     return ();
  417: }
  418: 
  419: # ---------------------------------------------------------------- Language IDs
  420: sub languageids {
  421:     return sort(keys(%language));
  422: }
  423: 
  424: # -------------------------------------------------------- Language Description
  425: sub languagedescription {
  426:     return $language{shift(@_)};
  427: }
  428: 
  429: # --------------------------------------------------------------- Copyright IDs
  430: sub copyrightids {
  431:     return sort(keys(%cprtag));
  432: }
  433: 
  434: # ------------------------------------------------------- Copyright Description
  435: sub copyrightdescription {
  436:     return $cprtag{shift(@_)};
  437: }
  438: 
  439: # ------------------------------------------------------------- File Categories
  440: sub filecategories {
  441:     return sort(keys(%fc));
  442: }
  443: 
  444: # -------------------------------------- File Types within a specified category
  445: sub filecategorytypes {
  446:     return @{$fc{lc(shift(@_))}};
  447: }
  448: 
  449: # ------------------------------------------------------------------ File Types
  450: sub fileextensions {
  451:     return sort(keys(%fe));
  452: }
  453: 
  454: # ------------------------------------------------------------- Embedding Style
  455: sub fileembstyle {
  456:     return $fe{lc(shift(@_))};
  457: }
  458: 
  459: # ------------------------------------------------------------ Description Text
  460: sub filedescription {
  461:     return $fd{lc(shift(@_))};
  462: }
  463: 
  464: # ------------------------------------------------------------ Description Text
  465: sub filedescriptionex {
  466:     my $ex=shift;
  467:     return '.'.$ex.' '.$fd{lc($ex)};
  468: }
  469: 
  470: sub get_previous_attempt {
  471:   my ($symb,$username,$domain,$course)=@_;
  472:   my $prevattempts='';
  473:   if ($symb) {
  474:     my (%returnhash)=
  475:       &Apache::lonnet::restore($symb,$course,$domain,$username);
  476:     if ($returnhash{'version'}) {
  477:       my %lasthash=();
  478:       my $version;
  479:       for ($version=1;$version<=$returnhash{'version'};$version++) {
  480:         foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
  481: 	  $lasthash{$_}=$returnhash{$version.':'.$_};
  482:         }
  483:       }
  484:       $prevattempts='<table border=2></tr><th>History</th>';
  485:       foreach (sort(keys %lasthash)) {
  486: 	my ($ign,@parts) = split(/\./,$_);
  487: 	if (@parts) {
  488: 	  my $data=$parts[-1];
  489: 	  pop(@parts);
  490: 	  $prevattempts.='<th>Part '.join('.',@parts).'<br />'.$data.'</th>';
  491: 	} else {
  492: 	  $prevattempts.='<th>'.$ign.'</th>';
  493: 	}
  494:       }
  495:       for ($version=1;$version<=$returnhash{'version'};$version++) {
  496:         $prevattempts.='</tr><tr><th>Attempt '.$version.'</th>';
  497:         foreach (sort(keys %lasthash)) {
  498: 	  my $value;
  499: 	  if ($_ =~ /timestamp/) {
  500: 	    $value=scalar(localtime($returnhash{$version.':'.$_}));
  501: 	  } else {
  502: 	    $value=$returnhash{$version.':'.$_};
  503: 	  }
  504: 	  $prevattempts.='<td>'.$value.'</td>';   
  505:         }
  506:       }
  507:       $prevattempts.='</tr><tr><th>Current</th>';
  508:       foreach (sort(keys %lasthash)) {
  509: 	my $value;
  510: 	if ($_ =~ /timestamp/) {
  511: 	  $value=scalar(localtime($lasthash{$_}));
  512: 	} else {
  513: 	  $value=$lasthash{$_};
  514: 	}
  515: 	$prevattempts.='<td>'.$value.'</td>';
  516:       }
  517:       $prevattempts.='</tr></table>';
  518:     } else {
  519:       $prevattempts='Nothing submitted - no attempts.';
  520:     }
  521:   } else {
  522:     $prevattempts='No data.';
  523:   }
  524: }
  525: 
  526: sub get_student_view {
  527:   my ($symb,$username,$domain,$courseid) = @_;
  528:   my ($map,$id,$feedurl) = split(/___/,$symb);
  529:   my (%old,%moreenv);
  530:   my @elements=('symb','courseid','domain','username');
  531:   foreach my $element (@elements) {
  532:     $old{$element}=$ENV{'form.grade_'.$element};
  533:     $moreenv{'form.grade_'.$element}=eval '$'.$element #'
  534:   }
  535:   &Apache::lonnet::appenv(%moreenv);
  536:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
  537:   &Apache::lonnet::delenv('form.grade_');
  538:   foreach my $element (@elements) {
  539:     $ENV{'form.grade_'.$element}=$old{$element};
  540:   }
  541:   $userview=~s/\<body[^\>]*\>//gi;
  542:   $userview=~s/\<\/body\>//gi;
  543:   $userview=~s/\<html\>//gi;
  544:   $userview=~s/\<\/html\>//gi;
  545:   $userview=~s/\<head\>//gi;
  546:   $userview=~s/\<\/head\>//gi;
  547:   $userview=~s/action\s*\=/would_be_action\=/gi;
  548:   return $userview;
  549: }
  550: 
  551: sub get_student_answers {
  552:   my ($symb,$username,$domain,$courseid) = @_;
  553:   my ($map,$id,$feedurl) = split(/___/,$symb);
  554:   my (%old,%moreenv);
  555:   my @elements=('symb','courseid','domain','username');
  556:   foreach my $element (@elements) {
  557:     $old{$element}=$ENV{'form.grade_'.$element};
  558:     $moreenv{'form.grade_'.$element}=eval '$'.$element #'
  559:   }
  560:   $moreenv{'form.grade_target'}='answer';
  561:   &Apache::lonnet::appenv(%moreenv);
  562:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
  563:   &Apache::lonnet::delenv('form.grade_');
  564:   foreach my $element (@elements) {
  565:     $ENV{'form.grade_'.$element}=$old{$element};
  566:   }
  567:   $userview=~s/\<body[^\>]*\>//gi;
  568:   $userview=~s/\<\/body\>//gi;
  569:   $userview=~s/\<html\>//gi;
  570:   $userview=~s/\<\/html\>//gi;
  571:   $userview=~s/\<head\>//gi;
  572:   $userview=~s/\<\/head\>//gi;
  573:   $userview=~s/action\s*\=/would_be_action\=/gi;
  574:   return $userview;
  575: }
  576: 
  577: sub get_unprocessed_cgi {
  578:   my ($query,$possible_names)= @_;
  579:   # $Apache::lonxml::debug=1;
  580:   foreach (split(/&/,$query)) {
  581:     my ($name, $value) = split(/=/,$_);
  582:     $name = &Apache::lonnet::unescape($name);
  583:     if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
  584:       $value =~ tr/+/ /;
  585:       $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
  586:       &Apache::lonxml::debug("Seting :$name: to :$value:");
  587:       unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
  588:     }
  589:   }
  590: }
  591: 
  592: sub cacheheader {
  593:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
  594:   my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
  595:   my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
  596:                 <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
  597:                 <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
  598:   return $output;
  599: }
  600: 
  601: sub no_cache {
  602:   my ($r) = @_;
  603:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
  604:   #my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
  605:   $r->no_cache(1);
  606:   $r->header_out("Pragma" => "no-cache");
  607:   #$r->header_out("Expires" => $date);
  608: }
  609: 
  610: sub add_to_env {
  611:   my ($name,$value)=@_;
  612:   if (defined($ENV{$name})) {
  613:     if (ref($ENV{$name})) {
  614:       #already have multiple values
  615:       push(@{ $ENV{$name} },$value);
  616:     } else {
  617:       #first time seeing multiple values, convert hash entry to an arrayref
  618:       my $first=$ENV{$name};
  619:       undef($ENV{$name});
  620:       push(@{ $ENV{$name} },$first,$value);
  621:     }
  622:   } else {
  623:     $ENV{$name}=$value;
  624:   }
  625: }
  626: 
  627: #---CSV Upload/Handling functions
  628: 
  629: # ========================================================= Store uploaded file
  630: # needs $ENV{'form.upfile'}
  631: # return $datatoken to be put into hidden field
  632: 
  633: sub upfile_store {
  634:     my $r=shift;
  635:     $ENV{'form.upfile'}=~s/\r/\n/gs;
  636:     $ENV{'form.upfile'}=~s/\f/\n/gs;
  637:     $ENV{'form.upfile'}=~s/\n+/\n/gs;
  638:     $ENV{'form.upfile'}=~s/\n+$//gs;
  639: 
  640:     my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}.
  641: 	'_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$;
  642:     {
  643: 	my $fh=Apache::File->new('>'.$r->dir_config('lonDaemons').
  644: 				 '/tmp/'.$datatoken.'.tmp');
  645: 	print $fh $ENV{'form.upfile'};
  646:     }
  647:     return $datatoken;
  648: }
  649: 
  650: # ================================================= Load uploaded file from tmp
  651: # needs $ENV{'form.datatoken'}
  652: # sets $ENV{'form.upfile'} to the contents of the file
  653: 
  654: sub load_tmp_file {
  655:     my $r=shift;
  656:     my @studentdata=();
  657:     {
  658: 	my $fh;
  659: 	if ($fh=Apache::File->new($r->dir_config('lonDaemons').
  660: 				  '/tmp/'.$ENV{'form.datatoken'}.'.tmp')) {
  661: 	    @studentdata=<$fh>;
  662: 	}
  663:     }
  664:     $ENV{'form.upfile'}=join('',@studentdata);
  665: }
  666: 
  667: # ========================================= Separate uploaded file into records
  668: # returns array of records
  669: # needs $ENV{'form.upfile'}
  670: # needs $ENV{'form.upfiletype'}
  671: 
  672: sub upfile_record_sep {
  673:     if ($ENV{'form.upfiletype'} eq 'xml') {
  674:     } else {
  675: 	return split(/\n/,$ENV{'form.upfile'});
  676:     }
  677: }
  678: 
  679: # =============================================== Separate a record into fields
  680: # needs $ENV{'form.upfiletype'}
  681: # takes $record as arg
  682: sub record_sep {
  683:     my $record=shift;
  684:     my %components=();
  685:     if ($ENV{'form.upfiletype'} eq 'xml') {
  686:     } elsif ($ENV{'form.upfiletype'} eq 'space') {
  687:         my $i=0;
  688:         foreach (split(/\s+/,$record)) {
  689:             my $field=$_;
  690:             $field=~s/^(\"|\')//;
  691:             $field=~s/(\"|\')$//;
  692:             $components{$i}=$field;
  693:             $i++;
  694:         }
  695:     } elsif ($ENV{'form.upfiletype'} eq 'tab') {
  696:         my $i=0;
  697:         foreach (split(/\t+/,$record)) {
  698:             my $field=$_;
  699:             $field=~s/^(\"|\')//;
  700:             $field=~s/(\"|\')$//;
  701:             $components{$i}=$field;
  702:             $i++;
  703:         }
  704:     } else {
  705:         my @allfields=split(/\,/,$record);
  706:         my $i=0;
  707:         my $j;
  708:         for ($j=0;$j<=$#allfields;$j++) {
  709:             my $field=$allfields[$j];
  710:             if ($field=~/^\s*(\"|\')/) {
  711: 		my $delimiter=$1;
  712:                 while (($field!~/$delimiter$/) && ($j<$#allfields)) {
  713: 		    $j++;
  714: 		    $field.=','.$allfields[$j];
  715: 		}
  716:                 $field=~s/^\s*$delimiter//;
  717:                 $field=~s/$delimiter\s*$//;
  718:             }
  719:             $components{$i}=$field;
  720: 	    $i++;
  721:         }
  722:     }
  723:     return %components;
  724: }
  725: 
  726: # =============================== HTML code to select file and specify its type
  727: sub upfile_select_html {
  728:     return (<<'ENDUPFORM');
  729: <input type="file" name="upfile" size="50">
  730: <br />Type: <select name="upfiletype">
  731: <option value="csv">CSV (comma separated values, spreadsheet)</option>
  732: <option value="space">Space separated</option>
  733: <option value="tab">Tabulator separated</option>
  734: <option value="xml">HTML/XML</option>
  735: </select>
  736: ENDUPFORM
  737: }
  738: 
  739: # ===================Prints a table of sample values from each column uploaded
  740: # $r is an Apache Request ref
  741: # $records is an arrayref from &Apache::loncommon::upfile_record_sep
  742: sub csv_print_samples {
  743:     my ($r,$records) = @_;
  744:     my (%sone,%stwo,%sthree);
  745:     %sone=&record_sep($$records[0]);
  746:     if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
  747:     if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
  748: 
  749:     $r->print('Samples<br /><table border="2"><tr>');
  750:     foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<th>Column&nbsp;'.($_+1).'</th>'); }
  751:     $r->print('</tr>');
  752:     foreach my $hash (\%sone,\%stwo,\%sthree) {
  753: 	$r->print('<tr>');
  754: 	foreach (sort({$a <=> $b} keys(%sone))) {
  755: 	    $r->print('<td>');
  756: 	    if (defined($$hash{$_})) { $r->print($$hash{$_}); }
  757: 	    $r->print('</td>');
  758: 	}
  759: 	$r->print('</tr>');
  760:     }
  761:     $r->print('</tr></table><br />'."\n");
  762: }
  763: 
  764: # ======Prints a table to create associations between values and table columns
  765: # $r is an Apache Request ref
  766: # $records is an arrayref from &Apache::loncommon::upfile_record_sep
  767: # $d is an array of 2 element arrays (internal name, displayed name)
  768: sub csv_print_select_table {
  769:     my ($r,$records,$d) = @_;
  770:     my $i=0;my %sone;
  771:     %sone=&record_sep($$records[0]);
  772:     $r->print('Associate columns with student attributes.'."\n".
  773: 	     '<table border="2"><tr><th>Attribute</th><th>Column</th></tr>'."\n");
  774:     foreach (@$d) {
  775: 	my ($value,$display)=@{ $_ };
  776: 	$r->print('<tr><td>'.$display.'</td>');
  777: 
  778: 	$r->print('<td><select name=f'.$i.
  779: 		  ' onchange="javascript:flip(this.form,'.$i.');">');
  780: 	$r->print('<option value="none"></option>');
  781: 	foreach (sort({$a <=> $b} keys(%sone))) {
  782: 	    $r->print('<option value="'.$_.'">Column '.($_+1).'</option>');
  783: 	}
  784: 	$r->print('</select></td></tr>'."\n");
  785: 	$i++;
  786:     }
  787:     $i--;
  788:     return $i;
  789: }
  790: 
  791: # ===================Prints a table of sample values from the upload and
  792: #                      can make associate samples to internal names
  793: # $r is an Apache Request ref
  794: # $records is an arrayref from &Apache::loncommon::upfile_record_sep
  795: # $d is an array of 2 element arrays (internal name, displayed name)
  796: sub csv_samples_select_table {
  797:     my ($r,$records,$d) = @_;
  798:     my %sone; my %stwo; my %sthree;
  799:     my $i=0;
  800: 
  801:     $r->print('<table border=2><tr><th>Field</th><th>Samples</th></tr>');
  802:     %sone=&record_sep($$records[0]);
  803:     if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
  804:     if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
  805: 
  806:     foreach (sort keys %sone) {
  807: 	$r->print('<tr><td><select name=f'.$i.
  808: 		  ' onchange="javascript:flip(this.form,'.$i.');">');
  809: 	foreach (@$d) {
  810: 	    my ($value,$display)=@{ $_ };
  811: 	    $r->print('<option value='.$value.'>'.$display.'</option>');
  812: 	}
  813: 	$r->print('</select></td><td>');
  814: 	if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); }
  815: 	if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); }
  816: 	if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); }
  817: 	$r->print('</td></tr>');
  818: 	$i++;
  819:     }
  820:     $i--;
  821:     return($i);
  822: }
  823: 1;
  824: __END__;
  825: 
  826: 
  827: =head1 NAME
  828: 
  829: Apache::loncommon - pile of common routines
  830: 
  831: =head1 SYNOPSIS
  832: 
  833: Referenced by other mod_perl Apache modules.
  834: 
  835: Invocation:
  836:  &Apache::loncommon::SUBROUTINENAME(ARGUMENTS);
  837: 
  838: =head1 INTRODUCTION
  839: 
  840: Common collection of used subroutines.  This collection helps remove
  841: redundancy from other modules and increase efficiency of memory usage.
  842: 
  843: Current things done:
  844: 
  845:  Makes a table out of the previous homework attempts
  846:  Inputs result_from_symbread, user, domain, course_id
  847:  Reads in non-network-related .tab files
  848: 
  849: This is part of the LearningOnline Network with CAPA project
  850: described at http://www.lon-capa.org.
  851: 
  852: =head1 HANDLER SUBROUTINE
  853: 
  854: There is no handler subroutine.
  855: 
  856: =head1 OTHER SUBROUTINES
  857: 
  858: =over 4
  859: 
  860: =item *
  861: 
  862: BEGIN() : initialize values from language.tab, copyright.tab, filetypes.tab,
  863: and filecategories.tab.
  864: 
  865: =item *
  866: 
  867: languageids() : returns list of all language ids
  868: 
  869: =item *
  870: 
  871: languagedescription() : returns description of a specified language id
  872: 
  873: =item *
  874: 
  875: copyrightids() : returns list of all copyrights
  876: 
  877: =item *
  878: 
  879: copyrightdescription() : returns description of a specified copyright id
  880: 
  881: =item *
  882: 
  883: filecategories() : returns list of all file categories
  884: 
  885: =item *
  886: 
  887: filecategorytypes() : returns list of file types belonging to a given file
  888: category
  889: 
  890: =item *
  891: 
  892: fileembstyle() : returns embedding style for a specified file type
  893: 
  894: =item *
  895: 
  896: filedescription() : returns description for a specified file type
  897: 
  898: =item *
  899: 
  900: filedescriptionex() : returns description for a specified file type with
  901: extra formatting
  902: 
  903: =item *
  904: 
  905: get_previous_attempt() : return string with previous attempt on problem
  906: 
  907: =item *
  908: 
  909: get_student_view() : show a snapshot of what student was looking at
  910: 
  911: =item *
  912: 
  913: get_student_answers() : show a snapshot of how student was answering problem
  914: 
  915: =item *
  916: 
  917: get_unprocessed_cgi() : get unparsed CGI parameters
  918: 
  919: =item *
  920: 
  921: cacheheader() : returns cache-controlling header code
  922: 
  923: =item *
  924: 
  925: nocache() : specifies header code to not have cache
  926: 
  927: =item *
  928: 
  929: add_to_env($name,$value) : adds $name to the %ENV hash with value
  930: $value, if $name already exists, the entry is converted to an array
  931: reference and $value is added to the array.
  932: 
  933: =back
  934: 
  935: =cut

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