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