--- loncom/homework/grades.pm 2023/09/07 17:38:56 1.596.2.12.2.60.2.5
+++ loncom/homework/grades.pm 2019/01/27 14:39:55 1.754
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.596.2.12.2.60.2.5 2023/09/07 17:38:56 raeburn Exp $
+# $Id: grades.pm,v 1.754 2019/01/27 14:39:55 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -44,11 +44,10 @@ use Apache::Constants qw(:common :http);
use Apache::lonlocal;
use Apache::lonenc;
use Apache::lonstathelpers;
+use Apache::lonquickgrades;
use Apache::bridgetask();
use Apache::lontexconvert();
use String::Similarity;
-use HTML::Parser();
-use File::MMagic;
use LONCAPA;
use POSIX qw(floor);
@@ -147,7 +146,6 @@ sub nameUserString {
#--- Get the partlist and the response type for a given problem. ---
#--- Indicate if a response type is coded handgraded or not. ---
-#--- Count responseIDs, essayresponse items, and dropbox items ---
#--- Sets response_error pointer to "1" if navmaps object broken ---
sub response_type {
my ($symb,$response_error) = @_;
@@ -165,7 +163,6 @@ sub response_type {
return;
}
my $partlist = $res->parts();
- my ($numresp,$numessay,$numdropbox) = (0,0,0);
my %vPart =
map { $_ => 1 } (&Apache::loncommon::get_env_multiple('form.vPart'));
my (%response_types,%handgrade);
@@ -175,20 +172,13 @@ sub response_type {
my @types = $res->responseType($part);
my @ids = $res->responseIds($part);
for (my $i=0; $i < scalar(@ids); $i++) {
- $numresp ++;
$response_types{$part}{$ids[$i]} = $types[$i];
- if ($types[$i] eq 'essay') {
- $numessay ++;
- if (&Apache::lonnet::EXT("resource.$part".'_'.$ids[$i].".uploadedfiletypes",$symb)) {
- $numdropbox ++;
- }
- }
$handgrade{$part.'_'.$ids[$i]} =
&Apache::lonnet::EXT('resource.'.$part.'_'.$ids[$i].
'.handgrade',$symb);
}
}
- return ($partlist,\%handgrade,\%response_types,$numresp,$numessay,$numdropbox);
+ return ($partlist,\%handgrade,\%response_types);
}
sub flatten_responseType {
@@ -215,129 +205,6 @@ sub get_display_part {
return $display;
}
-#--- Show parts and response type
-sub showResourceInfo {
- my ($symb,$partlist,$responseType,$formname,$checkboxes,$uploads) = @_;
- unless ((ref($partlist) eq 'ARRAY') && (ref($responseType) eq 'HASH')) {
- return '
';
- }
- my $coltitle = &mt('Problem Part Shown');
- if ($checkboxes) {
- $coltitle = &mt('Problem Part');
- } else {
- my $checkedparts = 0;
- foreach my $partid (&Apache::loncommon::get_env_multiple('form.vPart')) {
- if (grep(/^\Q$partid\E$/,@{$partlist})) {
- $checkedparts ++;
- }
- }
- if ($checkedparts == scalar(@{$partlist})) {
- return '
';
- }
- if ($uploads) {
- $coltitle = &mt('Problem Part Selected');
- }
- }
- my $result = '
'. - &mt('No dropbox items or essayresponse items with uploadedfiletypes set.'). - '
'; - } else { - return ''.&keywords_highlight($answer).''; + } elsif ( $response eq 'organic') { my $result=&mt('Smile representation: [_1]', '"'.&HTML::Entities::encode($answer, '"<>&').'"'); @@ -669,7 +537,7 @@ sub getclasslist { $cdom = $env{"course.$env{'request.course.id'}.domain"}; $cnum = $env{"course.$env{'request.course.id'}.num"}; my $res_error; - ($partlist) = &response_type($symb,\$res_error); + ($partlist,my $handgrade,my $responseType) = &response_type($symb,\$res_error); } foreach my $student (keys(%$classlist)) { my $end = @@ -785,7 +653,7 @@ sub canmodify { #can modify the requested section return 1; } else { - # can't modify the requested section + # can't modify the request section return 0; } } @@ -798,19 +666,19 @@ sub canview { my ($sec)=@_; if ($perm{'vgr'}) { if (!defined($perm{'vgr_section'})) { - # can view whole class + # can modify whole class return 1; } else { if ($sec eq $perm{'vgr_section'}) { - #can view the requested section + #can modify the requested section return 1; } else { - # can't view the requested section + # can't modify the request section return 0; } } } - #can't view + #can't modify return 0; } @@ -951,14 +819,14 @@ sub initialverifyreceipt { #--- Check whether a receipt number is valid.--- sub verifyreceipt { - my ($request,$symb) = @_; + my ($request,$symb) = @_; my $courseid = $env{'request.course.id'}; my $receipt = &Apache::lonnet::recprefix($courseid).'-'. $env{'form.receipt'}; $receipt =~ s/[^\-\d]//g; - my $title = + my $title.= '
'.&mt('[_1]Message:[_2] No more students for this section or class.','','').'
'."\n"; + my $the_end.=''.&mt('[_1]Message:[_2] No more students for this section or class.','','').'
'."\n"; $request->print($the_end); } return ''; @@ -3485,7 +3228,7 @@ sub processHandGrade { #---- Save the score and award for each student, if changed sub saveHandGrade { - my ($request,$symb,$stuname,$domain,$newflg,$submitter,$part,$queueable) = @_; + my ($request,$symb,$stuname,$domain,$newflg,$submitter,$part) = @_; my @version_parts; my $usec = &Apache::lonnet::getsection($domain,$stuname, $env{'request.course.id'}); @@ -3597,7 +3340,7 @@ 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,$queueable); + $cdom,$cnum,$domain,$stuname); } if ($aggregateflag) { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, @@ -3637,7 +3380,7 @@ sub makehidden { } sub check_and_remove_from_queue { - my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname,$queueable) = @_; + my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname) = @_; my @ungraded_parts; foreach my $part (@{$parts}) { if ( $record->{ 'resource.'.$part.'.awarded'} eq '' @@ -3645,9 +3388,7 @@ sub check_and_remove_from_queue { && $newrecord->{'resource.'.$part.'.awarded'} eq '' && $newrecord->{'resource.'.$part.'.solved' } ne 'excused' ) { - if ($queueable->{$part}) { - push(@ungraded_parts, $part); - } + push(@ungraded_parts, $part); } } if ( !@ungraded_parts ) { @@ -3673,19 +3414,19 @@ sub handback_files { my $part_resp = join('_',@{ $part_response_id }); if (($env{'form.'.$newflg.'_'.$part_resp.'_countreturndoc'} =~ /^\d+$/) & ($new_part eq $part_id)) { for (my $counter=1; $counter<=$env{'form.'.$newflg.'_'.$part_resp.'_countreturndoc'}; $counter++) { - # if multiple files are uploaded names will be 'returndoc2','returndoc3' - if ($env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$counter}) { + # if multiple files are uploaded names will be 'returndoc2','returndoc3' + if ($env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$counter}) { my $fname=$env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$counter.'.filename'}; my ($directory,$answer_file) = ($env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$counter} =~ /^(.*?)([^\/]*)$/); my ($answer_name,$answer_ver,$answer_ext) = - &file_name_version_ext($answer_file); + &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 = &get_next_version($answer_name,$answer_ext,$dir_list); + my $version = &Apache::lonnet::get_next_version($answer_name,$answer_ext,$dir_list); # fix filename my ($save_file_name) = (($directory.$answer_name.".$version.".$answer_ext) =~ /^.+\/${stuname}\/(.*)/); my $result=&Apache::lonnet::finishuserfileupload($stuname,$domain, @@ -3703,8 +3444,7 @@ sub handback_files { $$newrecord{"resource.$new_part.$resp_id.handback"}.=','; } $$newrecord{"resource.$new_part.$resp_id.handback"} .= $save_file_name; - $file_msg.=''.$save_file_name."".&mt('Users are in domain: [_1]',$domform)."
\n"); + $request->print("\n".&mt('Users are in domain: [_1]',$domform)."
\n"); } foreach my $key (sort(keys(%env))) { if ($key !~ /^form\.(.*)$/) { next; } @@ -5110,15 +4736,14 @@ sub get_fields { } sub csvuploadassign { - my ($request,$symb) = @_; + my ($request,$symb)= @_; if (!$symb) {return '';} my $error_msg = ''; my $datatoken = &Apache::loncommon::valid_datatoken($env{'form.datatoken'}); - if ($datatoken ne '') { + if ($datatoken ne '') { &Apache::loncommon::load_tmp_file($request,$datatoken); } my @gradedata = &Apache::loncommon::upfile_record_sep(); - if ($env{'form.noFirstLine'}) { shift(@gradedata); } my %fields=&get_fields(); my $courseid=$env{'request.course.id'}; my ($classlist) = &getclasslist('all',0); @@ -5140,13 +4765,45 @@ sub csvuploadassign { if (!$username) { my $id=$entries{$fields{'ID'}}; $id=~s/\s//g; - my %ids=&Apache::lonnet::idget($domain,$id); - $username=$ids{$id}; + if ($id ne '') { + my %ids=&Apache::lonnet::idget($domain,[$id]); + $username=$ids{$id}; + } else { + if ($entries{$fields{'clicker'}}) { + my $clicker = $entries{$fields{'clicker'}}; + $clicker=~s/\s//g; + if ($clicker ne '') { + my %clickers = &Apache::lonnet::idget($domain,[$clicker],'clickers'); + if ($clickers{$clicker} ne '') { + my $match = 0; + my @inclass; + foreach my $poss (split(/,/,$clickers{$clicker})) { + if (exists($$classlist{"$poss:$domain"})) { + $username = $poss; + push(@inclass,$poss); + $match ++; + + } + } + if ($match > 1) { + undef($username); + $request->print(''. + &mt('Score not saved for clicker: [_1] (matched multiple usernames: [_2])', + $clicker,join(', ',@inclass)).'
'); + } + } + } + } + } } if (!exists($$classlist{"$username:$domain"})) { my $id=$entries{$fields{'ID'}}; $id=~s/\s//g; - if ($id) { + my $clicker = $entries{$fields{'clicker'}}; + $clicker=~s/\s//g; + if ($clicker) { + push(@skipped,"$clicker:$domain"); + } elsif ($id) { push(@skipped,"$id:$domain"); } else { push(@skipped,"$username:$domain"); @@ -5174,7 +4831,7 @@ sub csvuploadassign { my $award=($pcr == 0) ? 'incorrect_by_override' : 'correct_by_override'; if ($pcr>1) { - push(@warnings,&mt("[_1]: point value larger than weight","$username:$domain")); + push(@warnings,&mt("[_1]: point value larger than weight","$username:$domain")); } $grades{"resource.$part.awarded"}=$pcr; $grades{"resource.$part.solved"}=$award; @@ -5195,7 +4852,7 @@ sub csvuploadassign { $grades{$store_key}=$entries{$fields{$dest}}; } } - if (! %grades) { + if (! %grades) { push(@skipped,&mt("[_1]: no data to save","$username:$domain")); } else { $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}"; @@ -5210,13 +4867,13 @@ sub csvuploadassign { $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}, $domain,$username); - } else { + $countdone++; + } else { $request->print("". &mt("Failed to save data for student [_1]. Message when trying to save was: [_2]", "$username:$domain",$result)."
"); } $request->rflush(); - $countdone++; } } $request->print(''
.&mt('Unable to accept last correction, an error occurred: [_1]',
$errmsg)
@@ -7514,7 +7145,7 @@ sub scantron_validate_file {
while (!$stop && $currentphase < scalar(@validate_phases)) {
$r->print(&mt('Validating '.$validate_phases[$currentphase]).'
');
$r->rflush();
-
+
my $which="scantron_validate_".$validate_phases[$currentphase];
{
no strict 'refs';
@@ -7544,7 +7175,7 @@ sub scantron_validate_file {
$r->print('');
$r->print(' '.&mt('this error').'
');
- $r->print('
'.&mt('Or return to [_1]Grade/Manage/Review Bubblesheets[_2] to start over.','','').'
'); + $r->print(''.&mt('Or return to [_1]Grade/Manage/Review Bubblesheets[_2] to start over.','','').'
'); } else { if ($validate_phases[$currentphase] eq 'doublebubble' || $validate_phases[$currentphase] eq 'missingbubbles') { $r->print(''); @@ -7923,9 +7554,10 @@ sub scantron_validate_sequence { my @resources= $navmap->retrieveResources($map,\&scantron_filter_not_exam,1,0); if (@resources) { - $r->print('' + $r->print( + '
' .&mt('Some resources in the sequence currently are not set to' - .' exam mode. Grading these resources currently may not' + .' bubblesheet exam mode. Grading these resources currently may not' .' work correctly.') .'
' ); @@ -8047,10 +7679,10 @@ sub scantron_get_correction { if ($error =~ /ID$/) { if ($error eq 'incorrectID') { - $r->print(''.&mt("The encoded ID is not in the classlist"). + $r->print('
'.&mt("The encoded ID is not in the classlist"). "
\n"); } elsif ($error eq 'duplicateID') { - $r->print(''.&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n"); + $r->print(''.&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n"); } $r->print($message); $r->print("".&mt("How should I handle this?")."
\n");
@@ -8070,8 +7702,8 @@ sub scantron_get_correction {
} elsif ($error eq 'duplicateCODE') {
$r->print('
'.&mt("The encoded CODE has also been used by a previous paper [_1], and CODEs are supposed to be unique.",join(', ',@{$arg}))."
\n"); } - $r->print("".&mt('The CODE on the form is [_1]', - "'$$scan_record{'scantron.CODE'}'") + $r->print("
".&mt('The CODE on the form is [_1]', + "'$$scan_record{'scantron.CODE'}'") ."
\n"); $r->print($message); $r->print("".&mt("How should I handle this?")."
\n"); @@ -8168,7 +7800,7 @@ ENDSCRIPT # The form field scantron_questions is actually a list of line numbers not # a list of question numbers. Therefore: # - + my $line_list = &questions_to_line_list($arg,$randomorder,$randompick, $respnumlookup,$startline); @@ -8193,7 +7825,7 @@ sub verify_bubbles_checked { my $ansnumstr = join('","',@ansnums); my $warning = &mt("A bubble or 'No bubble' selection has not been made for one or more lines."); &js_escape(\$warning); - my $output = &Apache::lonhtmlcommon::scripttag(<'.&mt("Uploading file to [_1]",$coursedata{'description'}).'
'); + $r->print(''.&mt('Uploading file to [_1]','"'.$coursedata{'description'}.'"').'
'); if (length($env{'form.upfile'}) < 2) { $r->print( &Apache::lonhtmlcommon::confirm_success( @@ -9594,19 +9192,15 @@ sub scantron_upload_scantron_data_save { if (@possibles > 1) { if ($env{'form.fileformat'} eq 'csv') { if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') { - if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') { - if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}}) > 1) { - $is_csv = 1; - } + if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}}) > 1) { + $is_csv = 1; } } } } elsif (@possibles == 1) { if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') { - if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') { - if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}}) > 1) { - $is_csv = 1; - } + if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}}) > 1) { + $is_csv = 1; } } } @@ -9618,7 +9212,7 @@ sub scantron_upload_scantron_data_save { my $result = &Apache::lonnet::userfileupload('upfile','scantron','scantron',$parser,'','', $env{'form.courseid'},$env{'form.domainid'}); - if ($result =~ m{^/uploaded/}) { + if ($result =~ m{^/uploaded/}) { $r->print( &Apache::lonhtmlcommon::confirm_success(&mt('Upload successful')).''. - &mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([quant,_4,bubblesheet line] per student).', - '', - $numstudents, - '', - $env{'form.scantron_maxbubble'}). - '
' + $r->print( + '' + .&mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([quant,_4,bubblesheet line] per student).', + '', + $numstudents, + '', + $env{'form.scantron_maxbubble'}) + .'
' ); $r->print(''
.&mt('Exact matches for [_1][quant,_2,student][_3].','',$passed,'')
.'
'
.&mt('Discrepancies detected for [_1][quant,_2,student][_3].','',$failed,'')
- .'