+ popwin=open('','popwin','width=400,height=100');
+ popwin.document.writeln(''+
+ 'Spreadsheet Calculation Progress
'+
+ ''+
+ '');
+ popwin.document.close();
+
+ENDPOP
+ $r->rflush();
map {
if ($_=~/^A(\d+)/) {
my $row=$1;
- unless ($f{$_}=~/^\!/) {
- my ($tname,$tdom)=split(/\:/,$_);
-# my @assessdata=split(/\_\_\_\;\_\_\_/,
-# &Apache::lonnet::ssi(
-# '/adm/studentcalc',('utarget' => 'export',
-# 'uname' => $tname,
-# 'udom' => $tdom)));
+ unless (($f{$_}=~/^\!/) || ($row==0)) {
+ my @studentdata=&exportsheet(split(/\:/,$f{$_}),
+ 'studentcalc');
+ undef %userrdatas;
+ $now++;
+ $r->print('');
+ $r->rflush();
+
my $index=0;
-# map {
-# if ($assessdata[$index]) {
-# $c{$_.$row}=$assessdata[$index];
-# unless ($_ eq 'A') {
-# $f{$_.$row}='import';
-# }
-# }
-# $index++;
-# } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
-# 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
+ map {
+ if ($studentdata[$index]) {
+ 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++;
+ } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
+ 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
}
}
} keys %f;
&setformulas($safeeval,%f);
&setconstants($safeeval,%c);
+ $r->print('');
+ $r->rflush();
}
# ------------------------------------------------ Load data for one assessment
@@ -1233,11 +1324,31 @@ sub loadassessment {
unless ($namespace=$cid) { return ''; }
# ----------------------------------------------------------- Get stored values
+
+ my %returnhash=();
+
+ if ($cachedassess eq $uname.':'.$udom) {
+#
+# get data out of the dumped stores
+#
+
+ my $version=$cachedstores{'version:'.$symb};
+ my $scope;
+ for ($scope=1;$scope<=$version;$scope++) {
+ map {
+ $returnhash{$_}=$cachedstores{$scope.':'.$symb.':'.$_};
+ } split(/\:/,$cachedstores{$scope.':keys:'.$symb});
+ }
+
+ } else {
+#
+# restore individual
+#
+
my $answer=&Apache::lonnet::reply(
"restore:$udom:$uname:".
&Apache::lonnet::escape($namespace).":".
&Apache::lonnet::escape($symb),$uhome);
- my %returnhash=();
map {
my ($name,$value)=split(/\=/,$_);
$returnhash{&Apache::lonnet::unescape($name)}=
@@ -1249,18 +1360,19 @@ sub loadassessment {
$returnhash{$_}=$returnhash{$version.':'.$_};
} split(/\:/,$returnhash{$version.':keys'});
}
+ }
# ----------------------------- returnhash now has all stores for this resource
# ---------------------------- initialize coursedata and userdata for this user
- %courseopt=();
- %useropt=();
+ undef %courseopt;
+ undef %useropt;
my $userprefix=$uname.'_'.$udom.'_';
unless ($uhome eq 'no_host') {
# -------------------------------------------------------------- Get coursedata
unless
- ((time-$courserdatas{$cid.'.last_cache'})<120) {
+ ((time-$courserdatas{$cid.'.last_cache'})<240) {
my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.
':resourcedata',$chome);
if ($reply!~/^error\:/) {
@@ -1272,10 +1384,10 @@ sub loadassessment {
my ($name,$value)=split(/\=/,$_);
$courseopt{$userprefix.&Apache::lonnet::unescape($name)}=
&Apache::lonnet::unescape($value);
- } split(/\&/,$courserdatas{$ENV{'request.course.id'}});
+ } split(/\&/,$courserdatas{$cid});
# --------------------------------------------------- Get userdata (if present)
unless
- ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<120) {
+ ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {
my $reply=
&Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);
if ($reply!~/^error\:/) {
@@ -1289,7 +1401,6 @@ sub loadassessment {
&Apache::lonnet::unescape($value);
} split(/\&/,$userrdatas{$uname.'___'.$udom});
}
-
# ----------------- now courseopt, useropt initialized for this user and course
# (used by parmval)
@@ -1302,12 +1413,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{$ckey}=$returnhash{$key};
}
}
}
@@ -1361,11 +1476,11 @@ sub updatesheet {
# Import the data for rows
#
-sub loadrows() {
- my $safeeval=shift;
+sub loadrows {
+ my ($safeeval,$r)=@_;
my $stype=&gettype($safeeval);
if ($stype eq 'classcalc') {
- &loadcourse($safeeval);
+ &loadcourse($safeeval,$r);
} elsif ($stype eq 'studentcalc') {
&loadstudent($safeeval);
} else {
@@ -1373,21 +1488,206 @@ 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'};
+ 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)) {
+ return 1;
+ }
+ } else {
+ if (&checkthis('::studentcalc:',$time) ||
+ &checkthis($uname.':'.$udom.':studencalc:',$time)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
# ============================================================== Export handler
#
# Non-interactive call from with program
#
sub exportsheet {
- my ($uname,$udom,$stype,$usymb,$fn)=@_;
+ 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='';
+ }
+ }
+
+ 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;
+}
+
+# ===================================================== 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
@@ -1484,107 +1784,108 @@ ENDSCRIPT
my $asheet=&makenewsheet($aname,$adom,$1,$ENV{'form.usymb'});
-# if ($ENV{'form.unewfield'}) {
-# $r->print('Modified Workcopy
');
-# $ENV{'form.unewformula'}=~s/\'/\"/g;
-# $r->print('New formula: '.$ENV{'form.unewfield'}.'='.
-# $ENV{'form.unewformula'}.'
');
-# &setfilename($sheetone,$ENV{'form.ufn'});
-# &tmpread($sheetone,$r->dir_config('lonDaemons').'/tmp/',
-# $ENV{'form.usymb'},
-# $ENV{'form.unewfield'},$ENV{'form.unewformula'});
-# } elsif ($ENV{'form.saveas'}) {
-# &setfilename($sheetone,$ENV{'form.ufn'});
-# &tmpread($sheetone,,
-# $ENV{'form.usymb'});
-# } else {
-# unless ($ENV{'form.ufn'}) {
-# }#
-#
-# if (&gettype($sheetone) eq 'classcalc') {
-# ---------------------------------- For course view: get courselist and update
-# &updatestudentrows($sheetone);
-# } else {
-# ----------------- For assessment and student: See if all import rows uptodate
-# $csec=&Apache::lonnet::usection($udom,$uname,$ENV{'request.course.id'});
-# if ($csec eq '-1') {
-# $r->print('
'.
-# "User '$uname' at domain '$udom' not a student in this course
");
-# }
-# &updaterows($sheetone);
-# untie(%parmhash);
-# } else {
-# $r->print(''.
-# 'Could not initialize import fields (not in a course)
');
-# }
-# }
+# ------------------------ If a new formula had been entered, go from work copy
+
+ if ($ENV{'form.unewfield'}) {
+ $r->print('Modified Workcopy
');
+ $ENV{'form.unewformula'}=~s/\'/\"/g;
+ $r->print('New formula: '.$ENV{'form.unewfield'}.'='.
+ $ENV{'form.unewformula'}.'
');
+ &setfilename($asheet,$ENV{'form.ufn'});
+ &tmpread($asheet,
+ $ENV{'form.unewfield'},$ENV{'form.unewformula'});
+
+ } elsif ($ENV{'form.saveas'}) {
+ &setfilename($asheet,$ENV{'form.ufn'});
+ &tmpread($asheet);
+ } else {
+ &readsheet($asheet,$ENV{'form.ufn'});
+ }
+
+# -------------------------------------------------- Print out user information
+
+ unless (&gettype($asheet) eq 'classcalc') {
+ $r->print('
User: '.&getuname($asheet).
+ '
Domain: '.&getudom($asheet));
+ if (&getcsec($asheet) eq '-1') {
+ $r->print('
'.
+ 'Not a student in this course
');
+ } else {
+ $r->print('
Section/Group: '.&getcsec($asheet));
+ }
+ }
+
+# ---------------------------------------------------------------- Course title
+
+ $r->print(''.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.'
');
+
+
# ---------------------------------------------------- See if something to save
-# if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
-# my $fname='';
-# if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {
-# $fname=~s/\W/\_/g;
-# if ($fname eq 'default') { $fname='course_default'; }
-# $fname.='_'.&gettype($sheetone);
-# &setfilename($sheetone,$fname);
-# $ENV{'form.ufn'}=$fname;
-# my $reply=&writesheet($sheetone);
-# unless ($reroute) {
-# $r->print('Saving spreadsheet: '.$reply.'
');
-# }
-# if ($ENV{'form.makedefufn'}) {
-# my $reply=&Apache::lonnet::reply('put:'.
-# $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.':'.
-# $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.
-# ':environment:spreadsheet_default_'.
-# &gettype($sheetone).'='.
-# &Apache::lonnet::escape($fname),
-# $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
-# unless ($reroute) {
-# $r->print('
Making default spreadsheet: '.$reply.'
');
-# }
-# }
-# }
-# }
+
+ if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
+ my $fname='';
+ if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {
+ $fname=~s/\W/\_/g;
+ if ($fname eq 'default') { $fname='course_default'; }
+ $fname.='_'.&gettype($asheet);
+ &setfilename($asheet,$fname);
+ $ENV{'form.ufn'}=$fname;
+ $r->print('
Saving spreadsheet: '.
+ &writesheet($asheet,$ENV{'form.makedefufn'}).'
');
+ }
+ }
+
# ------------------------------------------------ Write the modified worksheet
-#
-# &tmpwrite($sheetone,$r->dir_config('lonDaemons').'/tmp/',
- # $ENV{'form.usymb'});
-#
-# ----------------------------------------------------- Print user, course, etc
-# unless ($reroute) {
-# if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
-# my $fname=$ENV{'form.ufn'};
-# $fname=~s/\_[^\_]+$//;
-# if ($fname eq 'default') { $fname='course_default'; }
-# $r->print(''.
-# ' (make default: )
');
-# }
-# $r->print(&hiddenfield('ufn',$ENV{'form.ufn'}));
-# unless (&gettype($sheetone) eq 'classcalc') {
-# $r->print('
User: '.$uname.'
Domain: '.$udom);
-# }
-# $r->print('
'.
-# $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.'
');
-# if ($csec) {
-# $r->print('Group/Section: '.$csec.'
');
-# }
-# }
-# -------------------------------------------------------- Import and calculate
-#
-# if (&gettype($sheetone) eq 'assesscalc') {
-# &rowaassess($sheetone,$ENV{'form.usymb'});
-# } elsif (&gettype($sheetone) eq 'studentcalc') {
-# &rowazstudent($sheetone);
-# } else {
-# &rowazclass($sheetone);
-# }
+ $r->print('Current sheet: '.&getfilename($asheet).'');
+
+ &tmpwrite($asheet);
+
+# ----------------------------------------------------------------- Save dialog
+
+
+ if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
+ my $fname=$ENV{'form.ufn'};
+ $fname=~s/\_[^\_]+$//;
+ if ($fname eq 'default') { $fname='course_default'; }
+ $r->print(''.
+ ' (make default: )
');
+ }
+
+ $r->print(&hiddenfield('ufn',&getfilename($asheet)));
+
+# --------------------------------------------------------------- Cached sheets
+
+ 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(s), updating rows ...
\n");
+ $r->rflush();
- &readsheet($asheet,'');
&updatesheet($asheet);
- &loadrows($asheet);
+ $r->print("Updated rows, loading row data ...
\n");
+ $r->rflush();
+
+ &loadrows($asheet,$r);
+
+ $r->print("Loaded row data, calculating sheet ...
\n");
+ $r->rflush();
my $calcoutput=&calcsheet($asheet);
$r->print('
'.$calcoutput.'
');
@@ -1592,7 +1893,6 @@ ENDSCRIPT
&outsheet($r,$asheet);
$r->print('