--- loncom/homework/grades.pm 2019/02/06 05:55:25 1.596.2.12.2.41.2.5 +++ loncom/homework/grades.pm 2019/08/17 17:43:43 1.596.2.12.2.49 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.596.2.12.2.41.2.5 2019/02/06 05:55:25 raeburn Exp $ +# $Id: grades.pm,v 1.596.2.12.2.49 2019/08/17 17:43:43 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -44,6 +44,9 @@ use Apache::Constants qw(:common :http); use Apache::lonlocal; use Apache::lonenc; use Apache::bridgetask(); +use Apache::lontexconvert(); +use HTML::Parser(); +use File::MMagic; use String::Similarity; use LONCAPA; @@ -472,6 +475,7 @@ sub cleanRecord { $env{'form.kwstyle'} = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : ''; $env{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob. } + $answer = &Apache::lontexconvert::msgtexconverted($answer); return '

'.&keywords_highlight($answer).'
'; } elsif ( $response eq 'organic') { my $result=&mt('Smile representation: [_1]', @@ -2051,6 +2055,7 @@ sub submission { $env{'form.fullname'} = &Apache::loncommon::plainname($uname,$udom,'lastname') if $env{'form.fullname'} eq ''; my ($symb) = &get_symb($request); if ($symb eq '') { $request->print("Unable to handle ambiguous references:."); return ''; } + my ($essayurl,%coursedesc_by_cid); if (!&canview($usec)) { $request->print( @@ -2188,11 +2193,24 @@ sub submission { # # Load the other essays for similarity check # - my (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb); - my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/); - $apath=&escape($apath); - $apath=~s/\W/\_/gs; - &init_old_essays($symb,$apath,$adom,$aname); + (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb); + if ($essayurl eq 'lib/templates/simpleproblem.problem') { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if ($cdom ne '' && $cnum ne '') { + my ($map,$id,$res) = &Apache::lonnet::decode_symb($symb); + if ($map =~ m{^\Quploaded/$cdom/$cnum/\E(default(?:|_\d+)\.(?:sequence|page))$}) { + my $apath = $1.'_'.$id; + $apath=~s/\W/\_/gs; + &init_old_essays($symb,$apath,$cdom,$cnum); + } + } + } else { + my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/); + $apath=&escape($apath); + $apath=~s/\W/\_/gs; + &init_old_essays($symb,$apath,$adom,$aname); + } } } @@ -2333,27 +2351,52 @@ sub submission { &most_similar($uname,$udom,$symb,$subval); if ($osim) { $osim=int($osim*100.0); - my %old_course_desc = - &Apache::lonnet::coursedescription($ocrsid, - {'one_time' => 1}); - if ($hide eq 'anon') { $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). - '

'; - } - } - } + $similar='
'; + if ($essayurl eq 'lib/templates/simpleproblem.problem') { + $similar .= '

'. + &mt('Essay is [_1]% similar to an essay by [_2]', + $osim, + &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')'). + '

'; + } elsif ($ocrsid ne '') { + my %old_course_desc; + if (ref($coursedesc_by_cid{$ocrsid}) eq 'HASH') { + %old_course_desc = %{$coursedesc_by_cid{$ocrsid}}; + } else { + my $args; + if ($ocrsid ne $env{'request.course.id'}) { + $args = {'one_time' => 1}; + } + %old_course_desc = + &Apache::lonnet::coursedescription($ocrsid,$args); + $coursedesc_by_cid{$ocrsid} = \%old_course_desc; + } + $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'}). + ''; + } else { + $similar .= + '

'. + &mt('Essay is [_1]% similar to an essay by [_2] in an unknown course', + $osim, + &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')'). + '

'; + } + $similar .= '
'. + &keywords_highlight($oessay). + '

'; + } + } + } my $order=&get_order($partid,$respid,$symb,$uname,$udom, undef,$type,$trial,$rndseed); if ($env{'form.lastSub'} eq 'lastonly' || $env{'form.lastSub'} eq 'datesub' || $env{'form.lastSub'} =~ /^(last|all)$/ || ($env{'form.lastSub'} eq 'hdgrade' && @@ -4214,7 +4257,7 @@ sub editgrades { my ($uname,$udom)=split(/:/,$user); my %newrecord; my $updateflag = 0; - my $usec=$classlist->{"$uname:$udom"}[5]; + my $usec=$classlist->{"$uname:$udom"}[5]; my $canmodify = &canmodify($usec); my $line = ''. &nameUserString(undef,$$fullname{$user},$uname,$udom).''; @@ -4607,8 +4650,8 @@ sub csvuploadmap { $datatoken=&Apache::loncommon::upfile_store($request); } else { $datatoken=&Apache::loncommon::valid_datatoken($env{'form.datatoken'}); - if ($datatoken ne '') { - &Apache::loncommon::load_tmp_file($request,$datatoken); + if ($datatoken ne '') { + &Apache::loncommon::load_tmp_file($request,$datatoken); } } my @records=&Apache::loncommon::upfile_record_sep(); @@ -4869,6 +4912,7 @@ LISTJAVASCRIPT 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 $result='

 '. &mt('Manual Grading by Page or Sequence').'

'; @@ -4939,7 +4983,7 @@ LISTJAVASCRIPT ''.&nameUserString('header').''. &Apache::loncommon::end_data_table_header_row(); - my (undef,undef,$fullname) = &getclasslist($getsec,'1'); + my (undef,undef,$fullname) = &getclasslist($getsec,'1',$getgroup); my $ptr = 1; foreach my $student (sort { @@ -5815,12 +5859,12 @@ sub scantron_selectphase { $r->print('
'); - my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'}; - my $alertmsg = &mt('Please use the browse button to select a file from your local directory.'); - &js_escape(\$alertmsg); - my ($formatoptions,$formattitle,$formatjs) = &scantron_upload_dataformat($cdom); - $r->print(&Apache::lonhtmlcommon::scripttag(' + my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'}; + my $alertmsg = &mt('Please use the browse button to select a file from your local directory.'); + &js_escape(\$alertmsg); + my ($formatoptions,$formattitle,$formatjs) = &scantron_upload_dataformat($cdom); + $r->print(&Apache::lonhtmlcommon::scripttag(' function checkUpload(formname) { if (formname.upfile.value == "") { alert("'.$alertmsg.'"); @@ -5828,7 +5872,7 @@ sub scantron_selectphase { } formname.submit(); }'."\n".$formatjs)); - $r->print(' + $r->print('
'.$default_form_data.' @@ -5843,8 +5887,8 @@ sub scantron_selectphase { '.&Apache::loncommon::start_data_table_row().' '.&mt('File to upload: [_1]','').'
'."\n"); - if ($formatoptions) { - $r->print(' + if ($formatoptions) { + $r->print(' '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::start_data_table_row().' '.$formattitle.(' 'x2).$formatoptions.' @@ -5852,16 +5896,16 @@ sub scantron_selectphase { '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::start_data_table_row().' ' - ); - } else { - $r->print('
'); - } - $r->print(' + ); + } else { + $r->print('
'); + } + $r->print(' '.&Apache::loncommon::end_data_table_row().' '.&Apache::loncommon::end_data_table().'
' - ); + ); } @@ -10262,7 +10306,7 @@ sub process_clicker_file { $result .= &Apache::lonhtmlcommon::confirm_success( &mt('No IDs found to determine correct answer'),1); - return $result,.&show_grading_menu_form($symb); + return $result.&show_grading_menu_form($symb); } } if (length($env{'form.upfile'}) < 2) { @@ -10272,6 +10316,22 @@ sub process_clicker_file { ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').''),1); return $result.&show_grading_menu_form($symb); } + my $mimetype; + if ($env{'form.upfiletype'} eq 'iclicker') { + my $mm = new File::MMagic; + $mimetype = $mm->checktype_contents($env{'form.upfile'}); + unless (($mimetype eq 'text/plain') || ($mimetype eq 'text/html')) { + $result.= '

'. + &Apache::lonhtmlcommon::confirm_success( + &mt('File format is neither csv (iclicker 6) nor xml (iclicker 7)'),1).'

'; + return $result.&show_grading_menu_form($symb); + } + } elsif (($env{'form.upfiletype'} ne 'interwrite') && ($env{'form.upfiletype'} ne 'turning')) { + $result .= '

'. + &Apache::lonhtmlcommon::confirm_success( + &mt('Invalid clicker type: choose one of: i>clicker, Interwrite PRS, or Turning Technologies.'),1).'

'; + return $result.&show_grading_menu_form($symb); + } # Were able to get all the info needed, now analyze the file @@ -10299,12 +10359,14 @@ ENDHEADER my $errormsg=''; my $number=0; if ($env{'form.upfiletype'} eq 'iclicker') { - ($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses); - } - if ($env{'form.upfiletype'} eq 'interwrite') { + if ($mimetype eq 'text/plain') { + ($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses); + } elsif ($mimetype eq 'text/html') { + ($errormsg,$number)=&iclickerxml_eval(\@questiontitles,\%responses); + } + } elsif ($env{'form.upfiletype'} eq 'interwrite') { ($errormsg,$number)=&interwrite_eval(\@questiontitles,\%responses); - } - if ($env{'form.upfiletype'} eq 'turning') { + } elsif ($env{'form.upfiletype'} eq 'turning') { ($errormsg,$number)=&turning_eval(\@questiontitles,\%responses); } $result.='
'.&mt('Found [_1] question(s)',$number).'
'. @@ -10407,6 +10469,49 @@ sub iclicker_eval { return ($errormsg,$number); } +sub iclickerxml_eval { + my ($questiontitles,$responses)=@_; + my $number=0; + my $errormsg=''; + my @state; + my %respbyid; + my $p = HTML::Parser->new + ( + xml_mode => 1, + start_h => + [sub { + my ($tagname,$attr) = @_; + push(@state,$tagname); + if ("@state" eq "ssn p") { + my $title = $attr->{qn}; + $title =~ s/(^\s+|\s+$)//g; + $questiontitles->[$number]=$title; + } elsif ("@state" eq "ssn p v") { + my $id = $attr->{id}; + my $entry = $attr->{ans}; + $id=~s/^[\#0]+//; + $entry =~s/[^a-zA-Z0-9\.\*\-\+]+//g; + $respbyid{$id}[$number] = $entry; + } + }, "tagname, attr"], + end_h => + [sub { + my ($tagname) = @_; + if ("@state" eq "ssn p") { + $number++; + } + pop(@state); + }, "tagname"], + ); + + $p->parse($env{'form.upfile'}); + $p->eof; + foreach my $id (keys(%respbyid)) { + $responses->{$id}=join(',',@{$respbyid{$id}}); + } + return ($errormsg,$number); +} + sub interwrite_eval { my ($questiontitles,$responses)=@_; my $number=0; @@ -10700,7 +10805,7 @@ sub handler { } &Apache::loncommon::content_type($request,'text/html'); $request->send_http_header; - if (($command eq 'scantron_selectphase' && $perm{'mgr'}) || + if (($command eq 'scantron_selectphase' && $perm{'mgr'}) || (($command eq 'scantronupload') && (&Apache::lonnet::allowed('usc',$env{'request.role.domain'}) || &Apache::lonnet::allowed('usc',$env{'request.course.id'})))) { @@ -10708,7 +10813,7 @@ sub handler { undef,undef,undef,undef,'toggleScantab(document.rules);'); } else { unless ((($command eq 'submission' || $command eq 'versionsub')) && ($perm{'vgr'})) { - $request->print($start_page); + $request->print($start_page); } } if ($command eq 'submission' && $perm{'vgr'}) {