1: # The LearningOnline Network with CAPA
2: #
3: # $Id: lonstatistics.pm,v 1.123 2005/04/07 06:56:23 albertel Exp $
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
28: #
29: ###
30:
31: =pod
32:
33: =head1 NAME
34:
35: lonstatistics
36:
37: =head1 SYNOPSIS
38:
39: Main handler for statistics and chart.
40:
41: =over 4
42:
43: =cut
44:
45: package Apache::lonstatistics;
46:
47: use strict;
48: use Apache::Constants qw(:common :http);
49: use vars qw(
50: @FullClasslist
51: @Students
52: @Sections
53: %StudentData
54: @StudentDataOrder
55: @SelectedStudentData
56: $enrollment_status);
57:
58: use Apache::lonnet;
59: use Apache::lonhomework;
60: use Apache::loncommon;
61: use Apache::loncoursedata;
62: use Apache::lonhtmlcommon;
63: use Apache::lonmysql;
64: use Apache::lonlocal;
65: use Time::HiRes;
66: #
67: # Statistics Packages
68: use Apache::lonproblemanalysis();
69: use Apache::lonsubmissiontimeanalysis();
70: use Apache::loncorrectproblemplot();
71: use Apache::lonproblemstatistics();
72: use Apache::lonstudentassessment();
73: use Apache::lonpercentage;
74: use Apache::lonstudentsubmissions();
75: use Apache::lonsurveyreports();
76:
77: #######################################################
78: #######################################################
79:
80: =pod
81:
82: =item Package Variables
83:
84: =item @FullClasslist The full classlist
85:
86: =item @Students The students we are concerned with for this invocation
87:
88: =item @Sections The sections available in this class
89:
90: =item $curr_student The student currently being examined
91:
92: =item $prev_student The student previous in the classlist
93:
94: =item $next_student The student next in the classlist
95:
96: =over
97:
98: =cut
99:
100: #######################################################
101: #######################################################
102: #
103: # Classlist variables
104: #
105: my $curr_student;
106: my $prev_student;
107: my $next_student;
108:
109: #######################################################
110: #######################################################
111:
112: =pod
113:
114: =item &clear_classlist_variables()
115:
116: undef the following package variables:
117:
118: =over
119:
120: =item @FullClasslist
121:
122: =item @Students
123:
124: =item @Sections
125:
126: =item %StudentData
127:
128: =item @StudentDataOrder
129:
130: =item @SelectedStudentData
131:
132: =item $curr_student
133:
134: =item $prev_student
135:
136: =item $next_student
137:
138: =back
139:
140: =cut
141:
142: #######################################################
143: #######################################################
144: sub clear_classlist_variables {
145: undef(@FullClasslist);
146: undef(@Students);
147: undef(@Sections);
148: undef(%StudentData);
149: undef(@SelectedStudentData);
150: undef($curr_student);
151: undef($prev_student);
152: undef($next_student);
153: }
154:
155: #######################################################
156: #######################################################
157:
158: =pod
159:
160: =item &PrepareClasslist()
161:
162: Build up the classlist information. The classlist information is kept in
163: the following package variables:
164:
165: =over
166:
167: =item @FullClasslist
168:
169: =item @Students
170:
171: =item @Sections
172:
173: =item %StudentData
174:
175: =item @SelectedStudentData
176:
177: =item $curr_student
178:
179: =item $prev_student
180:
181: =item $next_student
182:
183: =back
184:
185: $curr_student, $prev_student, and $next_student may not be defined, depending
186: upon the calling context.
187:
188: =cut
189:
190: #######################################################
191: #######################################################
192: sub PrepareClasslist {
193: my %Sections;
194: &clear_classlist_variables();
195: #
196: # Retrieve the classlist
197: my $cid = $env{'request.course.id'};
198: my $cdom = $env{'course.'.$cid.'.domain'};
199: my $cnum = $env{'course.'.$cid.'.num'};
200: my ($classlist,$field_names) = &Apache::loncoursedata::get_classlist($cid,
201: $cdom,$cnum);
202: my @selected_sections = &get_selected_sections();
203: #
204: # Deal with instructors with restricted section access
205: if ($env{'request.course.sec'} !~ /^\s*$/) {
206: @selected_sections = ($env{'request.course.sec'});
207: }
208: #
209: # Set up %StudentData
210: @StudentDataOrder = qw/fullname username domain id section status comments/;
211: foreach my $field (@StudentDataOrder) {
212: $StudentData{$field}->{'title'} = &mt($field);
213: $StudentData{$field}->{'base_width'} = length(&mt($field));
214: $StudentData{$field}->{'width'} =
215: $StudentData{$field}->{'base_width'};
216: }
217: #
218: # get the status requested
219: $enrollment_status = 'Active';
220: $enrollment_status = $env{'form.Status'} if (exists($env{'form.Status'}));
221: #
222: # Process the classlist
223: while (my ($student,$student_data) = each (%$classlist)) {
224: my $studenthash = ();
225: for (my $i=0; $i< scalar(@$field_names);$i++) {
226: my $field = $field_names->[$i];
227: # Store the data
228: $studenthash->{$field}=$student_data->[$i];
229: # Keep track of the width of the fields
230: next if (! exists($StudentData{$field}));
231: my $length = length($student_data->[$i]);
232: if ($StudentData{$field}->{'width'} < $length) {
233: $StudentData{$field}->{'width'} = $length;
234: }
235: }
236: push (@FullClasslist,$studenthash);
237: #
238: # Build up a list of sections
239: my $section = $studenthash->{'section'};
240: if (! defined($section) || $section =~/^\s*$/ || $section == -1) {
241: $studenthash->{'section'} = 'none';
242: $section = $studenthash->{'section'};
243: }
244: $Sections{$section}++;
245: #
246: # Only put in the list those students we are interested in
247: foreach my $sect (@selected_sections) {
248: if ( (($sect eq 'all') ||
249: ($section eq $sect)) &&
250: (($studenthash->{'status'} eq $enrollment_status) ||
251: ($enrollment_status eq 'Any'))
252: ){
253: push (@Students,$studenthash);
254: last;
255: }
256: }
257: }
258: #
259: # Put the consolidated section data in the right place
260: if ($env{'request.course.sec'} !~ /^\s*$/) {
261: @Sections = ($env{'request.course.sec'});
262: } else {
263: @Sections = sort {$a cmp $b} keys(%Sections);
264: unshift(@Sections,'all'); # Put 'all' at the front of the list
265: }
266: #
267: # Sort the Students
268: my $sortby = 'fullname';
269: $sortby = $env{'form.sort'} if (exists($env{'form.sort'}));
270: my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} ||
271: $a->{'fullname'} cmp $b->{'fullname'} } @Students;
272: @Students = @TmpStudents;
273: #
274: # Now deal with that current student thing....
275: $curr_student = undef;
276: if (exists($env{'form.SelectedStudent'})) {
277: my ($current_uname,$current_dom) =
278: split(':',$env{'form.SelectedStudent'});
279: my $i;
280: for ($i = 0; $i<=$#Students; $i++) {
281: next if (($Students[$i]->{'username'} ne $current_uname) ||
282: ($Students[$i]->{'domain'} ne $current_dom));
283: $curr_student = $Students[$i];
284: last; # If we get here, we have our student.
285: }
286: if (defined($curr_student)) {
287: if ($i == 0) {
288: $prev_student = undef;
289: } else {
290: $prev_student = $Students[$i-1];
291: }
292: if ($i == $#Students) {
293: $next_student = undef;
294: } else {
295: $next_student = $Students[$i+1];
296: }
297: }
298: }
299: #
300: if (exists($env{'form.StudentData'})) {
301: if (ref($env{'form.StudentData'}) eq 'ARRAY') {
302: @SelectedStudentData = @{$env{'form.StudentData'}};
303: } else {
304: @SelectedStudentData = ($env{'form.StudentData'});
305: }
306: } else {
307: @SelectedStudentData = ('username');
308: }
309: foreach (@SelectedStudentData) {
310: if ($_ eq 'all') {
311: @SelectedStudentData = ('all');
312: last;
313: }
314: }
315: #
316: return;
317: }
318:
319: #######################################################
320: #######################################################
321:
322: =pod
323:
324: =item get_selected_sections
325:
326: Returns an array of the selected sections
327:
328: =cut
329:
330: #######################################################
331: #######################################################
332: sub get_selected_sections {
333: my @selected_sections;
334: if (exists($env{'form.Section'})) {
335: if (ref($env{'form.Section'})) {
336: @selected_sections = @{$env{'form.Section'}};
337: } elsif ($env{'form.Section'} !~ /^\s*$/) {
338: @selected_sections = ($env{'form.Section'});
339: }
340: }
341: @selected_sections = ('all') if (! @selected_sections);
342: foreach (@selected_sections) {
343: if ($_ eq 'all') {
344: @selected_sections = ('all');
345: }
346: }
347: #
348: # Deal with instructors with restricted section access
349: if ($env{'request.course.sec'} !~ /^\s*$/) {
350: @selected_sections = ($env{'request.course.sec'});
351: }
352: return @selected_sections;
353: }
354:
355: #######################################################
356: #######################################################
357:
358: =pod
359:
360: =item §ion_and_enrollment_description
361:
362: Returns a string describing the currenly selected section(s) and
363: enrollment status.
364:
365: Inputs: mode = 'plaintext' or 'localized' (defaults to 'localized')
366: 'plaintext' is used for example in Excel spreadsheets.
367: Returns: scalar description string.
368:
369: =cut
370:
371: #######################################################
372: #######################################################
373: sub section_and_enrollment_description {
374: my ($mode) = @_;
375: if (! defined($mode)) { $mode = 'localized'; }
376: my @sections = &Apache::lonstatistics::get_selected_sections();
377: my $description;
378: if ($mode eq 'localized') {
379: $description = &mt('Unable to determine section and enrollment');
380: } elsif ($mode eq 'plaintext') {
381: $description = 'Unable to determine section and enrollment';
382: } else {
383: $description = 'Bad parameter passed to lonstatistics::section_and_enrollment_description';
384: &Apache::lonnet::logthis($description);
385: }
386: if (scalar(@sections) == 1 && $sections[0] ne 'all') {
387: if ($mode eq 'localized') {
388: $description = &mt('Section [_1]. [_2] enrollment status.',
389: $sections[0],$env{'form.Status'});
390: } elsif ($mode eq 'plaintext') {
391: $description = 'Section '.$sections[0].'. '.
392: $env{'form.Status'}.' enrollment status.';
393: }
394: } elsif (scalar(@sections) && $sections[0] eq 'all') {
395: if ($mode eq 'localized') {
396: $description = &mt('All sections. [_1] enrollment status.',
397: $env{'form.Status'});
398: } elsif ($mode eq 'plaintext') {
399: $description = 'All sections. '.
400: $env{'form.Status'}.' enrollment status.';
401: }
402: } elsif (scalar(@sections)) {
403: my $lastsection = pop(@sections);
404: if ($mode eq 'localized') {
405: $description = &mt('Sections [_1] and [_2]. [_3] enrollment status.',
406: join(', ',@sections),$lastsection,
407: $env{'form.Status'});
408: } elsif ($mode eq 'plaintext') {
409: $description =
410: 'Sections '.join(', ',@sections).' and '.$lastsection.'. '.
411: $env{'form.Status'}.' enrollment status.';
412: }
413: }
414: return $description;
415: }
416:
417: #######################################################
418: #######################################################
419:
420: =pod
421:
422: =item get_students
423:
424: Returns a list of the selected students
425:
426: =cut
427:
428: #######################################################
429: #######################################################
430: sub get_students {
431: if (! @Students) {
432: &PrepareClasslist()
433: }
434: return @Students;
435: }
436:
437: #######################################################
438: #######################################################
439:
440: =pod
441:
442: =item ¤t_student()
443:
444: Returns a pointer to a hash containing data about the currently
445: selected student.
446:
447: =cut
448:
449: #######################################################
450: #######################################################
451: sub current_student {
452: return $curr_student;
453: }
454:
455: #######################################################
456: #######################################################
457:
458: =pod
459:
460: =item &previous_student()
461:
462: Returns a pointer to a hash containing data about the student prior
463: in the list of students. Or something.
464:
465: =cut
466:
467: #######################################################
468: #######################################################
469: sub previous_student {
470: return $prev_student;
471: }
472:
473: #######################################################
474: #######################################################
475:
476: =pod
477:
478: =item &next_student()
479:
480: Returns a pointer to a hash containing data about the next student
481: to be viewed.
482:
483: =cut
484:
485: #######################################################
486: #######################################################
487: sub next_student {
488: return $next_student;
489: }
490:
491: ##############################################
492: ##############################################
493:
494: =pod
495:
496: =item &StudentDataSelect($elementname,$status,$numvisible,$selected)
497:
498: Returns html for a selection box allowing the user to choose one (or more)
499: of the fields of student data available (fullname, username, id, section, etc)
500:
501: =over 4
502:
503: =item $elementname The name of the HTML form element
504:
505: =item $status 'multiple' or 'single' selection box
506:
507: =item $numvisible The number of options to be visible
508:
509: =back
510:
511: =cut
512:
513: ##############################################
514: ##############################################
515: sub StudentDataSelect {
516: my ($elementname,$status,$numvisible)=@_;
517: if ($numvisible < 1) {
518: return;
519: }
520: #
521: # Build the form element
522: my $Str = "\n";
523: $Str .= '<select name="'.$elementname.'" ';
524: if ($status ne 'single') {
525: $Str .= 'multiple="true" ';
526: }
527: $Str .= 'size="'.$numvisible.'" >'."\n";
528: #
529: # Deal with 'all'
530: $Str .= ' <option value="all" ';
531: foreach (@SelectedStudentData) {
532: if ($_ eq 'all') {
533: $Str .= 'selected ';
534: last;
535: }
536: }
537: $Str .= ">all</option>\n";
538: #
539: # Loop through the student data fields
540: foreach my $item (@StudentDataOrder) {
541: $Str .= ' <option value="'.$item.'" ';
542: foreach (@SelectedStudentData) {
543: if ($item eq $_ ) {
544: $Str .= 'selected ';
545: last;
546: }
547: }
548: $Str .= '>'.$item."</option>\n";
549: }
550: $Str .= "</select>\n";
551: return $Str;
552: }
553:
554: #######################################################
555: #######################################################
556:
557: =pod
558:
559: =item &get_selected_maps($elementname)
560:
561: Input: Name of the <select> form element used to specify the maps.
562:
563: Returns: Array of symbs of selected maps or the description 'all'.
564: If form.$elementname does not exist, 'all' is returned.
565:
566: =cut
567:
568: #######################################################
569: #######################################################
570: sub get_selected_maps {
571: my ($elementname) = @_;
572: my @selected_maps;
573: if (exists($env{'form.'.$elementname})) {
574: if (ref($env{'form.'.$elementname})) {
575: @selected_maps = @{$env{'form.'.$elementname}};
576: } else {
577: @selected_maps = ($env{'form.'.$elementname});
578: }
579: } else {
580: @selected_maps = ('all');
581: }
582: foreach my $map (@selected_maps) {
583: if ($map eq 'all') {
584: @selected_maps = ('all');
585: last;
586: }
587: }
588: return @selected_maps;
589: }
590:
591:
592: #######################################################
593: #######################################################
594:
595: =pod
596:
597: =item &selected_sequences_with_assessments
598:
599: Retrieve the sequences which were selected by the user to show.
600:
601: Input: $mode: scalar. Either 'selected' or 'all'. If not specified,
602: 'selected' is used.
603:
604: Returns: an array containing a navmap object and navmap resources,
605: or an array containing a scalar with an error message.
606:
607: =cut
608:
609: #######################################################
610: #######################################################
611: sub selected_sequences_with_assessments {
612: my ($mode) = @_;
613: $mode = 'selected' if (! defined($mode));
614: my $navmap = Apache::lonnavmaps::navmap->new();
615: if (!defined($navmap)) {
616: return ('Can not open Coursemap');
617: }
618: #
619: my @sequences = $navmap->retrieveResources(undef,
620: sub { shift->is_map(); },1,0,1);
621: my @sequences_with_assessments;
622: for my $sequence ($navmap->getById('0.0'), @sequences) {
623: if ($navmap->hasResource($sequence,sub { shift->is_problem(); },0,1)){
624: push(@sequences_with_assessments,$sequence);
625: }
626: }
627: #
628: my @sequences_to_show;
629: foreach my $sequence (@sequences_with_assessments) {
630: if ($mode eq 'all') {
631: push (@sequences_to_show,$sequence);
632: } elsif ($mode eq 'selected') {
633: foreach my $map_symb (&get_selected_maps('Maps')) {
634: if ($sequence->symb eq $map_symb || $map_symb eq 'all'){
635: push (@sequences_to_show,$sequence);
636: last; # Only put it in once
637: }
638: }
639: }
640:
641: }
642: return $navmap,@sequences_to_show;
643: }
644:
645: ##############################################
646: ##############################################
647:
648: =pod
649:
650: =item &map_select($elementname,$status,$numvisible,$restriction)
651:
652: Returns html for a selection box allowing the user to choose one (or more)
653: of the sequences in the course. The values of the sequences are the symbs.
654: If the top sequence is selected, the value 'top' will result.
655:
656: =over 4
657:
658: =item $elementname The name of the HTML form element
659:
660: =item $status 'multiple' or 'single' selection box
661:
662: =item $numvisible The number of options to be visible
663:
664: =back
665:
666: =cut
667:
668: ##############################################
669: ##############################################
670: sub map_select {
671: my ($elementname,$status,$numvisible)=@_;
672: if ($numvisible < 1) {
673: return;
674: }
675: #
676: # Set up array of selected items
677: my @selected_maps = &get_selected_maps($elementname);
678: #
679: # Build the form element
680: my $form = "\n";
681: $form .= '<select name="'.$elementname.'" ';
682: if ($status ne 'single') {
683: $form .= 'multiple="true" ';
684: }
685: $form .= 'size="'.$numvisible.'" >'."\n";
686: #
687: # Put in option for 'all'
688: $form .= ' <option value="all" ';
689: if ($selected_maps[0] eq 'all') {
690: $form .= 'selected ';
691: }
692: $form .= ">all</option>\n";
693: #
694: # Loop through the sequences
695: my @sequences = &selected_sequences_with_assessments('all');
696: my $navmap;
697: if (!ref($sequences[0])) {
698: return $sequences[0];
699: } else {
700: $navmap = shift(@sequences);
701: }
702: foreach my $seq (@sequences){
703: $form .= ' <option value="'.$seq->symb.'" ';
704: foreach (@selected_maps) {
705: if ($seq->symb eq $_) {
706: $form .= 'selected ';
707: last;
708: }
709: }
710: $form .= '>'.$seq->compTitle."</option>\n";
711: }
712: $form .= "</select>\n";
713: return $form;
714: }
715:
716: ##############################################
717: ##############################################
718:
719: =pod
720:
721: =item &SectionSelect($elementname,$status,$numvisible)
722:
723: Returns html for a selection box allowing the user to choose one (or more)
724: of the sections in the course.
725:
726: Uses the package variables @Sections
727: =over 4
728:
729: =item $elementname The name of the HTML form element
730:
731: =item $status 'multiple' or 'single' selection box
732:
733: =item $numvisible The number of options to be visible
734:
735: =back
736:
737: =cut
738:
739: ##############################################
740: ##############################################
741: sub SectionSelect {
742: my ($elementname,$status,$numvisible)=@_;
743: if ($numvisible < 1) {
744: return;
745: }
746: #
747: # Make sure we have the data we need to continue
748: if (! @Sections) {
749: &PrepareClasslist()
750: }
751: #
752: # Build the form element
753: my $Str = "\n";
754: $Str .= '<select name="'.$elementname.'" ';
755: if ($status ne 'single') {
756: $Str .= 'multiple="true" ';
757: }
758: $Str .= 'size="'.$numvisible.'" >'."\n";
759: #
760: # Loop through the sequences
761: foreach my $s (@Sections) {
762: $Str .= ' <option value="'.$s.'" ';
763: foreach (&get_selected_sections()) {
764: if ($s eq $_) {
765: $Str .= 'selected ';
766: last;
767: }
768: }
769: $Str .= '>'.$s."</option>\n";
770: }
771: $Str .= "</select>\n";
772: return $Str;
773: }
774:
775: ##################################################
776: ##################################################
777: sub DisplayClasslist {
778: my ($r)=@_;
779: &Apache::lonhtmlcommon::add_breadcrumb
780: ({text=>'Select One Student'});
781: #
782: # Output some of the standard interface components
783: my $Str;
784: $Str .= &Apache::lonhtmlcommon::breadcrumbs(undef,'Select One Student');
785: $Str .= '<p><table cellspacing="5">'."\n";
786: $Str .= '<tr>';
787: $Str .= '<th align="center"><b>'.&mt('Sections').'</b></th>';
788: $Str .= '<th align="center"><b>'.&mt('Enrollment Status').'</b></th>';
789: $Str .= '</tr>'.$/;
790: $Str .= '<tr>';
791: $Str .= '<td>'.
792: &Apache::lonstatistics::SectionSelect('Section','multiple',5).
793: '</td>';
794: $Str .= '<td>'.
795: &Apache::lonhtmlcommon::StatusOptions(undef,undef,5).
796: '</td>';
797:
798: $Str .= '</tr>'.$/;
799: $Str .= '</table></p>';
800: $Str .= '<input type="submit" name="selectstudent" value="'.
801: &mt('Update Display').'" />';
802: $r->print($Str);
803: $r->rflush();
804: #
805: my @Fields = ('fullname','username','domain','id','section','status');
806: #
807: $Str = '';
808: my @selected_sections = &get_selected_sections();
809: if (! @Students) {
810: if ($selected_sections[0] eq 'all') {
811: if (lc($env{'form.Status'}) eq 'any') {
812: $Str .= '<h2>'.
813: &mt('There are no students in the course.').
814: '</h2>';
815: } elsif (lc($env{'form.Status'}) eq 'active') {
816: $Str .= '<h2>'.
817: &mt('There are no currently enrolled students in the course.').
818: '</h2>';
819: } elsif (lc($env{'form.Status'}) eq 'expired') {
820: $Str .= '<h2>'.
821: &mt('There are no previously enrolled students in the course.').
822: '</h2>';
823: }
824: } else {
825: my $sections;
826: if (lc($env{'form.Status'}) eq 'any') {
827: $Str .= '<h2>'.
828: &mt('There are no students in the selected sections.').
829: '</h2>';
830: } elsif (lc($env{'form.Status'}) eq 'active') {
831: $Str .= '<h2>'.
832: &mt('There are no currently enrolled students in the selected sections.').
833: '</h2>';
834: } elsif (lc($env{'form.Status'}) eq 'expired') {
835: $Str .= '<h2>'.
836: &mt('There are no previously enrolled students in the selected sections.').
837: '</h2>';
838: }
839: }
840: $Str.= '<a href="/adm/statistics?reportSelected=student_assessment">'.
841: &mt('Click here to return to the chart').'</a>';
842: $r->print($Str);
843: $r->rflush();
844: return;
845: }
846:
847: # "Click" is asinine but it is probably not my place to change the world.
848: $Str .= '<h2>Click on a students name or username to view their chart</h2>';
849: $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
850: $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
851: foreach my $field (@Fields) {
852: $Str .= '<th><a href="/adm/statistics?'.
853: 'reportSelected=student_assessment&'.
854: 'selectstudent=1&'.
855: 'sort='.$field.'">'.&mt($field).
856: '</a></th>';
857: }
858: $Str .= '</tr>'."\n";
859: #
860: my $alternate = 0;
861: foreach my $student (@Students) { # @Students is a package variable
862: my $sname = $student->{'username'}.':'.$student->{'domain'};
863: if($alternate) {
864: $Str .= '<tr bgcolor="#ffffe6">';
865: } else {
866: $Str .= '<tr bgcolor="#ffffc6">';
867: }
868: $alternate = ($alternate + 1) % 2;
869: #
870: foreach my $field (@Fields) {
871: $Str .= '<td>';
872: if ($field eq 'fullname' || $field eq 'username') {
873: $Str .= '<a href="/adm/statistics?reportSelected=';
874: $Str .= &Apache::lonnet::escape('student_assessment');
875: $Str .= '&sort='.&Apache::lonnet::escape($env{'form.sort'});
876: $Str .= '&SelectedStudent=';
877: $Str .= &Apache::lonnet::escape($sname).'">';
878: $Str .= $student->{$field}.' ';
879: $Str .= '</a>';
880: } elsif ($field eq 'status') {
881: $Str .= &mt($student->{$field});
882: } else {
883: $Str .= $student->{$field};
884: }
885: $Str .= '</td>';
886: }
887: $Str .= "</tr>\n";
888: }
889: $Str .= '</table></td></tr></table>'."\n";
890: #
891: $r->print($Str);
892: $r->rflush();
893: #
894: return;
895: }
896:
897: ##############################################
898: ##############################################
899: sub CreateMainMenu {
900: #
901: # Define menu data
902: my @reports = ({ internal_name => 'problem_statistics',
903: name => &mt('Overall Problem Statistics'),
904: short_description =>
905: &mt('Student performance statistics on all problems.'),
906: },
907: { internal_name => 'problem_analysis',
908: name => &mt('Detailed Problem Analysis'),
909: short_description =>
910: &mt('Detailed statistics and graphs of student performance on problems.'),
911: },
912: { internal_name => 'submissiontime_analysis',
913: name => &mt('Submission Time Plots'),
914: short_description =>
915: &mt('Display and analysis of submission times on assessments.'),
916: },
917: { internal_name => 'student_submission_reports',
918: name => &mt('Student Submission Reports'),
919: short_description =>
920: &mt('Prepare reports of student submissions.'),
921: },
922: { internal_name => 'survey_reports',
923: name => &mt('Survey Reports'),
924: short_description =>
925: &mt('Prepare reports on survey results.'),
926: },
927: { internal_name => 'correct_problems_plot',
928: name => &mt('Correct Problems Plot'),
929: short_description =>
930: &mt('Display a histogram of student performance in the course.'),
931: },
932: # { internal_name => 'student_assessment',
933: # name => &mt('Problem Status Chart'),
934: # short_description =>
935: # &mt('Brief view of each students performance in course.'),
936: # },
937: # 'percentage' => 'Correct-problems Plot',
938: # 'activitylog' => 'Activity Log',
939: );
940: #
941: # Create the menu
942: my $Str;
943: $Str .= '<h2>'.&mt('Please select a report to generate').'</h2>';
944: foreach my $reportdata (@reports) {
945: $Str .=' <h3><a href="/adm/statistics?reportSelected='.
946: $reportdata->{'internal_name'}.'" >'.
947: $reportdata->{'name'}."</a></h3>\n";
948: $Str .= ' '.(' 'x8).$reportdata->{'short_description'}.
949: "\n";
950: }
951: $Str .="</dl>\n";
952: #
953: return $Str;
954: }
955:
956: ##############################################
957: ##############################################
958: sub handler {
959: my $r=shift;
960: my $c = $r->connection();
961: #
962: # Check for overloading
963: my $loaderror=&Apache::lonnet::overloaderror($r);
964: if ($loaderror) { return $loaderror; }
965: $loaderror=
966: &Apache::lonnet::overloaderror($r,
967: $env{'course.'.$env{'request.course.id'}.'.home'});
968: if ($loaderror) { return $loaderror; }
969: #
970: # Check for access
971: if (! &Apache::lonnet::allowed('vgr',$env{'request.course.id'})) {
972: $env{'user.error.msg'}=
973: $r->uri.":vgr:0:0:Cannot view grades for complete course";
974: if (! &Apache::lonnet::allowed('vgr',
975: $env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
976: $env{'user.error.msg'}=
977: $r->uri.":vgr:0:0:Cannot view grades with given role";
978: return HTTP_NOT_ACCEPTABLE;
979: }
980: }
981: #
982: # Send the header
983: &Apache::loncommon::no_cache($r);
984: &Apache::loncommon::content_type($r,'text/html');
985: $r->send_http_header;
986: if ($r->header_only) { return OK; }
987: #
988: # Extract form elements from query string
989: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
990: ['sort','reportSelected',
991: 'SelectedStudent']);
992: #
993: # Give the LON-CAPA page header
994: my $style = <<ENDSTYLE;
995: <style type="text/css">
996: ul.sub_studentans { list-style-type: none }
997: ul.sub_correctans { list-style-type: none }
998: tr.even { background-color: \#CCCCCC }
999: td.essay { border: 1px solid gray; }
1000: </style>
1001: ENDSTYLE
1002: my $html=&Apache::lonxml::xmlbegin();
1003: $r->print($html.'<head><title>'.
1004: &mt('Course Statistics and Charts').
1005: '</title>'.$style.
1006: "</head>\n".
1007: &Apache::loncommon::bodytag('Course Statistics and Charts'));
1008: $r->rflush();
1009: #
1010: # Either print out a menu for them or send them to a report
1011: &Apache::lonhtmlcommon::clear_breadcrumbs();
1012: &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/statistics',
1013: title=>'Statistics',
1014: text =>'Statistics',
1015: faq=>139,
1016: bug=>'Statistics and Charts'});
1017: if (! exists($env{'form.reportSelected'}) ||
1018: $env{'form.reportSelected'} eq '') {
1019: $r->print(&Apache::lonhtmlcommon::breadcrumbs
1020: (undef,&mt('Statistics Main Page')).
1021: &CreateMainMenu());
1022: } else {
1023: #
1024: if (! &Apache::lonmysql::verify_sql_connection()) {
1025: my $serveradmin = $r->dir_config('lonAdmEMail');
1026: $r->print('<h2><font color="Red">'.
1027: &mt('Unable to connect to database!').
1028: '</font></h2>');
1029: $r->print('<p>'.
1030: &mt('Please notify the server administrator ').
1031: '<b>'.$serveradmin.'</b></p>');
1032: $r->print('<p>'.
1033: &mt('Course Statistics and Charts cannot be '.
1034: 'retrieved until the database is restarted. '.
1035: 'Your data is intact but cannot be displayed '.
1036: 'at this time.').'</p>');
1037: $r->print('</body></html>');
1038: return;
1039: }
1040: #
1041: # Clean out the caches
1042: if (exists($env{'form.ClearCache'})) {
1043: &Apache::loncoursedata::delete_caches($env{'requres.course.id'});
1044: }
1045: #
1046: # Begin form output
1047: $r->print('<form name="Statistics" ');
1048: $r->print('method="post" action="/adm/statistics">');
1049: $r->rflush();
1050: #
1051: my $GoToPage = $env{'form.reportSelected'};
1052: #
1053: $r->print('<input type="hidden" name="reportSelected" value="'.
1054: $GoToPage.'">');
1055: if($GoToPage eq 'activitylog') {
1056: # &Apache::lonproblemstatistics::Activity();
1057: } elsif($GoToPage eq 'problem_statistics') {
1058: &Apache::lonhtmlcommon::add_breadcrumb
1059: ({href=>'/adm/statistics?reportselected=problem_statistics',
1060: text=>'Overall Problem Statistics'});
1061: &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c);
1062: } elsif($GoToPage eq 'problem_analysis') {
1063: &Apache::lonhtmlcommon::add_breadcrumb
1064: ({href=>'/adm/statistics?reportselected=problem_analysis',
1065: text=>'Detailed Problem Analysis'});
1066: &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c);
1067: } elsif($GoToPage eq 'submissiontime_analysis') {
1068: &Apache::lonhtmlcommon::add_breadcrumb
1069: ({href=>
1070: '/adm/statistics?reportselected=submissiontime_analysis',
1071: text=>'Submission Time Plots'});
1072: &Apache::lonsubmissiontimeanalysis::BuildSubmissionTimePage($r,$c);
1073: } elsif($GoToPage eq 'student_submission_reports') {
1074: &Apache::lonhtmlcommon::add_breadcrumb
1075: ({href=>
1076: '/adm/statistics?reportselected=student_submission_reports',
1077: text=>'Student Submission Reports'});
1078: &Apache::lonstudentsubmissions::BuildStudentSubmissionsPage($r,$c);
1079: } elsif($GoToPage eq 'survey_reports') {
1080: &Apache::lonhtmlcommon::add_breadcrumb
1081: ({href=>
1082: '/adm/statistics?reportselected=survey_reports',
1083: text=>'Survey Reports'});
1084: &Apache::lonsurveyreports::BuildSurveyReportsPage($r,$c);
1085: } elsif($GoToPage eq 'correct_problems_plot') {
1086: &Apache::lonhtmlcommon::add_breadcrumb
1087: ({href=>'/adm/statistics?reportselected=correct_problems_plot',
1088: text=>'Correct Problems Plot'});
1089: &Apache::loncorrectproblemplot::BuildCorrectProblemsPage($r,$c);
1090: } elsif($GoToPage eq 'student_assessment') {
1091: &Apache::lonhtmlcommon::clear_breadcrumbs();
1092: &Apache::lonhtmlcommon::add_breadcrumb
1093: ({href=>'/adm/statistics?reportselected=student_assessment',
1094: text=>'Chart'});
1095: &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c);
1096: }
1097: #
1098: $r->print("</form>\n");
1099: }
1100: $r->print("</body>\n</html>\n");
1101: $r->rflush();
1102: #
1103: return OK;
1104: }
1105:
1106: 1;
1107:
1108: #######################################################
1109: #######################################################
1110:
1111: =pod
1112:
1113: =back
1114:
1115: =cut
1116:
1117: #######################################################
1118: #######################################################
1119:
1120: __END__
1121:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>