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