';
+ $Ptr .= '';
+ $Ptr .= ' ';
+ $Ptr .= ' '.
+ ''.
+ 'Active '."\n".
+ 'Expired '."\n".
+ 'Any '."\n";
+ $Ptr .= ' ';
+
+ return $Ptr;
+}
+
+sub CreateLegend {
+ my $Str = "
".
+ "1..9: correct by student in 1..9 tries\n".
+ " *: correct by student in more than 9 tries\n".
+ " +: correct by override\n".
+ " -: incorrect by override\n".
+ " .: incorrect attempted\n".
+ " #: ungraded attempted\n".
+ " : not attempted\n".
+ " x: excused".
+ " ";
+ return $Str;
+}
+
+sub StartDocument {
+ my $Str = '';
+ $Str .= '';
+ $Str .= '
';
+ $Str .= 'LON-CAPA Assessment Chart ';
+ $Str .= '';
+ $Str .= '';
+ $Str .= ' ';
+ $Str .= 'Assessment Chart ';
+ $Str .= ''.$ENV{'course.'.$ENV{'request.course.id'}.'.description'};
+ $Str .= ' ';
+
+ return $Str;
+}
- if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
-# ------------------------------------------- Set document type for header only
+# ----- END FORMAT PRINT DATA ------------------------------------------
- if ($r->header_only) {
- if ($ENV{'browser.mathml'}) {
- $r->content_type('text/xml');
- } else {
- $r->content_type('text/html');
- }
- $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
-
-
-# ------------------------------------------------------------------ Build page
-
-# ---------------------------------------------------------------- Send headers
-
- $r->content_type('text/html');
- $r->send_http_header;
- $r->print(
- 'LON-CAPA Assessment Chart ');
-
- $r->print(''.
- ''.
- ' '.
- 'Assessment Chart ');
-
-# ---------------------------------------------------------------- Course title
-
- $r->print(''.
- $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".
- " -: incorrect by override\n".
- " .: incorrect attempted\n".
- " : not attempted\n".
- " x: excused ");
-
-# ------------------------------- This is going to take a while, produce output
-
- $r->rflush();
-
-# ----------------------- 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
-
- undef @rowlabels;
- undef @students;
-
- my $classlst=&Apache::lonnet::reply
- ('dump:'.$cdom.':'.$cnum.':classlist',$chome);
- my $now=time;
- unless ($classlst=~/^error\:/) {
- map {
- my ($name,$value)=split(/\=/,$_);
- my ($end,$start)=split(/\:/,&Apache::lonnet::unescape($value));
- my $active=1;
- if (($end) && ($now>$end)) { $active=0; }
- if ($active) {
- my $thisindex=$#students+1;
- $name=&Apache::lonnet::unescape($name);
- $students[$thisindex]=$name;
- my ($sname,$sdom)=split(/\:/,$name);
- my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid);
- if ($ssec==-1) {
- $rowlabels[$thisindex]=
- 'Data not available: '.$name;
- } else {
- my %reply=&Apache::lonnet::idrget($sdom,$sname);
- my $reply=&Apache::lonnet::reply('get:'.$sdom.':'.$sname.
- ':environment:lastname&generation&firstname&middlename',
- &Apache::lonnet::homeserver($sname,$sdom));
- $rowlabels[$thisindex]=
- sprintf('%3s',$ssec).' '.$reply{$sname}.' ';
- my $i=0;
- map {
- $i++;
- if ( $_ ne '') {
- $rowlabels[$thisindex].=&Apache::lonnet::unescape($_).' ';
- }
- if ($i == 2) {
- chop($rowlabels[$thisindex]);
- $rowlabels[$thisindex].=', ';
- }
- } split(/\&/,$reply);
+# ----- 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.';
+ }
+
+ my (@sequences, @currentResource, @finishResource);
+ my ($currentSequence, $currentResourceID, $lastResourceID);
+
+ $currentResourceID=$hash{'ids_/res/'.$ENV{'request.course.uri'}};
+ push(@currentResource, $currentResourceID);
+ $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}};
+
+ # Mark sequence as containing problems. If it doesn't, then
+ # it will be removed when processing for this sequence is
+ # complete. This allows the problems in a sequence
+ # to be outputed before problems in the subsequences
+ if(!defined($CacheData{'orderedSequences'})) {
+ $CacheData{'orderedSequences'}=$currentSequence;
+ } else {
+ $CacheData{'orderedSequences'}.=':'.$currentSequence;
+ }
+
+ $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;
+ }
+ }
+ }
+
+ # 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);
+ $lastResourceID=pop(@finishResource);
+
+ if(defined($CacheData{$currentSequence.':problems'})) {
+ # Capture sequence information here
+ $CacheData{$currentSequence.':title'}=
+ $hash{'title_'.$currentResourceID};
+
+ my $totalProblems=0;
+ foreach my $currentProblem (split(/\:/,
+ $CacheData{$currentSequence.
+ ':problems'})) {
+ foreach (split(/\:/,$CacheData{$currentSequence.':'.
+ $currentProblem.
+ ':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);
+ }
+ } else {
+ $CacheData{'orderedSequences'}=~s/$currentSequence//;
+ $CacheData{'orderedSequences'}=~s/::/:/g;
+ $CacheData{'orderedSequences'}=~s/^:|:$//g;
+ }
+
+ $currentSequence=pop(@sequences);
+ if($currentSequence eq $topLevelSequenceNumber) {
+ last;
+ }
+ }
+
+ # 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_'.$_});
+ }
+ push(@currentResource, @nextResources);
+ # Set the next resource to be processed
+ $currentResourceID=pop(@currentResource);
+ }
+
+ 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)".
+ ". ");
+ }
+
+ return 'OK';
+}
+
+sub ProcessSection {
+ my ($sectionData, $courseid,$ActiveFlag)=@_;
+ $courseid=~s/\_/\//g;
+ $courseid=~s/^(\w)/\/$1/;
+
+ 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='';
+ }
+ my ($dummy,$end,$start)=split(/\_/,$value);
+ my $now=time;
+ my $notactive=0;
+ if ($start) {
+ if($now<$start) {
+ $notactive=1;
+ }
+ }
+ 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, $CacheData->{'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/ ||
+ $name eq '') {
+ next;
+ }
+ if($c->aborted()) {
+ last;
+ }
+ push(@names,$name);
+ &ProcessStudentInformation(
+ \%CacheData,
+ $classlist->{$name.':studentInformation'},
+ $classlist->{$name.':section'},
+ $classlist->{$name},
+ $name,$courseID,$c);
+ }
+
+ # Time of download
+ $CacheData{'time'}=localtime();
+ untie(%CacheData);
+ }
+
+ return @names;
+}
+
+# ----- END PROCESSING FUNCTIONS ---------------------------------------
+
+# ----- 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;
+ }
}
- } sort split(/\&/,$classlst);
+ }
+ 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 {
- $r->print('
Could not access course data ');
+ if($firstname ne '') {
+ $Str .= $firstname.' ';
+ }
+ if($middlename ne '') {
+ $Str .= $middlename.' ';
+ }
+ if($generation ne '') {
+ $Str .= $generation;
+ } else {
+ chop($Str);
+ }
}
- my $allstudents=$#students+1;
- $r->print(''.$allstudents.' students ');
- $r->rflush();
+ return $Str;
+}
-# --------------- Find all assessments and put them into some linear-like order
+sub SortStudents {
+ my ($students,$CacheData)=@_;
- &tracetable($firstres,'&'.$lastres.'&');
+ my @sorted1Students=();
+ foreach (@$students) {
+ my ($end,$start)=split(/\:/,$CacheData->{$_.':date'});
+ my $active=1;
+ my $now=time;
+ my $Status=$CacheData->{'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, $_);
+ }
+ }
-# ----------------------------------------------------------------- Start table
+ my $Pos = $CacheData->{'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; $indexprint('
');
- my $index;
- for ($index=0;$index<=$#students;$index++) {
- $r->print(&ExtractStudentData($index,$cid).' ');
- $r->rflush();
- }
- $r->print(' ');
-
- } else {
- $r->print('Undefined course sequence ');
- }
-
- $r->print('');
-
-# ------------------------------------------------------------- End render page
- } else {
- $r->content_type('text/html');
- $r->send_http_header;
- $r->print('Coursemap undefined.');
- }
-# ------------------------------------------------------------------ Untie hash
- unless (untie(%hash)) {
- &Apache::lonnet::logthis("WARNING: ".
- "Could not untie coursemap $fn (browse). ");
- }
-
-# -------------------------------------------------------------------- All done
- return OK;
-# ----------------------------------------------- Errors, hash could no be tied
- }
- } else {
- $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
- return HTTP_NOT_ACCEPTABLE;
+ return @order;
}
-} else {
- $ENV{'user.error.msg'}=
- $r->uri.":vgr:0:0:Cannot view grades for complete course";
- return HTTP_NOT_ACCEPTABLE;
+sub TestCacheData {
+ my ($ChartDB)=@_;
+ my $isCached=-1;
+ my %testData;
+ my $tieTries=0;
+
+ if ((-e "$ChartDB") && (!defined($ENV{'form.recalculate'}))) {
+ $isCached = 1;
+ } else {
+ $isCached = 0;
+ }
+
+ while($tieTries < 10) {
+ my $result=0;
+ if($isCached) {
+ $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_READER,0640);
+ } else {
+ $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_NEWDB,0640);
+ }
+ if($result) {
+ last;
+ }
+ $tieTries++;
+ sleep 1;
+ }
+ if($tieTries >= 10) {
+ 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};
+ }
+ if(defined($CacheData{'NamesOfStudents'})) {
+ $CacheData{'NamesOfStudents'}.=':::'.$name;
+ } else {
+ $CacheData{'NamesOfStudents'}=$name;
+ }
+ }
+ untie(%CacheData);
+ }
+
+ return;
}
-1;
-__END__
+sub ShouldShowColumn {
+ my ($cache,$test)=@_;
+ if($cache->{'form.reset'} eq 'true') {
+ return 1;
+ }
+ my $headings=$cache->{'form.headings'};
+ my $sequences=$cache->{'form.sequences'};
+ if($headings eq 'ALLHEADINGS' || $sequences eq 'ALLSEQUENCES' ||
+ $headings=~/$test/ || $sequences=~/$test/) {
+ return 1;
+ }
+# my $reselected=$cache->{'form.reselect'};
+# if($reselected=~/$test/) {
+# return 1;
+# }
+ return 0;
+}
+sub ProcessFormData {
+ my ($ChartDB)=@_;
+ my %CacheData;
+
+ if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ 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';
+ }
+
+ my @headings=();
+ my @sequences=();
+ my $found=0;
+ foreach (keys(%ENV)) {
+ if(/form\.heading/) {
+ $found++;
+ push(@headings, $_);
+ } elsif(/form\.sequence/) {
+ $found++;
+ push(@sequences, $_);
+ } elsif(/form\./) {
+ $found++;
+ }
+ }
+ if($found) {
+ $CacheData{'form.headings'}=join(":::",@headings);
+ $CacheData{'form.sequences'}=join(":::",@sequences);
+ }
+
+ if(defined($ENV{'form.reselect'})) {
+ my @reselected = (ref($ENV{'form.reselect'}) ?
+ @{$ENV{'form.reselect'}}
+ : ($ENV{'form.reselect'}));
+ foreach (@reselected) {
+ if(/heading/) {
+ $CacheData{'form.headings'}.=":::".$_;
+ } elsif(/sequence/) {
+ $CacheData{'form.sequences'}.=":::".$_;
+ }
+ }
+ }
+
+ if(defined($ENV{'form.reset'})) {
+ $CacheData{'form.reset'}='true';
+ $CacheData{'form.status'}='Active';
+ $CacheData{'form.sort'}='username';
+ $CacheData{'form.headings'}='ALLHEADINGS';
+ $CacheData{'form.sequences'}='ALLSEQUENCES';
+ } else {
+ $CacheData{'form.reset'}='false';
+ }
+
+ 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;
+ }
+ &ProcessFormData($ChartDB);
+
+ # Download class list information if not using cached data
+ my %CacheData;
+ 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; }
+ } else {
+ if(!$c->aborted() && tie(%CacheData,'GDBM_File',$ChartDB,
+ &GDBM_READER,0640)) {
+ @students=split(/:::/,$CacheData{'NamesOfStudents'});
+ }
+ }
+
+ # Sort students and print out table desciptive data
+ if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
+ if(!$c->aborted()) { @students=&SortStudents(\@students,\%CacheData); }
+ my $downloadTime=0;
+ if(defined($CacheData{'time'})) { $downloadTime=$CacheData{'time'}; }
+ else { $downloadTime=localtime(); }
+ if(!$c->aborted()) { $r->print(''.$downloadTime.' '); }
+ if(!$c->aborted()) { $r->print(''.(scalar @students).
+ ' students '); }
+ if(!$c->aborted()) { $r->rflush(); }
+ if(!$c->aborted()) { $r->print(&CreateLegend()); }
+ if(!$c->aborted()) { $r->print(&CreateForm(\%CacheData)); }
+ if(!$c->aborted()) { $r->print(&CreateColumnSelectionBox(
+ \%CacheData,
+ \@studentInformation,
+ \@headings,
+ $spacePadding)); }
+ if(!$c->aborted()) { $r->print(&CreateColumnSelectors(
+ \%CacheData,
+ \@studentInformation,
+ \@headings,
+ $spacePadding)); }
+ if(!$c->aborted()) { $r->print(&CreateTableHeadings(
+ \%CacheData,
+ \@studentInformation,
+ \@headings,
+ $spacePadding)); }
+ if(!$c->aborted()) { $r->rflush(); }
+ untie(%CacheData);
+ } else {
+ $r->print("Init2: Unable to tie hash to db file");
+ return;
+ }
+
+ my @updateStudentList = ();
+ my $courseData;
+ $r->print('');
+ foreach (@students) {
+ if($c->aborted()) {
+ last;
+ }
+
+ if(!$isCached) {
+ $courseData=&DownloadStudentCourseInformation($_, $cid);
+ if($c->aborted()) { last; }
+ push(@updateStudentList, $_);
+ &ExtractStudentData($courseData, $_, $ChartDB);
+ }
+ $r->print(&FormatStudentData($_, $cid, \@studentInformation,
+ $spacePadding, $ChartDB));
+ $r->rflush();
+ }
+
+ if(!$isCached && tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+ $CacheData{'NamesOfStudents'}=join(":::", @updateStudentList);
+# $CacheData{'NamesOfStudents'}=
+# &Apache::lonnet::arrayref2str(\@updateStudentList);
+ untie(%CacheData);
+ }
+
+ $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__