File:
[LON-CAPA] /
loncom /
interface /
spreadsheet /
studentcalc.pm
Revision
1.27:
download - view:
text,
annotated -
select for diffs
Wed Dec 8 00:56:00 2004 UTC (19 years, 8 months ago) by
albertel
Branches:
MAIN
CVS tags:
version_1_3_X,
version_1_3_3,
version_1_3_2,
version_1_3_1,
version_1_3_0,
version_1_2_99_1,
HEAD
- BUG #2207, the SUBM,PGRD,PPRM links on the SPRS now go to the correct place.
1: #
2: # $Id: studentcalc.pm,v 1.27 2004/12/08 00:56:00 albertel Exp $
3: #
4: # Copyright Michigan State University Board of Trustees
5: #
6: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
7: #
8: # LON-CAPA is free software; you can redistribute it and/or modify
9: # it under the terms of the GNU General Public License as published by
10: # the Free Software Foundation; either version 2 of the License, or
11: # (at your option) any later version.
12: #
13: # LON-CAPA is distributed in the hope that it will be useful,
14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: # GNU General Public License for more details.
17: #
18: # You should have received a copy of the GNU General Public License
19: # along with LON-CAPA; if not, write to the Free Software
20: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21: #
22: # /home/httpd/html/adm/gpl.txt
23: #
24: # http://www.lon-capa.org/
25: #
26: # The LearningOnline Network with CAPA
27: # Spreadsheet/Grades Display Handler
28: #
29: # POD required stuff:
30:
31: =head1 NAME
32:
33: studentcalc
34:
35: =head1 SYNOPSIS
36:
37: =head1 DESCRIPTION
38:
39: =over 4
40:
41: =cut
42:
43: ###################################################
44: ### StudentSheet ###
45: ###################################################
46: package Apache::studentcalc;
47:
48: use warnings FATAL=>'all';
49: no warnings 'uninitialized';
50:
51: use strict;
52: use Apache::Constants qw(:common :http);
53: use Apache::lonnet;
54: use Apache::loncommon();
55: use Apache::loncoursedata();
56: use Apache::lonnavmaps;
57: use Apache::Spreadsheet();
58: use Apache::assesscalc();
59: use HTML::Entities();
60: use Time::HiRes;
61: use Apache::lonlocal;
62:
63: @Apache::studentcalc::ISA = ('Apache::Spreadsheet');
64:
65: my @Sequences = ();
66: my %Exportrows = ();
67:
68: my $current_course;
69:
70: sub initialize {
71: &Apache::assesscalc::initialize();
72: &initialize_sequence_cache();
73: }
74:
75: sub initialize_package {
76: $current_course = $ENV{'request.course.id'};
77: &initialize_sequence_cache();
78: &load_cached_export_rows();
79: }
80:
81: sub ensure_correct_sequence_data {
82: if ($current_course ne $ENV{'request.course.id'}) {
83: &initialize_sequence_cache();
84: $current_course = $ENV{'request.course.id'};
85: }
86: return;
87: }
88:
89: sub initialize_sequence_cache {
90: #
91: # Set up the sequences and assessments
92: undef(@Sequences);
93: my ($top,$sequences,$assessments) =
94: &Apache::loncoursedata::get_sequence_assessment_data();
95: if (! defined($top) || ! ref($top)) {
96: # There has been an error, better report it
97: &Apache::lonnet::logthis('top is undefined (studentcalc.pm)');
98: return;
99: }
100: @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY');
101: }
102:
103: sub clear_package {
104: undef(@Sequences);
105: undef(%Exportrows);
106: &Apache::assesscalc::clear_package();
107: }
108:
109: sub get_title {
110: my $self = shift;
111: my @title = ();
112: #
113: # Determine the students name
114: my $name = &Apache::loncommon::plainname($self->{'name'},
115: $self->{'domain'});
116: push (@title,$name);
117: push (@title,$self->{'coursedesc'});
118: push (@title,&Apache::lonlocal::locallocaltime(time));
119: return @title;
120: }
121:
122: sub get_html_title {
123: my $self = shift;
124: my ($name,$desc,$time) = $self->get_title();
125: my $title = '<h1>'.$name;
126: if ($ENV{'user.name'} ne $self->{'name'} &&
127: $ENV{'user.domain'} ne $self->{'domain'}) {
128: $title .= ' '.&Apache::loncommon::aboutmewrapper
129: ($self->{'name'}.'@'.$self->{'domain'},
130: $self->{'name'},$self->{'domain'});
131: }
132: $title .= "</h1>\n";
133: $title .= '<h2>'.$desc."</h2>\n";
134: $title .= '<h3>'.$time.'</h3>';
135: return $title;
136: }
137:
138: sub parent_link {
139: my $self = shift;
140: return '<p><a href="/adm/classcalc">'.&mt('Course level sheet').'</a></p>'."\n";
141: }
142:
143: sub convenience_links {
144: my $self = shift;
145: my ($resource) = @_;
146: my $result=&Apache::loncommon::submlink('<img src="/adm/lonMisc/subm_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->{'symb'},'LONcatInfo');
147: $result .= &Apache::loncommon::pgrdlink('<img src="/adm/lonMisc/pgrd_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->{'symb'},'LONcatInfo');
148: $result .= &Apache::loncommon::pprmlink('<img src="/adm/lonMisc/pprm_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->{'symb'},'LONcatInfo');
149: return $result;
150: }
151:
152: sub outsheet_html {
153: my $self = shift;
154: my ($r) = @_;
155: my $importcolor = '#FFFFAA';
156: my $exportcolor = '#88FF88';
157: ####################################
158: # Get the list of assessment files #
159: ####################################
160: my @AssessFileNames = $self->othersheets('assesscalc');
161: my $editing_is_allowed = &Apache::lonnet::allowed('mgr',
162: $ENV{'request.course.id'});
163: ####################################
164: # Report any calculation errors #
165: ####################################
166: $r->print($self->html_report_error());
167: ####################################
168: # Determine table structure #
169: ####################################
170: my $num_uneditable = 26;
171: my $num_left = 52-$num_uneditable;
172: my %lt=&Apache::lonlocal::texthash(
173: 'st' => 'Student',
174: 'im' => 'Import',
175: 'ca' => 'Calculations',
176: 'as' => 'Assessment',
177: 'ro' => 'Row',
178: );
179: my $tableheader =<<"END";
180: <p>
181: <table border="2">
182: <tr>
183: <th colspan="2" rowspan="2"><font size="+2">$lt{'st'}</font></th>
184: <td bgcolor="$importcolor" colspan="$num_uneditable">
185: <b><font size="+1">$lt{'im'}</font></b></td>
186: <td colspan="$num_left">
187: <b><font size="+1">$lt{'ca'}</font></b></td>
188: </tr><tr>
189: END
190: my $label_num = 0;
191: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
192: if ($label_num<$num_uneditable) {
193: $tableheader .='<td bgcolor="'.$importcolor.'">';
194: } else {
195: $tableheader .='<td>';
196: }
197: $tableheader .="<b><font size=+1>$_</font></b></td>";
198: $label_num++;
199: }
200: $tableheader .="</tr>\n";
201: if ($self->blackout()) {
202: $r->print('<font color="red" size="+2"><p>'.
203: &mt('Some computations are not available at this time.').'<br />'.
204: &mt('There are problems whose status you are not allowed to view.').
205: '</font></p>'."\n");
206: } else {
207: $r->print($tableheader);
208: #
209: # Print out template row
210: if (exists($ENV{'request.role.adv'}) && $ENV{'request.role.adv'}) {
211: $r->print('<tr><td>Template</td><td> </td>'.
212: $self->html_template_row($num_uneditable,
213: $importcolor)."</tr>\n");
214: }
215: #
216: # Print out summary/export row
217: $r->print('<tr><td>'.&mt('Summary').'</td><td>0</td>'.
218: $self->html_export_row($exportcolor)."</tr>\n");
219: }
220: $r->print("</table>\n");
221: #
222: # Prepare to output rows
223: if (exists($ENV{'request.role.adv'}) && $ENV{'request.role.adv'}) {
224: $tableheader =<<"END";
225: </p><p>
226: <table border="2">
227: <tr><th>$lt{'ro'}</th><th> </th><th>$lt{'as'}</th>
228: END
229: } else {
230: $tableheader =<<"END";
231: </p><p>
232: <table border="2">
233: <tr><th> </th><th>$lt{'as'}</th>
234: END
235: }
236: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
237: if ($label_num<$num_uneditable) {
238: $tableheader.='<td bgcolor="#FFDDDD">';
239: } else {
240: $tableheader.='<td>';
241: }
242: $tableheader.="<b><font size=+1>$_</font></b></td>";
243: }
244: $tableheader.="\n";
245: #
246: my $num_output = 1;
247: if (scalar(@Sequences)< 1) {
248: &initialize_sequence_cache();
249: }
250: foreach my $Sequence (@Sequences) {
251: next if ($Sequence->{'num_assess'} < 1);
252: $r->print("<h3>".$Sequence->{'title'}."</h3>\n");
253: $r->print($tableheader);
254: foreach my $resource (@{$Sequence->{'contents'}}) {
255: next if ($resource->{'type'} ne 'assessment');
256: my $rownum = $self->get_row_number_from_key($resource->{'symb'});
257: my $assess_filename = $self->{'row_source'}->{$rownum};
258: my $row_output = '<tr>';
259: if ($editing_is_allowed) {
260: $row_output .= '<td>'.$rownum.'</td>';
261: $row_output .= '<td>'.$self->convenience_links($resource).'</td>';
262: $row_output .= '<td>'.
263: '<a href="/adm/assesscalc?sname='.$self->{'name'}.
264: '&sdomain='.$self->{'domain'}.
265: '&filename='.$assess_filename.
266: '&usymb='.&Apache::lonnet::escape($resource->{'symb'}).
267: '">'.$resource->{'title'}.'</a><br />';
268: $row_output .= &assess_file_selector($rownum,
269: $assess_filename,
270: \@AssessFileNames).
271: '</td>';
272: } else {
273: $row_output .= '<td><a href="'.$resource->{'src'}.'?symb='.
274: &Apache::lonnet::escape($resource->{'symb'}).
275: '">Go To</a>';
276: $row_output .= '</td><td>'.$resource->{'title'}.'</td>';
277: }
278: if ($self->blackout() && $self->{'blackout_rows'}->{$rownum}>0) {
279: $row_output .=
280: '<td colspan="52">'.&mt('Unavailable at this time').'</td></tr>'."\n";
281: } else {
282: $row_output .= $self->html_row($num_uneditable,$rownum,
283: $exportcolor,$importcolor).
284: "</tr>\n";
285: }
286: $r->print($row_output);
287: }
288: $r->print("</table>\n");
289: }
290: $r->print("</p>\n");
291: return;
292: }
293:
294: ########################################################
295: ########################################################
296:
297: =pod
298:
299: =item &assess_file_selector()
300:
301: =cut
302:
303: ########################################################
304: ########################################################
305: sub assess_file_selector {
306: my ($row,$default,$AssessFiles)=@_;
307: if (!defined($AssessFiles) || ! @$AssessFiles) {
308: return '';
309: }
310: return '' if (! &Apache::lonnet::allowed('mgr',$ENV{'request.course.id'}));
311: my $element_name = 'FileSelect_'.$row;
312: my $load_dialog = '<select size="1" name="'.$element_name.'" '.
313: 'onchange="'.
314: "document.sheet.cell.value='source_$row';".
315: "document.sheet.newformula.value=document.sheet.$element_name\.value;".
316: 'document.sheet.submit()" '.'>'."\n";
317: foreach my $file (@{$AssessFiles}) {
318: $load_dialog .= ' <option name="'.$file.'"';
319: $load_dialog .= ' selected' if ($default eq $file);
320: $load_dialog .= '>'.$file."</option>\n";
321: }
322: $load_dialog .= "</select>\n";
323: return $load_dialog;
324: }
325:
326: sub modify_cell {
327: my $self = shift;
328: my ($cell,$formula) = @_;
329: if ($cell =~ /^source_(\d+)$/) {
330: # Need to make sure $formula is a valid filename....
331: my $row = $1;
332: $cell = 'A'.$row;
333: $self->{'row_source'}->{$row} = $formula;
334: my $original_source = $self->formula($cell);
335: if ($original_source =~ /__&&&__/) {
336: ($original_source,undef) = split('__&&&__',$original_source);
337: }
338: $formula = $original_source.'__&&&__'.$formula;
339: } elsif ($cell =~ /([A-z])\-/) {
340: $cell = 'template_'.$1;
341: } elsif ($cell !~ /^([A-z](\d+)|template_[A-z])$/) {
342: return;
343: }
344: $self->set_formula($cell,$formula);
345: $self->rebuild_stats();
346: return;
347: }
348:
349: sub csv_rows {
350: # writes the meat of the spreadsheet to an excel worksheet. Called
351: # by Spreadsheet::outsheet_excel;
352: my $self = shift;
353: my ($connection,$filehandle) = @_;
354: #
355: # Write a header row
356: $self->csv_output_row($filehandle,undef,
357: (&mt('Sequence or Folder'),&mt('Assessment title')));
358: #
359: # Write each assessments row
360: if (scalar(@Sequences)< 1) {
361: &initialize_sequence_cache();
362: }
363: foreach my $Sequence (@Sequences) {
364: next if ($Sequence->{'num_assess'} < 1);
365: foreach my $resource (@{$Sequence->{'contents'}}) {
366: my $rownum = $self->get_row_number_from_key($resource->{'symb'});
367: my @assessdata = ($Sequence->{'title'},
368: $resource->{'title'});
369: $self->csv_output_row($filehandle,$rownum,@assessdata);
370: }
371: }
372: return;
373: }
374:
375: sub excel_rows {
376: # writes the meat of the spreadsheet to an excel worksheet. Called
377: # by Spreadsheet::outsheet_excel;
378: my $self = shift;
379: my ($connection,$worksheet,$cols_output,$rows_output) = @_;
380: #
381: # Write a header row
382: $cols_output = 0;
383: foreach my $value ('Container','Assessment title') {
384: $worksheet->write($rows_output,$cols_output++,&mt($value));
385: }
386: $rows_output++;
387: #
388: # Write each assessments row
389: if (scalar(@Sequences)< 1) {
390: &initialize_sequence_cache();
391: }
392: foreach my $Sequence (@Sequences) {
393: next if ($Sequence->{'num_assess'} < 1);
394: foreach my $resource (@{$Sequence->{'contents'}}) {
395: my $rownum = $self->get_row_number_from_key($resource->{'symb'});
396: my @assessdata = ($Sequence->{'title'},
397: $resource->{'title'});
398: $self->excel_output_row($worksheet,$rownum,$rows_output++,
399: @assessdata);
400: }
401: }
402: return;
403: }
404:
405: sub outsheet_recursive_excel {
406: my $self = shift;
407: my ($r) = @_;
408: }
409:
410: ##
411: ## Routines to deal with sequences in the safe space
412: ##
413: sub get_rows_in_sequence {
414: my $self = shift();
415: my ($sequence) = @_;
416: my @Rows;
417: foreach my $resource (@{$sequence->{'contents'}}) {
418: if ($resource->{'type'} eq 'assessment') {
419: my $rownum = $self->get_row_number_from_key($resource->{'symb'});
420: push (@Rows,$rownum);
421: }
422: }
423: return @Rows;
424: }
425:
426: sub remove_sequence_data_from_safe_space {
427: my $self = shift();
428: my $command = 'undef(%Sequence_Rows);';
429: $self->{'safe'}->reval($command);
430: }
431:
432: sub put_sequence_data_in_safe_space {
433: my $self = shift();
434: my $data = 'undef(%Sequence_Rows);';
435: # Build up the %Sequence_Rows hash - each sequence title is associated with
436: # an array pointer, which holds the rows in the sequence.
437: foreach my $seq (@Sequences) {
438: my @Rows = $self->get_rows_in_sequence($seq);
439: #
440: # Potential problems with sequence titles:
441: # 1. duplicate titles - they get the total for the titles
442: # 2. control characters in titles - use q{} around the string to
443: # deal with it.
444: my $title = &HTML::Entities::decode($seq->{'title'});
445: $title =~ s/&\#058;/:/g;
446: if (@Rows) {
447: $data .= 'push(@{$Sequence_Rows{"'.quotemeta($title).'"}},'.
448: '('.join(',',@Rows).'));'."\n";;
449: }
450: }
451: my $new_code = $data.<<'END';
452: sub SUMSEQ {
453: my ($col,@titles) = @_;
454: return 'bad column: '.$col if ($col !~ /^[A-z]$/);
455: my $sum = 0;
456: foreach my $title (@titles) {
457: while (my ($seq_title,$rows) = each(%Sequence_Rows)) {
458: my $regexp;
459: if ($title =~ /^regexp:(.*)$/) {
460: $regexp = $1;
461: } elsif (lc($title) eq 'all') {
462: $regexp = '.';
463: }
464: if (defined($regexp)) {
465: next if ($seq_title !~ /$regexp/);
466: } else {
467: next if ($seq_title ne $title);
468: }
469: foreach my $rownum (@{$rows}) {
470: my $cell = $col.$rownum;
471: if (exists($sheet_values{$cell})) {
472: $sum += $sheet_values{$cell};
473: }
474: }
475: }
476: }
477: return $sum;
478: }
479: END
480: $self->{'safe'}->reval($new_code);
481: return;
482: }
483:
484: ##
485: ## Main computation method
486: ##
487: sub compute {
488: my $self = shift;
489: my ($r) = @_;
490: my $connection = $r->connection();
491: if ($connection->aborted()) { $self->cleanup; return; }
492: if (! defined($current_course) ||
493: $current_course ne $ENV{'request.course.id'} ||
494: ! @Sequences ) {
495: $current_course = $ENV{'request.course.id'};
496: &clear_package();
497: &initialize_sequence_cache();
498: }
499: $self->initialize_safe_space();
500: &Apache::assesscalc::initialize_package($self->{'name'},$self->{'domain'});
501: my %f = $self->formulas();
502: #
503: # Process the formulas list -
504: # the formula for the A column of a row is symb__&&__filename
505: my %c = $self->constants();
506: foreach my $seq (@Sequences) {
507: next if ($seq->{'num_assess'}<1);
508: foreach my $resource (@{$seq->{'contents'}}) {
509: if ($connection->aborted()) { $self->cleanup(); return; }
510: next if ($resource->{'type'} ne 'assessment');
511: my $rownum = $self->get_row_number_from_key($resource->{'symb'});
512: my $cell = 'A'.$rownum;
513: my $assess_filename = 'Default';
514: if (exists($self->{'row_source'}->{$rownum})) {
515: $assess_filename = $self->{'row_source'}->{$rownum};
516: } else {
517: $self->{'row_source'}->{$rownum} = $assess_filename;
518: }
519: $f{$cell} = $resource->{'symb'}.'__&&&__'.$assess_filename;
520: if ($connection->aborted()) { $self->cleanup(); return; }
521: my $assessSheet;
522: $assessSheet = Apache::assesscalc->new($self->{'name'},
523: $self->{'domain'},
524: $assess_filename,
525: $resource->{'symb'});
526: my @exportdata = $assessSheet->export_data($r);
527: #
528: if ($assessSheet->badcalc()) {
529: $self->set_calcerror(
530: &mt('Error computing row for assessment "[_1]" (row [_2]):[_3]',
531: $assessSheet->get_title(),$rownum,$assessSheet->calcerror()));
532: }
533: #
534: if ($connection->aborted()) { $self->cleanup(); return; }
535: if ($assessSheet->blackout()) {
536: $self->blackout(1);
537: $self->{'blackout_rows'}->{$rownum} = 1;
538: }
539: #
540: # Be sure not to disturb the formulas in the 'A' column
541: my $data = shift(@exportdata);
542: $c{$cell} = $data if (defined($data));
543: #
544: # Deal with the remaining columns
545: my $i=0;
546: foreach (split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ')) {
547: my $cell = $_.$rownum;
548: my $data = shift(@exportdata);
549: if (defined($data)) {
550: $f{$cell} = 'import';
551: $c{$cell} = $data;
552: }
553: $i++;
554: }
555: }
556: }
557: $self->constants(\%c);
558: $self->formulas(\%f);
559: $self->put_sequence_data_in_safe_space();
560: $self->calcsheet();
561: $self->remove_sequence_data_from_safe_space();
562: #
563: # Store export row in cache
564: my @exportarray=$self->exportrow();
565: my $student = $self->{'name'}.':'.$self->{'domain'};
566: $Exportrows{$student}->{'time'} = time;
567: $Exportrows{$student}->{'data'} = \@exportarray;
568: # save export row
569: $self->save_export_data();
570: #
571: $self->save() if ($self->need_to_save());
572: return;
573: }
574:
575: sub set_row_sources {
576: my $self = shift;
577: while (my ($cell,$value) = each(%{$self->{'formulas'}})) {
578: next if ($cell !~ /^A(\d+)$/ || $1 < 1);
579: my $row = $1;
580: (undef,$value) = split('__&&&__',$value);
581: $value = 'Default' if (! defined($value));
582: $self->{'row_source'}->{$row} = $value;
583: }
584: return;
585: }
586:
587: sub set_row_numbers {
588: my $self = shift;
589: while (my ($cell,$formula) = each(%{$self->{'formulas'}})) {
590: next if ($cell !~ /^A(\d+)/);
591: my $row = $1;
592: next if ($row == 0);
593: my ($symb,undef) = split('__&&&__',$formula);
594: $self->{'row_numbers'}->{$symb} = $row;
595: $self->{'maxrow'} = $row if ($row > $self->{'maxrow'});
596: }
597: }
598:
599: sub get_row_number_from_symb {
600: my $self = shift;
601: my ($key) = @_;
602: ($key,undef) = split('__&&&__',$key) if ($key =~ /__&&&__/);
603: return $self->get_row_number_from_key($key);
604: }
605:
606: #############################################
607: #############################################
608:
609: =pod
610:
611: =item &load_cached_export_rows
612:
613: Retrieves and parsers the export rows of the student spreadsheets.
614: These rows are saved in the courses directory in the format:
615:
616: sname:sdom:studentcalc:.time => time
617:
618: sname:sdom:studentcalc => ___=___Adata___;___Bdata___;___Cdata___;___ .....
619:
620: =cut
621:
622: #############################################
623: #############################################
624: sub load_cached_export_rows {
625: undef(%Exportrows);
626: my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets',
627: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
628: $ENV{'course.'.$ENV{'request.course.id'}.'.num'},undef);
629: my %Selected_Assess_Sheet;
630: if ($tmp[0] =~ /^error/) {
631: &Apache::lonnet::logthis('unable to read cached student export rows '.
632: 'for course '.$ENV{'request.course.id'});
633: return;
634: }
635: my %tmp = @tmp;
636: while (my ($key,$sheetdata) = each(%tmp)) {
637: my ($sname,$sdom,$sheettype,$remainder) = split(':',$key);
638: my $student = $sname.':'.$sdom;
639: if ($remainder =~ /\.time/) {
640: $Exportrows{$student}->{'time'} = $sheetdata;
641: } else {
642: $sheetdata =~ s/^___=___//;
643: my @Data = split('___;___',$sheetdata);
644: $Exportrows{$student}->{'data'} = \@Data;
645: }
646: }
647: }
648:
649: #############################################
650: #############################################
651:
652: =pod
653:
654: =item &save_export_data()
655:
656: Writes the export data for this student to the course cache.
657:
658: =cut
659:
660: #############################################
661: #############################################
662: sub save_export_data {
663: my $self = shift;
664: my $student = $self->{'name'}.':'.$self->{'domain'};
665: return if ($self->temporary());
666: if ($self->badcalc()){
667: # do not save data away when calculations have not been done properly.
668: delete($Exportrows{$student});
669: return;
670: }
671: return if (! exists($Exportrows{$student}));
672: &Apache::assesscalc::save_cached_export_rows($self->{'name'},
673: $self->{'domain'});
674: return if (! $self->is_default());
675: my $key = join(':',($self->{'name'},$self->{'domain'},'studentcalc')).':';
676: my $timekey = $key.'.time';
677: my $newstore = join('___;___',
678: @{$Exportrows{$student}->{'data'}});
679: $newstore = '___=___'.$newstore;
680: my $result= &Apache::lonnet::put('nohist_calculatedsheets',
681: { $key => $newstore,
682: $timekey => $Exportrows{$student}->{'time'} },
683: $self->{'cdom'},
684: $self->{'cnum'});
685: return;
686: }
687:
688: #############################################
689: #############################################
690:
691: =pod
692:
693: =item &export_data()
694:
695: Returns the export data associated with the spreadsheet. Computes the
696: spreadsheet only if necessary.
697:
698: =cut
699:
700: #############################################
701: #############################################
702: sub export_data {
703: my $self = shift;
704: my ($r) = @_;
705: my $connection = $r->connection();
706: my $student = $self->{'name'}.':'.$self->{'domain'};
707: if (! exists($Exportrows{$student}) ||
708: ! defined($Exportrows{$student}) ||
709: ! exists($Exportrows{$student}->{'data'}) ||
710: ! defined($Exportrows{$student}->{'data'}) ||
711: ! exists($Exportrows{$student}->{'time'}) ||
712: ! defined($Exportrows{$student}->{'time'}) ||
713: ! $self->check_expiration_time($Exportrows{$student}->{'time'})) {
714: $self->compute($r);
715: }
716: if ($connection->aborted()) { $self->cleanup(); return; }
717: my @Data;
718: if ($self->badcalc()) {
719: @Data = ();
720: } else {
721: @Data = @{$Exportrows{$student}->{'data'}};
722: for (my $i=0; $i<=$#Data;$i++) {
723: if ($Data[$i]=~/\D/ && defined($Data[$i])) {
724: $Data[$i]="'".$Data[$i]."'";
725: }
726: }
727: }
728: return @Data;
729: }
730:
731: 1;
732:
733: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>