Diff for /loncom/interface/loncommon.pm between versions 1.25 and 1.35

version 1.25, 2002/02/26 20:59:28 version 1.35, 2002/04/23 21:42:01
Line 38 Line 38
 # Inputs result_from_symbread, user, domain, course_id  # Inputs result_from_symbread, user, domain, course_id
 # Reads in non-network-related .tab files  # Reads in non-network-related .tab files
   
   # POD header:
   
   =head1 NAME
   
   Apache::loncommon - pile of common routines
   
   =head1 SYNOPSIS
   
   Referenced by other mod_perl Apache modules.
   
   Invocation:
    &Apache::loncommon::SUBROUTINENAME(ARGUMENTS);
   
   =head1 INTRODUCTION
   
   Common collection of used subroutines.  This collection helps remove
   redundancy from other modules and increase efficiency of memory usage.
   
   Current things done:
   
    Makes a table out of the previous homework attempts
    Inputs result_from_symbread, user, domain, course_id
    Reads in non-network-related .tab files
   
   This is part of the LearningOnline Network with CAPA project
   described at http://www.lon-capa.org.
   
   =head2 Subroutines
   
   =over 4
   
   =cut 
   
   # End of POD header
 package Apache::loncommon;  package Apache::loncommon;
   
 use strict;  use strict;
Line 65  my $thethreshold=0.1/$thefuzzy; Line 99  my $thethreshold=0.1/$thefuzzy;
 my $theavecount;  my $theavecount;
   
 # ----------------------------------------------------------------------- BEGIN  # ----------------------------------------------------------------------- BEGIN
   =item BEGIN() 
   
   Initialize values from language.tab, copyright.tab, filetypes.tab,
   and filecategories.tab.
   
   =cut
   # ----------------------------------------------------------------------- BEGIN
   
 BEGIN {  BEGIN {
   
     unless ($readit) {      unless ($readit) {
Line 143  BEGIN { Line 185  BEGIN {
               "<font color=yellow>INFO: Read file types and thesaurus</font>");                "<font color=yellow>INFO: Read file types and thesaurus</font>");
     $readit=1;      $readit=1;
 }  }
       
 }  }
 # ============================================================= END BEGIN BLOCK  # ============================================================= END BEGIN BLOCK
   ###############################################################
   ##        Home server <option> list generating code          ##
   ###############################################################
   #-------------------------------------------
   
   =item get_domains()
   
   Returns an array containing each of the domains listed in the hosts.tab
   file.
   
   =cut
   
   #-------------------------------------------
   sub get_domains {
       # The code below was stolen from "The Perl Cookbook", p 102, 1st ed.
       my @domains;
       my %seen;
       foreach (sort values(%Apache::lonnet::hostdom)) {
           push (@domains,$_) unless $seen{$_}++;
       }
       return @domains;
   }
   
   #-------------------------------------------
   
   =item select_dom_form($defdom,$name)
   
   Returns a string containing a <select name='$name' size='1'> form to 
   allow a user to select the domain to preform an operation in.  
   See loncreateuser.pm for an example invocation and use.
   
   =cut
   
   #-------------------------------------------
   sub select_dom_form {
       my ($defdom,$name) = @_;
       my @domains = get_domains();
       my $selectdomain = "<select name=\"$name\" size=\"1\">\n";
       foreach (@domains) {
           $selectdomain.="<option value=\"$_\" ".
               ($_ eq $defdom ? 'selected' : '').
                   ">$_</option>\n";
       }
       $selectdomain.="</select>";
       return $selectdomain;
   }
   
   #-------------------------------------------
   
   =item get_home_servers($domain)
   
   Returns a hash which contains keys like '103l3' and values like 
   'kirk.lite.msu.edu'.  All of the keys will be for machines in the
   given $domain.
   
   =cut
   
   #-------------------------------------------
   sub get_home_servers {
       my $domain = shift;
       my %home_servers;
       foreach (keys(%Apache::lonnet::libserv)) {
           if ($Apache::lonnet::hostdom{$_} eq $domain) {
               $home_servers{$_} = $Apache::lonnet::hostname{$_};
           }
       }
       return %home_servers;
   }
   
   #-------------------------------------------
   
   =item home_server_option_list($domain)
   
   returns a string which contains an <option> list to be used in a 
   <select> form input.  See loncreateuser.pm for an example.
   
   =cut
   
   #-------------------------------------------
   sub home_server_option_list {
       my $domain = shift;
       my %servers = &get_home_servers($domain);
       my $result = '';
       foreach (sort keys(%servers)) {
           $result.=
               '<option value="'.$_.'">'.$_.' '.$servers{$_}."</option>\n";
       }
       return $result;
   }
   ###############################################################
   ##    End of home server <option> list generating code       ##
   ###############################################################
   
   ###############################################################
   ##    Authentication changing form generation subroutines    ##
   ###############################################################
   ##
   ## All of the authform_xxxxxxx subroutines take their inputs in a
   ## hash, and have reasonable default values.
   ##
   ##    formname = the name given in the <form> tag.
   #-------------------------------------------
   
   =item authform_xxxxxx
   
   The authform_xxxxxx subroutines provide javascript and html forms which 
   handle some of the conveniences required for authentication forms.  
   This is not an optimal method, but it works.  
   
   See loncreateuser.pm for invocation and use examples.
   
   =over 4
   
   =item authform_header
   
   =item authform_authorwarning
   
   =item authform_nochange
   
   =item authform_kerberos
   
   =item authform_internal
   
   =item authform_filesystem
   
   =back
   
   =cut
   
   #-------------------------------------------
   sub authform_header{  
       my %in = (
           formname => 'cu',
           kerb_def_dom => 'MSU.EDU',
           @_,
       );
       $in{'formname'} = 'document.' . $in{'formname'};
       my $result='';
       $result.=<<"END";
   var current = new Object();
   current.radiovalue = 'nochange';
   current.argfield = null;
   
   function changed_radio(choice,currentform) {
       var choicearg = choice + 'arg';
       // If a radio button in changed, we need to change the argfield
       if (current.radiovalue != choice) {
           current.radiovalue = choice;
           if (current.argfield != null) {
               currentform.elements[current.argfield].value = '';
           }
           if (choice == 'nochange') {
               current.argfield = null;
           } else {
               current.argfield = choicearg;
               switch(choice) {
                   case 'krb': 
                       currentform.elements[current.argfield].value = 
                           "$in{'kerb_def_dom'}";
                   break;
                 default:
                   break;
               }
           }
       }
       return;
   }
   
   function changed_text(choice,currentform) {
       var choicearg = choice + 'arg';
       if (currentform.elements[choicearg].value !='') {
           switch (choice) {
               case 'krb': currentform.elements[choicearg].value =
                   currentform.elements[choicearg].value.toUpperCase();
                   break;
               default:
           }
           // clear old field
           if ((current.argfield != choicearg) && (current.argfield != null)) {
               currentform.elements[current.argfield].value = '';
           }
           current.argfield = choicearg;
       }
       set_auth_radio_buttons(choice,currentform);
       return;
   }
   
   function set_auth_radio_buttons(newvalue,currentform) {
       var i=0;
       while (i < currentform.login.length) {
           if (currentform.login[i].value == newvalue) { break; }
           i++;
       }
       if (i == currentform.login.length) {
           return;
       }
       current.radiovalue = newvalue;
       currentform.login[i].checked = true;
       return;
   }
   END
       return $result;
   }
   
   sub authform_authorwarning{
       my $result='';
       $result=<<"END";
   <i>As a general rule, only authors or co-authors should be filesystem
   authenticated (which allows access to the server filesystem).</i>
   END
       return $result;
   }
   
   sub authform_nochange{  
       my %in = (
                 formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',
                 @_,
             );
       my $result='';
       $result.=<<"END";
   <input type="radio" name="login" value="nochange" checked="checked"
          onclick="javascript:changed_radio('nochange',$in{'formname'});">
   Do not change login data
   END
       return $result;
   }
   
   sub authform_kerberos{  
       my %in = (
                 formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',
                 @_,
                 );
       my $result='';
       $result.=<<"END";
   <input type="radio" name="login" value="krb" 
          onclick="javascript:changed_radio('krb',$in{'formname'});"
          onchange="javascript:changed_radio('krb',$in{'formname'});">
   Kerberos authenticated with domain
   <input type="text" size="10" name="krbarg" value=""
          onchange="javascript:changed_text('krb',$in{'formname'});">
   END
       return $result;
   }
   
   sub authform_internal{  
       my %args = (
                   formname => 'document.cu',
                   kerb_def_dom => 'MSU.EDU',
                   @_,
                   );
       my $result='';
       $result.=<<"END";
   <input type="radio" name="login" value="int"
          onchange="javascript:changed_radio('int',$args{'formname'});"
          onclick="javascript:changed_radio('int',$args{'formname'});">
   Internally authenticated (with initial password 
   <input type="text" size="10" name="intarg" value=""
          onchange="javascript:changed_text('int',$args{'formname'});">
   END
       return $result;
   }
   
   sub authform_local{  
       my %in = (
                 formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',
                 @_,
                 );
       my $result='';
       $result.=<<"END";
   <input type="radio" name="login" value="loc"
          onchange="javascript:changed_radio('loc',$in{'formname'});"
          onclick="javascript:changed_radio('loc',$in{'formname'});"> 
   Local Authentication with argument
   <input type="text" size="10" name="locarg" value=""
          onchange="javascript:changed_text('loc',$in{'formname'});">
   END
       return $result;
   }
   
   sub authform_filesystem{  
       my %in = (
                 formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',
                 @_,
                 );
       my $result='';
       $result.=<<"END";
   <input type="radio" name="login" value="fsys" 
          onchange="javascript:changed_radio('fsys',$in{'formname'});"
          onclick="javascript:changed_radio('fsys',$in{'formname'});"> 
   Filesystem authenticated (with initial password 
   <input type="text" size="10" name="fsysarg" value=""
          onchange="javascript:changed_text('fsys',$in{'formname'});">
   END
       return $result;
   }
   
   ###############################################################
   ##   End Authentication changing form generation functions   ##
   ###############################################################
   
   
   
 # ---------------------------------------------------------- Is this a keyword?  # ---------------------------------------------------------- Is this a keyword?
Line 273  sub get_previous_attempt { Line 619  sub get_previous_attempt {
       }        }
       $prevattempts='<table border=2></tr><th>History</th>';        $prevattempts='<table border=2></tr><th>History</th>';
       foreach (sort(keys %lasthash)) {        foreach (sort(keys %lasthash)) {
         $prevattempts.='<th>'.$_.'</th>';   my ($ign,@parts) = split(/\./,$_);
    if (@parts) {
     my $data=$parts[-1];
     pop(@parts);
     $prevattempts.='<th>Part '.join('.',@parts).'<br />'.$data.'</th>';
    } else {
     $prevattempts.='<th>'.$ign.'</th>';
    }
       }        }
       for ($version=1;$version<=$returnhash{'version'};$version++) {        for ($version=1;$version<=$returnhash{'version'};$version++) {
         $prevattempts.='</tr><tr><th>Attempt '.$version.'</th>';          $prevattempts.='</tr><tr><th>Attempt '.$version.'</th>';
Line 359  sub get_student_answers { Line 712  sub get_student_answers {
   
 sub get_unprocessed_cgi {  sub get_unprocessed_cgi {
   my ($query,$possible_names)= @_;    my ($query,$possible_names)= @_;
   $Apache::lonxml::debug=1;    # $Apache::lonxml::debug=1;
   foreach (split(/&/,$query)) {    foreach (split(/&/,$query)) {
     my ($name, $value) = split(/=/,$_);      my ($name, $value) = split(/=/,$_);
     $name = &Apache::lonnet::unescape($name);      $name = &Apache::lonnet::unescape($name);
Line 367  sub get_unprocessed_cgi { Line 720  sub get_unprocessed_cgi {
       $value =~ tr/+/ /;        $value =~ tr/+/ /;
       $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
       &Apache::lonxml::debug("Seting :$name: to :$value:");        &Apache::lonxml::debug("Seting :$name: to :$value:");
       &add_to_env('form.'.$name,$value);        unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
     }      }
   }    }
 }  }
Line 392  sub no_cache { Line 745  sub no_cache {
   
 sub add_to_env {  sub add_to_env {
   my ($name,$value)=@_;    my ($name,$value)=@_;
   if ($ENV{$name}) {    if (defined($ENV{$name})) {
     if (defined(@{ $ENV{$name} })) {      if (ref($ENV{$name})) {
       #already have multiple values        #already have multiple values
       push(@{ $ENV{$name} },$value);        push(@{ $ENV{$name} },$value);
     } else {      } else {
Line 406  sub add_to_env { Line 759  sub add_to_env {
     $ENV{$name}=$value;      $ENV{$name}=$value;
   }    }
 }  }
 1;  
 __END__;  
   
   #---CSV Upload/Handling functions
   
 =head1 NAME  # ========================================================= Store uploaded file
   # needs $ENV{'form.upfile'}
   # return $datatoken to be put into hidden field
   
   sub upfile_store {
       my $r=shift;
       $ENV{'form.upfile'}=~s/\r/\n/gs;
       $ENV{'form.upfile'}=~s/\f/\n/gs;
       $ENV{'form.upfile'}=~s/\n+/\n/gs;
       $ENV{'form.upfile'}=~s/\n+$//gs;
   
 Apache::loncommon - pile of common routines      my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}.
    '_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$;
 =head1 SYNOPSIS      {
    my $fh=Apache::File->new('>'.$r->dir_config('lonDaemons').
 Referenced by other mod_perl Apache modules.   '/tmp/'.$datatoken.'.tmp');
    print $fh $ENV{'form.upfile'};
 Invocation:      }
  &Apache::loncommon::SUBROUTINENAME(ARGUMENTS);      return $datatoken;
   }
 =head1 INTRODUCTION  
   
 Common collection of used subroutines.  This collection helps remove  
 redundancy from other modules and increase efficiency of memory usage.  
   
 Current things done:  
   
  Makes a table out of the previous homework attempts  # ================================================= Load uploaded file from tmp
  Inputs result_from_symbread, user, domain, course_id  # needs $ENV{'form.datatoken'}
  Reads in non-network-related .tab files  # sets $ENV{'form.upfile'} to the contents of the file
   
 This is part of the LearningOnline Network with CAPA project  sub load_tmp_file {
 described at http://www.lon-capa.org.      my $r=shift;
       my @studentdata=();
       {
    my $fh;
    if ($fh=Apache::File->new($r->dir_config('lonDaemons').
     '/tmp/'.$ENV{'form.datatoken'}.'.tmp')) {
       @studentdata=<$fh>;
    }
       }
       $ENV{'form.upfile'}=join('',@studentdata);
   }
   
 =head1 HANDLER SUBROUTINE  # ========================================= Separate uploaded file into records
   # returns array of records
   # needs $ENV{'form.upfile'}
   # needs $ENV{'form.upfiletype'}
   
 There is no handler subroutine.  sub upfile_record_sep {
       if ($ENV{'form.upfiletype'} eq 'xml') {
       } else {
    return split(/\n/,$ENV{'form.upfile'});
       }
   }
   
 =head1 OTHER SUBROUTINES  # =============================================== Separate a record into fields
   # needs $ENV{'form.upfiletype'}
   # takes $record as arg
   sub record_sep {
       my $record=shift;
       my %components=();
       if ($ENV{'form.upfiletype'} eq 'xml') {
       } elsif ($ENV{'form.upfiletype'} eq 'space') {
           my $i=0;
           foreach (split(/\s+/,$record)) {
               my $field=$_;
               $field=~s/^(\"|\')//;
               $field=~s/(\"|\')$//;
               $components{$i}=$field;
               $i++;
           }
       } elsif ($ENV{'form.upfiletype'} eq 'tab') {
           my $i=0;
           foreach (split(/\t+/,$record)) {
               my $field=$_;
               $field=~s/^(\"|\')//;
               $field=~s/(\"|\')$//;
               $components{$i}=$field;
               $i++;
           }
       } else {
           my @allfields=split(/\,/,$record);
           my $i=0;
           my $j;
           for ($j=0;$j<=$#allfields;$j++) {
               my $field=$allfields[$j];
               if ($field=~/^\s*(\"|\')/) {
    my $delimiter=$1;
                   while (($field!~/$delimiter$/) && ($j<$#allfields)) {
       $j++;
       $field.=','.$allfields[$j];
    }
                   $field=~s/^\s*$delimiter//;
                   $field=~s/$delimiter\s*$//;
               }
               $components{$i}=$field;
       $i++;
           }
       }
       return %components;
   }
   
 =over 4  # =============================== HTML code to select file and specify its type
   sub upfile_select_html {
       return (<<'ENDUPFORM');
   <input type="file" name="upfile" size="50">
   <br />Type: <select name="upfiletype">
   <option value="csv">CSV (comma separated values, spreadsheet)</option>
   <option value="space">Space separated</option>
   <option value="tab">Tabulator separated</option>
   <option value="xml">HTML/XML</option>
   </select>
   ENDUPFORM
   }
   
   # ===================Prints a table of sample values from each column uploaded
   # $r is an Apache Request ref
   # $records is an arrayref from &Apache::loncommon::upfile_record_sep
   sub csv_print_samples {
       my ($r,$records) = @_;
       my (%sone,%stwo,%sthree);
       %sone=&record_sep($$records[0]);
       if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
       if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
   
       $r->print('Samples<br /><table border="2"><tr>');
       foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<th>Column&nbsp;'.($_+1).'</th>'); }
       $r->print('</tr>');
       foreach my $hash (\%sone,\%stwo,\%sthree) {
    $r->print('<tr>');
    foreach (sort({$a <=> $b} keys(%sone))) {
       $r->print('<td>');
       if (defined($$hash{$_})) { $r->print($$hash{$_}); }
       $r->print('</td>');
    }
    $r->print('</tr>');
       }
       $r->print('</tr></table><br />'."\n");
   }
   
 =item *  # ======Prints a table to create associations between values and table columns
   # $r is an Apache Request ref
   # $records is an arrayref from &Apache::loncommon::upfile_record_sep
   # $d is an array of 2 element arrays (internal name, displayed name)
   sub csv_print_select_table {
       my ($r,$records,$d) = @_;
       my $i=0;my %sone;
       %sone=&record_sep($$records[0]);
       $r->print('Associate columns with student attributes.'."\n".
        '<table border="2"><tr><th>Attribute</th><th>Column</th></tr>'."\n");
       foreach (@$d) {
    my ($value,$display)=@{ $_ };
    $r->print('<tr><td>'.$display.'</td>');
   
    $r->print('<td><select name=f'.$i.
     ' onchange="javascript:flip(this.form,'.$i.');">');
    $r->print('<option value="none"></option>');
    foreach (sort({$a <=> $b} keys(%sone))) {
       $r->print('<option value="'.$_.'">Column '.($_+1).'</option>');
    }
    $r->print('</select></td></tr>'."\n");
    $i++;
       }
       $i--;
       return $i;
   }
   
 BEGIN() : initialize values from language.tab, copyright.tab, filetypes.tab,  # ===================Prints a table of sample values from the upload and
 and filecategories.tab.  #                      can make associate samples to internal names
   # $r is an Apache Request ref
   # $records is an arrayref from &Apache::loncommon::upfile_record_sep
   # $d is an array of 2 element arrays (internal name, displayed name)
   sub csv_samples_select_table {
       my ($r,$records,$d) = @_;
       my %sone; my %stwo; my %sthree;
       my $i=0;
   
       $r->print('<table border=2><tr><th>Field</th><th>Samples</th></tr>');
       %sone=&record_sep($$records[0]);
       if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
       if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
   
       foreach (sort keys %sone) {
    $r->print('<tr><td><select name=f'.$i.
     ' onchange="javascript:flip(this.form,'.$i.');">');
    foreach (@$d) {
       my ($value,$display)=@{ $_ };
       $r->print('<option value='.$value.'>'.$display.'</option>');
    }
    $r->print('</select></td><td>');
    if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); }
    if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); }
    if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); }
    $r->print('</td></tr>');
    $i++;
       }
       $i--;
       return($i);
   }
   1;
   __END__;
   
 =item *  =item languageids() 
   
 languageids() : returns list of all language ids  returns list of all language ids
   
 =item *  =item languagedescription() 
   
 languagedescription() : returns description of a specified language id  returns description of a specified language id
   
 =item *  =item copyrightids() 
   
 copyrightids() : returns list of all copyrights  returns list of all copyrights
   
 =item *  =item copyrightdescription() 
   
 copyrightdescription() : returns description of a specified copyright id  returns description of a specified copyright id
   
 =item *  =item filecategories() 
   
 filecategories() : returns list of all file categories  returns list of all file categories
   
 =item *  =item filecategorytypes() 
   
 filecategorytypes() : returns list of file types belonging to a given file  returns list of file types belonging to a given file
 category  category
   
 =item *  =item fileembstyle() 
   
 fileembstyle() : returns embedding style for a specified file type  returns embedding style for a specified file type
   
 =item *  =item filedescription() 
   
 filedescription() : returns description for a specified file type  returns description for a specified file type
   
 =item *  =item filedescriptionex() 
   
 filedescriptionex() : returns description for a specified file type with  returns description for a specified file type with
 extra formatting  extra formatting
   
 =item *  =item get_previous_attempt() 
   
 get_previous_attempt() : return string with previous attempt on problem  return string with previous attempt on problem
   
 =item *  =item get_student_view() 
   
 get_student_view() : show a snapshot of what student was looking at  show a snapshot of what student was looking at
   
 =item *  =item get_student_answers() 
   
 get_student_answers() : show a snapshot of how student was answering problem  show a snapshot of how student was answering problem
   
 =item *  =item get_unprocessed_cgi() 
   
 get_unprocessed_cgi() : get unparsed CGI parameters  get unparsed CGI parameters
   
 =item *  =item cacheheader() 
   
 cacheheader() : returns cache-controlling header code  returns cache-controlling header code
   
 =item *  =item nocache() 
   
 nocache() : specifies header code to not have cache  specifies header code to not have cache
   
 =item *  =item add_to_env($name,$value) 
   
 add_to_env($name,$value) : adds $name to the %ENV hash with value  adds $name to the %ENV hash with value
 $value, if $name already exists, the entry is converted to an array  $value, if $name already exists, the entry is converted to an array
 reference and $value is added to the array.  reference and $value is added to the array.
   

Removed from v.1.25  
changed lines
  Added in v.1.35


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