Annotation of loncom/interface/lonstatistics.pm, revision 1.68
1.1 albertel 1: # The LearningOnline Network with CAPA
2: #
1.68 ! matthew 3: # $Id: lonstatistics.pm,v 1.67 2003/04/21 15:12:37 matthew Exp $
1.1 albertel 4: #
5: # Copyright Michigan State University Board of Trustees
6: #
7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
8: #
9: # LON-CAPA is free software; you can redistribute it and/or modify
10: # it under the terms of the GNU General Public License as published by
11: # the Free Software Foundation; either version 2 of the License, or
12: # (at your option) any later version.
13: #
14: # LON-CAPA is distributed in the hope that it will be useful,
15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: # GNU General Public License for more details.
18: #
19: # You should have received a copy of the GNU General Public License
20: # along with LON-CAPA; if not, write to the Free Software
21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22: #
23: # /home/httpd/html/adm/gpl.txt
24: #
25: # http://www.lon-capa.org/
26: #
27: # (Navigate problems for statistical reports
1.14 minaeibi 28: #
1.1 albertel 29: ###
30:
1.59 matthew 31: =pod
32:
33: =head1 NAME
34:
35: lonstatistics
36:
37: =head1 SYNOPSIS
38:
39: Main handler for statistics and chart.
40:
41: =head1 PACKAGES USED
42:
1.60 matthew 43: use strict;
44: use Apache::Constants qw(:common :http);
45: use Apache::lonnet();
46: use Apache::lonhomework;
47: use Apache::loncommon;
48: use Apache::loncoursedata;
49: use Apache::lonhtmlcommon;
50: use Apache::lonproblemanalysis;
51: use Apache::lonproblemstatistics;
52: use Apache::lonstudentassessment;
53: use Apache::lonpercentage;
1.66 matthew 54: use Apache::lonmysql;
1.59 matthew 55: =over 4
56:
57: =cut
58:
1.55 minaeibi 59: package Apache::lonstatistics;
1.1 albertel 60:
1.30 stredwic 61: use strict;
1.1 albertel 62: use Apache::Constants qw(:common :http);
1.61 matthew 63: use vars qw(
64: @FullClasslist
65: @Students
66: @Sections
67: @SelectedSections
68: %StudentData
69: @StudentDataOrder
70: @SelectedStudentData
71: $top_map
72: @Sequences
73: @SelectedMaps
74: @Assessments);
75:
1.1 albertel 76: use Apache::lonnet();
77: use Apache::lonhomework;
1.12 minaeibi 78: use Apache::loncommon;
1.29 stredwic 79: use Apache::loncoursedata;
80: use Apache::lonhtmlcommon;
1.61 matthew 81: use Apache::lonproblemanalysis();
82: use Apache::lonproblemstatistics();
83: use Apache::lonstudentassessment();
1.49 stredwic 84: use Apache::lonpercentage;
1.66 matthew 85: use Apache::lonmysql;
1.65 matthew 86: use Time::HiRes;
1.60 matthew 87:
88: #######################################################
89: #######################################################
90:
91: =pod
92:
93: =item Package Variables
94:
95: =item @FullClasslist The full classlist
96:
97: =item @Students The students we are concerned with for this invocation
98:
99: =item @Sections The sections available in this class
100:
101: =item $curr_student The student currently being examined
102:
103: =item $prev_student The student previous in the classlist
104:
105: =item $next_student The student next in the classlist
106:
107: =over
108:
109: =cut
110:
111: #######################################################
112: #######################################################
113: #
114: # Classlist variables
115: #
1.59 matthew 116: my $curr_student;
117: my $prev_student;
118: my $next_student;
119:
120: #######################################################
121: #######################################################
122:
123: =pod
124:
125: =item &clear_classlist_variables()
126:
127: undef the following package variables:
128:
129: =over
130:
1.60 matthew 131: =item @FullClasslist
132:
133: =item @Students
1.59 matthew 134:
1.60 matthew 135: =item @Sections
1.59 matthew 136:
1.60 matthew 137: =item @SelectedSections
1.59 matthew 138:
1.61 matthew 139: =item %StudentData
140:
141: =item @StudentDataOrder
142:
143: =item @SelectedStudentData
144:
1.60 matthew 145: =item $curr_student
1.59 matthew 146:
1.60 matthew 147: =item $prev_student
1.59 matthew 148:
1.60 matthew 149: =item $next_student
1.59 matthew 150:
151: =back
152:
153: =cut
154:
155: #######################################################
156: #######################################################
157: sub clear_classlist_variables {
158: undef(@FullClasslist);
159: undef(@Students);
160: undef(@Sections);
1.60 matthew 161: undef(@SelectedSections);
1.61 matthew 162: undef(%StudentData);
163: undef(@SelectedStudentData);
1.59 matthew 164: undef($curr_student);
165: undef($prev_student);
166: undef($next_student);
167: }
168:
169: #######################################################
170: #######################################################
171:
172: =pod
173:
174: =item &PrepareClasslist()
175:
176: Build up the classlist information. The classlist information is kept in
177: the following package variables:
178:
179: =over
180:
1.60 matthew 181: =item @FullClasslist
182:
183: =item @Students
1.59 matthew 184:
1.60 matthew 185: =item @Sections
1.59 matthew 186:
1.60 matthew 187: =item @SelectedSections
1.59 matthew 188:
1.61 matthew 189: =item %StudentData
190:
191: =item @SelectedStudentData
192:
1.60 matthew 193: =item $curr_student
1.59 matthew 194:
1.60 matthew 195: =item $prev_student
1.59 matthew 196:
1.60 matthew 197: =item $next_student
1.59 matthew 198:
199: =back
200:
201: $curr_student, $prev_student, and $next_student may not be defined, depending
202: upon the calling context.
203:
204: =cut
205:
206: #######################################################
207: #######################################################
208: sub PrepareClasslist {
209: my $r = shift;
210: my %Sections;
211: &clear_classlist_variables();
212: #
213: # Retrieve the classlist
214: my $cid = $ENV{'request.course.id'};
215: my $cdom = $ENV{'course.'.$cid.'.domain'};
216: my $cnum = $ENV{'course.'.$cid.'.num'};
217: my ($classlist,$field_names) = &Apache::loncoursedata::get_classlist($cid,
218: $cdom,$cnum);
1.60 matthew 219: if (exists($ENV{'form.Section'})) {
1.59 matthew 220: if (ref($ENV{'form.Section'})) {
1.61 matthew 221: @SelectedSections = @{$ENV{'form.Section'}};
222: } elsif ($ENV{'form.Section'} !~ /^\s*$/) {
223: @SelectedSections = ($ENV{'form.Section'});
224: }
225: }
226: @SelectedSections = ('all') if (! @SelectedSections);
227: foreach (@SelectedSections) {
228: if ($_ eq 'all') {
229: @SelectedSections = ('all');
1.59 matthew 230: }
231: }
1.61 matthew 232: #
233: # Set up %StudentData
234: @StudentDataOrder = qw/fullname username domain id section status/;
235: foreach my $field (@StudentDataOrder) {
236: $StudentData{$field}->{'title'} = $field;
1.63 matthew 237: $StudentData{$field}->{'base_width'} = length($field);
1.61 matthew 238: $StudentData{$field}->{'width'} =
239: $StudentData{$field}->{'base_width'};
240: }
241:
1.59 matthew 242: #
1.68 ! matthew 243: # get the status requested
! 244: my $requested_status = 'Active';
! 245: $requested_status = $ENV{'form.Status'} if (exists($ENV{'form.Status'}));
! 246: #
1.59 matthew 247: # Process the classlist
248: while (my ($student,$student_data) = each (%$classlist)) {
249: my $studenthash = ();
250: for (my $i=0; $i< scalar(@$field_names);$i++) {
1.61 matthew 251: my $field = $field_names->[$i];
252: # Store the data
253: $studenthash->{$field}=$student_data->[$i];
254: # Keep track of the width of the fields
255: next if (! exists($StudentData{$field}));
1.63 matthew 256: my $length = length($student_data->[$i]);
1.61 matthew 257: if ($StudentData{$field}->{'width'} < $length) {
258: $StudentData{$field}->{'width'} = $length;
259: }
1.59 matthew 260: }
261: push (@FullClasslist,$studenthash);
262: #
263: # Build up a list of sections
264: my $section = $studenthash->{'section'};
1.60 matthew 265: if (! defined($section) || $section =~/^\s*$/ || $section == -1) {
266: $studenthash->{'section'} = 'none';
267: $section = $studenthash->{'section'};
268: }
1.59 matthew 269: $Sections{$section}++;
270: #
271: # Only put in the list those students we are interested in
1.60 matthew 272: foreach my $sect (@SelectedSections) {
1.68 ! matthew 273: if ( (($sect eq 'all') ||
! 274: ($section eq $sect)) &&
! 275: (($studenthash->{'status'} eq $requested_status) ||
! 276: ($requested_status eq 'Any'))
! 277: ){
1.60 matthew 278: push (@Students,$studenthash);
279: last;
280: }
1.59 matthew 281: }
282: }
283: #
284: # Put the consolidated section data in the right place
1.60 matthew 285: @Sections = sort {$a cmp $b} keys(%Sections);
1.61 matthew 286: unshift(@Sections,'all'); # Put 'all' at the front of the list
1.59 matthew 287: #
288: # Sort the Students
289: my $sortby = 'fullname';
1.60 matthew 290: $sortby = $ENV{'form.sort'} if (exists($ENV{'form.sort'}));
291: my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} ||
292: $a->{'fullname'} cmp $b->{'fullname'} } @Students;
293: @Students = @TmpStudents;
1.59 matthew 294: #
295: # Now deal with that current student thing....
296: if (exists($ENV{'form.StudentAssessmentStudent'})) {
297: my ($current_uname,$current_dom) =
298: split(':',$ENV{'form.StudentAssessmentStudent'});
299: my $i;
300: for ($i = 0; $i<=$#Students; $i++) {
301: next if (($Students[$i]->{'username'} ne $current_uname) ||
302: ($Students[$i]->{'domain'} ne $current_dom));
1.60 matthew 303: $curr_student = $Students[$i];
1.59 matthew 304: last; # If we get here, we have our student.
305: }
306: if ($i == 0) {
307: $prev_student = 'none';
308: } else {
309: $prev_student = $Students[$i-1];
310: }
311: if ($i == $#Students) {
312: $next_student = 'none';
313: } else {
314: $next_student = $Students[$i+1];
315: }
316: }
1.61 matthew 317: #
318: if (exists($ENV{'form.StudentData'})) {
319: if (ref($ENV{'form.StudentData'}) eq 'ARRAY') {
320: @SelectedStudentData = @{$ENV{'form.StudentData'}};
321: } else {
322: @SelectedStudentData = ($ENV{'form.StudentData'});
323: }
324: } else {
325: @SelectedStudentData = ('fullname');
326: }
327: foreach (@SelectedStudentData) {
328: if ($_ eq 'all') {
329: @SelectedStudentData = ('all');
330: last;
331: }
332: }
333: #
334: return;
335: }
336:
337: #######################################################
338: #######################################################
339:
340: =pod
341:
342: =item ¤t_student()
343:
344: Returns a pointer to a hash containing data about the currently
345: selected student.
346:
347: =cut
348:
349: #######################################################
350: #######################################################
351: sub current_student {
352: if (defined($curr_student)) {
353: return $curr_student;
354: } else {
355: return 'All Students';
356: }
357: }
358:
359: #######################################################
360: #######################################################
361:
362: =pod
363:
364: =item &previous_student()
365:
366: Returns a pointer to a hash containing data about the student prior
367: in the list of students. Or something.
368:
369: =cut
370:
371: #######################################################
372: #######################################################
373: sub previous_student {
374: if (defined($prev_student)) {
375: return $prev_student;
376: } else {
377: return 'No Student Selected';
378: }
1.59 matthew 379: }
380:
381: #######################################################
382: #######################################################
1.61 matthew 383:
384: =pod
385:
386: =item &next_student()
387:
388: Returns a pointer to a hash containing data about the next student
389: to be viewed.
390:
391: =cut
392:
393: #######################################################
394: #######################################################
395: sub next_student {
396: if (defined($next_student)) {
397: return $next_student;
398: } else {
399: return 'No Student Selected';
400: }
401: }
1.60 matthew 402:
403: #######################################################
404: #######################################################
405:
406: =pod
407:
408: =item &clear_sequence_variables()
409:
410: =cut
411:
412: #######################################################
413: #######################################################
414: sub clear_sequence_variables {
415: undef($top_map);
416: undef(@Sequences);
417: undef(@Assessments);
418: }
419:
420: #######################################################
421: #######################################################
422:
423: =pod
424:
1.61 matthew 425: =item &SetSelectedMaps($elementname)
426:
427: Sets the @SelectedMaps array from $ENV{'form.'.$elementname};
428:
429: =cut
430:
431: #######################################################
432: #######################################################
433: sub SetSelectedMaps {
434: my $elementname = shift;
435: if (exists($ENV{'form.'.$elementname})) {
436: if (ref($ENV{'form.'.$elementname})) {
437: @SelectedMaps = @{$ENV{'form.'.$elementname}};
438: } else {
439: @SelectedMaps = ($ENV{'form.'.$elementname});
440: }
441: } else {
442: @SelectedMaps = ('all');
443: }
1.64 matthew 444: }
445:
446:
447: #######################################################
448: #######################################################
449:
450: =pod
451:
452: =item &Sequences_with_Assess()
453:
454: Returns an array containing the subset of @Sequences which contain
455: assessments.
456:
457: =cut
458:
459: #######################################################
460: #######################################################
461: sub Sequences_with_Assess {
462: my @Sequences_to_Show;
463: foreach my $map_symb (@SelectedMaps) {
464: foreach my $sequence (@Sequences) {
465: next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
466: next if ($sequence->{'num_assess'} < 1);
467: push (@Sequences_to_Show,$sequence);
468: }
469: }
470: return @Sequences_to_Show;
1.61 matthew 471: }
472:
473: #######################################################
474: #######################################################
475:
476: =pod
477:
1.60 matthew 478: =item &PrepareCourseData($r)
479:
480: =cut
481:
482: #######################################################
483: #######################################################
484: sub PrepareCourseData {
485: my ($r) = @_;
486: &clear_sequence_variables();
1.61 matthew 487: my ($top,$sequences,$assessments) =
488: &Apache::loncoursedata::get_sequence_assessment_data();
1.60 matthew 489: if (! defined($top) || ! ref($top)) {
490: # There has been an error, better report it
491: &Apache::lonnet::logthis('top is undefined');
492: return;
493: }
494: $top_map = $top if (ref($top));
495: @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY');
1.61 matthew 496: @Assessments = @{$assessments} if (ref($assessments) eq 'ARRAY');
497: #
498: # Compute column widths
499: foreach my $seq (@Sequences) {
1.63 matthew 500: my $name_length = length($seq->{'title'});
1.61 matthew 501: my $num_parts = $seq->{'num_assess_parts'};
502: #
503: # The number of columns needed for the summation text:
504: # " 1/5" = 1+3 columns, " 10/99" = 1+5 columns
1.63 matthew 505: my $sum_length = 1+1+2*(length($num_parts));
1.61 matthew 506: my $num_col = $num_parts+$sum_length;
507: if ($num_col < $name_length) {
508: $num_col = $name_length;
509: }
510: $seq->{'base_width'} = $name_length;
511: $seq->{'width'} = $num_col;
512: }
513: return;
514: }
515:
516: #######################################################
517: #######################################################
1.60 matthew 518:
519: =pod
520:
1.61 matthew 521: =item &log_sequence($sequence,$recursive,$padding)
522:
523: Write data about the sequence to a logfile. If $recursive is not
524: undef the data is written recursively. $padding is used for recursive
525: calls.
526:
527: =cut
528:
529: #######################################################
530: #######################################################
531: sub log_sequence {
532: my ($seq,$recursive,$padding) = @_;
533: $padding = '' if (! defined($padding));
534: if (ref($seq) ne 'HASH') {
535: &Apache::lonnet::logthis('log_sequence passed bad sequnce');
536: return;
537: }
538: &Apache::lonnet::logthis($padding.'sequence '.$seq->{'title'});
539: while (my($key,$value) = each(%$seq)) {
540: next if ($key eq 'contents');
541: if (ref($value) eq 'ARRAY') {
542: for (my $i=0;$i< scalar(@$value);$i++) {
543: &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
544: $value->[$i]);
545: }
546: } else {
547: &Apache::lonnet::logthis($padding.$key.'='.$value);
548: }
549: }
550: if (defined($recursive)) {
551: &Apache::lonnet::logthis($padding.'-'x20);
552: &Apache::lonnet::logthis($padding.'contains:');
553: foreach my $item (@{$seq->{'contents'}}) {
554: if ($item->{'type'} eq 'container') {
555: &log_sequence($item,$recursive,$padding.' ');
556: } else {
557: &Apache::lonnet::logthis($padding.'title = '.$item->{'title'});
558: while (my($key,$value) = each(%$item)) {
559: next if ($key eq 'title');
560: if (ref($value) eq 'ARRAY') {
561: for (my $i=0;$i< scalar(@$value);$i++) {
562: &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
563: $value->[$i]);
564: }
565: } else {
566: &Apache::lonnet::logthis($padding.$key.'='.$value);
567: }
568: }
569: }
1.60 matthew 570: }
1.61 matthew 571: &Apache::lonnet::logthis($padding.'end contents of '.$seq->{'title'});
572: &Apache::lonnet::logthis($padding.'-'x20);
1.60 matthew 573: }
1.61 matthew 574: return;
575: }
576:
577: ##############################################
578: ##############################################
579:
580: =pod
581:
582: =item &StudentDataSelect($elementname,$status,$numvisible,$selected)
583:
584: Returns html for a selection box allowing the user to choose one (or more)
585: of the fields of student data available (fullname, username, id, section, etc)
586:
587: =over 4
588:
589: =item $elementname The name of the HTML form element
590:
591: =item $status 'multiple' or 'single' selection box
592:
593: =item $numvisible The number of options to be visible
594:
595: =back
1.60 matthew 596:
597: =cut
598:
1.61 matthew 599: ##############################################
600: ##############################################
601: sub StudentDataSelect {
602: my ($elementname,$status,$numvisible)=@_;
603: if ($numvisible < 1) {
604: return;
605: }
606: #
607: # Build the form element
608: my $Str = "\n";
609: $Str .= '<select name="'.$elementname.'" ';
610: if ($status ne 'single') {
611: $Str .= 'multiple="true" ';
612: }
613: $Str .= 'size="'.$numvisible.'" >'."\n";
614: #
615: # Deal with 'all'
616: $Str .= ' <option value="all" ';
617: foreach (@SelectedStudentData) {
618: if ($_ eq 'all') {
619: $Str .= 'selected ';
620: last;
621: }
622: }
623: $Str .= ">all</option>\n";
624: #
625: # Loop through the student data fields
626: foreach my $item (@StudentDataOrder) {
627: $Str .= ' <option value="'.$item.'" ';
628: foreach (@SelectedStudentData) {
629: if ($item eq $_ ) {
630: $Str .= 'selected ';
631: last;
632: }
633: }
634: $Str .= '>'.$item."</option>\n";
635: }
636: $Str .= "</select>\n";
637: return $Str;
1.60 matthew 638: }
639:
640: ##############################################
641: ##############################################
642:
643: =pod
644:
1.61 matthew 645: =item &MapSelect($elementname,$status,$numvisible,$restriction)
1.60 matthew 646:
647: Returns html for a selection box allowing the user to choose one (or more)
648: of the sequences in the course. The values of the sequences are the symbs.
649: If the top sequence is selected, the value 'top' will result.
650:
651: =over 4
652:
653: =item $elementname The name of the HTML form element
654:
655: =item $status 'multiple' or 'single' selection box
656:
657: =item $numvisible The number of options to be visible
658:
659: =item $restriction Code reference to subroutine which returns true or
660: false. The code must expect a reference to a sequence data structure.
661:
662: =back
663:
664: =cut
665:
666: ##############################################
667: ##############################################
668: sub MapSelect {
1.61 matthew 669: my ($elementname,$status,$numvisible,$restriction)=@_;
1.60 matthew 670: if ($numvisible < 1) {
671: return;
672: }
673: #
674: # Set up array of selected items
1.61 matthew 675: &SetSelectedMaps($elementname);
1.60 matthew 676: #
677: # Set up the restriction call
678: if (! defined($restriction)) {
679: $restriction = sub { 1; };
680: }
681: #
682: # Build the form element
683: my $Str = "\n";
684: $Str .= '<select name="'.$elementname.'" ';
685: if ($status ne 'single') {
686: $Str .= 'multiple="true" ';
687: }
688: $Str .= 'size="'.$numvisible.'" >'."\n";
689: #
1.61 matthew 690: # Deal with 'all'
691: foreach (@SelectedMaps) {
692: if ($_ eq 'all') {
693: @SelectedMaps = ('all');
694: last;
695: }
696: }
697: #
698: # Put in option for 'all'
699: $Str .= ' <option value="all" ';
700: foreach (@SelectedMaps) {
701: if ($_ eq 'all') {
702: $Str .= 'selected ';
703: last;
704: }
705: }
706: $Str .= ">all</option>\n";
707: #
1.60 matthew 708: # Loop through the sequences
1.61 matthew 709: foreach my $seq (@Sequences) {
710: next if (! $restriction->($seq));
711: $Str .= ' <option value="'.$seq->{'symb'}.'" ';
712: foreach (@SelectedMaps) {
713: if ($seq->{'symb'} eq $_) {
1.60 matthew 714: $Str .= 'selected ';
715: last;
716: }
717: }
1.61 matthew 718: $Str .= '>'.$seq->{'title'}."</option>\n";
1.60 matthew 719: }
720: $Str .= "</select>\n";
721: return $Str;
722: }
723:
724: ##############################################
725: ##############################################
726:
727: =pod
728:
729: =item &SectionSelect($elementname,$status,$numvisible)
730:
731: Returns html for a selection box allowing the user to choose one (or more)
732: of the sections in the course.
733:
734: =over 4
735:
736: =item $elementname The name of the HTML form element
737:
738: =item $status 'multiple' or 'single' selection box
739:
740: =item $numvisible The number of options to be visible
741:
742: =item $selected Array ref to the names of the already selected sections.
743: If undef, $ENV{'form.'.$elementname} is used.
744: If $ENV{'form.'.$elementname} is also empty, none will be selected.
745:
746: =item $restriction Code reference to subroutine which returns true or
747: false. The code must expect a reference to a sequence data structure.
748:
749: =back
750:
751: =cut
752:
753: ##############################################
754: ##############################################
755: sub SectionSelect {
756: my ($elementname,$status,$numvisible)=@_;
757: if ($numvisible < 1) {
758: return;
759: }
760: #
761: # Build the form element
762: my $Str = "\n";
763: $Str .= '<select name="'.$elementname.'" ';
764: if ($status ne 'single') {
765: $Str .= 'multiple="true" ';
766: }
767: $Str .= 'size="'.$numvisible.'" >'."\n";
768: #
769: # Loop through the sequences
770: foreach my $s (@Sections) {
771: $Str .= ' <option value="'.$s.'" ';
772: foreach (@SelectedSections) {
1.61 matthew 773: if ($s eq $_) {
1.60 matthew 774: $Str .= 'selected ';
775: last;
776: }
777: }
778: $Str .= '>'.$s."</option>\n";
779: }
780: $Str .= "</select>\n";
781: return $Str;
782: }
783:
1.61 matthew 784: ##################################################
785: ##################################################
1.60 matthew 786: sub DisplayClasslist {
787: my ($r)=@_;
788: #
789: my @Fields = ('fullname','username','domain','id','section');
790: #
791: my $Str='';
792: $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
793: $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
794: foreach my $field (@Fields) {
1.65 matthew 795: $Str .= '<th><a href="/adm/statistics?reportSelected=classlist&sort='.$field.'">'.$field.
1.60 matthew 796: '</a></th>';
797: }
798: $Str .= '</tr>'."\n";
799: #
800: my $alternate = 0;
1.65 matthew 801: foreach my $student (@Students) { # @Students is a package variable
1.60 matthew 802: my $sname = $student->{'username'}.':'.$student->{'domain'};
803: if($alternate) {
804: $Str .= '<tr bgcolor="#ffffe6">';
805: } else {
806: $Str .= '<tr bgcolor="#ffffc6">';
807: }
808: $alternate = ($alternate + 1) % 2;
809: #
810: foreach my $field (@Fields) {
811: $Str .= '<td>';
812: if ($field eq 'fullname') {
813: $Str .= '<a href="/adm/statistics?reportSelected=';
1.65 matthew 814: $Str .= &Apache::lonnet::escape('student_assessment');
1.60 matthew 815: $Str .= '&StudentAssessmentStudent=';
1.61 matthew 816: $Str .= &Apache::lonnet::escape($sname).'">';
1.60 matthew 817: $Str .= $student->{$field}.' ';
818: $Str .= '</a>';
819: } else {
820: $Str .= $student->{$field};
821: }
822: $Str .= '</td>';
823: }
824: $Str .= "</tr>\n";
825: }
826: $Str .= '</table></td></tr></table>'."\n";
827: #
828: $r->print($Str);
829: $r->rflush();
830: #
831: return;
832: }
833:
1.65 matthew 834: ##############################################
835: ##############################################
1.33 stredwic 836: sub CreateMainMenu {
1.65 matthew 837: my ($status,$reports,$current)=@_;
838: #
1.33 stredwic 839: my $Str = '';
1.65 matthew 840: #
1.33 stredwic 841: $Str .= '<table border="0"><tbody><tr>'."\n";
1.63 matthew 842: $Str .= '<td></td>'."\n";
1.67 matthew 843: $Str .= '<td></td>'."\n";
1.57 minaeibi 844: $Str .= '<td align="center"><b>Select a Report</b></td>'."\n";
1.33 stredwic 845: $Str .= '<tr>'."\n";
1.65 matthew 846: #
1.67 matthew 847: $Str .= '<td align="center">'.
848: '<input type="submit" name="Refresh" value="Update Display" />'.
849: "</td>\n";
850: $Str .= '<td align="center">'.
851: '<input type="submit" name="ClearCache" value="Clear Caches" />'.
852: "</td>\n";
1.65 matthew 853: #
1.33 stredwic 854: $Str .= '<td align="center">';
1.65 matthew 855: $Str .= '<select name="reportSelected" >'."\n";
1.33 stredwic 856: foreach (sort(keys(%$reports))) {
1.65 matthew 857: $Str .= '<option value="'.$_.'"';
858: if($current eq $_) {
859: $Str .= ' selected';
1.33 stredwic 860: }
861: $Str .= '>'.$reports->{$_}.'</option>'."\n";
862: }
863: $Str .= '</select></td>'."\n";
1.65 matthew 864: #
1.33 stredwic 865: $Str .= '</tr></tbody></table>'."\n";
866: $Str .= '<hr>'."\n";
1.65 matthew 867: #
1.33 stredwic 868: return $Str;
869: }
870:
1.65 matthew 871: ##############################################
872: ##############################################
1.1 albertel 873: sub handler {
1.31 minaeibi 874: my $r=shift;
1.65 matthew 875: my $c = $r->connection();
876: #
877: # Check for overloading
1.51 www 878: my $loaderror=&Apache::lonnet::overloaderror($r);
879: if ($loaderror) { return $loaderror; }
880: $loaderror=
881: &Apache::lonnet::overloaderror($r,
882: $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
883: if ($loaderror) { return $loaderror; }
1.65 matthew 884: #
885: # Check for access
1.27 stredwic 886: unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
887: $ENV{'user.error.msg'}=
888: $r->uri.":vgr:0:0:Cannot view grades for complete course";
1.55 minaeibi 889: return HTTP_NOT_ACCEPTABLE;
1.27 stredwic 890: }
1.65 matthew 891: #
1.27 stredwic 892: # Set document type for header only
893: if($r->header_only) {
894: if ($ENV{'browser.mathml'}) {
895: $r->content_type('text/xml');
896: } else {
897: $r->content_type('text/html');
898: }
899: &Apache::loncommon::no_cache($r);
900: $r->send_http_header;
901: return OK;
902: }
1.65 matthew 903: #
904: # Send the header
1.27 stredwic 905: $r->content_type('text/html');
906: $r->send_http_header;
1.65 matthew 907: #
908: # Extract form elements from query string
1.60 matthew 909: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.65 matthew 910: ['sort','reportSelected',
1.61 matthew 911: 'StudentAssessmentStudent']);
1.65 matthew 912: if (! exists($ENV{'form.reportSelected'})) {
913: $ENV{'form.reportSelected'} = 'student_assessment';
914: }
915: #
916: # Give the LON-CAPA page header
917: $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts'));
918: $r->rflush();
919: #
1.66 matthew 920: if (! &Apache::lonmysql::verify_sql_connection()) {
921: my $serveradmin = $r->dir_config('lonAdmEMail');
922: $r->print(<<END);
923: <h2><font color="Red">Unable to connect to database!</font></h2>
924: <p>
925: Please notify the server administrator <b>$serveradmin</b>.
926: </p><p>
927: Course Statistics and Charts cannot be retrieved until the database is
928: restarted. Your data is intact but cannot be displayed at this time.
929: </p>
930: </body>
931: </html>
932: END
933: return;
1.67 matthew 934: }
935: #
936: # Clean out the caches
937: if (exists($ENV{'form.ClearCache'})) {
938: &Apache::loncoursedata::delete_caches($ENV{'requres.course.id'});
1.66 matthew 939: }
940: #
1.65 matthew 941: # Set up the statistics and chart environment
1.59 matthew 942: &PrepareClasslist($r);
1.60 matthew 943: &PrepareCourseData($r);
1.65 matthew 944: #
945: # Begin form output
946: $r->print('<form name="Statistics" ');
947: $r->print('method="post" action="/adm/statistics">');
948: #
949: # Print main menu
950: my %reports = ('classlist' => 'Class list',
951: 'problem_statistics' => 'Problem Statistics',
1.66 matthew 952: 'student_assessment' => 'Problem Status Chart',
1.65 matthew 953: 'percentage' => 'Correct-problems Plot',
954: 'option_response' => 'Option Response Analysis',
955: # 'activitylog' => 'Activity Log',
956: );
957: $r->print(&CreateMainMenu($ENV{'form.status'},
958: \%reports,$ENV{'form.reportSelected'}));
959: $r->rflush();
960: #
961: my $GoToPage = $ENV{'form.reportSelected'};
962: if($GoToPage eq 'activitylog') {
963: # &Apache::lonproblemstatistics::Activity();
964: } elsif($GoToPage eq 'problem_statistics') {
965: &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c);
966: } elsif($GoToPage eq 'option_response') {
967: # &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c);
968: } elsif($GoToPage eq 'student_assessment') {
969: &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c);
970: } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
971: # &Apache::lonproblemstatistics::BuildGraphicChart($r,$c);
972: } elsif($GoToPage eq 'classlist') {
973: &DisplayClasslist($r);
974: } elsif($GoToPage eq 'Correct-problems Plot') {
975: # &Apache::lonpercentage::BuildPercentageGraph($r,$c);
976: }
977: #
978: $r->print("</form>\n");
979: $r->print("</body>\n</html>\n");
980: $r->rflush();
981: #
1.27 stredwic 982: return OK;
1.1 albertel 983: }
1.65 matthew 984:
1.1 albertel 985: 1;
1.59 matthew 986:
1.65 matthew 987: #######################################################
988: #######################################################
989:
1.59 matthew 990: =pod
991:
992: =back
993:
994: =cut
1.65 matthew 995:
996: #######################################################
997: #######################################################
1.59 matthew 998:
1.1 albertel 999: __END__
1.31 minaeibi 1000:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>