';
- $result.=&show_linkitems_toolbar($args->{'linkitems'});
- if ($args->{'sort_html'}) {
- $result.='
'.
- '
'.$args->{'sort_html'}.'
';
- }
- $result .= '
';
+ $result .= &show_linkitems_toolbar($args,$condition);
} elsif ($args->{'sort_html'}) {
$result.=$args->{'sort_html'};
}
@@ -1715,7 +1776,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
@@ -1768,6 +1829,8 @@ END
}
}
}
+
+ $result.=&Apache::loncommon::end_data_table();
# Print out the part that jumps to #curloc if it exists
# delay needed because the browser is processing the jump before
@@ -1777,16 +1840,13 @@ 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();
-
if ($r) {
$r->print($result);
$result = "";
@@ -1803,41 +1863,64 @@ sub add_linkitem {
}
sub show_linkitems_toolbar {
- my ($linkitems,$condition)=@_;
- my @linkorder = ('firsthomework','everything','uncompleted',
- 'changefolder','clearbubbles');
- my $result .='
'."\n".
- ''."\n".
- '
';
- foreach my $link (@linkorder) {
- my $link_id = 'LC_content_toolbar_'.$link;
- if (defined($linkitems->{$link})) {
- if ($linkitems->{$link}{'text'} ne '') {
- $linkitems->{$link}{'cmd'}=~s/"/'/g;
- if ($linkitems->{$link}{'cmd'}) {
- if ($link eq 'changefolder') {
- if ($condition) {
- $link_id='LC_content_toolbar_changefolder_toggled';
- } else {
- $link_id='LC_content_toolbar_changefolder';
+ my ($args,$condition) = @_;
+ my $result;
+ if (ref($args) eq 'HASH') {
+ if (ref($args->{'linkitems'}) eq 'HASH') {
+ my $numlinks = scalar(keys(%{$args->{'linkitems'}}));
+ if ($numlinks > 1) {
+ $result = '
'."\n";
return $result;
}
-
1;
@@ -1924,6 +2007,13 @@ sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
+ bless($self); # So we can call change_user if neceesary
+
+ $self->{USERNAME} = shift || $env{'user.name'};
+ $self->{DOMAIN} = shift || $env{'user.domain'};
+ $self->{CODE} = shift;
+
+
# 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.
@@ -1933,38 +2023,102 @@ sub new {
# failed
$self->{NETWORK_FAILURE} = 0;
- # tie the nav hash
+ # We can only tie the nav hash as done below if the username/domain
+ # match the env one. Otherwise change_user does everything we need...since we can't
+ # assume there are course hashes for the specific requested user@domamin:
+ #
- my %navmaphash;
- my %parmhash;
- my $courseFn = $env{"request.course.fn"};
- if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db",
- &GDBM_READER(), 0640))) {
- return undef;
+ if (($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'}) && !$self->{CODE}) {
+
+ # tie the nav hash
+
+ my %navmaphash;
+ my %parmhash;
+ my $courseFn = $env{"request.course.fn"};
+ if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db",
+ &GDBM_READER(), 0640))) {
+ return undef;
+ }
+
+ if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db",
+ &GDBM_READER(), 0640)))
+ {
+ untie %{$self->{PARM_HASH}};
+ return undef;
+ }
+
+ $self->{NAV_HASH} = \%navmaphash;
+ $self->{PARM_HASH} = \%parmhash;
+ $self->{PARM_CACHE} = {};
+ } else {
+ $self->change_user($self->{USERNAME}, $self->{DOMAIN}, $self->{CODE});
}
+
+ return $self;
+}
+
+#
+# In some instances it is useful to be able to dynamically change the
+# username/domain associated with a navmap (e.g. to navigate for someone
+# else besides the current user...if sufficiently privileged.
+# Parameters:
+# user - New user.
+# domain- Domain the user belongs to.
+# code - Anonymous CODE in use.
+# Implicit inputs:
+#
+sub change_user {
+ my $self = shift;
+ $self->{USERNAME} = shift;
+ $self->{DOMAIN} = shift;
+ $self->{CODE} = shift;
+
+ # If the hashes are already tied make sure to break that bond:
+
+ untie %{$self->{NAV_HASH}};
+ untie %{$self->{PARM_HASH}};
+
+ # The assumption is that we have to
+ # use lonmap here to re-read the hash and from it reconstruct
+ # new big and parameter hashes. An implicit assumption at this time
+ # is that the course file is probably not created locally yet
+ # an that we will therefore just read without tying.
+
+ my ($cdom, $cnum) = split(/\_/, $env{'request.course.id'});
+
+ my %big_hash;
+ &Apache::lonmap::loadmap($cnum, $cdom, $self->{USERNAME}, $self->{DOMAIN}, $self->{CODE}, \%big_hash);
+ $self->{NAV_HASH} = \%big_hash;
+
+
+
+ # Now clear the parm cache and reconstruct the parm hash fromt he big_hash
+ # param.xxxx keys.
+
+ $self->{PARM_CACHE} = {};
- if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db",
- &GDBM_READER(), 0640)))
- {
- untie %{$self->{PARM_HASH}};
- return undef;
+ my %parm_hash = {};
+ foreach my $key (keys %big_hash) {
+ if ($key =~ /^param\./) {
+ my $param_key = $key;
+ $param_key =~ s/^param\.//;
+ $parm_hash{$param_key} = $big_hash{$key};
+ }
}
- $self->{NAV_HASH} = \%navmaphash;
- $self->{PARM_HASH} = \%parmhash;
- $self->{PARM_CACHE} = {};
+ $self->{PARM_HASH} = \%parm_hash;
- bless($self);
-
- return $self;
-}
+
+
+}
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'};
@@ -1998,6 +2152,8 @@ sub generate_course_user_opt {
return;
}
+
+
sub generate_email_discuss_status {
my $self = shift;
my $symb = shift;
@@ -2007,7 +2163,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) ?
@@ -2015,7 +2171,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;
@@ -2025,8 +2181,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')) {
@@ -2074,8 +2230,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;
@@ -2389,7 +2545,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])) {
@@ -2411,10 +2567,12 @@ sub parmval {
return $result->[0];
}
+
sub parmval_real {
my $self = shift;
my ($what,$symb,$recurse) = @_;
+
# Make sure the {USER_OPT} and {COURSE_OPT} hashes are populated
$self->generate_course_user_opt();
@@ -2426,8 +2584,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='';
@@ -2443,18 +2601,23 @@ sub parmval_real {
my $mapparm=$mapname.'___(all).'.$what;
my $usercourseprefix=$cid;
+
+
my $grplevel=$usercourseprefix.'.['.$cgroup.'].'.$what;
my $grplevelr=$usercourseprefix.'.['.$cgroup.'].'.$symbparm;
my $grplevelm=$usercourseprefix.'.['.$cgroup.'].'.$mapparm;
+
my $seclevel= $usercourseprefix.'.['.$csec.'].'.$what;
my $seclevelr=$usercourseprefix.'.['.$csec.'].'.$symbparm;
my $seclevelm=$usercourseprefix.'.['.$csec.'].'.$mapparm;
+
my $courselevel= $usercourseprefix.'.'.$what;
my $courselevelr=$usercourseprefix.'.'.$symbparm;
my $courselevelm=$usercourseprefix.'.'.$mapparm;
+
my $useropt = $self->{USER_OPT};
my $courseopt = $self->{COURSE_OPT};
my $parmhash = $self->{PARM_HASH};
@@ -2521,6 +2684,217 @@ sub parmval_real {
if (defined($pack_def)) { return [$pack_def,'resource']; }
return [''];
}
+#
+# Determines the open/close dates for printing a map that
+# encloses a resource.
+#
+sub map_printdates {
+ my ($self, $res, $part) = @_;
+
+
+
+
+
+ my $opendate = $self->get_mapparam($res->symb(), "$part.printstartdate");
+ my $closedate= $self->get_mapparam($res->symb(), "$part.printenddate");
+
+
+ return ($opendate, $closedate);
+}
+
+sub get_mapparam {
+ my ($self, $symb, $what) = @_;
+
+ # Ensure the course option hash is populated:
+
+ $self->generate_course_user_opt();
+
+ # Get the course id and section if there is one.
+
+ my $cid=$env{'request.course.id'};
+ my $csec=$env{'request.course.sec'};
+ my $cgroup='';
+ my @cgrps=split(/:/,$env{'request.course.groups'});
+ if (@cgrps > 0) {
+ @cgrps = sort(@cgrps);
+ $cgroup = $cgrps[0];
+ }
+ my $uname=$self->{USERNAME};
+ my $udom=$self->{DOMAIN};
+
+ unless ($symb) { return ['']; }
+ my $result='';
+
+
+ # Figure out which map we are in.
+
+ my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);
+ $mapname = &Apache::lonnet::deversion($mapname);
+
+
+ my $rwhat=$what;
+ $what=~s/^parameter\_//;
+ $what=~s/\_/\./;
+
+ # Build the hash keys for the lookup:
+
+ my $symbparm=$symb.'.'.$what;
+ my $mapparm=$mapname.'___(all).'.$what;
+ my $usercourseprefix=$cid;
+
+
+ my $grplevel = "$usercourseprefix.[$cgroup].$mapparm";
+ my $seclevel = "$usercourseprefix.[$csec].$mapparm";
+ my $courselevel = "$usercourseprefix.$mapparm";
+
+
+ # Get handy references to the hashes we need in $self:
+
+ my $useropt = $self->{USER_OPT};
+ my $courseopt = $self->{COURSE_OPT};
+ my $parmhash = $self->{PARM_HASH};
+
+ # Check per user
+
+
+
+ if ($uname and defined($useropt)) {
+ if (defined($$useropt{$courselevel})) {
+ return $$useropt{$courselevel};
+ }
+ }
+
+ # Check course -- group
+
+
+
+ if ($cgroup ne '' and defined ($courseopt)) {
+ if (defined($$courseopt{$grplevel})) {
+ return $$courseopt{$grplevel};
+ }
+ }
+
+ # Check course -- section
+
+
+
+
+
+ if ($csec and defined($courseopt)) {
+ if (defined($$courseopt{$seclevel})) {
+ return $$courseopt{$seclevel};
+ }
+ }
+ # Check the map parameters themselves:
+
+ my $thisparm = $$parmhash{$symbparm};
+ if (defined($thisparm)) {
+ return $thisparm;
+ }
+
+
+ # Additional course parameters:
+
+ if (defined($courseopt)) {
+ if (defined($$courseopt{$courselevel})) {
+ return $$courseopt{$courselevel};
+ }
+ }
+ return undef; # Unefined if we got here.
+}
+
+sub course_printdates {
+ my ($self, $symb, $part) = @_;
+
+
+ my $opendate = $self->getcourseparam($symb, $part . '.printstartdate');
+ my $closedate = $self->getcourseparam($symb, $part . '.printenddate');
+ return ($opendate, $closedate);
+
+}
+
+sub getcourseparam {
+ my ($self, $symb, $what) = @_;
+
+ $self->generate_course_user_opt(); # If necessary populate the hashes.
+
+ my $uname = $self->{USERNAME};
+ my $udom = $self->{DOMAIN};
+
+ # Course, section, group ids come from the env:
+
+ my $cid = $env{'request.course.id'};
+ my $csec = $env{'request.course.sec'};
+ my $cgroup = ''; # Assume no group
+
+ my @cgroups = split(/:/, $env{'request.course.groups'});
+ if(@cgroups > 0) {
+ @cgroups = sort(@cgroups);
+ $cgroup = $cgroups[0]; # There is a course group.
+ }
+ my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);
+ $mapname = &Apache::lonnet::deversion($mapname);
+
+ #
+ # Make the various lookup keys:
+ #
+
+ $what=~s/^parameter\_//;
+ $what=~s/\_/\./;
+
+
+ my $symbparm = $symb . '.' . $what;
+ my $mapparm=$mapname.'___(all).'.$what;
+
+ # Local refs to the hashes we're going to look at:
+
+ my $useropt = $self->{USER_OPT};
+ my $courseopt = $self->{COURSE_OPT};
+
+ #
+ # We want the course level stuff from the way
+ # parmval_real operates
+ # TODO: Fator some of this stuff out of
+ # both parmval_real and here
+ #
+ my $courselevel = $cid . '.' . $what;
+ my $grplevel = $cid . '.[' . $cgroup . ']' . $what;
+ my $seclevel = $cid . '.[' . $csec . ']' . $what;
+
+
+ # Try for the user's course level option:
+
+ if ($uname and defined($useropt)) {
+ if (defined($$useropt{$courselevel})) {
+ return $$useropt{$courselevel};
+ }
+ }
+ # Try for the group's course level option:
+
+ if ($uname ne '' and defined($courseopt)) {
+ if (defined($$courseopt{$grplevel})) {
+ return $$courseopt{$grplevel};
+ }
+ }
+
+ # Try for section level parameters:
+
+ if ($csec and defined($courseopt)) {
+ if (defined($$courseopt{$seclevel})) {
+ return $$courseopt{$seclevel};
+ }
+ }
+ # Try for 'additional' course parameterse:
+
+ if (defined($courseopt)) {
+ if (defined($$courseopt{$courselevel})) {
+ return $$courseopt{$courselevel};
+ }
+ }
+ return undef;
+
+}
+
=pod
@@ -2829,6 +3203,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();
@@ -2942,12 +3319,14 @@ sub new {
if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) {
my $firstResource = $resource->map_start();
my $finishResource = $resource->map_finish();
- return
- Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
- $finishResource, $self->{FILTER},
- $self->{ALREADY_SEEN},
- $self->{CONDITION},
- $self->{FORCE_TOP});
+ my $result;
+ $result = Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
+ $finishResource, $self->{FILTER},
+ $self->{ALREADY_SEEN},
+ $self->{CONDITION},
+ $self->{FORCE_TOP});
+ return $result;
+
}
@@ -2967,7 +3346,6 @@ sub new {
$self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1;
bless ($self);
-
return $self;
}
@@ -2982,6 +3360,7 @@ sub next {
# do so.
if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0}) {
$self->{HAVE_RETURNED_0} = 1;
+ my $nextTopLevel = $self->{NAV_MAP}->getById('0.0');
return $self->{NAV_MAP}->getById('0.0');
}
if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {
@@ -3001,7 +3380,6 @@ sub next {
if ($self->{RECURSIVE_DEPTH} == 0) {
$self->{RECURSIVE_ITERATOR_FLAG} = 0;
}
-
return $next;
}
@@ -3077,6 +3455,8 @@ sub next {
# So we need to look at all the resources we can get to from here,
# categorize them if we haven't seen them, remember if we have a new
my $nextUnfiltered = $here->getNext();
+
+
my $maxDepthAdded = -1;
for (@$nextUnfiltered) {
@@ -3110,7 +3490,6 @@ sub next {
$self->{RECURSIVE_ITERATOR_FLAG} = 1;
my $firstResource = $self->{HERE}->map_start();
my $finishResource = $self->{HERE}->map_finish();
-
$self->{RECURSIVE_ITERATOR} =
Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
$finishResource, $self->{FILTER},
@@ -3202,6 +3581,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();
@@ -3438,10 +3820,15 @@ 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;
+ $self->{DUEDATE_CACHE} = undef;
+
# A hash that can be used by two-pass algorithms to store data
# about this resource in. Not used by the resource object
# directly.
@@ -3460,7 +3847,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;
@@ -3701,7 +4088,7 @@ sub is_practice {
sub is_problem {
my $self=shift;
my $src = $self->src();
- if ($src =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) {
+ if ($src =~ /$LONCAPA::assess_re/) {
return !($self->is_practice());
}
return 0;
@@ -3724,9 +4111,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;
}
@@ -3738,7 +4123,7 @@ sub is_incomplete {
sub is_raw_problem {
my $self=shift;
my $src = $self->src();
- if ($src =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) {
+ if ($src =~ /$LONCAPA::assess_re/) {
return 1;
}
return 0;
@@ -3911,7 +4296,19 @@ 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.
@@ -3964,6 +4361,73 @@ Get the weight for the problem.
=cut
+
+
+
+sub printable {
+
+ my ($self, $part) = @_;
+
+ &Apache::lonnet::logthis($self->symb());
+
+
+ # The following cases apply:
+ # - If a start date is not set, it is replaced by the open date.
+ # - Ditto for start/open replaced by content open.
+ # - If neither start nor printdates are set the part is 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
+ #
+
+ # Get the print open/close dates for the resource.
+
+ my $start = $self->parmval("printstartdate", $part);
+ my $end = $self->parmval("printenddate", $part);
+
+ if (!$start) {
+ $start = $self->parmval("opendate", $part);
+ }
+ if (!$start) {
+ $start = $self->parmval("contentopen", $part);
+ }
+
+
+ my $now = time();
+
+
+ my $startok = 1;
+ my $endok = 1;
+
+ if ((defined $start) && ($start ne '')) {
+ $startok = $start <= $now;
+ }
+ if ((defined $end) && ($end != '')) {
+ $endok = $end >= $now;
+ }
+ return $startok && $endok;
+}
+
+sub resprintable {
+ my $self = shift;
+
+ # get parts...or realize there are no parts.
+
+ my $partsref = $self->parts();
+ my @parts = @$partsref;
+
+ if (!@parts) {
+ 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);
@@ -4016,8 +4480,16 @@ 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) = @_;
+ if (defined ($self->{DUEDATE_CACHE}->{$part})) {
+ return $self->{DUEDATE_CACHE}->{$part};
+ }
my $date;
my @interval=$self->parmval("interval", $part);
my $due_date=$self->parmval("duedate", $part);
@@ -4034,6 +4506,7 @@ sub duedate {
} else {
$date = $due_date;
}
+ $self->{DUEDATE_CACHE}->{$part} = $date;
return $date;
}
sub handgrade {
@@ -4095,8 +4568,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;
}
@@ -4124,7 +4597,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;
}
}
@@ -4636,6 +5109,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
@@ -4647,6 +5124,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;
@@ -4665,6 +5143,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;
}
@@ -4754,6 +5239,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.
@@ -4827,6 +5316,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;
@@ -4865,12 +5358,13 @@ sub status {
}
# Otherwise, it's untried and open
- return OPEN;
+ return OPEN;
}
sub check_for_slot {
my $self = shift;
my $part = shift;
+ my $symb = $self->symb();
my ($use_slots,$available,$availablestudent) = $self->slot_control($part);
if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) {
my @slots = (split(/:/,$availablestudent),split(/:/,$available));
@@ -4878,50 +5372,45 @@ sub check_for_slot {
my $cdom=$env{'course.'.$cid.'.domain'};
my $cnum=$env{'course.'.$cid.'.num'};
my $now = time;
+ my $num_usable_slots = 0;
if (@slots > 0) {
my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);
if (&Apache::lonnet::error(%slots)) {
return (UNKNOWN);
}
- my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots);
+ my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime');
my ($checkedin,$checkedinslot);
foreach my $slot_name (@sorted_slots) {
- next if (!defined($slots{$slot_name}) ||
- !ref($slots{$slot_name}));
+ next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name}));
my $end = $slots{$slot_name}->{'endtime'};
my $start = $slots{$slot_name}->{'starttime'};
my $ip = $slots{$slot_name}->{'ip'};
if ($self->simpleStatus() == OPEN) {
- my $startreserve = $slots{$slot_name}->{'startreserve'};
- my @proctors;
- if ($slots{$slot_name}->{'proctor'} ne '') {
- @proctors = split(',',$slots{$slot_name}->{'proctor'});
- }
if ($end > $now) {
- ($checkedin,$checkedinslot) = $self->checkedin();
- if ($startreserve < $now) {
- if ($start > $now) {
- return (RESERVED_LATER,$start,$slot_name);
- } else {
- if ($ip ne '') {
- if (!&Apache::loncommon::check_ip_acc($ip)) {
- return (RESERVED_LOCATION,$ip,$slot_name);
- }
- }
- if (@proctors > 0) {
- unless ((grep(/^\Q$checkedin\E/,@proctors)) &&
- ($checkedinslot eq $slot_name)) {
- return (NEEDS_CHECKIN,undef,$slot_name);
- }
+ if ($start > $now) {
+ return (RESERVED_LATER,$start,$slot_name);
+ } else {
+ if ($ip ne '') {
+ if (!&Apache::loncommon::check_ip_acc($ip)) {
+ return (RESERVED_LOCATION,$ip,$slot_name);
}
- return (RESERVED,$end,$slot_name);
}
- } else {
- if ($start > $now) {
- return (RESERVABLE,$startreserve,$slot_name);
+ my @proctors;
+ if ($slots{$slot_name}->{'proctor'} ne '') {
+ @proctors = split(',',$slots{$slot_name}->{'proctor'});
+ }
+ if (@proctors > 0) {
+ ($checkedin,$checkedinslot) = $self->checkedin();
+ unless ((grep(/^\Q$checkedin\E/,@proctors)) &&
+ ($checkedinslot eq $slot_name)) {
+ return (NEEDS_CHECKIN,undef,$slot_name);
+ }
}
+ return (RESERVED,$end,$slot_name);
}
}
+ } elsif ($end > $now) {
+ $num_usable_slots ++;
}
}
my ($is_correct,$got_grade);
@@ -4929,7 +5418,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_/);
@@ -4942,32 +5431,33 @@ sub check_for_slot {
return (CORRECT);
}
}
- return(NOT_IN_A_SLOT);
- } else {
- if (!$future_slots_checked) {
- $future_slots = &get_future_slots($cdom,$cnum,$now);
- $future_slots_checked = 1;
- }
- if ($future_slots) {
+ if ($num_usable_slots) {
return(NOT_IN_A_SLOT);
}
- return(NOTRESERVABLE);
}
- }
- return;
-}
-
-sub get_future_slots {
- my ($cdom,$cnum,$now) = @_;
- my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum);
- my $future_slots = 0;
- foreach my $slot (keys(%slots)) {
- if (($slots{$slot}->{'starttime'} > $now) &&
- ($slots{$slot}->{'endtime'} > $now)) {
- $future_slots ++;
+ my $reservable = &Apache::lonnet::get_reservable_slots($cnum,$cdom,$env{'user.name'},
+ $env{'user.domain'});
+ if (ref($reservable) eq 'HASH') {
+ if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) {
+ foreach my $slot (reverse (@{$reservable->{'now_order'}})) {
+ if (($reservable->{'now'}{$slot}{'symb'} eq '') ||
+ ($reservable->{'now'}{$slot}{'symb'} eq $symb)) {
+ return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'});
+ }
+ }
+ }
+ if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) {
+ foreach my $slot (@{$reservable->{'future_order'}}) {
+ if (($reservable->{'future'}{$slot}{'symb'} eq '') ||
+ ($reservable->{'future'}{$slot}{'symb'} eq $symb)) {
+ return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'});
+ }
+ }
+ }
}
+ return(NOTRESERVABLE);
}
- return $future_slots;
+ return;
}
sub CLOSED { return 23; }
@@ -5019,6 +5509,7 @@ my %compositeToSimple =
INCORRECT() => INCORRECT,
OPEN() => OPEN,
ATTEMPTED() => ATTEMPTED,
+ CREDIT_ATTEMPTED() => CORRECT,
ANSWER_SUBMITTED() => ATTEMPTED
);
@@ -5093,6 +5584,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;