File:  [LON-CAPA] / loncom / interface / loncommon.pm
Revision 1.32: download - view: text, annotated - select for diffs
Mon Apr 22 15:26:46 2002 UTC (22 years, 2 months ago) by matthew
Branches: MAIN
CVS tags: HEAD
New javascript to handle authentication forms.

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

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