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