--- loncom/interface/lonnavmaps.pm 2010/03/29 14:50:46 1.446 +++ loncom/interface/lonnavmaps.pm 2011/05/18 11:26:44 1.459 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.446 2010/03/29 14:50:46 raeburn Exp $ +# $Id: lonnavmaps.pm,v 1.459 2011/05/18 11:26:44 foxr Exp $ # # Copyright Michigan State University Board of Trustees @@ -483,7 +483,7 @@ use POSIX qw (floor strftime); use Time::HiRes qw( gettimeofday tv_interval ); use LONCAPA; use DateTime(); - +use Data::Dumper; # symbolic constants sub SYMB { return 1; } sub URL { return 2; } @@ -528,6 +528,7 @@ my %colormap = $resObj->OPEN => '', $resObj->NOTHING_SET => '', $resObj->ATTEMPTED => '', + $resObj->CREDIT_ATTEMPTED => '', $resObj->ANSWER_SUBMITTED => '', $resObj->PARTIALLY_CORRECT => '#006600' ); @@ -608,10 +609,10 @@ sub getDescription { return &mt("Having technical difficulties; please check status later"); } if ($status == $res->NOTHING_SET) { - return &mt("Not currently assigned."); + return &Apache::lonhtmlcommon::direct_parm_link(&mt("Not currently assigned.",$res->symb(),'opendate'),$part); } if ($status == $res->OPEN_LATER) { - return &mt("Open ") .timeToHumanString($open,'start'); + return &mt("Open ") .&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start'),$res->symb(),'opendate',$part); } if ($res->simpleStatus($part) == $res->OPEN) { unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) { @@ -645,27 +646,27 @@ sub getDescription { if ($status == $res->OPEN) { if ($due) { if ($res->is_practice()) { - return &mt("Closes ")." " .timeToHumanString($due,'start'); + return &mt("Closes ")." " .&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'duedate',$part); } else { - return &mt("Due")." " .timeToHumanString($due,'end'); + return &mt("Due")." " .&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part); } } else { - return &mt("Open, no due date"); + return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part); } } if ($status == $res->PAST_DUE_ANSWER_LATER) { - return &mt("Answer open")." " .timeToHumanString($answer,'start'); + return &mt("Answer open")." " .&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start'),$res->symb(),'answerdate',$part); } if ($status == $res->PAST_DUE_NO_ANSWER) { if ($res->is_practice()) { - return &mt("Closed")." " . timeToHumanString($due,'start'); + return &mt("Closed")." " . &Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'answerdate,duedate',$part); } else { - return &mt("Was due")." " . timeToHumanString($due,'end'); + return &mt("Was due")." " .&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'answerdate,duedate',$part); } } if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT) && $res->handgrade($part) ne 'yes') { - return &mt("Answer available"); + return &Apache::lonhtmlcommon::direct_parm_link(&mt("Answer available"),$res->symb(),'answerdate,duedate',$part); } if ($status == $res->EXCUSED) { return &mt("Excused by instructor"); @@ -677,6 +678,11 @@ sub getDescription { return &mt("Answer submitted, not yet graded"); } } + if ($status == $res->CREDIT_ATTEMPTED) { + if ($res->is_anonsurvey($part) || $res->is_survey($part)) { + return &mt("Credit for survey submission"); + } + } if ($status == $res->TRIES_LEFT) { my $tries = $res->tries($part); my $maxtries = $res->maxtries($part); @@ -688,10 +694,10 @@ sub getDescription { } } if ($due) { - return &mt("Due")." " . timeToHumanString($due,'end') . + return &mt("Due")." " . &Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part) . " $triesString"; } else { - return &mt("No due date")." $triesString"; + return &Apache::lonhtmlcommon::direct_parm_link(&mt("No due date"),$res->symb(),'duedate',$part)." $triesString"; } } if ($status == $res->ANSWER_SUBMITTED) { @@ -939,10 +945,10 @@ sub render_resource { } if ($resource->randomout()) { - $nonLinkedText .= ' ('.&mt('hidden').') '; + $nonLinkedText .= ' ('.&mt('hidden').') '; } if (!$resource->condval()) { - $nonLinkedText .= ' ('.&mt('conditionally hidden').') '; + $nonLinkedText .= ' ('.&mt('conditionally hidden').') '; } if (($resource->is_practice()) && ($resource->is_raw_problem())) { $nonLinkedText .=' '.&mt('not graded').''; @@ -1084,9 +1090,10 @@ sub render_long_status { } } - if ($resource->kind() eq "res" && + if (($resource->kind() eq "res" && ($resource->is_problem() || $resource->is_practice()) && - !$firstDisplayed) { + !$firstDisplayed) && + $resource->is_raw_problem()) { if ($color) {$result .= ""; } $result .= getDescription($resource, $part); if ($color) {$result .= ""; } @@ -1401,11 +1408,11 @@ sub render { my ($link,$text); if ($condition) { $link='navmaps?condition=0&filter=&'.$queryString. - '&here='.&escape($here); + '&here='.&escape($here); $text='Close all folders'; } else { $link='navmaps?condition=1&filter=&'.$queryString. - '&here='.&escape($here); + '&here='.&escape($here); $text='Open all folders'; } if ($env{'form.register'}) { @@ -1715,7 +1722,7 @@ END if (defined($anchor)) { $anchor='#'.$anchor; } my $srcHasQuestion = $src =~ /\?/; $args->{"resourceLink"} = $src. - ($srcHasQuestion?'&':'?') . + ($srcHasQuestion?'&':'?') . 'symb=' . &escape($symb).$anchor; } # Now, we've decided what parts to show. Loop through them and @@ -1777,12 +1784,11 @@ END # it's quite likely this might fix other browsers, too, and # certainly won't hurt anything. if ($displayedJumpMarker) { - $result .= " -"; +"); } $result.=&Apache::loncommon::end_data_table(); @@ -1802,40 +1808,6 @@ sub add_linkitem { $$linkitems{$name}{'text'}=&mt($text); } -sub show_linkitems { - my ($linkitems)=@_; - my @linkorder = ("blank","launchnav","closenav","firsthomework", - "everything","uncompleted","changefolder","clearbubbles"); - - my $result .= (< - -
-   -
'."\n"; - - return $result; -} - sub show_linkitems_toolbar { my ($linkitems,$condition)=@_; my @linkorder = ('firsthomework','everything','uncompleted', @@ -1959,6 +1931,9 @@ sub new { my $class = ref($proto) || $proto; my $self = {}; + $self->{USERNAME} = shift || $env{'user.name'}; + $self->{DOMAIN} = shift || $env{'user.domain'}; + # Resource cache stores navmap resources as we reference them. We generate # them on-demand so we don't pay for creating resources unless we use them. $self->{RESOURCE_CACHE} = {}; @@ -1997,8 +1972,9 @@ sub generate_course_user_opt { my $self = shift; if ($self->{COURSE_USER_OPT_GENERATED}) { return; } - my $uname=$env{'user.name'}; - my $udom=$env{'user.domain'}; + my $uname=$self->{USERNAME}; + my $udom=$self->{DOMAIN}; + my $cid=$env{'request.course.id'}; my $cdom=$env{'course.'.$cid.'.domain'}; my $cnum=$env{'course.'.$cid.'.num'}; @@ -2041,7 +2017,7 @@ sub generate_email_discuss_status { my $cdom=$env{'course.'.$cid.'.domain'}; my $cnum=$env{'course.'.$cid.'.num'}; - my %emailstatus = &Apache::lonnet::dump('email_status'); + my %emailstatus = &Apache::lonnet::dump('email_status',$self->{DOMAIN},$self->{USERNAME}); my $logoutTime = $emailstatus{'logout'}; my $courseLeaveTime = $emailstatus{'logout_'.$env{'request.course.id'}}; $self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ? @@ -2049,7 +2025,7 @@ sub generate_email_discuss_status { my %discussiontime = &Apache::lonnet::dump('discussiontimes', $cdom, $cnum); my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', - $env{'user.domain'},$env{'user.name'},'lastread'); + $self->{DOMAIN},$self->{USERNAME},'lastread'); my %lastreadtime = (); foreach my $key (keys %lastread) { my $shortkey = $key; @@ -2059,8 +2035,8 @@ sub generate_email_discuss_status { my %feedback=(); my %error=(); - my @keys = &Apache::lonnet::getkeys('nohist_email',$env{'user.domain'}, - $env{'user.name'}); + my @keys = &Apache::lonnet::getkeys('nohist_email',$self->{DOMAIN}, + $self->{USERNAME}); foreach my $msgid (@keys) { if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) { @@ -2108,8 +2084,8 @@ sub get_user_data { # Retrieve performance data on problems my %student_data = Apache::lonnet::currentdump($env{'request.course.id'}, - $env{'user.domain'}, - $env{'user.name'}); + $self->{DOMAIN}, + $self->{USERNAME}); $self->{STUDENT_DATA} = \%student_data; $self->{RETRIEVED_USER_DATA} = 1; @@ -2338,7 +2314,7 @@ resource object. Based on the symb of the resource, get a resource object for that resource. This is one of the proper ways to get a resource object. -=item * B(map_pc): +=item * B(map_pc): Based on the map_pc of the resource, get a resource object for the given map. This is one of the proper ways to get a resource object. @@ -2423,7 +2399,7 @@ sub parmval { my $self = shift; my ($what,$symb,$recurse)=@_; my $hashkey = $what."|||".$symb; - + my $cache = $self->{PARM_CACHE}; if (defined($self->{PARM_CACHE}->{$hashkey})) { if (ref($self->{PARM_CACHE}->{$hashkey}) eq 'ARRAY') { if (defined($self->{PARM_CACHE}->{$hashkey}->[0])) { @@ -2438,6 +2414,7 @@ sub parmval { } } my $result = $self->parmval_real($what, $symb, $recurse); + my $dumper = Data::Dumper->new([$result]); $self->{PARM_CACHE}->{$hashkey} = $result; if (wantarray) { return @{$result}; @@ -2460,8 +2437,8 @@ sub parmval_real { @cgrps = sort(@cgrps); $cgroup = $cgrps[0]; } - my $uname=$env{'user.name'}; - my $udom=$env{'user.domain'}; + my $uname=$self->{USERNAME}; + my $udom=$self->{DOMAIN}; unless ($symb) { return ['']; } my $result=''; @@ -2608,7 +2585,7 @@ in the filter function. Retrieves version infomation for a url. Returns the version (a number, or the string "mostrecent") for resources which have version information in the big hash. - + =cut @@ -2863,6 +2840,9 @@ sub new { weaken($self->{NAV_MAP} = shift); return undef unless ($self->{NAV_MAP}); + $self->{USERNAME} = $self->{NAV_MAP}->{USERNAME}; + $self->{DOMAIN} = $self->{NAV_MAP}->{DOMAIN}; + # Handle the parameters $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); @@ -3236,6 +3216,9 @@ sub new { weaken($self->{NAV_MAP} = shift); return undef unless ($self->{NAV_MAP}); + $self->{USERNAME} = $self->{NAV_MAP}->{USERNAME}; + $self->{DOMAIN} = $self->{NAV_MAP}->{DOMAIN}; + $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); @@ -3472,6 +3455,9 @@ sub new { weaken($self->{NAV_MAP} = shift); $self->{ID} = shift; + $self->{USERNAME} = $self->{NAV_MAP}->{USERNAME}; + $self->{DOMAIN} = $self->{NAV_MAP}->{DOMAIN}; + # Store this new resource in the parent nav map's cache. $self->{NAV_MAP}->{RESOURCE_CACHE}->{$self->{ID}} = $self; $self->{RESOURCE_ERROR} = 0; @@ -3494,7 +3480,7 @@ sub navHash { my $param = shift; my $id = shift; my $arg = $param . ($id?$self->{ID}:""); - if (defined($arg)) { + if (ref($self) && ref($self->{NAV_MAP}) && defined($arg)) { return $self->{NAV_MAP}->navhash($arg); } return; @@ -3758,9 +3744,7 @@ my %incomplete_hash = sub is_incomplete { my $self = shift; if ($self->is_problem()) { - &Apache::lonnet::logthis('is problem'); foreach my $part (@{$self->parts()}) { - &Apache::lonnet::logthis("$part status ".$self->status($part)); if (exists($incomplete_hash{$self->status($part)})) { return 1; } @@ -3874,6 +3858,12 @@ resource of the map. Returns a string with the type of the map in it. +=item *B: + +Returns a string with a comma-separated ordered list of map_pc IDs +for the hierarchy of maps containing a map, with the top level +map first, then descending to deeper levels, with the enclosing map last. + =back =cut @@ -3904,6 +3894,11 @@ sub map_type { my $pc = $self->map_pc(); return $self->navHash("map_type_$pc", 0); } +sub map_hierarchy { + my $self = shift; + my $pc = $self->map_pc(); + return $self->navHash("map_hierarchy_$pc", 0); +} ##### # Property queries @@ -3934,7 +3929,17 @@ their code.) =over 4 -=item * B: +=item * B + +returns true if the current date is such that the +specified resource part is printable. + +=item * B + +Returns true if all parts in the resource are printable making the +entire resource printable. + +=item * B Get the Client IP/Name Access Control information. @@ -3987,6 +3992,54 @@ Get the weight for the problem. =cut +sub printable { + + &Apache::lonnet::logthis("Printable"); + my ($self, $part) = @_; + + # Get the print open/close dates for the resource. + + my $start = $self->parmval("printopendate", $part); + my $end = $self->parmval("printclosedate", $part); + my $dumper = Data::Dumper->new([$self, $part, $start, $end]); + &Apache::lonnet::logthis("Start for " . $dumper->Dump); + + # The following cases apply: + # - No dates set: Printable. + # - Start date set but no end date: Printable if now >= start date. + # - End date set but no start date: Printable if now <= end date. + # - both defined: printable if start <= now <= end + # + my $now = time(); + + my $startok = 1; + my $endok = 1; + + if ($start ne '') { + $startok = $start <= $now; + } + if ($end ne '') { + $endok = $end >= $now; + } + return $startok && $endok; +} + +sub resprintable { + my $self = shift; + + # get parts...or realize there are no parts. + + my $parts = $self->parts(); + if ($parts == 0) { + return $self->printable(0); + } else { + foreach my $part (@$parts) { + if (!$self->printable($part)) { return 0; } + } + return 1; + } +} + sub acc { (my $self, my $part) = @_; my $acc = $self->parmval("acc", $part); @@ -4039,6 +4092,11 @@ sub checkedin { } } # this should work exactly like the copy in lonhomework.pm +# Why is there a copy in lonhomework? Why not centralized? +# +# TODO: Centralize duedate. +# + sub duedate { (my $self, my $part) = @_; my $date; @@ -4118,8 +4176,8 @@ sub weight { my $self = shift; my $part = shift; if (!defined($part)) { $part = '0'; } my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight', - $self->symb(), $env{'user.domain'}, - $env{'user.name'}, + $self->symb(), $self->{DOMAIN}, + $self->{USERNAME}, $env{'request.course.sec'}); return $weight; } @@ -4147,7 +4205,7 @@ sub getReturnHash { my $self = shift; if (!defined($self->{RETURN_HASH})) { - my %tmpHash = &Apache::lonnet::restore($self->symb()); + my %tmpHash = &Apache::lonnet::restore($self->symb(),undef,$self->{DOMAIN},$self->{USERNAME}); $self->{RETURN_HASH} = \%tmpHash; } } @@ -4659,6 +4717,10 @@ Information not available due to network Attempted, and not yet graded. +=item * B: + +Attempted, and credit received for attempt (survey and anonymous survey only). + =back =cut @@ -4670,6 +4732,7 @@ sub CORRECT { return 13; } sub CORRECT_BY_OVERRIDE { return 14; } sub EXCUSED { return 15; } sub ATTEMPTED { return 16; } +sub CREDIT_ATTEMPTED { return 17; } sub getCompletionStatus { my $self = shift; @@ -4688,6 +4751,13 @@ sub getCompletionStatus { if ($status eq 'incorrect_by_override') {return $self->INCORRECT_BY_OVERRIDE; } if ($status eq 'excused') {return $self->EXCUSED; } if ($status eq 'ungraded_attempted') {return $self->ATTEMPTED; } + if ($status eq 'credit_attempted') { + if ($self->is_anonsurvey($part) || $self->is_survey($part)) { + return $self->CREDIT_ATTEMPTED; + } else { + return $self->ATTEMPTED; + } + } return $self->NOT_ATTEMPTED; } @@ -4777,6 +4847,10 @@ The item is open and not yet tried. The problem has been attempted. +=item * B: + +The problem has been attempted, and credit given for the attempt (survey and anonymous survey only). + =item * B: An answer has been submitted, but the student should not see it. @@ -4850,6 +4924,10 @@ sub status { return ATTEMPTED; } + if ($completionStatus == CREDIT_ATTEMPTED) { + return CREDIT_ATTEMPTED; + } + # If it's EXCUSED, then return that no matter what if ($completionStatus == EXCUSED) { return EXCUSED; @@ -4952,7 +5030,7 @@ sub check_for_slot { my $taskstatus = $self->taskstatus(); $is_correct = (($taskstatus eq 'pass') || ($self->solved() =~ /^correct_/)); - $got_grade = ($self->solved() =~ /^(?:pass|fail)$/); + $got_grade = ($taskstatus =~ /^(?:pass|fail)$/); } else { $got_grade = 1; $is_correct = ($self->solved() =~ /^correct_/); @@ -5042,6 +5120,7 @@ my %compositeToSimple = INCORRECT() => INCORRECT, OPEN() => OPEN, ATTEMPTED() => ATTEMPTED, + CREDIT_ATTEMPTED() => CORRECT, ANSWER_SUBMITTED() => ATTEMPTED ); @@ -5116,6 +5195,7 @@ sub completable { # and it is not "attempted" (manually graded problem), it is # not "complete" if ($self->getCompletionStatus($part) == ATTEMPTED() || + $self->getCompletionStatus($part) == CREDIT_ATTEMPTED() || $status == ANSWER_SUBMITTED() ) { # did this part already, as well as we can next;