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