--- loncom/interface/Attic/lonchart.pm 2002/05/30 13:08:34 1.40
+++ loncom/interface/Attic/lonchart.pm 2002/06/28 18:06:14 1.44
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonchart.pm,v 1.40 2002/05/30 13:08:34 stredwic Exp $
+# $Id: lonchart.pm,v 1.44 2002/06/28 18:06:14 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -55,305 +55,193 @@ use Apache::loncommon();
use HTML::TokeParser;
use GDBM_File;
-# -------------------------------------------------------------- Module Globals
-my %hash;
-my %CachData;
-my @cols;
-my @rowlabels;
-my @students;
-my @PreCol;
-my $r;
-
-# ------------------------------------------------------------- Find out status
+#my $jr;
+# ----- FORMAT PRINT DATA ----------------------------------------------
-sub ExtractStudentData {
- my ($index,$coid)=@_;
- my ($sname,$sdom) = split( /\:/, $students[$index] );
- my %result=&Apache::lonnet::dump($coid,$sdom,$sname);
- my $ResId;
- my $Code;
- my $Tries;
- my $Wrongs;
- my %TempHash;
- my $Version;
- my $ProbNo;
- my $ProbSolved;
- my $ProbTotal;
- my $LatestVersion;
- my $Str=substr($students[$index].
- ' ',0,14).' ! '.
- substr($rowlabels[$index].
- ' ',0,45).' ! ';
-
- my($checkForError)=keys (%result);
- if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
- my $PrTot = sprintf( "%5d", $ProbTotal );
- my $PrSvd = sprintf( "%5d", $ProbSolved );
- $Str .= ' '.''.$PrSvd.' /'.$PrTot.' ';
- return $Str;
+sub FormatStudentInformation {
+ my ($cache,$name,$studentInformation,$spacePadding)=@_;
+ my $Str='
';
+
+ foreach (@$studentInformation) {
+ my $data=$cache->{$name.':'.$_};
+ $Str .= $data;
+
+ my @dataLength=split(//,$data);
+ my $length=scalar @dataLength;
+ $Str .= (' 'x($cache->{$_.'Length'}-$length));
+ $Str .= $spacePadding;
}
- $ProbNo = 0;
- $ProbTotal = 0;
- $ProbSolved = 0;
- my $IterationNo = 0;
- foreach $ResId (@cols) {
- if ($IterationNo == 0) {$IterationNo++; next;}
- if (!$ResId) {
- my $PrNo = sprintf( "%3d", $ProbNo );
- $Str .= ' '.''.$PrNo.' ';
- $ProbSolved += $ProbNo;
- $ProbNo=0;
- next;
- }
- $ResId=~/(\d+)\.(\d+)/;
- my $meta=$hash{'src_'.$ResId};
- my $PartNo = 0;
- undef %TempHash;
- foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {
- if ($_=~/^stores\_(\d+)\_tries$/) {
- my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
- if ( $TempHash{"$Part"} eq '' ) {
- $TempHash{"$Part"} = $Part;
- $TempHash{$PartNo}=$Part;
- $TempHash{"$Part.Code"} = ' ';
- $PartNo++;
- }
- }
- }
+ return $Str;
+}
- my $Prob = &Apache::lonnet::symbclean(
- &Apache::lonnet::declutter($hash{'map_id_'.$1} ).
- '___'.$2.'___'.
- &Apache::lonnet::declutter( $hash{'src_'.$ResId} ));
- $Code=' ';
- $Tries = 0;
- $LatestVersion = $result{"version:$Prob"};
-
- if ( $LatestVersion ) {
- for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {
- my $vkeys = $result{"$Version:keys:$Prob"};
- my @keys = split(/\:/,$vkeys);
-
- foreach my $Key (@keys) {
- if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) {
- my $Part = $1;
- $Tries = $result{"$Version:$Prob:resource.$Part.tries"};
- $TempHash{"$Part.Tries"}=($Tries) ? $Tries : 0;
- my $Val = $result{"$Version:$Prob:resource.$Part.solved"};
- if ($Val eq 'correct_by_student'){$Code='*';}
- elsif ($Val eq 'correct_by_override'){$Code = '+';}
- elsif ($Val eq 'incorrect_attempted'){$Code = '.';}
- elsif ($Val eq 'incorrect_by_override'){$Code = '-';}
- elsif ($Val eq 'excused'){$Code = 'x';}
- elsif ($Val eq 'ungraded_attempted'){$Code = '#';}
- else {$Code = ' ';}
+sub FormatStudentData {
+ my ($name,$coid,$studentInformation,$spacePadding,$ChartDB)=@_;
+ my ($sname,$sdom) = split(/\:/,$name);
+ my $Str;
+ my %CacheData;
- $TempHash{"$Part.Code"} = $Code;
- }
- }
- }
-# Actually append problem to output (all parts)
- $Str.='';
- for ( my $n = 0; $n < $PartNo; $n++ ) {
- my $part = $TempHash{$n};
- my $Code = $TempHash{"$part.Code"};
- if ( $Code eq '*') {
- $ProbNo++;
- if (($TempHash{"$part.Tries"}<10) ||
- ($TempHash{"$part.Tries"} eq '')) {
- $TempHash{"$part.Code"}=$TempHash{"$part.Tries"};
- }
- }
- elsif ( $Code eq '+' ) {$ProbNo++;}
- $Str .= $TempHash{"$part.Code"};
- if ( $Code ne 'x' ) {$ProbTotal++;}
- }
- $Str.='';
- } else {
- for(my $n=0; $n<$PartNo; $n++) {
- $Str.=' ';
- $ProbTotal++;
- }
- }
+ unless(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
+ return '';
+ }
+ # Handle Student information ------------------------------------------
+ # Handle user data
+ $Str=&FormatStudentInformation(\%CacheData, $name, $studentInformation,
+ $spacePadding);
+
+ # Handle errors
+ if($CacheData{$name.':error'} =~ /environment/) {
+ untie(%CacheData);
+ $Str .= '
';
+ return $Str;
+# my $errorMessage = $CacheData{$name.':error'};
+# return ''.$sname.' | '.$sdom.
+# ' | '.$errorMessage.' | ';
}
- my $PrTot = sprintf( "%5d", $ProbTotal );
- my $PrSvd = sprintf( "%5d", $ProbSolved );
- $Str .= ' '.''.$PrSvd.' /'.$PrTot.' ';
-
- return $Str ;
-}
+ if($CacheData{$name.':error'} =~ /course/) {
+ untie(%CacheData);
+ $Str .= '';
+ return $Str;
+# my $errorMessage = 'May have no course data or '.
+# $CacheData{$name.':error'};
+# return ''.$sname.' | '.$sdom.
+# ' | '.$errorMessage.' | ';
+ }
+
+ # Handle problem data ------------------------------------------------
+ my $Version;
+ my $problemsCorrect = 0;
+ my $totalProblems = 0;
+ my $problemsSolved = 0;
+ my $numberOfParts = 0;
+ foreach my $sequence (split(/\:/,$CacheData{'orderedSequences'})) {
+ my $characterCount=0;
+ foreach my $problemID (split(/\:/,$CacheData{$sequence.':problems'})) {
+ my $problem = $CacheData{$problemID.':problem'};
+ my $LatestVersion = $CacheData{$name.":version:$problem"};
+
+ if(!$LatestVersion) {
+ foreach my $part (split(/\:/,$CacheData{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+ $Str .= ' ';
+ $totalProblems++;
+ $characterCount++;
+ }
+ next;
+ }
+
+ my %partData=undef;
+ #initialize data, displays skips correctly
+ foreach my $part (split(/\:/,$CacheData{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+ $partData{$part.':tries'}=0;
+ $partData{$part.':code'}=' ';
+ }
+ for(my $Version=1; $Version<=$LatestVersion; $Version++) {
+ foreach my $part (split(/\:/,$CacheData{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+
+ if(!defined($CacheData{$name.":$Version:$problem".
+ ":resource.$part.solved"})) {
+ next;
+ }
+
+ my $tries=0;
+ my $code=' ';
+
+ $tries = $CacheData{$name.":$Version:$problem".
+ ":resource.$part.tries"};
+ $partData{$part.':tries'}=($tries) ? $tries : 0;
+
+ my $val = $CacheData{$name.":$Version:$problem".
+ ":resource.$part.solved"};
+ if ($val eq 'correct_by_student') {$code = '*';}
+ elsif ($val eq 'correct_by_override') {$code = '+';}
+ elsif ($val eq 'incorrect_attempted') {$code = '.';}
+ elsif ($val eq 'incorrect_by_override'){$code = '-';}
+ elsif ($val eq 'excused') {$code = 'x';}
+ elsif ($val eq 'ungraded_attempted') {$code = '#';}
+ else {$code = ' ';}
+ $partData{$part.':code'}=$code;
+ }
+ }
+
+ $Str.='';
+ foreach(split(/\:/,$CacheData{$sequence.':'.$problemID.
+ ':parts'})) {
+ if($partData{$_.':code'} eq '*') {
+ $problemsCorrect++;
+ if (($partData{$_.':tries'}<10) &&
+ ($partData{$_.':tries'} ne '')) {
+ $partData{$_.':code'}=$partData{$_.':tries'};
+ }
+ } elsif($partData{$_.':code'} eq '+') {
+ $problemsCorrect++;
+ }
+
+ $Str .= $partData{$_.':code'};
+ $characterCount++;
+
+ if($partData{$_.':code'} ne 'x') {
+ $totalProblems++;
+ }
+ }
+ $Str.='';
+ }
+ my $spacesNeeded=$CacheData{$sequence.':columnWidth'}-$characterCount;
+ $spacesNeeded -= 3;
+ $Str .= (' 'x$spacesNeeded);
+
+ my $outputProblemsCorrect = sprintf( "%3d", $problemsCorrect );
+ $Str .= ''.$outputProblemsCorrect.'';
+ $problemsSolved += $problemsCorrect;
+ $problemsCorrect=0;
-# ------------------------------------------------------------ Build page table
-
-sub tracetable {
- my ($rid,$beenhere)=@_;
- unless ($beenhere=~/\&$rid\&/) {
- $beenhere.=$rid.'&';
-# new ... updating the map according to sequence and page
- if (defined($hash{'is_map_'.$rid})) {
- my $cmap=$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}};
- if ( $cmap eq 'sequence' || $cmap eq 'page' ) {
- $cols[$#cols+1]=0;
- }
- if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&
- (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) {
- my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};
-
- &tracetable($hash{'map_start_'.$hash{'src_'.$rid}},
- '&'.$frid.'&');
-
- if ($hash{'src_'.$frid}) {
- if ($hash{'src_'.$frid}=~
- /\.(problem|exam|quiz|assess|survey|form)$/) {
- $cols[$#cols+1]=$frid;
- }
- }
-
- }
- } else {
- if ($hash{'src_'.$rid}) {
- if ($hash{'src_'.$rid}=~
- /\.(problem|exam|quiz|assess|survey|form)$/) {
- $cols[$#cols+1]=$rid;
- }
- }
- }
- if (defined($hash{'to_'.$rid})) {
- foreach (split(/\,/,$hash{'to_'.$rid})){
- &tracetable($hash{'goesto_'.$_},$beenhere);
- }
- }
+ $Str .= $spacePadding;
}
-}
-sub usection {
- my ($udom,$unam,$courseid,$ActiveFlag)=@_;
- $courseid=~s/\_/\//g;
- $courseid=~s/^(\w)/\/$1/;
+ $Str .= ''.$problemsSolved.
+ ' / '.$totalProblems.'';
- my %result=&Apache::lonnet::dump('roles',$udom,$unam);
+ untie(%CacheData);
+ return $Str;
+}
- my($checkForError)=keys (%result);
- if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
- return -1;
+sub CreateTableHeadings {
+ my ($CacheData,$studentInformation,$headings,$spacePadding)=@_;
+ my $Str='';
+
+ for(my $index=0; $index<(scalar @$headings); $index++) {
+ my $data=$$headings[$index];
+ $Str .= $data;
+
+ my @dataLength=split(//,$data);
+ my $length=scalar @dataLength;
+ $Str .= (' 'x($CacheData->{$$studentInformation[$index].'Length'}-
+ $length));
+ $Str .= $spacePadding;
}
- foreach my $key (keys (%result)) {
- my $value = $result{$key};
- if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {
- my $section=$1;
- if ($key eq $courseid.'_st') { $section=''; }
- my ($dummy,$end,$start)=split(/\_/,$value);
- if ( $ActiveFlag ne 'Any' ) {
- my $now=time;
- my $notactive=0;
- if ($start) {
- if ($now<$start) { $notactive=1; }
- }
- if ($end) {
- if ($now>$end) { $notactive=1; }
- }
- if ((($ActiveFlag eq 'Expired') && $notactive == 1) ||
- (($ActiveFlag eq 'Active') && $notactive == 0 ) ) {
- return $section;
- }
- else { return '-1'; }
- }
- return $section;
- }
+ foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) {
+ $Str .= $CacheData->{$sequence.':title'};
+ my @titleLength=split(//,$CacheData->{$sequence.':title'});
+ my $leftover=$CacheData->{$sequence.':columnWidth'}-
+ (scalar @titleLength);
+ $Str .= (' 'x$leftover);
+ $Str .= $spacePadding;
}
- return '-1';
-}
-sub BuildChart {
-# ----------------------- Get first and last resource, see if there is anything
- my $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}};
- my $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}};
- if (($firstres) && ($lastres)) {
-# ----------------------------------------------------------------- Render page
- my $cid=$ENV{'request.course.id'};
- my $chome=$ENV{'course.'.$cid.'.home'};
- my ($cdom,$cnum)=split(/\_/,$cid);
-# ---------------------------------------------- Read class list and row labels
- my %classlist=&Apache::lonnet::dump('classlist',$cdom,$cnum);
-
- my($checkForError)=keys (%classlist);
- if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
- $r->print('Could not access course data
');
- } else {
- my $now=time;
- foreach my $name (keys (%classlist)) {
- my $value=$classlist{$name};
- my ($end,$start)=split(/\:/,$value);
- my $active=1;
- my $Status=$ENV{'form.status'};
- $Status = ($Status) ? $Status : 'Active';
- if ( ( ($end) && $now > $end ) &&
- ( ($Status eq 'Active') ) ) { $active=0; }
- if ( ($Status eq 'Expired') &&
- ($end == 0 || $now < $end) ) { $active=0; }
- if ($active) {
- my $thisindex=$#students+1;
- $students[$thisindex]=$name;
- my ($sname,$sdom)=split(/\:/,$name);
- $PreCol[$thisindex]=$sname.':';
- my $ssec=&usection($sdom,$sname,$cid,$Status);
- if ($ssec==-1) {
- $rowlabels[$thisindex]=
- 'Data not available: '.$name;
- } else {
- my %reply=&Apache::lonnet::idrget($sdom,$sname);
- my $reply=&Apache::lonnet::get('environment',
- ['lastname','generation'
- ,'firstname'
- ,'middlename'],
- $sdom,$sname);
- #$ssec=(int($ssec)) ? int($ssec) : $ssec;
- my $sec=sprintf('%3s',$ssec);
- $rowlabels[$thisindex]=$sec.' '.$reply{$sname}.' ';
- $PreCol[$thisindex] .= $reply.':'.$sec;
- my $i=0;
- foreach (split(/\&/,$reply)) {
- $i++;
- if ( $_ ne '') {
- $rowlabels[$thisindex].=&Apache::lonnet::unescape($_).' ';
- }
- if ($i == 2) {
- chop($rowlabels[$thisindex]);
- $rowlabels[$thisindex].=', ';
- }
- }
- }
- }
- }
- }
+ $Str .= 'Total Solved/Total Problems';
+ $Str .= '
';
- my $allstudents=$#students+1;
- $r->print(''.$allstudents.' students
');
- &CreateForm();
- $r->rflush();
-
-# --------------- Find all assessments and put them into some linear-like order
- &tracetable($firstres,'&'.$lastres.'&');
-# ----------------------------------------------------------------- Start table
-
- $r->print('');
- my $index;
- for ($index=0;$index<=$#students;$index++) {
- my $Str=&ExtractStudentData($index,$cid);
- $r->print($Str.'
');
- $r->rflush();
- $CachData{$PreCol[$index]}=$Str;
- }
- $r->print('
');
- } else {
- $r->print('Undefined course sequence
');
- }
+ return $Str;
}
sub CreateForm {
@@ -365,14 +253,14 @@ sub CreateForm {
elsif ($Status eq 'Expired' ) { $OpSel2 = 'selected'; }
else { $OpSel1 = 'selected'; }
- my $Ptr = ''."\n";
- $r->print( $Ptr );
-}
-
-sub CacheChart {
- my %list = ();
- my $count=0;
-
- my $Pos = $ENV{'form.sort'};
- if ( $Pos eq 'Last Name' ) {$Pos=1;}
- elsif ( $Pos eq 'Section' ) {$Pos=2;}
- else {$Pos=0;}
-
- foreach my $key( keys %CachData) {
- my @Temp=split(/\:/,$key);
- my $Use = $Temp[$Pos];
- $list{$Use.$key}=$key;
- $count++;
- }
- my @order = sort(keys(%list));
+ return $Ptr;
+}
- $r->print(''.$count.' students
');
- &CreateForm();
- $r->rflush();
-
- $r->print('');
- for ( my $n; $n < $count; $n++) {
- $r->print($CachData{$list{$order[$n]}}.'
');
- }
- $r->print('
');
-}
-
-sub Start {
- undef %hash;
- undef %CachData;
- undef @students;
- undef @cols;
- undef @rowlabels;
- undef @PreCol;
-
- $r->print(''.
- 'LON-CAPA Assessment Chart');
- $r->print(''.
- ''.
- ''.
- 'Assessment Chart
');
-# ---------------------------------------------------------------- Course title
- $r->print(''.$ENV{'course.'.$ENV{'request.course.id'}.
- '.description'}.'
'.localtime().
+sub CreateLegend {
+ my $Str = ''.$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
+ '
'.localtime().
"
1..9: correct by student in 1..9 tries\n".
" *: correct by student in more than 9 tries\n".
" +: correct by override\n".
@@ -438,88 +285,684 @@ sub Start {
" .: incorrect attempted\n".
" #: ungraded attempted\n".
" : not attempted\n".
- " x: excused
");
-# ------------------------------- This is going to take a while, produce output
- $r->rflush();
+ " x: excused
";
+ return $Str;
+}
- my $cid=$ENV{'request.course.id'};
- my $ChartDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
- "_$ENV{'user.domain'}_$cid\_chart.db";
+sub StartDocument {
+ my $Str = '';
+ $Str .= '';
+ $Str .= '
';
+ $Str .= 'LON-CAPA Assessment Chart';
+ $Str .= '';
+ $Str .= '';
+ $Str .= '';
+ $Str .= 'Assessment Chart
';
- if ((-e "$ChartDB") && ($ENV{'form.sort'} ne 'Recalculate Chart')) {
- if (tie(%CachData,'GDBM_File',"$ChartDB",&GDBM_READER,0640)) {
- &CacheChart();
- }
- else {
- $r->print("Unable to tie hash to db file");
+ return $Str;
+}
+
+# ----- END FORMAT PRINT DATA ------------------------------------------
+
+# ----- DOWNLOAD INFORMATION -------------------------------------------
+
+sub DownloadPrerequisiteData {
+ my ($courseID, $c)=@_;
+ my ($courseDomain,$courseNumber)=split(/\_/,$courseID);
+
+ my %classlist=&Apache::lonnet::dump('classlist',$courseDomain,
+ $courseNumber);
+ my ($checkForError)=keys (%classlist);
+ if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
+ return \%classlist;
+ }
+
+ foreach my $name (keys(%classlist)) {
+ if($c->aborted()) {
+ $classlist{'error'}='aborted';
+ return \%classlist;
+ }
+
+ my ($studentName,$studentDomain) = split(/\:/,$name);
+ # Download student environment data, specifically the full name and id.
+ my %studentInformation=&Apache::lonnet::get('environment',
+ ['lastname','generation',
+ 'firstname','middlename',
+ 'id'],
+ $studentDomain,
+ $studentName);
+ $classlist{$name.':studentInformation'}=\%studentInformation;
+
+ if($c->aborted()) {
+ $classlist{'error'}='aborted';
+ return \%classlist;
+ }
+
+ #Section
+ my %section=&Apache::lonnet::dump('roles',$studentDomain,$studentName);
+ $classlist{$name.':section'}=\%section;
+ }
+
+ return \%classlist;
+}
+
+sub DownloadStudentCourseInformation {
+ my ($name,$courseID)=@_;
+ my ($studentName,$studentDomain) = split(/\:/,$name);
+
+ # Download student course data
+ my %courseData=&Apache::lonnet::dump($courseID,$studentDomain,
+ $studentName);
+ return \%courseData;
+}
+
+# ----- END DOWNLOAD INFORMATION ---------------------------------------
+
+# ----- END PROCESSING FUNCTIONS ---------------------------------------
+
+sub ProcessTopResourceMap {
+ my ($ChartDB,$c)=@_;
+ my %hash;
+ my $fn=$ENV{'request.course.fn'};
+ if(-e "$fn.db") {
+ my $tieTries=0;
+ while($tieTries < 3) {
+ if(tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) {
+ last;
+ }
+ $tieTries++;
+ sleep 1;
}
+ if($tieTries >= 3) {
+ return 'Coursemap undefined.';
+ }
+ } else {
+ return 'Can not open Coursemap.';
+ }
+
+ my %CacheData;
+ unless(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ untie(%hash);
+ return 'Could not tie cache hash.';
}
- else {
- if (tie(%CachData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
- foreach (keys %CachData) {delete $CachData{$_};}
- &BuildChart();
+
+ my (@sequences, @currentResource, @finishResource);
+ my ($currentSequence, $currentResourceID, $lastResourceID);
+
+ $currentResourceID=$hash{'ids_/res/'.$ENV{'request.course.uri'}};
+ $lastResourceID=-1;
+ $currentSequence=-1;
+ my $topLevelSequenceNumber = $currentSequence;
+
+ while(1) {
+ if($c->aborted()) {
+ last;
+ }
+ # HANDLE NEW SEQUENCE!
+ #if page || sequence
+ if(defined($hash{'map_pc_'.$hash{'src_'.$currentResourceID}})) {
+ push(@sequences, $currentSequence);
+ push(@currentResource, $currentResourceID);
+ push(@finishResource, $lastResourceID);
+
+ $currentSequence=$hash{'map_pc_'.$hash{'src_'.$currentResourceID}};
+ $lastResourceID=$hash{'map_finish_'.
+ $hash{'src_'.$currentResourceID}};
+ $currentResourceID=$hash{'map_start_'.
+ $hash{'src_'.$currentResourceID}};
+
+ if(!($currentResourceID) || !($lastResourceID)) {
+ $currentSequence=pop(@sequences);
+ $currentResourceID=pop(@currentResource);
+ $lastResourceID=pop(@finishResource);
+ if($currentSequence eq $topLevelSequenceNumber) {
+ last;
+ }
+ }
}
- else {
- $r->print("Unable to tie hash to db file");
+
+ # Handle gradable resources: exams, problems, etc
+ $currentResourceID=~/(\d+)\.(\d+)/;
+ my $partA=$1;
+ my $partB=$2;
+ if($hash{'src_'.$currentResourceID}=~
+ /\.(problem|exam|quiz|assess|survey|form)$/ &&
+ $partA eq $currentSequence) {
+ my $Problem = &Apache::lonnet::symbclean(
+ &Apache::lonnet::declutter($hash{'map_id_'.$partA}).
+ '___'.$partB.'___'.
+ &Apache::lonnet::declutter($hash{'src_'.
+ $currentResourceID}));
+
+ $CacheData{$currentResourceID.':problem'}=$Problem;
+ if(!defined($CacheData{$currentSequence.':problems'})) {
+ $CacheData{$currentSequence.':problems'}=$currentResourceID;
+ } else {
+ $CacheData{$currentSequence.':problems'}.=
+ ':'.$currentResourceID;
+ }
+
+ #Get Parts for problem
+ my $meta=$hash{'src_'.$currentResourceID};
+ foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {
+ if($_=~/^stores\_(\d+)\_tries$/) {
+ my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
+ if(!defined($CacheData{$currentSequence.':'.
+ $currentResourceID.':parts'})) {
+ $CacheData{$currentSequence.':'.$currentResourceID.
+ ':parts'}=$Part;
+ } else {
+ $CacheData{$currentSequence.':'.$currentResourceID.
+ ':parts'}.=':'.$Part;
+ }
+ }
+ }
}
+
+ #if resource == finish resource
+ if($currentResourceID eq $lastResourceID) {
+ #pop off last resource of sequence
+ $currentResourceID=pop(@currentResource);
+ #pop to get last resource in previous sequence
+ $currentResourceID=pop(@currentResource);
+ $lastResourceID=pop(@finishResource);
+
+ if(defined($CacheData{$currentSequence.':problems'})) {
+ # Capture sequence information here
+ if(!defined($CacheData{'orderedSequences'})) {
+ $CacheData{'orderedSequences'}=$currentSequence;
+ } else {
+ $CacheData{'orderedSequences'}.=':'.$currentSequence;
+ }
+
+ $CacheData{$currentSequence.':title'}=
+ $hash{'title_'.$currentResourceID};
+
+ my $totalProblems=0;
+ foreach (split(/\:/,$CacheData{$currentSequence.
+ ':problems'})) {
+ foreach ($CacheData{$currentSequence.':'.$_.':parts'}) {
+ $totalProblems++;
+ }
+ }
+ my @titleLength=split(//,$CacheData{$currentSequence.
+ ':title'});
+ # $extra is 3 for problems correct and 3 for space
+ # between problems correct and problem output
+ my $extra = 6;
+ if(($totalProblems + $extra) > (scalar @titleLength)) {
+ $CacheData{$currentSequence.':columnWidth'}=
+ $totalProblems + $extra;
+ } else {
+ $CacheData{$currentSequence.':columnWidth'}=
+ (scalar @titleLength);
+ }
+ }
+
+ $currentSequence=pop(@sequences);
+ if($currentSequence eq $topLevelSequenceNumber) {
+ last;
+ }
+ #else
+ }
+
+ # MOVE!!!
+ #move to next resource
+ unless(defined($hash{'to_'.$currentResourceID})) {
+ # big problem, need to handle. Next is probably wrong
+ last;
+ }
+ my @nextResources=();
+ foreach (split(/\,/,$hash{'to_'.$currentResourceID})) {
+ push(@nextResources, $hash{'goesto_'.$_});
+ }
+ pop(@currentResource);
+ push(@currentResource, @nextResources);
+ # Set the next resource to be popped(processed)
+ $currentResourceID=$currentResource[-1];
+ }
+
+ unless (untie(%hash)) {
+ &Apache::lonnet::logthis("WARNING: ".
+ "Could not untie coursemap $fn (browse)".
+ ".");
+ }
+
+ unless (untie(%CacheData)) {
+ &Apache::lonnet::logthis("WARNING: ".
+ "Could not untie Cache Hash (browse)".
+ ".");
}
- untie(%CachData);
+
+ return 'OK';
}
-# ================================================================ Main Handler
+sub ProcessSection {
+ my ($sectionData, $courseid,$ActiveFlag)=@_;
+ $courseid=~s/\_/\//g;
+ $courseid=~s/^(\w)/\/$1/;
-sub handler {
- $r=shift;
- if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
-# ------------------------------------------- Set document type for header only
- if ($r->header_only) {
- if ($ENV{'browser.mathml'}) {
- $r->content_type('text/xml');
- } else {
- $r->content_type('text/html');
+ my $cursection='-1';
+ my $oldsection='-1';
+ my $status='Expired';
+ my $section='';
+ foreach my $key (keys (%$sectionData)) {
+ my $value = $sectionData->{$key};
+ if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {
+ $section=$1;
+ if($key eq $courseid.'_st') {
+ $section='';
}
- &Apache::loncommon::no_cache($r);
- $r->send_http_header;
- return OK;
- }
-
- my $requrl=$r->uri;
-# ----------------------------------------------------------------- Tie db file
- if ($ENV{'request.course.fn'}) {
- my $fn=$ENV{'request.course.fn'};
- if (-e "$fn.db") {
- if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) {
-# ------------------------------------------------------------------- Hash tied
-# ---------------------------------------------------------------- Send headers
- $r->content_type('text/html');
- $r->send_http_header;
- &Start();
- $r->print('');
-# ------------------------------------------------------------- End render page
- } else {
- $r->content_type('text/html');
- $r->send_http_header;
- $r->print('Coursemap undefined.');
+ my ($dummy,$end,$start)=split(/\_/,$value);
+ my $now=time;
+ my $notactive=0;
+ if ($start) {
+ if($now<$start) {
+ $notactive=1;
}
-# ------------------------------------------------------------------ Untie hash
- unless (untie(%hash)) {
- &Apache::lonnet::logthis("WARNING: ".
- "Could not untie coursemap $fn (browse).");
+ }
+ if($end) {
+ if ($now>$end) {
+ $notactive=1;
}
+ }
+ if($notactive == 0) {
+ $status='Active';
+ $cursection=$section;
+ last;
+ }
+ if($notactive == 1) {
+ $oldsection=$section;
+ }
+ }
+ }
+ if($status eq $ActiveFlag) {
+ if($cursection eq '-1') {
+ return $oldsection;
+ }
+ return $cursection;
+ }
+ if($ActiveFlag eq 'Any') {
+ if($cursection eq '-1') {
+ return $oldsection;
+ }
+ return $cursection;
+ }
+ return '-1';
+}
+
+sub ProcessStudentInformation {
+ my ($CacheData,$studentInformation,$section,$date,$name,$courseID,$c)=@_;
+ my ($studentName,$studentDomain) = split(/\:/,$name);
+
+ $CacheData->{$name.':username'}=$studentName;
+ $CacheData->{$name.':domain'}=$studentDomain;
+ $CacheData->{$name.':date'}=$date;
+
+ my ($checkForError)=keys(%$studentInformation);
+ if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
+ $CacheData->{$name.':error'}=
+ 'Could not download student environment data.';
+ $CacheData->{$name.':fullname'}='';
+ $CacheData->{$name.':id'}='';
+ } else {
+ $CacheData->{$name.':fullname'}=&ProcessFullName(
+ $studentInformation->{'lastname'},
+ $studentInformation->{'generation'},
+ $studentInformation->{'firstname'},
+ $studentInformation->{'middlename'});
+ $CacheData->{$name.':id'}=$studentInformation->{'id'};
+ }
+
+ # Get student's section number
+ my $sec=&ProcessSection($section, $courseID, $ENV{'form.status'});
+ if($sec != -1) {
+ $CacheData->{$name.':section'}=$sec;
+ } else {
+ $CacheData->{$name.':section'}='';
+ }
+
+ return 0;
+}
+
+sub ProcessClassList {
+ my ($classlist,$courseID,$ChartDB,$c)=@_;
+ my @names=();
+
+ my %CacheData;
+ if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ foreach my $name (keys(%$classlist)) {
+ if($name =~ /\:section/ || $name =~ /\:studentInformation/) {
+ next;
+ }
+ if($c->aborted()) {
+ last;
+ }
+ push(@names,$name);
+ &ProcessStudentInformation(
+ \%CacheData,
+ $classlist->{$name.':studentInformation'},
+ $classlist->{$name.':section'},
+ $classlist->{$name},
+ $name,$courseID,$c);
+ }
+
+ $CacheData{'NamesOfStudents'}=join(":::",@names);
+# $CacheData{'NamesOfStudents'}=&Apache::lonnet::arrayref2str(\@names);
+ untie(%CacheData);
+ }
+
+ return @names;
+}
+
+# ----- END PROCESSING FUNCTIONS ---------------------------------------
-# -------------------------------------------------------------------- All done
- return OK;
-# ----------------------------------------------- Errors, hash could no be tied
+# ----- HELPER FUNCTIONS -----------------------------------------------
+
+sub SpaceColumns {
+ my ($students,$studentInformation,$headings,$ChartDB)=@_;
+
+ my %CacheData;
+ if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ # Initialize Lengths
+ for(my $index=0; $index<(scalar @$headings); $index++) {
+ my @titleLength=split(//,$$headings[$index]);
+ $CacheData{$$studentInformation[$index].'Length'}=
+ scalar @titleLength;
+ }
+
+ foreach my $name (@$students) {
+ foreach (@$studentInformation) {
+ my @dataLength=split(//,$CacheData{$name.':'.$_});
+ my $length=scalar @dataLength;
+ if($length > $CacheData{$_.'Length'}) {
+ $CacheData{$_.'Length'}=$length;
+ }
+ }
+ }
+ untie(%CacheData);
+ }
+
+ return;
+}
+
+sub ProcessFullName {
+ my ($lastname, $generation, $firstname, $middlename)=@_;
+ my $Str = '';
+
+ if($lastname ne '') {
+ $Str .= $lastname.' ';
+ if($generation ne '') {
+ $Str .= $generation;
+ } else {
+ chop($Str);
+ }
+ $Str .= ', ';
+ if($firstname ne '') {
+ $Str .= $firstname.' ';
+ }
+ if($middlename ne '') {
+ $Str .= $middlename;
+ } else {
+ chop($Str);
+ if($firstname eq '') {
+ chop($Str);
}
+ }
+ } else {
+ if($firstname ne '') {
+ $Str .= $firstname.' ';
+ }
+ if($middlename ne '') {
+ $Str .= $middlename.' ';
+ }
+ if($generation ne '') {
+ $Str .= $generation;
} else {
- $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
- return HTTP_NOT_ACCEPTABLE;
+ chop($Str);
+ }
+ }
+
+ return $Str;
+}
+
+sub SortStudents {
+ my ($CacheData)=@_;
+ my @students = split(/:::/,$CacheData->{'NamesOfStudents'});
+# my @students=&Apache::lonnet::str2array($CacheData->{'NamesOfStudents'});
+
+ my @sorted1Students=();
+ foreach (@students) {
+ my ($end,$start)=split(/\:/,$CacheData->{$_.':date'});
+ my $active=1;
+ my $now=time;
+ my $Status=$ENV{'form.status'};
+ $Status = ($Status) ? $Status : 'Active';
+ if((($end) && $now > $end) && (($Status eq 'Active'))) {
+ $active=0;
+ }
+ if(($Status eq 'Expired') && ($end == 0 || $now < $end)) {
+ $active=0;
+ }
+ if($active) {
+ push(@sorted1Students, $_);
+ }
+ }
+
+ my $Pos = $ENV{'form.sort'};
+ my %sortData;
+ if($Pos eq 'Last Name') {
+ for(my $index=0; $index{$sorted1Students[$index].':fullname'}}=
+ $sorted1Students[$index];
+ }
+ } elsif($Pos eq 'Section') {
+ for(my $index=0; $index{$sorted1Students[$index].':section'}.
+ $sorted1Students[$index]}=$sorted1Students[$index];
+ }
+ } else {
+ # Sort by user name
+ for(my $index=0; $index= 3) {
+ return -1;
+ }
+
+ untie(%testData);
+
+ return $isCached;
+}
+
+sub ExtractStudentData {
+ my ($courseData, $name, $ChartDB)=@_;
+
+ my %CacheData;
+ if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ my ($checkForError) = keys(%$courseData);
+ if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
+ $CacheData{$name.':error'}='Could not download course data.';
+ } else {
+ foreach my $key (keys (%$courseData)) {
+ $CacheData{$name.':'.$key}=$courseData->{$key};
+ }
+ }
+ untie(%CacheData);
+ }
+
+ return;
+}
+
+# ----- END HELPER FUNCTIONS --------------------------------------------
+
+sub BuildChart {
+ my ($r)=@_;
+ my $c = $r->connection;
+
+ # Start the lonchart document
+ $r->content_type('text/html');
+ $r->send_http_header;
+ $r->print(&StartDocument());
+ $r->rflush();
+
+ # Test for access to the CacheData
+ my $isCached=0;
+ my $cid=$ENV{'request.course.id'};
+ my $ChartDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
+ "_$ENV{'user.domain'}_$cid\_chart.db";
+
+ $isCached=&TestCacheData($ChartDB);
+ if($isCached < 0) {
+ $r->print("Unable to tie hash to db file");
+ $r->rflush();
+ return;
+ }
+
+ # Download class list information if not using cached data
+ my @students=();
+ my @studentInformation=('username','domain','section','id','fullname');
+ my @headings=('User Name','Domain','Section','PID','Full Name');
+ my $spacePadding=' ';
+ if(!$isCached) {
+ my $processTopResourceMapReturn=&ProcessTopResourceMap($ChartDB,$c);
+ if($processTopResourceMapReturn ne 'OK') {
+ $r->print($processTopResourceMapReturn);
+ return;
+ }
+ if($c->aborted()) { return; }
+ my $classlist=&DownloadPrerequisiteData($cid, $c);
+ my ($checkForError)=keys(%$classlist);
+ if($checkForError =~ /^(con_lost|error|no_such_host)/i ||
+ defined($classlist->{'error'})) {
+ return;
+ }
+ if($c->aborted()) { return; }
+ @students=&ProcessClassList($classlist,$cid,$ChartDB,$c);
+ if($c->aborted()) { return; }
+ &SpaceColumns(\@students,\@studentInformation,\@headings,
+ $ChartDB);
+ if($c->aborted()) { return; }
+ }
+
+ # Sort students and print out table desciptive data
+ my %CacheData;
+ if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
+ if(!$c->aborted()) { @students=&SortStudents(\%CacheData); }
+ if(!$c->aborted()) { $r->print(&CreateLegend()); }
+ if(!$c->aborted()) { $r->print(&CreateForm()); }
+ if(!$c->aborted()) { $r->print(''.(scalar @students).
+ ' students
'); }
+ if(!$c->aborted()) { $r->rflush(); }
+ if(!$c->aborted()) { $r->print(&CreateTableHeadings(
+ \%CacheData,
+ \@studentInformation,
+ \@headings,
+ $spacePadding)); }
+ untie(%CacheData);
+ } else {
+ $r->print("Init2: Unable to tie hash to db file");
+ return;
+ }
+
+ my @updateStudentList = ();
+ my $courseData;
+ foreach (@students) {
+ if($c->aborted()) {
+ if(!$isCached &&
+ tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ $CacheData{'NamesOfStudents'}=join(":::", @updateStudentList);
+# $CacheData{'NamesOfStudents'}=
+# &Apache::lonnet::arrayref2str(\@updateStudentList);
+ untie(%CacheData);
+ }
+ last;
+ }
+
+ if(!$isCached) {
+ $courseData=&DownloadStudentCourseInformation($_, $cid);
+ if($c->aborted()) { next; }
+ push(@updateStudentList, $_);
+ &ExtractStudentData($courseData, $_, $ChartDB);
+ }
+ $r->print(&FormatStudentData($_, $cid, \@studentInformation,
+ $spacePadding, $ChartDB));
+ $r->rflush();
+ }
+
+ $r->print('');
+ $r->rflush();
+
+ return;
+}
+
+# ================================================================ Main Handler
+
+sub handler {
+ my $r=shift;
+# $jr=$r;
+ unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
$ENV{'user.error.msg'}=
$r->uri.":vgr:0:0:Cannot view grades for complete course";
return HTTP_NOT_ACCEPTABLE;
}
+
+ # Set document type for header only
+ if ($r->header_only) {
+ if($ENV{'browser.mathml'}) {
+ $r->content_type('text/xml');
+ } else {
+ $r->content_type('text/html');
+ }
+ &Apache::loncommon::no_cache($r);
+ $r->send_http_header;
+ return OK;
+ }
+
+ unless($ENV{'request.course.fn'}) {
+ my $requrl=$r->uri;
+ $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
+ return HTTP_NOT_ACCEPTABLE;
+ }
+
+ &BuildChart($r);
+
+ return OK;
}
1;
__END__