File:
[LON-CAPA] /
loncom /
interface /
spreadsheet /
studentcalc.pm
Revision
1.43:
download - view:
text,
annotated -
select for diffs
Fri Jul 6 19:50:00 2007 UTC (17 years, 2 months ago) by
albertel
Branches:
MAIN
CVS tags:
version_2_8_X,
version_2_8_2,
version_2_8_1,
version_2_8_0,
version_2_7_X,
version_2_7_99_1,
version_2_7_99_0,
version_2_7_1,
version_2_7_0,
version_2_6_X,
version_2_6_99_1,
version_2_6_99_0,
version_2_6_3,
version_2_6_2,
version_2_6_1,
version_2_6_0,
version_2_5_X,
version_2_5_99_1,
version_2_5_99_0,
version_2_5_2,
version_2_5_1,
version_2_5_0,
version_2_4_99_0,
HEAD,
GCI_1,
BZ5434-fox
- BUG#5306, turn off navmaps folder eliding for SPRS
1: #
2: # $Id: studentcalc.pm,v 1.43 2007/07/06 19:50: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: use LONCAPA;
63:
64:
65: @Apache::studentcalc::ISA = ('Apache::Spreadsheet');
66:
67: my @Sequences = ();
68: my $navmap;
69: my %Exportrows = ();
70:
71: my $current_course;
72:
73: sub initialize {
74: &initialize_sequence_cache();
75: &Apache::assesscalc::initialize($navmap);
76: }
77:
78: sub initialize_package {
79: $current_course = $env{'request.course.id'};
80: &initialize_sequence_cache();
81: &load_cached_export_rows();
82: }
83:
84: sub ensure_correct_sequence_data {
85: if ($current_course ne $env{'request.course.id'}) {
86: &initialize_sequence_cache();
87: $current_course = $env{'request.course.id'};
88: }
89: return;
90: }
91:
92: sub initialize_sequence_cache {
93: #
94: # Set up the sequences and assessments
95: undef(@Sequences);
96: undef($navmap);
97: $navmap = Apache::lonnavmaps::navmap->new();
98: if (!defined($navmap)) {
99: &Apache::lonnet::logthis('student spreadsheet:Can not open Coursemap');
100: }
101: my @all_sequences = $navmap->retrieveResources(undef,
102: sub { shift->is_map(); },1,0,1);
103: for my $sequence ($navmap->getById('0.0'), @all_sequences) {
104: if ($navmap->hasResource($sequence,sub { shift->is_problem(); }, 0,1)){
105: push(@Sequences,$sequence);
106: &get_resources($sequence);
107: }
108: }
109: }
110:
111: my %res_memoize;
112: sub get_resources {
113: my ($seq) = @_;
114: if (exists($res_memoize{$seq->symb()})) {
115: return @{$res_memoize{$seq->symb()}};
116: }
117: return () if (! defined($navmap) || ! ref($navmap));
118: my @resources = $navmap->retrieveResources($seq,
119: sub { shift->is_problem(); },
120: 0,0,1);
121: $res_memoize{$seq->symb()}=\@resources;
122: return @resources;
123: }
124:
125: sub clear_package {
126: undef(@Sequences);
127: undef(%Exportrows);
128: undef(%res_memoize);
129: undef($navmap);
130: &Apache::assesscalc::clear_package();
131: }
132:
133: sub get_title {
134: my $self = shift;
135: my @title = ();
136: #
137: # Determine the students name
138: my $name = &Apache::loncommon::plainname($self->{'name'},
139: $self->{'domain'});
140: push (@title,$name);
141: push (@title,$self->{'coursedesc'});
142: push (@title,&Apache::lonlocal::locallocaltime(time));
143: return @title;
144: }
145:
146: sub get_html_title {
147: my $self = shift;
148: my ($name,$desc,$time) = $self->get_title();
149: my $title = '<h1>'.$name;
150: if ($env{'user.name'} ne $self->{'name'} &&
151: $env{'user.domain'} ne $self->{'domain'}) {
152: $title .= ' '.&Apache::loncommon::aboutmewrapper
153: ($self->{'name'}.'@'.$self->{'domain'},
154: $self->{'name'},$self->{'domain'});
155: }
156: $title .= "</h1>\n";
157: $title .= '<h2>'.$desc."</h2>\n";
158: $title .= '<h3>'.$time.'</h3>';
159: return $title;
160: }
161:
162: sub parent_link {
163: my $self = shift;
164: return '<p><a href="/adm/classcalc">'.&mt('Course level sheet').'</a></p>'."\n";
165: }
166:
167: sub convenience_links {
168: my $self = shift;
169: my ($resource) = @_;
170: my $result=&Apache::loncommon::submlink('<img src="/adm/lonMisc/subm_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->symb,'LONcatInfo');
171: $result .= &Apache::loncommon::pgrdlink('<img src="/adm/lonMisc/pgrd_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->symb,'LONcatInfo');
172: $result .= &Apache::loncommon::pprmlink('<img src="/adm/lonMisc/pprm_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->symb,'LONcatInfo');
173: return $result;
174: }
175:
176: sub outsheet_html {
177: my $self = shift;
178: my ($r) = @_;
179: my $importcolor = '#FFFFAA';
180: my $exportcolor = '#88FF88';
181: ####################################
182: # Get the list of assessment files #
183: ####################################
184: my @AssessFileNames = $self->othersheets('assesscalc');
185: my $editing_is_allowed = &Apache::lonnet::allowed('mgr',
186: $env{'request.course.id'});
187: ####################################
188: # Report any calculation errors #
189: ####################################
190: $r->print($self->html_report_error());
191: ####################################
192: # Determine table structure #
193: ####################################
194: my $num_uneditable = 26;
195: my $num_left = 52-$num_uneditable;
196: my %lt=&Apache::lonlocal::texthash(
197: 'st' => 'Student',
198: 'im' => 'Import',
199: 'ca' => 'Calculations',
200: 'as' => 'Assessment',
201: 'ro' => 'Row',
202: );
203: my $tableheader =<<"END";
204: <p>
205: <table border="2">
206: <tr>
207: <th colspan="2" rowspan="2"><font size="+2">$lt{'st'}</font></th>
208: <td bgcolor="$importcolor" colspan="$num_uneditable">
209: <b><font size="+1">$lt{'im'}</font></b></td>
210: <td colspan="$num_left">
211: <b><font size="+1">$lt{'ca'}</font></b></td>
212: </tr><tr>
213: END
214: my $label_num = 0;
215: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
216: if ($label_num<$num_uneditable) {
217: $tableheader .='<td bgcolor="'.$importcolor.'">';
218: } else {
219: $tableheader .='<td>';
220: }
221: $tableheader .="<b><font size=+1>$_</font></b></td>";
222: $label_num++;
223: }
224: $tableheader .="</tr>\n";
225: if ($self->blackout()) {
226: $r->print('<font color="red" size="+2"><p>'.
227: &mt('Some computations are not available at this time.').'<br />'.
228: &mt('There are problems whose status you are not allowed to view.').
229: '</font></p>'."\n");
230: } else {
231: $r->print($tableheader);
232: #
233: # Print out template row
234: if (exists($env{'request.role.adv'}) && $env{'request.role.adv'}) {
235: $r->print('<tr><td>Template</td><td> </td>'.
236: $self->html_template_row($num_uneditable,
237: $importcolor)."</tr>\n");
238: }
239: #
240: # Print out summary/export row
241: $r->print('<tr><td>'.&mt('Summary').'</td><td>0</td>'.
242: $self->html_export_row($exportcolor)."</tr>\n");
243: }
244: $r->print("</table>\n");
245: #
246: # Prepare to output rows
247: if (exists($env{'request.role.adv'}) && $env{'request.role.adv'}) {
248: $tableheader =<<"END";
249: </p><p>
250: <table border="2">
251: <tr><th>$lt{'ro'}</th><th> </th><th>$lt{'as'}</th>
252: END
253: } else {
254: $tableheader =<<"END";
255: </p><p>
256: <table border="2">
257: <tr><th> </th><th>$lt{'as'}</th>
258: END
259: }
260: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
261: if ($label_num<$num_uneditable) {
262: $tableheader.='<td bgcolor="#FFDDDD">';
263: } else {
264: $tableheader.='<td>';
265: }
266: $tableheader.="<b><font size=+1>$_</font></b></td>";
267: }
268: $tableheader.="\n";
269: #
270: my $num_output = 1;
271: if (scalar(@Sequences)< 1) {
272: &initialize_sequence_cache();
273: }
274: foreach my $Sequence (@Sequences) {
275: $r->print("<h3>".$Sequence->compTitle."</h3>\n");
276:
277: my @resources = &get_resources($Sequence);
278: my $first_rownum =
279: $self->get_row_number_from_key($resources[0]->symb);
280: my $last_rownum =
281: $self->get_row_number_from_key($resources[-1]->symb);
282: $r->print(&assess_file_selector([$first_rownum, $last_rownum],
283: undef, \@AssessFileNames));
284:
285: $r->print($tableheader);
286: foreach my $resource (@resources) {
287: my $rownum = $self->get_row_number_from_key($resource->symb);
288: my $assess_filename = $self->{'row_source'}->{$rownum};
289: my $row_output = '<tr>';
290: if ($editing_is_allowed) {
291: $row_output .= '<td>'.$rownum.'</td>';
292: $row_output .= '<td>'.$self->convenience_links($resource).'</td>';
293: $row_output .= '<td>'.
294: '<a href="/adm/assesscalc?sname='.$self->{'name'}.
295: '&sdomain='.$self->{'domain'}.
296: '&filename='.$assess_filename.
297: '&usymb='.&escape($resource->symb).
298: '">'.$resource->compTitle.'</a><br />';
299: $row_output .= &assess_file_selector($rownum,
300: $assess_filename,
301: \@AssessFileNames).
302: '</td>';
303: } else {
304: $row_output .= '<td><a href="'.$resource->src.'?symb='.
305: &escape($resource->symb).
306: '">Go To</a>';
307: $row_output .= '</td><td>'.$resource->compTitle.'</td>';
308: }
309: if ($self->blackout() && $self->{'blackout_rows'}->{$rownum}>0) {
310: $row_output .=
311: '<td colspan="52">'.&mt('Unavailable at this time').'</td></tr>'."\n";
312: } else {
313: $row_output .= $self->html_row($num_uneditable,$rownum,
314: $exportcolor,$importcolor).
315: "</tr>\n";
316: }
317: $r->print($row_output);
318: }
319: $r->print("</table>\n");
320: }
321: $r->print("</p>\n");
322: return;
323: }
324:
325: ########################################################
326: ########################################################
327:
328: =pod
329:
330: =item &assess_file_selector()
331:
332: =cut
333:
334: ########################################################
335: ########################################################
336: sub assess_file_selector {
337: my ($row,$default,$AssessFiles)=@_;
338: if (!defined($AssessFiles) || ! @$AssessFiles) {
339: return '';
340: }
341: return '' if (! &Apache::lonnet::allowed('mgr',$env{'request.course.id'}));
342: my $element_name;
343: my $source_row = $row;
344: if (ref($row)) {
345: my ($first_rownum, $last_rownum) = @$row;
346: $element_name = "FileSelect_${first_rownum}_${last_rownum}";
347: $source_row = "${first_rownum}:${last_rownum}";
348: } else {
349: $element_name = 'FileSelect_'.$row;
350: }
351: my $load_dialog = '<select size="1" name="'.$element_name.'" '.
352: 'onchange="'.
353: "document.sheet.cell.value='source_${source_row}';".
354: "document.sheet.newformula.value=document.sheet.$element_name\.value;".
355: 'document.sheet.submit()" '.'>'."\n";
356: if (ref($row)) {
357: $load_dialog .= ' <option name="" value="">' .
358: &mt("Select spreadsheet for entire sequence")
359: . "</option>\n";
360: }
361: foreach my $file (@{$AssessFiles}) {
362: $load_dialog .= ' <option name="'.$file.'"';
363: $load_dialog .= ' selected' if ($default eq $file);
364: $load_dialog .= '>'.$file."</option>\n";
365: }
366: $load_dialog .= "</select>\n";
367: return $load_dialog;
368: }
369:
370: sub modify_cell {
371: my $self = shift;
372: my ($cell,$formula) = @_;
373:
374: my $set_row = sub {
375: my $row = shift;
376: my $formula = shift;
377: my $cell = 'A' . $row;
378: $self->{'row_source'}->{$row} = $formula;
379: my $original_source = $self->formula($cell);
380: if ($original_source =~ /__&&&__/) {
381: ($original_source,undef) = split('__&&&__',$original_source);
382: }
383: $formula = $original_source.'__&&&__'.$formula;
384: $self->set_formula($cell,$formula);
385: };
386:
387: if ($cell =~ /^source_(\d+):(\d+)$/) {
388: my $first_row = $1;
389: my $last_row = $2;
390: for my $row ($first_row..$last_row) {
391: $set_row->($row, $formula);
392: }
393: } elsif ($cell =~ /^source_(\d+)$/) {
394: # Need to make sure $formula is a valid filename....
395: my $row = $1;
396: $set_row->($row, $formula);
397: } elsif ($cell =~ /([A-z])\-/) {
398: $cell = 'template_'.$1;
399: $self->set_formula($cell,$formula);
400: } elsif ($cell !~ /^([A-z](\d+)|template_[A-z])$/) {
401: return;
402: } else {
403: $self->set_formula($cell,$formula);
404: }
405: $self->rebuild_stats();
406: return;
407: }
408:
409: sub csv_rows {
410: # writes the meat of the spreadsheet to an excel worksheet. Called
411: # by Spreadsheet::outsheet_excel;
412: my $self = shift;
413: my ($connection,$filehandle) = @_;
414: #
415: # Write a header row
416: $self->csv_output_row($filehandle,undef,
417: (&mt('Sequence or Folder'),&mt('Assessment title')));
418: #
419: # Write each assessments row
420: if (scalar(@Sequences)< 1) {
421: &initialize_sequence_cache();
422: }
423: foreach my $Sequence (@Sequences) {
424: foreach my $resource (&get_resources($Sequence)) {
425: my $rownum = $self->get_row_number_from_key($resource->symb);
426: my @assessdata = ($Sequence->compTitle,
427: $resource->compTitle);
428: $self->csv_output_row($filehandle,$rownum,@assessdata);
429: }
430: }
431: return;
432: }
433:
434: sub excel_rows {
435: # writes the meat of the spreadsheet to an excel worksheet. Called
436: # by Spreadsheet::outsheet_excel;
437: my $self = shift;
438: my ($connection,$worksheet,$cols_output,$rows_output,$format) = @_;
439: #
440: # Write a header row
441: $cols_output = 0;
442: foreach my $value ('Container','Assessment title') {
443: $worksheet->write($rows_output,$cols_output++,&mt($value),$format->{'h4'});
444: }
445: $rows_output++;
446: #
447: # Write each assessments row
448: if (scalar(@Sequences)< 1) {
449: &initialize_sequence_cache();
450: }
451: foreach my $Sequence (@Sequences) {
452: foreach my $resource (&get_resources($Sequence)) {
453: my $rownum = $self->get_row_number_from_key($resource->symb);
454: my @assessdata = ($Sequence->compTitle,
455: $resource->compTitle);
456: $self->excel_output_row($worksheet,$rownum,$rows_output++,
457: @assessdata);
458: }
459: }
460: return;
461: }
462:
463: sub outsheet_recursive_excel {
464: my $self = shift;
465: my ($r) = @_;
466: }
467:
468: ##
469: ## Routines to deal with sequences in the safe space
470: ##
471: sub get_rows_in_sequence {
472: my $self = shift();
473: my ($sequence) = @_;
474: my @Rows;
475: my @resources = &get_resources($sequence);
476: foreach my $resource (@resources) {
477: my $rownum = $self->get_row_number_from_key($resource->symb);
478: push (@Rows,$rownum);
479: }
480: return @Rows;
481: }
482:
483: sub remove_sequence_data_from_safe_space {
484: my $self = shift();
485: my $command = 'undef(%Sequence_Rows);';
486: $self->{'safe'}->reval($command);
487: }
488:
489: sub put_sequence_data_in_safe_space {
490: my $self = shift();
491: my $data = 'undef(%Sequence_Rows);';
492: # Build up the %Sequence_Rows hash - each sequence title is associated with
493: # an array pointer, which holds the rows in the sequence.
494: foreach my $seq (@Sequences) {
495: my @Rows = $self->get_rows_in_sequence($seq);
496: #
497: # Potential problems with sequence titles:
498: # 1. duplicate titles - they get the total for the titles
499: # 2. control characters in titles - use q{} around the string to
500: # deal with it.
501: my $title = &HTML::Entities::decode($seq->title());
502: $title =~ s/&\#058;/:/g;
503: if (@Rows) {
504: $data .= 'push(@{$Sequence_Rows{"'.quotemeta($title).'"}},'.
505: '('.join(',',@Rows).'));'."\n";;
506: }
507: }
508: my $new_code = $data.<<'END';
509: sub SUMSEQ {
510: my ($col,@titles) = @_;
511: return 'bad column: '.$col if ($col !~ /^[A-z]$/);
512: my $sum = 0;
513: foreach my $title (@titles) {
514: while (my ($seq_title,$rows) = each(%Sequence_Rows)) {
515: my $regexp;
516: if ($title =~ /^regexp:(.*)$/) {
517: $regexp = $1;
518: } elsif (lc($title) eq 'all') {
519: $regexp = '.';
520: }
521: if (defined($regexp)) {
522: next if ($seq_title !~ /$regexp/);
523: } else {
524: next if ($seq_title ne $title);
525: }
526: foreach my $rownum (@{$rows}) {
527: my $cell = $col.$rownum;
528: if (exists($sheet_values{$cell})) {
529: $sum += $sheet_values{$cell};
530: }
531: }
532: }
533: }
534: return $sum;
535: }
536: END
537: $self->{'safe'}->reval($new_code);
538: return;
539: }
540:
541: ##
542: ## Main computation method
543: ##
544: sub compute {
545: my $self = shift;
546: my ($r) = @_;
547: if (! defined($current_course) ||
548: $current_course ne $env{'request.course.id'} ||
549: ! @Sequences ) {
550: $current_course = $env{'request.course.id'};
551: &clear_package();
552: &initialize_sequence_cache();
553: }
554: $self->initialize_safe_space();
555: &Apache::assesscalc::initialize_package($self->{'name'},$self->{'domain'},
556: $navmap,$self);
557: my %f = $self->formulas();
558: #
559: # Process the formulas list -
560: # the formula for the A column of a row is symb__&&__filename
561: my %c = $self->constants();
562: foreach my $seq (@Sequences) {
563: foreach my $resource (&get_resources($seq)) {
564: my $rownum = $self->get_row_number_from_key($resource->symb);
565: my $cell = 'A'.$rownum;
566: my $assess_filename = 'Default';
567: if (exists($self->{'row_source'}->{$rownum})) {
568: $assess_filename = $self->{'row_source'}->{$rownum};
569: } else {
570: $self->{'row_source'}->{$rownum} = $assess_filename;
571: }
572: $f{$cell} = $resource->symb.'__&&&__'.$assess_filename;
573: my $assessSheet;
574: $assessSheet = Apache::assesscalc->new($self->{'name'},
575: $self->{'domain'},
576: $assess_filename,
577: $resource->symb,
578: $self->{'section'},
579: $self->{'groups'});
580: my @exportdata = $assessSheet->export_data($r);
581: #
582: if ($assessSheet->badcalc()) {
583: $self->set_calcerror(
584: &mt('Error computing row for assessment "[_1]" (row [_2]):[_3]',
585: $assessSheet->get_title(),$rownum,$assessSheet->calcerror()));
586: }
587: #
588: if ($assessSheet->blackout()) {
589: $self->blackout(1);
590: $self->{'blackout_rows'}->{$rownum} = 1;
591: }
592: #
593: # Be sure not to disturb the formulas in the 'A' column
594: my $data = shift(@exportdata);
595: $c{$cell} = $data if (defined($data));
596: #
597: # Deal with the remaining columns
598: my $i=0;
599: foreach (split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ')) {
600: my $cell = $_.$rownum;
601: my $data = shift(@exportdata);
602: if (defined($data)) {
603: $f{$cell} = 'import';
604: $c{$cell} = $data;
605: }
606: $i++;
607: }
608: }
609: }
610: $self->constants(\%c);
611: $self->formulas(\%f);
612: $self->put_sequence_data_in_safe_space();
613: $self->calcsheet();
614: $self->remove_sequence_data_from_safe_space();
615: #
616: # Store export row in cache
617: my @exportarray=$self->exportrow();
618: my $student = $self->{'name'}.':'.$self->{'domain'};
619: $Exportrows{$student}->{'time'} = time;
620: $Exportrows{$student}->{'data'} = \@exportarray;
621: # save export row
622: $self->save_export_data();
623: #
624: $self->save() if ($self->need_to_save());
625: return;
626: }
627:
628: sub set_row_sources {
629: my $self = shift;
630: $self->check_formulas_loaded();
631: while (my ($cell,$value) = each(%{$self->{'formulas'}})) {
632: next if ($cell !~ /^A(\d+)$/ || $1 < 1);
633: my $row = $1;
634: (undef,$value) = split('__&&&__',$value);
635: $value = 'Default' if (! defined($value));
636: $self->{'row_source'}->{$row} = $value;
637: }
638: return;
639: }
640:
641: sub set_row_numbers {
642: my $self = shift;
643: $self->check_formulas_loaded();
644: while (my ($cell,$formula) = each(%{$self->{'formulas'}})) {
645: next if ($cell !~ /^A(\d+)/);
646: my $row = $1;
647: next if ($row == 0);
648: my ($symb,undef) = split('__&&&__',$formula);
649: $self->{'row_numbers'}->{$symb} = $row;
650: $self->{'maxrow'} = $row if ($row > $self->{'maxrow'});
651: }
652: }
653:
654: sub get_row_number_from_symb {
655: my $self = shift;
656: my ($key) = @_;
657: ($key,undef) = split('__&&&__',$key) if ($key =~ /__&&&__/);
658: return $self->get_row_number_from_key($key);
659: }
660:
661: #############################################
662: #############################################
663:
664: =pod
665:
666: =item &load_cached_export_rows
667:
668: Retrieves and parsers the export rows of the student spreadsheets.
669: These rows are saved in the courses directory in the format:
670:
671: sname:sdom:studentcalc:.time => time
672:
673: sname:sdom:studentcalc => ___=___Adata___;___Bdata___;___Cdata___;___ .....
674:
675: =cut
676:
677: #############################################
678: #############################################
679: sub load_cached_export_rows {
680: undef(%Exportrows);
681: my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets',
682: $env{'course.'.$env{'request.course.id'}.'.domain'},
683: $env{'course.'.$env{'request.course.id'}.'.num'},undef);
684: my %Selected_Assess_Sheet;
685: if ($tmp[0] =~ /^error/) {
686: &Apache::lonnet::logthis('unable to read cached student export rows '.
687: 'for course '.$env{'request.course.id'});
688: return;
689: }
690: my %tmp = @tmp;
691: while (my ($key,$sheetdata) = each(%tmp)) {
692: my ($sname,$sdom,$sheettype,$remainder) = split(':',$key);
693: my $student = $sname.':'.$sdom;
694: if ($remainder =~ /\.time/) {
695: $Exportrows{$student}->{'time'} = $sheetdata;
696: } else {
697: $sheetdata =~ s/^___=___//;
698: my @Data = split('___;___',$sheetdata);
699: $Exportrows{$student}->{'data'} = \@Data;
700: }
701: }
702: }
703:
704: #############################################
705: #############################################
706:
707: =pod
708:
709: =item &save_export_data()
710:
711: Writes the export data for this student to the course cache.
712:
713: =cut
714:
715: #############################################
716: #############################################
717: sub save_export_data {
718: my $self = shift;
719: my $student = $self->{'name'}.':'.$self->{'domain'};
720: return if ($self->temporary());
721: if ($self->badcalc()){
722: # do not save data away when calculations have not been done properly.
723: delete($Exportrows{$student});
724: return;
725: }
726: return if (! exists($Exportrows{$student}));
727: &Apache::assesscalc::save_cached_export_rows($self->{'name'},
728: $self->{'domain'});
729: return if (! $self->is_default());
730: my $key = join(':',($self->{'name'},$self->{'domain'},'studentcalc')).':';
731: my $timekey = $key.'.time';
732: my $newstore = join('___;___',
733: @{$Exportrows{$student}->{'data'}});
734: $newstore = '___=___'.$newstore;
735: my $result= &Apache::lonnet::put('nohist_calculatedsheets',
736: { $key => $newstore,
737: $timekey => $Exportrows{$student}->{'time'} },
738: $self->{'cdom'},
739: $self->{'cnum'});
740: return;
741: }
742:
743: #############################################
744: #############################################
745:
746: =pod
747:
748: =item &export_data()
749:
750: Returns the export data associated with the spreadsheet. Computes the
751: spreadsheet only if necessary.
752:
753: =cut
754:
755: #############################################
756: #############################################
757: sub export_data {
758: my $self = shift;
759: my ($r) = @_;
760: my $connection = $r->connection();
761: my $student = $self->{'name'}.':'.$self->{'domain'};
762: if (! exists($Exportrows{$student}) ||
763: ! defined($Exportrows{$student}) ||
764: ! exists($Exportrows{$student}->{'data'}) ||
765: ! defined($Exportrows{$student}->{'data'}) ||
766: ! exists($Exportrows{$student}->{'time'}) ||
767: ! defined($Exportrows{$student}->{'time'}) ||
768: ! $self->check_expiration_time($Exportrows{$student}->{'time'})) {
769: $self->compute($r);
770: }
771: if ($connection->aborted()) { $self->cleanup(); return; }
772: my @Data;
773: if ($self->badcalc()) {
774: @Data = ();
775: } else {
776: @Data = @{$Exportrows{$student}->{'data'}};
777: for (my $i=0; $i<=$#Data;$i++) {
778: if ($Data[$i]=~/\D/ && defined($Data[$i])) {
779: $Data[$i]="'".$Data[$i]."'";
780: }
781: }
782: }
783: return @Data;
784: }
785:
786: 1;
787:
788: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>