--- loncom/interface/loncoursedata.pm 2003/02/13 22:52:48 1.46 +++ loncom/interface/loncoursedata.pm 2003/02/25 15:55:15 1.50 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # (Publication Handler # -# $Id: loncoursedata.pm,v 1.46 2003/02/13 22:52:48 matthew Exp $ +# $Id: loncoursedata.pm,v 1.50 2003/02/25 15:55:15 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -120,9 +120,10 @@ sub DownloadClasslist { my ($courseDomain,$courseNumber)=split(/\_/,$courseID); my %classlist; - my $modifiedTime = &Apache::lonnet::GetFileTimestamp($courseDomain, $courseNumber, + my $modifiedTime = &Apache::lonnet::GetFileTimestamp($courseDomain, + $courseNumber, 'classlist.db', - $Apache::lonnet::perlvar{'lonUsersDir'}); + $Apache::lonnet::perlvar{'lonUsersDir'}); # Always download the information if lastDownloadTime is set to # Not downloaded, otherwise it is only downloaded if the file @@ -261,7 +262,8 @@ with stopping downloading then can not t # ----- PROCESSING FUNCTIONS --------------------------------------- - +#################################################### +#################################################### =pod @@ -278,19 +280,25 @@ The returned structure is a hash referen symb => 'symb', source => '/s/o/u/r/c/e', type => (container|assessment), + num_assess => 2, # only for container contents => [ {},{},{},{} ], # only for container parts => [11,13,15], # only for assessment - response_ids => [12,14,16] # only for assessment + response_ids => [12,14,16], # only for assessment + contents => [........] # only for container } $hash->{'contents'} is a reference to an array of hashes of the same structure. +Also returned are array references to the sequences and assessments contained +in the course. + + =cut +#################################################### +#################################################### sub get_sequence_assessment_data { - return undef; my $fn=$ENV{'request.course.fn'}; - &Apache::lonnet::logthis('filename = '.$fn); ## ## use navmaps my $navmap = Apache::lonnavmaps::navmap->new($fn.".db",$fn."_parms.db", @@ -312,25 +320,29 @@ sub get_sequence_assessment_data { my $symb = $curRes->symb(); my $src = $curRes->src(); # + my @Sequences; + my @Assessments; my @Nested_Sequences = (); # Stack of sequences, keeps track of depth my $top = { title => $title, symb => $symb, type => 'container', num_assess => 0, contents => [], }; + push (@Sequences,$top); push (@Nested_Sequences, $top); # # We need to keep track of which sequences contain homework problems # + my $previous = $top; while (scalar(@Nested_Sequences)) { + $previous = $curRes; $curRes = $iterator->next(); my $currentmap = $Nested_Sequences[-1]; # Last one on the stack if ($curRes == $iterator->BEGIN_MAP()) { # get the map itself, instead of BEGIN_MAP - $curRes = $iterator->next(); - $title = $curRes->title(); - $symb = $curRes->symb(); - $src = $curRes->src(); + $title = $previous->title();#$curRes->title(); + $symb = $previous->symb;#curRes->symb(); + $src = $previous->src();#$curRes->src(); my $newmap = { title => $title, src => $src, symb => $symb, @@ -339,6 +351,7 @@ sub get_sequence_assessment_data { contents => [], }; push (@{$currentmap->{'contents'}},$newmap); # this is permanent + push (@Sequences,$newmap); push (@Nested_Sequences, $newmap); # this is a stack next; } @@ -347,7 +360,7 @@ sub get_sequence_assessment_data { next; } next if (! ref($curRes)); - next if (! $curRes->is_problem() && !$curRes->randomout); + next if (! $curRes->is_problem());# && !$curRes->randomout); # Okay, from here on out we only deal with assessments $title = $curRes->title(); $symb = $curRes->symb(); @@ -358,12 +371,16 @@ sub get_sequence_assessment_data { symb => $symb, type => 'assessment', }; + push(@Assessments,$assessment); push(@{$currentmap->{'contents'}},$assessment); $currentmap->{'num_assess'}++; } - return $top; + return ($top,\@Sequences,\@Assessments); } +################################################# +################################################# + =pod =item &ProcessTopResourceMap() @@ -1498,11 +1515,36 @@ sub CheckForResidualDownload { =pod +=item &make_into_hash($values); + +Returns a reference to a hash as described by $values. $values is +assumed to be the result of + join(':',map {&Apache::lonnet::escape($_)} %orighash; + +This is a helper function for get_current_state. + +=cut + +################################################ +################################################ +sub make_into_hash { + my $values = shift; + my %tmp = map { &Apache::lonnet::unescape($_); } + split(':',$values); + return \%tmp; +} + + +################################################ +################################################ + +=pod + =item &get_current_state($sname,$sdom,$symb,$courseid); -Retrive the current status of a students performance. $sname and +Retrieve the current status of a students performance. $sname and $sdom are the only required parameters. If $symb is undef the results -of a &Apache::lonnet::currentdump() will be returned. +of an &Apache::lonnet::currentdump() will be returned. If $courseid is undef it will be retrieved from the environment. The return structure is based on &Apache::lonnet::currentdump. If @@ -1520,8 +1562,6 @@ If $symb is specified, a hash of ) is returned. -Eventually this routine will cache the results locally. - If no data is found for $symb, or if the student has not performance data, an empty list is returned. @@ -1529,23 +1569,98 @@ an empty list is returned. ################################################ ################################################ - sub get_current_state { - my ($sname,$sdom,$symb,$courseid)=@_; - return undef if (! defined($sname) || ! defined($sdom)); + my ($sname,$sdom,$symb,$courseid,$forcedownload)=@_; + return () if (! defined($sname) || ! defined($sdom)); + # $courseid = $ENV{'request.course.id'} if (! defined($courseid)); - # For a first pass, just get a currentdump and return the requested - # results - my @tmp = &Apache::lonnet::currentdump($courseid,$sdom,$sname); - if (! ((scalar(@tmp) > 0) && ($tmp[0] !~ /^error:/)) ) { - &Apache::lonnet::logthis('error getting data for '.$sname.':'.$sdom. - 'in course '.$courseid); - return (); + # + my $cachefilename = $Apache::lonnet::tmpdir.$ENV{'user.name'}.'_'. + $ENV{'user.domain'}.'_'. + $courseid.'_student_data.db'; + my %cache; + # + my %student_data; # return values go here + # + my $updatetime = 0; + my $key = &Apache::lonnet::escape($sname).':'. + &Apache::lonnet::escape($sdom).':'; + # Open the cache file + if (tie(%cache,'GDBM_File',$cachefilename,&GDBM_READER(),0640)) { + if (exists($cache{$key.'time'})) { + $updatetime = $cache{$key.'time'}; +# &Apache::lonnet::logthis('got updatetime of '.$updatetime); + } + untie(%cache); + } + # timestamp/devalidation + my $modifiedtime = 1; + # Take whatever steps are neccessary at this point to give $modifiedtime a + # new value + # + if (($updatetime < $modifiedtime) || + (defined($forcedownload) && $forcedownload)) { +# &Apache::lonnet::logthis("loading data"); + # Get all the students current data + my $time_of_retrieval = time; + my @tmp = &Apache::lonnet::currentdump($courseid,$sdom,$sname); + if ((scalar(@tmp) > 0) && ($tmp[0] =~ /^error:/)) { + &Apache::lonnet::logthis('error getting data for '. + $sname.':'.$sdom.' in course '.$courseid. + ':'.$tmp[0]); + return (); + } + %student_data = @tmp; + # + # Store away the data + # + # The cache structure is colon deliminated. + # $uname:$udom:time => timestamp + # $uname:$udom:$symb => $parm1:$val1:$parm2:$val2 ... + # + # BEWARE: The colons are NOT escaped so can search with escaped + # keys instead of unescaping every key. + # + if (tie(%cache,'GDBM_File',$cachefilename,&GDBM_WRCREAT(),0640)) { +# &Apache::lonnet::logthis("writing data"); + while (my ($current_symb,$param_hash) = each(%student_data)) { + my @Parameters = %{$param_hash}; + my $value = join(':',map { &Apache::lonnet::escape($_); } + @Parameters); + # Store away the values + $cache{$key.&Apache::lonnet::escape($current_symb)}=$value; + } + $cache{$key.'time'}=$time_of_retrieval; + untie(%cache); + } + } else { + &Apache::lonnet::logthis('retrieving cached data '); + if (tie(%cache,'GDBM_File',$cachefilename,&GDBM_READER(),0640)) { + if (defined($symb)) { + my $searchkey = $key.&Apache::lonnet::escape($symb); + if (exists($cache{$searchkey})) { + $student_data{$symb} = &make_into_hash($cache{$searchkey}); + } + } else { + my $searchkey = '^'.$key.'(.*)$';#' + while (my ($testkey,$params)=each(%cache)) { + if ($testkey =~ /$searchkey/) { # \Q \E? May be necc. + my $tmpsymb = $1; + next if ($tmpsymb =~ 'time'); +# &Apache::lonnet::logthis('found '.$tmpsymb.':'); + $student_data{&Apache::lonnet::unescape($tmpsymb)} = + &make_into_hash($params); + } + } + } + untie(%cache); + } } - my %student_data = @tmp; if (! defined($symb)) { +# &Apache::lonnet::logthis("returning all data"); return %student_data; } elsif (exists($student_data{$symb})) { +# &Apache::lonnet::logthis("returning data for symb=".$symb); return %{$student_data{$symb}}; } else { return ();