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