print($result);
my $gradeTable='';
- $request->print($endform);
+ }
+ $lastsubonly.=''."\n"; # End: LC_grade_submissions_body
}
- return '';
+ return ($lastsubonly,$partinfo);
}
sub check_collaborators {
@@ -2710,18 +3847,51 @@ sub check_collaborators {
#--- Retrieve the last submission for all the parts
sub get_last_submission {
my ($returnhash,$is_tool)=@_;
- my (@string,$timestamp,%lasthidden);
+ my (@string,$timestamp,$lastgradetime,$lastsubmittime);
if ($$returnhash{'version'}) {
my %lasthash=();
- my ($version);
+ my %prevsolved=();
+ my %solved=();
+ my $version;
for ($version=1;$version<=$$returnhash{'version'};$version++) {
+ my %handgraded = ();
foreach my $key (sort(split(/\:/,
$$returnhash{$version.':keys'}))) {
$lasthash{$key}=$$returnhash{$version.':'.$key};
- $timestamp =
- &Apache::lonlocal::locallocaltime($$returnhash{$version.':timestamp'});
+ if ($key =~ /\.([^.]+)\.regrader$/) {
+ $handgraded{$1} = 1;
+ } elsif ($key =~ /\.portfiles$/) {
+ if (($$returnhash{$version.':'.$key} ne '') &&
+ ($$returnhash{$version.':'.$key} !~ /\.\d+\.\w+$/)) {
+ $lastsubmittime = $$returnhash{$version.':timestamp'};
+ }
+ } elsif ($key =~ /\.submission$/) {
+ if ($$returnhash{$version.':'.$key} ne '') {
+ $lastsubmittime = $$returnhash{$version.':timestamp'};
+ }
+ } elsif ($key =~ /\.([^.]+)\.solved$/) {
+ $prevsolved{$1} = $solved{$1};
+ $solved{$1} = $lasthash{$key};
+ }
+ }
+ foreach my $partid (keys(%handgraded)) {
+ if (($prevsolved{$partid} eq 'ungraded_attempted') &&
+ (($solved{$partid} eq 'incorrect_by_override') ||
+ ($solved{$partid} eq 'correct_by_override'))) {
+ $lastgradetime = $$returnhash{$version.':timestamp'};
+ }
+ if ($solved{$partid} ne '') {
+ $prevsolved{$partid} = $solved{$partid};
+ }
}
}
+#
+# Timestamp is for last transaction for this resource, which does not
+# necessarily correspond to the time of last submission for problem (or part).
+#
+ if ($lasthash{'timestamp'} ne '') {
+ $timestamp = &Apache::lonlocal::locallocaltime($lasthash{'timestamp'});
+ }
my (%typeparts,%randombytry);
my $showsurv =
&Apache::lonnet::allowed('vas',$env{'request.course.id'});
@@ -2784,7 +3954,7 @@ sub get_last_submission {
$string[0] =
''.$msg.' ';
}
- return (\@string,\$timestamp);
+ return (\@string,$timestamp,$lastgradetime,$lastsubmittime);
}
#--- High light keywords, with style choosen by user.
@@ -2991,13 +4161,33 @@ sub processHandGrade {
my $ntstu = $env{'form.NTSTU'};
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my ($res_error,%queueable);
+ my ($partlist,$handgrade,$responseType,$numresp,$numessay) = &response_type($symb,\$res_error);
+ if ($res_error) {
+ $request->print(&navmap_errormsg());
+ return;
+ } else {
+ foreach my $part (@{$partlist}) {
+ if (ref($responseType->{$part}) eq 'HASH') {
+ foreach my $id (keys(%{$responseType->{$part}})) {
+ if (($responseType->{$part}->{$id} eq 'essay') ||
+ (lc($handgrade->{$part.'_'.$id}) eq 'yes')) {
+ $queueable{$part} = 1;
+ last;
+ }
+ }
+ }
+ }
+ }
if ($button eq 'Save & Next') {
+ my %needpb = &passbacks_for_symb($cdom,$cnum,$symb);
+ my (%skip_passback,%pbsave,%pbcollab);
my $ctr = 0;
while ($ctr < $ngrade) {
my ($uname,$udom) = split(/:/,$env{'form.unamedom'.$ctr});
my ($errorflag,$pts,$wgt,$numhidden) =
- &saveHandGrade($request,$symb,$uname,$udom,$ctr);
+ &saveHandGrade($request,$symb,$uname,$udom,$ctr,undef,undef,\%queueable,\%needpb,\%skip_passback,\%pbsave);
if ($errorflag eq 'no_score') {
$ctr++;
next;
@@ -3052,11 +4242,13 @@ sub processHandGrade {
foreach my $collaborator (@collaborators) {
my ($errorflag,$pts,$wgt) =
&saveHandGrade($request,$symb,$collaborator,$udom,$ctr,
- $env{'form.unamedom'.$ctr},$part);
+ $env{'form.unamedom'.$ctr},$part,\%queueable,\%needpb,\%skip_passback,%pbsave);
if ($errorflag eq 'not_allowed') {
$request->print("".&mt('Not allowed to modify grades for [_1]',"$collaborator:$udom")." ");
next;
- } elsif ($message ne '') {
+ } else {
+ $pbcollab{$collaborator}{$part} = [$pts,$wgt];
+ if ($message ne '') {
my ($baseurl,$showsymb) =
&get_feedurl_and_symb($symb,$collaborator,
$udom);
@@ -3072,15 +4264,17 @@ sub processHandGrade {
}
$ctr++;
}
+ if ((keys(%pbcollab)) && (keys(%needpb))) {
+ # FIXME passback scores for collaborators
+ }
}
-# if ($env{'form.handgrade'} eq 'yes') {
- if (1) {
+ my %keyhash = ();
+ if ($numessay) {
# Keywords sorted in alphabatical order
my $loginuser = $env{'user.name'}.':'.$env{'user.domain'};
- my %keyhash = ();
$env{'form.keywords'} =~ s/,\s{0,}|\s+/ /g;
- $env{'form.keywords'} =~ s/^\s+|\s+$//;
+ $env{'form.keywords'} =~ s/^\s+|\s+$//g;
my (@keywords) = sort(split(/\s+/,$env{'form.keywords'}));
$env{'form.keywords'} = join(' ',@keywords);
$keyhash{$symb.'_keywords'} = $env{'form.keywords'};
@@ -3088,7 +4282,9 @@ sub processHandGrade {
$keyhash{$loginuser.'_kwclr'} = $env{'form.kwclr'};
$keyhash{$loginuser.'_kwsize'} = $env{'form.kwsize'};
$keyhash{$loginuser.'_kwstyle'} = $env{'form.kwstyle'};
+ }
+ if ($env{'form.compmsg'}) {
# message center - Order of message gets changed. Blank line is eliminated.
# New messages are saved in env for the next student.
# All messages are saved in nohist_handgrade.db
@@ -3103,17 +4299,20 @@ sub processHandGrade {
$ctr = 0;
while ($ctr < $ngrade) {
if ($env{'form.newmsg'.$ctr} ne '') {
- $keyhash{$symb.'_savemsg'.$idx} = $env{'form.newmsg'.$ctr};
- $env{'form.savemsg'.$idx} = $env{'form.newmsg'.$ctr};
- $idx++;
+ $keyhash{$symb.'_savemsg'.$idx} = $env{'form.newmsg'.$ctr};
+ $env{'form.savemsg'.$idx} = $env{'form.newmsg'.$ctr};
+ $idx++;
}
$ctr++;
}
$env{'form.savemsgN'} = --$idx;
$keyhash{$symb.'_savemsgN'} = $env{'form.savemsgN'};
- my $putresult = &Apache::lonnet::put
- ('nohist_handgrade',\%keyhash,$cdom,$cnum);
}
+ if (($numessay) || ($env{'form.compmsg'})) {
+ my $putresult = &Apache::lonnet::put
+ ('nohist_handgrade',\%keyhash,$cdom,$cnum);
+ }
+
# Called by Save & Refresh from Highlight Attribute Window
my (undef,undef,$fullname) = &getclasslist($env{'form.section'},'1');
if ($env{'form.refresh'} eq 'on') {
@@ -3153,7 +4352,6 @@ sub processHandGrade {
}
return $a cmp $b;
} (keys(%$fullname))) {
-# FIXME: this is fishy, looks like the button label
if ($nextflg == 1 && $button =~ /Next$/) {
push(@parsedlist,$item);
}
@@ -3164,14 +4362,7 @@ sub processHandGrade {
}
}
$ctr = 0;
-# FIXME: this is fishy, looks like the button label
@parsedlist = reverse @parsedlist if ($button eq 'Previous');
- my $res_error;
- my ($partlist) = &response_type($symb,\$res_error);
- if ($res_error) {
- $request->print(&navmap_errormsg());
- return;
- }
foreach my $student (@parsedlist) {
my $submitonly=$env{'form.submitonly'};
my ($uname,$udom) = split(/:/,$student);
@@ -3229,7 +4420,7 @@ sub processHandGrade {
#---- Save the score and award for each student, if changed
sub saveHandGrade {
- my ($request,$symb,$stuname,$domain,$newflg,$submitter,$part) = @_;
+ my ($request,$symb,$stuname,$domain,$newflg,$submitter,$part,$queueable,$needpb,$skip_passback,$pbsave) = @_;
my @version_parts;
my $usec = &Apache::lonnet::getsection($domain,$stuname,
$env{'request.course.id'});
@@ -3240,23 +4431,36 @@ sub saveHandGrade {
my ($pts,$wgt,$totchg) = ('','',0);
my %aggregate = ();
my $aggregateflag = 0;
+ my $sendupdate;
if ($env{'form.HIDE'.$newflg}) {
my ($version,$parts) = split(/:/,$env{'form.HIDE'.$newflg},2);
my $numchgs = &makehidden($version,$parts,\%record,$symb,$domain,$stuname,1);
$totchg += $numchgs;
+ if ($numchgs) {
+ $sendupdate = 1;
+ }
}
+ my (%weights,%awardeds,%excuseds);
my @parts = split(/:/,$env{'form.partlist'.$newflg});
foreach my $new_part (@parts) {
#collaborator ($submi may vary for different parts
if ($submitter && $new_part ne $part) { next; }
my $dropMenu = $env{'form.GD_SEL'.$newflg.'_'.$new_part};
+ if ($env{'form.WGT'.$newflg.'_'.$new_part} eq '') {
+ $weights{$symb}{$new_part} = 1;
+ } else {
+ $weights{$symb}{$new_part} = $env{'form.WGT'.$newflg.'_'.$new_part};
+ }
if ($dropMenu eq 'excused') {
+ $excuseds{$symb}{$new_part} = 1;
+ $awardeds{$symb}{$new_part} = '';
if ($record{'resource.'.$new_part.'.solved'} ne 'excused') {
$newrecord{'resource.'.$new_part.'.solved'} = 'excused';
if (exists($record{'resource.'.$new_part.'.awarded'})) {
$newrecord{'resource.'.$new_part.'.awarded'} = '';
}
$newrecord{'resource.'.$new_part.'.regrader'}="$env{'user.name'}:$env{'user.domain'}";
+ $sendupdate = 1;
}
} elsif ($dropMenu eq 'reset status'
&& exists($record{'resource.'.$new_part.'.solved'})) { #don't bother if no old records -> no attempts
@@ -3280,6 +4484,9 @@ sub saveHandGrade {
&decrement_aggs($symb,$new_part,\%aggregate,$aggtries,$totaltries,$solvedstatus);
$aggregateflag = 1;
}
+ $sendupdate = 1;
+ $excuseds{$symb}{$new_part} = '';
+ $awardeds{$symb}{$new_part} = '';
} elsif ($dropMenu eq '') {
$pts = ($env{'form.GD_BOX'.$newflg.'_'.$new_part} ne '' ?
$env{'form.GD_BOX'.$newflg.'_'.$new_part} :
@@ -3290,12 +4497,15 @@ sub saveHandGrade {
$wgt = $env{'form.WGT'.$newflg.'_'.$new_part} eq '' ? 1 :
$env{'form.WGT'.$newflg.'_'.$new_part};
my $partial= $pts/$wgt;
+ $awardeds{$symb}{$new_part} = $partial;
+ $excuseds{$symb}{$new_part} = '';
if ($partial eq $record{'resource.'.$new_part.'.awarded'}) {
#do not update score for part if not changed.
&handback_files($request,$symb,$stuname,$domain,$newflg,$new_part,\%newrecord);
next;
} else {
push(@parts_graded,$new_part);
+ $sendupdate = 1;
}
if ($record{'resource.'.$new_part.'.awarded'} ne $partial) {
$newrecord{'resource.'.$new_part.'.awarded'} = $partial;
@@ -3341,12 +4551,19 @@ sub saveHandGrade {
&Apache::lonnet::cstore(\%newrecord,$symb,
$env{'request.course.id'},$domain,$stuname);
&check_and_remove_from_queue(\@parts,\%record,\%newrecord,$symb,
- $cdom,$cnum,$domain,$stuname);
+ $cdom,$cnum,$domain,$stuname,$queueable);
}
if ($aggregateflag) {
&Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate,
$cdom,$cnum);
}
+ if (($sendupdate) && (!$submitter)) {
+ if ((ref($needpb) eq 'HASH') &&
+ (keys(%{$needpb}))) {
+ &process_passbacks('handgrade',[$symb],$cdom,$cnum,$domain,$stuname,\%weights,
+ \%awardeds,\%excuseds,$needpb,$skip_passback,$pbsave);
+ }
+ }
return ('',$pts,$wgt,$totchg);
}
@@ -3381,7 +4598,7 @@ sub makehidden {
}
sub check_and_remove_from_queue {
- my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname) = @_;
+ my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname,$queueable) = @_;
my @ungraded_parts;
foreach my $part (@{$parts}) {
if ( $record->{ 'resource.'.$part.'.awarded'} eq ''
@@ -3389,7 +4606,9 @@ sub check_and_remove_from_queue {
&& $newrecord->{'resource.'.$part.'.awarded'} eq ''
&& $newrecord->{'resource.'.$part.'.solved' } ne 'excused'
) {
- push(@ungraded_parts, $part);
+ if ($queueable->{$part}) {
+ push(@ungraded_parts, $part);
+ }
}
}
if ( !@ungraded_parts ) {
@@ -3424,7 +4643,7 @@ sub handback_files {
&Apache::lonnet::file_name_version_ext($answer_file);
my ($portfolio_path) = ($directory =~ /^.+$stuname\/portfolio(.*)/);
my $getpropath = 1;
- my ($dir_list,$listerror) =
+ my ($dir_list,$listerror) =
&Apache::lonnet::dirlist($portfolio_root.$portfolio_path,
$domain,$stuname,$getpropath);
my $version = &Apache::lonnet::get_next_version($answer_name,$answer_ext,$dir_list);
@@ -3588,8 +4807,8 @@ sub version_portfiles {
$$record{$key} = join(',',@versioned_portfiles);
push(@returned_keys,$key);
}
- }
- return (@returned_keys);
+ }
+ return (@returned_keys);
}
#--------------------------------------------------------------------------------------
@@ -3808,7 +5027,26 @@ sub viewgrades {
}
my ($common_header,$specific_header,@sections,$section_display);
- @sections = &Apache::loncommon::get_env_multiple('form.section');
+ if ($env{'request.course.sec'} ne '') {
+ @sections = ($env{'request.course.sec'});
+ } else {
+ @sections = &Apache::loncommon::get_env_multiple('form.section');
+ }
+
+# Check if Save button should be usable
+ my $disabled = ' disabled="disabled"';
+ if ($perm{'mgr'}) {
+ if (grep(/^all$/,@sections)) {
+ undef($disabled);
+ } else {
+ foreach my $sec (@sections) {
+ if (&canmodify($sec)) {
+ undef($disabled);
+ last;
+ }
+ }
+ }
+ }
if (grep(/^all$/,@sections)) {
@sections = ('all');
if ($group_display) {
@@ -3884,7 +5122,6 @@ sub viewgrades {
my $part_resp = join('_',@{ $part_response_id });
next if $seen{$partid};
$seen{$partid}++;
-# my $handgrade=$$handgrade{$part_resp};
my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
$weight{$partid} = $wgt eq '' ? '1' : $wgt;
@@ -4001,7 +5238,7 @@ sub viewgrades {
}
$result.=&Apache::loncommon::end_data_table();
$result.=' '."\n";
- $result.=' '."\n";
if ($ctr == 0) {
my $stu_status = join(' or ',&Apache::loncommon::get_env_multiple('form.Status'));
@@ -4214,6 +5451,10 @@ sub editgrades {
);
my ($classlist,undef,$fullname) = &getclasslist($env{'form.section'},'0');
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my %needpb = &passbacks_for_symb($cdom,$cnum,$symb);
+
my (@partid);
my %weight = ();
my %columns = ();
@@ -4264,6 +5505,7 @@ sub editgrades {
&Apache::loncommon::end_data_table_header_row();
my @noupdate;
my ($updateCtr,$noupdateCtr) = (1,1);
+ my ($got_types,%queueable,%pbsave,%skip_passback);
for ($i=0; $i<$env{'form.total'}; $i++) {
my $user = $env{'form.ctr'.$i};
my ($uname,$udom)=split(/:/,$user);
@@ -4282,6 +5524,7 @@ sub editgrades {
my %aggregate = ();
my $aggregateflag = 0;
$user=~s/:/_/; # colon doen't work in javascript for names
+ my (%weights,%awardeds,%excuseds);
foreach (@partid) {
my $old_aw = $env{'form.GD_'.$user.'_'.$_.'_awarded_s'};
my $old_part_pcr = $old_aw/($weight{$_} ne '0' ? $weight{$_}:1);
@@ -4290,6 +5533,7 @@ sub editgrades {
my $awarded = $env{'form.GD_'.$user.'_'.$_.'_awarded'};
my $pcr = $awarded/($weight{$_} ne '0' ? $weight{$_} : 1);
my $partial = $awarded eq '' ? '' : $pcr;
+ $awardeds{$symb}{$_} = $partial;
my $score;
if ($partial eq '') {
$score = $scoreptr{$env{'form.GD_'.$user.'_'.$_.'_solved_s'}};
@@ -4330,6 +5574,11 @@ sub editgrades {
my $partid=$_;
+ if ($score eq 'excused') {
+ $excuseds{$symb}{$partid} = 1;
+ } else {
+ $excuseds{$symb}{$partid} = '';
+ }
foreach my $stores (@parts) {
my ($part,$type) = &split_part_type($stores);
if ($part !~ m/^\Q$partid\E/) { next;}
@@ -4347,9 +5596,6 @@ sub editgrades {
}
$line.="\n";
- my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
- my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
-
if ($updateflag) {
$count++;
&Apache::lonnet::cstore(\%newrecord,$symb,$env{'request.course.id'},
@@ -4363,14 +5609,33 @@ sub editgrades {
$udom,$uname);
my $all_graded = 1;
my $none_graded = 1;
+ unless ($got_types) {
+ my $error;
+ my ($plist,$handgrd,$resptype) = &response_type($symb,\$error);
+ unless ($error) {
+ foreach my $part (@parts) {
+ if (ref($resptype->{$part}) eq 'HASH') {
+ foreach my $id (keys(%{$resptype->{$part}})) {
+ if (($resptype->{$part}->{$id} eq 'essay') ||
+ (lc($handgrd->{$part.'_'.$id}) eq 'yes')) {
+ $queueable{$part} = 1;
+ last;
+ }
+ }
+ }
+ }
+ }
+ $got_types = 1;
+ }
foreach my $part (@parts) {
- if ( $record{'resource.'.$part.'.awarded'} eq '' ) {
- $all_graded = 0;
- } else {
- $none_graded = 0;
+ if ($queueable{$part}) {
+ if ( $record{'resource.'.$part.'.awarded'} eq '' ) {
+ $all_graded = 0;
+ } else {
+ $none_graded = 0;
+ }
}
- }
-
+ }
if ($all_graded || $none_graded) {
&Apache::bridgetask::remove_from_queue('gradingqueue',
$symb,$cdom,$cnum,
@@ -4382,6 +5647,11 @@ sub editgrades {
' '.$updateCtr.' '.$line.
&Apache::loncommon::end_data_table_row();
$updateCtr++;
+ if (keys(%needpb)) {
+ $weights{$symb} = \%weight;
+ &process_passbacks('editgrades',[$symb],$cdom,$cnum,$udom,$uname,\%weights,
+ \%awardeds,\%excuseds,\%needpb,\%skip_passback,\%pbsave);
+ }
} else {
push(@noupdate,
' '.$noupdateCtr.' '.$line);
@@ -4747,11 +6017,33 @@ sub csvuploadassign {
my @gradedata = &Apache::loncommon::upfile_record_sep();
my %fields=&get_fields();
my $courseid=$env{'request.course.id'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my ($classlist) = &getclasslist('all',0);
my @notallowed;
my @skipped;
my @warnings;
my $countdone=0;
+ my @parts;
+ my %needpb = &passbacks_for_symb($cdom,$cnum,$symb);
+ my $passback;
+ if (keys(%needpb)) {
+ $passback = 1;
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (ref($navmap)) {
+ my $res = $navmap->getBySymb($symb);
+ if (ref($res)) {
+ my $partlist = $res->parts();
+ if (ref($partlist) eq 'ARRAY') {
+ @parts = sort(@{$partlist});
+ }
+ }
+ } else {
+ return &navmap_errormsg();
+ }
+ }
+ my (%skip_passback,%pbsave,%weights,%awardeds,%excuseds);
+
foreach my $grade (@gradedata) {
my %entries=&Apache::loncommon::record_sep($grade);
my $domain;
@@ -4826,9 +6118,14 @@ sub csvuploadassign {
my $part=$1;
my $wgt =&Apache::lonnet::EXT('resource.'.$part.'.weight',
$symb,$domain,$username);
+ $weights{$symb}{$part} = $wgt;
if ($wgt) {
$entries{$fields{$dest}}=~s/\s//g;
my $pcr=$entries{$fields{$dest}} / $wgt;
+ if ($passback) {
+ $awardeds{$symb}{$part} = $pcr;
+ $excuseds{$symb}{$part} = '';
+ }
my $award=($pcr == 0) ? 'incorrect_by_override'
: 'correct_by_override';
if ($pcr>1) {
@@ -4848,6 +6145,22 @@ sub csvuploadassign {
if ($dest=~/stores_(.*)_awarded/) { if ($points{$1}) {next;} }
if ($dest=~/stores_(.*)_solved/) { if ($points{$1}) {next;} }
my $store_key=$dest;
+ if ($passback) {
+ if ($store_key=~/stores_(.*)_(awarded|solved)/) {
+ my ($part,$key) = ($1,$2);
+ unless ((ref($weights{$symb}) eq 'HASH') && (exists($weights{$symb}{$part}))) {
+ $weights{$symb}{$part} = &Apache::lonnet::EXT('resource.'.$part.'.weight',
+ $symb,$domain,$username);
+ }
+ if ($key eq 'awarded') {
+ $awardeds{$symb}{$part} = $entries{$fields{$dest}};
+ } elsif ($key eq 'solved') {
+ if ($entries{$fields{$dest}} =~ /^excused/) {
+ $excuseds{$symb}{$part} = 1;
+ }
+ }
+ }
+ }
$store_key=~s/^stores/resource/;
$store_key=~s/_/\./g;
$grades{$store_key}=$entries{$fields{$dest}};
@@ -4864,11 +6177,32 @@ sub csvuploadassign {
# Successfully stored
$request->print('.');
# Remove from grading queue
- &Apache::bridgetask::remove_from_queue('gradingqueue',$symb,
- $env{'course.'.$env{'request.course.id'}.'.domain'},
- $env{'course.'.$env{'request.course.id'}.'.num'},
+ &Apache::bridgetask::remove_from_queue('gradingqueue',$symb,$cdom,$cnum,
$domain,$username);
$countdone++;
+ if ($passback) {
+ my @parts_in_upload;
+ if (ref($weights{$symb}) eq 'HASH') {
+ @parts_in_upload = sort(keys(%{$weights{$symb}}));
+ }
+ my @diffs = &Apache::loncommon::compare_arrays(\@parts_in_upload,\@parts);
+ if (@diffs > 0) {
+ my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$domain,$username);
+ foreach my $part (@parts) {
+ next if (grep(/^\Q$part\E$/,@parts_in_upload));
+ $weights{$symb}{$part} = &Apache::lonnet::EXT('resource.'.$part.'.weight',
+ $symb,$domain,$username);
+ if ($record{"resource.$part.solved"} =~/^excused/) {
+ $excuseds{$symb}{$part} = 1;
+ } else {
+ $excuseds{$symb}{$part} = '';
+ }
+ $awardeds{$symb}{$part} = $record{"resource.$part.awarded"};
+ }
+ }
+ &process_passbacks('csvupload',[$symb],$cdom,$cnum,$domain,$username,\%weights,
+ \%awardeds,\%excuseds,\%needpb,\%skip_passback,\%pbsave);
+ }
} else {
$request->print("".
&mt("Failed to save data for student [_1]. Message when trying to save was: [_2]",
@@ -5241,10 +6575,14 @@ sub displayPage {
}
$curRes = $iterator->next();
}
+ my $disabled;
+ unless (&canmodify($usec)) {
+ $disabled = ' disabled="disabled"';
+ }
$studentTable.=
''."\n".
- ' '.
''."\n";
$request->print($studentTable);
@@ -5460,6 +6798,7 @@ sub updateGradeByPage {
$iterator->next(); # skip the first BEGIN_MAP
my $curRes = $iterator->next(); # for "current resource"
my ($depth,$question,$prob,$changeflag,$hideflag)= (1,1,1,0,0);
+ my (@updates,%weights,%excuseds,%awardeds,@symbs_in_map);
while ($depth > 0) {
if($curRes == $iterator->BEGIN_MAP) { $depth++; }
if($curRes == $iterator->END_MAP) { $depth--; }
@@ -5468,6 +6807,7 @@ sub updateGradeByPage {
my $parts = $curRes->parts();
my $title = $curRes->compTitle();
my $symbx = $curRes->symb();
+ push(@symbs_in_map,$symbx);
$studentTable.=
&Apache::loncommon::start_data_table_row().
'
'.$prob.
@@ -5480,18 +6820,37 @@ sub updateGradeByPage {
my @displayPts=();
my %aggregate = ();
my $aggregateflag = 0;
+ my %queueable;
if ($env{'form.HIDE'.$prob}) {
my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'},$udom,$uname);
my ($version,$parts) = split(/:/,$env{'form.HIDE'.$prob},2);
my $numchgs = &makehidden($version,$parts,\%record,$symbx,$udom,$uname,1);
+ if ($numchgs) {
+ push(@updates,$symbx);
+ }
$hideflag += $numchgs;
}
foreach my $partid (@{$parts}) {
my $newpts = $env{'form.GD_BOX'.$question.'_'.$partid};
my $oldpts = $env{'form.oldpts'.$question.'_'.$partid};
-
+ my @types = $curRes->responseType($partid);
+ if (grep(/^essay$/,@types)) {
+ $queueable{$partid} = 1;
+ } else {
+ my @ids = $curRes->responseIds($partid);
+ for (my $i=0; $i < scalar(@ids); $i++) {
+ my $hndgrd = &Apache::lonnet::EXT('resource.'.$partid.'_'.$ids[$i].
+ '.handgrade',$symb);
+ if (lc($hndgrd) eq 'yes') {
+ $queueable{$partid} = 1;
+ last;
+ }
+ }
+ }
my $wgt = $env{'form.WGT'.$question.'_'.$partid} != 0 ?
$env{'form.WGT'.$question.'_'.$partid} : 1;
+ $weights{$symbx}{$partid} = $wgt;
+ $excuseds{$symbx}{$partid} = '';
my $partial = $newpts/$wgt;
my $score;
if ($partial > 0) {
@@ -5503,6 +6862,7 @@ sub updateGradeByPage {
if ($dropMenu eq 'excused') {
$partial = '';
$score = 'excused';
+ $excuseds{$symbx}{$partid} = 1;
} elsif ($dropMenu eq 'reset status'
&& $env{'form.solved'.$question.'_'.$partid} ne '') { #update only if previous record exists
$newrecord{'resource.'.$partid.'.tries'} = 0;
@@ -5530,6 +6890,11 @@ sub updateGradeByPage {
(($score eq 'excused') ? 'excused' : $newpts).
' ';
$question++;
+ if (($newpts eq '') || ($partial eq '')) {
+ $awardeds{$symbx}{$partid} = 0;
+ } else {
+ $awardeds{$symbx}{$partid} = $partial;
+ }
next if ($dropMenu eq 'reset status' || ($newpts eq $oldpts && $score ne 'excused'));
$newrecord{'resource.'.$partid.'.awarded'} = $partial if $partial ne '';
@@ -5555,7 +6920,7 @@ sub updateGradeByPage {
$env{'request.course.id'},
$udom,$uname);
&check_and_remove_from_queue($parts,\%record,undef,$symbx,
- $cdom,$cnum,$udom,$uname);
+ $cdom,$cnum,$udom,$uname,\%queueable);
}
if ($aggregateflag) {
@@ -5569,6 +6934,9 @@ sub updateGradeByPage {
&Apache::loncommon::end_data_table_row();
$prob++;
+ if ($changeflag) {
+ push(@updates,$symbx);
+ }
}
$curRes = $iterator->next();
}
@@ -5582,6 +6950,76 @@ sub updateGradeByPage {
$hideflag).' ');
$request->print($hidemsg.$grademsg.$studentTable);
+ if (@updates) {
+ undef(@Apache::lonhomework::ltipassback);
+ my (@allsymbs,$mapsymb,@recurseup,%parentmapsymbs,%possmappb,%possrespb);
+ @allsymbs = @updates;
+ if (ref($map)) {
+ $mapsymb = $map->symb();
+ push(@allsymbs,$mapsymb);
+ @recurseup = $navmap->recurseup_maps($map->src,1);
+ }
+ if (@recurseup) {
+ push(@allsymbs,@recurseup);
+ map { $parentmapsymbs{$_} = 1; } @recurseup;
+ }
+ my %passback = &Apache::lonnet::get('nohist_linkprot_passback',\@allsymbs,$cdom,$cnum);
+ my (%uniqsymbs,$use_symbs_in_map);
+ if (keys(%passback)) {
+ foreach my $possible (keys(%passback)) {
+ if (ref($passback{$possible}) eq 'HASH') {
+ if ($possible eq $mapsymb) {
+ foreach my $launcher (keys(%{$passback{$possible}})) {
+ $possmappb{$launcher} = 1;
+ }
+ $use_symbs_in_map = 1;
+ } elsif (exists($parentmapsymbs{$possible})) {
+ foreach my $launcher (keys(%{$passback{$possible}})) {
+ my ($linkuri,$linkprotector,$scope) = split(/\0/,$launcher);
+ if ($scope eq 'rec') {
+ $possmappb{$launcher} = 1;
+ $use_symbs_in_map = 1;
+ }
+ }
+ } elsif (grep(/^\Q$possible$\E$/,@updates)) {
+ foreach my $launcher (keys(%{$passback{$possible}})) {
+ $possrespb{$launcher} = 1;
+ }
+ $uniqsymbs{$possible} = 1;
+ }
+ }
+ }
+ }
+ if ($use_symbs_in_map) {
+ map { $uniqsymbs{$_} = 1; } @symbs_in_map;
+ }
+ my @posslaunchers;
+ if (keys(%possmappb)) {
+ push(@posslaunchers,keys(%possmappb));
+ }
+ if (keys(%possrespb)) {
+ push(@posslaunchers,keys(%possrespb));
+ }
+ if (@posslaunchers) {
+ my (%pbsave,%skip_passback,%needpb);
+ my %pbids = &Apache::lonnet::get('nohist_'.$cdom.'_'.$cnum.'_linkprot_pb',\@posslaunchers,$udom,$uname);
+ foreach my $key (keys(%pbids)) {
+ if (ref($pbids{$key}) eq 'ARRAY') {
+ $needpb{$key} = 1;
+ }
+ }
+ my @symbs = keys(%uniqsymbs);
+ &process_passbacks('updatebypage',\@symbs,$cdom,$cnum,$udom,$uname,\%weights,
+ \%awardeds,\%excuseds,\%needpb,\%skip_passback,\%pbsave,\%pbids);
+ if (@Apache::lonhomework::ltipassback) {
+ unless ($registered_cleanup) {
+ my $handlers = $request->get_handlers('PerlCleanupHandler');
+ $request->set_handlers('PerlCleanupHandler' =>
+ [\&Apache::lonhomework::do_ltipassback,@{$handlers}]);
+ }
+ }
+ }
+ }
return '';
}
@@ -6467,9 +7905,12 @@ sub scantron_parse_scanline {
}
sub get_master_seq {
- my ($resources,$master_seq,$symb_to_resource) = @_;
+ my ($resources,$master_seq,$symb_to_resource,$need_symb_in_map,$symb_for_examcode) = @_;
return unless ((ref($resources) eq 'ARRAY') && (ref($master_seq) eq 'ARRAY') &&
(ref($symb_to_resource) eq 'HASH'));
+ if ($need_symb_in_map) {
+ return unless (ref($symb_for_examcode) eq 'HASH');
+ }
my $resource_error;
foreach my $resource (@{$resources}) {
my $ressymb;
@@ -6477,6 +7918,14 @@ sub get_master_seq {
$ressymb = $resource->symb();
push(@{$master_seq},$ressymb);
$symb_to_resource->{$ressymb} = $resource;
+ if ($need_symb_in_map) {
+ unless ($resource->is_map()) {
+ my $map=(&Apache::lonnet::decode_symb($ressymb))[0];
+ unless (exists($symb_for_examcode->{$map})) {
+ $symb_for_examcode->{$map} = $ressymb;
+ }
+ }
+ }
} else {
$resource_error = 1;
last;
@@ -8488,6 +9937,17 @@ sub scantron_validate_doublebubble {
if (ref($map)) {
$randomorder = $map->randomorder();
$randompick = $map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
if ($randomorder || $randompick) {
$nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
if ($nav_error) {
@@ -8671,6 +10131,17 @@ sub scantron_validate_missingbubbles {
if (ref($map)) {
$randomorder = $map->randomorder();
$randompick = $map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
if ($randomorder || $randompick) {
$nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
if ($nav_error) {
@@ -8812,10 +10283,21 @@ sub scantron_process_students {
}
my $map=$navmap->getResourceByUrl($sequence);
my ($randomorder,$randompick,@master_seq,%symb_to_resource,%grader_partids_by_symb,
- %grader_randomlists_by_symb);
+ %grader_randomlists_by_symb,%symb_for_examcode);
if (ref($map)) {
$randomorder = $map->randomorder();
$randompick = $map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
} else {
$r->print(&navmap_errormsg());
return '';
@@ -8823,7 +10305,7 @@ sub scantron_process_students {
my $nav_error;
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
if ($randomorder || $randompick) {
- $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
+ $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource,1,\%symb_for_examcode);
if ($nav_error) {
$r->print(&navmap_errormsg());
return '';
@@ -8978,11 +10460,16 @@ SCANTRONFORM
}
if (($scancode) && ($randomorder || $randompick)) {
- my $parmresult =
- &Apache::lonparmset::storeparm_by_symb($symb,
- '0_examcode',2,$scancode,
- 'string_examcode',$uname,
- $udom);
+ foreach my $key (keys(%symb_for_examcode)) {
+ my $symb_in_map = $symb_for_examcode{$key};
+ if ($symb_in_map ne '') {
+ my $parmresult =
+ &Apache::lonparmset::storeparm_by_symb($symb_in_map,
+ '0_examcode',2,$scancode,
+ 'string_examcode',$uname,
+ $udom);
+ }
+ }
}
$completedstudents{$uname}={'line'=>$line};
if ($env{'form.verifyrecord'}) {
@@ -9297,14 +10784,14 @@ END
my @lines = &Apache::lonnet::get_scantronformat_file();
my $count = 0;
foreach my $line (@lines) {
- next if ($line =~ /^#/);
+ next if (($line =~ /^\#/) || ($line eq ''));
$singleline = $line;
$count ++;
}
if ($count > 1) {
$formatextra = ''.
''.
- &mt('Bubblesheet type:').' '.
+ &mt('Bubblesheet type').': '.
&scantron_scantab().'
';
$onclick = ' onclick="toggleScantab(this.form);"';
$formatjs = <<"END";
@@ -9491,7 +10978,7 @@ sub validate_uploaded_scantron_file {
my %unique_formats;
my @formatlines = &Apache::lonnet::get_scantronformat_file();
foreach my $line (@formatlines) {
- chomp($line);
+ next if (($line =~ /^\#/) || ($line eq ''));
my @config = split(/:/,$line);
my $idstart = $config[5];
my $idlength = $config[6];
@@ -9861,6 +11348,17 @@ sub checkscantron_results {
if (ref($map)) {
$randomorder=$map->randomorder();
$randompick=$map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
}
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
my $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
@@ -10179,7 +11677,8 @@ sub verify_scantron_grading {
sub href_symb_cmd {
my ($symb,$cmd)=@_;
- return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='.$cmd;
+ return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='.
+ &HTML::Entities::encode($cmd,'<>&"');
}
sub grading_menu {
@@ -10214,37 +11713,47 @@ sub grading_menu {
$fields{'command'} = 'initialverifyreceipt';
my $url5 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
-
+
+ my %permissions;
+ if ($perm{'mgr'}) {
+ $permissions{'either'} = 'F';
+ $permissions{'mgr'} = 'F';
+ }
+ if ($perm{'vgr'}) {
+ $permissions{'either'} = 'F';
+ $permissions{'vgr'} = 'F';
+ }
+
my @menu = ({ categorytitle=>'Hand Grading',
items =>[
{ linktext => 'Select individual students to grade',
url => $url1a,
- permission => 'F',
+ permission => $permissions{'either'},
icon => 'grade_students.png',
linktitle => 'Grade current resource for a selection of students.'
},
{ linktext => 'Grade ungraded submissions',
url => $url1b,
- permission => 'F',
+ permission => $permissions{'either'},
icon => 'ungrade_sub.png',
linktitle => 'Grade all submissions that have not been graded yet.'
},
{ linktext => 'Grading table',
url => $url1c,
- permission => 'F',
+ permission => $permissions{'either'},
icon => 'grading_table.png',
linktitle => 'Grade current resource for all students.'
},
{ linktext => 'Grade page/folder for one student',
url => $url1d,
- permission => 'F',
+ permission => $permissions{'either'},
icon => 'grade_PageFolder.png',
linktitle => 'Grade all resources in current page/sequence/folder for one student.'
},
{ linktext => 'Download submissions',
url => $url1e,
- permission => 'F',
+ permission => $permissions{'either'},
icon => 'download_sub.png',
linktitle => 'Download all students submissions.'
}]},
@@ -10253,32 +11762,45 @@ sub grading_menu {
{ linktext => 'Upload Scores',
url => $url2,
- permission => 'F',
+ permission => $permissions{'mgr'},
icon => 'uploadscores.png',
linktitle => 'Specify a file containing the class scores for current resource.'
},
{ linktext => 'Process Clicker',
url => $url3,
- permission => 'F',
+ permission => $permissions{'mgr'},
icon => 'addClickerInfoFile.png',
linktitle => 'Specify a file containing the clicker information for this resource.'
},
{ linktext => 'Grade/Manage/Review Bubblesheets',
url => $url4,
- permission => 'F',
+ permission => $permissions{'mgr'},
icon => 'bubblesheet.png',
linktitle => 'Grade bubblesheet exams, upload/download bubblesheet data files, and review previously graded bubblesheet exams.'
},
{ linktext => 'Verify Receipt Number',
url => $url5,
- permission => 'F',
+ permission => $permissions{'either'},
icon => 'receipt_number.png',
linktitle => 'Verify a system-generated receipt number for correct problem solution.'
}
]
});
-
+ my $cdom = $env{"course.$env{'request.course.id'}.domain"};
+ my $cnum = $env{"course.$env{'request.course.id'}.num"};
+ my %passback = &Apache::lonnet::dump('nohist_linkprot_passback',$cdom,$cnum);
+ if (keys(%passback)) {
+ $fields{'command'} = 'initialpassback';
+ my $url6 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+ push (@{$menu[1]{items}},
+ { linktext => 'Passback of Scores',
+ url => $url6,
+ permission => $permissions{'either'},
+ icon => 'passback.png',
+ linktitle => 'Passback scores to launcher CMS for resources accessed via LTI-mediated deep-linking',
+ });
+ }
# Create the menu
my $Str;
$Str .= '';
@@ -10336,11 +11858,30 @@ sub submit_options_download {
my ($request,$symb) = @_;
if (!$symb) {return '';}
+ my $res_error;
+ my ($partlist,$handgrade,$responseType,$numresp,$numessay,$numdropbox) =
+ &response_type($symb,\$res_error);
+ if ($res_error) {
+ $request->print(&mt('An error occurred retrieving response types'));
+ return;
+ }
+ unless ($numessay) {
+ $request->print(&mt('No essayresponse items found'));
+ return;
+ }
+ my $table;
+ if (ref($partlist) eq 'ARRAY') {
+ if (scalar(@$partlist) > 1 ) {
+ $table = &showResourceInfo($symb,$partlist,$responseType,'gradingMenu',1,1);
+ }
+ }
+
my $is_tool = ($symb =~ /ext\.tool$/);
&commonJSfunctions($request);
my $result=' '."\n".
- ' '."\n";
+ $table."\n".
+ ' '."\n";
$result.='
'.&mt('Select Students for whom to Download Submissions').'
@@ -10387,6 +11928,14 @@ sub selectfield {
(&substatus_options,
'select_form_order' => ['yes','queued','graded','incorrect','all']);
}
+
+ #
+ # PrepareClasslist() needs to be called to avoid getting a sections list
+ # for a different course from the @Sections global in lonstatistics.pm,
+ # populated by an earlier request.
+ #
+ &Apache::lonstatistics::PrepareClasslist();
+
my $result='
@@ -11099,6 +12648,7 @@ sub assign_clicker_grades {
$result.="Failed to save student $username:$domain. Message when trying to save was ($returncode) ";
} else {
$storecount++;
+ #FIXME Do passback for $user if required
}
}
}
@@ -11118,7 +12668,7 @@ sub navmap_errormsg {
}
sub startpage {
- my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$js,$onload) = @_;
+ my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$head_extra,$onload,$divforres) = @_;
my %args;
if ($onload) {
my %loaditems = (
@@ -11128,28 +12678,101 @@ sub startpage {
}
if ($nomenu) {
$args{'only_body'} = 1;
- $r->print(&Apache::loncommon::start_page("Student's Version",$js,\%args));
+ $r->print(&Apache::loncommon::start_page("Student's Version",$head_extra,\%args));
} else {
- unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
+ if ($env{'request.course.id'}) {
+ unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
+ }
$args{'bread_crumbs'} = $crumbs;
- $r->print(&Apache::loncommon::start_page('Grading',$js,\%args));
+ $r->print(&Apache::loncommon::start_page('Grading',$head_extra,\%args));
if ($env{'request.course.id'}) {
&Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading'));
}
}
unless ($nodisplayflag) {
- $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag,$stuvcurrent,$stuvdisp));
+ $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag,$stuvcurrent,$stuvdisp,$divforres));
}
}
sub select_problem {
my ($r)=@_;
$r->print(''.&mt('Select the problem or one of the problems you want to grade').' ');
- $r->print(&Apache::lonstathelpers::problem_selector('.',undef,1,undef,undef,undef,undef,1));
+ $r->print(&Apache::lonstathelpers::problem_selector('.',undef,1,undef,undef,1,1));
$r->print(' ');
$r->print(' ');
}
+#----- display problem, answer, and submissions for a single student (no grading)
+
+sub view_as_user {
+ my ($symb,$vuname,$vudom,$hasperm) = @_;
+ my $plainname = &Apache::loncommon::plainname($vuname,$vudom,'lastname');
+ my $displayname = &nameUserString('',$plainname,$vuname,$vudom);
+ my $output = &Apache::loncommon::get_student_view($symb,$vuname,$vudom,
+ $env{'request.course.id'},
+ undef,{'disable_submit' => 1}).
+ "\n\n".
+ ''.
+ '
'.$displayname.' '.
+ "\n".
+ &Apache::loncommon::track_student_link('View recent activity',
+ $vuname,$vudom,'check').' '.
+ "\n";
+ if (&Apache::lonnet::allowed('opa',$env{'request.course.id'}) ||
+ (($env{'request.course.sec'} ne '') &&
+ &Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'.$env{'request.course.sec'}))) {
+ $output .= &Apache::loncommon::pprmlink(&mt('Set/Change parameters'),
+ $vuname,$vudom,$symb,'check');
+ }
+ $output .= "\n";
+ my $companswer = &Apache::loncommon::get_student_answers($symb,$vuname,$vudom,
+ $env{'request.course.id'});
+ $companswer=~s|
||g;
+ $companswer=~s| ||g;
+ $companswer=~s|name="submit"|name="would_have_been_submit"|g;
+ $output .= '
'.
+ '
'.&mt('Correct answer for[_1]',$displayname).' '.
+ $companswer.
+ ''."\n";
+ my $is_tool = ($symb =~ /ext\.tool$/);
+ my ($essayurl,%coursedesc_by_cid);
+ (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb);
+ my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$vudom,$vuname);
+ my $res_error;
+ my ($partlist,$handgrade,$responseType,$numresp,$numessay) =
+ &response_type($symb,\$res_error);
+ my $fullname;
+ my $collabinfo;
+ if ($numessay) {
+ unless ($hasperm) {
+ &init_perm();
+ }
+ ($collabinfo,$fullname)=
+ &check_collaborators($symb,$vuname,$vudom,\%record,$handgrade,0);
+ unless ($hasperm) {
+ &reset_perm();
+ }
+ }
+ my $checkIcon = '
';
+ my ($lastsubonly,$partinfo) =
+ &show_last_submission($vuname,$vudom,$symb,$essayurl,$responseType,'datesub',
+ '',$fullname,\%record,\%coursedesc_by_cid);
+ $output .= '
'.
+ '
'.&mt('Submissions').' '."\n".$collabinfo."\n";
+ if (($numresp > $numessay) & !$is_tool) {
+ $output .='
'.
+ &mt('Part(s) graded correct by the computer is marked with a [_1] symbol.',$checkIcon).
+ "
\n";
+ }
+ $output .= $partinfo;
+ $output .= $lastsubonly;
+ $output .= &displaySubByDates($symb,\%record,$partlist,$responseType,$checkIcon,$vuname,$vudom);
+ $output .= '
'."\n";
+ return $output;
+}
+
sub handler {
my $request=$_[0];
&reset_caches();
@@ -11202,24 +12825,49 @@ sub handler {
&select_problem($request);
} else {
if ($command eq 'submission' && $perm{'vgr'}) {
- my ($stuvcurrent,$stuvdisp,$versionform,$js);
+ my ($stuvcurrent,$stuvdisp,$versionform,$js,$onload);
if (($env{'form.student'} ne '') && ($env{'form.userdom'} ne '')) {
($stuvcurrent,$stuvdisp,$versionform,$js) =
&choose_task_version_form($symb,$env{'form.student'},
$env{'form.userdom'});
}
- &startpage($request,$symb,[{href=>"", text=>"Student Submissions"}],undef,undef,$stuvcurrent,$stuvdisp,undef,$js);
+ my $divforres;
+ if ($env{'form.student'} eq '') {
+ $js .= &part_selector_js();
+ $onload = "toggleParts('gradesub');";
+ } else {
+ $divforres = 1;
+ }
+ my $head_extra = $js;
+ unless ($env{'form.vProb'} eq 'no') {
+ my $csslinks = &Apache::loncommon::css_links($symb);
+ if ($csslinks) {
+ $head_extra .= "\n$csslinks";
+ }
+ }
+ &startpage($request,$symb,[{href=>"", text=>"Student Submissions"}],undef,undef,
+ $stuvcurrent,$stuvdisp,undef,$head_extra,$onload,$divforres);
if ($versionform) {
+ if ($divforres) {
+ $request->print('
');
+ }
$request->print($versionform);
}
- $request->print(' ');
- ($env{'form.student'} eq '' ? &listStudents($request,$symb) : &submission($request,0,0,$symb));
+ ($env{'form.student'} eq '' ? &listStudents($request,$symb,'',$divforres) : &submission($request,0,0,$symb,$divforres,$command));
} elsif ($command eq 'versionsub' && $perm{'vgr'}) {
my ($stuvcurrent,$stuvdisp,$versionform,$js) =
&choose_task_version_form($symb,$env{'form.student'},
$env{'form.userdom'},
$env{'form.inhibitmenu'});
- &startpage($request,$symb,[{href=>"", text=>"Previous Student Version"}],undef,undef,$stuvcurrent,$stuvdisp,$env{'form.inhibitmenu'},$js);
+ my $head_extra = $js;
+ unless ($env{'form.vProb'} eq 'no') {
+ my $csslinks = &Apache::loncommon::css_links($symb);
+ if ($csslinks) {
+ $head_extra .= "\n$csslinks";
+ }
+ }
+ &startpage($request,$symb,[{href=>"", text=>"Previous Student Version"}],undef,undef,
+ $stuvcurrent,$stuvdisp,$env{'form.inhibitmenu'},$head_extra);
if ($versionform) {
$request->print($versionform);
}
@@ -11230,10 +12878,14 @@ sub handler {
{href=>'',text=>'Select student'}],1,1);
&pickStudentPage($request,$symb);
} elsif ($command eq 'displayPage' && $perm{'vgr'}) {
+ my $csslinks;
+ unless ($env{'form.vProb'} eq 'no') {
+ $csslinks = &Apache::loncommon::css_links($symb,'map');
+ }
&startpage($request,$symb,
[{href=>&href_symb_cmd($symb,'all_for_one'),text=>'Grade page/folder for one student'},
{href=>'',text=>'Select student'},
- {href=>'',text=>'Grade student'}],1,1);
+ {href=>'',text=>'Grade student'}],1,1,undef,undef,undef,$csslinks);
&displayPage($request,$symb);
} elsif ($command eq 'gradeByPage' && $perm{'mgr'}) {
&startpage($request,$symb,[{href=>&href_symb_cmd($symb,'all_for_one'),text=>'Grade page/folder for one student'},
@@ -11242,8 +12894,12 @@ sub handler {
{href=>'',text=>'Store grades'}],1,1);
&updateGradeByPage($request,$symb);
} elsif ($command eq 'processGroup' && $perm{'vgr'}) {
+ my $csslinks;
+ unless ($env{'form.vProb'} eq 'no') {
+ $csslinks = &Apache::loncommon::css_links($symb);
+ }
&startpage($request,$symb,[{href=>'',text=>'...'},
- {href=>'',text=>'Modify grades'}]);
+ {href=>'',text=>'Modify grades'}],undef,undef,undef,undef,undef,$csslinks,undef,1);
&processGroup($request,$symb);
} elsif ($command eq 'gradingmenu' && $perm{'vgr'}) {
&startpage($request,$symb);
@@ -11252,7 +12908,10 @@ sub handler {
&startpage($request,$symb,[{href=>'',text=>'Select individual students to grade'}]);
$request->print(&submit_options($request,$symb));
} elsif ($command eq 'ungraded' && $perm{'vgr'}) {
- &startpage($request,$symb,[{href=>'',text=>'Grade ungraded submissions'}]);
+ my $js = &part_selector_js();
+ my $onload = "toggleParts('gradesub');";
+ &startpage($request,$symb,[{href=>'',text=>'Grade ungraded submissions'}],
+ undef,undef,undef,undef,undef,$js,$onload);
$request->print(&listStudents($request,$symb,'graded'));
} elsif ($command eq 'table' && $perm{'vgr'}) {
&startpage($request,$symb,[{href=>"", text=>"Grading table"}]);
@@ -11350,13 +13009,56 @@ sub handler {
&startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
$request->print(&checkscantron_results($request,$symb));
} elsif ($command eq 'downloadfilesselect' && $perm{'vgr'}) {
- &startpage($request,$symb,[{href=>'', text=>'Select which submissions to download'}]);
+ my $js = &part_selector_js();
+ my $onload = "toggleParts('gradingMenu');";
+ &startpage($request,$symb,[{href=>'', text=>'Select which submissions to download'}],
+ undef,undef,undef,undef,undef,$js,$onload);
$request->print(&submit_options_download($request,$symb));
} elsif ($command eq 'downloadfileslink' && $perm{'vgr'}) {
&startpage($request,$symb,
[{href=>&href_symb_cmd($symb,'downloadfilesselect'), text=>'Select which submissions to download'},
- {href=>'', text=>'Download submitted files'}]);
+ {href=>'', text=>'Download submitted files'}],
+ undef,undef,undef,undef,undef,undef,undef,1);
+ $request->print('
');
&submit_download_link($request,$symb);
+ } elsif ($command eq 'initialpassback') {
+ &startpage($request,$symb,[{href=>'', text=>'Choose Launcher'}],undef,1);
+ $request->print(&initialpassback($request,$symb));
+ } elsif ($command eq 'passback') {
+ &startpage($request,$symb,
+ [{href=>&href_symb_cmd($symb,'initialpassback'), text=>'Choose Launcher'},
+ {href=>'', text=>'Types of User'}],undef,1);
+ $request->print(&passback_filters($request,$symb));
+ } elsif ($command eq 'passbacknames') {
+ my $chosen;
+ if ($env{'form.passback'} ne '') {
+ if ($env{'form.passback'} eq &unescape($env{'form.passback'})) {
+ $env{'form.passback'} = &escape($env{'form.passback'} );
+ }
+ $chosen = &HTML::Entities::encode($env{'form.passback'},'<>"&');
+ }
+ &startpage($request,$symb,
+ [{href=>&href_symb_cmd($symb,'initialpassback'), text=>'Choose Launcher'},
+ {href=>&href_symb_cmd($symb,'passback').'&passback='.$chosen, text=>'Types of User'},
+ {href=>'', text=>'Select Users'}],undef,1);
+ $request->print(&names_for_passback($request,$symb));
+ } elsif ($command eq 'passbackscores') {
+ my ($chosen,$stu_status);
+ if ($env{'form.passback'} ne '') {
+ if ($env{'form.passback'} eq &unescape($env{'form.passback'})) {
+ $env{'form.passback'} = &escape($env{'form.passback'} );
+ }
+ $chosen = &HTML::Entities::encode($env{'form.passback'},'<>"&');
+ }
+ if ($env{'form.Status'}) {
+ $stu_status = &HTML::Entities::encode($env{'form.Status'});
+ }
+ &startpage($request,$symb,
+ [{href=>&href_symb_cmd($symb,'initialpassback'), text=>'Choose Launcher'},
+ {href=>&href_symb_cmd($symb,'passback').'&passback='.$chosen, text=>'Types of User'},
+ {href=>&href_symb_cmd($symb,'passbacknames').'&Status='.$stu_status.'&passback='.$chosen, text=>'Select Users'},
+ {href=>'', text=>'Execute Passback'}],undef,1);
+ $request->print(&do_passback($request,$symb));
} elsif ($command) {
&startpage($request,$symb,[{href=>'', text=>'Access denied'}]);
$request->print(''.&mt('Access Denied ([_1])',$command).'
');
@@ -11535,8 +13237,8 @@ Side Effects: None.
- missingbubble - array ref of the bubble lines that have missing
bubble errors
- $randomorder - True if exam folder has randomorder set
- $randompick - True if exam folder has randompick set
+ $randomorder - True if exam folder (or a sub-folder) has randomorder set
+ $randompick - True if exam folder (or a sub-folder) has randompick set
$respnumlookup - Reference to HASH mapping question numbers in bubble lines
for current line to question number used for same question
in "Master Seqence" (as seen by Course Coordinator).