--- loncom/interface/Attic/lonspreadsheet.pm 2001/03/13 15:50:47 1.44 +++ loncom/interface/Attic/lonspreadsheet.pm 2001/07/21 23:55:31 1.57 @@ -4,7 +4,9 @@ # 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,03/08,03/10,03/12,03/13 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, +# 07/09,07/14,07/21 Gerd Kortemeyer package Apache::lonspreadsheet; @@ -22,6 +24,8 @@ use HTML::TokeParser; # my %oldsheets; +my %loadedcaches; +my %expiredates; # # Cache for stores of an individual user @@ -74,12 +78,14 @@ sub initsheet { # v: output values # c: preloaded constants (A-column) # rl: row label +# os: other spreadsheets (for student spreadsheet only) undef %v; undef %t; undef %f; undef %c; undef %rl; +undef @os; $maxrow=0; $sheettype=''; @@ -394,7 +400,18 @@ sub outrowassess { my $n=shift; my @cols=(); if ($n) { - $cols[0]=$rl{$f{'A'.$n}}; + my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{'A'.$n}); + $cols[0]=$f{'A'.$n}.'<br>'.$rl{$usy}.'<br>'. + '<select name="sel_'.$n.'" onChange="changesheet('.$n. + ')"><option name="default">Default</option>'; + map { + $cols[0].='<option name="'.$_.'"'; + if ($ufn eq $_) { + $cols[0].=' selected'; + } + $cols[0].='>'.$_.'</option>'; + } @os; + $cols[0].='</select>'; } else { $cols[0]='<b><font size=+1>Export</font></b>'; } @@ -457,6 +474,13 @@ sub setconstants { %{$safeeval->varglob('c')}=%c; } +# --------------------------------------------- Set names of other spreadsheets + +sub setothersheets { + my ($safeeval,@os)=@_; + @{$safeeval->varglob('os')}=@os; +} + # ------------------------------------------------ Add or change formula values sub setrowlabels { @@ -597,6 +621,7 @@ sub exportdata { return $safeeval->reval('&exportrowa()'); } + # ========================================================== End of Spreadsheet # ============================================================================= @@ -635,11 +660,15 @@ sub rown { my $showf=0; my $proc; my $maxred; - if (&gettype($safeeval) eq 'assesscalc') { + if (&gettype($safeeval) eq 'studentcalc') { $proc='&outrowassess'; - $maxred=1; + $maxred=26; } else { $proc='&outrow'; + } + if (&gettype($safeeval) eq 'assesscalc') { + $maxred=1; + } else { $maxred=26; } if ($n eq '-') { $proc='&templaterow'; $n=-1; } @@ -713,6 +742,29 @@ 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\:/) { + map { + $alternatives[$#alternatives+1]= + &Apache::lonnet::unescape((split(/\=/,$_))[0]); + } split(/\&/,$result); + } + return @alternatives; +} + +# # -------------------------------------- Read spreadsheet formulas for a course # @@ -832,8 +884,10 @@ sub writesheet { # ----------------------------------------------------------------- Write sheet my $sheetdata=''; map { + unless ($f{$_} eq 'import') { $sheetdata.=&Apache::lonnet::escape($_).'='. &Apache::lonnet::escape($f{$_}).'&'; + } } keys %f; $sheetdata=~s/\&$//; my $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.$fn.':'. @@ -841,7 +895,8 @@ sub writesheet { if ($reply eq 'ok') { $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'. $stype.'_spreadsheets:'. - &Apache::lonnet::escape($fn).'='.$ENV{'user.name'}, + &Apache::lonnet::escape($fn).'='.$ENV{'user.name'}.'@'. + $ENV{'user.domain'}, $chome); if ($reply eq 'ok') { if ($makedef) { @@ -899,7 +954,14 @@ sub tmpread { $fo{$name}=$value; } } - if ($nfield) { $fo{$nfield}=$nform; } + if ($nform eq 'changesheet') { + $fo{'A'.$nfield}=(split(/\_\_\&\&\&\_\_/,$fo{'A'.$nfield}))[0]; + unless ($ENV{'form.sel_'.$nfield} eq 'Default') { + $fo{'A'.$nfield}.='__&&&__'.$ENV{'form.sel_'.$nfield}; + } + } else { + if ($nfield) { $fo{$nfield}=$nform; } + } &setformulas($safeeval,%fo); } @@ -1025,10 +1087,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}.'<br>'; + $rowlabel='<a href="/adm/studentcalc?uname='.$sname. + '&udom='.$sdom.'">'. + $ssec.' '.$reply{$sname}.'<br>'; map { $rowlabel.=&Apache::lonnet::unescape($_).' '; } split(/\&/,$reply); + $rowlabel.='</a>'; } $currentlist{&Apache::lonnet::unescape($name)}=$rowlabel; } @@ -1087,9 +1152,17 @@ sub updatestudentassesssheet { &GDBM_READER,0640)) { # --------------------------------------------------------- Get all assessments - my %allkeys=(); + my %allkeys=('timestamp' => + 'Timestamp of Last Transaction<br>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; @@ -1102,7 +1175,8 @@ sub updatestudentassesssheet { '___'.$resid.'___'. &Apache::lonnet::declutter($srcf); $allassess{$symb}= - '<a href="/adm/assesscalc?usymb='.$symb.'">'.$bighash{'title_'.$id}.'</a>'; + '<a href="/adm/assesscalc?usymb='.$symb.$adduserstr.'">'. + $bighash{'title_'.$id}.'</a>'; if ($stype eq 'assesscalc') { map { if (($_=~/^stores\_(.*)/) || ($_=~/^parameter\_(.*)/)) { @@ -1155,10 +1229,14 @@ sub updatestudentassesssheet { map { if ($_=~/^A(\d+)/) { $maxrow=($1>$maxrow)?$1:$maxrow; - $existing{$f{$_}}=1; - unless ((defined($current{$f{$_}})) || (!$1)) { + my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_}); + $existing{$usy}=1; + unless ((defined($current{$usy})) || (!$1)) { $f{$_}='!!! Obsolete'; $changed=1; + } elsif ($ufn) { + $current{$usy} + =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/; } } } keys %f; @@ -1208,9 +1286,10 @@ sub loadstudent { if ($_=~/^A(\d+)/) { my $row=$1; unless (($f{$_}=~/^\!/) || ($row==0)) { + my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_}); @assessdata=&exportsheet(&getuname($safeeval), &getudom($safeeval), - 'assesscalc',$f{$_}); + 'assesscalc',$usy,$ufn); my $index=0; map { if ($assessdata[$index]) { @@ -1254,7 +1333,7 @@ sub loadcourse { <script> popwin=open('','popwin','width=400,height=100'); popwin.document.writeln('<html><body bgcolor="#FFFFFF">'+ - '<h1>Spreadsheet Calculation Progress</h1>'+ + '<h3>Spreadsheet Calculation Progress</h3>'+ '<form name=popremain>'+ '<input type=text size=35 name=remaining value=Starting></form>'+ '</body></html>'); @@ -1482,6 +1561,37 @@ 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 @@ -1493,6 +1603,7 @@ sub exportsheet { # # Check if cached # + my $key=$uname.':'.$udom.':'.$stype.':'.$usymb; my $found=''; @@ -1505,6 +1616,26 @@ sub exportsheet { } 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 @@ -1514,7 +1645,8 @@ sub exportsheet { } else { # # Not cached -# +# + my $thissheet=&makenewsheet($uname,$udom,$stype,$usymb); &readsheet($thissheet,$fn); &updatesheet($thissheet); @@ -1525,12 +1657,24 @@ sub exportsheet { # Store now # my $cid=$ENV{'request.course.id'}; - my $current=&Apache::lonnet::reply('get:'. + 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 { @@ -1545,30 +1689,64 @@ sub exportsheet { if ($newstore) { $newstore.='___&___'; } $newstore.=$_.'___=___'.$currentlystored{$_}; } keys %currentlystored; - &Apache::lonnet::reply('put:'. + 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($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 all previously cached spreadsheets for this course +# Load previously cached student spreadsheets for this course # -sub cachedsheets { +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'}); - undef %oldsheets; unless ($reply=~/^error\:/) { map { my ($name,$value)=split(/\=/,$_); @@ -1578,6 +1756,35 @@ sub cachedsheets { } } +# ===================================================== 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 @@ -1617,6 +1824,10 @@ $tmpdir=$r->dir_config('lonDaemons').'/t } } (split(/&/,$ENV{'QUERY_STRING'})); +# -------------------------------------- Interactive loading of specific sheet? + if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) { + $ENV{'form.ufn'}=$ENV{'form.loadthissheet'}; + } # ------------------------------------------- Nothing there? Must be login user my $aname; @@ -1652,6 +1863,12 @@ $tmpdir=$r->dir_config('lonDaemons').'/t } } + function changesheet(cn) { + document.sheet.unewfield.value=cn; + document.sheet.unewformula.value='changesheet'; + document.sheet.submit(); + } + </script> ENDSCRIPT $r->print('</head><body bgcolor="#FFFFFF">'. @@ -1668,6 +1885,18 @@ ENDSCRIPT $r->rflush(); +# ---------------------------------------------------------------- Full recalc? + + + if ($ENV{'form.forcerecalc'}) { + $r->print('<h4>Completely Recalculating Sheet ...</h4>'); + undef %spreadsheets; + undef %courserdatas; + undef %userrdatas; + undef %defaultsheets; + undef %updatedata; + } + # ---------------------------------------- Read new sheet or modified worksheet $r->uri=~/\/(\w+)$/; @@ -1710,27 +1939,37 @@ ENDSCRIPT $r->print('<h1>'. $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.'</h1>'); +# ---------------------------------------------------- See if user can see this -# ---------------------------------------------------- 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($asheet); - &setfilename($asheet,$fname); - $ENV{'form.ufn'}=$fname; - $r->print('<p>Saving spreadsheet: '. - &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>'); - } + 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( + '<h1>Access Permission Denied</h1></form></body></html>'); + return OK; + } } -# ------------------------------------------------ Write the modified worksheet - - $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>'); +# ---------------------------------------------------------- Additional options - &tmpwrite($asheet); + $r->print( + '<input type=submit name=forcerecalc value="Completely Recalculate Sheet"><p>' + ); + if (&gettype($asheet) eq 'assesscalc') { + $r->print ('<p><font size=+2><a href="/adm/studentcalc?uname='. + &getuname($asheet). + '&udom='.&getudom($asheet). + '">Level up: Student Sheet</a></font><p>'); + } + + if ((&gettype($asheet) eq 'studentcalc') && + (&Apache::lonnet::allowed('vgr',&getcid($asheet)))) { + $r->print ( + '<p><font size=+2><a href="/adm/classcalc">'. + 'Level up: Course Sheet</a></font><p>'); + } + # ----------------------------------------------------------------- Save dialog @@ -1746,9 +1985,41 @@ ENDSCRIPT $r->print(&hiddenfield('ufn',&getfilename($asheet))); -# ----------------------------------------------------------- Get cached sheets +# ----------------------------------------------------------------- Load dialog + if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) { + $r->print('<p><input type=submit name=load value="Load ...">'. + '<select name="loadthissheet">'. + '<option name="default">Default</option>'); + map { + $r->print('<option name="'.$_.'"'); + if ($ENV{'form.ufn'} eq $_) { + $r->print(' selected'); + } + $r->print('>'.$_.'</option>'); + } &othersheets($asheet,&gettype($asheet)); + $r->print('</select><p>'); + if (&gettype($asheet) eq 'studentcalc') { + &setothersheets($asheet,&othersheets($asheet,'assesscalc')); + } + } - &cachedsheets(); +# --------------------------------------------------------------- Cached sheets + + &expirationdates(); + + undef %oldsheets; + undef %loadedcaches; + + if (&gettype($asheet) eq 'classcalc') { + $r->print("Loading previously calculated student sheets ...<br>\n"); + $r->rflush(); + &cachedcsheets(); + } elsif (&gettype($asheet) eq 'studentcalc') { + $r->print("Loading previously calculated assessment sheets ...<br>\n"); + $r->rflush(); + &cachedssheets(&getuname($asheet),&getudom($asheet), + &getuhome($asheet)); + } # ----------------------------------------------------- Update sheet, load rows @@ -1768,6 +2039,29 @@ ENDSCRIPT my $calcoutput=&calcsheet($asheet); $r->print('<h3><font color=red>'.$calcoutput.'</h3></font>'); +# ---------------------------------------------------- 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($asheet); + &setfilename($asheet,$fname); + $ENV{'form.ufn'}=$fname; + $r->print('<p>Saving spreadsheet: '. + &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>'); + } + } + +# ------------------------------------------------ Write the modified worksheet + + $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>'); + + &tmpwrite($asheet); + +# ------------------------------------------------------------- Print out sheet + &outsheet($r,$asheet); $r->print('</form></body></html>');