1: #
2: # $Id: classcalc.pm,v 1.31 2011/12/21 21:25:46 www 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: classcalc
34:
35: =head1 SYNOPSIS
36:
37: =head1 DESCRIPTION
38:
39: =over 4
40:
41: =cut
42:
43: ###################################################
44: ### CourseSheet ###
45: ###################################################
46: package Apache::classcalc;
47:
48: use strict;
49: use warnings FATAL=>'all';
50: no warnings 'uninitialized';
51: use Apache::Constants qw(:common :http);
52: use Apache::loncoursedata();
53: use Apache::lonhtmlcommon();
54: use Apache::Spreadsheet;
55: use Apache::studentcalc;
56: use Apache::lonstatistics();
57: use HTML::Entities();
58: use Spreadsheet::WriteExcel;
59: use Apache::lonnet;
60: use Time::HiRes;
61: use Apache::lonlocal;
62:
63: @Apache::classcalc::ISA = ('Apache::Spreadsheet');
64:
65: ##
66: ## Package variable
67: ##
68:
69: my @Students;
70:
71: sub initialize {
72: &Apache::lonstatistics::clear_classlist_variables();
73: @Students = &Apache::lonstatistics::get_students();
74: return;
75: }
76:
77: sub clear_package {
78: undef(@Students);
79: &Apache::studentcalc::clear_package();
80: }
81:
82: sub html_header {
83: my $self = shift;
84: my ($toprow,$bottomrow);
85: &Apache::lonstatistics::clear_classlist_variables();
86: foreach (['Sections',&Apache::lonstatistics::SectionSelect('Section','multiple',3)],
87: ['Groups',&Apache::lonstatistics::GroupSelect('Group','multiple',3)],
88: ['Access Status',&Apache::lonhtmlcommon::StatusOptions(undef,undef,3)],
89: ['Output Format',$self->output_selector()]) {
90: my ($name,$selector) = @{$_};
91: $toprow .= '<th align="center"><b>'.&mt($name).'</b></th>';
92: $bottomrow .= '<td>'.$selector.'</td>';
93: }
94: return "<p>\n<table>\n".
95: "<tr>".$toprow."</tr>\n".
96: "<tr>".$bottomrow."</tr>\n".
97: "</table>\n".
98: "</p>";
99: }
100:
101: sub get_title {
102: my $self = shift;
103: # Section info should be included
104: my @title = ($self->{'coursedesc'}, &Apache::lonlocal::locallocaltime(time) );
105: return @title;
106: }
107:
108: sub get_html_title {
109: my $self = shift;
110: my ($classcalc_title,$time) = $self->get_title();
111: my $title = '<h1>'.$classcalc_title."</h1>\n".'<h3>'.$time."</h3>\n";
112: return $title;
113: }
114:
115: sub parent_link {
116: return '';
117: }
118:
119: sub outsheet_html {
120: my $self = shift;
121: my ($r) = @_;
122: ####################################
123: # Report any calculation errors #
124: ####################################
125: $r->print($self->html_report_error());
126: ###################################
127: # Determine table structure
128: ###################################
129: my $importcolor = '#88FF88';
130: my $exportcolor = '#BBBBFF';
131: my $num_uneditable = 26;
132: my $num_left = 52-$num_uneditable;
133: #
134: my %header=&Apache::lonlocal::texthash(
135: 'course' => 'Course',
136: 'import' => 'Import',
137: 'calculations' => 'Calculations',
138: 'student' => 'Student',
139: 'status' => 'Status',
140: 'username' => 'Username',
141: 'domain' => 'Domain',
142: 'section' => 'Section',
143: 'groups' => 'Groups',
144: 'row' => 'Row',
145: );
146: my $tableheader =<<"END";
147: <p>
148: <table border="2">
149: <tr>
150: <th colspan="2" rowspan="2"><font size="+2">$header{'course'}</font></th>
151: <td bgcolor="$importcolor" colspan="$num_uneditable">
152: <b><font size="+1">$header{'import'}</font></b></td>
153: <td colspan="$num_left">
154: <b><font size="+1">$header{'calculations'}</font></b></td>
155: </tr><tr>
156: END
157: my $label_num = 0;
158: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
159: if ($label_num<$num_uneditable) {
160: $tableheader.='<th bgcolor="'.$importcolor.'">';
161: } else {
162: $tableheader.='<th>';
163: }
164: $tableheader.="<b><font size=+1>$_</font></b></th>";
165: $label_num++;
166: }
167: $tableheader.="</tr>\n";
168: #
169: $r->print($tableheader);
170: #
171: # Print out template row
172: $r->print('<tr><td>'.&mt('Template').'</td><td> </td>'.
173: $self->html_template_row($num_uneditable,$importcolor).
174: "</tr>\n");
175: #
176: # Print out summary/export row
177: $r->print('<tr><td>'.&mt('Summary').'</td><td>0</td>'.
178: $self->html_export_row($exportcolor)."</tr>\n");
179: #
180: # Prepare to output rows
181: $tableheader =<<"END";
182: </p><p>
183: <table border="2">
184: <tr><th>$header{'row'}</th>
185: <th>$header{'student'}</th>
186: <th>$header{'username'}</th>
187: <th>$header{'domain'}</th>
188: <th>$header{'section'}</th>
189: <th>$header{'groups'}</th>
190: <th>$header{'status'}</th>
191: END
192: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
193: if ($label_num<$num_uneditable) {
194: $tableheader.='<th bgcolor="'.$importcolor.'">';
195: } else {
196: $tableheader.='<th>';
197: }
198: $tableheader.="<b><font size=+1>$_</font></b></th>";
199: }
200: #
201: my $num_output = 0;
202: foreach my $student (@Students) {
203: if ($num_output++ % 50 == 0) {
204: $r->print("</table>\n".$tableheader);
205: }
206: my $rownum = $self->get_row_number_from_key
207: ($student->{'username'}.':'.$student->{'domain'});
208: my $link = '<a href="/adm/studentcalc?sname='.$student->{'username'}.
209: '&sdomain='.$student->{'domain'}.'">';
210: $student->{'section'} = 'none' if ($student->{'section'} eq '-1');
211: $r->print('<tr>'.'<td>'.$rownum.'</td>'.
212: '<td>'.$student->{'fullname'}.'</td>'.
213: '<td>'.$link.$student->{'username'}.'</a></td>'.
214: '<td>'.$student->{'domain'} .'</td>'.
215: '<td>'.$student->{'section'} .'</td>'.
216: '<td>'.$student->{'groups'} .'</td>'.
217: '<td>'.$student->{'status'} .'</td>'.
218: $self->html_row($num_uneditable,$rownum,$exportcolor,
219: $importcolor).
220: "</tr>\n");
221: }
222: $r->print("</table></p>\n");
223: return;
224: }
225:
226: sub excel_rows {
227: # writes the meat of the spreadsheet to an excel worksheet. Called
228: # by Spreadsheet::outsheet_excel;
229: my $self = shift;
230: my ($connection,$worksheet,$cols_output,$rows_output,$format) = @_;
231: #
232: # Write a header row
233: $cols_output = 0;
234: foreach my $value ('Fullname','Username','Domain','Section','Group','Status','ID') {
235: $worksheet->write($rows_output,$cols_output++,&mt($value),$format->{'h4'});
236: }
237: $rows_output++;
238: #
239: # Write each students row
240: foreach my $student (@Students) {
241: $cols_output = 0;
242: my $rownum = $self->get_row_number_from_key
243: ($student->{'username'}.':'.$student->{'domain'});
244: $student->{'section'} = 'none' if ($student->{'section'} eq '-1');
245: my @studentdata = ($student->{'fullname'},
246: $student->{'username'},
247: $student->{'domain'},
248: $student->{'section'},
249: $student->{'groups'},
250: $student->{'status'},
251: $student->{'id'});
252: $self->excel_output_row($worksheet,$rownum,$rows_output++,
253: @studentdata);
254: }
255: return;
256: }
257:
258: sub csv_rows {
259: # writes the meat of the spreadsheet to an excel worksheet. Called
260: # by Spreadsheet::outsheet_excel;
261: my $self = shift;
262: my ($connection,$filehandle) = @_;
263: #
264: # Write a header row
265: $self->csv_output_row($filehandle,undef,
266: (&mt('Fullname'),&mt('Username'),&mt('Domain'),&mt('Section'),&mt('Group'),&mt('Status'),&mt('ID')));
267: #
268: # Write each students row
269: foreach my $student (@Students) {
270: my $rownum = $self->get_row_number_from_key
271: ($student->{'username'}.':'.$student->{'domain'});
272: $student->{'section'} = 'none' if ($student->{'section'} eq '-1');
273: my @studentdata = ($student->{'fullname'},
274: $student->{'username'},
275: $student->{'domain'},
276: $student->{'section'},
277: $student->{'groups'},
278: $student->{'status'},
279: $student->{'id'});
280: $self->csv_output_row($filehandle,$rownum,@studentdata);
281: }
282: return;
283: }
284:
285: sub output_options {
286: my $self = shift();
287: return ({value => 'htmlclasslist',
288: description => 'Student Sheet Links'},
289: {value => 'source',
290: description => 'Show Source'},
291: {value => 'html',
292: description => 'HTML'},
293: {value => 'excel',
294: description => 'Excel'},
295: {value => 'csv',
296: description => 'Comma Separated Values'},
297: # {value => 'xml',
298: # description => 'XML'},
299: );
300: }
301:
302: sub outsheet_recursive_excel {
303: my $self = shift;
304: my ($r) = @_;
305: }
306:
307: sub outsheet_htmlclasslist {
308: my $self = shift;
309: my ($r) = @_;
310: #
311: # Determine if we should output expire caches links...
312: my $show_expire_link = 0;
313: if (exists($env{'user.role.dc./'.$env{'request.role.domain'}.'/'})){
314: $show_expire_link = 1;
315: }
316: #
317: if ($show_expire_link) {
318: $r->print('<a href="/adm/classcalc?output_format=htmlclasslist&'.
319: 'recalc=expireallsheets¬_first_run=1">'.
320: &mt('Expire all student spreadsheets').'</a>'.$/);
321: }
322: #
323: $r->print('<h3>'.
324: &mt('Click on a student to be taken to their spreadsheet').
325: '</h3>');
326: #
327: my %header=&Apache::lonlocal::texthash(
328: 'student' => 'Student',
329: 'status' => 'Status',
330: 'username' => 'Username',
331: 'domain' => 'Domain',
332: 'section' => 'Section',
333: 'groups' => 'Groups',
334: );
335: #
336: # Prepare to output rows
337: my $tableheader =<<"END";
338: </p><p>
339: <table border="2">
340: <tr>
341: <th></th>
342: <th>$header{'student'}</th>
343: <th>$header{'username'}</th>
344: <th>$header{'domain'}</th>
345: <th>$header{'section'}</th>
346: <th>$header{'groups'}</th>
347: <th>$header{'status'}</th>
348: END
349: if ($show_expire_link) {
350: $tableheader.= '<th> </th>';
351: }
352: $tableheader.= "</tr>\n";
353: #
354: my $num_output = 0;
355: foreach my $student (@Students) {
356: if ($num_output++ % 50 == 0) {
357: $r->print("</table>\n".$tableheader);
358: }
359: my $link = '<a href="/adm/studentcalc?sname='.$student->{'username'}.
360: '&sdomain='.$student->{'domain'}.'">';
361: $student->{'section'} = 'none' if ($student->{'section'} eq '-1');
362: $r->print('<tr>'.
363: '<td>'.$num_output.'</td>'.
364: '<td>'.$link.$student->{'fullname'}.'</a></td>'.
365: '<td>'.$link.$student->{'username'}.'</a></td>'.
366: '<td>'.$student->{'domain'} .'</td>'.
367: '<td>'.$student->{'section'} .'</td>'.
368: '<td>'.$student->{'groups'} .'</td>'.
369: '<td>'.$student->{'status'} .'</td>');
370: if ($show_expire_link) {
371: $r->print('<td>'.
372: '<a href="/adm/classcalc?recalc=student:'.
373: $student->{'username'}.':'.$student->{'domain'}.'&'.
374: 'output_format=htmlclasslist&'.
375: 'not_first_run=1'.'">Expire Record</a>'.$/);
376: }
377: $r->print("</tr>\n");
378: }
379: $r->print("</table></p>\n");
380: return;
381: }
382:
383: sub compute {
384: my $self = shift;
385: my ($r) = @_;
386: my $connection = $r->connection();
387: if ($connection->aborted()) { $self->cleanup(); return; }
388: $self->initialize_safe_space();
389: my %c = $self->constants();
390: my %f = $self->formulas();
391: &Apache::studentcalc::initialize_package();
392: my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,scalar(@Students));
393: &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Processing first student'));
394: foreach my $student (@Students) {
395: if ($connection->aborted()) { $self->cleanup(); return; }
396: my $sname = $student->{'username'}.':'.$student->{'domain'};
397: my $studentsheet = Apache::studentcalc->new
398: ($student->{'username'},$student->{'domain'},undef,undef,
399: $student->{'section'},$student->{'groupref'} );
400: if ($connection->aborted()) { $self->cleanup(); return; }
401: my @exportdata = $studentsheet->export_data($r);
402: if ($studentsheet->badcalc()) {
403: $self->set_calcerror($sname.' : '.
404: $studentsheet->calcerror());
405: }
406: if ($connection->aborted()) { $self->cleanup(); return; }
407: my $rownum = $self->get_row_number_from_key($sname);
408: $f{'A'.$rownum} = $sname;
409: $self->{'row_source'}->{$rownum} = $sname;
410: $c{'A'.$rownum} = shift(@exportdata);
411: foreach (split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ')) {
412: my $cell = $_.$rownum;
413: my $data = shift(@exportdata);
414: if (defined($data)) {
415: $f{$cell} = 'import';
416: $c{$cell} = $data;
417: }
418: }
419: &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last student');
420: }
421: &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
422: $r->rflush();
423: $self->constants(\%c);
424: $self->formulas(\%f);
425: $self->calcsheet();
426: $self->save() if ($self->need_to_save());
427: }
428:
429: 1;
430:
431: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>