--- loncom/interface/Attic/lonspreadsheet.pm 2002/11/07 15:37:02 1.135 +++ loncom/interface/Attic/lonspreadsheet.pm 2002/12/04 21:49:33 1.154 @@ -1,5 +1,5 @@ # -# $Id: lonspreadsheet.pm,v 1.135 2002/11/07 15:37:02 matthew Exp $ +# $Id: lonspreadsheet.pm,v 1.154 2002/12/04 21:49:33 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,17 +53,19 @@ built-in functions. package Apache::lonspreadsheet; use strict; +use Apache::Constants qw(:common :http); +use Apache::lonnet; +use Apache::lonhtmlcommon; +use Apache::loncoursedata; +use Apache::File(); use Safe; use Safe::Hole; use Opcode; -use Apache::lonnet; -use Apache::Constants qw(:common :http); use GDBM_File; +use HTML::Entities(); use HTML::TokeParser; -use Apache::lonhtmlcommon; -use Apache::loncoursedata; -use Apache::File(); use Spreadsheet::WriteExcel; + # # Caches for coursewide information # @@ -93,7 +95,7 @@ my %spreadsheets; my %courserdatas; my %userrdatas; my %defaultsheets; -my %updatedata; +my %rowlabel_cache; # # These global hashes are dependent on user, course and resource, @@ -964,11 +966,9 @@ sub templaterow { 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', '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') { - my $fm=$sheet->{'f'}->{'template_'.$_}; - $fm=~s/[\'\"]/\&\#34;/g; push(@cols,{ name => 'template_'.$_, - formula => $fm, - value => $fm }); + formula => $sheet->{'f'}->{'template_'.$_}, + value => $sheet->{'f'}->{'template_'.$_} }); } return ($rowlabel,@cols); } @@ -981,7 +981,11 @@ sub outrowassess { if ($n) { my ($usy,$ufn)=split(/__&&&\__/,$sheet->{'f'}->{'A'.$n}); if (exists($sheet->{'rowlabel'}->{$usy})) { - $rowlabel = $sheet->{'rowlabel'}->{$usy}; + # This is dumb, but we need the information when we output + # the html version of the studentcalc spreadsheet for the + # links to the assesscalc sheets. + $rowlabel = $sheet->{'rowlabel'}->{$usy}.':'. + &Apache::lonnet::escape($ufn); } else { $rowlabel = ''; } @@ -992,10 +996,8 @@ sub outrowassess { 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', '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') { - my $fm=$sheet->{'f'}->{$_.$n}; - $fm=~s/[\'\"]/\&\#34;/g; push(@cols,{ name => $_.$n, - formula => $fm, + formula => $sheet->{'f'}->{$_.$n}, value => $sheet->{'values'}->{$_.$n}}); } return ($rowlabel,@cols); @@ -1018,10 +1020,8 @@ sub outrow { 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', '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') { - my $fm=$sheet->{'f'}->{$_.$n}; - $fm=~s/[\'\"]/\&\#34;/g; push(@cols,{ name => $_.$n, - formula => $fm, + formula => $sheet->{'f'}->{$_.$n}, value => $sheet->{'values'}->{$_.$n}}); } return ($rowlabel,@cols); @@ -1085,6 +1085,44 @@ sub geterrorlog { return ${$sheet->{'safe'}->varglob('errorlog')}; } +sub gettitle { + my $sheet = shift; + if ($sheet->{'sheettype'} eq 'classcalc') { + return $sheet->{'coursedesc'}; + } elsif ($sheet->{'sheettype'} eq 'studentcalc') { + return 'Grades for '.$sheet->{'uname'}.'@'.$sheet->{'udom'}; + } elsif ($sheet->{'sheettype'} eq 'assesscalc') { + if (($sheet->{'usymb'} eq '_feedback') || + ($sheet->{'usymb'} eq '_evaluation') || + ($sheet->{'usymb'} eq '_discussion') || + ($sheet->{'usymb'} eq '_tutoring')) { + my $title = $sheet->{'usymb'}; + $title =~ s/^_//; + $title = ucfirst($title); + return $title; + } + return if (! defined($sheet->{'mapid'}) || + $sheet->{'mapid'} !~ /^\d+$/); + my $mapid = $sheet->{'mapid'}; + return if (! defined($sheet->{'resid'}) || + $sheet->{'resid'} !~ /^\d+$/); + my $resid = $sheet->{'resid'}; + my %course_db; + tie(%course_db,'GDBM_File',$sheet->{'coursefilename'}.'.db', + &GDBM_READER(),0640); + return if (! tied(%course_db)); + my $key = 'title_'.$mapid.'.'.$resid; + my $title = ''; + if (exists($course_db{$key})) { + $title = $course_db{$key}; + } else { + $title = $sheet->{'usymb'}; + } + untie (%course_db); + return $title; + } +} + # ----------------------------------------------------- Get value of $f{'A'.$n} sub getfa { my $sheet = shift; @@ -1107,6 +1145,22 @@ sub exportdata { return @exportarray; } + + +sub update_student_sheet{ + my ($sheet,$r,$c) = @_; + # Load in the studentcalc sheet + &readsheet($sheet,'default_studentcalc'); + # Determine the structure (contained assessments, etc) of the sheet + &updatesheet($sheet); + # Load in the cached sheets for this student + &cachedssheets($sheet); + # Load in the (possibly cached) data from the assessment sheets + &loadstudent($sheet,$r,$c); + # Compute the sheet + &calcsheet($sheet); +} + # ========================================================== End of Spreadsheet # ============================================================================= # @@ -1131,16 +1185,49 @@ sub get_row { ######################################################################## sub sort_indicies { my $sheet = shift; - # - # Sort the rows in some manner - # - my @sortby=(); my @sortidx=(); - for (my $row=1;$row<=$sheet->{'maxrow'};$row++) { - push (@sortby, $sheet->{'safe'}->reval('$f{"A'.$row.'"}')); - push (@sortidx, $row); + # + if ($sheet->{'sheettype'} eq 'classcalc') { + my @sortby=(undef); + # Skip row 0 + for (my $row=1;$row<=$sheet->{'maxrow'};$row++) { + my (undef,$sname,$sdom,$fullname,$section,$id) = + split(':',$sheet->{'rowlabel'}->{$sheet->{'f'}->{'A'.$row}}); + push (@sortby, lc($fullname)); + push (@sortidx, $row); + } + @sortidx = sort { $sortby[$a] cmp $sortby[$b]; } @sortidx; + } elsif ($sheet->{'sheettype'} eq 'studentcalc') { + my @sortby1=(undef); + my @sortby2=(undef); + # Skip row 0 + for (my $row=1;$row<=$sheet->{'maxrow'};$row++) { + my ($key,undef) = split(/__&&&\__/,$sheet->{'f'}->{'A'.$row}); + my $rowlabel = $sheet->{'rowlabel'}->{$key}; + my (undef,$symb,$mapid,$resid,$title,$ufn) = + split(':',$rowlabel); + $ufn = &Apache::lonnet::unescape($ufn); + $symb = &Apache::lonnet::unescape($symb); + $title = &Apache::lonnet::unescape($title); + my ($sequence) = ($symb =~ /\/([^\/]*\.sequence)/); + if ($sequence eq '') { + $sequence = $symb; + } + push (@sortby1, $sequence); + push (@sortby2, $title); + push (@sortidx, $row); + } + @sortidx = sort { $sortby1[$a] cmp $sortby1[$b] || + $sortby2[$a] cmp $sortby2[$b] } @sortidx; + } else { + my @sortby=(undef); + # Skip row 0 + for (my $row=1;$row<=$sheet->{'maxrow'};$row++) { + push (@sortby, $sheet->{'safe'}->reval('$f{"A'.$row.'"}')); + push (@sortidx, $row); + } + @sortidx = sort { $sortby[$a] cmp $sortby[$b]; } @sortidx; } - @sortidx=sort { lc($sortby[$a]) cmp lc($sortby[$b]); } @sortidx; return @sortidx; } @@ -1169,18 +1256,28 @@ sub html_editable_cell { if ($formula ne '') { $value = 'undefined value'; } - } - if ($value =~ /^\s*$/ ) { + } elsif ($value =~ /^\s*$/ ) { $value = '#'; + } else { + $value = &HTML::Entities::encode($value); } - $result .= ''.$value.''; + # Make the formula safe for outputting + $formula =~ s/\'/\"/g; + # The formula will be parsed by the browser *twice* before being + # displayed to the user for editing. + $formula = &HTML::Entities::encode(&HTML::Entities::encode($formula)); + # Escape newlines so they make it into the edit window + $formula =~ s/\n/\\n/gs; + # Glue everything together + $result .= "".$value.""; return $result; } sub html_uneditable_cell { my ($cell,$bgcolor) = @_; my $value = (defined($cell) ? $cell->{'value'} : ''); + $value = &HTML::Entities::encode($value); return ' '.$value.' '; } @@ -1232,7 +1329,7 @@ END # Print out template row #################################### my ($rowlabel,@rowdata) = &get_row($sheet,'-'); - my $row_html = '
+This operation may take longer than a complete recalculation of the +spreadsheet. +
+To abort this operation, hit the stop button on your browser. +
+A link to the spreadsheet will be available at the end of this process. +
+
+END
$r->rflush();
- foreach (keys(%f)) {
- next if ($_!~/^A(\d+)/ || $1 == 0 || ($f{$_}=~/^[!~-]/));
+ my $starttime = time;
+ foreach my $rownum (&sort_indicies($sheet)) {
$count++;
- my ($sname,$sdom) = split(':',$f{$_});
+ my ($sname,$sdom) = split(':',$f{'A'.$rownum});
my $student_excel_worksheet=$workbook->addworksheet($sname.'@'.$sdom);
# Create a new spreadsheet
my $studentsheet = &makenewsheet($sname,$sdom,'studentcalc',undef);
# Read in the spreadsheet definition
- &readsheet($studentsheet,'default_studentcalc');
- # Determine the structure (contained assessments, etc) of the sheet
- &updatesheet($studentsheet);
- # Load in the (possibly cached) data from the assessment sheets
- &loadrows($studentsheet);
- # Compute the sheet
- &calcsheet($studentsheet);
- &Apache::lonnet::logthis("Sheet value for A0 = ".$sheet->{'values'}->{'A0'});
+ &update_student_sheet($studentsheet,$r,$c);
# Stuff the sheet into excel
&export_sheet_as_excel($studentsheet,$student_excel_worksheet);
+ my $totaltime = int((time - $starttime) / $count * $sheet->{'maxrow'});
+ my $timeleft = int((time - $starttime) / $count * ($sheet->{'maxrow'} - $count));
if ($count % 5 == 0) {
- $r->print($count.' students completed
');
+ $r->print($count.' students completed.'.
+ ' Time remaining: '.$timeleft.' sec. '.
+ ' Estimated total time: '.$totaltime." sec
\n");
$r->rflush();
}
+ if(defined($c) && ($c->aborted())) {
+ last;
+ }
}
#
- $r->print('All students spreadsheets completed
');
- $r->rflush();
- #
- # &export_sheet_as_excel fills $worksheet with the data from $sheet
- &export_sheet_as_excel($sheet,$main_worksheet);
- #
- $workbook->close();
- # Okay, the spreadsheet is taken care of, so give the user a link.
- $r->print('
'.
- 'Your Excel spreadsheet.'."\n");
+ if(! $c->aborted() ) {
+ $r->print('All students spreadsheets completed!
');
+ $r->rflush();
+ #
+ # &export_sheet_as_excel fills $worksheet with the data from $sheet
+ &export_sheet_as_excel($sheet,$main_worksheet);
+ #
+ $workbook->close();
+ # Okay, the spreadsheet is taken care of, so give the user a link.
+ $r->print('
'.
+ 'Your Excel spreadsheet.'."\n");
+ } else {
+ $workbook->close(); # Not sure how necessary this is.
+ #unlink('/home/httpd'.$filename); # No need to keep this around?
+ }
return 1;
}
@@ -1482,7 +1615,6 @@ sub create_excel_spreadsheet {
my $filename = '/prtspool/'.
$ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
time.'_'.rand(1000000000).'.xls';
- #&Apache::lonnet::logthis("spreadsheet:filename = ".$filename);
my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
if (! defined($workbook)) {
$r->log_error("Error creating excel spreadsheet $filename: $!");
@@ -1505,24 +1637,57 @@ sub create_excel_spreadsheet {
sub export_sheet_as_excel {
my $sheet = shift;
my $worksheet = shift;
+ #
+ my $rows_output = 0;
+ my $cols_output = 0;
+ ####################################
+ # Write an identifying row #
+ ####################################
+ my @Headerinfo = ($sheet->{'coursedesc'});
+ my $title = &gettitle($sheet);
+ $cols_output = 0;
+ if (defined($title)) {
+ $worksheet->write($rows_output++,$cols_output++,$title);
+ }
+ ####################################
+ # Write the summary/export row #
+ ####################################
+ my ($rowlabel,@rowdata) = &get_row($sheet,'0');
+ my $label = &format_excel_rowlabel($sheet,$rowlabel);
+ $cols_output = 0;
+ $worksheet->write($rows_output,$cols_output++,$label);
+ foreach my $cell (@rowdata) {
+ $worksheet->write($rows_output,$cols_output++,$cell->{'value'});
+ }
+ $rows_output+= 2; # Skip a row, just for fun
####################################
# Prepare to output rows
####################################
my @Rows = &sort_indicies($sheet);
#
# Loop through the rows and output them one at a time
- my $rows_output=0;
foreach my $rownum (@Rows) {
my ($rowlabel,@rowdata) = &get_row($sheet,$rownum);
- my $cols_output = 0;
- my $label = &format_excel_rowlabel($rowlabel);
+ next if ($rowlabel =~ /^[\s]*$/);
+ $cols_output = 0;
+ my $label = &format_excel_rowlabel($sheet,$rowlabel);
+ if ( ! $ENV{'form.showall'} &&
+ $sheet->{'sheettype'} =~ /^(studentcalc|classcalc)$/) {
+ my $row_is_empty = 1;
+ foreach my $cell (@rowdata) {
+ if ($cell->{'value'} !~ /^\s*$/) {
+ $row_is_empty = 0;
+ last;
+ }
+ }
+ next if ($row_is_empty);
+ }
$worksheet->write($rows_output,$cols_output++,$label);
if (ref($label)) {
$cols_output = (scalar(@$label));
}
foreach my $cell (@rowdata) {
- $worksheet->write($rows_output,$cols_output++,
- $cell->{'value'});
+ $worksheet->write($rows_output,$cols_output++,$cell->{'value'});
}
$rows_output++;
}
@@ -1543,7 +1708,7 @@ sub outsheet_xml {
## Outsheet - calls other outsheet_* functions
##
sub outsheet {
- my ($r,$sheet)=@_;
+ my ($sheet,$r)=@_;
if (! exists($ENV{'form.output'})) {
$ENV{'form.output'} = 'HTML';
}
@@ -1655,7 +1820,8 @@ sub readsheet {
if ($fh=Apache::File->new($includedir.'/'.$dfn)) {
$sheetxml=join('',<$fh>);
} else {
- $sheetxml='
timestamp',
@@ -2066,29 +2316,16 @@ sub updatestudentassesssheet {
'parameter:Number of Tutor Responses
tutornumber',
'totalpoints' =>
'parameter:Total Points Granted
totalpoints');
- #
- # assesslist holds the descriptions of all assessments
- my %assesslist;
- foreach ('Feedback','Evaluation','Tutoring','Discussion') {
- my $symb = '_'.lc($_);
- $assesslist{$symb} = join(':',('symb',$symb,$uname,$udom,$_));
- }
- while (($_,undef) = each(%bighash)) {
- next if ($_!~/^src\_(\d+)\.(\d+)$/);
- my $mapid=$1;
- my $resid=$2;
- my $id=$mapid.'.'.$resid;
- my $srcf=$bighash{$_};
+ while (my ($key,$srcf) = each(%course_db)) {
+ next if ($key !~ /^src_(\d+)\.(\d+)$/);
+ my $mapid = $1;
+ my $resid = $2;
+ my $id = $mapid.'.'.$resid;
if ($srcf=~/\.(problem|exam|quiz|assess|survey|form)$/) {
- my $symb=
- &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}).
- '___'.$resid.'___'.&Apache::lonnet::declutter($srcf);
- $assesslist{$symb}='symb:'.&Apache::lonnet::escape($symb).':'
- .$uname.':'.$udom.':'.$bighash{'title_'.$id};
- next if ($stype ne 'assesscalc');
- foreach my $key (split(/\,/,
- &Apache::lonnet::metadata($srcf,'keys')
- )) {
+ # Loop through the metadata for this key
+ my @Metadata = split(/,/,
+ &Apache::lonnet::metadata($srcf,'keys'));
+ foreach my $key (@Metadata) {
next if ($key !~ /^(stores|parameter)_/);
my $display=
&Apache::lonnet::metadata($srcf,$key.'.display');
@@ -2100,46 +2337,40 @@ sub updatestudentassesssheet {
$parameter_labels{$key}='parameter:'.$display;
} # end of foreach
}
- } # end of foreach (keys(%bighash))
- untie(%bighash);
- #
- # %parameter_labels has a list of storage and parameter displays by
- # unikey
- # %assesslist has a list of all resource, by symb
- #
- if ($stype eq 'assesscalc') {
- $sheet->{'rowlabel'} = \%parameter_labels;
- } elsif ($stype eq 'studentcalc') {
- $sheet->{'rowlabel'} = \%assesslist;
- }
- $updatedata{$sheet->{'coursefilename'}.'_'.$stype.'_'
- .$uname.'_'.$udom}=
- join('___;___',%{$sheet->{'rowlabel'}});
- # Get current from cache
+ }
+ untie(%course_db);
+ # Store away the results
+ $sheet->{'rowlabel'} = \%parameter_labels;
+ $rowlabel_cache{$identifier}=join('___;___',%{$sheet->{'rowlabel'}});
}
- # Find discrepancies between the course row table and this
- #
+
+}
+
+sub updatestudentassesssheet {
+ my $sheet = shift;
+ if ($sheet->{'sheettype'} eq 'studentcalc') {
+ &get_student_rowlabels($sheet);
+ } else {
+ &get_assess_rowlabels($sheet);
+ }
+ # Determine if any of the information has changed
my %f=&getformulas($sheet);
my $changed=0;
$sheet->{'maxrow'} = 0;
my %existing=();
# Now obsolete rows
- foreach (keys(%f)) {
- next if ($_!~/^A(\d+)/);
- if ($1 > $sheet->{'maxrow'}) {
- $sheet->{'maxrow'} = $1;
- }
- my ($usy,$ufn)=split(/__&&&\__/,$f{$_});
+ foreach my $cell (keys(%f)) {
+ my $formula = $f{$cell};
+ next if ($cell !~ /^A(\d+)/);
+ $sheet->{'maxrow'} = $1 if ($1 > $sheet->{'maxrow'});
+ my ($usy,$ufn)=split(/__&&&\__/,$formula);
$existing{$usy}=1;
unless ((exists($sheet->{'rowlabel'}->{$usy}) &&
(defined($sheet->{'rowlabel'}->{$usy})) || (!$1) ||
- ($f{$_}=~/^(~~~|---)/))){
+ ($formula =~ /^(~~~|---)/) )) {
$f{$_}='!!! Obsolete';
$changed=1;
- } elsif ($ufn) {
- $sheet->{'rowlabel'}->{$usy}
- =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/;
}
}
# New and unknown keys
@@ -2154,16 +2385,14 @@ sub updatestudentassesssheet {
$sheet->{'f'} = \%f;
&setformulas($sheet);
}
- #
- undef %existing;
}
# ------------------------------------------------ Load data for one assessment
sub loadstudent{
- my ($sheet)=@_;
- my %c=();
- my %f=&getformulas($sheet);
+ my ($sheet,$r,$c)=@_;
+ my %constants=();
+ my %formulas=&getformulas($sheet);
$cachedassess=$sheet->{'uname'}.':'.$sheet->{'udom'};
# Get ALL the student preformance data
my @tmp = &Apache::lonnet::dump($sheet->{'cid'},
@@ -2176,50 +2405,51 @@ sub loadstudent{
undef @tmp;
#
my @assessdata=();
- foreach (keys(%f)) {
- next if ($_!~/^A(\d+)/);
+ foreach my $cell (keys(%formulas)) {
+ my $value = $formulas{$cell};
+ if(defined($c) && ($c->aborted())) {
+ last;
+ }
+ next if ($cell !~ /^A(\d+)/);
my $row=$1;
- next if (($f{$_}=~/^[\!\~\-]/) || ($row==0));
- my ($usy,$ufn)=split(/__&&&\__/,$f{$_});
+ next if (($value =~ /^[!~-]/) || ($row==0));
+ my ($usy,$ufn)=split(/__&&&\__/,$value);
@assessdata=&exportsheet($sheet,$sheet->{'uname'},
$sheet->{'udom'},
- 'assesscalc',$usy,$ufn);
+ 'assesscalc',$usy,$ufn,$r);
my $index=0;
- foreach ('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') {
- if ($assessdata[$index]) {
- my $col=$_;
+ foreach my $col ('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') {
+ if (defined($assessdata[$index])) {
if ($assessdata[$index]=~/\D/) {
- $c{$col.$row}="'".$assessdata[$index]."'";
+ $constants{$col.$row}="'".$assessdata[$index]."'";
} else {
- $c{$col.$row}=$assessdata[$index];
- }
- unless ($col eq 'A') {
- $f{$col.$row}='import';
+ $constants{$col.$row}=$assessdata[$index];
}
+ $formulas{$col.$row}='import' if ($col ne 'A');
}
$index++;
}
}
$cachedassess='';
undef %cachedstores;
- $sheet->{'f'} = \%f;
+ $sheet->{'f'} = \%formulas;
&setformulas($sheet);
- &setconstants($sheet,\%c);
+ &setconstants($sheet,\%constants);
}
# --------------------------------------------------- Load data for one student
#
sub loadcourse {
- my ($sheet,$r)=@_;
+ my ($sheet,$r,$c)=@_;
#
- my %c=();
- my %f=&getformulas($sheet);
+ my %constants=();
+ my %formulas=&getformulas($sheet);
#
my $total=0;
- foreach (keys(%f)) {
+ foreach (keys(%formulas)) {
if ($_=~/^A(\d+)/) {
- unless ($f{$_}=~/^[\!\~\-]/) { $total++; }
+ unless ($formulas{$_}=~/^[\!\~\-]/) { $total++; }
}
}
my $now=0;
@@ -2236,12 +2466,16 @@ sub loadcourse {
ENDPOP
$r->rflush();
- foreach (keys(%f)) {
+ foreach (keys(%formulas)) {
+ if(defined($c) && ($c->aborted())) {
+ last;
+ }
next if ($_!~/^A(\d+)/);
my $row=$1;
- next if (($f{$_}=~/^[\!\~\-]/) || ($row==0));
- my ($sname,$sdom) = split(':',$f{$_});
- my @studentdata=&exportsheet($sheet,$sname,$sdom,'studentcalc');
+ next if (($formulas{$_}=~/^[\!\~\-]/) || ($row==0));
+ my ($sname,$sdom) = split(':',$formulas{$_});
+ my @studentdata=&exportsheet($sheet,$sname,$sdom,'studentcalc',
+ undef,undef,$r);
undef %userrdatas;
$now++;
$r->print('');
$r->rflush();
}
@@ -2276,7 +2510,7 @@ ENDPOP
# ------------------------------------------------ Load data for one assessment
#
sub loadassessment {
- my ($sheet)=@_;
+ my ($sheet,$r,$c)=@_;
my $uhome = $sheet->{'uhome'};
my $uname = $sheet->{'uname'};
@@ -2426,8 +2660,7 @@ sub selectbox {
sub updatesheet {
my ($sheet)=@_;
- my $stype=$sheet->{'sheettype'};
- if ($stype eq 'classcalc') {
+ if ($sheet->{'sheettype'} eq 'classcalc') {
return &updateclasssheet($sheet);
} else {
return &updatestudentassesssheet($sheet);
@@ -2441,13 +2674,14 @@ sub updatesheet {
sub loadrows {
my ($sheet,$r)=@_;
+ my $c = $r->connection;
my $stype=$sheet->{'sheettype'};
if ($stype eq 'classcalc') {
- &loadcourse($sheet,$r);
+ &loadcourse($sheet,$r,$c);
} elsif ($stype eq 'studentcalc') {
- &loadstudent($sheet);
+ &loadstudent($sheet,$r,$c);
} else {
- &loadassessment($sheet);
+ &loadassessment($sheet,$r,$c);
}
}
@@ -2455,7 +2689,11 @@ sub loadrows {
sub checkthis {
my ($keyname,$time)=@_;
- return ($time<$expiredates{$keyname});
+ if (! exists($expiredates{$keyname})) {
+ return 0;
+ } else {
+ return ($time<$expiredates{$keyname});
+ }
}
sub forcedrecalc {
@@ -2473,7 +2711,7 @@ sub forcedrecalc {
&checkthis($uname.':'.$udom.':assesscalc:'.$map,$time) ||
&checkthis($uname.':'.$udom.':assesscalc:'.$usymb,$time)) {
return 1;
- }
+ }
} else {
if (&checkthis('::studentcalc:',$time) ||
&checkthis($uname.':'.$udom.':studentcalc:',$time)) {
@@ -2488,11 +2726,13 @@ sub forcedrecalc {
# returns the export row for a spreadsheet.
#
sub exportsheet {
- my ($sheet,$uname,$udom,$stype,$usymb,$fn)=@_;
+ my ($sheet,$uname,$udom,$stype,$usymb,$fn,$r)=@_;
+ my $flag = 0;
$uname = $uname || $sheet->{'uname'};
$udom = $udom || $sheet->{'udom'};
$stype = $stype || $sheet->{'sheettype'};
my @exportarr=();
+ # This handles the assessment sheets for '_feedback', etc
if (defined($usymb) && ($usymb=~/^\_(\w+)/) &&
(!defined($fn) || $fn eq '')) {
$fn='default_'.$1;
@@ -2542,7 +2782,7 @@ sub exportsheet {
my ($newsheet)=&makenewsheet($uname,$udom,$stype,$usymb);
&readsheet($newsheet,$fn);
&updatesheet($newsheet);
- &loadrows($newsheet);
+ &loadrows($newsheet,$r);
&calcsheet($newsheet);
@exportarr=&exportdata($newsheet);
##
@@ -2557,14 +2797,24 @@ sub exportsheet {
[$key],
$sheet->{'cdom'},$sheet->{'cnum'});
if ($tmp[0]!~/^error/) {
- %currentlystored = @tmp;
+ # We only got one key, so we will access it directly.
+ foreach (split('___&___',$tmp[1])) {
+ my ($key,$value) = split('___=___',$_);
+ $key = '' if (! defined($key));
+ $currentlystored{$key} = $value;
+ }
}
} else {
my @tmp = &Apache::lonnet::get('nohist_calculatedsheets_'.
$sheet->{'cid'},[$key],
$sheet->{'udom'},$sheet->{'uname'});
if ($tmp[0]!~/^error/) {
- %currentlystored = @tmp;
+ # We only got one key, so we will access it directly.
+ foreach (split('___&___',$tmp[1])) {
+ my ($key,$value) = split('___=___',$_);
+ $key = '' if (! defined($key));
+ $currentlystored{$key} = $value;
+ }
}
}
#
@@ -2583,17 +2833,19 @@ sub exportsheet {
#
# Store away the new value
#
+ my $timekey = $key.'.time';
if ($stype eq 'studentcalc') {
- &Apache::lonnet::put('nohist_calculatedsheets',
- { $key => $newstore,
- $key.time => $now },
- $sheet->{'cdom'},$sheet->{'cnum'});
- } else {
- &Apache::lonnet::put('nohist_calculatedsheets_'.$sheet->{'cid'},
- { $key => $newstore,
- $key.time => $now },
- $sheet->{'udom'},
- $sheet->{'uname'})
+ my $result = &Apache::lonnet::put('nohist_calculatedsheets',
+ { $key => $newstore,
+ $timekey => $now },
+ $sheet->{'cdom'},
+ $sheet->{'cnum'});
+ } else {
+ my $result = &Apache::lonnet::put('nohist_calculatedsheets_'.$sheet->{'cid'},
+ { $key => $newstore,
+ $timekey => $now },
+ $sheet->{'udom'},
+ $sheet->{'uname'});
}
return @exportarr;
}
@@ -2602,13 +2854,13 @@ sub exportsheet {
#
# Load previously cached student spreadsheets for this course
#
-sub expirationdates {
+sub load_spreadsheet_expirationdates {
undef %expiredates;
my $cid=$ENV{'request.course.id'};
my @tmp = &Apache::lonnet::dump('nohist_expirationdates',
$ENV{'course.'.$cid.'.domain'},
$ENV{'course.'.$cid.'.num'});
- if (lc($tmp[0])!~/^error/){
+ if (lc($tmp[0]) !~ /^error/){
%expiredates = @tmp;
}
}
@@ -2640,18 +2892,21 @@ sub cachedssheets {
my ($sheet,$uname,$udom) = @_;
$uname = $uname || $sheet->{'uname'};
$udom = $udom || $sheet->{'udom'};
- if (! $loadedcaches{$sheet->{'uname'}.'_'.$sheet->{'udom'}}) {
+ if (! $loadedcaches{$uname.'_'.$udom}) {
my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets',
$sheet->{'udom'},
$sheet->{'uname'});
if ($tmp[0] !~ /^error/) {
- my %StupidTempHash = @tmp;
- while (my ($key,$value) = each %StupidTempHash) {
+ my %TempHash = @tmp;
+ my $count = 0;
+ while (my ($key,$value) = each %TempHash) {
$oldsheets{$key} = $value;
+ $count++;
}
$loadedcaches{$sheet->{'uname'}.'_'.$sheet->{'udom'}}=1;
}
}
+
}
# ===================================================== Calculated sheets cache
@@ -2677,6 +2932,9 @@ sub handler {
lc($ENV{'form.output'}) eq 'recursive excel')) {
$ENV{'form.output'} = 'HTML';
}
+ #
+ # Overload checking
+ #
# Check this server
my $loaderror=&Apache::lonnet::overloaderror($r);
if ($loaderror) { return $loaderror; }
@@ -2684,15 +2942,22 @@ sub handler {
$loaderror= &Apache::lonnet::overloaderror($r,
$ENV{'course.'.$ENV{'request.course.id'}.'.home'});
if ($loaderror) { return $loaderror; }
-
+ #
+ # HTML Header
+ #
if ($r->header_only) {
$r->content_type('text/html');
$r->send_http_header;
return OK;
}
+ #
# Global directory configs
+ #
$includedir = $r->dir_config('lonIncludes');
$tmpdir = $r->dir_config('lonDaemons').'/tmp/';
+ #
+ # Roles Checking
+ #
# Needs to be in a course
if (! $ENV{'request.course.fn'}) {
# Not in a course, or not allowed to modify parms
@@ -2700,17 +2965,32 @@ sub handler {
$r->uri.":opa:0:0:Cannot modify spreadsheet";
return HTTP_NOT_ACCEPTABLE;
}
+ #
# Get query string for limited number of parameters
- &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['uname','udom','usymb','ufn']);
+ #
+ &Apache::loncommon::get_unprocessed_cgi
+ ($ENV{'QUERY_STRING'},['uname','udom','usymb','ufn','mapid','resid']);
+ #
+ # Deal with restricted student permissions
+ #
if ($ENV{'request.role'} =~ /^st\./) {
delete $ENV{'form.unewfield'} if (exists($ENV{'form.unewfield'}));
delete $ENV{'form.unewformula'} if (exists($ENV{'form.unewformula'}));
}
- if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {
+ #
+ # Look for special assessment spreadsheets - '_feedback', etc.
+ #
+ if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'} ||
+ $ENV{'form.ufn'} eq '' ||
+ $ENV{'form.ufn'} eq 'default')) {
$ENV{'form.ufn'}='default_'.$1;
}
+ if (!$ENV{'form.ufn'} || $ENV{'form.ufn'} eq 'default') {
+ $ENV{'form.ufn'}='course_default_'.$sheettype;
+ }
+ #
# Interactive loading of specific sheet?
+ #
if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {
$ENV{'form.ufn'}=$ENV{'form.loadthissheet'};
}
@@ -2726,24 +3006,57 @@ sub handler {
$adom=$ENV{'form.udom'};
}
#
- # Open page
+ # Open page, try to prevent browser cache.
+ #
$r->content_type('text/html');
$r->header_out('Cache-control','no-cache');
$r->header_out('Pragma','no-cache');
$r->send_http_header;
- # Screen output
+ #
+ # Header....
+ #
$r->print('