--- loncom/homework/grades.pm 2009/05/04 22:41:37 1.567 +++ loncom/homework/grades.pm 2010/04/12 12:55:18 1.611 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.567 2009/05/04 22:41:37 raeburn Exp $ +# $Id: grades.pm,v 1.611 2010/04/12 12:55:18 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -96,10 +96,19 @@ sub ssi_print_error { # # --- Retrieve the parts from the metadata file.--- +# Returns an array of everything that the resources stores away +# + sub getpartlist { - my ($symb) = @_; + my ($symb,$errorref) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + if (ref($errorref)) { + $$errorref = 'navmap'; + return; + } + } my $res = $navmap->getBySymb($symb); my $partlist = $res->parts(); my $url = $res->src(); @@ -114,21 +123,6 @@ sub getpartlist { return @stores; } -# --- Get the symbolic name of a problem and the url -sub get_symb { - my ($request,$silent) = @_; - (my $url=$env{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--; - my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url))); - if ($symb eq '') { - if (!$silent) { - $request->print("Unable to handle ambiguous references:$url:."); - return (); - } - } - &Apache::lonenc::check_decrypt(\$symb); - return ($symb); -} - #--- Format fullname, username:domain if different for display #--- Use anywhere where the student names are listed sub nameUserString { @@ -144,10 +138,20 @@ sub nameUserString { #--- Get the partlist and the response type for a given problem. --- #--- Indicate if a response type is coded handgraded or not. --- sub response_type { - my ($symb) = shift; + my ($symb,$response_error) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + if (ref($response_error)) { + $$response_error = 1; + } + return; + } my $res = $navmap->getBySymb($symb); + unless (ref($res)) { + $$response_error = 1; + return; + } my $partlist = $res->parts(); my %vPart = map { $_ => 1 } (&Apache::loncommon::get_env_multiple('form.vPart')); @@ -183,50 +187,14 @@ sub get_display_part { my ($partID,$symb)=@_; my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',$symb); if (defined($display) and $display ne '') { - $display.= " (id $partID)"; + $display.= ' (' + .&mt('Part ID: [_1]',$partID).')'; } else { $display=$partID; } return $display; } -#--- Show resource title -#--- and parts and response type -sub showResourceInfo { - my ($symb,$probTitle,$checkboxes) = @_; - my $col=3; - if ($checkboxes) { $col=4; } - my $result = '

'.&mt('Current Resource').': '.$probTitle.'

'."\n"; - $result .=''; - my ($partlist,$handgrade,$responseType) = &response_type($symb); - my %resptype = (); - my $hdgrade='no'; - my %partsseen; - foreach my $partID (sort(keys(%$responseType))) { - foreach my $resID (sort(keys(%{ $responseType->{$partID} }))) { - my $handgrade=$$handgrade{$partID.'_'.$resID}; - my $responsetype = $responseType->{$partID}->{$resID}; - $hdgrade = $handgrade if ($handgrade eq 'yes'); - $result.=''; - if ($checkboxes) { - if (exists($partsseen{$partID})) { - $result.=""; - } else { - $result.=""; - } - $partsseen{$partID}=1; - } - my $display_part=&get_display_part($partID,$symb); - $result.=''. - ''; -# ''; - } - } - $result.='
 '.&mt('Part').': '.$display_part. - ' '.$resID.''.&mt('Type').': '.$responsetype.'
'.&mt('Handgrade: [_1]',$handgrade).'
'."\n"; - return $result,$responseType,$hdgrade,$partlist,$handgrade; -} - sub reset_caches { &reset_analyze_cache(); &reset_perm(); @@ -396,7 +364,7 @@ sub cleanRecord { return '
'. ''.$toprow.''. ''. - $grayFont.$bottomrow.''.'
'.&mt('Answer').'
'.$grayFont.&mt('Option ID').'
'; + $bottomrow.''.''; } elsif ($response eq 'essay') { if (! exists ($env{'form.'.$symb})) { my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade', @@ -458,8 +426,7 @@ sub cleanRecord { #-- A couple of common js functions sub commonJSfunctions { my $request = shift; - $request->print(< + $request->print(&Apache::lonhtmlcommon::scripttag(< 1) { @@ -487,7 +454,6 @@ sub commonJSfunctions { return selectOne.value; } } - COMMONJSFUNCTIONS } @@ -642,17 +608,16 @@ sub student_gradeStatus { sub jscriptNform { my ($symb) = @_; my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status')); - my $jscript=''."\n"; + "\n"); $jscript.= '
'."\n". ''."\n". ''."\n". - ''."\n". ''."\n". ''."\n". ''."\n". @@ -705,7 +670,7 @@ sub most_similar { # ignore empty submissions (occuring when only files are sent) - unless ($uessay=~/\w+/) { return ''; } + unless ($uessay=~/\w+/s) { return ''; } # these will be returned. Do not care if not at least 50 percent similar my $limit=0.6; @@ -742,22 +707,31 @@ sub most_similar { #------------------------------------ Receipt Verification Routines # + +sub initialverifyreceipt { + my ($request,$symb) = @_; + &commonJSfunctions($request); + return ''. + &Apache::lonnet::recprefix($env{'request.course.id'}). + '-'. + ''."\n". + ''. + "
\n"; +} + #--- Check whether a receipt number is valid.--- sub verifyreceipt { - my $request = shift; + my ($request,$symb) = @_; my $courseid = $env{'request.course.id'}; my $receipt = &Apache::lonnet::recprefix($courseid).'-'. $env{'form.receipt'}; $receipt =~ s/[^\-\d]//g; - my ($symb) = &get_symb($request); my $title.= '

'. - &mt('Verifying Receipt No. [_1]',$receipt). - '

'."\n". - '

'.&mt('Resource: [_1]',$env{'form.probTitle'}). - '

'."\n"; + &mt('Verifying Receipt Number [_1]',$receipt). + ''."\n"; my ($string,$contents,$matches) = ('','',0); my (undef,undef,$fullname) = &getclasslist('all','0'); @@ -766,7 +740,13 @@ sub verifyreceipt { if ($env{"course.$courseid.receiptalg"} eq 'receipt2' || $env{"course.$courseid.receiptalg"} eq 'receipt3') { $receiptparts=1; } my $parts=['0']; - if ($receiptparts) { ($parts)=&response_type($symb); } + if ($receiptparts) { + my $res_error; + ($parts)=&response_type($symb,\$res_error); + if ($res_error) { + return &navmap_errormsg(); + } + } my $header = &Apache::loncommon::start_data_table(). @@ -808,11 +788,14 @@ sub verifyreceipt { } } if ($matches == 0) { - $string = $title.&mt('No match found for the above receipt.'); + $string = $title + .'

' + .&mt('No match found for the above receipt number.') + .'

'; } else { $string = &jscriptNform($symb).$title. '

'. - &mt('The above receipt matches the following [numerate,_1,student].',$matches). + &mt('The above receipt number matches the following [quant,_1,student].',$matches). '

'. $header. $contents. @@ -826,30 +809,28 @@ sub verifyreceipt { #--- Also called directly when one clicks on the subm button # on the problem page. sub listStudents { - my ($request) = shift; + my ($request,$symb) = @_; - my ($symb) = &get_symb($request); my $cdom = $env{"course.$env{'request.course.id'}.domain"}; my $cnum = $env{"course.$env{'request.course.id'}.num"}; my $getsec = $env{'form.section'} eq '' ? 'all' : $env{'form.section'}; my $getgroup = $env{'form.group'} eq '' ? 'all' : $env{'form.group'}; my $submitonly= $env{'form.submitonly'} eq '' ? 'all' : $env{'form.submitonly'}; my $viewgrade = $env{'form.showgrading'} eq 'yes' ? 'View/Grade/Regrade' : 'View'; - $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? - &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'}; my $result='

 ' .&mt("$viewgrade Submissions for a Student or a Group of Students") .'

'; - my ($table,undef,$hdgrade,$partlist,$handgrade) = &showResourceInfo($symb,$env{'form.probTitle'},($env{'form.showgrading'} eq 'yes')); + my ($partlist,$handgrade,$responseType) = &response_type($symb +#,$res_error + ); my %lt = &Apache::lonlocal::texthash ( 'multiple' => 'Please select a student or group of students before clicking on the Next button.', 'single' => 'Please select the student before clicking on the Next button.', ); - $request->print(< + $request->print(&Apache::lonhtmlcommon::scripttag(< LISTJAVASCRIPT &commonJSfunctions($request); @@ -887,7 +867,7 @@ LISTJAVASCRIPT my $checkhdgrade = ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1 ) ? 'checked="checked"' : ''; my $checklastsub = $checkhdgrade eq '' ? 'checked="checked"' : ''; my $gradeTable='
'. - "\n".$table; + "\n"; $gradeTable .= &Apache::lonhtmlcommon::start_pick_box(); $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('View Problem Text')) @@ -910,10 +890,18 @@ LISTJAVASCRIPT my $saveStatus = $stu_status eq '' ? 'Active' : $stu_status; $env{'form.Status'} = $saveStatus; $submission_options.= - ''."\n". - ''."\n". - ''."\n". - ''; + ''. + ''."\n". + ''. + ''."\n". + ''. + ''."\n". + ''. + ''; $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Submissions')) .$submission_options .&Apache::lonhtmlcommon::row_closure(); @@ -933,7 +921,6 @@ LISTJAVASCRIPT '
'."\n". '
'."\n". ''."\n". - ''."\n". ''."\n". ''."\n"; @@ -959,8 +946,8 @@ LISTJAVASCRIPT # checkall buttons $gradeTable.=&check_script('gradesub', 'stuinfo'); $gradeTable.='
'."\n"; + 'onclick="javascript:checkSelect(this.form.stuinfo);" '."\n". + 'value="'.&mt('Next').' →" />
'."\n"; $gradeTable.=&check_buttons(); my ($classlist, undef, $fullname) = &getclasslist($getsec,'1',$getgroup); $gradeTable.= &Apache::loncommon::start_data_table(). @@ -1077,9 +1064,9 @@ LISTJAVASCRIPT } $gradeTable.=&Apache::loncommon::end_data_table()."\n". - '
'."\n"; + ''."\n"; if ($ctr == 0) { my $num_students=(scalar(keys(%$fullname))); if ($num_students eq 0) { @@ -1106,7 +1093,7 @@ LISTJAVASCRIPT sub check_script { my ($form, $type)=@_; - my $chkallscript=''."\n"; +'."\n"); return $chkallscript; } @@ -1176,8 +1163,7 @@ sub processGroup { sub sub_page_js { my $request = shift; my $alertmsg = &mt('A number equal or greater than 0 is expected. Entered value = '); - $request->print(< + $request->print(&Apache::lonhtmlcommon::scripttag(< SUBJAVASCRIPT } @@ -1355,8 +1340,7 @@ sub sub_page_kw_js { my $iconpath = $request->dir_config('lonIconsURL'); &commonJSfunctions($request); - my $inner_js_msg_central=< + my $inner_js_msg_central= &Apache::lonhtmlcommon::scripttag(< INNERJS - my $inner_js_highlight_central=< + my $inner_js_highlight_central= &Apache::lonhtmlcommon::scripttag(< INNERJS my $start_page_msg_central = @@ -1432,8 +1413,7 @@ INNERJS my $docopen=&Apache::lonhtmlcommon::javascript_docopen(); $docopen=~s/^document\.//; my $alertmsg = &mt('Please select a word or group of words from document and then click this link.'); - $request->print(< + $request->print(&Apache::lonhtmlcommon::scripttag(<"); pDoc.write("<\\/td><\\/tr><\\/table> "); - pDoc.write("  "); - pDoc.write("

"); + pDoc.write("  "); + pDoc.write("

"); pDoc.write("<\\/form>"); pDoc.write('$end_page_msg_central'); pDoc.close(); @@ -1657,14 +1637,13 @@ INNERJS var hDoc = hwdWin.document; hDoc.write("<\\/table>"); hDoc.write("<\\/td><\\/tr><\\/table> "); - hDoc.write("  "); - hDoc.write("

"); + hDoc.write("  "); + hDoc.write("

"); hDoc.write("<\\/form>"); hDoc.write('$end_page_highlight_central'); hDoc.close(); } - SUBJAVASCRIPT } @@ -1677,6 +1656,25 @@ sub get_increment { return $increment; } +sub gradeBox_start { + return ( + &Apache::loncommon::start_data_table() + .&Apache::loncommon::start_data_table_header_row() + .''.&mt('Part').'' + .''.&mt('Points').'' + .' ' + .''.&mt('Assign Grade').'' + .''.&mt('Weight').'' + .''.&mt('Grade Status').'' + .&Apache::loncommon::end_data_table_header_row() + ); +} + +sub gradeBox_end { + return ( + &Apache::loncommon::end_data_table() + ); +} #--- displays the grading box, used in essay type problem and grading by page/sequence sub gradeBox { my ($request,$symb,$uname,$udom,$counter,$partid,$record) = @_; @@ -1696,7 +1694,7 @@ sub gradeBox { if ($last_resets{$partid}) { $aggtries = &get_num_tries($record,$last_resets{$partid},$partid); } - $result.=''; + $result.=&Apache::loncommon::start_data_table_row(); my $ctr = 0; my $thisweight = 0; my $increment = &get_increment(); @@ -1704,7 +1702,7 @@ sub gradeBox { my $radio.='
'."\n"; # display radio buttons in a nice table 10 across while ($thisweight<=$wgt) { $radio.= '\n"; $radio.=(($ctr+1)%10 == 0 ? '' : ''); @@ -1715,13 +1713,13 @@ sub gradeBox { my $line.=''."\n"; $line.=''."\n"; + $line.='',$display_part,$radio,$line); $result .= - ''. - - $result.='
/'.$wgt.' '.$wgtmsg. ($$record{'resource.'.$partid.'.solved'} eq 'correct_by_student' ? ' '.$checkIcon : ''). - ' '.&mt('Grade Status').':'."\n"; - $line.=''."\n"; - #&mt('Part:[_1]Points:[_2]or[_3]'.&mt('Part').':'.$display_part.''.&mt('Points').':'.$radio.''.&mt('or').''.$line.'
'."\n"; + ''.$display_part.''.$radio.''.&mt('or').''.$line.''; + $result.=&Apache::loncommon::end_data_table_row(); $result.=''."\n". ''."\n". ''."\n". ''."\n"; - $result.=&handback_box($symb,$uname,$udom,$counter,$partid,$record); + my $res_error; + $result.=&handback_box($symb,$uname,$udom,$counter,$partid,$record,\$res_error); + if ($res_error) { + return &navmap_errormsg(); + } return $result; } sub handback_box { - my ($symb,$uname,$udom,$counter,$partid,$record) = @_; - my ($partlist,$handgrade,$responseType) = &response_type($symb); + my ($symb,$uname,$udom,$counter,$partid,$record,$res_error) = @_; + my ($partlist,$handgrade,$responseType) = &response_type($symb,$res_error); my (@respids); my @part_response_id = &flatten_responseType($responseType); foreach my $part_response_id (@part_response_id) { @@ -1813,26 +1813,23 @@ sub show_problem { $companswer=~s|name="submit"|name="would_have_been_submit"|g; } $rendered= - '
'. - &mt('View of the problem'). - '
'. - $rendered. - '
'; + '
' + .'

'.&mt('View of the problem').'

' + .$rendered + .'
'; $companswer= - '
'. - &mt('Correct answer'). - '
'. - $companswer. - '
'; + '
' + .'

'.&mt('Correct answer').'

' + .$companswer + .'
'; my $result; if ($mode eq 'both') { - $result=$rendered.$companswer; + $result=$rendered.$companswer; } elsif ($mode eq 'text') { - $result=$rendered; + $result=$rendered; } elsif ($mode eq 'answer') { - $result=$companswer; + $result=$companswer; } - $result='
'.$result.'
'; return $result; } @@ -1888,12 +1885,13 @@ sub build_section_inputs { # --------------------------- show submissions of a student, option to grade sub submission { - my ($request,$counter,$total) = @_; + my ($request,$counter,$total,$symb) = @_; my ($uname,$udom) = ($env{'form.student'},$env{'form.userdom'}); $udom = ($udom eq '' ? $env{'user.domain'} : $udom); #has form.userdom changed for a student? my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'}); $env{'form.fullname'} = &Apache::loncommon::plainname($uname,$udom,'lastname') if $env{'form.fullname'} eq ''; - my $symb = &get_symb($request); + + my $probtitle=&Apache::lonnet::gettitle($symb); if ($symb eq '') { $request->print("Unable to handle ambiguous references:."); return ''; } if (!&canview($usec)) { @@ -1917,13 +1915,10 @@ sub submission { if ($counter == 0) { &sub_page_js($request); &sub_page_kw_js($request) if ($env{'form.handgrade'} eq 'yes'); - $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? - &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'}; if ($env{'form.handgrade'} eq 'yes' && &files_exist($request, $symb)) { &download_all_link($request, $symb); } - $request->print('

 '.&mt('Submission Record').'

'."\n". - '

 '.&mt('Resource: [_1]',$env{'form.probTitle'}).'

'."\n"); + $request->print('

 '.&mt('Submission Record').'

'); # option to display problem, only once else it cause problems # with the form later since the problem has a form. @@ -1954,7 +1949,7 @@ sub submission { $env{'form.kwsize'} = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0'; $env{'form.kwstyle'} = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : ''; $env{'form.msgsub'} = $keyhash{$symb.'_subject'} ne '' ? - $keyhash{$symb.'_subject'} : $env{'form.probTitle'}; + $keyhash{$symb.'_subject'} : $probtitle; $env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0'; } my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'}; @@ -1964,7 +1959,6 @@ sub submission { ''."\n". ''."\n". ''."\n". - ''."\n". ''."\n". ''."\n". ''."\n". @@ -2010,7 +2004,7 @@ sub submission { $request->print(<Keyword Options:  List    -Paste Selection to List    Highlight Attribute

KEYWORDS @@ -2026,12 +2020,31 @@ KEYWORDS } # This is where output for one specific student would start - my $add_class = ($counter%2) ? 'LC_grade_show_user_odd_row' : ''; - $request->print("\n\n". - '
'. - '
'.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).'
'. - '
'."\n"); + my $add_class = ($counter%2) ? ' LC_grade_show_user_odd_row' : ''; + $request->print( + "\n\n" + .'
' + .'

'.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).'

' + ."\n" + ); + + # Show additional functions if allowed + if ($perm{'vgr'}) { + $request->print( + &Apache::loncommon::track_student_link( + &mt('View recent activity'), + $uname,$udom,'check') + .' ' + ); + } + if ($perm{'opa'}) { + $request->print( + &Apache::loncommon::pprmlink( + &mt('Set/Change parameters'), + $uname,$udom,$symb,'check')); + } + # Show Problem if ($env{'form.vProb'} eq 'all' or $env{'form.vAns'} eq 'all') { my $mode; if ($env{'form.vProb'} eq 'all' && $env{'form.vAns'} eq 'all') { @@ -2046,24 +2059,26 @@ KEYWORDS } my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname); - my ($partlist,$handgrade,$responseType) = &response_type($symb); + my $res_error; + my ($partlist,$handgrade,$responseType) = &response_type($symb,\$res_error); + if ($res_error) { + $request->print(&navmap_errormsg()); + return; + } # Display student info $request->print(($counter == 0 ? '' : '
')); - my $result='
'; - - $result.='
'; - $result.= &mt('Submissions'); + + my $result='
' + .'

'.&mt('Submissions').'

'; $result.=''."\n"; + '" value="'.$env{'form.fullname'}.'" />'."\n"; if ($env{'form.handgrade'} eq 'no') { - $result.=''. - &mt('Part(s) graded correct by the computer is marked with a [_1] symbol.',$checkIcon)."\n"; - + $result.='

' + .&mt('Part(s) graded correct by the computer is marked with a [_1] symbol.',$checkIcon) + ."

\n"; } - - # If any part of the problem is an essay-response (handgraded), then check for collaborators my $fullname; my $col_fullnames = []; @@ -2074,9 +2089,9 @@ KEYWORDS $result.=$sub_result; } $request->print($result."\n"); - $request->print('
'."\n"); + # print student answer/submission - # Options are (1) Handgaded submission only + # Options are (1) Handgraded submission only # (2) Last submission, includes submission that is not handgraded # (for multi-response type part) # (3) Last submission plus the parts info @@ -2086,10 +2101,12 @@ KEYWORDS my $lastsubonly; - if ($$timestamp eq '') { - $lastsubonly.='
'.$$string[0].'
'; - } else { - $lastsubonly = '
Date Submitted: '.$$timestamp."\n"; + if ($$timestamp eq '') { + $lastsubonly.='
'.$$string[0].'
'; + } else { + $lastsubonly = + '
' + .''.&mt('Date Submitted:').' '.$$timestamp."\n"; my %seenparts; my @part_response_id = &flatten_responseType($responseType); @@ -2113,16 +2130,18 @@ KEYWORDS } my $responsetype = $responseType->{$partid}->{$respid}; if (!exists($record{"resource.$partid.$respid.submission"})) { - $lastsubonly.="\n".'
Part: '. - $display_part.' ( ID '.$respid. - ' )   '. + $lastsubonly.="\n".'
'. + ''.&mt('Part: [_1]',$display_part).''. + ' '. + '('.&mt('Part ID: [_1]',$respid).')'. + '   '. ''.&mt('Nothing submitted - no attempts.').'

'; next; } foreach my $submission (@$string) { my ($partid,$respid) = ($submission =~ /^resource\.([^\.]*)\.([^\.]*)\.submission/); if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; } - my ($ressub,$subval) = split(/:/,$submission,2); + my ($ressub,$hide,$subval) = split(/:/,$submission,3); # Similarity check my $similar=''; if($env{'form.checkPlag'}){ @@ -2134,17 +2153,21 @@ KEYWORDS &Apache::lonnet::coursedescription($ocrsid, {'one_time' => 1}); - $similar="

". - &mt('Essay is [_1]% similar to an essay by [_2] ([_3]:[_4]) in course [_5] (course id [_6]:[_7])', - $osim, - &Apache::loncommon::plainname($oname,$odom), - $oname,$odom, - $old_course_desc{'description'}, - $old_course_desc{'num'}, - $old_course_desc{'domain'}). - '

'. - &keywords_highlight($oessay). - '

'; + if ($hide) { + $similar='
'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'
'. + &mt('As the current submission is for an anonymous survey, no other details are available.').'

'; + } else { + $similar="

". + &mt('Essay is [_1]% similar to an essay by [_2] in course [_3] (course id [_4]:[_5])', + $osim, + &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')', + $old_course_desc{'description'}, + $old_course_desc{'num'}, + $old_course_desc{'domain'}). + '

'. + &keywords_highlight($oessay). + '

'; + } } } my $order=&get_order($partid,$respid,$symb,$uname,$udom); @@ -2152,33 +2175,43 @@ KEYWORDS ($env{'form.lastSub'} eq 'hdgrade' && $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) { my $display_part=&get_display_part($partid,$symb); - $lastsubonly.='
Part: '. - $display_part.' ( ID '.$respid. - ' )   '; + $lastsubonly.='
'. + ''.&mt('Part: [_1]',$display_part).''. + ' '. + '('.&mt('Part ID: [_1]',$respid).')'. + '   '; my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record); if (@$files) { - $lastsubonly.='
'.&mt('Like all files provided by users, this file may contain viruses').'
'; - my $file_counter = 0; - foreach my $file (@$files) { - $file_counter++; - &Apache::lonnet::allowuploaded('/adm/grades',$file); - $lastsubonly.='
'.$file.''; - } + if ($hide) { + $lastsubonly.='
'.&mt('[quant,_1,file] uploaded to this anonymous survey',scalar(@{$files})); + } else { + $lastsubonly.='
'.&mt('Like all files provided by users, this file may contain viruses').'
'; + foreach my $file (@$files) { + &Apache::lonnet::allowuploaded('/adm/grades',$file); + $lastsubonly.='
'.$file.''; + } + } $lastsubonly.='
'; } - $lastsubonly.=''.&mt('Submitted Answer:').' '. - &cleanRecord($subval,$responsetype,$symb,$partid, - $respid,\%record,$order,undef,$uname,$udom); + if ($hide) { + $lastsubonly.=''.&mt('Anonymous Survey').''; + } else { + $lastsubonly.=''.&mt('Submitted Answer:').' '. + &cleanRecord($subval,$responsetype,$symb,$partid, + $respid,\%record,$order,undef,$uname,$udom); + } if ($similar) {$lastsubonly.="

$similar\n";} $lastsubonly.='
'; } } } - $lastsubonly.='
'."\n"; + $lastsubonly.='
'."\n"; # End: LC_grade_submissions_body } $request->print($lastsubonly); } elsif ($env{'form.lastSub'} eq 'datesub') { - my (undef,$responseType,undef,$parts) = &showResourceInfo($symb); +# my (undef,$responseType,undef,$parts) = &showResourceInfo($symb); + my ($parts,$handgrade,$responseType) = &response_type($symb); + $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom)); } elsif ($env{'form.lastSub'} =~ /^(last|all)$/) { $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom, @@ -2192,7 +2225,7 @@ KEYWORDS # return if view submission with no grading option if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) { my $toGrade.='  '."\n" if (&canmodify($usec)); $toGrade.='
'."\n"; if (($env{'form.command'} eq 'submission') || @@ -2236,11 +2269,11 @@ KEYWORDS my @partlist; my @gradePartRespid; my @part_response_id = &flatten_responseType($responseType); - $request->print('
'. - - '
'. - &mt('Assign Grades').'
'. - '
'); + $request->print( + '
' + .'

'.&mt('Assign Grades').'

' + ); + $request->print(&gradeBox_start()); foreach my $part_response_id (@part_response_id) { my ($partid,$respid) = @{ $part_response_id }; my $part_resp = join('_',@{ $part_response_id }); @@ -2252,19 +2285,10 @@ KEYWORDS push(@gradePartRespid,$partid.'.'.$respid); $request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record)); } - $request->print('
'); + $request->print(&gradeBox_end()); #
+ $request->print('
'); $request->print(''); $result=''."\n"; + my $endform='

'."\n"; $endform.='  '."\n"; my $ntstu =''."\n"; my $nsel = ($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : '1'); $ntstu =~ s/
'; @@ -2371,7 +2396,7 @@ sub check_collaborators { #--- Retrieve the last submission for all the parts sub get_last_submission { my ($returnhash)=@_; - my (@string,$timestamp); + my (@string,$timestamp,%lasthidden); if ($$returnhash{'version'}) { my %lasthash=(); my ($version); @@ -2383,13 +2408,39 @@ sub get_last_submission { &Apache::lonlocal::locallocaltime($$returnhash{$version.':timestamp'}); } } + my %typeparts; + my $showsurv = + &Apache::lonnet::allowed('vas',$env{'request.course.id'}); + foreach my $key (sort(keys(%lasthash))) { + if ($key =~ /\.type$/) { + if (($lasthash{$key} eq 'anonsurvey') || + ($lasthash{$key} eq 'anonsurveycred')) { + my ($ign,@parts) = split(/\./,$key); + pop(@parts); + unless ($showsurv) { + my $id = join(',',@parts); + $typeparts{$ign.'.'.$id} = $lasthash{$key}; + } + delete($lasthash{$key}); + } + } + } + my @hidden = keys(%typeparts); foreach my $key (keys(%lasthash)) { next if ($key !~ /\.submission$/); - + my $hide; + if (@hidden) { + foreach my $id (@hidden) { + if ($key =~ /^\Q$id\E/) { + $hide = 1; + last; + } + } + } my ($partid,$foo) = split(/submission$/,$key); my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ? 'Draft Copy ' : ''; - push(@string, join(':', $key, $draft.$lasthash{$key})); + push(@string, join(':', $key, $hide, $draft.$lasthash{$key})); } } if (!@string) { @@ -2414,8 +2465,7 @@ sub keywords_highlight { #--- Called from submission routine sub processHandGrade { - my ($request) = shift; - my $symb = &get_symb($request); + my ($request,$symb) = @_; my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb); my $button = $env{'form.gradeOpt'}; my $ngrade = $env{'form.NCT'}; @@ -2455,7 +2505,7 @@ sub processHandGrade { if ($env{'form.withgrades'.$ctr}) { $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt; $messagetail = " for $env{'form.probTitle'}"; + $feedurl."?symb=$showsymb\">$restitle"; } $msgstatus = &Apache::lonmsg::user_normal_msg($uname,$udom,$subject, @@ -2463,7 +2513,7 @@ sub processHandGrade { undef,$feedurl,undef, undef,undef,$showsymb, $restitle); - $request->print('
'.&mt('Sending message to [_1]:[_2]',$uname,$udom).': '. + $request->print('
'.&mt('Sending message to [_1]',$uname.':'.$udom).': '. $msgstatus); } if ($env{'form.collaborator'.$ctr}) { @@ -2483,7 +2533,7 @@ sub processHandGrade { $udom); if ($env{'form.withgrades'.$ctr}) { $messagetail = " for $env{'form.probTitle'}"; + $baseurl."?symb=$showsymb\">$restitle"; } $msgstatus = &Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message.$messagetail,undef,$baseurl,undef,undef,undef,$showsymb,$restitle); @@ -2556,7 +2606,7 @@ sub processHandGrade { # Go directly to grade student - from submission or link from chart page if ($button eq 'Grade Student') { - (undef,undef,$env{'form.handgrade'},undef,undef) = &showResourceInfo($symb); +# (undef,undef,$env{'form.handgrade'},undef,undef) = &showResourceInfo($symb); my $processUser = $env{'form.unamedom'.$env{'form.studentNo'}}; ($env{'form.student'},$env{'form.userdom'}) = split(/:/,$processUser); $env{'form.fullname'} = $$fullname{$processUser}; @@ -2583,6 +2633,7 @@ 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); } @@ -2593,8 +2644,14 @@ sub processHandGrade { } } $ctr = 0; +# FIXME: this is fishy, looks like the button label @parsedlist = reverse @parsedlist if ($button eq 'Previous'); - my ($partlist) = &response_type($symb); + 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); @@ -2792,8 +2849,12 @@ sub check_and_remove_from_queue { sub handback_files { my ($request,$symb,$stuname,$domain,$newflg,$new_part,$newrecord) = @_; my $portfolio_root = '/userfiles/portfolio'; - my ($partlist,$handgrade,$responseType) = &response_type($symb); - + my $res_error; + my ($partlist,$handgrade,$responseType) = &response_type($symb,\$res_error); + if ($res_error) { + $request->print('
'.&navmap_errormsg().'
'); + return; + } my @part_response_id = &flatten_responseType($responseType); foreach my $part_response_id (@part_response_id) { my ($part_id,$resp_id) = @{ $part_response_id }; @@ -3041,8 +3102,7 @@ sub viewgrades_js { my ($request) = shift; my $alertmsg = &mt('A number equal or greater than 0 is expected. Entered value = '); - $request->print(< + $request->print(&Apache::lonhtmlcommon::scripttag(< VIEWJAVASCRIPT } #--- show scores for a section or whole class w/ option to change/update a score sub viewgrades { - my ($request) = shift; + my ($request,$symb) = @_; &viewgrades_js($request); - my ($symb) = &get_symb($request); #need to make sure we have the correct data for later EXT calls, #thus invalidate the cache &Apache::lonnet::devalidatecourseresdata( @@ -3221,7 +3279,6 @@ sub viewgrades { &Apache::lonnet::clear_EXT_cache_status(); my $result='

'.&mt('Manual Grading').'

'; - $result.='

'.&mt('Current Resource: [_1]',$env{'form.probTitle'}).'

'."\n"; #view individual student submission form - called using Javascript viewOneStudent $result.=&jscriptNform($symb); @@ -3234,7 +3291,6 @@ sub viewgrades { &build_section_inputs(). ''."\n". ''."\n". - ''."\n"; my ($common_header,$specific_header); if ($env{'form.section'} eq 'all') { @@ -3251,7 +3307,11 @@ sub viewgrades { $result.= '

'.$common_header.'

'.&Apache::loncommon::start_data_table(); #radio buttons/text box for assigning points for a section or class. #handles different parts of a problem - my ($partlist,$handgrade,$responseType) = &response_type($symb); + my $res_error; + my ($partlist,$handgrade,$responseType) = &response_type($symb,\$res_error); + if ($res_error) { + return &navmap_errormsg(); + } my %weight = (); my $ctsparts = 0; my %seen = (); @@ -3277,11 +3337,11 @@ sub viewgrades { } $radio.=''; my $line = ' /'. $weight{$partid}.' '.&mt('(problem weight)').''."\n"; $line.= ''.&mt('Grade Status').':'; $result.=''; + 'onclick="javascript:resetEntry('.$ctsparts.');" />'; #table listing all the students in a section/class #header of table @@ -3311,7 +3371,11 @@ sub viewgrades { &Apache::loncommon::start_data_table_header_row(). ''.&mt('No.').''. ''.&nameUserString('header')."\n"; - my (@parts) = sort(&getpartlist($symb)); + my $partserror; + my (@parts) = sort(&getpartlist($symb,\$partserror)); + if ($partserror) { + return &navmap_errormsg(); + } my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb); my @partids = (); foreach my $part (@parts) { @@ -3362,7 +3426,7 @@ sub viewgrades { $result.=&Apache::loncommon::end_data_table(); $result.=''."\n"; $result.=''."\n"; + 'onclick="javascript:submit();" target="_self" />'."\n"; if (scalar(%$fullname) eq 0) { my $colspan=3+scalar(@parts); my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section')); @@ -3414,7 +3478,7 @@ sub viewstudentgrade { 'GD_'.$student.'_'.$part.'_awarded_s" value="'.$pts.'" />'."\n"; $result.=''."\n"; } elsif ($type eq 'solved') { my ($status,$foo)=split(/_/,$score,2); @@ -3423,7 +3487,7 @@ sub viewstudentgrade { $part.'_solved_s" value="'.$status.'" />'."\n"; $result.='  + @@ -3790,20 +3857,23 @@ to this page if the data selected is ins value="$env{'form.upfile_associate'}" /> -
- ENDPICK + $request->print(&Apache::lonhtmlcommon::scripttag($javascript)); return ''; } sub csvupload_fields { - my ($symb) = @_; - my (@parts) = &getpartlist($symb); + my ($symb,$errorref) = @_; + my (@parts) = &getpartlist($symb,$errorref); + if (ref($errorref)) { + if ($$errorref) { + return; + } + } + my @fields=(['ID','Student/Employee ID'], ['username','Student Username'], ['domain','Student Domain']); @@ -3828,15 +3898,14 @@ sub csvuploadmap_footer { -
+
ENDPICK } sub checkforfile_js { my $alertmsg = &mt('Please use the browse button to select a file from your local directory.'); - my $result =< + my $result = &Apache::lonhtmlcommon::scripttag(< CSVFORMJS return $result; } sub upcsvScores_form { - my ($request) = shift; - my ($symb)=&get_symb($request); + my ($request,$symb) = @_; if (!$symb) {return '';} my $result=&checkforfile_js(); - $env{'form.probTitle'} = &Apache::lonnet::gettitle($symb); - my ($table) = &showResourceInfo($symb,$env{'form.probTitle'}); - $result.=$table; $result.='
'."\n"; $result.=''. @@ -4393,11 +4471,13 @@ sub displayPage { } if (&canmodify($usec)) { + $studentTable.=&gradeBox_start(); foreach my $partid (@{$parts}) { $studentTable.=&gradeBox($request,$symbx,$uname,$udom,$question,$partid,\%record); $studentTable.=''."\n"; $question++; } + $studentTable.=&gradeBox_end(); $prob++; } $studentTable.=''; @@ -4406,10 +4486,11 @@ sub displayPage { $curRes = $iterator->next(); } - $studentTable.='
'."\n"; $result.=' '.&mt('Specify a file containing the class scores for current resource.'). @@ -3870,10 +3934,9 @@ sub upcsvScores_form {
- $upfile_select -
+
ENDUPFORM @@ -3887,8 +3950,7 @@ ENDUPFORM sub csvuploadmap { - my ($request)= @_; - my ($symb)=&get_symb($request); + my ($request,$symb)= @_; if (!$symb) {return '';} my $datatoken; @@ -3903,8 +3965,12 @@ sub csvuploadmap { &csvuploadmap_header($request,$symb,$datatoken,$#records+1); my ($i,$keyfields); if (@records) { - my @fields=&csvupload_fields($symb); - + my $fieldserror; + my @fields=&csvupload_fields($symb,\$fieldserror); + if ($fieldserror) { + $request->print(&navmap_errormsg()); + return; + } if ($env{'form.upfile_associate'} eq 'reverse') { &Apache::loncommon::csv_print_samples($request,\@records); $i=&Apache::loncommon::csv_print_select_table($request,\@records, @@ -3931,8 +3997,7 @@ sub csvuploadmap { } sub csvuploadoptions { - my ($request)= @_; - my ($symb)=&get_symb($request); + my ($request,$symb)= @_; my $checked=(($env{'form.noFirstLine'})?'1':'0'); my $ignore=&mt('Ignore First Line'); $request->print(<print('
'.&mt("Saved [_1] students",$countdone)."\n"); + $request->print('
'.&Apache::lonhtmlcommon::confirm_success(&mt("Saved scores for [quant,_1,student]",$countdone),$countdone==0)); if (@skipped) { - $request->print('

'.&mt('Skipped Students').'

'); - foreach my $student (@skipped) { $request->print("$student
\n"); } + $request->print('
'.&Apache::lonhtmlcommon::confirm_success(&mt('No scores stored for the following username(s):'),1).'
'); + $request->print(join(', ',@skipped)); } if (@notallowed) { - $request->print('

'.&mt('Students Not Allowed to Modify').'

'); - foreach my $student (@notallowed) { $request->print("$student
\n"); } + $request->print('
'.&Apache::lonhtmlcommon::confirm_success(&mt('Modification of scores not allowed for the following username(s):'),1).'
'); + $request->print(join(', ',@notallowed)); } $request->print("
\n"); $request->print(&show_grading_menu_form($symb)); @@ -4111,11 +4175,10 @@ sub csvuploadassign { # #--- Select a page/sequence and a student to grade sub pickStudentPage { - my ($request) = shift; + my ($request,$symb) = @_; my $alertmsg = &mt('Please select the student you wish to grade.'); - $request->print(< + $request->print(&Apache::lonhtmlcommon::scripttag(< LISTJAVASCRIPT &commonJSfunctions($request); - my ($symb) = &get_symb($request); + my $cdom = $env{"course.$env{'request.course.id'}.domain"}; my $cnum = $env{"course.$env{'request.course.id'}.num"}; my $getsec = $env{'form.section'} eq '' ? 'all' : $env{'form.section'}; @@ -4140,7 +4202,12 @@ LISTJAVASCRIPT &mt('Manual Grading by Page or Sequence').''; $result.='
'."\n"; - my ($titles,$symbx) = &getSymbMap(); + my $map_error; + my ($titles,$symbx) = &getSymbMap($map_error); + if ($map_error) { + $request->print(&navmap_errormsg()); + return; + } my ($curpage) =&Apache::lonnet::decode_symb($symb); # my ($curpage,$mapId) =&Apache::lonnet::decode_symb($symb); # my $type=($curpage =~ /\.(page|sequence)/); @@ -4187,7 +4254,7 @@ LISTJAVASCRIPT $result.=' '.&mt('Use CODE').':
'."\n"; $result.=' 
'."\n"; + 'onclick="javascript:checkPickOne(this.form);" value="'.&mt('Next').' →" />
'."\n"; $request->print($result); @@ -4226,7 +4293,7 @@ LISTJAVASCRIPT } $studentTable.=&Apache::loncommon::end_data_table()."\n"; $studentTable.='
'."\n"; + 'onclick="javascript:checkPickOne(this.form);" value="'.&mt('Next').' →" />'."\n"; $studentTable.=&show_grading_menu_form($symb); $request->print($studentTable); @@ -4235,8 +4302,14 @@ LISTJAVASCRIPT } sub getSymbMap { + my ($map_error) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); - + unless (ref($navmap)) { + if (ref($map_error)) { + $$map_error = 'navmap'; + } + return; + } my %symbx = (); my @titles = (); my $minder = 0; @@ -4259,9 +4332,7 @@ sub getSymbMap { # #--- Displays a page/sequence w/wo problems, w/wo submissions sub displayPage { - my ($request) = shift; - - my ($symb) = &get_symb($request); + my ($request,$symb) = @_; my $cdom = $env{"course.$env{'request.course.id'}.domain"}; my $cnum = $env{"course.$env{'request.course.id'}.num"}; my $getsec = $env{'form.section'} eq '' ? 'all' : $env{'form.section'}; @@ -4295,6 +4366,11 @@ sub displayPage { $request->print($result); my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + $request->print(&navmap_errormsg()); + $request->print(&show_grading_menu_form($symb)); + return; + } my ($mapUrl, $id, $resUrl)=&Apache::lonnet::decode_symb($env{'form.page'}); my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps if (!$map) { @@ -4322,7 +4398,9 @@ sub displayPage { my $checkIcon = ''.&mt('Check Mark').
 	''; - $studentTable.=' '.&mt('Note: Problems graded correct by the computer are marked with a [_1] symbol.',$checkIcon)."\n". + $studentTable.=' '. + &mt('Problems graded correct by the computer are marked with a [_1] symbol.',$checkIcon). + ''."\n". &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). '
 Prob. 
'."\n". - ''. - ''."\n"; + $studentTable.= + '
'."\n". + ''. + ''."\n"; $studentTable.=&show_grading_menu_form($symb); $request->print($studentTable); @@ -4455,37 +4536,49 @@ sub displaySubByDates { my @versionKeys = split(/\:/,$$record{$version.':keys'}); my @displaySub = (); foreach my $partid (@{$parts}) { + my $hidden; + if (($$record{$version.':resource.'.$partid.'.type'} eq 'anonsurvey') || + ($$record{$version.':resource.'.$partid.'.type'} eq 'anonsurveycred')) { + $hidden = 1; + } my @matchKey = ($isTask ? sort(grep /^resource\.\d+\.\Q$partid\E\.award$/,@versionKeys) : sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys)); - # next if ($$record{"$version:resource.$partid.solved"} eq ''); my $display_part=&get_display_part($partid,$symb); foreach my $matchKey (@matchKey) { if (exists($$record{$version.':'.$matchKey}) && $$record{$version.':'.$matchKey} ne '') { - + my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/) : ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/)); - $displaySub[0].=''.&mt('Part:').' '.$display_part.' '; - $displaySub[0].='('.&mt('ID').' '. - $responseId.') '; - if ($$record{"$where.$partid.tries"} eq '') { - $displaySub[0].=&mt('Trial not counted'); - } else { - $displaySub[0].=&mt('Trial [_1]', + $displaySub[0].='' + .' ' + .'('.&mt('Part ID: [_1]',$responseId).')' + .'' + .' '; + if ($hidden) { + $displaySub[0].= &mt('Anonymous Survey').''; + } else { + if ($$record{"$where.$partid.tries"} eq '') { + $displaySub[0].=&mt('Trial not counted'); + } else { + $displaySub[0].=&mt('Trial: [_1]', $$record{"$where.$partid.tries"}); - } - my $responseType=($isTask ? 'Task' + } + my $responseType=($isTask ? 'Task' : $responseType->{$partid}->{$responseId}); - if (!exists($orders{$partid})) { $orders{$partid}={}; } - if (!exists($orders{$partid}->{$responseId})) { - $orders{$partid}->{$responseId}= - &get_order($partid,$responseId,$symb,$uname,$udom, - $no_increment); - } - $displaySub[0].='  '. - &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom).'
'; + if (!exists($orders{$partid})) { $orders{$partid}={}; } + if (!exists($orders{$partid}->{$responseId})) { + $orders{$partid}->{$responseId}= + &get_order($partid,$responseId,$symb,$uname,$udom, + $no_increment); + } + $displaySub[0].=''; # /nobreak + $displaySub[0].='  '. + &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom).'
'; + } } } if (exists($$record{"$where.$partid.checkedin"})) { @@ -4525,7 +4618,7 @@ sub displaySubByDates { } sub updateGradeByPage { - my ($request) = shift; + my ($request,$symb) = @_; my $cdom = $env{"course.$env{'request.course.id'}.domain"}; my $cnum = $env{"course.$env{'request.course.id'}.num"}; @@ -4545,12 +4638,16 @@ sub updateGradeByPage { $request->print($result); + my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + $request->print(&navmap_errormsg()); + return; + } my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'}); my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps if (!$map) { $request->print(''.&mt('Unable to grade requested sequence ([_1]).',$resUrl).''); - my ($symb)=&get_symb($request); $request->print(&show_grading_menu_form($symb)); return; } @@ -4690,7 +4787,7 @@ sub updateGradeByPage { # #------------------------------------------------------------------- -#--------------------Scantron Grading----------------------------------- +#-------------------- Bubblesheet (Scantron) Grading ------------------- # #------ start of section for handling grading by page/sequence --------- @@ -4756,8 +4853,7 @@ the homework problem. sub defaultFormData { my ($symb)=@_; return ''."\n". - ''."\n". - ''."\n"; + ''; } @@ -4768,14 +4864,19 @@ sub defaultFormData { Return html dropdown of possible sequences to grade Arguments: - $symb - $symb of the current resource + $symb - $symb of the current resource + $map_error - ref to scalar which will container error if + $navmap object is unavailable in &getSymbMap(). =cut sub getSequenceDropDown { - my ($symb)=@_; + my ($symb,$map_error)=@_; my $result=' + + + '.&mt('File to upload: [_1]','').' +
+ + +'); + + $r->print(' + + '.&Apache::loncommon::end_data_table_row().' + '.&Apache::loncommon::end_data_table().' +'); + } + # Chunk of form to prompt for a file to grade and how: $result.= ' @@ -5069,10 +5220,10 @@ sub scantron_selectphase { '.&mt('Sequence to grade:').' '.$sequence_selector.' '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::start_data_table_row().' - '.&mt('Filename of scoring office file:').' '.$file_selector.' + '.&mt('Filename of bubblesheet data file:').' '.$file_selector.' '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::start_data_table_row().' - '.&mt('Format of data file:').' '.$format_selector.' + '.&mt('Format of bubblesheet data file:').' '.$format_selector.' '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::start_data_table_row().' '.&mt('Saved CODEs to validate against:').' '.$CODE_selector.' @@ -5090,7 +5241,7 @@ sub scantron_selectphase { '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::start_data_table_row().' - + '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::end_data_table().' @@ -5099,53 +5250,7 @@ sub scantron_selectphase { $r->print($result); - if (&Apache::lonnet::allowed('usc',$env{'request.role.domain'}) || - &Apache::lonnet::allowed('usc',$env{'request.course.id'})) { - # Chunk of form to prompt for a scantron file upload. - - $r->print(' -
- '.&Apache::loncommon::start_data_table('LC_scantron_action').' - '.&Apache::loncommon::start_data_table_header_row().' - -  '.&mt('Specify a Scantron data file to upload.').' - - '.&Apache::loncommon::end_data_table_header_row().' - '.&Apache::loncommon::start_data_table_row().' - -'); - my $default_form_data=&defaultFormData(&get_symb($r,1)); - my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'}; - $r->print(' - - -
- '.$default_form_data.' - - - - '.&mt('File to upload: [_1]','').' -
- -
-'); - - $r->print(' - - '.&Apache::loncommon::end_data_table_row().' - '.&Apache::loncommon::end_data_table().' -'); - } # Chunk of the form that prompts to view a scoring office file, # corrected file, skipped records in a file. @@ -5178,7 +5283,7 @@ sub scantron_selectphase { &Apache::loncommon::start_data_table('LC_scantron_action')."\n". &Apache::loncommon::start_data_table_header_row()."\n". ' -  '.&mt('Review scantron data and submissions for a previously graded folder/sequence')."\n". +  '.&mt('Review bubblesheet data and submissions for a previously graded folder/sequence')."\n". ''."\n". &Apache::loncommon::end_data_table_header_row()."\n". &Apache::loncommon::start_data_table_row()."\n". @@ -5200,7 +5305,7 @@ sub scantron_selectphase { &Apache::loncommon::start_data_table_row()."\n". ''."\n". ''."\n". - ''."\n". + ''."\n". ''."\n". &Apache::loncommon::end_data_table_row()."\n". &Apache::loncommon::end_data_table()."\n". @@ -5241,7 +5346,7 @@ sub scantron_selectphase { CODEstart - (only matter if a CODE exists) column in the line where the CODE starts CODElength - length of the CODE - IDstart - column where the student/employee ID number starts + IDstart - column where the student/employee ID starts IDlength - length of the student/employee ID info Qstart - column where the information from the bubbled 'questions' start @@ -5341,7 +5446,7 @@ sub username_to_idmap { $whichline - line number of the passed in scanline $field - type of change to process (either - 'ID' -> correct the student/employee ID number + 'ID' -> correct the student/employee ID 'CODE' -> correct the CODE 'answer' -> fixup the submitted answers) @@ -6105,8 +6210,7 @@ sub scantron_warning_screen { =cut sub scantron_do_warning { - my ($r)=@_; - my ($symb)=&get_symb($r); + my ($r,$symb)=@_; if (!$symb) {return '';} my $default_form_data=&defaultFormData($symb); $r->print(&scantron_form_start().$default_form_data); @@ -6187,8 +6291,7 @@ SCANTRONFORM =cut sub scantron_validate_file { - my ($r) = @_; - my ($symb)=&get_symb($r); + my ($r,$symb) = @_; if (!$symb) {return '';} my $default_form_data=&defaultFormData($symb); @@ -6215,7 +6318,12 @@ sub scantron_validate_file { $r->print('

'.&mt('Gathering necessary information.').'

');$r->rflush(); #get the student pick code ready $r->print(&Apache::loncommon::studentbrowser_javascript()); - my $max_bubble=&scantron_get_maxbubble(); + my $nav_error; + my $max_bubble=&scantron_get_maxbubble(\$nav_error); + if ($nav_error) { + $r->print(&navmap_errormsg()); + return ''; + } my $result=&scantron_form_start($max_bubble).$default_form_data; $r->print($result); @@ -6251,7 +6359,7 @@ sub scantron_validate_file { ''.&mt('No'). '
'. &mt('Grading will take longer if you use verification.').'
'. - &mt("Alternatively, the 'Review scantron data' utility (see grading menu) can be used for all students after grading is complete.").'

'. + &mt("Alternatively, the 'Review bubblesheet data' utility (see grading menu) can be used for all students after grading is complete.").'

'. ''. ''."\n"); } else { @@ -6627,6 +6735,10 @@ sub scantron_validate_sequence { my ($r,$currentphase) = @_; my $navmap=Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + $r->print(&navmap_errormsg()); + return (1,$currentphase); + } my (undef,undef,$sequence)= &Apache::lonnet::decode_symb($env{'form.selectpage'}); @@ -6658,8 +6770,13 @@ sub scantron_validate_ID { #get scantron line setup my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); - - &scantron_get_maxbubble(); # parse needs the bubble_lines.. array. + + my $nav_error; + &scantron_get_maxbubble(\$nav_error); # parse needs the bubble_lines.. array. + if ($nav_error) { + $r->print(&navmap_errormsg()); + return(1,$currentphase); + } my %found=('ids'=>{},'usernames'=>{}); for (my $i=0;$i<=$scanlines->{'count'};$i++) { @@ -6777,10 +6894,10 @@ sub scantron_get_correction { if ($closest > 0) { foreach my $testcode (@{$closest}) { my $checked=''; - if (!$i) { $checked=' checked="checked" '; } + if (!$i) { $checked=' checked="checked"'; } $r->print(" @@ -6791,18 +6908,17 @@ sub scantron_get_correction { } } if ($$scan_record{'scantron.CODE'}=~/\S/ ) { - my $checked; if (!$i) { $checked=' checked="checked" '; } + my $checked; if (!$i) { $checked=' checked="checked"'; } $r->print(" "); $r->print("\n
"); } - $r->print(< + $r->print(&Apache::lonhtmlcommon::scripttag(< ENDSCRIPT my $href="/adm/pickcode?". "form=".&escape("scantronupload"). @@ -6882,8 +6997,7 @@ sub verify_bubbles_checked { my (@ansnums) = @_; my $ansnumstr = join('","',@ansnums); my $warning = &mt("A bubble or 'No bubble' selection has not been made for one or more lines."); - my $output = (< + my $output = &Apache::lonhtmlcommon::scripttag((< ENDSCRIPT return $output; } @@ -7018,7 +7131,7 @@ sub prompt_for_corrections { ($responsetype_per_response{$question-1} eq 'imageresponse') || ($responsetype_per_response{$question-1} eq 'reactionresponse') || ($responsetype_per_response{$question-1} eq 'organicresponse')) { - $r->print(&mt("Although this particular question type requires handgrading, the instructions for this question in the exam directed students to leave [quant,_1,line] blank on their scantron sheets.",$lines).'

'.&mt('A non-zero score can be assigned to the student during scantron grading by selecting a bubble in at least one line.').'
'.&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.').'
'.&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.").'

'); + $r->print(&mt("Although this particular question type requires handgrading, the instructions for this question in the exam directed students to leave [quant,_1,line] blank on their bubblesheets.",$lines).'

'.&mt('A non-zero score can be assigned to the student during bubblesheet grading by selecting a bubble in at least one line.').'
'.&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.').'
'.&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.").'

'); } else { $r->print(&mt("Select at most one bubble in a single line and select 'No Bubble' in all the other lines. ")."
"); } @@ -7212,7 +7325,12 @@ sub scantron_validate_CODE { my %allcodes=&get_codes(); - &scantron_get_maxbubble(); # parse needs the lines per response array. + my $nav_error; + &scantron_get_maxbubble(\$nav_error); # parse needs the lines per response array. + if ($nav_error) { + $r->print(&navmap_errormsg()); + return(1,$currentphase); + } my ($scanlines,$scan_data)=&scantron_getfile(); for (my $i=0;$i<=$scanlines->{'count'};$i++) { @@ -7266,7 +7384,12 @@ sub scantron_validate_doublebubble { #get scantron line setup my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); - &scantron_get_maxbubble(); # parse needs the bubble line array. + my $nav_error; + &scantron_get_maxbubble(\$nav_error); # parse needs the bubble line array. + if ($nav_error) { + $r->print(&navmap_errormsg()); + return(1,$currentphase); + } for (my $i=0;$i<=$scanlines->{'count'};$i++) { my $line=&scantron_get_line($scanlines,$scan_data,$i); @@ -7284,6 +7407,7 @@ sub scantron_validate_doublebubble { sub scantron_get_maxbubble { + my ($nav_error) = @_; if (defined($env{'form.scantron_maxbubble'}) && $env{'form.scantron_maxbubble'}) { &restore_bubble_lines(); @@ -7294,6 +7418,12 @@ sub scantron_get_maxbubble { &Apache::lonnet::decode_symb($env{'form.selectpage'}); my $navmap=Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + if (ref($nav_error)) { + $$nav_error = 1; + } + return; + } my $map=$navmap->getResourceByUrl($sequence); my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); @@ -7383,7 +7513,11 @@ sub scantron_validate_missingbubbles { #get scantron line setup my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); - my $max_bubble=&scantron_get_maxbubble(); + my $nav_error; + my $max_bubble=&scantron_get_maxbubble(\$nav_error); + if ($nav_error) { + return(1,$currentphase); + } if (!$max_bubble) { $max_bubble=2**31; } for (my $i=0;$i<=$scanlines->{'count'};$i++) { my $line=&scantron_get_line($scanlines,$scan_data,$i); @@ -7429,10 +7563,9 @@ sub scantron_validate_missingbubbles { sub scantron_process_students { - my ($r) = @_; + my ($r,$symb) = @_; my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'}); - my ($symb)=&get_symb($r); if (!$symb) { return ''; } @@ -7443,13 +7576,24 @@ sub scantron_process_students { my $classlist=&Apache::loncoursedata::get_classlist(); my %idmap=&username_to_idmap($classlist); my $navmap=Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + $r->print(&navmap_errormsg()); + return ''; + } my $map=$navmap->getResourceByUrl($sequence); my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); my (%grader_partids_by_symb,%grader_randomlists_by_symb); &graders_resources_pass(\@resources,\%grader_partids_by_symb, \%grader_randomlists_by_symb); + my $resource_error; foreach my $resource (@resources) { - my $ressymb = $resource->symb(); + my $ressymb; + if (ref($resource)) { + $ressymb = $resource->symb(); + } else { + $resource_error = 1; + last; + } my ($analysis,$parts) = &scantron_partids_tograde($resource,$env{'request.course.id'}, $env{'user.name'},$env{'user.domain'},1); @@ -7461,6 +7605,10 @@ sub scantron_process_students { } } } + if ($resource_error) { + $r->print(&navmap_errormsg()); + return ''; + } my ($uname,$udom); my $result= <print(&navmap_errormsg()); + return ''; + } # If an ssi failed in scantron_get_maxbubble, put an error message out to # the user and return. @@ -7526,9 +7679,15 @@ SCANTRONFORM } ($uname,$udom)=split(/:/,$uname); - my %partids_by_symb; + my (%partids_by_symb,$res_error); foreach my $resource (@resources) { - my $ressymb = $resource->symb(); + my $ressymb; + if (ref($resource)) { + $ressymb = $resource->symb(); + } else { + $res_error = 1; + last; + } if ((exists($grader_randomlists_by_symb{$ressymb})) || (ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) { my ($analysis,$parts) = @@ -7539,6 +7698,12 @@ SCANTRONFORM } } + if ($res_error) { + &scantron_add_delay(\@delayqueue,$line, + 'An error occurred while grading student '.$uname,2); + next; + } + &Apache::lonxml::clear_problem_counter(); &Apache::lonnet::appenv($scan_record); @@ -7700,7 +7865,7 @@ sub grade_student_bubbles { } sub scantron_upload_scantron_data { - my ($r)=@_; + my ($r,$symb)=@_; my $dom = $env{'request.role.domain'}; my $domdesc = &Apache::lonnet::domain($dom,'description'); $r->print(&Apache::loncommon::coursebrowser_javascript($dom)); @@ -7709,16 +7874,17 @@ sub scantron_upload_scantron_data { 'coursename',$dom); my $syllabuslink = ''.&mt('Syllabus').''. (' 'x2).&mt('(shows course personnel)'); - my $default_form_data=&defaultFormData(&get_symb($r,1)); - $r->print(' - - +')); + $r->print('

'.&mt('Send scanned bubblesheet data to a course').'

@@ -7760,7 +7926,7 @@ sub scantron_upload_scantron_data { &Apache::lonhtmlcommon::end_pick_box().'
- +
'); return ''; @@ -7768,8 +7934,7 @@ sub scantron_upload_scantron_data { sub scantron_upload_scantron_data_save { - my($r)=@_; - my ($symb)=&get_symb($r,1); + my($r,$symb)=@_; my $doanotherupload= '
'."\n". ''."\n". @@ -7778,7 +7943,7 @@ sub scantron_upload_scantron_data_save { if (!&Apache::lonnet::allowed('usc',$env{'form.domainid'}) && !&Apache::lonnet::allowed('usc', $env{'form.domainid'}.'_'.$env{'form.courseid'})) { - $r->print(&mt("You are not allowed to upload Scantron data to the requested course.")."
"); + $r->print(&mt("You are not allowed to upload bubblesheet data to the requested course.")."
"); if ($symb) { $r->print(&show_grading_menu_form($symb)); } else { @@ -7787,37 +7952,25 @@ sub scantron_upload_scantron_data_save { return ''; } my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'}); + my $uploadedfile; $r->print('

'.&mt("Uploading file to [_1]",$coursedata{'description'}).'

'); - my $fname=$env{'form.upfile.filename'}; - #FIXME - #copied from lonnet::userfileupload() - #make that function able to target a specified course - # Replace Windows backslashes by forward slashes - $fname=~s/\\/\//g; - # Get rid of everything but the actual filename - $fname=~s/^.*\/([^\/]+)$/$1/; - # Replace spaces by underscores - $fname=~s/\s+/\_/g; - # Replace all other weird characters by nothing - $fname=~s/[^\w\.\-]//g; - # See if there is anything left - unless ($fname) { return 'error: no uploaded file'; } - my $uploadedfile=$fname; - $fname='scantron_orig_'.$fname; if (length($env{'form.upfile'}) < 2) { - $r->print(&mt("Error: The file you attempted to upload, [_1] contained no information. Please check that you entered the correct filename.",''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')."")); + $r->print(&mt('[_1]Error:[_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.','','',''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'')); } else { - my $result=&Apache::lonnet::finishuserfileupload($env{'form.courseid'},$env{'form.domainid'},'upfile',$fname); - if ($result =~ m|^/uploaded/|) { + my $result = + &Apache::lonnet::userfileupload('upfile','','scantron','','','', + $env{'form.courseid'},$env{'form.domainid'}); + if ($result =~ m{^/uploaded/}) { $r->print(&mt('[_1]Success:[_2] Successfully uploaded [_3] bytes of data into location: [_4]', '','',(length($env{'form.upfile'})-1), ''.$result.'')); + ($uploadedfile) = ($result =~ m{/([^/]+)$}); $r->print(&validate_uploaded_scantron_file($env{'form.domainid'}, - $env{'form.courseid'},$fname)); + $env{'form.courseid'},$uploadedfile)); } else { $r->print(&mt('[_1]Error:[_2] An error ([_3]) occurred when attempting to upload the file, [_4]', '','',$result, - ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')."")); + ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'')); } } if ($symb) { @@ -7923,8 +8076,8 @@ sub valid_file { } sub scantron_download_scantron_data { - my ($r)=@_; - my $default_form_data=&defaultFormData(&get_symb($r,1)); + my ($r,$symb)=@_; + my $default_form_data=&defaultFormData($symb); my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; my $file=$env{'form.scantron_selectfile'}; @@ -7934,7 +8087,7 @@ sub scantron_download_scantron_data { '.&mt('The requested file name was invalid.').'

'); - $r->print(&show_grading_menu_form(&get_symb($r,1))); + $r->print(&show_grading_menu_form($symb)); return; } my $orig='/uploaded/'.$cdom.'/'.$cname.'/scantron_orig_'.$file; @@ -7957,13 +8110,12 @@ sub scantron_download_scantron_data { '','').'

'); - $r->print(&show_grading_menu_form(&get_symb($r,1))); + $r->print(&show_grading_menu_form($symb)); return ''; } sub checkscantron_results { - my ($r) = @_; - my ($symb)=&get_symb($r); + my ($r,$symb) = @_; if (!$symb) {return '';} my $grading_menu_button=&show_grading_menu_form($symb); my $cid = $env{'request.course.id'}; @@ -7979,6 +8131,10 @@ sub checkscantron_results { my $classlist=&Apache::loncoursedata::get_classlist(); my %idmap=&Apache::grades::username_to_idmap($classlist); my $navmap=Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + $r->print(&navmap_errormsg()); + return ''; + } my $map=$navmap->getResourceByUrl($sequence); my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); my (%grader_partids_by_symb,%grader_randomlists_by_symb); @@ -7993,12 +8149,16 @@ sub checkscantron_results { my %completedstudents; my $count=&Apache::grades::get_todo_count($scanlines,$scan_data); - my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Scantron/Submissions Comparison Status', - 'Progress of Scantron Data/Submission Records Comparison',$count, + my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Bubblesheet/Submissions Comparison Status', + 'Progress of Bubblesheet Data/Submission Records Comparison',$count, 'inline',undef,'checkscantron'); my ($username,$domain,$started); - - &scantron_get_maxbubble(); # Need the bubble lines array to parse. + my $nav_error; + &scantron_get_maxbubble(\$nav_error); # Need the bubble lines array to parse. + if ($nav_error) { + $r->print(&navmap_errormsg()); + return ''; + } &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state, 'Processing first student'); @@ -8071,14 +8231,14 @@ sub checkscantron_results { if ($scandata{$pid} eq $record{$pid}) { my $css_class = ($passed % 2)?'LC_odd_row':'LC_even_row'; $okstudents .= ''. -''.&mt('Scantron').''.$showscandata.''.$last.''.$pid.''."\n". +''.&mt('Bubblesheet').''.$showscandata.''.$last.''.$pid.''."\n". ''."\n". ''."\n". 'Submissions'.$showrecord.''."\n"; $passed ++; } else { my $css_class = ($failed % 2)?'LC_odd_row':'LC_even_row'; - $badstudents .= ''.&mt('Scantron').''.$scandata{$pid}.''.$last.''.$pid.''."\n". + $badstudents .= ''.&mt('Bubblesheet').''.$scandata{$pid}.''.$last.''.$pid.''."\n". ''."\n". ''."\n". 'Submissions'.$record{$pid}.''."\n". @@ -8089,10 +8249,10 @@ sub checkscantron_results { } } } - $r->print('

'.&mt('Comparison of scantron data (including corrections) with corresponding submission records (most recent submission) for [quant,_1,student] ([_2] scantron lines/student).',$numstudents,$env{'form.scantron_maxbubble'}).'

'); + $r->print('

'.&mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [quant,_1,student] ([_2] scantron lines/student).',$numstudents,$env{'form.scantron_maxbubble'}).'

'); $r->print('

'.&mt('Exact matches for [quant,_1,student].',$passed).'
'.&mt('Discrepancies detected for [quant,_1,student].',$failed).'

'); if ($passed) { - $r->print(&mt('Students with exact correspondence between scantron data and submissions are as follows:').'

'); + $r->print(&mt('Students with exact correspondence between bubblesheet data and submissions are as follows:').'

'); $r->print(&Apache::loncommon::start_data_table()."\n". &Apache::loncommon::start_data_table_header_row()."\n". ''.&mt('Source').''.&mt('Bubble records').''.&mt('Name').''.&mt('ID').''. @@ -8101,14 +8261,14 @@ sub checkscantron_results { &Apache::loncommon::end_data_table().'
'); } if ($failed) { - $r->print(&mt('Students with differences between scantron data and submissions are as follows:').'

'); + $r->print(&mt('Students with differences between bubblesheet data and submissions are as follows:').'

'); $r->print(&Apache::loncommon::start_data_table()."\n". &Apache::loncommon::start_data_table_header_row()."\n". ''.&mt('Source').''.&mt('Bubble records').''.&mt('Name').''.&mt('ID').''. &Apache::loncommon::end_data_table_header_row()."\n". $badstudents."\n". &Apache::loncommon::end_data_table()).'
'. - &mt('Differences can occur if submissions were modified using manual grading after a scantron grading pass.').'
'.&mt('If unexpected discrepancies were detected, it is recommended that you inspect the original scantron sheets.'); + &mt('Differences can occur if submissions were modified using manual grading after a bubblesheet grading pass.').'
'.&mt('If unexpected discrepancies were detected, it is recommended that you inspect the original bubblesheets.'); } $r->print('

'.$grading_menu_button); return; @@ -8264,36 +8424,26 @@ sub show_grading_menu_form { return $result; } -# -- Retrieve choices for grading form -sub savedState { - my %savedState = (); - if ($env{'form.saveState'}) { - foreach (split(/:/,$env{'form.saveState'})) { - my ($key,$value) = split(/=/,$_,2); - $savedState{$key} = $value; - } - } - return \%savedState; -} - sub grading_menu { - my ($request) = @_; - my ($symb)=&get_symb($request); + my ($request,$symb) = @_; if (!$symb) {return '';} - my $probTitle = &Apache::lonnet::gettitle($symb); - my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle); - $request->print($table); my %fields = ('symb'=>&Apache::lonenc::check_encrypt($symb), - 'handgrade'=>$hdgrade, - 'probTitle'=>$probTitle, - 'command'=>'submit_options', - 'saveState'=>"", + 'command'=>'individual', 'gradingMenu'=>1, 'showgrading'=>"yes"); - my $url1 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - + my $url1a = &Apache::lonhtmlcommon::build_url('grades/',\%fields); + + $fields{'command'}='ungraded'; + my $url1b=&Apache::lonhtmlcommon::build_url('grades/',\%fields); + + $fields{'command'}='table'; + my $url1c=&Apache::lonhtmlcommon::build_url('grades/',\%fields); + + $fields{'command'}='all_for_one'; + my $url1d=&Apache::lonhtmlcommon::build_url('grades/',\%fields); + $fields{'command'} = 'csvform'; my $url2 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); @@ -8302,15 +8452,40 @@ sub grading_menu { $fields{'command'} = 'scantron_selectphase'; my $url4 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); + + $fields{'command'} = 'initialverifyreceipt'; + my $url5 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - my @menu = ({ categorytitle=>'Course Grading', + my @menu = ({ categorytitle=>'Hand Grading', items =>[ - { linktext => 'Manual Grading/View Submissions', - url => $url1, + { linktext => 'Select individual students to grade', + url => $url1a, permission => 'F', icon => 'edit-find-replace.png', - linktitle => 'Start the process of hand grading submissions.' + linktitle => 'Grade current resource for a selection of students.' + }, + { linktext => 'Grade ungraded submissions.', + url => $url1b, + permission => 'F', + icon => 'edit-find-replace.png', + linktitle => 'Grade all submissions that have not been graded yet.' }, + + { linktext => 'Grading table', + url => $url1c, + permission => 'F', + icon => 'edit-find-replace.png', + linktitle => 'Grade current resource for all students.' + }, + { linktext => 'Grade complete page/sequence/folder for one student', + url => $url1d, + permission => 'F', + icon => 'edit-find-replace.png', + linktitle => 'Grade all resources in current page/sequence/folder for one student.' + }]}, + { categorytitle=>'Automated Grading', + items =>[ + { linktext => 'Upload Scores', url => $url2, permission => 'F', @@ -8323,171 +8498,131 @@ sub grading_menu { icon => 'addClickerInfoFile.png', linktitle => 'Specify a file containing the clicker information for this resource.' }, - { linktext => 'Grade/Manage/Review Scantron Forms', + { linktext => 'Grade/Manage/Review Bubblesheets', url => $url4, permission => 'F', icon => 'stat.png', linktitle => 'Grade scantron exams, upload/download scantron data files, and review previously graded scantron exams.' - } + }, + { linktext => 'Verify Receipt No.', + url => $url5, + permission => 'F', + icon => 'edit-find-replace.png', + linktitle => 'Verify a system-generated receipt number for correct problem solution.' + } + ] }); - #$fields{'command'} = 'verify'; - #$url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - # # Create the menu my $Str; - # $Str .= '

'.&mt('Please select a grading task').'

'; $Str .= '
'; $Str .= ''. ''."\n". - ''."\n". - ''."\n". - ''."\n". ''."\n". ''."\n"; - $Str .= Apache::lonhtmlcommon::generate_menu(@menu); - #$menudata->{'jscript'} - $Str .='
'. - &Apache::lonnet::recprefix($env{'request.course.id'}). - '-'; + $Str .= &Apache::lonhtmlcommon::generate_menu(@menu); + return $Str; +} - $Str .="
\n"; - my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box."); - $request->print(< - function checkChoice(formname,val,cmdx) { - if (val <= 2) { - var cmd = radioSelection(formname.radioChoice); - var cmdsave = cmd; - } else { - cmd = cmdx; - cmdsave = 'submission'; - } - formname.command.value = cmd; - if (val < 5) formname.submit(); - if (val == 5) { - if (!checkReceiptNo(formname,'notOK')) { - return false; - } else { - formname.submit(); - } - } - } - function checkReceiptNo(formname,nospace) { - var receiptNo = formname.receipt.value; - var checkOpt = false; - if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;} - if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;} - if (checkOpt) { - alert("$receiptalert"); - formname.receipt.value = ""; - formname.receipt.focus(); - return false; - } - return true; - } - -GRADINGMENUJS +sub ungraded { + my ($request)=@_; + &submit_options($request); +} + +sub submit_options_sequence { + my ($request,$symb) = @_; + if (!$symb) {return '';} &commonJSfunctions($request); - return $Str; + my $result; + + $result.='
'."\n". + ''."\n". + ''."\n". + ''."\n"; + + $result.=' +

+ '.&mt('Grade complete page/sequence/folder for one student').' +

'. + &selectfield(0). + ' +
+ +
+
+ '; + $result .= &show_grading_menu_form($symb); + return $result; } +sub submit_options_table { + my ($request,$symb) = @_; + if (!$symb) {return '';} + &commonJSfunctions($request); + my $result; + + $result.='
'."\n". + ''."\n". + ''."\n". + ''."\n"; + + $result.=' +

+ '.&mt('Grading table').' +

'. + &selectfield(0). + ' +
+ +
+
+ '; + $result .= &show_grading_menu_form($symb); + return $result; +} + + #--- Displays the submissions first page ------- sub submit_options { - my ($request) = @_; - my ($symb)=&get_symb($request); + my ($request,$symb) = @_; if (!$symb) {return '';} - my $probTitle = &Apache::lonnet::gettitle($symb); - my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box."); - $request->print(< - function checkChoice(formname,val,cmdx) { - if (val <= 2) { - var cmd = radioSelection(formname.radioChoice); - var cmdsave = cmd; - } else { - cmd = cmdx; - cmdsave = 'submission'; - } - formname.command.value = cmd; - formname.saveState.value = "saveCmd="+cmdsave+":saveSec="+pullDownSelection(formname.section)+ - ":saveSub="+pullDownSelection(formname.submitonly)+":saveStatus="+pullDownSelection(formname.Status); - if (val < 5) formname.submit(); - if (val == 5) { - if (!checkReceiptNo(formname,'notOK')) { return false;} - formname.submit(); - } - if (val < 7) formname.submit(); - } - - function checkReceiptNo(formname,nospace) { - var receiptNo = formname.receipt.value; - var checkOpt = false; - if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;} - if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;} - if (checkOpt) { - alert("$receiptalert"); - formname.receipt.value = ""; - formname.receipt.focus(); - return false; - } - return true; - } - -GRADINGMENUJS &commonJSfunctions($request); - my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle); my $result; - my (undef,$sections) = &getclasslist('all','0'); - my $savedState = &savedState(); - my $saveCmd = ($$savedState{'saveCmd'} eq '' ? 'submission' : $$savedState{'saveCmd'}); - my $saveSec = ($$savedState{'saveSec'} eq '' ? 'all' : $$savedState{'saveSec'}); - my $saveSub = ($$savedState{'saveSub'} eq '' ? 'all' : $$savedState{'saveSub'}); - my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'}); - - # Preselect sections - my $selsec=""; - if (ref($sections)) { - foreach my $section (sort(@$sections)) { - $selsec.=''."\n"; - } - } $result.='
'."\n". ''."\n". - ''."\n". - ''."\n". - ''."\n". - ''."\n". ''."\n". ''."\n"; $result.='

- '.&mt('Grade Current Resource').' -

-
- '.$table.' -
+ '.&mt('Select individual students to grade').' +'.&selectfield(1).' + + +
+
+ -
+ '; + $result .= &show_grading_menu_form($symb); + return $result; +} + +sub selectfield { + my ($full)=@_; + my $result='
'.&mt('Sections').' -   '; - $result.=' + '.&Apache::lonstatistics::SectionSelect('section','multiple',5).'
@@ -8501,63 +8636,25 @@ GRADINGMENUJS '.&mt('Access Status').' - '.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,5,undef,'mult').' -
- + '.&Apache::lonhtmlcommon::StatusOptions(undef,undef,5,undef,'mult').' + '; + if ($full) { + $result.='
'.&mt('Submission Status').' - - -
- -
- -
-
-
- -
-
- -
-
- -
-
- - -

- '.&mt('Grade Complete Folder for One Student').' -

-
-
- -
-
- -
-
- '; - $result .= &show_grading_menu_form($symb); + '. + &Apache::loncommon::select_form('all','submitonly', + (&Apache::lonlocal::texthash( + 'yes' => 'with submissions', + 'queued' => 'in grading queue', + 'graded' => 'with ungraded submissions', + 'incorrect' => 'with incorrect submissions', + 'all' => 'with any status'), + 'select_form_order' => ['yes','queued','graded','incorrect','all'])). + ''; + } + $result.='

'; return $result; } @@ -8645,18 +8742,14 @@ sub clicker_grading_parameters { } sub process_clicker { - my ($r)=@_; - my ($symb)=&get_symb($r); + my ($r,$symb)=@_; if (!$symb) {return '';} my $result=&checkforfile_js(); - $env{'form.probTitle'} = &Apache::lonnet::gettitle($symb); - my ($table) = &showResourceInfo($symb,$env{'form.probTitle'}); - $result.=$table; $result.='
'."\n"; $result.=''."\n"; - $result.='
'."\n"; $result.=' '.&mt('Specify a file containing the clicker information for this resource.'). '
'."\n"; + $result.='
'."\n"; # Attempt to restore parameters from last session, set defaults if not present my %Saveable_Parameters=&clicker_grading_parameters(); &Apache::loncommon::restore_course_settings('grades_clicker', @@ -8669,7 +8762,7 @@ sub process_clicker { my %checked; foreach my $gradingmechanism ('attendance','personnel','specific','given') { if ($env{'form.gradingmechanism'} eq $gradingmechanism) { - $checked{$gradingmechanism}="checked='checked'"; + $checked{$gradingmechanism}=' checked="checked"'; } } @@ -8686,8 +8779,7 @@ sub process_clicker { ('iclicker' => 'i>clicker', 'interwrite' => 'interwrite PRS')); $symb = &Apache::lonenc::check_encrypt($symb); - $result.=< + $result.= &Apache::lonhtmlcommon::scripttag(< +ENDUPFORM + $result.= < -
-
-
-
+
+
+
-
+

    -
-
-
- +
+
+
+' ENDUPFORM $result.='
'."\n". '


'."\n"; @@ -8753,15 +8845,13 @@ ENDUPFORM } sub process_clicker_file { - my ($r)=@_; - my ($symb)=&get_symb($r); + my ($r,$symb)=@_; if (!$symb) {return '';} my %Saveable_Parameters=&clicker_grading_parameters(); &Apache::loncommon::store_course_settings('grades_clicker', \%Saveable_Parameters); - - my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); + my $result=''; if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) { $result.=''.&mt('You need to specify a clicker ID for the correct answer').''; return $result.&show_grading_menu_form($symb); @@ -8838,7 +8928,6 @@ sub process_clicker_file {
- @@ -8988,15 +9077,18 @@ sub interwrite_eval { } sub assign_clicker_grades { - my ($r)=@_; - my ($symb)=&get_symb($r); + my ($r,$symb)=@_; if (!$symb) {return '';} # See which part we are saving to - my ($partlist,$handgrade,$responseType) = &response_type($symb); + my $res_error; + my ($partlist,$handgrade,$responseType) = &response_type($symb,\$res_error); + if ($res_error) { + return &navmap_errormsg(); + } # FIXME: This should probably look for the first handgradeable part my $part=$$partlist[0]; # Start screen output - my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); + my $result=''; my $heading=&mt('Assigning grades based on clicker file'); $result.=(<'. + &mt('An error occurred retrieving information about resources in the course.').'
'. + &mt('It is recommended that you [_1]re-initialize the course[_2] and then return to this grading page.','',''). + '
'; +} + +sub startpage { + my ($r,$symb,$crumbs,$onlyfolderflag) = @_; + unshift(@$crumbs,{href=>"/adm/grades?command=gradingmenu&symb=".&HTML::Entities::encode($symb,'<>&"'),text=>"Grading"}); + $r->print(&Apache::loncommon::start_page('Grading',undef, + {'bread_crumbs' => $crumbs})); + $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag)); +} + sub handler { my $request=$_[0]; &reset_caches(); @@ -9107,7 +9214,9 @@ sub handler { $request->send_http_header; return '' if $request->header_only; &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}); - my $symb=&get_symb($request,1); + +# see what command we need to execute + my @commands=&Apache::loncommon::get_env_multiple('form.command'); my $command=$commands[0]; @@ -9115,107 +9224,133 @@ sub handler { &Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands)); } +# see what the symb is + + my $symb=$env{'form.symb'}; + unless ($symb) { + (my $url=$env{'form.url'}) =~ s-^https*://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--; + $symb=&Apache::lonnet::symbread($url); + } + &Apache::lonenc::check_decrypt(\$symb); + $ssi_error = 0; - my $brcrum = [{href=>"/adm/grades",text=>"Grading"}]; - $request->print(&Apache::loncommon::start_page('Grading',undef, - {'bread_crumbs' => $brcrum})); if ($symb eq '' && $command eq '') { - if ($env{'user.adv'}) { - if (($env{'form.codeone'}) && ($env{'form.codetwo'}) && - ($env{'form.codethree'})) { - my $token=$env{'form.codeone'}.'*'.$env{'form.codetwo'}.'*'. - $env{'form.codethree'}; - my ($tsymb,$tuname,$tudom,$tcrsid)= - &Apache::lonnet::checkin($token); - if ($tsymb) { - my ($map,$id,$url)=&Apache::lonnet::decode_symb($tsymb); - if (&Apache::lonnet::allowed('mgr',$tcrsid)) { - $request->print(&ssi_with_retries('/res/'.$url, $ssi_retries, - ('grade_username' => $tuname, - 'grade_domain' => $tudom, - 'grade_courseid' => $tcrsid, - 'grade_symb' => $tsymb))); - } else { - $request->print('

Not authorized: '.$token.'

'); - } - } else { - $request->print('

Not a valid DocID: '.$token.'

'); - } - } else { - $request->print(&Apache::lonxml::tokeninputfield()); - } - } +# +# Not called from a resource +# + } else { &init_perm(); if ($command eq 'submission' && $perm{'vgr'}) { - ($env{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0)); + &startpage($request,$symb,[{href=>"", text=>"Student Submissions"}]); + ($env{'form.student'} eq '' ? &listStudents($request,$symb) : &submission($request,0,0,$symb)); } elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) { - &pickStudentPage($request); + &startpage($request,$symb); + &pickStudentPage($request,$symb); } elsif ($command eq 'displayPage' && $perm{'vgr'}) { - &displayPage($request); + &startpage($request,$symb); + &displayPage($request,$symb); } elsif ($command eq 'gradeByPage' && $perm{'mgr'}) { - &updateGradeByPage($request); + &startpage($request,$symb); + &updateGradeByPage($request,$symb); } elsif ($command eq 'processGroup' && $perm{'vgr'}) { - &processGroup($request); + &startpage($request,$symb); + &processGroup($request,$symb); } elsif ($command eq 'gradingmenu' && $perm{'vgr'}) { - $request->print(&grading_menu($request)); - } elsif ($command eq 'submit_options' && $perm{'vgr'}) { - $request->print(&submit_options($request)); + &startpage($request,$symb); + $request->print(&grading_menu($request,$symb)); + } elsif ($command eq 'individual' && $perm{'vgr'}) { + &startpage($request,$symb); + $request->print(&submit_options($request,$symb)); + } elsif ($command eq 'ungraded' && $perm{'vgr'}) { + &startpage($request,$symb); + $request->print(&submit_options($request,$symb)); + } elsif ($command eq 'table' && $perm{'vgr'}) { + &startpage($request,$symb); + $request->print(&submit_options_table($request,$symb)); + } elsif ($command eq 'all_for_one' && $perm{'vgr'}) { + &startpage($request,$symb); + $request->print(&submit_options_sequence($request,$symb)); } elsif ($command eq 'viewgrades' && $perm{'vgr'}) { - $request->print(&viewgrades($request)); + &startpage($request,$symb); + $request->print(&viewgrades($request,$symb)); } elsif ($command eq 'handgrade' && $perm{'mgr'}) { - $request->print(&processHandGrade($request)); + &startpage($request,$symb); + $request->print(&processHandGrade($request,$symb)); } elsif ($command eq 'editgrades' && $perm{'mgr'}) { - $request->print(&editgrades($request)); + &startpage($request,$symb); + $request->print(&editgrades($request,$symb)); + } elsif ($command eq 'initialverifyreceipt' && $perm{'vgr'}) { + &startpage($request,$symb); + $request->print(&initialverifyreceipt($request,$symb)); } elsif ($command eq 'verify' && $perm{'vgr'}) { - $request->print(&verifyreceipt($request)); + &startpage($request,$symb); + $request->print(&verifyreceipt($request,$symb)); } elsif ($command eq 'processclicker' && $perm{'mgr'}) { - $request->print(&process_clicker($request)); + &startpage($request,$symb); + $request->print(&process_clicker($request,$symb)); } elsif ($command eq 'processclickerfile' && $perm{'mgr'}) { - $request->print(&process_clicker_file($request)); + &startpage($request,$symb); + $request->print(&process_clicker_file($request,$symb)); } elsif ($command eq 'assignclickergrades' && $perm{'mgr'}) { - $request->print(&assign_clicker_grades($request)); + &startpage($request,$symb); + $request->print(&assign_clicker_grades($request,$symb)); } elsif ($command eq 'csvform' && $perm{'mgr'}) { - $request->print(&upcsvScores_form($request)); + &startpage($request,$symb); + $request->print(&upcsvScores_form($request,$symb)); } elsif ($command eq 'csvupload' && $perm{'mgr'}) { - $request->print(&csvupload($request)); + &startpage($request,$symb); + $request->print(&csvupload($request,$symb)); } elsif ($command eq 'csvuploadmap' && $perm{'mgr'} ) { - $request->print(&csvuploadmap($request)); + &startpage($request,$symb); + $request->print(&csvuploadmap($request,$symb)); } elsif ($command eq 'csvuploadoptions' && $perm{'mgr'}) { if ($env{'form.associate'} ne 'Reverse Association') { - $request->print(&csvuploadoptions($request)); + &startpage($request,$symb); + $request->print(&csvuploadoptions($request,$symb)); } else { if ( $env{'form.upfile_associate'} ne 'reverse' ) { $env{'form.upfile_associate'} = 'reverse'; } else { $env{'form.upfile_associate'} = 'forward'; } - $request->print(&csvuploadmap($request)); + &startpage($request,$symb); + $request->print(&csvuploadmap($request,$symb)); } } elsif ($command eq 'csvuploadassign' && $perm{'mgr'} ) { - $request->print(&csvuploadassign($request)); + &startpage($request,$symb); + $request->print(&csvuploadassign($request,$symb)); } elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) { - $request->print(&scantron_selectphase($request)); + &startpage($request,$symb); + $request->print(&scantron_selectphase($request,$symb)); } elsif ($command eq 'scantron_warning' && $perm{'mgr'}) { - $request->print(&scantron_do_warning($request)); + &startpage($request,$symb); + $request->print(&scantron_do_warning($request,$symb)); } elsif ($command eq 'scantron_validate' && $perm{'mgr'}) { - $request->print(&scantron_validate_file($request)); + &startpage($request,$symb); + $request->print(&scantron_validate_file($request,$symb)); } elsif ($command eq 'scantron_process' && $perm{'mgr'}) { - $request->print(&scantron_process_students($request)); + &startpage($request,$symb); + $request->print(&scantron_process_students($request,$symb)); } elsif ($command eq 'scantronupload' && (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})|| &Apache::lonnet::allowed('usc',$env{'request.course.id'}))) { - $request->print(&scantron_upload_scantron_data($request)); + &startpage($request,$symb); + $request->print(&scantron_upload_scantron_data($request,$symb)); } elsif ($command eq 'scantronupload_save' && (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})|| &Apache::lonnet::allowed('usc',$env{'request.course.id'}))) { - $request->print(&scantron_upload_scantron_data_save($request)); + &startpage($request,$symb); + $request->print(&scantron_upload_scantron_data_save($request,$symb)); } elsif ($command eq 'scantron_download' && &Apache::lonnet::allowed('usc',$env{'request.course.id'})) { - $request->print(&scantron_download_scantron_data($request)); + &startpage($request,$symb); + $request->print(&scantron_download_scantron_data($request,$symb)); } elsif ($command eq 'checksubmissions' && $perm{'vgr'}) { - $request->print(&checkscantron_results($request)); + &startpage($request,$symb); + $request->print(&checkscantron_results($request,$symb)); } elsif ($command) { + &startpage($request,$symb); $request->print('

'.&mt('Access Denied ([_1])',$command).'

'); } } @@ -9321,6 +9456,13 @@ ssi_with_retries() =item scantron_get_maxbubble() : + Arguments: + $nav_error - Reference to scalar which is a flag to indicate a + failure to retrieve a navmap object. + if $nav_error is set to 1 by scantron_get_maxbubble(), the + calling routine should trap the error condition and display the warning + found in &navmap_errormsg(). + Returns the maximum number of bubble lines that are expected to occur. Does this by walking the selected sequence rendering the resource and then checking &Apache::lonxml::get_problem_counter() @@ -9386,6 +9528,11 @@ ssi_with_retries() Validates all scanlines in the selected file to not have any invalid or underspecified student/employee IDs +=item navmap_errormsg() : + + Returns HTML mark-up inside a
with a link to re-initialize the course. + Should be called whenever the request to instantiate a navmap object fails. + =back =cut