Annotation of loncom/interface/lonstatistics.pm, revision 1.69
1.1 albertel 1: # The LearningOnline Network with CAPA
2: #
1.69 ! matthew 3: # $Id: lonstatistics.pm,v 1.68 2003/05/12 22:07:17 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: #
1.69 ! matthew 233: # Deal with instructors with restricted section access
! 234: if ($ENV{'request.course.sec'} ne '') {
! 235: @SelectedSections = ($ENV{'request.course.sec'});
! 236: }
! 237: #
1.61 matthew 238: # Set up %StudentData
239: @StudentDataOrder = qw/fullname username domain id section status/;
240: foreach my $field (@StudentDataOrder) {
241: $StudentData{$field}->{'title'} = $field;
1.63 matthew 242: $StudentData{$field}->{'base_width'} = length($field);
1.61 matthew 243: $StudentData{$field}->{'width'} =
244: $StudentData{$field}->{'base_width'};
245: }
1.59 matthew 246: #
1.68 matthew 247: # get the status requested
248: my $requested_status = 'Active';
249: $requested_status = $ENV{'form.Status'} if (exists($ENV{'form.Status'}));
250: #
1.59 matthew 251: # Process the classlist
252: while (my ($student,$student_data) = each (%$classlist)) {
253: my $studenthash = ();
254: for (my $i=0; $i< scalar(@$field_names);$i++) {
1.61 matthew 255: my $field = $field_names->[$i];
256: # Store the data
257: $studenthash->{$field}=$student_data->[$i];
258: # Keep track of the width of the fields
259: next if (! exists($StudentData{$field}));
1.63 matthew 260: my $length = length($student_data->[$i]);
1.61 matthew 261: if ($StudentData{$field}->{'width'} < $length) {
262: $StudentData{$field}->{'width'} = $length;
263: }
1.59 matthew 264: }
265: push (@FullClasslist,$studenthash);
266: #
267: # Build up a list of sections
268: my $section = $studenthash->{'section'};
1.60 matthew 269: if (! defined($section) || $section =~/^\s*$/ || $section == -1) {
270: $studenthash->{'section'} = 'none';
271: $section = $studenthash->{'section'};
272: }
1.59 matthew 273: $Sections{$section}++;
274: #
275: # Only put in the list those students we are interested in
1.60 matthew 276: foreach my $sect (@SelectedSections) {
1.68 matthew 277: if ( (($sect eq 'all') ||
278: ($section eq $sect)) &&
279: (($studenthash->{'status'} eq $requested_status) ||
280: ($requested_status eq 'Any'))
281: ){
1.60 matthew 282: push (@Students,$studenthash);
283: last;
284: }
1.59 matthew 285: }
286: }
287: #
288: # Put the consolidated section data in the right place
1.69 ! matthew 289: if ($ENV{'request.course.sec'} ne '') {
! 290: @Sections = ($ENV{'request.course.sec'});
! 291: } else {
! 292: @Sections = sort {$a cmp $b} keys(%Sections);
! 293: unshift(@Sections,'all'); # Put 'all' at the front of the list
! 294: }
1.59 matthew 295: #
296: # Sort the Students
297: my $sortby = 'fullname';
1.60 matthew 298: $sortby = $ENV{'form.sort'} if (exists($ENV{'form.sort'}));
299: my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} ||
300: $a->{'fullname'} cmp $b->{'fullname'} } @Students;
301: @Students = @TmpStudents;
1.59 matthew 302: #
303: # Now deal with that current student thing....
304: if (exists($ENV{'form.StudentAssessmentStudent'})) {
305: my ($current_uname,$current_dom) =
306: split(':',$ENV{'form.StudentAssessmentStudent'});
307: my $i;
308: for ($i = 0; $i<=$#Students; $i++) {
309: next if (($Students[$i]->{'username'} ne $current_uname) ||
310: ($Students[$i]->{'domain'} ne $current_dom));
1.60 matthew 311: $curr_student = $Students[$i];
1.59 matthew 312: last; # If we get here, we have our student.
313: }
314: if ($i == 0) {
315: $prev_student = 'none';
316: } else {
317: $prev_student = $Students[$i-1];
318: }
319: if ($i == $#Students) {
320: $next_student = 'none';
321: } else {
322: $next_student = $Students[$i+1];
323: }
324: }
1.61 matthew 325: #
326: if (exists($ENV{'form.StudentData'})) {
327: if (ref($ENV{'form.StudentData'}) eq 'ARRAY') {
328: @SelectedStudentData = @{$ENV{'form.StudentData'}};
329: } else {
330: @SelectedStudentData = ($ENV{'form.StudentData'});
331: }
332: } else {
333: @SelectedStudentData = ('fullname');
334: }
335: foreach (@SelectedStudentData) {
336: if ($_ eq 'all') {
337: @SelectedStudentData = ('all');
338: last;
339: }
340: }
341: #
342: return;
343: }
344:
345: #######################################################
346: #######################################################
347:
348: =pod
349:
350: =item ¤t_student()
351:
352: Returns a pointer to a hash containing data about the currently
353: selected student.
354:
355: =cut
356:
357: #######################################################
358: #######################################################
359: sub current_student {
360: if (defined($curr_student)) {
361: return $curr_student;
362: } else {
363: return 'All Students';
364: }
365: }
366:
367: #######################################################
368: #######################################################
369:
370: =pod
371:
372: =item &previous_student()
373:
374: Returns a pointer to a hash containing data about the student prior
375: in the list of students. Or something.
376:
377: =cut
378:
379: #######################################################
380: #######################################################
381: sub previous_student {
382: if (defined($prev_student)) {
383: return $prev_student;
384: } else {
385: return 'No Student Selected';
386: }
1.59 matthew 387: }
388:
389: #######################################################
390: #######################################################
1.61 matthew 391:
392: =pod
393:
394: =item &next_student()
395:
396: Returns a pointer to a hash containing data about the next student
397: to be viewed.
398:
399: =cut
400:
401: #######################################################
402: #######################################################
403: sub next_student {
404: if (defined($next_student)) {
405: return $next_student;
406: } else {
407: return 'No Student Selected';
408: }
409: }
1.60 matthew 410:
411: #######################################################
412: #######################################################
413:
414: =pod
415:
416: =item &clear_sequence_variables()
417:
418: =cut
419:
420: #######################################################
421: #######################################################
422: sub clear_sequence_variables {
423: undef($top_map);
424: undef(@Sequences);
425: undef(@Assessments);
426: }
427:
428: #######################################################
429: #######################################################
430:
431: =pod
432:
1.61 matthew 433: =item &SetSelectedMaps($elementname)
434:
435: Sets the @SelectedMaps array from $ENV{'form.'.$elementname};
436:
437: =cut
438:
439: #######################################################
440: #######################################################
441: sub SetSelectedMaps {
442: my $elementname = shift;
443: if (exists($ENV{'form.'.$elementname})) {
444: if (ref($ENV{'form.'.$elementname})) {
445: @SelectedMaps = @{$ENV{'form.'.$elementname}};
446: } else {
447: @SelectedMaps = ($ENV{'form.'.$elementname});
448: }
449: } else {
450: @SelectedMaps = ('all');
451: }
1.64 matthew 452: }
453:
454:
455: #######################################################
456: #######################################################
457:
458: =pod
459:
460: =item &Sequences_with_Assess()
461:
462: Returns an array containing the subset of @Sequences which contain
463: assessments.
464:
465: =cut
466:
467: #######################################################
468: #######################################################
469: sub Sequences_with_Assess {
470: my @Sequences_to_Show;
471: foreach my $map_symb (@SelectedMaps) {
472: foreach my $sequence (@Sequences) {
473: next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
474: next if ($sequence->{'num_assess'} < 1);
475: push (@Sequences_to_Show,$sequence);
476: }
477: }
478: return @Sequences_to_Show;
1.61 matthew 479: }
480:
481: #######################################################
482: #######################################################
483:
484: =pod
485:
1.60 matthew 486: =item &PrepareCourseData($r)
487:
488: =cut
489:
490: #######################################################
491: #######################################################
492: sub PrepareCourseData {
493: my ($r) = @_;
494: &clear_sequence_variables();
1.61 matthew 495: my ($top,$sequences,$assessments) =
496: &Apache::loncoursedata::get_sequence_assessment_data();
1.60 matthew 497: if (! defined($top) || ! ref($top)) {
498: # There has been an error, better report it
499: &Apache::lonnet::logthis('top is undefined');
500: return;
501: }
502: $top_map = $top if (ref($top));
503: @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY');
1.61 matthew 504: @Assessments = @{$assessments} if (ref($assessments) eq 'ARRAY');
505: #
506: # Compute column widths
507: foreach my $seq (@Sequences) {
1.63 matthew 508: my $name_length = length($seq->{'title'});
1.61 matthew 509: my $num_parts = $seq->{'num_assess_parts'};
510: #
511: # The number of columns needed for the summation text:
512: # " 1/5" = 1+3 columns, " 10/99" = 1+5 columns
1.63 matthew 513: my $sum_length = 1+1+2*(length($num_parts));
1.61 matthew 514: my $num_col = $num_parts+$sum_length;
515: if ($num_col < $name_length) {
516: $num_col = $name_length;
517: }
518: $seq->{'base_width'} = $name_length;
519: $seq->{'width'} = $num_col;
520: }
521: return;
522: }
523:
524: #######################################################
525: #######################################################
1.60 matthew 526:
527: =pod
528:
1.61 matthew 529: =item &log_sequence($sequence,$recursive,$padding)
530:
531: Write data about the sequence to a logfile. If $recursive is not
532: undef the data is written recursively. $padding is used for recursive
533: calls.
534:
535: =cut
536:
537: #######################################################
538: #######################################################
539: sub log_sequence {
540: my ($seq,$recursive,$padding) = @_;
541: $padding = '' if (! defined($padding));
542: if (ref($seq) ne 'HASH') {
543: &Apache::lonnet::logthis('log_sequence passed bad sequnce');
544: return;
545: }
546: &Apache::lonnet::logthis($padding.'sequence '.$seq->{'title'});
547: while (my($key,$value) = each(%$seq)) {
548: next if ($key eq 'contents');
549: if (ref($value) eq 'ARRAY') {
550: for (my $i=0;$i< scalar(@$value);$i++) {
551: &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
552: $value->[$i]);
553: }
554: } else {
555: &Apache::lonnet::logthis($padding.$key.'='.$value);
556: }
557: }
558: if (defined($recursive)) {
559: &Apache::lonnet::logthis($padding.'-'x20);
560: &Apache::lonnet::logthis($padding.'contains:');
561: foreach my $item (@{$seq->{'contents'}}) {
562: if ($item->{'type'} eq 'container') {
563: &log_sequence($item,$recursive,$padding.' ');
564: } else {
565: &Apache::lonnet::logthis($padding.'title = '.$item->{'title'});
566: while (my($key,$value) = each(%$item)) {
567: next if ($key eq 'title');
568: if (ref($value) eq 'ARRAY') {
569: for (my $i=0;$i< scalar(@$value);$i++) {
570: &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
571: $value->[$i]);
572: }
573: } else {
574: &Apache::lonnet::logthis($padding.$key.'='.$value);
575: }
576: }
577: }
1.60 matthew 578: }
1.61 matthew 579: &Apache::lonnet::logthis($padding.'end contents of '.$seq->{'title'});
580: &Apache::lonnet::logthis($padding.'-'x20);
1.60 matthew 581: }
1.61 matthew 582: return;
583: }
584:
585: ##############################################
586: ##############################################
587:
588: =pod
589:
590: =item &StudentDataSelect($elementname,$status,$numvisible,$selected)
591:
592: Returns html for a selection box allowing the user to choose one (or more)
593: of the fields of student data available (fullname, username, id, section, etc)
594:
595: =over 4
596:
597: =item $elementname The name of the HTML form element
598:
599: =item $status 'multiple' or 'single' selection box
600:
601: =item $numvisible The number of options to be visible
602:
603: =back
1.60 matthew 604:
605: =cut
606:
1.61 matthew 607: ##############################################
608: ##############################################
609: sub StudentDataSelect {
610: my ($elementname,$status,$numvisible)=@_;
611: if ($numvisible < 1) {
612: return;
613: }
614: #
615: # Build the form element
616: my $Str = "\n";
617: $Str .= '<select name="'.$elementname.'" ';
618: if ($status ne 'single') {
619: $Str .= 'multiple="true" ';
620: }
621: $Str .= 'size="'.$numvisible.'" >'."\n";
622: #
623: # Deal with 'all'
624: $Str .= ' <option value="all" ';
625: foreach (@SelectedStudentData) {
626: if ($_ eq 'all') {
627: $Str .= 'selected ';
628: last;
629: }
630: }
631: $Str .= ">all</option>\n";
632: #
633: # Loop through the student data fields
634: foreach my $item (@StudentDataOrder) {
635: $Str .= ' <option value="'.$item.'" ';
636: foreach (@SelectedStudentData) {
637: if ($item eq $_ ) {
638: $Str .= 'selected ';
639: last;
640: }
641: }
642: $Str .= '>'.$item."</option>\n";
643: }
644: $Str .= "</select>\n";
645: return $Str;
1.60 matthew 646: }
647:
648: ##############################################
649: ##############################################
650:
651: =pod
652:
1.61 matthew 653: =item &MapSelect($elementname,$status,$numvisible,$restriction)
1.60 matthew 654:
655: Returns html for a selection box allowing the user to choose one (or more)
656: of the sequences in the course. The values of the sequences are the symbs.
657: If the top sequence is selected, the value 'top' will result.
658:
659: =over 4
660:
661: =item $elementname The name of the HTML form element
662:
663: =item $status 'multiple' or 'single' selection box
664:
665: =item $numvisible The number of options to be visible
666:
667: =item $restriction Code reference to subroutine which returns true or
668: false. The code must expect a reference to a sequence data structure.
669:
670: =back
671:
672: =cut
673:
674: ##############################################
675: ##############################################
676: sub MapSelect {
1.61 matthew 677: my ($elementname,$status,$numvisible,$restriction)=@_;
1.60 matthew 678: if ($numvisible < 1) {
679: return;
680: }
681: #
682: # Set up array of selected items
1.61 matthew 683: &SetSelectedMaps($elementname);
1.60 matthew 684: #
685: # Set up the restriction call
686: if (! defined($restriction)) {
687: $restriction = sub { 1; };
688: }
689: #
690: # Build the form element
691: my $Str = "\n";
692: $Str .= '<select name="'.$elementname.'" ';
693: if ($status ne 'single') {
694: $Str .= 'multiple="true" ';
695: }
696: $Str .= 'size="'.$numvisible.'" >'."\n";
697: #
1.61 matthew 698: # Deal with 'all'
699: foreach (@SelectedMaps) {
700: if ($_ eq 'all') {
701: @SelectedMaps = ('all');
702: last;
703: }
704: }
705: #
706: # Put in option for 'all'
707: $Str .= ' <option value="all" ';
708: foreach (@SelectedMaps) {
709: if ($_ eq 'all') {
710: $Str .= 'selected ';
711: last;
712: }
713: }
714: $Str .= ">all</option>\n";
715: #
1.60 matthew 716: # Loop through the sequences
1.61 matthew 717: foreach my $seq (@Sequences) {
718: next if (! $restriction->($seq));
719: $Str .= ' <option value="'.$seq->{'symb'}.'" ';
720: foreach (@SelectedMaps) {
721: if ($seq->{'symb'} eq $_) {
1.60 matthew 722: $Str .= 'selected ';
723: last;
724: }
725: }
1.61 matthew 726: $Str .= '>'.$seq->{'title'}."</option>\n";
1.60 matthew 727: }
728: $Str .= "</select>\n";
729: return $Str;
730: }
731:
732: ##############################################
733: ##############################################
734:
735: =pod
736:
737: =item &SectionSelect($elementname,$status,$numvisible)
738:
739: Returns html for a selection box allowing the user to choose one (or more)
740: of the sections in the course.
741:
742: =over 4
743:
744: =item $elementname The name of the HTML form element
745:
746: =item $status 'multiple' or 'single' selection box
747:
748: =item $numvisible The number of options to be visible
749:
750: =item $selected Array ref to the names of the already selected sections.
751: If undef, $ENV{'form.'.$elementname} is used.
752: If $ENV{'form.'.$elementname} is also empty, none will be selected.
753:
754: =item $restriction Code reference to subroutine which returns true or
755: false. The code must expect a reference to a sequence data structure.
756:
757: =back
758:
759: =cut
760:
761: ##############################################
762: ##############################################
763: sub SectionSelect {
764: my ($elementname,$status,$numvisible)=@_;
765: if ($numvisible < 1) {
766: return;
767: }
768: #
769: # Build the form element
770: my $Str = "\n";
771: $Str .= '<select name="'.$elementname.'" ';
772: if ($status ne 'single') {
773: $Str .= 'multiple="true" ';
774: }
775: $Str .= 'size="'.$numvisible.'" >'."\n";
776: #
777: # Loop through the sequences
778: foreach my $s (@Sections) {
779: $Str .= ' <option value="'.$s.'" ';
780: foreach (@SelectedSections) {
1.61 matthew 781: if ($s eq $_) {
1.60 matthew 782: $Str .= 'selected ';
783: last;
784: }
785: }
786: $Str .= '>'.$s."</option>\n";
787: }
788: $Str .= "</select>\n";
789: return $Str;
790: }
791:
1.61 matthew 792: ##################################################
793: ##################################################
1.60 matthew 794: sub DisplayClasslist {
795: my ($r)=@_;
796: #
797: my @Fields = ('fullname','username','domain','id','section');
798: #
799: my $Str='';
800: $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
801: $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
802: foreach my $field (@Fields) {
1.65 matthew 803: $Str .= '<th><a href="/adm/statistics?reportSelected=classlist&sort='.$field.'">'.$field.
1.60 matthew 804: '</a></th>';
805: }
806: $Str .= '</tr>'."\n";
807: #
808: my $alternate = 0;
1.65 matthew 809: foreach my $student (@Students) { # @Students is a package variable
1.60 matthew 810: my $sname = $student->{'username'}.':'.$student->{'domain'};
811: if($alternate) {
812: $Str .= '<tr bgcolor="#ffffe6">';
813: } else {
814: $Str .= '<tr bgcolor="#ffffc6">';
815: }
816: $alternate = ($alternate + 1) % 2;
817: #
818: foreach my $field (@Fields) {
819: $Str .= '<td>';
820: if ($field eq 'fullname') {
821: $Str .= '<a href="/adm/statistics?reportSelected=';
1.65 matthew 822: $Str .= &Apache::lonnet::escape('student_assessment');
1.60 matthew 823: $Str .= '&StudentAssessmentStudent=';
1.61 matthew 824: $Str .= &Apache::lonnet::escape($sname).'">';
1.60 matthew 825: $Str .= $student->{$field}.' ';
826: $Str .= '</a>';
827: } else {
828: $Str .= $student->{$field};
829: }
830: $Str .= '</td>';
831: }
832: $Str .= "</tr>\n";
833: }
834: $Str .= '</table></td></tr></table>'."\n";
835: #
836: $r->print($Str);
837: $r->rflush();
838: #
839: return;
840: }
841:
1.65 matthew 842: ##############################################
843: ##############################################
1.33 stredwic 844: sub CreateMainMenu {
1.65 matthew 845: my ($status,$reports,$current)=@_;
846: #
1.33 stredwic 847: my $Str = '';
1.65 matthew 848: #
1.33 stredwic 849: $Str .= '<table border="0"><tbody><tr>'."\n";
1.63 matthew 850: $Str .= '<td></td>'."\n";
1.67 matthew 851: $Str .= '<td></td>'."\n";
1.57 minaeibi 852: $Str .= '<td align="center"><b>Select a Report</b></td>'."\n";
1.33 stredwic 853: $Str .= '<tr>'."\n";
1.65 matthew 854: #
1.67 matthew 855: $Str .= '<td align="center">'.
856: '<input type="submit" name="Refresh" value="Update Display" />'.
857: "</td>\n";
858: $Str .= '<td align="center">'.
859: '<input type="submit" name="ClearCache" value="Clear Caches" />'.
860: "</td>\n";
1.65 matthew 861: #
1.33 stredwic 862: $Str .= '<td align="center">';
1.65 matthew 863: $Str .= '<select name="reportSelected" >'."\n";
1.33 stredwic 864: foreach (sort(keys(%$reports))) {
1.65 matthew 865: $Str .= '<option value="'.$_.'"';
866: if($current eq $_) {
867: $Str .= ' selected';
1.33 stredwic 868: }
869: $Str .= '>'.$reports->{$_}.'</option>'."\n";
870: }
871: $Str .= '</select></td>'."\n";
1.65 matthew 872: #
1.33 stredwic 873: $Str .= '</tr></tbody></table>'."\n";
874: $Str .= '<hr>'."\n";
1.65 matthew 875: #
1.33 stredwic 876: return $Str;
877: }
878:
1.65 matthew 879: ##############################################
880: ##############################################
1.1 albertel 881: sub handler {
1.31 minaeibi 882: my $r=shift;
1.65 matthew 883: my $c = $r->connection();
884: #
885: # Check for overloading
1.51 www 886: my $loaderror=&Apache::lonnet::overloaderror($r);
887: if ($loaderror) { return $loaderror; }
888: $loaderror=
889: &Apache::lonnet::overloaderror($r,
890: $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
891: if ($loaderror) { return $loaderror; }
1.65 matthew 892: #
893: # Check for access
1.69 ! matthew 894: if (! &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
1.27 stredwic 895: $ENV{'user.error.msg'}=
1.69 ! matthew 896: $r->uri.":vgr:0:0:Cannot view grades for complete course";
! 897: if (! &Apache::lonnet::allowed('vgr',
! 898: $ENV{'request.course.id'}.'/'.$ENV{'request.course.sec'})) {
! 899: $ENV{'user.error.msg'}=
! 900: $r->uri.":vgr:0:0:Cannot view grades with given role";
! 901: return HTTP_NOT_ACCEPTABLE;
! 902: }
1.27 stredwic 903: }
1.65 matthew 904: #
1.27 stredwic 905: # Set document type for header only
906: if($r->header_only) {
907: if ($ENV{'browser.mathml'}) {
908: $r->content_type('text/xml');
909: } else {
910: $r->content_type('text/html');
911: }
912: &Apache::loncommon::no_cache($r);
913: $r->send_http_header;
914: return OK;
915: }
1.65 matthew 916: #
917: # Send the header
1.27 stredwic 918: $r->content_type('text/html');
919: $r->send_http_header;
1.65 matthew 920: #
921: # Extract form elements from query string
1.60 matthew 922: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.65 matthew 923: ['sort','reportSelected',
1.61 matthew 924: 'StudentAssessmentStudent']);
1.65 matthew 925: if (! exists($ENV{'form.reportSelected'})) {
926: $ENV{'form.reportSelected'} = 'student_assessment';
927: }
928: #
929: # Give the LON-CAPA page header
930: $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts'));
931: $r->rflush();
932: #
1.66 matthew 933: if (! &Apache::lonmysql::verify_sql_connection()) {
934: my $serveradmin = $r->dir_config('lonAdmEMail');
935: $r->print(<<END);
936: <h2><font color="Red">Unable to connect to database!</font></h2>
937: <p>
938: Please notify the server administrator <b>$serveradmin</b>.
939: </p><p>
940: Course Statistics and Charts cannot be retrieved until the database is
941: restarted. Your data is intact but cannot be displayed at this time.
942: </p>
943: </body>
944: </html>
945: END
946: return;
1.67 matthew 947: }
948: #
949: # Clean out the caches
950: if (exists($ENV{'form.ClearCache'})) {
951: &Apache::loncoursedata::delete_caches($ENV{'requres.course.id'});
1.66 matthew 952: }
953: #
1.65 matthew 954: # Set up the statistics and chart environment
1.59 matthew 955: &PrepareClasslist($r);
1.60 matthew 956: &PrepareCourseData($r);
1.65 matthew 957: #
958: # Begin form output
959: $r->print('<form name="Statistics" ');
960: $r->print('method="post" action="/adm/statistics">');
961: #
962: # Print main menu
963: my %reports = ('classlist' => 'Class list',
964: 'problem_statistics' => 'Problem Statistics',
1.66 matthew 965: 'student_assessment' => 'Problem Status Chart',
1.65 matthew 966: 'percentage' => 'Correct-problems Plot',
967: 'option_response' => 'Option Response Analysis',
968: # 'activitylog' => 'Activity Log',
969: );
970: $r->print(&CreateMainMenu($ENV{'form.status'},
971: \%reports,$ENV{'form.reportSelected'}));
972: $r->rflush();
973: #
974: my $GoToPage = $ENV{'form.reportSelected'};
975: if($GoToPage eq 'activitylog') {
976: # &Apache::lonproblemstatistics::Activity();
977: } elsif($GoToPage eq 'problem_statistics') {
978: &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c);
979: } elsif($GoToPage eq 'option_response') {
980: # &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c);
981: } elsif($GoToPage eq 'student_assessment') {
982: &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c);
983: } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
984: # &Apache::lonproblemstatistics::BuildGraphicChart($r,$c);
985: } elsif($GoToPage eq 'classlist') {
986: &DisplayClasslist($r);
987: } elsif($GoToPage eq 'Correct-problems Plot') {
988: # &Apache::lonpercentage::BuildPercentageGraph($r,$c);
989: }
990: #
991: $r->print("</form>\n");
992: $r->print("</body>\n</html>\n");
993: $r->rflush();
994: #
1.27 stredwic 995: return OK;
1.1 albertel 996: }
1.65 matthew 997:
1.1 albertel 998: 1;
1.59 matthew 999:
1.65 matthew 1000: #######################################################
1001: #######################################################
1002:
1.59 matthew 1003: =pod
1004:
1005: =back
1006:
1007: =cut
1.65 matthew 1008:
1009: #######################################################
1010: #######################################################
1.59 matthew 1011:
1.1 albertel 1012: __END__
1.31 minaeibi 1013:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>