--- loncom/interface/Attic/lonchart.pm 2002/07/08 13:38:52 1.55 +++ loncom/interface/Attic/lonchart.pm 2002/07/08 16:50:03 1.58 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # (Publication Handler # -# $Id: lonchart.pm,v 1.55 2002/07/08 13:38:52 stredwic Exp $ +# $Id: lonchart.pm,v 1.58 2002/07/08 16:50:03 stredwic Exp $ # # Copyright Michigan State University Board of Trustees # @@ -245,6 +245,8 @@ sub FormatStudentData { my $problem = $CacheData{$problemID.':problem'}; my $LatestVersion = $CacheData{$name.":version:$problem"}; + # Output blanks for all the parts of this problem if there + # is no version information about the current problem. if(!$LatestVersion) { foreach my $part (split(/\:/,$CacheData{$sequence.':'. $problemID. @@ -257,13 +259,19 @@ sub FormatStudentData { } my %partData=undef; - #initialize data, displays skips correctly + # Initialize part data, display skips correctly + # Skip refers to when a student made no submissions on that + # part/problem. foreach my $part (split(/\:/,$CacheData{$sequence.':'. $problemID. ':parts'})) { $partData{$part.':tries'}=0; $partData{$part.':code'}=' '; } + + # Looping through all the versions of each part, starting with the + # oldest version. Basically, it gets the most recent + # set of grade data for each part. for(my $Version=1; $Version<=$LatestVersion; $Version++) { foreach my $part (split(/\:/,$CacheData{$sequence.':'. $problemID. @@ -271,6 +279,7 @@ sub FormatStudentData { if(!defined($CacheData{$name.":$Version:$problem". ":resource.$part.solved"})) { + # No grade for this submission, so skip next; } @@ -294,6 +303,9 @@ sub FormatStudentData { } } + # All grades (except for versionless parts) are displayed as links + # to their submission record. Loop through all the parts for the + # current problem in the correct order and prepare the output links $Str.=''; @@ -319,6 +331,9 @@ sub FormatStudentData { $Str.=''; } + # Output the number of correct answers for the current sequence. + # This part takes up 6 character slots, but is formated right + # justified. my $spacesNeeded=$CacheData{$sequence.':columnWidth'}-$characterCount; $spacesNeeded -= 3; $Str .= (' 'x$spacesNeeded); @@ -331,6 +346,9 @@ sub FormatStudentData { $Str .= $spacePadding; } + # Output the total correct problems over the total number of problems. + # I don't like this type of formatting, but it is a solution. Need + # a way to dynamically determine the space requirements. my $outputProblemsSolved = sprintf( "%4d", $problemsSolved ); my $outputTotalProblems = sprintf( "%4d", $totalProblems ); $Str .= ''.$outputProblemsSolved. @@ -672,7 +690,7 @@ here in the future. =item &DownloadPrerequisiteData() -Collects lastname, generation, middlename, firstname PID, and section for each +Collects lastname, generation, middlename, firstname, PID, and section for each student from their environment database. The list of students is built from collecting a classlist for the course that is to be displayed. @@ -793,6 +811,28 @@ tie hash to database later. =pod +=item &ProcessTopResourceMap() + +Trace through the "big hash" created in rat/lonuserstate.pm::loadmap. +Basically, this function organizes a subset of the data and stores it in +cached data. The data stored is the problems, sequences, sequence titles, +parts of problems, and their ordering. Column width information is also +partially handled here on a per sequence basis. + +=over 4 + +Input: $ChartDB, $c + +$ChartDB: The name of the cache database file + +$c: The connection class used to determine if an abort has been sent to the +browser + +Output: A string that contains an error message or "OK" if everything went +smoothly. + +=back + =cut sub ProcessTopResourceMap { @@ -821,6 +861,7 @@ sub ProcessTopResourceMap { return 'Could not tie cache hash.'; } + # Initialize state machine. Set information pointing to top level map. my (@sequences, @currentResource, @finishResource); my ($currentSequence, $currentResourceID, $lastResourceID); @@ -889,7 +930,7 @@ sub ProcessTopResourceMap { ':'.$currentResourceID; } - #Get Parts for problem + # Get Parts for problem my $meta=$hash{'src_'.$currentResourceID}; foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) { if($_=~/^stores\_(\d+)\_tries$/) { @@ -906,9 +947,9 @@ sub ProcessTopResourceMap { } } - #if resource == finish resource + # if resource == finish resource, then it is the end of a sequence/page if($currentResourceID eq $lastResourceID) { - #pop off last resource of sequence + # pop off last resource of sequence $currentResourceID=pop(@currentResource); $lastResourceID=pop(@finishResource); @@ -940,6 +981,8 @@ sub ProcessTopResourceMap { (scalar @titleLength); } } else { + # Remove sequence from list, if it contains no problems to + # display. $CacheData{'orderedSequences'}=~s/$currentSequence//; $CacheData{'orderedSequences'}=~s/::/:/g; $CacheData{'orderedSequences'}=~s/^:|:$//g; @@ -952,7 +995,7 @@ sub ProcessTopResourceMap { } # MOVE!!! - #move to next resource + # move to next resource unless(defined($hash{'to_'.$currentResourceID})) { # big problem, need to handle. Next is probably wrong last; @@ -981,6 +1024,35 @@ sub ProcessTopResourceMap { return 'OK'; } +=pod + +=item &ProcessSection() + +Determine the section number for a student for the class. A student can have +multiple sections for the same class. The correct one is chosen. + +=over 4 + +Input: $sectionData, $courseid, $ActiveFlag + +$sectionData: A pointer to a hash containing all section data for this +student for the class + +$courseid: The course ID. + +$ActiveFlag: The student's active status (Active/Expired) + +Output: $oldsection, $cursection, or -1 + +$oldsection and $cursection and sections number that will be displayed in the +chart. + +-1 is returned if an error occurs. + +=back + +=cut + sub ProcessSection { my ($sectionData, $courseid,$ActiveFlag)=@_; $courseid=~s/\_/\//g; @@ -1035,8 +1107,44 @@ sub ProcessSection { return '-1'; } +=pod + +=item &ProcessStudentInformation() + +Takes data downloaded for a student and breaks it up into managable pieces and +stored in cache data. The username, domain, class related date, PID, +full name, and section are all processed here. + +=over 4 + +Input: $CacheData, $studentInformation, $section, $date, $name, $courseID + +$CacheData: A hash pointer to the cached data + +$studentInformation: Student information is what was requested in +&DownloadPrerequistedData(). See that function for what data is requested. + +$section: A hash pointer to class section related information. + +$date: A composite of the start and end date for this class for this +student. Format: end:start + +$name: the username:domain information + +$courseID: The course ID + +Output: None + +*NOTE: There is no return value, but if an error occurs a key is added to +the cache data with the value being the error message. The key is +username:domain:error. It will only exist if an error occurs. + +=back + +=cut + sub ProcessStudentInformation { - my ($CacheData,$studentInformation,$section,$date,$name,$courseID,$c)=@_; + my ($CacheData,$studentInformation,$section,$date,$name,$courseID)=@_; my ($studentName,$studentDomain) = split(/\:/,$name); $CacheData->{$name.':username'}=$studentName; @@ -1066,9 +1174,43 @@ sub ProcessStudentInformation { $CacheData->{$name.':section'}=''; } - return 0; + return; } +=pod + +=item &ProcessClassList() + +Taking the class list dumped from &DownloadPrerequisiteData(), all the +students and their non-class information is processed using the +&ProcessStudentInformation() function. A date stamp is also recorded for +when the data was processed. + +=over 4 + +Input: $classlist, $courseID, $ChartDB, $c + +$classlist: The hash of data collected about a student from +&DownloadPrerequisteData(). The hash contains a list of students, a pointer +to a hash of student information for each student, and each student's section +number. + +$courseID: The course ID + +$ChartDB: The name of the cache database file. + +$c: The connection class used to determine if an abort has been sent to the +browser + +Output: @names + +@names: An array of students whose information has been processed, and are to +be considered in an arbitrary order. + +=back + +=cut + sub ProcessClassList { my ($classlist,$courseID,$ChartDB,$c)=@_; my @names=(); @@ -1089,7 +1231,7 @@ sub ProcessClassList { $classlist->{$name.':studentInformation'}, $classlist->{$name.':section'}, $classlist->{$name}, - $name,$courseID,$c); + $name,$courseID); } # Time of download @@ -1100,6 +1242,40 @@ sub ProcessClassList { return @names; } +=pod + +=item &ProcessStudentData() + +Takes the course data downloaded for a student in +&DownloadStudentCourseInformation() and breaks it up into key value pairs +to be stored in the cached data. The keys are comprised of the +$username:$domain:$keyFromCourseDatabase. The student username:domain is +stored away signifying that the student's information has been downloaded and +can be reused from cached data. + +=over 4 + +Input: $courseData, $name, $ChartDB + +$courseData: A hash pointer that points to the course data downloaded for a +student. + +$name: username:domain + +$ChartDB: The name of the cache database file which will allow the data to +be written to the cache. + +Output: None + +*NOTE: There is no output, but an error message is stored away in the cache +data. This is checked in &FormatStudentData(). The key username:domain:error +will only exist if an error occured. The error is an error from +&DownloadStudentCourseInformation(). + +=back + +=cut + sub ProcessStudentData { my ($courseData, $name, $ChartDB)=@_; @@ -1147,26 +1323,29 @@ Output: None =cut +# For all data, if ENV data doesn't exist for it, default values is used. sub ProcessFormData { my ($ChartDB, $isCached)=@_; my %CacheData; if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) { + # Ignore $ENV{'form.refresh'} + # Ignore $ENV{'form.recalculate'} + if(defined($ENV{'form.sort'})) { $CacheData{'form.sort'}=$ENV{'form.sort'}; } elsif(!defined($CacheData{'form.sort'})) { $CacheData{'form.sort'}='username'; } - # Ignore $ENV{'form.refresh'} - # Ignore $ENV{'form.recalculate'} - if(defined($ENV{'form.status'})) { $CacheData{'form.status'}=$ENV{'form.status'}; } elsif(!defined($CacheData{'form.status'})) { $CacheData{'form.status'}='Active'; } + # $found checks for any instances of form data in the ENV. If it is + # missing I assume the chrt button on the remote has been pressed. my @headings=(); my @sequences=(); my $found=0; @@ -1200,6 +1379,8 @@ sub ProcessFormData { } } + # !$found and !$isCached are how I determine if the chrt button + # on the remote was pressed and needs to reset all the selections if(defined($ENV{'form.reset'}) || (!$found && !$isCached)) { $CacheData{'form.reset'}='true'; $CacheData{'form.status'}='Active'; @@ -1287,7 +1468,8 @@ jobs. =item &ProcessFullName() Takes lastname, generation, firstname, and middlename (or some partial -set of this data) and returns the full name version as a string. +set of this data) and returns the full name version as a string. Format +is Lastname generation, firstname middlename or a subset of this. =cut @@ -1519,16 +1701,16 @@ functions return strings to BuildChart t =item &BuildChart() - The following is the process that BuildChart goes through to create the - html document. + The following is the process that BuildChart goes through to + create the html document. -Start the lonchart document -Test for access to the CacheData -Download class list information if not using cached data -Sort students and print out table desciptive data -Output student data - -If recalculating, store a list of students, but only if all their data was - downloaded. Leave off the others. + -If recalculating, store a list of students, but only if all + their data was downloaded. Leave off the others. -End document =over 4 @@ -1715,7 +1897,7 @@ sub handler { $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";