--- loncom/interface/spreadsheet/assesscalc.pm 2003/12/05 22:24:20 1.17.2.3 +++ loncom/interface/spreadsheet/assesscalc.pm 2003/10/14 18:36:54 1.26 @@ -1,5 +1,5 @@ # -# $Id: assesscalc.pm,v 1.17.2.3 2003/12/05 22:24:20 matthew Exp $ +# $Id: assesscalc.pm,v 1.26 2003/10/14 18:36:54 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -44,6 +44,8 @@ assesscalc package Apache::assesscalc; use strict; +use warnings FATAL=>'all'; +no warnings 'uninitialized'; use Apache::Constants qw(:common :http); use Apache::lonnet; use Apache::loncommon; @@ -53,6 +55,7 @@ use HTML::Entities(); use Spreadsheet::WriteExcel; use GDBM_File; use Time::HiRes; +use Apache::lonlocal; @Apache::assesscalc::ISA = ('Apache::Spreadsheet'); @@ -89,6 +92,7 @@ use Time::HiRes; ######################################################## my %Exportrows; +my %newExportrows; my $current_name; my $current_domain; @@ -98,6 +102,7 @@ my %parmhash; my %nice_parameter_name; my %useropt; +my %userdata; my %courseopt; ######################################################## @@ -109,21 +114,40 @@ my %courseopt; =item &clear_package() -Reset all package variables. +Reset all package variables and clean up caches. =cut ######################################################## ######################################################## sub clear_package { + if (defined($current_name) && + defined($current_domain) && + defined($current_course) && + $current_course eq $ENV{'request.course.id'} && + %newExportrows) { + &save_cached_export_rows($current_name,$current_domain); + } undef(%Exportrows); + undef(%newExportrows); undef($current_name); undef($current_domain); undef($current_course); undef(%useropt); + undef(%userdata); undef(%courseopt); } +sub save_cached_export_rows { + my ($sname,$sdomain) = @_; + my $start = Time::HiRes::time; + my $result = &Apache::lonnet::put + ('nohist_calculatedsheets_'.$ENV{'request.course.id'}, + $newExportrows{$sname.':'.$sdomain}, + $sdomain,$sname); + delete($newExportrows{$sname.':'.$sdomain}); +} + sub initialize { &clear_package(); &Apache::loncoursedata::clear_internal_caches(); @@ -144,6 +168,8 @@ sub initialize_package { my ($sname,$sdomain) = @_; $current_name = $sname; $current_domain = $sdomain; + undef(%useropt); + undef(%userdata); if ($current_course ne $ENV{'request.course.id'}) { $current_course = $ENV{'request.course.id'}; undef(%courseopt); @@ -153,6 +179,7 @@ sub initialize_package { &Apache::loncoursedata::clear_internal_caches(); } + ######################################################## ######################################################## @@ -170,11 +197,9 @@ sub load_parameter_caches { # # Course Parameters Cache if (! %courseopt) { - &Apache::lonnet::logthis("loading course options"); $current_course = $ENV{'request.course.id'}; undef(%courseopt); if (! defined($current_name) || ! defined($current_domain)) { - &Apache::lonnet::logthis('bad call to setup_parameter_caches'); return; } my $dom = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}; @@ -194,7 +219,14 @@ sub load_parameter_caches { } $useropt{$userprefix.$name}=$value; } + $useropt{'loadtime'} = time; + } + if (! %userdata) { + %userdata = &Apache::loncoursedata::get_current_state($current_name, + $current_domain); + $userdata{'loadtime'} = time; } + return; } ######################################################## @@ -208,18 +240,27 @@ sub load_parameter_caches { ######################################################## ######################################################## -sub ensure_current_parameter_caches { +sub ensure_current_caches { my $self = shift; + ## + ## Check for a modified parameters + ## if (! defined($current_course) || $current_course ne $ENV{'request.course.id'} ) { $current_course = $ENV{'request.course.id'}; undef(%courseopt); + undef(%useropt); + undef(%userdata); } + ## + ## Check for new user + ## if (! defined($current_name) || $current_name ne $self->{'name'} || ! defined($current_domain) || $current_domain ne $self->{'domain'}) { $current_domain = $self->{'domain'}; $current_name = $self->{'name'}; undef(%useropt); + undef(%userdata); } &load_parameter_caches(); } @@ -259,7 +300,7 @@ sub parmval { my $result=''; # # This should be a - my ($mapname,$id,$fn)=split(/___/,$symb); + my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb); # Cascading lookup scheme my $rwhat=$what; $what =~ s/^parameter\_//; @@ -358,7 +399,7 @@ sub get_title { join(' ',@userenv{'firstname','middlename','lastname','generation'}); $name =~ s/\s+$//; push (@title,$name); - push (@title,scalar(localtime(time))); + push (@title,&Apache::lonlocal::locallocaltime(time)); return @title; } @@ -367,17 +408,13 @@ sub parent_link { my $link .= '

'. - 'Student level sheet

'."\n"; + &mt('Student level sheet').'

'."\n"; return $link; } sub outsheet_html { my $self = shift; my ($r) = @_; - #################################### - # Report any calculation errors # - #################################### - $r->print($self->html_report_error()); ################################### # Determine table structure ################################### @@ -385,13 +422,17 @@ sub outsheet_html { my $exportcolor = '#FFFFAA'; my $num_uneditable = 1; my $num_left = 52-$num_uneditable; + my %lt=&Apache::lonlocal::texthash( + 'as' => 'Assessment', + 'ca' => 'Calculations', + ); my $tableheader =<<"END"; - + + $lt{'ca'} END my $label_num = 0; @@ -481,7 +522,7 @@ sub csv_rows { # # Write a header row $self->csv_output_row($filehandle,undef, - ('Parameter','Description','Value')); + (&mt('Parameter'),&mt('Description'),&mt('Value'))); # # Write each row foreach my $rownum (sort {$a <=> $b} ($self->rows())) { @@ -505,7 +546,7 @@ sub excel_rows { # Write a header row $cols_output = 0; foreach my $value ('Parameter','Description','Value') { - $worksheet->write($rows_output,$cols_output++,$value); + $worksheet->write($rows_output,$cols_output++,&mt($value)); } $rows_output++; # @@ -522,9 +563,85 @@ sub excel_rows { return; } +## +## Routines to support assesscalc::compute +## +sub get_parm_names { + my $self = shift; + my @Mandatory_parameters = @_; + my %parameters_and_names; + # + my ($symap,$syid,$srcf) = &Apache::lonnet::decode_symb($self->{'symb'}); + my @Metadata = split(/\,/,&Apache::lonnet::metadata($srcf,'keys')); + foreach my $parm (@Mandatory_parameters,@Metadata) { + next if ($parm !~ /^(resource\.|stores|parameter)_/); + my $cleaned_name = $parm; + $cleaned_name =~ s/^resource\./stores_/; + $cleaned_name =~ s/\./_/g; + my $display = &Apache::lonnet::metadata($srcf, + $cleaned_name.'.display'); + if (! $display) { + $display .= &Apache::lonnet::metadata($srcf,$cleaned_name.'.name'); + } + $parameters_and_names{$cleaned_name}=$display; + } + return (%parameters_and_names); +} + +sub get_parameter_values { + my $self = shift(); + my @Parameters; + my ($parameters) = @_; + if (!ref($parameters)) { + @Parameters = @_; + } elsif (ref($parameters) eq 'ARRAY') { + @Parameters = @$parameters; + } elsif (ref($parameters) eq 'HASH') { + @Parameters = keys(%$parameters); + } + # + my %parameters; + # + my $filename = $self->{'coursefilename'}.'_parms.db'; + if (tie(%parmhash,'GDBM_File', + $self->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) { + foreach my $parmname (@Parameters) { + my $value = $self->parmval($parmname); + $parameters{$parmname} =$value; + } + untie(%parmhash); + } else { + $self->logthis('unable to tie '.$filename); + } + return %parameters; +} + +sub deal_with_export_row { + my $self = shift(); + my @exportarray = @_; + $Exportrows{$self->{'symb'}}->{'time'} = time; + $Exportrows{$self->{'symb'}}->{$self->{'filename'}} = \@exportarray; + # + # Save the export data + $self->save_export_data(); + return; +} + +sub get_problem_state { + my $self = shift; + my %student_parameters; + if (exists($userdata{$self->{'symb'}}) && + ref($userdata{$self->{'symb'}}) eq 'HASH') { + %student_parameters = %{$userdata{$self->{'symb'}}}; + } + return %student_parameters; +} + sub compute { my $self = shift; -# $self->logthis('computing'); + my ($r) = @_; + my $connection = $r->connection(); + if ($connection->aborted()) { $self->cleanup(); return; } $self->initialize_safe_space(); ######################################### ######################################### @@ -545,35 +662,18 @@ sub compute { my %parameters; # holds underscored parameters by name # # Get the metadata fields and determine their proper names - my ($symap,$syid,$srcf)=split(/___/,$self->{'symb'}); - my @Metadata = split(/\,/,&Apache::lonnet::metadata($srcf,'keys')); - foreach my $parm (@Mandatory_parameters,@Metadata) { - next if ($parm !~ /^(resource\.|stores|parameter)_/); - my $cleaned_name = $parm; - $cleaned_name =~ s/^resource\./stores_/; - $cleaned_name =~ s/\./_/g; - my $display = &Apache::lonnet::metadata($srcf, - $cleaned_name.'.display'); - if (! $display) { - $display .= &Apache::lonnet::metadata($srcf,$cleaned_name.'.name'); - } + my %nice_parm_names = $self->get_parm_names(@Mandatory_parameters); + while (my($cleaned_name,$display) = each(%nice_parm_names)) { $parameters{$cleaned_name}++; $nice_parameter_name{$cleaned_name} = $display; } # # Get the values of the metadata fields - $self->ensure_current_parameter_caches(); - my $filename = $self->{'coursefilename'}.'_parms.db'; - if (tie(%parmhash,'GDBM_File', - $self->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) { - foreach my $parmname (keys(%parameters)) { - my $value = $self->parmval($parmname); - $parameters{$parmname} =$value; - } - untie(%parmhash); - } else { - $self->logthis('unable to tie '.$filename); - } + if ($connection->aborted()) { $self->cleanup(); return; } + $self->ensure_current_caches(); + if ($connection->aborted()) { $self->cleanup(); return; } + %parameters = $self->get_parameter_values(keys(%parameters)); + if ($connection->aborted()) { $self->cleanup(); return; } # # Clean out unnecessary parameters foreach (keys(%parameters)) { @@ -581,11 +681,7 @@ sub compute { } # # Get the students performance data - my %student_parameters = - &Apache::loncoursedata::get_current_state($self->{'name'}, - $self->{'domain'}, - $self->{'symb'}, - $self->{'cid'}); + my %student_parameters = $self->get_problem_state(); while (my ($parm,$value) = each(%student_parameters)) { $parm =~ s/^resource\./stores_/; $parm =~ s/\./_/g; @@ -601,18 +697,20 @@ sub compute { while (my ($parm,$value) = each(%parameters)) { last if ($self->blackout()); next if ($parm !~ /^(parameter_.*)_problemstatus$/); - if ($parameters{$1.'_answerdate'} ne '' && - $parameters{$1.'_answerdate'} < time) { - next; - } + if ($parameters{$1.'_answerdate'} ne '' && + $parameters{$1.'_answerdate'} < time) { + next; + } if (lc($value) eq 'no') { # We must blackout this sheet $self->blackout(1); } } } + if ($connection->aborted()) { $self->cleanup(); return; } # # Move the parameters into the spreadsheet + if ($connection->aborted()) { $self->cleanup(); return; } while (my ($parm,$value) = each(%parameters)) { my $cell = 'A'.$self->get_row_number_from_key($parm); $f{$cell} = $parm; @@ -621,16 +719,14 @@ sub compute { } $self->formulas(\%f); $self->constants(\%c); + if ($connection->aborted()) { $self->cleanup(); return; } $self->calcsheet(); # # Store export row in cache my @exportarray = $self->exportrow(); - $Exportrows{$self->{'symb'}}->{'time'} = time; - $Exportrows{$self->{'symb'}}->{$self->{'filename'}} = \@exportarray; - # - # Save the export data - $self->save_export_data(); + $self->deal_with_export_row(@exportarray); $self->save() if ($self->need_to_save()); + if ($connection->aborted()) { $self->cleanup(); return; } return; } @@ -699,7 +795,7 @@ These rows are saved in the students dir ######################################################## ######################################################## sub load_cached_export_rows { - %Exportrows = undef; + undef(%Exportrows); my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets_'. $ENV{'request.course.id'}, $current_domain,$current_name,undef); @@ -740,28 +836,26 @@ spreadsheet only if necessary. ############################################# sub export_data { my $self = shift; + my ($r) = @_; + my $connection = $r->connection(); my $symb = $self->{'symb'}; if (! exists($ENV{'request.role.adv'}) || ! $ENV{'request.role.adv'} || ! exists($Exportrows{$symb}) || ! defined($Exportrows{$symb}) || ! $self->check_expiration_time($Exportrows{$symb}->{'time'}) || ! exists($Exportrows{$symb}->{$self->{'filename'}}) || - ! defined($Exportrows{$symb}->{$self->{'filename'}})) { - $self->compute(); + ! defined($Exportrows{$symb}->{$self->{'filename'}}) || + ! ref($Exportrows{$symb}->{$self->{'filename'}}) + ) { + $self->compute($r); + } + if ($connection->aborted()) { $self->cleanup(); return; } + my @Data = @{$Exportrows{$symb}->{$self->{'filename'}}}; + if ($Data[0] =~ /^(.*)___=___/) { + $self->{'sheetname'} = $1; + $Data[0] =~ s/^(.*)___=___//; } - my @Data; - if ($self->badcalc()) { - @Data = (); - } else { - @Data = @{$Exportrows{$symb}->{$self->{'filename'}}}; - if ($Data[0] =~ /^(.*)___=___/) { - $self->{'sheetname'} = $1; - $Data[0] =~ s/^(.*)___=___//; - } - for (my $i=0;$i<$#Data;$i++) { - if ($Data[$i]=~/\D/ && defined($Data[$i])) { - $Data[$i]="'".$Data[$i]."'"; - } - } + for (my $i=0;$i<$#Data;$i++) { + $Data[$i]="'".$Data[$i]."'" if ($Data[$i]=~/\D/ && defined($Data[$i])); } return @Data; } @@ -784,26 +878,18 @@ sub save_export_data { return if ($self->temporary()); my $student = $self->{'name'}.':'.$self->{'domain'}; my $symb = $self->{'symb'}; - if ($self->badcalc()){ - # do not save data away when calculations have not been done properly. - delete($Exportrows{$symb}); - return; - } if (! exists($Exportrows{$symb}) || ! exists($Exportrows{$symb}->{$self->{'filename'}})) { return; } my $key = join(':',($self->{'name'},$self->{'domain'},'assesscalc',$symb)); my $timekey = $key.'.time'; - my $newstore= join('___;___',@{$Exportrows{$symb}->{$self->{'filename'}}}); + my $newstore= join('___;___', + map {s/[^[:print:]]//g;$_;} # strip out unprintable + @{$Exportrows{$symb}->{$self->{'filename'}}}); $newstore = $self->{'filename'}.'___=___'.$newstore; - my $result = &Apache::lonnet::put - ('nohist_calculatedsheets_'.$ENV{'request.course.id'}, - { $key => $newstore, - $timekey => $Exportrows{$symb}->{'time'} }, - $self->{'domain'}, - $self->{'name'}); - + $newExportrows{$student}->{$key} = $newstore; + $newExportrows{$student}->{$timekey} = $Exportrows{$symb}->{'time'}; return; }
Assessment$lt{'as'}   - Calculations