[LON-CAPA-cvs] cvs: loncom /interface lonnavmaps.pm lonprintout.pm
foxr
foxr at source.lon-capa.org
Mon May 28 06:31:17 EDT 2012
foxr Mon May 28 10:31:17 2012 EDT
Modified files:
/loncom/interface lonnavmaps.pm lonprintout.pm
Log:
BZ 3462 - Alter choices presented to students if folders or the course itself
are not printable.
-------------- next part --------------
Index: loncom/interface/lonnavmaps.pm
diff -u loncom/interface/lonnavmaps.pm:1.484 loncom/interface/lonnavmaps.pm:1.485
--- loncom/interface/lonnavmaps.pm:1.484 Mon May 7 19:43:44 2012
+++ loncom/interface/lonnavmaps.pm Mon May 28 10:31:17 2012
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.484 2012/05/07 19:43:44 raeburn Exp $
+# $Id: lonnavmaps.pm,v 1.485 2012/05/28 10:31:17 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
@@ -487,7 +487,7 @@
# For debugging
-# use Data::Dumper;
+use Data::Dumper;
# symbolic constants
@@ -2146,6 +2146,8 @@
return;
}
+
+
sub generate_email_discuss_status {
my $self = shift;
my $symb = shift;
@@ -2559,10 +2561,12 @@
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();
@@ -2591,18 +2595,23 @@
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};
@@ -2669,6 +2678,217 @@
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
@@ -3094,12 +3314,14 @@
my $firstResource = $resource->map_start();
my $finishResource = $resource->map_finish();
my $result;
- return
- Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
- $finishResource, $self->{FILTER},
- $self->{ALREADY_SEEN},
- $self->{CONDITION},
- $self->{FORCE_TOP});
+ $result = Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
+ $finishResource, $self->{FILTER},
+ $self->{ALREADY_SEEN},
+ $self->{CONDITION},
+ $self->{FORCE_TOP});
+ return $result;
+
+
}
# Set up some bookkeeping information.
@@ -4068,11 +4290,13 @@
=over 4
+
=item * B<printable>
returns true if the current date is such that the
specified resource part is printable.
+
=item * B<resprintable>
Returns true if all parts in the resource are printable making the
@@ -4131,6 +4355,9 @@
=cut
+
+
+
sub printable {
my ($self, $part) = @_;
Index: loncom/interface/lonprintout.pm
diff -u loncom/interface/lonprintout.pm:1.615 loncom/interface/lonprintout.pm:1.616
--- loncom/interface/lonprintout.pm:1.615 Tue Apr 10 09:49:36 2012
+++ loncom/interface/lonprintout.pm Mon May 28 10:31:17 2012
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Printout
#
-# $Id: lonprintout.pm,v 1.615 2012/04/10 09:49:36 foxr Exp $
+# $Id: lonprintout.pm,v 1.616 2012/05/28 10:31:17 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -47,7 +47,7 @@
use HTTP::Response;
use LONCAPA::map();
-use POSIX qw(strftime);
+use POSIX qw(ctime);
use Apache::lonlocal;
use Carp;
use LONCAPA;
@@ -77,6 +77,71 @@
#---------------------------- Helper helpers. -------------------------
+##
+# Filter function to determine if a resource is a printable sequence.
+#
+# @param $res -Resource to check.
+#
+# @return 1 - printable and a resource
+# 0 - either notm a sequence or not printable.
+#
+sub printable_sequence {
+ my $res = shift;
+
+ # Non-sequences are not listed:
+
+ if (!$res->is_sequence()) {
+ return 0;
+ }
+
+ # Person with pav or pfo can always print:
+
+ if ($perm{'pav'} || $perm{'pfo'}) {
+ return 1;
+ }
+
+ if ($res->is_sequence()) {
+ my $symb = $res->symb();
+ &Apache::lonnet::logthis("Symb: $symb");
+ my $navmap = $res->{NAV_MAP};
+
+ # Find the first resource in the map:
+
+ my $iterator = $navmap->getIterator($res, undef, undef, 1, 1);
+ my $first = $iterator->next();
+
+ while (1) {
+ if ($first == $iterator->END_ITERATOR) {
+ &Apache::lonnet::logthis("End of iterator");
+ last; }
+ if (ref($first)) {
+ &Apache::lonnet::logthis("Looking at: " . $first->symb());
+ } else {
+ &Apache::lonnet::logthis("Got: $first");
+ }
+ if (ref($first) && ! $first->is_sequence()) {last; }
+ $first = $iterator->next();
+ }
+
+
+ # Might be an empty map:
+
+ if (!ref($first)) {
+ &Apache::lonnet::logthis("printable_sequence: empty");
+ return 0;
+ }
+ my $partsref = $first->parts();
+ my @parts = @$partsref;
+ &Apache::lonnet::logthis("Dates for " . $first->symb());
+ my ($open, $close) = $navmap->map_printdates($first, $parts[0]);
+ &Apache::lonnet::logthis("Opens $open, closes $close");
+ &Apache::lonnet::logthis(ctime($open));
+ &Apache::lonnet::logthis(ctime($close));
+ return &printable($open, $close);
+ }
+ return 0;
+}
+
# BZ5209:
# Create the states needed to run the helper for incomplete problems from
# the current folder for selected students.
@@ -435,6 +500,83 @@
#-----------------------------------------------------------------------
+# Computes an open and close date from a list of open/close dates for a resource's
+# parts.
+#
+# @param \@opens - reference to an array of open dates.
+# @param \@closes - reference to an array of close dates.
+#
+# @return ($open, $close)
+#
+# @note If open/close dates are not defined they will be retunred as undef
+# @note It is possible for there to be no overlap in which case -1,-1
+# will be returned.
+# @note The algorithm used is to take the latest open date and the earliest end date.
+#
+sub compute_open_window {
+ my ($opensref, $closesref) = @_;
+
+ my @opens = @$opensref;
+ my @closes = @$closesref;
+
+ # latest open date:
+ my $latest_open;
+
+ foreach my $open (@opens) {
+ if (!defined($latest_open) || ($open > $latest_open)) {
+ $latest_open = $open;
+ }
+ }
+ # Earliest close:
+
+ my $earliest_close;
+ foreach my $close (@closes) {
+ if (!defined($earliest_close) || ($close < $earliest_close)) {
+ $earliest_close = $close;
+ }
+ }
+
+ # If no overlap...both are -1 as promised.
+
+ if (defined($earliest_close) && defined($latest_open)
+ && ($earliest_close < $latest_open)) {
+ $latest_open = -1;
+ $earliest_close = -1;
+ }
+
+ return ($latest_open, $earliest_close);
+
+}
+
+##
+# Determines if 'now' is within the set of printable dates.
+#
+# @param $open_date - Starting date/timestamp.
+# @param $close_date - Ending date/timestamp.
+#
+# @return 0 - Not open.
+# @return 1 - open.
+#
+sub printable {
+ my ($open_date, $close_date) = @_;
+
+
+ my $now = time();
+
+ # Have to do a bit of fancy footwork around undefined open/close dates:
+
+ if ($open_date && ($open_date > $now)) {
+ return 0;
+ }
+
+ if ($close_date && ($close_date < $now)) {
+ return 0;
+ }
+
+ return 1;
+
+}
+
##
# Returns the innermost print start/print end dates for a resource.
# This is done by looking at the start/end dates for its parts and choosing
@@ -456,22 +598,87 @@
my @parts = @$partsref;
my $open_date;
my $close_date;
+ my @open_dates;
+ my @close_dates;
+
if (defined(@parts) && (scalar(@parts) > 0)) {
foreach my $part (@parts) {
my $partopen = $res->parmval('printstartdate', $part);
my $partclose = $res->parmval('printenddate', $part);
-
- $open_date = POSIX::strftime('%D', localtime($partopen));
- $close_date = POSIX::strftime('%D', localtime($partclose));
-
- # TODO: Complete this function and use it to tailor the
- # can't print current resource message.
- #
-
+
+ push(@open_dates, $partopen);
+ push(@close_dates, $partclose);
}
}
+ ($open_date, $close_date) = &compute_open_window(\@open_dates, \@close_dates);
+
+ if ($open_date) {
+ $open_date = POSIX::strftime('%D', localtime($open_date));
+ }
+ if ($close_date) {
+ $close_date = POSIX::strftime('%D', localtime($close_date));
+ }
+
+ return ($open_date, $close_date);
+}
+
+##
+# Get the dates for which a course says a resource can be printed. This is like
+# get_print_dates but namvaps::course_print_dates are gotten...and not converted
+# to times either.
+#
+# @param $res - Reference to a resource has from lonnvampas::resource.
+#
+# @return (opendate, closedate)
+#
+sub course_print_dates {
+ my $res = shift;
+ my $partsref = $res->parts();
+ my @parts = @$partsref;
+ my $open_date;
+ my $close_date;
+ my @open_dates;
+ my @close_dates;
+ my $navmap = $res->{NAV_MAP}; # Slightly OO dirty.
+
+ # Don't bother looping over undefined or empty parts arraY;
+
+ if (defined(@parts) && (scalar(@parts) > 0)) {
+ foreach my $part (@parts) {
+ my ($partopen, $partclose) = $navmap->course_printdates($res, $part);
+ push(@open_dates, $partopen);
+ push(@close_dates, $partclose);
+ }
+ ($open_date, $close_date) = &compute_open_window(\@open_dates, \@close_dates);
+ }
+ return ($open_date, $close_date);
+}
+##
+# Same as above but for the enclosing map:
+#
+sub map_print_dates {
+ my $res = shift;
+ my $partsref = $res->parts();
+ my @parts = @$partsref;
+ my $open_date;
+ my $close_date;
+ my @open_dates;
+ my @close_dates;
+ my $navmap = $res->{NAV_MAP}; # slightly OO dirty.
+
+
+ # Don't bother looping over undefined or empty parts arraY;
+
+ if (defined(@parts) && (scalar(@parts) > 0)) {
+ foreach my $part (@parts) {
+ my ($partopen, $partclose) = $navmap->map_printdates($res, $part);
+ push(@open_dates, $partopen);
+ push(@close_dates, $partclose);
+ }
+ ($open_date, $close_date) = &compute_open_window(\@open_dates, \@close_dates);
+ }
return ($open_date, $close_date);
}
@@ -3756,6 +3963,10 @@
my $userCanPrint = ($perm{'pav'} || $perm{'pfo'});
my $res_printstartdate;
my $res_printenddate;
+ my $map_open = 0;
+ my $map_close = 0xffffffff;
+ my $course_open = 0;
+ my $course_close = 0xffffffff;
# Get the resource name from construction space
if ($helper->{VARS}->{'construction'}) {
@@ -3774,6 +3985,9 @@
my $res = $navmap->getBySymb($symb);
$res_printable = $res->resprintable() | $userCanPrint; #printability in course context
($res_printstartdate, $res_printenddate) = &get_print_dates($res);
+ ($course_open, $course_close) = &course_print_dates($res);
+ ($map_open, $map_close) = &map_print_dates($res);
+
} else {
# Resource space.
@@ -3792,6 +4006,7 @@
if (!$helper->{VARS}->{'curseed'} && $env{'form.curseed'}) {
$helper->{VARS}->{'curseed'}=$env{'form.curseed'};
}
+
if (!$helper->{VARS}->{'probstatus'} && $env{'form.problemtype'}) {
$helper->{VARS}->{'probstatus'}=$env{'form.problemstatus'};
}
@@ -3927,7 +4142,7 @@
my $nextState = 'CHOOSE_INCOMPLETE_SEQ';
my $textSuffix = '';
- if ($userCanPrint) {
+ if ($userCanPrint) {
$printSelector = 'map_incomplete_problems_people_seq';
$nextState = 'CHOOSE_INCOMPLETE_PEOPLE_SEQ';
$textSuffix = ' for selected students';
@@ -3935,51 +4150,59 @@
&create_incomplete_folder_selstud_helper($helper, $map);
&Apache::lonxml::xmlparse($r, 'helper', $helperStates);
} else {
- my $helperStates = &create_incomplete_folder_helper($helper, $map); # Create needed states for student.
- &Apache::lonxml::xmlparse($r, 'helper', $helperStates);
+ if (&printable($map_open, $map_close)) {
+ my $helperStates = &create_incomplete_folder_helper($helper, $map); # Create needed states for student.
+ &Apache::lonxml::xmlparse($r, 'helper', $helperStates);
+ } else {
+ # TODO: Figure out how to break the news...this folder is not printable.
+ }
}
- push(@{$printChoices},
- [&mt('Selected [_1]Incomplete Problems[_2] from folder [_3]' . $textSuffix,
- '<b>', '</b>',
- '<b><i>'. $sequenceTitle . '</b></i>'),
- $printSelector,
- $nextState]);
-
+ if ($userCanPrint || &printable($map_open, $map_close)) {
+ push(@{$printChoices},
+ [&mt('Selected [_1]Incomplete Problems[_2] from folder [_3]' . $textSuffix,
+ '<b>', '</b>',
+ '<b><i>'. $sequenceTitle . '</b></i>'),
+ $printSelector,
+ $nextState]);
+ }
# Allow problems from sequence
- push @{$printChoices},
+ if ($userCanPrint || &printable($map_open, $map_close)) {
+ push @{$printChoices},
[&mt('Selected [_1]Problems[_2] from folder [_3]','<b>','</b>','<b><i>'.$sequenceTitle.'</i></b>'),
'map_problems',
'CHOOSE_PROBLEMS'];
- # Allow all resources from sequence
- push @{$printChoices}, [&mt('Selected [_1]Resources[_2] from folder [_3]','<b>','</b>','<b><i>'.$sequenceTitle.'</i></b>'),
- 'map_problems_pages',
- 'CHOOSE_PROBLEMS_HTML'];
- my $helperFragment = &generate_resource_chooser('CHOOSE_PROBLEMS',
- 'Select Problem(s) to print',
- 'multichoice="1" toponly="1" addstatus="1" closeallpages="1"',
- 'RESOURCES',
- 'PAGESIZE',
- $map,
- $isProblem, '',
- $symbFilter,
- $start_new_option);
- $helperFragment .= &generate_resource_chooser('CHOOSE_PROBLEMS_HTML',
- 'Select Resource(s) to print',
- 'multichoice="1" toponly="1" addstatus="1" closeallpages="1"',
- 'RESOURCES',
- 'PAGESIZE',
- $map,
- $isNotMap, '',
- $symbFilter,
- $start_new_option);
-
- &Apache::lonxml::xmlparse($r, 'helper', $helperFragment);
+ # Allow all resources from sequence
+ push @{$printChoices}, [&mt('Selected [_1]Resources[_2] from folder [_3]','<b>','</b>','<b><i>'.$sequenceTitle.'</i></b>'),
+ 'map_problems_pages',
+ 'CHOOSE_PROBLEMS_HTML'];
+ my $helperFragment = &generate_resource_chooser('CHOOSE_PROBLEMS',
+ 'Select Problem(s) to print',
+ 'multichoice="1" toponly="1" addstatus="1" closeallpages="1"',
+ 'RESOURCES',
+ 'PAGESIZE',
+ $map,
+ ! $isProblem, '',
+ $symbFilter,
+ $start_new_option);
+ $helperFragment .= &generate_resource_chooser('CHOOSE_PROBLEMS_HTML',
+ 'Select Resource(s) to print',
+ 'multichoice="1" toponly="1" addstatus="1" closeallpages="1"',
+ 'RESOURCES',
+ 'PAGESIZE',
+ $map,
+ $isNotMap, '',
+ $symbFilter,
+ $start_new_option);
+
+ &Apache::lonxml::xmlparse($r, 'helper', $helperFragment);
+ } else {
+ # TODO: Figure out how to tell them the folder is not printable.
+ }
}
-
- # If the user has pfo (print for others) allow them to print all
- # problems and resources in the entire course, optionally for selected students
- my $post_data = $helper->{VARS}->{'postdata'};
+ # If the user has pfo (print for others) allow them to print all
+ # problems and resources in the entire course, optionally for selected students
+ my $post_data = $helper->{VARS}->{'postdata'};
if ($perm{'pfo'} && !$is_published &&
($post_data=~/\/res\// || $post_data =~/\/(syllabus|smppg|aboutme|bulletinboard)$/)) {
@@ -4342,7 +4565,7 @@
<message>Select the sequence to print resources from:</message>
<resource variable="SEQUENCE">
<nextstate>CHOOSE_FROM_ANY_SEQUENCE</nextstate>
- <filterfunc>return \$res->is_sequence;</filterfunc>
+ <filterfunc>return &Apache::lonprintout::printable_sequence(\$res);</filterfunc>
<valuefunc>return $urlValue;</valuefunc>
<choicefunc>return \$res->hasResource(\$res,sub { return !\$_[0]->is_sequence() },0,0);
</choicefunc>
More information about the LON-CAPA-cvs
mailing list