--- loncom/interface/Attic/lonspreadsheet.pm 2001/03/05 21:26:29 1.39 +++ loncom/interface/Attic/lonspreadsheet.pm 2001/04/09 17:59:04 1.54 @@ -4,7 +4,8 @@ # 11/11,11/15,11/27,12/04,12/05,12/06,12/07, # 12/08,12/09,12/11,12/12,12/15,12/16,12/18,12/19,12/30, # 01/01/01,02/01,03/01,19/01,20/01,22/01, -# 03/05 Gerd Kortemeyer +# 03/05,03/08,03/10,03/12,03/13,03/15,03/17, +# 03/19,03/20,03/21,03/27,04/05,04/09 Gerd Kortemeyer package Apache::lonspreadsheet; @@ -18,6 +19,14 @@ use GDBM_File; use HTML::TokeParser; # +# Caches for previously calculated spreadsheets +# + +my %oldsheets; +my %loadedcaches; +my %expiredates; + +# # Cache for stores of an individual user # @@ -48,25 +57,6 @@ my %parmhash; my $includedir; my $tmpdir; - -sub mdeb { - my $msg=shift; - my $mem=''; - { - my $mfh=Apache::File->new('/proc/'.$$.'/status'); - my $line; - while ($line=<$mfh>) { - my ($name,$value)=split(/\:/,$line); - if ($name eq 'VmSize') { $mem=$value; } - } - $mfh->close(); - } - print $msg.$mem."
\n"; -} - - - - # ============================================================================= # ===================================== Implements an instance of a spreadsheet @@ -336,7 +326,7 @@ sub sett { $t{$lb}=~s/\#/$trow/g; $t{$lb}=~s/\.\.+/\,/g; $t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; - $t{$lb}=~s/(^|[^\"\'])\[([\w\.]+)\]/$1\$c\{\'$2\'\}/g; + $t{$lb}=~s/(^|[^\"\'])\[(\w+)\]/$1\$c\{\'$2\'\}/g; } } } keys %f; @@ -345,7 +335,8 @@ sub sett { } keys %f; map { if (($f{$_}) && ($_!~/template\_/)) { - if ($_=~/^$pattern/) { + my $matches=($_=~/^$pattern(\d+)/); + if (($matches) && ($1)) { unless ($f{$_}=~/^\!/) { $t{$_}=$c{$_}; } @@ -1037,10 +1028,13 @@ sub updateclasssheet { my $reply=&Apache::lonnet::reply('get:'.$sdom.':'.$sname. ':environment:firstname&middlename&lastname&generation', &Apache::lonnet::homeserver($sname,$sdom)); - $rowlabel=$ssec.' '.$reply{$sname}.'
'; + $rowlabel=''. + $ssec.' '.$reply{$sname}.'
'; map { $rowlabel.=&Apache::lonnet::unescape($_).' '; } split(/\&/,$reply); + $rowlabel.='
'; } $currentlist{&Apache::lonnet::unescape($name)}=$rowlabel; } @@ -1099,9 +1093,17 @@ sub updatestudentassesssheet { &GDBM_READER,0640)) { # --------------------------------------------------------- Get all assessments - my %allkeys=(); + my %allkeys=('timestamp' => + 'Timestamp of Last Transaction
timestamp'); my %allassess=(); + my $adduserstr=''; + if ((&getuname($safeeval) ne $ENV{'user.name'}) || + (&getudom($safeeval) ne $ENV{'user.domain'})) { + $adduserstr='&uname='.&getuname($safeeval). + '&udom='.&getudom($safeeval); + } + map { if ($_=~/^src\_(\d+)\.(\d+)$/) { my $mapid=$1; @@ -1114,7 +1116,8 @@ sub updatestudentassesssheet { '___'.$resid.'___'. &Apache::lonnet::declutter($srcf); $allassess{$symb}= - ''.$bighash{'title_'.$id}.''; + ''. + $bighash{'title_'.$id}.''; if ($stype eq 'assesscalc') { map { if (($_=~/^stores\_(.*)/) || ($_=~/^parameter\_(.*)/)) { @@ -1122,9 +1125,10 @@ sub updatestudentassesssheet { my $display= &Apache::lonnet::metadata($srcf,$key.'.display'); unless ($display) { - $display= + $display.= &Apache::lonnet::metadata($srcf,$key.'.name'); } + $display.='
'.$key; $allkeys{$key}=$display; } } split(/\,/,&Apache::lonnet::metadata($srcf,'keys')); @@ -1218,16 +1222,21 @@ sub loadstudent { map { if ($_=~/^A(\d+)/) { my $row=$1; - unless ($f{$_}=~/^\!/) { + unless (($f{$_}=~/^\!/) || ($row==0)) { @assessdata=&exportsheet(&getuname($safeeval), &getudom($safeeval), 'assesscalc',$f{$_}); my $index=0; map { if ($assessdata[$index]) { - $c{$_.$row}=$assessdata[$index]; - unless ($_ eq 'A') { - $f{$_.$row}='import'; + my $col=$_; + if ($assessdata[$index]=~/\D/) { + $c{$col.$row}="'".$assessdata[$index]."'"; + } else { + $c{$col.$row}=$assessdata[$index]; + } + unless ($col eq 'A') { + $f{$col.$row}='import'; } } $index++; @@ -1260,18 +1269,18 @@ sub loadcourse { ENDPOP $r->rflush(); map { if ($_=~/^A(\d+)/) { my $row=$1; - unless ($f{$_}=~/^\!/) { + unless (($f{$_}=~/^\!/) || ($row==0)) { my @studentdata=&exportsheet(split(/\:/,$f{$_}), 'studentcalc'); undef %userrdatas; @@ -1284,9 +1293,14 @@ ENDPOP my $index=0; map { if ($studentdata[$index]) { - $c{$_.$row}=$studentdata[$index]; - unless ($_ eq 'A') { - $f{$_.$row}='import'; + my $col=$_; + if ($studentdata[$index]=~/\D/) { + $c{$col.$row}="'".$studentdata[$index]."'"; + } else { + $c{$col.$row}=$studentdata[$index]; + } + unless ($col eq 'A') { + $f{$col.$row}='import'; } } $index++; @@ -1297,7 +1311,7 @@ ENDPOP } keys %f; &setformulas($safeeval,%f); &setconstants($safeeval,%c); - $r->print(''); + $r->print(''); $r->rflush(); } @@ -1408,13 +1422,16 @@ sub loadassessment { if ($_=~/^A/) { unless ($f{$_}=~/^\!/) { if ($f{$_}=~/^parameter/) { - $c{$_}=&parmval($f{$_},$safeeval); + my $val=&parmval($f{$_},$safeeval); + $c{$_}=$val; + $c{$f{$_}}=$val; } else { my $key=$f{$_}; + my $ckey=$key; $key=~s/^stores\_/resource\./; $key=~s/\_/\./; $c{$_}=$returnhash{$key}; - $c{$key}=$returnhash{$key}; + $c{$ckey}=$returnhash{$key}; } } } @@ -1480,22 +1497,230 @@ sub loadrows { } } +# ======================================================= Forced recalculation? + +sub checkthis { + my ($keyname,$time)=@_; + return ($time<$expiredates{$keyname}); +} +sub forcedrecalc { + my ($uname,$udom,$stype,$usymb)=@_; + my $key=$uname.':'.$udom.':'.$stype.':'.$usymb; + my $time=$oldsheets{$key.'.time'}; + if ($ENV{'form.forcerecalc'}) { return 1; } + unless ($time) { return 1; } + if ($stype eq 'assesscalc') { + my $map=(split(/\_\_\_/,$usymb))[0]; + if (&checkthis('::assesscalc:',$time) || + &checkthis('::assesscalc:'.$map,$time) || + &checkthis('::assesscalc:'.$usymb,$time) || + &checkthis($uname.':'.$udom.':assesscalc:',$time) || + &checkthis($uname.':'.$udom.':assesscalc:'.$map,$time) || + &checkthis($uname.':'.$udom.':assesscalc:'.$usymb,$time)) { + return 1; + } + } else { + if (&checkthis('::studentcalc:',$time) || + &checkthis($uname.':'.$udom.':studentcalc:',$time)) { + return 1; + } + } + return 0; +} + # ============================================================== Export handler # # Non-interactive call from with program # sub exportsheet { + my ($uname,$udom,$stype,$usymb,$fn)=@_; + my @exportarr=(); +# +# Check if cached +# + + my $key=$uname.':'.$udom.':'.$stype.':'.$usymb; + my $found=''; + + if ($oldsheets{$key}) { + map { + my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_); + if ($name eq $fn) { + $found=$value; + } + } split(/\_\_\_\&\_\_\_/,$oldsheets{$key}); + } + + unless ($found) { + &cachedssheets($uname,$udom,&Apache::lonnet::homeserver($uname,$udom)); + if ($oldsheets{$key}) { + map { + my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_); + if ($name eq $fn) { + $found=$value; + } + } split(/\_\_\_\&\_\_\_/,$oldsheets{$key}); + } + } +# +# Check if still valid +# + if ($found) { + if (&forcedrecalc($uname,$udom,$stype,$usymb)) { + $found=''; + } + } - my ($uname,$udom,$stype,$usymb,$fn)=@_; + if ($found) { +# +# Return what was cached +# + @exportarr=split(/\_\_\_\;\_\_\_/,$found); + + } else { +# +# Not cached +# + my $thissheet=&makenewsheet($uname,$udom,$stype,$usymb); &readsheet($thissheet,$fn); &updatesheet($thissheet); &loadrows($thissheet); - &calcsheet($thissheet); - return &exportdata($thissheet); + &calcsheet($thissheet); + @exportarr=&exportdata($thissheet); +# +# Store now +# + my $cid=$ENV{'request.course.id'}; + my $current=''; + if ($stype eq 'studentcalc') { + $current=&Apache::lonnet::reply('get:'. + $ENV{'course.'.$cid.'.domain'}.':'. + $ENV{'course.'.$cid.'.num'}. + ':nohist_calculatedsheets:'. + &Apache::lonnet::escape($key), + $ENV{'course.'.$cid.'.home'}); + } else { + $current=&Apache::lonnet::reply('get:'. + &getudom($thissheet).':'. + &getuname($thissheet). + ':nohist_calculatedsheets_'. + $ENV{'request.course.id'}.':'. + &Apache::lonnet::escape($key), + &getuhome($thissheet)); + + } + my %currentlystored=(); + unless ($current=~/^error\:/) { + map { + my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_); + $currentlystored{$name}=$value; + } split(/\_\_\_\&\_\_\_/,&Apache::lonnet::unescape($current)); + } + $currentlystored{$fn}=join('___;___',@exportarr); + + my $newstore=''; + map { + if ($newstore) { $newstore.='___&___'; } + $newstore.=$_.'___=___'.$currentlystored{$_}; + } keys %currentlystored; + my $now=time; + if ($stype eq 'studentcalc') { + &Apache::lonnet::reply('put:'. + $ENV{'course.'.$cid.'.domain'}.':'. + $ENV{'course.'.$cid.'.num'}. + ':nohist_calculatedsheets:'. + &Apache::lonnet::escape($key).'='. + &Apache::lonnet::escape($newstore).'&'. + &Apache::lonnet::escape($key).'.time='.$now, + $ENV{'course.'.$cid.'.home'}); + } else { + &Apache::lonnet::reply('put:'. + &getudom($thissheet).':'. + &getuname($thissheet). + ':nohist_calculatedsheets_'. + $ENV{'request.course.id'}.':'. + &Apache::lonnet::escape($key).'='. + &Apache::lonnet::escape($newstore).'&'. + &Apache::lonnet::escape($key).'.time='.$now, + &getuhome($thissheet)); + } + } + return @exportarr; +} +# ============================================================ Expiration Dates +# +# Load previously cached student spreadsheets for this course +# + +sub expirationdates { + undef %expiredates; + my $cid=$ENV{'request.course.id'}; + my $reply=&Apache::lonnet::reply('dump:'. + $ENV{'course.'.$cid.'.domain'}.':'. + $ENV{'course.'.$cid.'.num'}. + ':nohist_expirationdates', + $ENV{'course.'.$cid.'.home'}); + unless ($reply=~/^error\:/) { + map { + my ($name,$value)=split(/\=/,$_); + $expiredates{&Apache::lonnet::unescape($name)} + =&Apache::lonnet::unescape($value); + } split(/\&/,$reply); + } +} + +# ===================================================== Calculated sheets cache +# +# Load previously cached student spreadsheets for this course +# + +sub cachedcsheets { + my $cid=$ENV{'request.course.id'}; + my $reply=&Apache::lonnet::reply('dump:'. + $ENV{'course.'.$cid.'.domain'}.':'. + $ENV{'course.'.$cid.'.num'}. + ':nohist_calculatedsheets', + $ENV{'course.'.$cid.'.home'}); + unless ($reply=~/^error\:/) { + map { + my ($name,$value)=split(/\=/,$_); + $oldsheets{&Apache::lonnet::unescape($name)} + =&Apache::lonnet::unescape($value); + } split(/\&/,$reply); + } } +# ===================================================== Calculated sheets cache +# +# Load previously cached assessment spreadsheets for this student +# + +sub cachedssheets { + my ($sname,$sdom,$shome)=@_; + unless (($loadedcaches{$sname.'_'.$sdom}) || ($shome eq 'no_host')) { + my $cid=$ENV{'request.course.id'}; + my $reply=&Apache::lonnet::reply('dump:'.$sdom.':'.$sname. + ':nohist_calculatedsheets_'. + $ENV{'request.course.id'}, + $shome); + unless ($reply=~/^error\:/) { + map { + my ($name,$value)=split(/\=/,$_); + $oldsheets{&Apache::lonnet::unescape($name)} + =&Apache::lonnet::unescape($value); + } split(/\&/,$reply); + } + $loadedcaches{$sname.'_'.$sdom}=1; + } +} + +# ===================================================== Calculated sheets cache +# +# Load previously cached assessment spreadsheets for this student +# + # ================================================================ Main handler # # Interactive call to screen @@ -1586,6 +1811,18 @@ ENDSCRIPT $r->rflush(); +# ---------------------------------------------------------------- Full recalc? + + + if ($ENV{'form.forcerecalc'}) { + $r->print('

Completely Recalculating Sheet ...

'); + undef %spreadsheets; + undef %courserdatas; + undef %userrdatas; + undef %defaultsheets; + undef %updatedata; + } + # ---------------------------------------- Read new sheet or modified worksheet $r->uri=~/\/(\w+)$/; @@ -1628,6 +1865,17 @@ ENDSCRIPT $r->print('

'. $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.'

'); +# ---------------------------------------------------- See if user can see this + + if ((&gettype($asheet) eq 'classcalc') || + (&getuname($asheet) ne $ENV{'user.name'}) || + (&getudom($asheet) ne $ENV{'user.domain'})) { + unless (&Apache::lonnet::allowed('vgr',&getcid($asheet))) { + $r->print( + '

Access Permission Denied

'); + return OK; + } + } # ---------------------------------------------------- See if something to save @@ -1650,6 +1898,26 @@ ENDSCRIPT &tmpwrite($asheet); +# ---------------------------------------------------------- Additional options + + $r->print( + '

' + ); + if (&gettype($asheet) eq 'assesscalc') { + $r->print ('

Level up: Student Sheet

'); + } + + if ((&gettype($asheet) eq 'studentcalc') && + (&Apache::lonnet::allowed('vgr',&getcid($asheet)))) { + $r->print ( + '

'. + 'Level up: Course Sheet

'); + } + + # ----------------------------------------------------------------- Save dialog @@ -1664,10 +1932,27 @@ ENDSCRIPT $r->print(&hiddenfield('ufn',&getfilename($asheet))); +# --------------------------------------------------------------- Cached sheets + + &expirationdates(); + + undef %oldsheets; + undef %loadedcaches; + + if (&gettype($asheet) eq 'classcalc') { + $r->print("Loading previously calculated student sheets ...
\n"); + $r->rflush(); + &cachedcsheets(); + } elsif (&gettype($asheet) eq 'studentcalc') { + $r->print("Loading previously calculated assessment sheets ...
\n"); + $r->rflush(); + &cachedssheets(&getuname($asheet),&getudom($asheet), + &getuhome($asheet)); + } # ----------------------------------------------------- Update sheet, load rows - $r->print("Loaded sheet, updating rows ...
\n"); + $r->print("Loaded sheet(s), updating rows ...
\n"); $r->rflush(); &updatesheet($asheet); @@ -1699,19 +1984,3 @@ ENDSCRIPT 1; __END__ - - - - - - - - - - - - - - - -