--- loncom/homework/bridgetask.pm 2006/06/09 23:09:01 1.164 +++ loncom/homework/bridgetask.pm 2006/11/06 17:50:17 1.184.2.4 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # definition of tags that give a structure to a document # -# $Id: bridgetask.pm,v 1.164 2006/06/09 23:09:01 albertel Exp $ +# $Id: bridgetask.pm,v 1.184.2.4 2006/11/06 17:50:17 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -43,23 +43,23 @@ use LONCAPA; BEGIN { - &Apache::lonxml::register('Apache::bridgetask',('Task','IntroParagraph','Dimension','Question','QuestionText','Setup','Instance','InstanceText','Criteria','ClosingParagraph')); + &Apache::lonxml::register('Apache::bridgetask',('Task','IntroParagraph','Dimension','Question','QuestionText','Setup','Instance','InstanceText','Criteria','GraderNote','ClosingParagraph')); } +my %dimension; sub initialize_bridgetask { # id of current Dimension, 0 means that no dimension is current # (inside only) - $Apache::bridgetask::dimension=''; + @Apache::bridgetask::dimension=(); # list of all Dimension ids seen - @Apache::bridgetask::dimensionlist=(); - # mandatory attribute of all Dimensions seen - %Apache::bridgetask::dimensionmandatory=(); + %Apache::bridgetask::top_dimensionlist=(); # list of all current Instance ids - @Apache::bridgetask::instance=(); + %Apache::bridgetask::instance=(); # list of all Instance ids seen in this problem @Apache::bridgetask::instancelist=(); # key of queud user data that we are currently grading $Apache::bridgetask::queue_key=''; + undef(%dimension); } sub proctor_check_auth { @@ -83,7 +83,7 @@ sub proctor_check_auth { } } if ($authenticated) { - &create_new_version($type,$user,$domain,$slot_name); + &check_in($type,$user,$domain,$slot_name); return 1; } } @@ -91,8 +91,43 @@ sub proctor_check_auth { return 0; } +sub check_in { + my ($type,$user,$domain,$slot_name) = @_; + my $useslots = &Apache::lonnet::EXT("resource.0.useslots"); + if ( $useslots eq 'map_map') { + &check_in_sequence($user,$domain,$slot_name); + } else { + &create_new_version($type,$user,$domain,$slot_name); + } + return 1; +} + +sub check_in_sequence { + my ($user,$domain,$slot_name) = @_; + my $navmap = Apache::lonnavmaps::navmap->new(); + my ($symb) = &Apache::lonxml::whichuser(); + my ($map) = &Apache::lonnet::decode_symb($symb); + my @resources = + $navmap->retrieveResources($map, sub { $_[0]->is_problem() },0,0); + my %old_history = %Apache::lonhomework::history; + my %old_results = %Apache::lonhomework::results; + + foreach my $res (@resources) { + &Apache::lonxml::debug("doing ".$res->src); + &Apache::structuretags::initialize_storage($res->symb); + my $type = ($res->is_task()) ? 'Task' : 'problem'; + &create_new_version($type,$user,$domain,$slot_name); + &Apache::structuretags::finalize_storage($res->symb); + } + + %Apache::lonhomework::history = %old_history; + %Apache::lonhomework::results = %old_results; +} + sub create_new_version { my ($type,$user,$domain,$slot_name) = @_; + + my $id = '0'; if ($type eq 'Task') { # increment version my $version= @@ -107,28 +142,27 @@ sub create_new_version { } #setup new version and who did it - $Apache::lonhomework::results{'resource.0.version'}=$version; - if (defined($user) && defined($domain)) { - $Apache::lonhomework::results{"resource.$version.0.checkedin"}= - $user.':'.$domain; - } else { - $Apache::lonhomework::results{"resource.$version.0.checkedin"}= - $env{'user.name'}.':'.$env{'user.domain'}; - } - if (defined($slot_name)) { - $Apache::lonhomework::results{"resource.$version.0.checkedin.slot"}= - $slot_name; + $Apache::lonhomework::results{'resource.0.version'}=$version; + $id = "$version.0"; + if (!defined($user) || !defined($domain)) { + $user = $env{'user.name'}; + $domain = $env{'user.domain'}; } + } elsif ($type eq 'problem') { &Apache::lonxml::debug("authed $slot_name"); - if (defined($user) && defined($domain)) { - $Apache::lonhomework::results{"resource.0.checkedin"}= - $user.':'.$domain; - } - if (defined($slot_name)) { - $Apache::lonhomework::results{"resource.0.checkedin.slot"}= - $slot_name; - } + } + if (!defined($user) || !defined($domain)) { + $user = $env{'user.name'}; + $domain = $env{'user.domain'}; + } + + $Apache::lonhomework::results{"resource.$id.checkedin"}= + $user.':'.$domain; + + if (defined($slot_name)) { + $Apache::lonhomework::results{"resource.$id.checkedin.slot"}= + $slot_name; } } @@ -292,9 +326,22 @@ sub style { my ($target) = @_; if ($target eq 'web' || $target eq 'webgrade') { - return (< STYLE + if ($env{'browser.type'} eq 'explorer' + && $env{'browser.os'} eq 'win' ) { + if ($env{'browser.version'} < 7) { + $style .= (< +STYLE + } else { + $style .= (< +STYLE + } + } + return $style; } return; } @@ -316,6 +363,38 @@ sub show_task { return 1; } +my @delay; +sub nest { + if (@delay) { + return $delay[-1]; + } else { + return; + } +} + +sub nested_parse { + my ($str,$env,$args) = @_; + my @old_env = @Apache::scripttag::parser_env; + @Apache::scripttag::parser_env = @$env; + if (exists($args->{'set_dim_id'})) { + &enable_dimension_parsing($args->{'set_dim_id'}); + } + push(@delay,(($args->{'delayed_dim_results'})? 1 : 0)); + my $result = &Apache::scripttag::xmlparse($$str); + pop(@delay); + if (exists($args->{'set_dim_id'})) { + &disable_dimension_parsing(); + } + @Apache::scripttag::parser_env = @old_env; + if ($args->{'delayed_dim_results'}) { + my $dim = &get_dim_id(); + &Apache::lonxml::debug(" tossing out $result "); + &Apache::lonxml::debug(" usining out $dim 's ". $dimension{$dim}{'result'}); + return $dimension{$dim}{'result'}; + } + return $result; +} + sub internal_location { my ($id)=@_; return ''; @@ -326,8 +405,10 @@ sub submission_time_stamp { my $submissiontime; my $version=$Apache::lonhomework::history{'resource.0.version'}; for (my $v=$Apache::lonhomework::history{'version'};$v>0;$v--) { - if (defined($Apache::lonhomework::history{$v.':resource.'.$version.'.0.bridgetask.portfiles'})) { + if (defined($Apache::lonhomework::history{$v.':resource.'.$version.'.0.bridgetask.portfiles'}) + && defined($Apache::lonhomework::history{$v.':resource.'.$version.'.0.tries'})) { $submissiontime=$Apache::lonhomework::history{$v.':timestamp'}; + last; } } my $result; @@ -338,16 +419,18 @@ sub submission_time_stamp { my ($color,$when)=('#FF6666','after'); if ($diff > 0) { ($color,$when)=('#336600','before'); } my $info; + $diff = abs($diff); if ($diff%60) { $info=($diff%60).' seconds'; } $diff=int($diff/60); if ($diff%60) { $info=($diff%60).' minutes '.$info; } $diff=int($diff/60); if ($diff) { $info=$diff.' hours '.$info; } $result='

'. - &mt('Student submitted [_1] [_2] the deadline. - (Submission was at [_3], end of period was [_4].)', - $info,$when,scalar(localtime($submissiontime)), - scalar(localtime($slot{'endtime'}))). + &mt('Student submitted [_1] [_2] the deadline. '. + '(Submission was at [_3], end of period was [_4].)', + $info,$when, + &Apache::lonlocal::locallocaltime($submissiontime), + &Apache::lonlocal::locallocaltime($slot{'endtime'})). '

'; } return $result; @@ -390,7 +473,7 @@ sub webgrade_standard_info { 'fail' => 'Fail Rest', 'cancel' => 'Cancel', ); - my %lt=&Apache::lonlocal::texthash(%lt); + %lt=&Apache::lonlocal::texthash(%lt); my $result=< @@ -413,12 +496,64 @@ INFO return $result; } +sub done_screen { + my ($version) = @_; + my $title=&Apache::lonnet::gettitle(); + my @files=split(',',$Apache::lonhomework::history{'resource.'.$version.'.0.bridgetask.portfiles'}); + my (undef,undef,$domain,$user)= &Apache::lonxml::whichuser(); + my $files = '
    '; + my $msg; + foreach my $file (@files) { + my $url="/uploaded/$domain/$user/portfolio$file"; + if (! &Apache::lonnet::stat_file($url)) { + $file = &mt(' Nonexistent file: '. + '[_1]',$file); + $msg .= "

    Submitted non-existant file $file

    \n"; + } else { + $file = ''.$file.''; + $msg .= "

    Submitted file $file

    \n"; + } + $files .= '
  • '.$file.'
  • '; + } + $files.='
'; + my $subject = "Submission message for $title"; + my ($message_status,$comment_status); + my $setting = $env{'course.'.$env{'request.course.id'}.'.task_messages'}; + $setting =~ s/^\s*(\S*)\s*$/$1/; + $setting = lc($setting); + if ($setting eq 'only_student' + || $setting eq 'student_and_user_notes_screen') { + $message_status = + &Apache::lonmsg::user_normal_msg($user,$domain,$subject,$msg); + $message_status = '

'.&mt('Message sent to user: [_1]', + $message_status).'

'; + } + if ($setting eq 'student_and_user_notes_screen') { + $comment_status = + &Apache::lonmsg::store_instructor_comment($subject.'
'. + $msg,$user,$domain); + $comment_status = '

'.&mt('Message sent to instructor: [_1]', + $comment_status).'

'; + } + return <$title +

Files submitted: $files

+

You are now done with this Bridge Task

+
+

Logout

+

Change to a different course

+$message_status +$comment_status +DONESCREEN + +} + sub start_Task { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my ($status,$accessmsg,$slot); + &Apache::structuretags::init_problem_globals('Task'); if ($target ne 'webgrade') { - &Apache::structuretags::init_problem_globals('Task'); &Apache::structuretags::initialize_storage(); &Apache::lonhomework::showhash(%Apache::lonhomework::history); if ($env{'request.state'} eq 'construct') { @@ -481,7 +616,9 @@ sub start_Task { ($status,$accessmsg,my $slot_name,$slot) = &Apache::lonhomework::check_slot_access('0','Task'); if ($status eq 'CAN_ANSWER' && $version eq '') { - &create_new_version('Task',undef,undef,$slot_name); + # CAN_ANSWER mode, and no current version, unproctored access + # thus self-checkedin + &check_in('Task',undef,undef,$slot_name); &add_to_queue('gradingqueue',{'type' => 'Task', 'time' => time, 'slot' => $slot_name}); @@ -513,30 +650,7 @@ sub start_Task { } elsif ($status eq 'WAITING_FOR_GRADE') { $msg.='

'.&mt('Your submission is in the grading queue.').'

'; } elsif ($env{'form.donescreen'}) { - my $title=&Apache::lonnet::gettitle(); - my @files=split(',',$Apache::lonhomework::history{'resource.'.$version.'.0.bridgetask.portfiles'}); - my (undef,undef,$domain,$user)= - &Apache::lonxml::whichuser(); - my $files = '
    '; - foreach my $file (@files) { - my $url="/uploaded/$domain/$user/portfolio$file"; - if (! &Apache::lonnet::stat_file($url)) { - $file = &mt(' Nonexistant file: [_1]',$file); - } else { - $file = ''.$file.''; - } - $files .= '
  • '.$file.'
  • '; - } - $files.='
'; - - $result.=<$title -

Files submitted: $files

-

You are now done with this Bridge Task

-
-

Logout

-

Change to a different course

-DONESCREEN + $result .= &done_screen($version); } elsif ($status ne 'NOT_YET_VIEWED') { $msg.='

'.&mt('Not open to be viewed').'

'; } @@ -618,6 +732,11 @@ DONESCREEN $result.=''. &mt("Requested user has never accessed the task."). ''.$back; + } elsif ($status_code =~ /still_open:(.*)/) { + my $date = &Apache::lonlocal::locallocaltime($1); + $result.=''. + &mt("Task is still open, will close at [_1].",$date). + ''.$back; } elsif ($status_code eq 'lock_failed') { $result.=''.&mt("Failed to lock the requested record.") .''.$back; @@ -682,6 +801,20 @@ DONESCREEN return $result; } +sub get_task_end_time { + my ($queue_entry,$symb,$udom,$uname) = @_; + + my $end_time; + if (my $slot = &slotted_access($queue_entry)) { + my %slot_data=&Apache::lonnet::get_slot($slot); + $end_time = $slot_data{'endtime'}; + } else { + $end_time = &Apache::lonhomework::due_date('0',$symb, + $udom,$uname); + } + return $end_time; +} + sub get_key_todo { my ($target)=@_; my $todo; @@ -737,6 +870,16 @@ sub get_key_todo { return ($gradingkey); } + if ($queue) { + my $queue_entry = &get_queue_data($queue,$udom,$uname); + + my $end_time = &get_task_end_time($queue_entry,$symb, + $udom,$uname); + if ($end_time > time) { + return (undef,"still_open:$end_time"); + } + } + my $who=&queue_key_locked($queue,$gradingkey); if ($who eq $me) { #already have the lock @@ -913,11 +1056,11 @@ DONEBUTTON my $man_count=0; my $opt_count=0; my $opt_passed=0; - foreach my $dim_id (@Apache::bridgetask::dimensionlist) { - if ($Apache::bridgetask::dimensionmandatory{$dim_id} + foreach my $dim (keys(%Apache::bridgetask::top_dimensionlist)) { + if ($Apache::bridgetask::top_dimensionlist{$dim}{'manadatory'} eq 'N') { $opt_count++; - if ($Apache::lonhomework::history{"resource.$version.0.$dim_id.status"} eq 'pass') { + if ($Apache::lonhomework::history{"resource.$version.0.$dim.status"} eq 'pass') { $opt_passed++; } } else { @@ -937,6 +1080,17 @@ DONEBUTTON &Apache::loncommon::end_page({'discussion' => 1}); } } + + my $useslots = &Apache::lonnet::EXT("resource.0.useslots"); + my %queue_data = ('type' => 'Task', + 'time' => time,); + if (defined($Apache::inputtags::slot_name)) { + $queue_data{'slot'} = $Apache::inputtags::slot_name; + } elsif (defined($Apache::lonhomework::history{"resource.$version.0.checkedin.slot"})) { + $queue_data{'slot'} = $Apache::lonhomework::history{"resource.$version.0.checkedin.slot"}; + } + + if ($target eq 'grade' && !$env{'form.webgrade'} && !$previous) { my $award='SUBMITTED'; &Apache::essayresponse::file_submission("$version.0",'bridgetask', @@ -959,20 +1113,8 @@ DONEBUTTON &Apache::lonhomework::showhash(%Apache::lonhomework::results); &Apache::structuretags::finalize_storage(); if ($award eq 'SUBMITTED') { - my $useslots = &Apache::lonnet::EXT("resource.0.useslots"); - if ($useslots =~ /^\s*no\s*$/i) { - &add_to_queue('gradingqueue', - {'type' => 'Task', - 'time' => time}); - } elsif (defined($Apache::inputtags::slot_name)) { - &add_to_queue('gradingqueue', - {'type' => 'Task', - 'time' => time, - 'slot' => $Apache::inputtags::slot_name}); - } + &add_to_queue('gradingqueue',\%queue_data); } - } elsif ($Apache::lonhomework::results{'INTERNAL_store'}) { - &Apache::structuretags::finalize_storage(); } if ($target eq 'grade' && $env{'form.webgrade'} eq 'yes' && exists($env{'form.cancel'})) { @@ -988,11 +1130,11 @@ DONEBUTTON my $ungraded=0; my $review=0; &Apache::lonhomework::showhash(%Apache::lonhomework::results); - foreach my $dim_id (@Apache::bridgetask::dimensionlist) { + foreach my $dim (keys(%Apache::bridgetask::top_dimensionlist)) { my $status= - $Apache::lonhomework::results{"resource.$version.0.$dim_id.status"}; + $Apache::lonhomework::results{"resource.$version.0.$dim.status"}; my $mandatory= - ($Apache::bridgetask::dimensionmandatory{$dim_id} ne 'N'); + ($Apache::bridgetask::top_dimensionlist{$dim}{'manadatory'} ne 'N'); if ($status eq 'pass') { if (!$mandatory) { $optional_passed++; } } elsif ($status eq 'fail') { @@ -1008,33 +1150,18 @@ DONEBUTTON if ($optional_passed < $optional_required) { $mandatory_failed++; } - &Apache::lonxml::debug("all dim ".join(':',@Apache::bridgetask::dimensionlist)."results -> m_f $mandatory_failed o_p $optional_passed u $ungraded r $review"); + &Apache::lonxml::debug("all dim ".join(':',keys(%Apache::bridgetask::top_dimensionlist))."results -> m_f $mandatory_failed o_p $optional_passed u $ungraded r $review"); $Apache::lonhomework::results{'resource.0.regrader'}= $env{'user.name'}.':'.$env{'user.domain'}; if ($review) { $Apache::lonhomework::results{"resource.$version.0.status"}='review'; - if ($env{'form.queue'} eq 'reviewqueue') { - &check_queue_unlock($env{'form.queue'}); - &Apache::lonxml::debug(" still needs review not changing status."); - } else { - &move_between_queues($env{'form.queue'},'reviewqueue'); - } } elsif ($ungraded) { $Apache::lonhomework::results{"resource.$version.0.status"}='ungraded'; - if ($env{'form.queue'} eq 'reviewqueue' || - $env{'form.queue'} eq 'none' ) { - &Apache::lonxml::debug("moving back."); - &move_between_queues($env{'form.queue'},'gradingqueue'); - } else { - &check_queue_unlock($env{'form.queue'}); - } } elsif ($mandatory_failed) { $Apache::lonhomework::results{"resource.$version.0.status"}='fail'; $Apache::lonhomework::results{"resource.$version.0.solved"}='incorrect_by_override'; $Apache::lonhomework::results{"resource.$version.0.award"}='INCORRECT'; $Apache::lonhomework::results{"resource.$version.0.awarded"}='0'; - &remove_from_queue($env{'form.queue'}); - my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser(); if ($env{'form.regrade'} ne 'yes') { @@ -1051,8 +1178,6 @@ DONEBUTTON $Apache::lonhomework::results{"resource.$version.0.solved"}='correct_by_override'; $Apache::lonhomework::results{"resource.$version.0.award"}='EXACT_ANS'; $Apache::lonhomework::results{"resource.$version.0.awarded"}='1'; - &remove_from_queue($env{'form.queue'}); - my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser(); if ($env{'form.regrade'} ne 'yes') { $Apache::lonhomework::results{"resource.$version.0.bridgetask.portfiles"}= @@ -1076,6 +1201,38 @@ DONEBUTTON } &minimize_storage(); &Apache::structuretags::finalize_storage(); + + # data stored, now handle queue + if ($review) { + if ($env{'form.queue'} eq 'reviewqueue') { + &check_queue_unlock($env{'form.queue'}); + &Apache::lonxml::debug(" still needs review not changing status."); + } else { + if ($env{'form.queue'} ne 'none') { + &move_between_queues($env{'form.queue'},'reviewqueue'); + } else { + &add_to_queue('reviewqueue',\%queue_data); + } + } + } elsif ($ungraded) { + if ($env{'form.queue'} eq 'reviewqueue') { + &Apache::lonxml::debug("moving back."); + &move_between_queues($env{'form.queue'}, + 'gradingqueue'); + } elsif ($env{'form.queue'} eq 'none' ) { + &add_to_queue('gradingqueue',\%queue_data); + } else { + &check_queue_unlock($env{'form.queue'}); + } + } elsif ($mandatory_failed) { + &remove_from_queue($env{'form.queue'}); + } else { + &remove_from_queue($env{'form.queue'}); + } + } + if (exists($Apache::lonhomework::results{'INTERNAL_store'})) { + # instance generation occured and hasn't yet been stored + &Apache::structuretags::finalize_storage(); } } elsif ($target eq 'webgrade') { $result.=""; @@ -1099,7 +1256,12 @@ DONEBUTTON 'Partial Credit Factor'); $result.=&Apache::response::meta_stores_write('status','string', 'Bridge Task Status'); + } elsif ($target eq 'edit') { + &Apache::structuretags::reset_problem_globals('Task'); + undef($Apache::lonhomework::parsing_a_task); + return ('','no'); } + &Apache::structuretags::reset_problem_globals('Task'); undef($Apache::lonhomework::parsing_a_task); return $result; } @@ -1190,8 +1352,12 @@ sub setup_env_for_other_user { } sub get_queue_data { - my ($queue)=@_; - my ($symb,$cid,$udom,$uname)=&Apache::lonxml::whichuser(); + my ($queue,$udom,$uname)=@_; + my ($symb,$cid,$other_udom,$other_uname)=&Apache::lonxml::whichuser(); + if (!$uname || !$udom) { + $uname=$other_uname; + $udom =$other_udom; + } my $cnum=$env{'course.'.$cid.'.num'}; my $cdom=$env{'course.'.$cid.'.domain'}; my $todo="$symb\0queue\0$uname:$udom"; @@ -1415,7 +1581,6 @@ sub get_queue_counts { foreach my $key (sort(keys(%queue))) { my ($symb,$uname,$udom) = &decode_queue_key($key); if (!defined($classlist->{$uname.':'.$udom})) { next; } - if ($key=~/locked$/) { $locks++; } elsif ($key=~/timestamp$/) { @@ -1826,6 +1991,10 @@ sub end_ClosingParagraph { return $result; } +sub get_dim_id { + return $Apache::bridgetask::dimension[-1]; +} + sub get_id { my ($parstack,$safeeval)=@_; my $id=&Apache::lonxml::get_param('id',$parstack,$safeeval); @@ -1833,36 +2002,72 @@ sub get_id { return $id; } -my %dimension; sub start_Setup { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - undef(%dimension); - my $dim_id=&get_id($parstack,$safeeval); - $Apache::bridgetask::dimension=$dim_id; - undef(@Apache::bridgetask::instance); + #undef(%dimension); + my $dim = &get_id($parstack,$safeeval); + push(@Apache::bridgetask::dimension,$dim); &Apache::lonxml::startredirection(); - return &internal_location($dim_id); + return &internal_location($dim); } + +{ + my @allowed; + sub enable_dimension_parsing { + my ($id) = @_; + push(@allowed,$id); + } + sub disable_dimension_parsing { + pop(@allowed); + } + sub skip_dimension_parsing { + my ($check) = @_; + if (!@allowed) { return 0;} + # if unspecified allow any id + if ($allowed[-1] eq undef) { return 0;} + + return ($check ne $allowed[-1]); + } +} + sub start_Question { return &start_Dimension(@_); } sub start_Dimension { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - undef(%dimension); - my $dim_id=&get_id($parstack,$safeeval); - $Apache::bridgetask::dimension=$dim_id; - push(@Apache::bridgetask::dimensionlist,$dim_id); - undef(@Apache::bridgetask::instance); - $Apache::bridgetask::dimensionmandatory{$dim_id}= - &Apache::lonxml::get_param('Mandatory',$parstack,$safeeval); + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $dim = &get_id($parstack,$safeeval); + my $previous_dim; + if (@Apache::bridgetask::dimension) { + $previous_dim = $Apache::bridgetask::dimension[-1]; + push(@{$Apache::bridgetask::dimension{$previous_dim}{'contains'}}, + $dim); + if(&skip_dimension_parsing($dim)) { + $dimension{$previous_dim}{'criteria.'.$dim} = + $token->[4] + .&Apache::lonxml::get_all_text('/'.$tagstack->[-1],$parser, + $style) + .'[-1].'>'; + } + $dimension{$previous_dim}{'criteria.'.$dim.'.type'}='dimension'; + $dimension{$previous_dim}{'criteria.'.$dim.'.mandatory'}= + &Apache::lonxml::get_param('Mandatory',$parstack,$safeeval); + push(@{$dimension{$previous_dim}{'criterias'}},$dim); + $dimension{$dim}{'nested'}=$previous_dim; + &Apache::lonxml::debug("adding $dim as criteria to $previous_dim"); + } else { + $Apache::bridgetask::top_dimensionlist{$dim}{'manadatory'}= + &Apache::lonxml::get_param('Mandatory',$parstack,$safeeval); + } + push(@Apache::bridgetask::dimension,$dim); &Apache::lonxml::startredirection(); - return &internal_location($dim_id); + &enable_dimension_parsing($dim); + return &internal_location($dim); } sub start_QuestionText { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; - my $dim_id=$Apache::bridgetask::dimension; + my $dim = &get_dim_id(); my $text=&Apache::lonxml::get_all_text('/questiontext',$parser,$style); if ($target eq 'grade' || $target eq 'web' || $target eq 'webgrade') { - $dimension{'questiontext'}=$text; + $dimension{$dim}{'questiontext'}=$text; } return ''; } @@ -1878,7 +2083,7 @@ sub get_instance { $rand_alg eq '64bit2' || $rand_alg eq '64bit3' || $rand_alg eq '64bit4' ) { &Apache::response::pushrandomnumber(); - my @order=&Math::Random::random_permutation(@{$dimension{'instances'}}); + my @order=&Math::Random::random_permutation(@{$dimension{$dim}{'instances'}}); my $num=@order; my $version=&get_version(); my $which=($version-1)%$num; @@ -1890,26 +2095,40 @@ sub get_instance { if (defined($instance)) { return $instance; } &Apache::response::pushrandomnumber(); - my @instances = @{$dimension{'instances'}}; - # remove disabled instances - for (my $i=0; $i < $#instances; $i++) { - if ($dimension{$instances[$i].'.disabled'}) { - splice(@instances,$i,1); - $i--; + if (ref($dimension{$dim}{'instances'}) eq 'ARRAY') { + my @instances = @{$dimension{$dim}{'instances'}}; + # remove disabled instances + for (my $i=0; $i < $#instances; $i++) { + if ($dimension{$dim}{$instances[$i].'.disabled'}) { + splice(@instances,$i,1); + $i--; + } + } + @instances = &Math::Random::random_permutation(@instances); + $instance = $instances[($version-1)%scalar(@instances)]; + if ($version =~ /^\d$/) { + $Apache::lonhomework::results{"resource.$version.0.$dim.instance"} = + $instance; + $Apache::lonhomework::results{'INTERNAL_store'} = 1; } - } - @instances = &Math::Random::random_permutation(@instances); - $instance = $instances[($version-1)%scalar(@instances)]; - if ($version =~ /^\d$/) { - $Apache::lonhomework::results{"resource.$version.0.$dim.instance"} = - $instance; - $Apache::lonhomework::results{'INTERNAL_store'} = 1; } &Apache::response::poprandomnumber(); return $instance; } } +sub get_criteria { + my ($what,$version,$dim,$id) = @_; + my $type = $dimension{$dim}{'criteria.'.$id.'.type'}; + my $prefix = ($type eq 'criteria') ? "$dim.$id" + : "$id"; + my $entry = "resource.$version.0.$prefix.$what"; + if (exists($Apache::lonhomework::results{$entry})) { + return $Apache::lonhomework::results{$entry}; + } + return $Apache::lonhomework::history{$entry}; +} + { my $last_link; sub link { @@ -1922,27 +2141,43 @@ sub get_instance { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result=&Apache::lonxml::endredirection(); my $dim=&get_id($parstack,$safeeval); + if (&skip_dimension_parsing($dim)) { + &disable_dimension_parsing($dim); + pop(@Apache::bridgetask::dimension); + return; + } my $instance=&get_instance($dim); my $version=&get_version(); if ($target eq 'web') { - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'intro'}); + $result .= &nested_parse(\$dimension{$dim}{'intro'},[@_]); my @instances = $instance; if (&Apache::response::showallfoils()) { - @instances = @{$dimension{'instances'}}; + @instances = @{$dimension{$dim}{'instances'}}; } my $shown_question_text; foreach my $instance (@instances) { - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{$instance.'.text'}); - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'questiontext'}); - if ($Apache::lonhomework::history{"resource.$version.0.status"} eq 'pass' || - $Apache::lonhomework::history{"resource.$version.0.status"} eq 'fail') { - + $result .= &nested_parse(\$dimension{$dim}{$instance.'.text'}, + [@_]); + $result .= &nested_parse(\$dimension{$dim}{'questiontext'}, + [@_],{'set_dim_id' => undef}); + my $task_status = + $Apache::lonhomework::history{"resource.$version.0.status"}; + if ($task_status ne 'pass' && $task_status ne 'fail') { + + foreach my $id (@{$dimension{$dim}{$instance.'.criterias'}}, + @{$dimension{$dim}{'criterias'}}) { + my $type = $dimension{$dim}{'criteria.'.$id.'.type'}; + &Apache::lonxml::debug("$id is $type"); + if ($type eq 'dimension') { + $result.= + &nested_parse(\$dimension{$dim}{'criteria.'.$id}, + [@_],{'set_dim_id' => $id}); + } + } + } else { my $dim_status=$Apache::lonhomework::history{"resource.$version.0.$dim.status"}; my $mandatory='Mandatory'; - if ($Apache::bridgetask::dimensionmandatory{$dim} eq 'N') { + if (&Apache::lonxml::get_param('Mandatory',$parstack,$safeeval) eq 'N') { $mandatory='Optional'; } my $dim_info="
\n"; @@ -1956,24 +2191,21 @@ sub get_instance { my $man_passed=0; my $opt_count=0; my $opt_passed=0; - foreach my $id ( @{$dimension{$instance.'.criterias'}}, - @{$dimension{'criterias'}} ) { - if ($dimension{'criteria.'.$id.'.mandatory'} + foreach my $id ( @{$dimension{$dim}{$instance.'.criterias'}}, + @{$dimension{$dim}{'criterias'}} ) { + my $status = &get_criteria('status',$version,$dim,$id); + if ($dimension{$dim}{'criteria.'.$id.'.mandatory'} eq 'N') { $opt_count++; - if ($Apache::lonhomework::history{"resource.$version.0.$dim.$id.status"} eq 'pass') { - $opt_passed++; - } + if ($status eq 'pass') { $opt_passed++; } } else { $man_count++; - if ($Apache::lonhomework::history{"resource.$version.0.$dim.$instance.$id.status"} eq 'pass') { - $man_passed++; - } + if ($status eq 'pass') { $man_passed++; } } } if ($man_passed eq $man_count) { $man_passed='all'; } - my $opt_req=$dimension{$instance.'.optionalrequired'}; + my $opt_req=$dimension{$dim}{$instance.'.optionalrequired'}; if ($opt_req !~ /\S/) { $opt_req= &Apache::lonxml::get_param('OptionalRequired', @@ -1985,54 +2217,43 @@ sub get_instance { my $internal_location=&internal_location($dim); $result=~s/\Q$internal_location\E/$dim_info/; - foreach my $id (@{$dimension{$instance.'.criterias'}}, - @{$dimension{'criterias'}}) { - my $status=$Apache::lonhomework::history{"resource.$version.0.$dim.$id.status"}; - my $comment=$Apache::lonhomework::history{"resource.$version.0.$dim.$id.comment"}; - my $mandatory=($dimension{'criteria.'.$id.'.mandatory'} ne 'N'); - if ($mandatory) { - $mandatory='Mandatory'; - } else { - $mandatory='Optional'; - } - if ($status eq 'fail') { - } elsif ($status eq 'pass') { - } else { - &Apache::lonxml::error("Student viewing a graded bridgetask was shown a status of $status"); - } - my $status_display=$status; - $status_display=~s/^([a-z])/uc($1)/e; - $result.= - '

' - .$mandatory.' Criteria

'; - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'criteria.'.$id}); - $result.='

'.$status_display.'

'; - if ($Apache::lonhomework::history{"resource.$version.0.$dim.$id.comment"}) { - $result.='

'.&mt('Comment: [_1]',$Apache::lonhomework::history{"resource.$version.0.$dim.$id.comment"}).'

'; + foreach my $id (@{$dimension{$dim}{$instance.'.criterias'}}, + @{$dimension{$dim}{'criterias'}}) { + my $type = $dimension{$dim}{'criteria.'.$id.'.type'}; + if ($type eq 'dimension') { + $result.=$dimension{$id}{'result'}; + next; } - $result.='
'; } } } } elsif ($target eq 'webgrade') { # in case of any side effects that we need - @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{'intro'}); - @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{$instance.'.text'}); - @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{'questiontext'}); - foreach my $id (@{$dimension{$instance.'.criterias'}}, - @{$dimension{'criterias'}} ) { + &nested_parse(\$dimension{$dim}{'intro'},[@_]); + &nested_parse(\$dimension{$dim}{$instance.'.text'},[@_]); + $result.= + &nested_parse(\$dimension{$dim}{'questiontext'},[@_], + {'set_dim_id' => undef, + 'delayed_dim_results' => 1}); + foreach my $id (@{$dimension{$dim}{$instance.'.criterias'}}, + @{$dimension{$dim}{'criterias'}} ) { + my $type = $dimension{$dim}{'criteria.'.$id.'.type'}; + if ($type eq 'dimension') { + # dimensional 'criteria' don't get assigned grades + $result.= + &nested_parse(\$dimension{$dim}{'criteria.'.$id}, + [@_],{'set_dim_id' => $id}); + next; + } + my $link=&link($id); - my $status=$Apache::lonhomework::history{"resource.$version.0.$dim.$id.status"}; + my $status= &get_criteria('status',$version,$dim,$id); $result.='
'."\n". '
'."\n"; - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'criteria.'.$id}); + $result.= + &nested_parse(\$dimension{$dim}{'criteria.'.$id},[@_]); + $result.='
'."\n". - #$dimension{'criteria.'.$id}. '
'."\n". ''."\n". ''."\n". @@ -2040,7 +2261,7 @@ sub get_instance { ''."\n". '
'."\n". ''."\n". '
    '."\n". '
  • Prev
  • '."\n". @@ -2050,25 +2271,40 @@ sub get_instance { $result.=&grading_history($version,$dim,$id); $last_link=$link; } + if (&nest()) { + &Apache::lonxml::debug(" for $dim stashing results into ".$dimension{$dim}{'nested'}); + $dimension{$dimension{$dim}{'nested'}}{'result'}.=$result; + undef($result); + } } elsif ($target eq 'grade' && $env{'form.webgrade'}) { my $optional_passed=0; my $mandatory_failed=0; my $ungraded=0; my $review=0; - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'intro'}); - @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{$instance.'.text'}); - @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{'questiontext'}); + $result .= &nested_parse(\$dimension{$dim}{'intro'},[@_]); + $result .= &nested_parse(\$dimension{$dim}{$instance.'.text'}, + [@_]); + $result .= &nested_parse(\$dimension{$dim}{'questiontext'}, + [@_],{'set_dim_id' => undef}); - foreach my $id (@{$dimension{$instance.'.criterias'}}, - @{$dimension{'criterias'}}) { + foreach my $id (@{$dimension{$dim}{$instance.'.criterias'}}, + @{$dimension{$dim}{'criterias'}}) { my $link=&link($id); - my $status=$Apache::lonhomework::results{"resource.$version.0.$dim.$id.status"}=$env{'form.HWVAL_'.$link}; - $Apache::lonhomework::results{"resource.$version.0.$dim.$id.comment"}=$env{'form.HWVAL_comment_'.$link}; - my $mandatory=($dimension{'criteria.'.$id.'.mandatory'} ne 'N'); + + my $type = $dimension{$dim}{'criteria.'.$id.'.type'}; + if ($type eq 'criteria') { + # dimensional 'criteria' don't get assigned grades + $Apache::lonhomework::results{"resource.$version.0.$dim.$id.status"}=$env{'form.HWVAL_'.$link}; + $Apache::lonhomework::results{"resource.$version.0.$dim.$id.comment"}=$env{'form.HWVAL_comment_'.$link}; + } else { + $result .= + &nested_parse(\$dimension{$dim}{'criteria.'.$id}, + [@_],{'set_dim_id' => $id}); + } + my $status= &get_criteria('status',$version,$dim,$id); + + my $mandatory=($dimension{$dim}{'criteria.'.$id.'.mandatory'} ne 'N'); if ($status eq 'pass') { if (!$mandatory) { $optional_passed++; } } elsif ($status eq 'fail') { @@ -2082,7 +2318,7 @@ sub get_instance { } } # FIXME optional required can apply to only right now... - my $opt_req=$dimension{$instance.'.optionalrequired'}; + my $opt_req=$dimension{$dim}{$instance.'.optionalrequired'}; if ($opt_req !~ /\S/) { $opt_req= &Apache::lonxml::get_param('OptionalRequired', @@ -2092,7 +2328,7 @@ sub get_instance { if ($optional_passed < $opt_req) { $mandatory_failed++; } - &Apache::lonxml::debug("all instance ".join(':',@{$dimension{$instance.'.criterias'}})." results -> m_f $mandatory_failed o_p $optional_passed u $ungraded r $review"); + &Apache::lonxml::debug("all instance ".join(':',@{$dimension{$dim}{$instance.'.criterias'}})." results -> m_f $mandatory_failed o_p $optional_passed u $ungraded r $review"); if ($review) { $Apache::lonhomework::results{"resource.$version.0.$dim.status"}= 'review'; @@ -2110,6 +2346,8 @@ sub get_instance { # any other targets no output undef($result); } + &disable_dimension_parsing(); + pop(@Apache::bridgetask::dimension); return $result; } @@ -2121,30 +2359,31 @@ sub get_instance { my $version=&get_version(); if ($target eq 'web') { @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'intro'}); + $result.=&Apache::scripttag::xmlparse($dimension{$dim}{'intro'}); my @instances = $instance; if (&Apache::response::showallfoils()) { - @instances = @{$dimension{'instances'}}; + @instances = @{$dimension{$dim}{'instances'}}; } foreach my $instance (@instances) { @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{$instance.'.text'}); + $result.=&Apache::scripttag::xmlparse($dimension{$dim}{$instance.'.text'}); @Apache::scripttag::parser_env = @_; - $result.=&Apache::scripttag::xmlparse($dimension{'questiontext'}); + $result.=&Apache::scripttag::xmlparse($dimension{$dim}{'questiontext'}); } } elsif ($target eq 'webgrade' || $target eq 'grade' && $env{'form.webgrade'}) { # in case of any side effects that we need @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{'intro'}); + &Apache::scripttag::xmlparse($dimension{$dim}{'intro'}); @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{$instance.'.text'}); + &Apache::scripttag::xmlparse($dimension{$dim}{$instance.'.text'}); @Apache::scripttag::parser_env = @_; - &Apache::scripttag::xmlparse($dimension{'questiontext'}); + &Apache::scripttag::xmlparse($dimension{$dim}{'questiontext'}); } else { # any other targets no output undef($result); } + pop(@Apache::bridgetask::dimension); return $result; } } @@ -2184,9 +2423,10 @@ sub grading_history { sub start_IntroParagraph { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; + my $dim = &get_dim_id(); if ($target eq 'grade' || $target eq 'web' || $target eq 'webgrade') { if ($tagstack->[-2] eq 'Dimension' || $tagstack->[-2] eq 'Question' ) { - $dimension{'intro'}= + $dimension{$dim}{'intro'}= &Apache::lonxml::get_all_text('/introparagraph', $parser,$style); } elsif ($tagstack->[-2] eq 'Task' && $target eq 'webgrade') { @@ -2206,15 +2446,16 @@ sub end_IntroParagraph { sub start_Instance { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - my $id=&get_id($parstack,$safeeval); - push(@{$dimension{'instances'}},$id); - push(@Apache::bridgetask::instance,$id); + my $dim = &get_dim_id(); + my $id = &get_id($parstack,$safeeval); + push(@{$dimension{$dim}{'instances'}},$id); + push(@{$Apache::bridgetask::instance{$dim}},$id); push(@Apache::bridgetask::instancelist,$id); - $dimension{$id.'.optionalrequired'}= + $dimension{$dim}{$id.'.optionalrequired'}= &Apache::lonxml::get_param('OptionalRequired',$parstack,$safeeval); my $disabled = &Apache::lonxml::get_param('Disabled',$parstack,$safeeval); if (lc($disabled) eq 'yes') { - $dimension{$id.'.disabled'}='1'; + $dimension{$dim}{$id.'.disabled'}='1'; } return ''; } @@ -2224,10 +2465,11 @@ sub end_Instance { sub start_InstanceText { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; - my $instance_id=$Apache::bridgetask::instance[-1]; + my $dim = &get_dim_id(); + my $instance_id=$Apache::bridgetask::instance{$dim}[-1]; my $text=&Apache::lonxml::get_all_text('/instancetext',$parser,$style); if ($target eq 'grade' || $target eq 'web' || $target eq 'webgrade') { - $dimension{$instance_id.'.text'}=$text; + $dimension{$dim}{$instance_id.'.text'}=$text; } return ''; } @@ -2239,27 +2481,82 @@ sub end_InstanceText { sub start_Criteria { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $criteria=&Apache::lonxml::get_all_text('/criteria',$parser,$style); + my $result = ''; if ($target eq 'web' || $target eq 'webgrade' || $target eq 'grade') { + my $dim = &get_dim_id(); my $id=&get_id($parstack,$safeeval); + &Apache::lonxml::debug("Criteria $id with $dim"); if (&Apache::londefdef::is_inside_of($tagstack,'Instance')) { - my $instance_id=$Apache::bridgetask::instance[-1]; - $dimension{"criteria.$instance_id.$id"}=$criteria; - $dimension{"criteria.$instance_id.$id.mandatory"}= + my $instance_id=$Apache::bridgetask::instance{$dim}[-1]; + $dimension{$dim}{"criteria.$instance_id.$id"}=$criteria; + $dimension{$dim}{"criteria.$instance_id.$id.type"}='criteria'; + $dimension{$dim}{"criteria.$instance_id.$id.mandatory"}= &Apache::lonxml::get_param('Mandatory',$parstack,$safeeval); - push(@{$dimension{$instance_id.'.criterias'}},"$instance_id.$id"); + push(@{$dimension{$dim}{$instance_id.'.criterias'}},"$instance_id.$id"); } else { - $dimension{'criteria.'.$id}=$criteria; - $dimension{'criteria.'.$id.'.mandatory'}= + $dimension{$dim}{'criteria.'.$id}=$criteria; + $dimension{$dim}{'criteria.'.$id.'.type'}='criteria'; + $dimension{$dim}{'criteria.'.$id.'.mandatory'}= &Apache::lonxml::get_param('Mandatory',$parstack,$safeeval); - push(@{$dimension{'criterias'}},$id); + push(@{$dimension{$dim}{'criterias'}},$id); + + my $version=&get_version(); + my $task_status = + $Apache::lonhomework::history{"resource.$version.0.status"}; + if ($target eq 'web' + && ($task_status eq 'pass' || $task_status eq 'fail')) { + my $status= &get_criteria('status', $version,$dim,$id); + my $comment=&get_criteria('comment',$version,$dim,$id); + my $mandatory=($dimension{$dim}{'criteria.'.$id.'.mandatory'} ne 'N'); + if ($mandatory) { + $mandatory='Mandatory'; + } else { + $mandatory='Optional'; + } + my $status_display=$status; + $status_display=~s/^([a-z])/uc($1)/e; + $result.= + '

    ' + .$mandatory.' Criteria

    '; + $result.= + &nested_parse(\$dimension{$dim}{'criteria.'.$id},[@_]); + $result.='

    '.$status_display.'

    '; + if ($comment =~ /\w/) { + $result.='

    '. + &mt('Comment: [_1]',$comment).'

    '; + } + $result.='
    '; + } } } - return ''; + return $result; } sub end_Criteria { } +sub start_GraderNote { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target eq 'webgrade') { + return '
    '. + &mt('Note to graders:').''; + } + my $note=&Apache::lonxml::get_all_text('/gradernote',$parser,$style); + return; +} + +sub end_GraderNote { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target eq 'webgrade') { + return '
    '; + } + return; +} + + + sub proctor_validation_screen { my ($slot) = @_; my (undef,undef,$domain,$user) = &Apache::lonxml::whichuser();