Diff for /loncom/interface/spreadsheet/assesscalc.pm between versions 1.1 and 1.59

version 1.1, 2003/05/16 20:55:11 version 1.59, 2012/10/12 13:56:38
Line 44  assesscalc Line 44  assesscalc
 package Apache::assesscalc;  package Apache::assesscalc;
   
 use strict;  use strict;
   use warnings FATAL=>'all';
   no warnings 'uninitialized';
 use Apache::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
 use Apache::lonnet;  use Apache::lonnet;
   use Apache::loncommon;
 use Apache::Spreadsheet;  use Apache::Spreadsheet;
   use Apache::loncoursedata();
 use HTML::Entities();  use HTML::Entities();
 use Spreadsheet::WriteExcel;  use Spreadsheet::WriteExcel;
 use GDBM_File;  use GDBM_File;
 use Time::HiRes;  use Time::HiRes;
   use Apache::lonlocal;
   
 @Apache::assesscalc::ISA = ('Apache::Spreadsheet');  @Apache::assesscalc::ISA = ('Apache::Spreadsheet');
   
Line 87  use Time::HiRes; Line 92  use Time::HiRes;
 ########################################################  ########################################################
   
 my %Exportrows;  my %Exportrows;
   my %newExportrows;
   
 my $current_name;  my $current_name;
 my $current_domain;  my $current_domain;
Line 96  my %parmhash; Line 102  my %parmhash;
 my %nice_parameter_name;  my %nice_parameter_name;
   
 my %useropt;  my %useropt;
   my %userdata;
 my %courseopt;  my %courseopt;
   my $navmap;
   
 ########################################################  ########################################################
 ########################################################  ########################################################
Line 107  my %courseopt; Line 115  my %courseopt;
   
 =item &clear_package()  =item &clear_package()
   
 Reset all package variables.    Reset all package variables and clean up caches.
   
 =cut  =cut
   
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub clear_package {  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(%Exportrows);
       undef(%newExportrows);
     undef($current_name);      undef($current_name);
     undef($current_domain);      undef($current_domain);
     undef($current_course);      undef($current_course);
     undef(%useropt);      undef(%useropt);
       undef(%userdata);
     undef(%courseopt);      undef(%courseopt);
       undef($navmap);
   }
   
   sub save_cached_export_rows {
       my ($sname,$sdomain) = @_;
       my $result = &Apache::lonnet::put
           ('nohist_calculatedsheets_'.$env{'request.course.id'},
            $newExportrows{$sname.':'.$sdomain},
            $sdomain,$sname);
       delete($newExportrows{$sname.':'.$sdomain});
   }
   
   sub initialize {
       my ($in_navmap) = @_;
       &clear_package();
       $navmap = $in_navmap;
       if (! defined($navmap)) {
           $navmap = Apache::lonnavmaps::navmap->new();
       }
       if ((!defined($navmap)) || (!ref($navmap))) {
           &Apache::lonnet::logthis('assesscalc:Can not open Coursemap');
       }
       &Apache::loncoursedata::clear_internal_caches();
 }  }
   
 ########################################################  ########################################################
Line 134  sub clear_package { Line 174  sub clear_package {
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub initialize_package {  sub initialize_package {
     my ($sname,$sdomain) = @_;      my ($sname,$sdomain,$in_navmap,$calling_sheet) = @_;
     $current_course = $ENV{'request.course.id'};  
     $current_name   = $sname;      $current_name   = $sname;
     $current_domain = $sdomain;      $current_domain = $sdomain;
     undef(%courseopt);      $navmap = $in_navmap;
       undef(%useropt);
       undef(%userdata);
       if ($current_course ne $env{'request.course.id'}) {
           $current_course = $env{'request.course.id'};
           undef(%courseopt);
       }
     &load_cached_export_rows();      &load_cached_export_rows();
     &load_parameter_caches();      &load_parameter_caches($calling_sheet);
       &Apache::loncoursedata::clear_internal_caches();
 }  }
   
   
 ########################################################  ########################################################
 ########################################################  ########################################################
   
Line 155  sub initialize_package { Line 202  sub initialize_package {
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub load_parameter_caches {  sub load_parameter_caches {
       my ($calling_sheet) = @_;
     my $userprefix = $current_name.':'.$current_domain.'_';      my $userprefix = $current_name.':'.$current_domain.'_';
     $userprefix =~ s/:/_/g;      $userprefix =~ s/:/_/g;
     #      #
     # Course Parameters Cache      # Course Parameters Cache
     if (! %courseopt) {      if (! %courseopt) {
         &Apache::lonnet::logthis("loading course options");          $current_course = $env{'request.course.id'};
         $current_course = $ENV{'request.course.id'};  
         undef(%courseopt);          undef(%courseopt);
         if (! defined($current_name) || ! defined($current_domain)) {          if (! defined($current_name) || ! defined($current_domain)) {
             &Apache::lonnet::logthis('bad call to setup_parameter_caches');  
             return;              return;
         }          }
         my $dom = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};          my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $id  = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};          my $id  = $env{'course.'.$env{'request.course.id'}.'.num'};
         my %Tmp = &Apache::lonnet::dump('resourcedata',$dom,$id);          my %Tmp = &Apache::lonnet::dump('resourcedata',$dom,$id);
         while (my ($name,$value) = each(%Tmp)) {          while (my ($name,$value) = each(%Tmp)) {
             $courseopt{$userprefix.$name}=$value;              $courseopt{$name}=$value;
         }          }
     }      }
     if (! %useropt) {      if (! %useropt) {
Line 184  sub load_parameter_caches { Line 230  sub load_parameter_caches {
             }              }
             $useropt{$userprefix.$name}=$value;              $useropt{$userprefix.$name}=$value;
         }          }
           $useropt{'loadtime'} = time;
     }      }
       if (! %userdata) {
           %userdata = &Apache::loncoursedata::get_current_state($current_name,
                                                                 $current_domain);
    my ($tmp) = %userdata;
    if ($tmp =~ /^error:(.*)/) {
       $calling_sheet->set_calcerror($1);
    }
           $userdata{'loadtime'} = time;
       }
       return;
 }  }
   
 ########################################################  ########################################################
Line 198  sub load_parameter_caches { Line 255  sub load_parameter_caches {
   
 ########################################################  ########################################################
 ########################################################  ########################################################
   sub ensure_current_caches {
 sub ensure_current_parameter_caches {  
     my $self = shift;      my $self = shift;
       ##
       ## Check for a modified parameters
       ##
     if (! defined($current_course) ||       if (! defined($current_course) || 
         $current_course ne $ENV{'request.course.id'} ) {          $current_course ne $env{'request.course.id'} ) {
         $current_course = $ENV{'request.course.id'};          $current_course = $env{'request.course.id'};
         undef(%courseopt);           undef(%courseopt); 
           undef(%useropt);
           undef(%userdata);
     }      }
       ##
       ## Check for new user
       ##
     if (! defined($current_name)   || $current_name ne $self->{'name'} ||      if (! defined($current_name)   || $current_name ne $self->{'name'} ||
         ! defined($current_domain) || $current_domain ne $self->{'domain'}) {          ! defined($current_domain) || $current_domain ne $self->{'domain'}) {
         $current_domain = $self->{'domain'};          $current_domain = $self->{'domain'};
         $current_name   = $self->{'name'};          $current_name   = $self->{'name'};
         undef(%useropt);          undef(%useropt);
           undef(%userdata);
     }      }
     &load_parameter_caches();      &load_parameter_caches($self);
 }  }
   
 ##################################################  ##################################################
Line 230  Returns: The value of a parameter, or '' Line 295  Returns: The value of a parameter, or ''
   
 This function cascades through the possible levels searching for a value for  This function cascades through the possible levels searching for a value for
 a parameter.  The levels are checked in the following order:  a parameter.  The levels are checked in the following order:
 user, course (at section level and course level), map, and lonnet::metadata.  user, course (at group, section level and course level), map, and 
   lonnet::metadata.
 This function uses %parmhash, which must be tied prior to calling it.  This function uses %parmhash, which must be tied prior to calling it.
 This function also requires %courseopt and %useropt to be initialized for  This function also requires %courseopt and %useropt to be initialized for
 this user and course.  this user and course.
Line 241  this user and course. Line 307  this user and course.
 ##################################################  ##################################################
 sub parmval {  sub parmval {
     my $self = shift;      my $self = shift;
     my ($what,$symb,$uname,$udom,$csec)=@_;      my ($what,$symb,$uname,$udom,$csec,$recurse,$mapname,$id,$fn,$groups)=@_;
     $uname = $self->{'name'}    if (! defined($uname));      $uname  = $self->{'name'}     if (! defined($uname));
     $udom  = $self->{'domain'}  if (! defined($udom));      $udom   = $self->{'domain'}   if (! defined($udom));
     $csec  = $self->{'section'} if (! defined($csec));      $csec   = $self->{'section'}  if (! defined($csec));
     $symb  = $self->{'symb'}    if (! defined($symb));      $groups = $self->{'groups'}   if (! defined($groups)); 
       $symb   = $self->{'symb'}     if (! defined($symb));
     #      #
     my $result='';      my $result='';
     #      #
     # This should be a       # This should be a 
     my ($mapname,$id,$fn)=split(/___/,$symb);      if (!defined($mapname) || !defined($id) || !defined($fn)) {
    ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);
    $mapname = &Apache::lonnet::deversion($mapname);
       }
     # Cascading lookup scheme      # Cascading lookup scheme
     my $rwhat=$what;      my $rwhat=$what;
     $what =~ s/^parameter\_//;      $what =~ s/^parameter\_//;
Line 258  sub parmval { Line 328  sub parmval {
     #      #
     my $symbparm = $symb.'.'.$what;      my $symbparm = $symb.'.'.$what;
     my $mapparm  = $mapname.'___(all).'.$what;      my $mapparm  = $mapname.'___(all).'.$what;
       my $courseprefix = $self->{'cid'};
     my $usercourseprefix = $uname.'_'.$udom.'_'.$self->{'cid'};      my $usercourseprefix = $uname.'_'.$udom.'_'.$self->{'cid'};
     #      #
     my $seclevel  = $usercourseprefix.'.['.$csec.'].'.$what;      my $seclevel  = $courseprefix.'.['.$csec.'].'.$what;
     my $seclevelr = $usercourseprefix.'.['.$csec.'].'.$symbparm;      my $seclevelr = $courseprefix.'.['.$csec.'].'.$symbparm;
     my $seclevelm = $usercourseprefix.'.['.$csec.'].'.$mapparm;      my $seclevelm = $courseprefix.'.['.$csec.'].'.$mapparm;
     #      #
     my $courselevel  = $usercourseprefix.'.'.$what;      my $courselevel  = $courseprefix.'.'.$what;
     my $courselevelr = $usercourseprefix.'.'.$symbparm;      my $courselevelr = $courseprefix.'.'.$symbparm;
     my $courselevelm = $usercourseprefix.'.'.$mapparm;      my $courselevelm = $courseprefix.'.'.$mapparm;
    # check user      #
       my $ucourselevel  = $usercourseprefix.'.'.$what;
       my $ucourselevelr = $usercourseprefix.'.'.$symbparm;
       my $ucourselevelm = $usercourseprefix.'.'.$mapparm;
       # check user
     if (defined($uname)) {      if (defined($uname)) {
         return $useropt{$courselevelr} if (defined($useropt{$courselevelr}));          return $useropt{$ucourselevelr} if (defined($useropt{$ucourselevelr}));
         return $useropt{$courselevelm} if (defined($useropt{$courselevelm}));          return $useropt{$ucourselevelm} if (defined($useropt{$ucourselevelm}));
         return $useropt{$courselevel}  if (defined($useropt{$courselevel}));          return $useropt{$ucourselevel}  if (defined($useropt{$ucourselevel}));
       }
       # check groups
       if (defined($groups) && ref($groups) eq 'ARRAY') {
           foreach my $group (@{$groups}) {
               foreach my $level ($symbparm,$mapparm,$what) {
                   my $item = $courseprefix.'.['.$group.'].'.$level;
                   if (defined($courseopt{$item})) {
                       return $courseopt{$item};
                   }
               }
           }
     }      }
     # check section      # check section
     if (defined($csec)) {      if (defined($csec)) {
Line 282  sub parmval { Line 368  sub parmval {
     #      #
     # check course      # check course
     return $courseopt{$courselevelr} if (defined($courseopt{$courselevelr}));      return $courseopt{$courselevelr} if (defined($courseopt{$courselevelr}));
     return $courseopt{$courselevelm} if (defined($courseopt{$courselevelm}));  
     return $courseopt{$courselevel}  if (defined($courseopt{$courselevel}));  
     # check map parms      # check map parms
     my $thisparm = $parmhash{$symbparm};      my $thisparm = $parmhash{$symbparm};
     return $thisparm if (defined($thisparm));      return $thisparm if (defined($thisparm));
     # check default      # check default
     $thisparm = &Apache::lonnet::metadata($fn,$rwhat.'.default');      $thisparm = &Apache::lonnet::metadata($fn,$rwhat.'.default');
     return $thisparm if (defined($thisparm));      return $thisparm if (defined($thisparm));
     #      # check more course
       return $courseopt{$courselevelm} if (defined($courseopt{$courselevelm}));
       return $courseopt{$courselevel}  if (defined($courseopt{$courselevel}));
   
     # Cascade Up      # Cascade Up
     my $space=$what;      my $space=$what;
     $space=~s/\.\w+$//;      $space=~s/\.[^._]+$//;
     if ($space ne '0') {      if ($space ne '0') {
  my @parts=split(/_/,$space);   my @parts=split(/_/,$space);
  my $id=pop(@parts);   my $id=pop(@parts);
Line 301  sub parmval { Line 388  sub parmval {
  if ($part eq '') { $part='0'; }   if ($part eq '') { $part='0'; }
  my $newwhat=$rwhat;   my $newwhat=$rwhat;
  $newwhat=~s/\Q$space\E/$part/;   $newwhat=~s/\Q$space\E/$part/;
  my $partgeneral=$self->parmval($newwhat,$symb,$uname,$udom,$csec);   my $partgeneral=$self->parmval($newwhat,$symb,$uname,$udom,$csec,1,
          $mapname,$id,$fn,$groups);
  if (defined($partgeneral)) { return $partgeneral; }   if (defined($partgeneral)) { return $partgeneral; }
     }      }
       if ($recurse) { return undef; }
       my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$what);
       if (defined($pack_def)) { return $pack_def; }
     #nothing defined      #nothing defined
     return '';      return '';
 }  }
   
   sub get_html_title {
       my $self = shift;
       my ($assess_title,$name,$time) = $self->get_full_title();
       my $title = '<h1>'.$assess_title.'</h1>'.
           '<h2>'.$name.', '.
           &Apache::loncommon::aboutmewrapper
                            ($self->{'name'}.'@'.$self->{'domain'},
                             $self->{'name'},$self->{'domain'});
       $title .= '<h3>'.$time.'</h3>';
       return $title;
   }
   
 sub get_title {  sub get_title {
     my $self = shift;      my $self = shift;
     my $title;      if (($self->{'symb'} eq '_feedback') ||
     if (($self->{'usymb'} eq '_feedback') ||          ($self->{'symb'} eq '_evaluation') ||
         ($self->{'usymb'} eq '_evaluation') ||          ($self->{'symb'} eq '_discussion') ||
         ($self->{'usymb'} eq '_discussion') ||          ($self->{'symb'} eq '_tutoring')) {
         ($self->{'usymb'} eq '_tutoring')) {          my $assess_title = ucfirst($self->{'symb'});
         $title = $self->{'usymb'};          $assess_title =~ s/^_//;
         $title =~ s/^_//;          return $assess_title;
         $title = '<h1>'.ucfirst($title)."</h1>\n";  
     } else {      } else {
         $title = '<h1>'.&Apache::lonnet::gettitle($self->{'symb'})."</h1>\n";          return &Apache::lonnet::gettitle($self->{'symb'});
     }      }
     $title .= '<h2>'.$self->{'name'}.'@'.$self->{'domain'}."</h2>\n";  }
     $title .= '<h3>'.localtime(time).'</h3>';  
     #  sub get_full_title {
     return $title;      my $self = shift;
       my @title = ($self->get_title());
       # Look up the users identifying information
       # Get the users information
       my $name = &Apache::loncommon::plainname($self->{'name'},
        $self->{'domain'});
       push (@title,$name);
       push (@title,&Apache::lonlocal::locallocaltime(time));
       return @title;
 }  }
   
 sub parent_link {  sub parent_link {
Line 332  sub parent_link { Line 442  sub parent_link {
     my $link .= '<p><a href="/adm/studentcalc?'.      my $link .= '<p><a href="/adm/studentcalc?'.
         'sname='.$self->{'name'}.          'sname='.$self->{'name'}.
             '&sdomain='.$self->{'domain'}.'">'.              '&sdomain='.$self->{'domain'}.'">'.
                 'Student level sheet</a></p>'."\n";                  &mt('Student level sheet').'</a></p>'."\n";
     return $link;      return $link;
 }  }
   
 sub outsheet_html {  sub outsheet_html {
     my $self = shift;      my $self = shift;
     my ($r) = @_;      my ($r) = @_;
       ####################################
       # Report any calculation errors    #
       ####################################
       $r->print($self->html_report_error());
     ###################################      ###################################
     # Determine table structure      # Determine table structure
     ###################################      ###################################
       my $importcolor = '#FFFFFF';
       my $exportcolor = '#FFFFAA';
     my $num_uneditable = 1;      my $num_uneditable = 1;
     my $num_left = 52-$num_uneditable;      my $num_left = 52-$num_uneditable;
       my %lt=&Apache::lonlocal::texthash(
          'as' => 'Assessment',
          'ca' => 'Calculations',
          );
     my $tableheader =<<"END";      my $tableheader =<<"END";
 <table border="2">  <table border="2">
 <tr>  <tr>
   <th colspan="2" rowspan="2"><font size="+2">Assessment</font></th>    <th colspan="2" rowspan="2"><font size="+2">$lt{'as'}</font></th>
   <td bgcolor="#FFDDDD" colspan="$num_uneditable">&nbsp;</td>    <td bgcolor="$importcolor" colspan="$num_uneditable">&nbsp;</td>
   <td colspan="$num_left">    <td colspan="$num_left">
       <b><font size="+1">Calculations</font></b></td>        <b><font size="+1">$lt{'ca'}</font></b></td>
 </tr><tr>  </tr><tr>
 END  END
     my $label_num = 0;      my $label_num = 0;
     foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){      foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
         if ($label_num<$num_uneditable) {           if ($label_num<$num_uneditable) { 
             $tableheader .= '<td bgcolor="#FFDDDD">';              $tableheader .= '<td bgcolor="'.$importcolor.'">';
         } else {          } else {
             $tableheader .= '<td>';              $tableheader .= '<td>';
         }          }
Line 369  END Line 489  END
     #      #
     # Print out template row      # Print out template row
     $r->print('<tr><td>Template</td><td>&nbsp;</td>'.      $r->print('<tr><td>Template</td><td>&nbsp;</td>'.
       $self->html_template_row($num_uneditable)."</tr>\n");        $self->html_template_row($num_uneditable,$importcolor).
                 "</tr>\n");
     #      #
     # Print out summary/export row      # Print out summary/export row
     $r->print('<tr><td>Export</td><td>0</td>'.      $r->print('<tr><td>Export</td><td>0</td>'.
       $self->html_export_row()."</tr>\n");        $self->html_export_row($exportcolor)."</tr>\n");
     #      #
     # Prepare to output rows      # Prepare to output rows
     $tableheader =<<"END";      $tableheader =<<"END";
Line 382  END Line 503  END
 END  END
     foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){      foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
  if ($label_num<$num_uneditable) {    if ($label_num<$num_uneditable) { 
             $tableheader.='<th bgcolor="#FFDDDD">';              $tableheader.='<th bgcolor="'.$importcolor.'">';
         } else {          } else {
             $tableheader.='<th>';              $tableheader.='<th>';
         }          }
Line 390  END Line 511  END
     }      }
     #      #
     my $num_output = 0;      my $num_output = 0;
     foreach my $rownum ($self->rows()) {      foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
           if (! $self->parameter_part_is_valid(
                                                $self->{'formulas'}->{'A'.$rownum}
                                                )) {
               next;
           }
  if ($num_output++ % 50 == 0) {   if ($num_output++ % 50 == 0) {
     $r->print("</table>\n".$tableheader);      $r->print("</table>\n".$tableheader);
  }   }
  $r->print('<tr><td>'.$rownum.'</td>'.   $r->print('<tr><td>'.$rownum.'</td>'.
                   $self->assess_html_row($num_uneditable,$rownum)."</tr>\n");                    $self->assess_html_row($rownum,$importcolor)."</tr>\n");
     }      }
     $r->print("</table>\n");      $r->print("</table>\n");
     return;      return;
Line 403  END Line 529  END
   
 sub assess_html_row {  sub assess_html_row {
     my $self = shift();      my $self = shift();
     my ($num_uneditable,$row) = @_;      my ($row,$importcolor) = @_;
     my $requester_is_student = ($ENV{'request.role'} =~ /^st\./);  
     my $parameter_name = $self->{'formulas'}->{'A'.$row};      my $parameter_name = $self->{'formulas'}->{'A'.$row};
     my @rowdata = $self->get_row($row);      my @rowdata = $self->get_row($row);
     my $num_cols_output = 0;      my $num_cols_output = 0;
     my $row_html;      my $row_html;
     if (exists($nice_parameter_name{$parameter_name})) {      my $name=$self->get_parm_name($parameter_name);
         my $name = $nice_parameter_name{$parameter_name};      if ($name ne '') {
         $name =~ s/ /\&nbsp;/g;          $name =~ s/ /\&nbsp;/g;
         $row_html .= '<td>'.$name.'<br />'.$parameter_name.'</td>';          $row_html .= '<td>'.$name.'<br />'.$parameter_name.'</td>';
     } else {      } else {
         $row_html .= '<td>'.$parameter_name.'</td>';          $row_html .= '<td>'.$parameter_name.'</td>';
     }      }
     foreach my $cell (@rowdata) {      foreach my $cell (@rowdata) {
  if ($requester_is_student ||           if ($num_cols_output < 1) {
     $num_cols_output++ < $num_uneditable) {              $row_html .= '<td bgcolor="'.$importcolor.'">';
     $row_html .= '<td bgcolor="#FFDDDD">';              $row_html .= &Apache::Spreadsheet::html_uneditable_cell($cell,
     $row_html .= &Apache::Spreadsheet::html_uneditable_cell($cell,'#FFDDDD');                                                                      '#FFDDDD');
  } else {          } else {
     $row_html .= '<td bgcolor="#EOFFDD">';              $row_html .= '<td bgcolor="#E0FFDD">';
     $row_html .= &Apache::Spreadsheet::html_editable_cell($cell,'#E0FFDD');              $row_html .= &Apache::Spreadsheet::html_editable_cell($cell,
  }                                                                    '#E0FFDD',1);
           }
  $row_html .= '</td>';   $row_html .= '</td>';
           $num_cols_output++;
     }      }
     return $row_html;      return $row_html;
 }  }
   
 sub outsheet_csv {  sub csv_rows {
     my $self = shift;      # writes the meat of the spreadsheet to an excel worksheet.  Called
     my ($r)=@_;      # by Spreadsheet::outsheet_excel;
 }      my $self = shift;
       my ($connection,$filehandle) = @_;
 sub outsheet_excel {      #
     my $self = shift;      # Write a header row
     my ($r)=@_;      $self->csv_output_row($filehandle,undef,
                             (&mt('Parameter'),&mt('Description'),&mt('Value')));
       #
       # Write each row
       foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
           my $parameter_name = $self->{'formulas'}->{'A'.$rownum};
           my $description = $self->get_parm_name($parameter_name);
           $self->csv_output_row($filehandle,$rownum,
                                 $parameter_name,$description);
       }
       return;
 }  }
   
 sub display {  sub excel_rows {
     my $self = shift;      # writes the meat of the spreadsheet to an excel worksheet.  Called
     my ($r) = @_;      # by Spreadsheet::outsheet_excel;
     $self->compute();      my $self = shift;
     $self->outsheet_html($r);      my ($connection,$worksheet,$cols_output,$rows_output,$format) = @_;
       return if (! ref($worksheet));
       #
       # Write a header row
       $cols_output = 0;
       foreach my $value ('Parameter','Description','Value') {
           $worksheet->write($rows_output,$cols_output++,$value,$format->{'h4'});
       }
       $rows_output++;
       #
       # Write each row
       foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
           my $parameter_name = $self->{'formulas'}->{'A'.$rownum};
           my $description = $self->get_parm_name($parameter_name);
           $self->excel_output_row($worksheet,$rownum,$rows_output++,
                                   $parameter_name,$description);
       }
       return;
 }  }
   
 sub compute {  ##
   ## Routines to support assesscalc::compute
   ##
   sub get_parm {
     my $self = shift;      my $self = shift;
     $self->logthis('computing');      my @Mandatory_parameters = @_;
     $self->initialize_safe_space();      my %parameters;
     #      #
     # Definitions      my ($symap,$syid,$srcf) = &Apache::lonnet::decode_symb($self->{'symb'});
     undef(%nice_parameter_name);  
     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'));      my @Metadata = split(/\,/,&Apache::lonnet::metadata($srcf,'keys'));
     foreach my $parm (@Metadata) {      foreach my $parm (@Mandatory_parameters,@Metadata) {
         next if ($parm !~ /^(resource\.|stores|parameter)_/);          next if ($parm !~ /^(resource\.|stores|parameter)_/);
         my $cleaned_name = $parm;          my $cleaned_name = $parm;
         $cleaned_name =~ s/^resource\./stores_/;          $cleaned_name =~ s/^resource\./stores_/;
         $cleaned_name =~ s/\./_/g;          $cleaned_name =~ s/\./_/g;
         my $display = &Apache::lonnet::metadata($srcf,          $parameters{$cleaned_name}=1;
                                                 $cleaned_name.'.display');      }
         if (! $display) {      return (keys(%parameters));
             $display .= &Apache::lonnet::metadata($srcf,$cleaned_name.'.name');  }
         }  
         $parameters{$cleaned_name}++;  sub get_parm_name {
         $nice_parameter_name{$cleaned_name} = $display;      my $self = shift;
       my $parm = shift;
       my ($symap,$syid,$srcf) = &Apache::lonnet::decode_symb($self->{'symb'});
       my $display = &Apache::lonnet::metadata($srcf,$parm.'.display');
       if (! $display) {
    $display .= &Apache::lonnet::metadata($srcf,$parm.'.name');
       }
       return $display;
   }
   
   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);
     }      }
     #      #
     # Get the values of the metadata fields      my %parameters;
     $self->ensure_current_parameter_caches();      #
     my $filename = $self->{'coursefilename'}.'_parms.db';      my $filename = $self->{'coursefilename'}.'_parms.db';
     if (tie(%parmhash,'GDBM_File',      if (tie(%parmhash,'GDBM_File',
             $self->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) {              $self->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) {
         foreach my $parmname (keys(%parameters)) {   my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($self->{'symb'});
             my $value =  $self->parmval($parmname);   $mapname = &Apache::lonnet::deversion($mapname);
           foreach my $parmname (@Parameters) {
               my $value = $self->parmval($parmname,$self->{'symb'},
          $self->{'name'},$self->{'domain'},
          $self->{'section'},undef,
          $mapname,$id,$fn,$self->{'groups'});
             $parameters{$parmname} =$value;              $parameters{$parmname} =$value;
         }          }
         untie(%parmhash);          untie(%parmhash);
     } else {      } else {
         $self->logthis('unable to tie '.$filename);          $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 determine_parts {
       my $self = shift;
       my $check_hidden = shift;
       if (exists($self->{'Parts'}) && ref($self->{'Parts'}) eq 'HASH') {
           return;
       }
       my (undef,undef,$url) = &Apache::lonnet::decode_symb($self->{'symb'});
       my $src = &Apache::lonnet::clutter($url);
       return if (! defined($src));
       my %Parts;
       my $metadata = &Apache::lonnet::metadata($src,'packages');
       foreach (split(',',$metadata)) {
           my ($part) = (/^part_(.*)$/);
           if (!defined($part)) { next; }
           if (!$check_hidden) { $Parts{$part}++; next; }
           if (!&Apache::loncommon::check_if_partid_hidden
       ($part,$self->{'symb'},$self->{'name'},$self->{'domain'})
               ) {
               $Parts{$part}++;
           }
       }
       # Make sure part 0 is defined.
       $Parts{'0'}++;
       $self->{'Parts'} = \%Parts;
       return;
   }
   
   sub parameter_part_is_valid {
       my $self = shift;
       my ($parameter) = @_;
       return 1 if ($parameter eq 'timestamp');
       if (! defined($self->{'Parts'}) || 
           ! ref ($self->{'Parts'})    ||
           ref($self->{'Parts'}) ne 'HASH') {
           return 1;
       }
       #
       my ($start,@pieces)=split('_',$parameter);
       if ( $start !~ m/^(resource|stores|parameter)$/) { return 0; }
       while (@pieces) {
           pop(@pieces);
           my $testpart=join('_',@pieces);
    if (exists($self->{'Parts'}->{$testpart}) &&
       $self->{'Parts'}->{$testpart} ) {
       return 1;
    }
       }
       return 0;
   }
   
   sub compute {
       my $self = shift;
       my ($r) = @_;
       $self->initialize_safe_space();
       #########################################
       #########################################
       ###                                   ###
       ###  Retrieve the problem parameters  ###
       ###                                   ###
       #########################################
       #########################################
       my @Mandatory_parameters = ("stores_0_solved",
                                   "stores_0_awarddetail",
                                   "stores_0_awarded",
                                   "timestamp",
                                   "stores_0_tries",
                                   "stores_0_award");
       #
       # Definitions
       undef(%nice_parameter_name);
       my %parameters;   # holds underscored parameters by name
       #
       # Get the metadata fields and determine their proper names
       my @parameters=$self->get_parm(@Mandatory_parameters);
       #
       # Get the values of the metadata fields
       $self->ensure_current_caches();
       %parameters = $self->get_parameter_values(@parameters);
     #      #
     # Clean out unnecessary parameters      # Clean out unnecessary parameters
     foreach (keys(%parameters)) {      foreach (keys(%parameters)) {
Line 493  sub compute { Line 771  sub compute {
     }      }
     #      #
     # Get the students performance data      # Get the students performance data
     my %student_parameters =       $self->determine_parts(($parameters{'parameter_0_hiddenparts'} ne ''));
         &Apache::loncoursedata::get_current_state($self->{'name'},      my %student_parameters = $self->get_problem_state();
                                                   $self->{'domain'},  
                                                   $self->{'symb'},  
                                                   $self->{'cid'});  
     while (my ($parm,$value) = each(%student_parameters)) {      while (my ($parm,$value) = each(%student_parameters)) {
         $parm =~ s/^resource\./stores_/;          $parm =~ s/^resource\./stores_/;
         $parm =~ s/\./_/g;          $parm =~ s/\./_/g;
         $parameters{$parm} = $value;   # Clean out any bad parameters
    next if (! $self->parameter_part_is_valid($parm));
    $parameters{$parm} = $value;
     }      }
     #      #
     # Set up the formulas and parameter values      # Set up the formulas and parameter values
     my %f=$self->formulas();      my %f=$self->formulas();
     my %c;      my %c;
     #      #
       # Check for blackout requirements
       if ((!exists($env{'request.role.adv'}) || !$env{'request.role.adv'})) {
           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 (lc($value) eq 'no') {
                   # We must blackout this sheet
                   $self->blackout(1);
               }
           }
       }
       #
       # Move the parameters into the spreadsheet
     while (my ($parm,$value) = each(%parameters)) {      while (my ($parm,$value) = each(%parameters)) {
         my $cell = 'A'.$self->get_row_number_from_key($parm);          my $cell = 'A'.$self->get_row_number_from_key($parm);
         $f{$cell} = $parm;          $f{$cell} = $parm;
           if ($parm =~ /_submission$/ && $value =~ /(\{|\})/) {
               $value = 'witheld';
           }
           $value = 'q{'.$value.'}' if ($value =~/([^\d\.]|\.\.)/);
         $c{$parm} = $value;          $c{$parm} = $value;
     }      }
     $self->formulas(%f);      foreach my $cell (grep(/^A/,keys(%f))) {
     $self->constants(%c);          # Clean out any bad formulas
    next if (exists($c{$f{$cell}}));
    next if ($cell eq 'A0');
    delete($f{$cell});
       }
       $self->formulas(\%f);
       $self->constants(\%c);
     $self->calcsheet();      $self->calcsheet();
     #      #
     # Store export row in cache      # Store export row in cache
     my @exportarray = $self->exportrow();      my @exportarray = $self->exportrow();
     $Exportrows{$self->{'symb'}}->{'time'} = time;      $self->deal_with_export_row(@exportarray);
     $Exportrows{$self->{'symb'}}->{$self->{'filename'}} = \@exportarray;      $self->save() if ($self->need_to_save());
     #  
     # Save the export data  
     $self->save_export_data();  
     return;      return;
 }  }
   
Line 533  sub compute { Line 834  sub compute {
 sub sett {  sub sett {
     my $self = shift;      my $self = shift;
     my %t=();      my %t=();
       undef(%Apache::Spreadsheet::sheet_values);
     #      #
     # Deal with the template row by copying the template formulas into each      # Deal with the template row by copying the template formulas into each
     # row.      # row.
Line 550  sub sett { Line 852  sub sett {
             # Replace 'A0' with the value from 'A0'              # Replace 'A0' with the value from 'A0'
             $t{$cell}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;              $t{$cell}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
             # Replace parameters              # Replace parameters
             $t{$cell}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.$self->expandnamed($2)/ge;              $t{$cell}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.$self->expandnamed($2)/sge;
         }          }
     }      }
     #      #
Line 558  sub sett { Line 860  sub sett {
     while (my ($cell,$formula) = each(%{$self->{'formulas'}})) {      while (my ($cell,$formula) = each(%{$self->{'formulas'}})) {
  next if ($cell =~ /template_/);   next if ($cell =~ /template_/);
         if ($cell =~ /^A/ && $cell ne 'A0') {          if ($cell =~ /^A/ && $cell ne 'A0') {
             if ($formula !~ /^\!/) {      if ($formula !~ /^\!/ 
                 $t{$cell}=$self->{'constants'}->{$formula};   && exists($self->{'constants'}->{$formula}) 
    && $self->{'constants'}->{$formula} ne ''
    ) {
    $Apache::Spreadsheet::sheet_values{$cell}=
       eval($self->{'constants'}->{$formula});
             }              }
         } else {          } else {
             $t{$cell}=$formula;              $t{$cell}=$formula;
             $t{$cell}=~s/\.\.+/\,/g;              $t{$cell}=~s/\.\.+/\,/g;
             $t{$cell}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;              $t{$cell}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
             $t{$cell}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.$self->expandnamed($2)/ge;              $t{$cell}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.$self->expandnamed($2)/sge;
         }          }
     }      }
     # Put %t into the safe space      # Put %t into the safe space
Line 592  These rows are saved in the students dir Line 898  These rows are saved in the students dir
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub load_cached_export_rows {  sub load_cached_export_rows {
     %Exportrows = undef;      undef(%Exportrows);
     &Apache::lonnet::logthis("loading cached assess sheets for $current_name $current_domain");  
     my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets_'.      my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets_'.
                                     $ENV{'request.course.id'},                                      $env{'request.course.id'},
                                     $current_domain,$current_name,undef);                                      $current_domain,$current_name,undef);
     if ($tmp[0]!~/^error/) {      if ($tmp[0]!~/^error/) {
         my %tmp = @tmp;          my %tmp = @tmp;
         my $default_filename =  $ENV{'course.'.$ENV{'request.course.id'}.          my $default_filename =  $env{'course.'.$env{'request.course.id'}.
                                          '.spreadsheet_default_assesscalc'};                                           '.spreadsheet_default_assesscalc'};
         # We only got one key, so we will access it directly.          # We only got one key, so we will access it directly.
         while (my ($key,$sheetdata) = each(%tmp)) {          while (my ($key,$sheetdata) = each(%tmp)) {
             my ($sname,$sdom,$sheettype,$symb) = split(':',$key);              my ($sname,$sdom,$sheettype,$symb) = split(':',$key);
               if (! defined($sname) || $sname eq '' ||
                   ! defined($sdom)  || $sdom eq '' ) {
                   next;
               }
             if ($symb =~ /\.time$/) {              if ($symb =~ /\.time$/) {
                 $symb =~ s/\.time$//;                  $symb =~ s/\.time$//;
                 $Exportrows{$symb}->{'time'} = $sheetdata;                  $Exportrows{$symb}->{'time'} = $sheetdata;
Line 634  spreadsheet only if necessary. Line 943  spreadsheet only if necessary.
 #############################################  #############################################
 sub export_data {  sub export_data {
     my $self = shift;      my $self = shift;
       my ($r) = @_;
     my $symb = $self->{'symb'};      my $symb = $self->{'symb'};
     if (! exists($Exportrows{$symb}) || ! defined($Exportrows{$symb})  ||      if (! exists($env{'request.role.adv'}) || ! $env{'request.role.adv'} ||
           ! exists($Exportrows{$symb}) || ! defined($Exportrows{$symb})  ||
         ! $self->check_expiration_time($Exportrows{$symb}->{'time'}) ||          ! $self->check_expiration_time($Exportrows{$symb}->{'time'}) ||
         ! exists($Exportrows{$symb}->{$self->{'filename'}}) ||          ! exists($Exportrows{$symb}->{$self->{'filename'}}) ||
         ! defined($Exportrows{$symb}->{$self->{'filename'}})) {          ! defined($Exportrows{$symb}->{$self->{'filename'}}) ||
         $self->compute();          ! ref($Exportrows{$symb}->{$self->{'filename'}}) 
     }          ) {
     my @Data = @{$Exportrows{$symb}->{$self->{'filename'}}};          $self->compute($r);
     if ($Data[0] =~ /^(.*)___=___/) {      }
         $self->{'sheetname'} = $1;      my @Data;
         $Data[0] =~ s/^(.*)___=___//;      if ($self->badcalc()) {
     }          @Data = ();
     for (my $i=0;$i<$#Data;$i++) {      } else {
         $Data[$i]="'".$Data[$i]."'" if ($Data[$i]=~/\D/ && defined($Data[$i]));          @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]."'";
               }
           }
     }      }
     return @Data;      return @Data;
 }  }
Line 667  Writes the export data for this spreadsh Line 987  Writes the export data for this spreadsh
 #############################################  #############################################
 sub save_export_data {  sub save_export_data {
     my $self = shift;      my $self = shift;
       return if ($self->temporary());
     my $student = $self->{'name'}.':'.$self->{'domain'};      my $student = $self->{'name'}.':'.$self->{'domain'};
     my $symb    = $self->{'symb'};      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}) ||       if (! exists($Exportrows{$symb}) || 
         ! exists($Exportrows{$symb}->{$self->{'filename'}})) {          ! exists($Exportrows{$symb}->{$self->{'filename'}})) {
         return;          return;
     }      }
     my $key = join(':',($self->{'name'},$self->{'domain'},'assesscalc',$symb));      my $key = join(':',($self->{'name'},$self->{'domain'},'assesscalc',$symb));
     my $timekey = $key.'.time';      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;      $newstore = $self->{'filename'}.'___=___'.$newstore;
     my $result = &Apache::lonnet::put      $newExportrows{$student}->{$key} = $newstore;
         ('nohist_calculatedsheets_'.$ENV{'request.course.id'},      $newExportrows{$student}->{$timekey} = $Exportrows{$symb}->{'time'};
          { $key     => $newstore,  
            $timekey => $Exportrows{$symb}->{'time'} },  
          $self->{'domain'},  
          $self->{'name'});  
   
     return;      return;
 }  }
   

Removed from v.1.1  
changed lines
  Added in v.1.59


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>