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