--- loncom/homework/lonhomework.pm 2004/12/22 22:05:40 1.190
+++ loncom/homework/lonhomework.pm 2007/11/20 17:53:22 1.286
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Homework handler
#
-# $Id: lonhomework.pm,v 1.190 2004/12/22 22:05:40 albertel Exp $
+# $Id: lonhomework.pm,v 1.286 2007/11/20 17:53:22 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,7 +30,7 @@ package Apache::lonhomework;
use strict;
use Apache::style();
use Apache::lonxml();
-use Apache::lonnet();
+use Apache::lonnet;
use Apache::lonplot();
use Apache::inputtags();
use Apache::structuretags();
@@ -49,11 +49,11 @@ use Apache::matchresponse();
use Apache::chemresponse();
use Apache::drawimage();
use Apache::Constants qw(:common);
-use HTML::Entities();
use Apache::loncommon();
use Apache::lonlocal;
use Time::HiRes qw( gettimeofday tv_interval );
-use Apache::lonnet();
+use HTML::Entities();
+use File::Copy();
# FIXME - improve commenting
@@ -63,6 +63,28 @@ BEGIN {
}
+=pod
+
+=item set_bubble_lines()
+
+Called at analysis time to set the bubble lines
+hash for the problem.. This should be called in the
+end_problemtype tag in analysis mode.
+
+We fetch the hash of part id counters from lonxml
+ and push them into analyze:{part_id.bubble_lines}.
+
+=cut
+
+sub set_bubble_lines {
+ my %bubble_counters = &Apache::lonxml::get_bubble_line_hash();
+
+ foreach my $key (keys(%bubble_counters)) {
+ $Apache::lonhomework::analyze{"$key.bubble_lines"} =
+ $bubble_counters{"$key"};
+ }
+}
+
#
# Decides what targets to render for.
# Implicit inputs:
@@ -72,59 +94,68 @@ BEGIN {
# contruct - is a /priv/ resource
# form.grade_target - a form parameter requesting a specific target
sub get_target {
- &Apache::lonxml::debug("request.state = $ENV{'request.state'}");
- if( defined($ENV{'form.grade_target'})) {
- &Apache::lonxml::debug("form.grade_target= $ENV{'form.grade_target'}");
+ &Apache::lonxml::debug("request.state = $env{'request.state'}");
+ if( defined($env{'form.grade_target'})) {
+ &Apache::lonxml::debug("form.grade_target= $env{'form.grade_target'}");
} else {
&Apache::lonxml::debug("form.grade_target ");
}
- if (($ENV{'request.state'} eq "published") ||
- ($ENV{'request.state'} eq "uploaded")) {
- if ( defined($ENV{'form.grade_target'} )
- && ($ENV{'form.grade_target'} eq 'tex')) {
- return ($ENV{'form.grade_target'});
- } elsif ( defined($ENV{'form.grade_target'} )
+ if (($env{'request.state'} eq "published") ||
+ ($env{'request.state'} eq "uploaded")) {
+ if ( defined($env{'form.grade_target'} )
+ && ($env{'form.grade_target'} eq 'tex')) {
+ return ($env{'form.grade_target'});
+ } elsif ( defined($env{'form.grade_target'} )
&& ($Apache::lonhomework::viewgrades eq 'F' )) {
- return ($ENV{'form.grade_target'});
+ return ($env{'form.grade_target'});
+ } elsif ( $env{'form.grade_target'} eq 'webgrade'
+ && ($Apache::lonhomework::queuegrade eq 'F' )) {
+ return ($env{'form.grade_target'});
+ }
+ if ($env{'form.webgrade'} &&
+ ($Apache::lonhomework::modifygrades eq 'F'
+ || $Apache::lonhomework::queuegrade eq 'F' )) {
+ return ('grade','webgrade');
}
-
- if ( defined($ENV{'form.submitted'}) &&
- ( !defined($ENV{'form.resetdata'})) &&
- ( !defined($ENV{'form.newrandomization'}))) {
+ if ( defined($env{'form.submitted'}) &&
+ ( !defined($env{'form.newrandomization'}))) {
return ('grade', 'web');
} else {
return ('web');
}
- } elsif ($ENV{'request.state'} eq "construct") {
- if ( defined($ENV{'form.grade_target'}) ) {
- return ($ENV{'form.grade_target'});
+ } elsif ($env{'request.state'} eq "construct") {
+ if ( defined($env{'form.grade_target'}) ) {
+ return ($env{'form.grade_target'});
}
- if ( defined($ENV{'form.preview'})) {
- if ( defined($ENV{'form.submitted'})) {
+ if ( defined($env{'form.preview'})) {
+ if ( defined($env{'form.submitted'})) {
return ('grade', 'web');
} else {
return ('web');
}
} else {
- if ( $ENV{'form.problemmode'} eq &mt('View') ||
- $ENV{'form.problemmode'} eq &mt('Discard Edits and View')) {
- if ( defined($ENV{'form.submitted'}) &&
- (!defined($ENV{'form.resetdata'})) &&
- (!defined($ENV{'form.newrandomization'}))) {
+ if ($env{'form.problemstate'} eq 'WEB_GRADE') {
+ #$env{'form.webgrade'} = 'yes';
+ return ('grade','webgrade','answer');
+ } elsif ( $env{'form.problemmode'} eq &mt('View') ||
+ $env{'form.problemmode'} eq &mt('Discard Edits and View')) {
+ if ( defined($env{'form.submitted'}) &&
+ (!defined($env{'form.resetdata'})) &&
+ (!defined($env{'form.newrandomization'}))) {
return ('grade', 'web','answer');
} else {
return ('web','answer');
}
- } elsif ( $ENV{'form.problemmode'} eq &mt('Edit') ||
- $ENV{'form.problemmode'} ee 'Edit') {
- if ( $ENV{'form.submitted'} eq 'edit' ) {
- if ( $ENV{'form.submit'} eq &mt('Submit Changes and View') ) {
+ } elsif ( $env{'form.problemmode'} eq &mt('Edit') ||
+ $env{'form.problemmode'} eq 'Edit') {
+ if ( $env{'form.submitted'} eq 'edit' ) {
+ if ( $env{'form.submit'} eq &mt('Save and View') ) {
return ('modified','web','answer');
} else {
- return ('modified','edit');
+ return ('modified','no_output_web','edit');
}
} else {
- return ('edit');
+ return ('no_output_web','edit');
}
} else {
return ('web');
@@ -140,12 +171,6 @@ sub setup_vars {
# return ';$external::target='.$target.';';
}
-sub send_header {
- my ($request)= @_;
- $request->print(&Apache::lontexconvert::header());
-# $request->print('');
- $request->print(&Apache::lontexconvert::footer());
-}
+sub proctor_checked_in {
+ my ($slot_name,$slot,$type)=@_;
+ my @possible_proctors=split(",",$slot->{'proctor'});
+
+ return 1 if (!@possible_proctors);
-$Apache::lonxml::browse='';
+ my $key;
+ if ($type eq 'Task') {
+ my $version=$Apache::lonhomework::history{'resource.0.version'};
+ $key ="resource.$version.0.checkedin";
+ } elsif ($type eq 'problem') {
+ $key ='resource.0.checkedin';
+ }
+ # backward compatability, used to be username@domain,
+ # now is username:domain
+ my $who = $Apache::lonhomework::history{$key};
+ if ($who !~ /:/) {
+ $who =~ tr/@/:/;
+ }
+ foreach my $possible (@possible_proctors) {
+ if ($who eq $possible
+ && $Apache::lonhomework::history{$key.'.slot'} eq $slot_name) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
sub check_ip_acc {
my ($acc)=@_;
- if (!defined($acc) || $acc =~ /^\s*$/) { return 1; }
+ &Apache::lonxml::debug("acc is $acc");
+ if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
+ return 1;
+ }
my $allowed=0;
- my $ip=$ENV{'REMOTE_ADDR'};
+ my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
+
my $name;
foreach my $pattern (split(',',$acc)) {
+ $pattern =~ s/^\s*//;
+ $pattern =~ s/\s*$//;
if ($pattern =~ /\*$/) {
#35.8.*
$pattern=~s/\*//;
@@ -209,6 +261,129 @@ sub check_ip_acc {
}
return $allowed;
}
+
+sub check_slot_access {
+ my ($id,$type)=@_;
+
+ # does it pass normal muster
+ my ($status,$datemsg)=&check_access($id);
+
+ my $useslots = &Apache::lonnet::EXT("resource.0.useslots");
+ if ($useslots ne 'resource' && $useslots ne 'map'
+ && $useslots ne 'map_map') {
+ return ($status,$datemsg);
+ }
+
+ if ($status eq 'SHOW_ANSWER' ||
+ $status eq 'CLOSED' ||
+ $status eq 'INVALID_ACCESS' ||
+ $status eq 'UNAVAILABLE') {
+ return ($status,$datemsg);
+ }
+ if ($env{'request.state'} eq "construct") {
+ return ($status,$datemsg);
+ }
+
+ if ($type eq 'Task') {
+ my $version=$Apache::lonhomework::history{'resource.version'};
+ if ($Apache::lonhomework::history{"resource.$version.0.checkedin"} &&
+ $Apache::lonhomework::history{"resource.$version.0.status"} eq 'pass') {
+ return ('SHOW_ANSWER');
+ }
+ }
+
+ my @slots=
+ (split(':',&Apache::lonnet::EXT("resource.0.availablestudent")),
+ split(':',&Apache::lonnet::EXT("resource.0.available")));
+
+# if (!@slots) {
+# return ($status,$datemsg);
+# }
+ my $slotstatus='NOT_IN_A_SLOT';
+ my ($returned_slot,$slot_name);
+ foreach my $slot (@slots) {
+ $slot =~ s/(^\s*|\s*$)//g;
+ &Apache::lonxml::debug("getting $slot");
+ my %slot=&Apache::lonnet::get_slot($slot);
+ &Apache::lonhomework::showhash(%slot);
+ if ($slot{'starttime'} < time &&
+ $slot{'endtime'} > time &&
+ &check_ip_acc($slot{'ip'})) {
+ &Apache::lonxml::debug("$slot is good");
+ $slotstatus='NEEDS_CHECKIN';
+ $returned_slot=\%slot;
+ $slot_name=$slot;
+ last;
+ }
+ }
+ if ($slotstatus eq 'NEEDS_CHECKIN' &&
+ &proctor_checked_in($slot_name,$returned_slot,$type)) {
+ &Apache::lonxml::debug("protoctor checked in");
+ $slotstatus='CAN_ANSWER';
+ }
+
+ my ($is_correct,$got_grade,$checkedin);
+ if ($type eq 'Task') {
+ my $version=$Apache::lonhomework::history{'resource.0.version'};
+ $got_grade =
+ ($Apache::lonhomework::history{"resource.$version.0.status"}
+ =~ /^(?:pass|fail)$/);
+ $is_correct =
+ ($Apache::lonhomework::history{"resource.$version.0.status"} eq 'pass'
+ || $Apache::lonhomework::history{"resource.0.solved"} =~ /^correct_/ );
+ $checkedin =
+ $Apache::lonhomework::history{"resource.$version.0.checkedin"};
+ } elsif ($type eq 'problem') {
+ $got_grade = 1;
+ $checkedin = $Apache::lonhomework::history{"resource.0.checkedin"};
+ $is_correct =
+ ($Apache::lonhomework::history{"resource.0.solved"} =~/^correct_/);
+ }
+
+ &Apache::lonxml::debug(" slot is $slotstatus checkedin ($checkedin) got_grade ($got_grade) is_correct ($is_correct)");
+
+ # no slot is currently open, and has been checked in for this version
+ # but hasn't got a grade, therefore must be awaiting a grade
+ if (!defined($slot_name)
+ && $checkedin
+ && !$got_grade) {
+ return ('WAITING_FOR_GRADE');
+ }
+
+ # no slot is currently open, and has been checked in for this version
+ # previous slot is therefore CLOSED, so therefore the problem is
+ if (!defined($slot_name)
+ && $checkedin
+ && $type eq 'problem') {
+ return ('CLOSED',$datemsg);
+ }
+
+ if ($slotstatus eq 'NOT_IN_A_SLOT'
+ && $checkedin ) {
+
+ if ($got_grade) {
+ return ('SHOW_ANSWER');
+ } else {
+ return ('WAITING_FOR_GRADE');
+ }
+
+ }
+
+ if ( $is_correct) {
+ if ($type eq 'problem') {
+ return ($status);
+ }
+ return ('SHOW_ANSWER');
+ }
+
+ if ( $status eq 'CANNOT_ANSWER' &&
+ ($slotstatus ne 'NEEDS_CHECKIN' && $slotstatus ne 'NOT_IN_A_SLOT')) {
+ return ($status,$datemsg);
+ }
+
+ return ($slotstatus,$datemsg,$slot_name,$returned_slot);
+}
+
# JB, 9/24/2002: Any changes in this function may require a change
# in lonnavmaps::resource::getDateStatus.
sub check_access {
@@ -217,20 +392,19 @@ sub check_access {
my $status;
my $datemsg = '';
my $lastdate = '';
- my $temp;
my $type;
my $passed;
- if ($ENV{'request.state'} eq "construct") {
- if ($ENV{'form.problemstate'}) {
- if ($ENV{'form.problemstate'} =~ /^CANNOT_ANSWER/) {
- if ( ! ($ENV{'form.problemstate'} eq 'CANNOT_ANSWER_correct' &&
- lc($Apache::lonhomework::problemstatus) eq 'no')) {
+ if ($env{'request.state'} eq "construct") {
+ if ($env{'form.problemstate'}) {
+ if ($env{'form.problemstate'} =~ /^CANNOT_ANSWER/) {
+ if ( ! ($env{'form.problemstate'} eq 'CANNOT_ANSWER_correct'
+ && &hide_problem_status())) {
return ('CANNOT_ANSWER',
&mt('is in this state due to author settings.'));
}
} else {
- return ($ENV{'form.problemstate'},
+ return ($env{'form.problemstate'},
&mt('is in this state due to author settings.'));
}
}
@@ -243,7 +417,10 @@ sub check_access {
&Apache::lonxml::debug("checking for part :$id:");
&Apache::lonxml::debug("time:".time);
- if ($ENV{'request.state'} ne "construct") {
+ my ($symb)=&Apache::lonnet::whichuser();
+ &Apache::lonxml::debug("symb:".$symb);
+ #if ($env{'request.state'} ne "construct" && $symb ne '') {
+ if ($env{'request.state'} ne "construct") {
my $allowed=&check_ip_acc(&Apache::lonnet::EXT("resource.$id.acc"));
if (!$allowed && ($Apache::lonhomework::browse ne 'F')) {
$status='INVALID_ACCESS';
@@ -251,9 +428,14 @@ sub check_access {
return($status,$date);
}
- foreach $temp ("opendate","duedate","answerdate") {
+ foreach my $temp ("opendate","duedate","answerdate") {
$lastdate = $date;
- $date = &Apache::lonnet::EXT("resource.$id.$temp");
+ if ($temp eq 'duedate') {
+ $date = &due_date($id);
+ } else {
+ $date = &Apache::lonnet::EXT("resource.$id.$temp");
+ }
+
my $thistype = &Apache::lonnet::EXT("resource.$id.$temp.type");
if ($thistype =~ /^(con_lost|no_such_host)/ ||
$date =~ /^(con_lost|no_such_host)/) {
@@ -276,7 +458,7 @@ sub check_access {
$date = &mt("an indeterminate date"); $passed = 0;
} else {
if (time < $date) { $passed = 0; } else { $passed = 1; }
- $date = localtime $date;
+ $date = &Apache::lonlocal::locallocaltime($date);
}
if (!$passed) { $type=$temp; last; }
}
@@ -295,43 +477,46 @@ sub check_access {
$datemsg = &mt("was due on")." $lastdate".&mt(", and answers will be available on")." $date";
}
}
- if ($status eq 'CAN_ANSWER') {
+ if ($status eq 'CAN_ANSWER' ||
+ (($Apache::lonhomework::browse eq 'F') && ($status eq 'CLOSED'))) {
#check #tries, and if correct.
my $tries = $Apache::lonhomework::history{"resource.$id.tries"};
my $maxtries = &Apache::lonnet::EXT("resource.$id.maxtries");
if ( $tries eq '' ) { $tries = '0'; }
if ( $maxtries eq '' &&
- $ENV{'request.state'} ne 'construct') { $maxtries = '2'; }
+ $env{'request.state'} ne 'construct') { $maxtries = '2'; }
if ($maxtries && $tries >= $maxtries) { $status = 'CANNOT_ANSWER'; }
# if (correct and show prob status) or excused then CANNOT_ANSWER
if(($Apache::lonhomework::history{"resource.$id.solved"}=~/^correct/
&&
- lc($Apache::lonhomework::problemstatus) ne 'no')
+ &show_problem_status())
||
$Apache::lonhomework::history{"resource.$id.solved"}=~/^excused/) {
$status = 'CANNOT_ANSWER';
}
+ if ($status eq 'CANNOT_ANSWER'
+ && &show_answer_problem_status()) {
+ $status = 'SHOW_ANSWER';
+ }
}
if ($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER') {
- my $interval=&Apache::lonnet::EXT("resource.$id.interval");
- &Apache::lonxml::debug("looking for interval $interval");
- if ($interval) {
- my $first_access=&Apache::lonnet::get_first_access('map');
+ my @interval=&Apache::lonnet::EXT("resource.$id.interval");
+ &Apache::lonxml::debug("looking for interval @interval");
+ if ($interval[0]) {
+ my $first_access=&Apache::lonnet::get_first_access($interval[1]);
&Apache::lonxml::debug("looking for accesstime $first_access");
if (!$first_access) {
$status='NOT_YET_VIEWED';
- $datemsg=' '.$interval.' seconds';
- } else {
- my $newdate=localtime($first_access+$interval);
- if (time > ($first_access+$interval)) {
- $status='CLOSED';
- $datemsg = &mt("was due on")." $newdate".&mt(", and answers will be available on")." $date";
- } else {
- $datemsg = &mt("is due at")." $newdate";
+ my $due_date = &due_date($id);
+ my $seconds_left = $due_date - time;
+ if ($seconds_left > $interval[0] || $due_date eq '') {
+ $seconds_left = $interval[0];
}
+ $datemsg=&seconds_to_human_length($seconds_left);
}
}
}
+
#if (($status ne 'CLOSED') && ($Apache::lonhomework::type eq 'exam') &&
# (!$Apache::lonhomework::history{"resource.0.outtoken"})) {
# return ('UNCHECKEDOUT','needs to be checked out');
@@ -347,6 +532,50 @@ sub check_access {
return ($status,$datemsg);
}
+# this should work exactly like the copy in lonnavmaps.pm
+sub due_date {
+ my ($part_id,$symb,$udom,$uname)=@_;
+ my $date;
+ my @interval= &Apache::lonnet::EXT("resource.$part_id.interval",$symb,
+ $udom,$uname);
+ &Apache::lonxml::debug("looking for interval $part_id $symb @interval");
+ my $due_date= &Apache::lonnet::EXT("resource.$part_id.duedate",$symb,
+ $udom,$uname);
+ &Apache::lonxml::debug("looking for due_date $part_id $symb $due_date");
+ if ($interval[0] =~ /\d+/) {
+ my $first_access=&Apache::lonnet::get_first_access($interval[1],$symb);
+ &Apache::lonxml::debug("looking for first_access $first_access ($interval[1])");
+ if (defined($first_access)) {
+ my $interval = $first_access+$interval[0];
+ $date = (!$due_date || $interval < $due_date) ? $interval
+ : $due_date;
+ } else {
+ $date = $due_date;
+ }
+ } else {
+ $date = $due_date;
+ }
+ return $date
+}
+
+sub seconds_to_human_length {
+ my ($length)=@_;
+
+ my $seconds=$length%60; $length=int($length/60);
+ my $minutes=$length%60; $length=int($length/60);
+ my $hours=$length%24; $length=int($length/24);
+ my $days=$length;
+
+ my $timestr;
+ if ($days > 0) { $timestr.=&mt('[quant,_1,day]',$days); }
+ if ($hours > 0) { $timestr.=($timestr?", ":"").
+ &mt('[quant,_1,hour]',$hours); }
+ if ($minutes > 0) { $timestr.=($timestr?", ":"").
+ &mt('[quant,_1,minute]',$minutes); }
+ if ($seconds > 0) { $timestr.=($timestr?", ":"").
+ &mt('[quant,_1,second]',$seconds); }
+ return $timestr;
+}
sub showhash {
my (%hash) = @_;
@@ -358,10 +587,11 @@ sub showarray {
my ($array)=@_;
my $string="(";
foreach my $elm (@{ $array }) {
- if (ref($elm)) {
- if ($elm =~ /ARRAY/ ) {
- $string.=&showarray($elm);
- }
+ if (ref($elm) eq 'ARRAY') {
+ $string.=&showarray($elm);
+ } elsif (ref($elm) eq 'HASH') {
+ $string.= "HASH --- \n
";
+ $string.= &showhashsubset($elm,'.');
} else {
$string.="$elm,"
}
@@ -375,20 +605,15 @@ sub showhashsubset {
my ($hash,$keyre) = @_;
my $resultkey;
foreach $resultkey (sort keys %$hash) {
- if ($resultkey =~ /$keyre/) {
- if (ref($$hash{$resultkey})) {
- if ($$hash{$resultkey} =~ /ARRAY/ ) {
- &Apache::lonxml::debug("$resultkey ---- ".
- &showarray($$hash{$resultkey}));
- } elsif ($$hash{$resultkey} =~ /HASH/ ) {
- &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
- &showhashsubset($$hash{$resultkey},'.');
- } else {
- &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
- }
- } else {
- &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
- }
+ if ($resultkey !~ /$keyre/) { next; }
+ if (ref($$hash{$resultkey}) eq 'ARRAY' ) {
+ &Apache::lonxml::debug("$resultkey ---- ".
+ &showarray($$hash{$resultkey}));
+ } elsif (ref($$hash{$resultkey}) eq 'HASH' ) {
+ &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
+ &showhashsubset($$hash{$resultkey},'.');
+ } else {
+ &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
}
}
&Apache::lonxml::debug("\n
restored values^\n");
@@ -396,34 +621,60 @@ sub showhashsubset {
}
sub setuppermissions {
- $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$ENV{'request.filename'});
- my $viewgrades = &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
+ $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$env{'request.filename'});
+ my $viewgrades = &Apache::lonnet::allowed('vgr',$env{'request.course.id'});
if (! $viewgrades &&
- exists($ENV{'request.course.sec'}) &&
- $ENV{'request.course.sec'} !~ /^\s*$/) {
- $viewgrades = &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}.
- '/'.$ENV{'request.course.sec'});
+ exists($env{'request.course.sec'}) &&
+ $env{'request.course.sec'} !~ /^\s*$/) {
+ $viewgrades = &Apache::lonnet::allowed('vgr',$env{'request.course.id'}.
+ '/'.$env{'request.course.sec'});
}
- $Apache::lonhomework::viewgrades = $viewgrades; # File global variable...dirt.
+ $Apache::lonhomework::viewgrades = $viewgrades;
+
if ($Apache::lonhomework::browse eq 'F' &&
- $ENV{'form.devalidatecourseresdata'} eq 'on') {
- my (undef,$courseid) = &Apache::lonxml::whichuser();
- &Apache::lonnet::devalidatecourseresdata($ENV{"course.$courseid.num"},
- $ENV{"course.$courseid.domain"});
+ $env{'form.devalidatecourseresdata'} eq 'on') {
+ my (undef,$courseid) = &Apache::lonnet::whichuser();
+ &Apache::lonnet::devalidatecourseresdata($env{"course.$courseid.num"},
+ $env{"course.$courseid.domain"});
+ }
+
+ my $modifygrades = &Apache::lonnet::allowed('mgr',$env{'request.course.id'});
+ if (! $modifygrades &&
+ exists($env{'request.course.sec'}) &&
+ $env{'request.course.sec'} !~ /^\s*$/) {
+ $modifygrades =
+ &Apache::lonnet::allowed('mgr',$env{'request.course.id'}.
+ '/'.$env{'request.course.sec'});
+ }
+ $Apache::lonhomework::modifygrades = $modifygrades;
+
+ my $queuegrade = &Apache::lonnet::allowed('mqg',$env{'request.course.id'});
+ if (! $queuegrade &&
+ exists($env{'request.course.sec'}) &&
+ $env{'request.course.sec'} !~ /^\s*$/) {
+ $queuegrade =
+ &Apache::lonnet::allowed('qgr',$env{'request.course.id'}.
+ '/'.$env{'request.course.sec'});
}
- return ''
+ $Apache::lonhomework::queuegrade = $queuegrade;
+ return '';
+}
+
+sub unset_permissions {
+ undef($Apache::lonhomework::queuegrade);
+ undef($Apache::lonhomework::modifygrades);
+ undef($Apache::lonhomework::viewgrades);
+ undef($Apache::lonhomework::browse);
}
sub setupheader {
my $request=$_[0];
- if ($ENV{'browser.mathml'}) {
- &Apache::loncommon::content_type($request,'text/xml');
- } else {
- &Apache::loncommon::content_type($request,'text/html');
- }
+ &Apache::loncommon::content_type($request,'text/html');
if (!$Apache::lonxml::debug && ($ENV{'REQUEST_METHOD'} eq 'GET')) {
&Apache::loncommon::no_cache($request);
}
+# $request->set_last_modified(&Apache::lonnet::metadata($request->uri,
+# 'lastrevisiondate'));
$request->send_http_header;
return OK if $request->header_only;
return ''
@@ -435,38 +686,55 @@ sub handle_save_or_undo {
my $filebak =$file.".bak";
my $filetmp =$file.".tmp";
my $error=0;
-
- &Apache::lonnet::correct_line_ends($result);
-
- if ($ENV{'form.Undo'} eq &mt('undo')) {
+ if ($env{'form.Undo'} eq &mt('undo')) {
my $error=0;
- if (!copy($file,$filetmp)) { $error=1; }
- if ((!$error) && (!copy($filebak,$file))) { $error=1; }
- if ((!$error) && (!move($filetmp,$filebak))) { $error=1; }
+ if (!&File::Copy::copy($file,$filetmp)) { $error=1; }
+ if ((!$error) && (!&File::Copy::copy($filebak,$file))) { $error=1; }
+ if ((!$error) && (!&File::Copy::move($filetmp,$filebak))) { $error=1; }
if (!$error) {
- &Apache::lonxml::info("".&mt("Undid changes, Switched")." $filebak ".&mt("and")." $file
");
+ &Apache::lonxml::info("".
+ &mt("Undid changes, Switched [_1] and [_2]",
+ ''.$filebak.
+ '',
+ ''.$file.
+ '')."
");
} else {
- &Apache::lonxml::info("".&mt("Unable to undo, unable to switch")." $filebak ".&mt("and")." $file
");
+ &Apache::lonxml::info("".
+ &mt("Unable to undo, unable to switch [_1] and [_2]",
+ ''.
+ $filebak.'',
+ ''.
+ $file.'')."
");
$error=1;
}
} else {
+ &Apache::lonnet::correct_line_ends($result);
my $fs=Apache::File->new(">$filebak");
if (defined($fs)) {
print $fs $$problem;
- &Apache::lonxml::info("".&mt("Making Backup to").
- " $filebak");
+ &Apache::lonxml::info("".&mt("Making Backup to [_1]",
+ ''.
+ $filebak.'').
+ "");
} else {
- &Apache::lonxml::info("".&mt("Unable to make backup")." $filebak");
+ &Apache::lonxml::info("".
+ &mt("Unable to make backup [_1]",
+ ''.
+ $filebak.'')."");
$error=2;
}
my $fh=Apache::File->new(">$file");
if (defined($fh)) {
print $fh $$result;
- &Apache::lonxml::info("".&mt("Saving Modifications to").
- " $file");
+ &Apache::lonxml::info("".&mt("Saving Modifications to [_1]",
+ ''.
+ $file.'' )."");
} else {
- &Apache::lonxml::info("".
- &mt("Unable to write to")." $file");
+ &Apache::lonxml::info(''.
+ &mt("Unable to write to [_1]",
+ ''.
+ $file.'').
+ '');
$error|=4;
}
}
@@ -475,21 +743,22 @@ sub handle_save_or_undo {
sub analyze_header {
my ($request) = @_;
- my $bodytag='';
- if ($ENV{'environment.remote'} eq 'off') {
- $bodytag=&Apache::loncommon::bodytag();
- }
- my $result.='
- '.&mt("Analyzing a problem").'
- '.$bodytag.&Apache::lonxml::message_location().'
+ my $result =
+ &Apache::loncommon::start_page('Analyzing a problem',undef);
+
+ $result .=
+ &Apache::lonxml::message_location().'
';
&Apache::lonxml::add_messages(\$result);
$request->print($result);
@@ -498,8 +767,7 @@ sub analyze_header {
sub analyze_footer {
my ($request) = @_;
- my $result='';
- $request->print($result);
+ $request->print(&Apache::loncommon::end_page());
$request->rflush();
}
@@ -508,21 +776,23 @@ sub analyze {
&Apache::lonxml::debug("Analyze");
my $result;
my %overall;
+ my %seedexample;
my %allparts;
- my $rndseed=$ENV{'form.rndseed'};
+ my $rndseed=$env{'form.rndseed'};
&analyze_header($request);
my %prog_state=
&Apache::lonhtmlcommon::Create_PrgWin($request,&mt('Analyze Progress'),
&mt('Getting Problem Variants'),
- $ENV{'form.numtoanalyze'},
+ $env{'form.numtoanalyze'},
'inline',undef);
- for(my $i=1;$i<$ENV{'form.numtoanalyze'}+1;$i++) {
+ for(my $i=1;$i<$env{'form.numtoanalyze'}+1;$i++) {
&Apache::lonhtmlcommon::Increment_PrgWin($request,\%prog_state,
&mt('last problem'));
if (&Apache::loncommon::connection_aborted($request)) { return; }
+ my $thisseed=$i+$rndseed;
my $subresult=&Apache::lonnet::ssi($request->uri,
('grade_target' => 'analyze'),
- ('rndseed' => $i+$rndseed));
+ ('rndseed' => $thisseed));
(my $garbage,$subresult)=split(/_HASH_REF__/,$subresult,2);
my %analyze=&Apache::lonnet::str2hash($subresult);
my @parts;
@@ -534,37 +804,64 @@ sub analyze {
if ($analyze{$part.'.type'} eq 'numericalresponse' ||
$analyze{$part.'.type'} eq 'stringresponse' ||
$analyze{$part.'.type'} eq 'formularesponse' ) {
- push( @{ $overall{$part.'.answer'} },
- [@{ $analyze{$part.'.answer'} }]);
+ foreach my $name (keys(%{ $analyze{$part.'.answer'} })) {
+ my $i=0;
+ foreach my $answer_part (@{ $analyze{$part.'.answer'}{$name} }) {
+ push( @{ $overall{$part.'.answer'}[$i] },
+ $answer_part);
+ my $concatanswer= join("\0",@{ $answer_part });
+ if (($concatanswer eq '') || ($concatanswer=~/^\@/)) {
+ $answer_part = [''.&mt('Error').''];
+ }
+ $seedexample{join("\0",$part,$i,@{$answer_part})}=
+ $thisseed;
+ $i++;
+ }
+ }
+ if (!keys(%{ $analyze{$part.'.answer'} })) {
+ my $answer_part =
+ [''.&mt('Error').''];
+ $seedexample{join("\0",$part,0,@{$answer_part})}=
+ $thisseed;
+ push( @{ $overall{$part.'.answer'}[0] },
+ $answer_part);
+ }
}
}
}
&Apache::lonhtmlcommon::Update_PrgWin($request,\%prog_state,
&mt('Analyzing Results'));
- $request->print('
'.&mt('List of possible answers').': ');
+ $request->print('
'.&mt('List of possible answers').': ');
foreach my $part (sort(keys(%allparts))) {
if (defined(@{ $overall{$part.'.answer'} })) {
- my $num_cols=scalar(@{ $overall{$part.'.answer'}->[0] });
- $request->print(''.&mt('Part').' '.$part.' |
');
- my %frequency;
- foreach my $answer (sort {$a->[0] <=> $b->[0]} (@{ $overall{$part.'.answer'} })) {
- $frequency{join("\0",@{ $answer })}++;
- }
- $request->print(''.&mt('Answer').' | '.&mt('Frequency').' |
');
- foreach my $answer (sort {(split("\0",$a))[0] <=> (split("\0",$b))[0]} (keys(%frequency))) {
- $request->print(''.
- join(' | ',split("\0",$answer)).
- ' | ('.$frequency{$answer}.
- ') |
');
+ for (my $i=0;$iprint(''.&mt('Part').' '.$part);
+ if (scalar(@{ $overall{$part.'.answer'} }) > 1) {
+ $request->print(&mt(' Answer [_1]',$i+1));
+ }
+ $request->print(' |
');
+ my %frequency;
+ foreach my $answer (sort {$a->[0] <=> $b->[0]} (@{ $overall{$part.'.answer'}[$i] })) {
+ $frequency{join("\0",@{ $answer })}++;
+ }
+ $request->print(''.&mt('Answer').' | '.&mt('Frequency').' ('
+ .&mt('click for example').') |
');
+ foreach my $answer (sort {(split("\0",$a))[0] <=> (split("\0",$b))[0]} (keys(%frequency))) {
+ $request->print(''.
+ join(' | ',split("\0",$answer)).
+ ' | '.$frequency{$answer}.
+ ' |
');
+ }
+ $request->print('
');
}
- $request->print('
');
} else {
$request->print(''.&mt('Response').' '.$part.' '.
&mt('is not analyzable at this time').'
');
}
}
if (scalar(keys(%allparts)) == 0 ) {
- $request->print(''.&mt('Found no analyzable respones in this problem, currently only Numerical, Formula and String response styles are supported.').'
');
+ $request->print(''.&mt('Found no analyzable responses in this problem, currently only Numerical, Formula and String response styles are supported.').'
');
}
&Apache::lonhtmlcommon::Close_PrgWin($request,\%prog_state);
&analyze_footer($request);
@@ -572,6 +869,41 @@ sub analyze {
return $result;
}
+{
+ my $show_problem_status;
+ sub reset_show_problem_status {
+ undef($show_problem_status);
+ }
+
+ sub set_show_problem_status {
+ my ($new_status) = @_;
+ $show_problem_status = lc($new_status);
+ }
+
+ sub hide_problem_status {
+ return ($show_problem_status eq 'no'
+ || $show_problem_status eq 'no_feedback_ever');
+ }
+
+ sub show_problem_status {
+ return ($show_problem_status eq 'yes'
+ || $show_problem_status eq 'answer'
+ || $show_problem_status eq '');
+ }
+
+ sub show_some_problem_status {
+ return ($show_problem_status eq 'no');
+ }
+
+ sub show_no_problem_status {
+ return ($show_problem_status eq 'no_feedback_ever');
+ }
+
+ sub show_answer_problem_status {
+ return ($show_problem_status eq 'answer');
+ }
+}
+
sub editxmlmode {
my ($request,$file) = @_;
my $result;
@@ -581,15 +913,15 @@ sub editxmlmode {
" $file");
$problem='';
}
- if (defined($ENV{'form.editxmltext'}) || defined($ENV{'form.Undo'})) {
+ if (defined($env{'form.editxmltext'}) || defined($env{'form.Undo'})) {
my $error=&handle_save_or_undo($request,\$problem,
- \$ENV{'form.editxmltext'});
+ \$env{'form.editxmltext'});
if (!$error) { $problem=&Apache::lonnet::getfile($file); }
}
- &Apache::lonhomework::showhashsubset(\%ENV,'^form');
- if ( $ENV{'form.submit'} eq &mt('Submit Changes and View') ) {
- &Apache::lonhomework::showhashsubset(\%ENV,'^form');
- $ENV{'form.problemmode'}='View';
+ &Apache::lonhomework::showhashsubset(\%env,'^form');
+ if ( $env{'form.submit'} eq &mt('Save and View') ) {
+ &Apache::lonhomework::showhashsubset(\%env,'^form');
+ $env{'form.problemmode'}='View';
&renderpage($request,$file);
} else {
my ($rows,$cols) = &Apache::edit::textarea_sizes(\$problem);
@@ -597,31 +929,57 @@ sub editxmlmode {
&Apache::loncommon::helpLatexCheatsheet("Problem_Editor_XML_Index",
"Problem Editing Help").
''.
- &Apache::loncommon::help_open_menu('',undef,undef,undef,5,'Authoring').
+ &Apache::loncommon::help_open_menu(undef,undef,5,'Authoring').
' | ';
if ($cols > 80) { $cols = 80; }
if ($cols < 70) { $cols = 70; }
if ($rows < 20) { $rows = 20; }
- my $bodytag='';
- if ($ENV{'environment.remote'} eq 'off') {
- $bodytag=&Apache::loncommon::bodytag();
- }
- $result.=''.$bodytag.&Apache::lonxml::message_location().'
- ';
+
+ ' . '
+
+
+
+ '.&Apache::loncommon::end_page();
&Apache::lonxml::add_messages(\$result);
$request->print($result);
}
@@ -632,11 +990,12 @@ sub editxmlmode {
# Render the page in whatever target desired.
#
sub renderpage {
- my ($request,$file) = @_;
+ my ($request,$file,$targets,$return_string) = @_;
- my (@targets) = &get_target();
- &Apache::lonhomework::showhashsubset(\%ENV,'form.');
+ my @targets = @{$targets || [&get_target()]};
+ &Apache::lonhomework::showhashsubset(\%env,'form.');
&Apache::lonxml::debug("Running targets ".join(':',@targets));
+
my $overall_result;
foreach my $target (@targets) {
# FIXME need to do something intelligent when a problem goes
@@ -647,22 +1006,35 @@ sub renderpage {
# $request->print(" You most likely shouldn't see me.");
#}
#my $t0 = [&gettimeofday()];
+ my $output=1;
+ if ($target eq 'no_output_web') {
+ $target = 'web'; $output=0;
+ }
my $problem=&Apache::lonnet::getfile($file);
+ my $result;
if ($problem eq -1) {
- &Apache::lonxml::error(" ".&mt('Unable to find')." $file");
$problem='';
+ my $filename=(split('/',$file))[-1];
+ my $error =
+ " ".&mt('Unable to find [_1]',
+ ' '.$filename.'')
+ ."";
+ $result.=
+ &Apache::loncommon::simple_error_page($request,'Not available',
+ $error);
+ return;
}
my %mystyle;
- my $result = '';
if ($target eq 'analyze') { %Apache::lonhomework::analyze=(); }
if ($target eq 'answer') { &showhash(%Apache::lonhomework::history); }
- if ($target eq 'web') {&Apache::lonhomework::showhashsubset(\%ENV,'^form');}
+ if ($target eq 'web') {&Apache::lonhomework::showhashsubset(\%env,'^form');}
&Apache::lonxml::debug("Should be parsing now");
- $result = &Apache::lonxml::xmlparse($request, $target, $problem,
- &setup_vars($target),%mystyle);
- undef($Apache::lonhomework::parsing_a_problem);
+ $result .= &Apache::lonxml::xmlparse($request, $target, $problem,
+ &setup_vars($target),%mystyle);
+ &finished_parsing();
+ if (!$output) { $result = ''; }
#$request->print("Result follows:");
if ($target eq 'modified') {
&handle_save_or_undo($request,\$problem,\$result);
@@ -683,55 +1055,63 @@ sub renderpage {
#$request->print(":Result ends");
#my $td=&tv_interval($t0);
}
- &Apache::lonxml::add_messages(\$overall_result);
- $request->print($overall_result);
- $request->rflush();
+ if (!$return_string) {
+ &Apache::lonxml::add_messages(\$overall_result);
+ $request->print($overall_result);
+ $request->rflush();
+ } else {
+ return $overall_result;
+ }
+}
+
+sub finished_parsing {
+ undef($Apache::lonhomework::parsing_a_problem);
+ undef($Apache::lonhomework::parsing_a_task);
}
-# with no arg it returns a HTML \n';
+ my $glob_extension = $extension;
+ if ($extension eq 'survey' || $extension eq 'exam') {
+ $glob_extension = 'problem';
+ }
+ my @files = glob($Apache::lonnet::perlvar{'lonIncludes'}.
+ '/templates/*.'.$glob_extension);
+ @files = map {[$_,&mt(&Apache::lonnet::metadata($_, 'title'))]} (@files);
+ @files = sort {$a->[1] cmp $b->[1]} (@files);
+ foreach my $file (@files) {
+ next if ($file->[1] !~ /\S/);
+ $result .=
+ '
';
}
return $result;
}
sub newproblem {
my ($request) = @_;
- my $extension=$request->uri;
- $extension=~s:^.*\.([\w]+)$:$1:;
- &Apache::lonxml::debug("Looking for :$extension:");
- my $templatelist=&get_template_list('',$extension);
- if ($ENV{'form.template'} &&
- $ENV{'form.template'} ne "Select a $extension template") {
- use File::Copy;
- my $file = &get_template_list($ENV{'form.template'},$extension);
+
+ if ($env{'form.template'}) {
+ my $file = $env{'form.template'};
my $dest = &Apache::lonnet::filelocation("",$request->uri);
- copy($file,$dest);
+ &File::Copy::copy($file,$dest);
&renderpage($request,$dest);
- } elsif($ENV{'form.newfile'} && !$templatelist) {
- # I don't like hard-coded filenames but for now, this will work.
- use File::Copy;
+ return;
+ }
+
+ my ($extension) = ($request->uri =~ m/\.(\w+)$/);
+ &Apache::lonxml::debug("Looking for :$extension:");
+ my $templatelist=&get_template_list($extension);
+ if ($env{'form.newfile'} && !$templatelist) {
+ # no templates found
my $templatefilename =
- $request->dir_config('lonIncludes').'/templates/blank.problem';
+ $request->dir_config('lonIncludes').'/templates/blank.'.$extension;
&Apache::lonxml::debug("$templatefilename");
my $dest = &Apache::lonnet::filelocation("",$request->uri);
- copy($templatefilename,$dest);
+ &File::Copy::copy($templatefilename,$dest);
&renderpage($request,$dest);
} else {
my $url=&HTML::Entities::encode($request->uri,'<>&"');
@@ -739,121 +1119,100 @@ sub newproblem {
$shownurl=~s-^/~-/priv/-;
my $dest = &Apache::lonnet::filelocation("",$request->uri);
my $errormsg;
- if ($ENV{'form.newfile'}) {
- $errormsg=''.&mt('You did not select a template.').'
'."\n";
- }
my $instructions;
- my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,
- ($ENV{'environment.remote'} ne 'off'));
- if ($templatelist) { $instructions=&mt(", select a template from the pull-down menu below.").'
'.&mt("Then");}
- my %lt=&Apache::lonlocal::texthash( 'create' => 'Creating a new',
- 'resource' => 'resource',
- 'requested' => 'The requested file',
- 'not exist' => 'currently does not exist',
- 'createnew' => 'To create a new',
- 'click' => 'click on the',
- 'Create' => 'Create',
- 'button' => 'button');
- $request->print(<$lt{'create'} $extension $lt{'resource'}
+ my $start_page =
+ &Apache::loncommon::start_page("Create New $extension");
+ $request->print("
+$start_page
+".&mt("Creating a new $extension resource.")."
$errormsg
-$lt{'requested'} $shownurl $lt{'not exist'}.
+".&mt("The requested file [_1] currently does not exist.",
+ "$shownurl")."
-$lt{'createnew'} $extension$instructions $lt{'click'} "$lt{'Create'} $extension" $lt{'button'}.
-
-
".&Apache::loncommon::end_page());
+ }
+ return;
+}
+
+sub update_construct_style {
+ if ($env{'request.state'} eq "construct"
+ && $env{'form.problemmode'} eq &mt('View')
+ && defined($env{'form.submitted'})
+ && !defined($env{'form.resetdata'})
+ && !defined($env{'form.newrandomization'})) {
+ if ((!$env{'form.style_file'} && $env{'construct.style'})
+ ||$env{'form.clear_style_file'}) {
+ &Apache::lonnet::delenv('construct\\.style');
+ } elsif ($env{'form.style_file'}
+ && $env{'construct.style'} ne $env{'form.style_file'}) {
+ &Apache::lonnet::appenv('construct.style' =>
+ $env{'form.style_file'});
}
- $request->print("
");
- $request->print("