--- loncom/interface/Attic/lonspreadsheet.pm 2002/01/14 16:32:38 1.78
+++ loncom/interface/Attic/lonspreadsheet.pm 2002/04/10 15:30:13 1.83
@@ -1,3 +1,28 @@
+#
+# $Id: lonspreadsheet.pm,v 1.83 2002/04/10 15:30:13 matthew Exp $
+#
+# Copyright Michigan State University Board of Trustees
+#
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
# The LearningOnline Network with CAPA
# Spreadsheet/Grades Display Handler
#
@@ -9,6 +34,32 @@
# 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13,9/14,9/17,
# 10/16,10/17,10/20,11/05,11/28,12/27 Gerd Kortemeyer
# 01/14/02 Matthew
+# 02/04/02 Matthew
+
+# POD required stuff:
+
+=head1 NAME
+
+lonspreadsheet
+
+=head1 SYNOPSIS
+
+Spreadsheet interface to internal LON-CAPA data
+
+=head1 DESCRIPTION
+
+Lonspreadsheet provides course coordinators the ability to manage their
+students grades online. The students are able to view their own grades, but
+not the grades of their peers. The spreadsheet is highly customizable,
+offering the ability to use Perl code to manipulate data, as well as many
+built-in functions.
+
+
+=head2 Functions available to user of lonspreadsheet
+
+=over 4
+
+=cut
package Apache::lonspreadsheet;
@@ -190,6 +241,273 @@ sub mask {
return '^'.$alpha.$num."\$";
}
+#-------------------------------------------------------
+
+=item UWCALC(hashname,modules,units,date)
+
+returns the proportion of the module
+weights not previously completed by the student.
+
+=over 4
+
+=item hashname
+
+name of the hash the module dates have been inserted into
+
+=item modules
+
+reference to a cell which contains a comma deliminated list of modules
+covered by the assignment.
+
+=item units
+
+reference to a cell which contains a comma deliminated list of module
+weights with respect to the assignment
+
+=item date
+
+reference to a cell which contains the date the assignment was completed.
+
+=back
+
+=cut
+
+#-------------------------------------------------------
+sub UWCALC {
+ my ($hashname,$modules,$units,$date) = @_;
+ my @Modules = split(/,/,$modules);
+ my @Units = split(/,/,$units);
+ my $total_weight;
+ foreach (@Units) {
+ $total_weight += $_;
+ }
+ my $usum=0;
+ for (my $i=0; $i<=$#Modules; $i++) {
+ if (&HASH($hashname,$Modules[$i]) eq $date) {
+ $usum += $Units[$i];
+ }
+ }
+ return $usum/$total_weight;
+}
+
+#-------------------------------------------------------
+
+=item CDLSUM(list)
+
+returns the sum of the elements in a cell which contains
+a Comma Deliminate List of numerical values.
+'list' is a reference to a cell which contains a comma deliminated list.
+
+=cut
+
+#-------------------------------------------------------
+sub CDLSUM {
+ my ($list)=@_;
+ my $sum;
+ foreach (split/,/,$list) {
+ $sum += $_;
+ }
+ return $sum;
+}
+
+#-------------------------------------------------------
+
+=item CDLITEM(list,index)
+
+returns the item at 'index' in a Comma Deliminated List.
+
+=over 4
+
+=item list
+
+reference to a cell which contains a comma deliminated list.
+
+=item index
+
+the Perl index of the item requested (first element in list has
+an index of 0)
+
+=back
+
+=cut
+
+#-------------------------------------------------------
+sub CDLITEM {
+ my ($list,$index)=@_;
+ my @Temp = split/,/,$list;
+ return $Temp[$index];
+}
+
+#-------------------------------------------------------
+
+=item CDLHASH(name,key,value)
+
+loads a comma deliminated list of keys into
+the hash 'name', all with a value of 'value'.
+
+=over 4
+
+=item name
+
+name of the hash.
+
+=item key
+
+(a pointer to) a comma deliminated list of keys.
+
+=item value
+
+a single value to be entered for each key.
+
+=back
+
+=cut
+
+#-------------------------------------------------------
+sub CDLHASH {
+ my ($name,$key,$value)=@_;
+ my @Keys;
+ my @Values;
+ # Check to see if we have multiple $key values
+ if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $keymask = &mask($key);
+ # Assume the keys are addresses
+ my @Temp = grep /$keymask/,keys(%v);
+ @Keys = $v{@Temp};
+ } else {
+ $Keys[0]= $key;
+ }
+ my @Temp;
+ foreach $key (@Keys) {
+ @Temp = (@Temp, split/,/,$key);
+ }
+ @Keys = @Temp;
+ if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $valmask = &mask($value);
+ my @Temp = grep /$valmask/,keys(%v);
+ @Values =$v{@Temp};
+ } else {
+ $Values[0]= $value;
+ }
+ $value = $Values[0];
+ # Add values to hash
+ for (my $i = 0; $i<=$#Keys; $i++) {
+ my $key = $Keys[$i];
+ if (! exists ($hashes{$name}->{$key})) {
+ $hashes{$name}->{$key}->[0]=$value;
+ } else {
+ my @Temp = sort(@{$hashes{$name}->{$key}},$value);
+ $hashes{$name}->{$key} = \@Temp;
+ }
+ }
+ return "hash '$name' updated";
+}
+
+#-------------------------------------------------------
+
+=item GETHASH(name,key,index)
+
+returns the element in hash 'name'
+reference by the key 'key', at index 'index' in the values list.
+
+=cut
+
+#-------------------------------------------------------
+sub GETHASH {
+ my ($name,$key,$index)=@_;
+ if (! defined($index)) {
+ $index = 0;
+ }
+ if ($key =~ /^[A-z]\d+$/) {
+ $key = $v{$key};
+ }
+ return $hashes{$name}->{$key}->[$index];
+}
+
+#-------------------------------------------------------
+
+=item CLEARHASH(name)
+
+clears all the values from the hash 'name'
+
+=item CLEARHASH(name,key)
+
+clears all the values from the hash 'name' associated with the given key.
+
+=cut
+
+#-------------------------------------------------------
+sub CLEARHASH {
+ my ($name,$key)=@_;
+ if (defined($key)) {
+ if (exists($hashes{$name}->{$key})) {
+ $hashes{$name}->{$key}=undef;
+ return "hash '$name' key '$key' cleared";
+ }
+ } else {
+ if (exists($hashes{$name})) {
+ $hashes{$name}=undef;
+ return "hash '$name' cleared";
+ }
+ }
+ return "Error in clearing hash";
+}
+
+#-------------------------------------------------------
+
+=item HASH(name,key,value)
+
+loads values into an internal hash. If a key
+already has a value associated with it, the values are sorted numerically.
+
+=item HASH(name,key)
+
+returns the 0th value in the hash 'name' associated with 'key'.
+
+=cut
+
+#-------------------------------------------------------
+sub HASH {
+ my ($name,$key,$value)=@_;
+ my @Keys;
+ undef @Keys;
+ my @Values;
+ # Check to see if we have multiple $key values
+ if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $keymask = &mask($key);
+ # Assume the keys are addresses
+ my @Temp = grep /$keymask/,keys(%v);
+ @Keys = $v{@Temp};
+ } else {
+ $Keys[0]= $key;
+ }
+ # If $value is empty, return the first value associated
+ # with the first key.
+ if (! $value) {
+ return $hashes{$name}->{$Keys[0]}->[0];
+ }
+ # Check to see if we have multiple $value(s)
+ if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $valmask = &mask($value);
+ my @Temp = grep /$valmask/,keys(%v);
+ @Values =$v{@Temp};
+ } else {
+ $Values[0]= $value;
+ }
+ # Add values to hash
+ for (my $i = 0; $i<=$#Keys; $i++) {
+ my $key = $Keys[$i];
+ my $value = ($i<=$#Values ? $Values[$i] : $Values[0]);
+ if (! exists ($hashes{$name}->{$key})) {
+ $hashes{$name}->{$key}->[0]=$value;
+ } else {
+ my @Temp = sort(@{$hashes{$name}->{$key}},$value);
+ $hashes{$name}->{$key} = \@Temp;
+ }
+ }
+ return $Values[-1];
+}
+
sub NUM {
my $mask=mask(@_);
my $num= $#{@{grep(/$mask/,keys(%v))}}+1;
@@ -456,7 +774,7 @@ sub outrowassess {
'n','o','p','q','r','s','t','u','v','w','x','y','z') {
my $fm=$f{$_.$n};
$fm=~s/[\'\"]/\&\#34;/g;
- $cols[$#cols+1]="'$_$n','$fm'".'___eq___'.$v{$_.$n};
+ push(@cols,"'$_$n','$fm'".'___eq___'.$v{$_.$n});
}
return @cols;
}
@@ -815,26 +1133,51 @@ sub outsheet {
#
# ----------------------------------------------- Read list of available sheets
#
-
sub othersheets {
my ($safeeval,$stype)=@_;
-
+ #
my $cnum=&getcnum($safeeval);
my $cdom=&getcdom($safeeval);
my $chome=&getchome($safeeval);
-
+ #
my @alternatives=();
- my $result=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.':'.
- $stype.'_spreadsheets',$chome);
- if ($result!~/^error\:/) {
- foreach (split(/\&/,$result)) {
- $alternatives[$#alternatives+1]=
- &Apache::lonnet::unescape((split(/\=/,$_))[0]);
- }
- }
+ my %results=&Apache::lonnet::dump($stype.'_spreadsheets',$cdom,$cnum);
+ my ($tmp) = keys(%results);
+ unless ($tmp =~ /^(con_lost|error|no_such_host)/i) {
+ @alternatives = sort (keys(%results));
+ }
return @alternatives;
}
+
+#
+# -------------------------------------- Parse a spreadsheet
+#
+sub parse_sheet {
+ # $sheetxml is a scalar reference or a scalar
+ my ($sheetxml) = @_;
+ if (! ref($sheetxml)) {
+ my $tmp = $sheetxml;
+ $sheetxml = \$tmp;
+ }
+ my %f;
+ my $parser=HTML::TokeParser->new($sheetxml);
+ my $token;
+ while ($token=$parser->get_token) {
+ if ($token->[0] eq 'S') {
+ if ($token->[1] eq 'field') {
+ $f{$token->[2]->{'col'}.$token->[2]->{'row'}}=
+ $parser->get_text('/field');
+ }
+ if ($token->[1] eq 'template') {
+ $f{'template_'.$token->[2]->{'col'}}=
+ $parser->get_text('/template');
+ }
+ }
+ }
+ return \%f;
+}
+
#
# -------------------------------------- Read spreadsheet formulas for a course
#
@@ -846,17 +1189,19 @@ sub readsheet {
my $cdom=&getcdom($safeeval);
my $chome=&getchome($safeeval);
-# --------- There is no filename. Look for defaults in course and global, cache
-
- unless($fn) {
+ if (! defined($fn)) {
+ # There is no filename. Look for defaults in course and global, cache
unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {
- $fn=&Apache::lonnet::reply('get:'.$cdom.':'.$cnum.
- ':environment:spreadsheet_default_'.$stype,
- $chome);
- unless (($fn) && ($fn!~/^error\:/)) {
- $fn='default_'.$stype;
- }
- $defaultsheets{$cnum.'_'.$cdom.'_'.$stype}=$fn;
+ my %tmphash = &Apache::lonnet::get('environment',
+ ['spreadsheet_default_'.$stype],
+ $cdom,$cnum);
+ my ($tmp) = keys(%tmphash);
+ if ($tmp =~ /^(con_lost|error|no_such_host)/i) {
+ $fn = 'default_'.$stype;
+ } else {
+ $fn = $tmphash{'spreadsheet_default_'.$stype};
+ }
+ $defaultsheets{$cnum.'_'.$cdom.'_'.$stype}=$fn;
}
}
@@ -875,44 +1220,40 @@ sub readsheet {
my %f=();
if ($fn=~/^default\_/) {
- my $sheetxml='';
- {
+ my $sheetxml='';
my $fh;
my $dfn=$fn;
$dfn=~s/\_/\./g;
if ($fh=Apache::File->new($includedir.'/'.$dfn)) {
- $sheetxml=join('',<$fh>);
- } else {
+ $sheetxml=join('',<$fh>);
+ } else {
$sheetxml='
$sheetxml"; + if ($sheetxml == -1) { + $sheetxml='
"; + foreach (sort( keys(%f))) { + print "$_ = $f{$_}\n"; + } + print ""; + } else { + my $sheet=''; + my %tmphash = &Apache::lonnet::dump($fn,$cdom,$cnum); + my ($tmp) = keys(%tmphash); + unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { + foreach (keys(%tmphash)) { + $f{$_}=$tmphash{$_}; } - } - } - } else { - my $sheet=''; - my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.':'.$fn, - $chome); - unless ($reply=~/^error\:/) { - $sheet=$reply; - } - foreach (split(/\&/,$sheet)) { - my ($name,$value)=split(/\=/,$_); - $f{&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - } - } + } + } # --------------------------------------------------------------- Cache and set $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f); &setformulas($safeeval,%f);