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