--- loncom/homework/grades.pm 2004/09/02 21:02:21 1.208 +++ loncom/homework/grades.pm 2005/02/01 21:03:13 1.240 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.208 2004/09/02 21:02:21 albertel Exp $ +# $Id: grades.pm,v 1.240 2005/02/01 21:03:13 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,16 +25,6 @@ # # http://www.lon-capa.org/ # -# 2/9,2/13 Guy Albertelli -# 6/8 Gerd Kortemeyer -# 7/26 H.K. Ng -# 8/20 Gerd Kortemeyer -# Year 2002 -# June-August H.K. Ng -# Year 2003 -# February, March H.K. Ng -# July, H. K. Ng -# package Apache::grades; use strict; @@ -101,25 +91,6 @@ sub get_symb_and_url { return ($symb,$url); } -# --- Retrieve the fullname for a user. Return lastname, first middle --- -# --- Generation is attached next to the lastname if it exists. --- -sub get_fullname { - my ($uname,$udom) = @_; - my %name=&Apache::lonnet::get('environment', ['lastname','generation', - 'firstname','middlename'], - $udom,$uname); - my $fullname; - my ($tmp) = keys(%name); - if ($tmp !~ /^(con_lost|error|no_such_host)/i) { - $fullname = &Apache::loncoursedata::ProcessFullName - (@name{qw/lastname generation firstname middlename/}); - } else { - &Apache::lonnet::logthis('grades.pm: no name data for '.$uname. - '@'.$udom.':'.$tmp); - } - return $fullname; -} - #--- Format fullname, username:domain if different for display #--- Use anywhere where the student names are listed sub nameUserString { @@ -1001,6 +972,8 @@ sub sub_page_kw_js { my $request = shift; my $iconpath = $request->dir_config('lonIconsURL'); &commonJSfunctions($request); + my $docopen=&Apache::lonhtmlcommon::javascript_docopen(); + $docopen=~s/^document\.//; $request->print(< @@ -1113,7 +1086,7 @@ sub sub_page_kw_js { pWin = window.open('', 'MessageCenter', 'resizable=yes,toolbar=no,location=no,scrollbars='+scrollbar+',screenx='+xpos+',screeny='+ypos+',width=600,height='+height); pWin.focus(); pDoc = pWin.document; - pDoc.open('text/html','replace'); + pDoc.$docopen; pDoc.write(""); pDoc.write("Message Central"); @@ -1244,7 +1217,7 @@ sub sub_page_kw_js { hwdWin = window.open('', 'KeywordHighlightCentral', 'resizeable=yes,toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx='+xpos+',screeny='+ypos); hwdWin.focus(); var hDoc = hwdWin.document; - hDoc.open('text/html','replace'); + hDoc.$docopen; hDoc.write(""); hDoc.write("Highlight Central"); @@ -1413,14 +1386,15 @@ sub submission { 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'} = &get_fullname ($uname,$udom) if $ENV{'form.fullname'} eq ''; + $ENV{'form.fullname'} = &Apache::loncommon::plainname($uname,$udom,'lastname') if $ENV{'form.fullname'} eq ''; my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url))); if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; } if (!&canview($usec)) { $request->print('Unable to view requested student.('. - $uname.$udom.$usec.$ENV{'request.course.id'}.')'); + $uname.'@'.$udom.' in section '.$usec.' in course id '. + $ENV{'request.course.id'}.')'); $request->print(&show_grading_menu_form($symb,$url)); return; } @@ -1697,10 +1671,26 @@ KEYWORDS $lastsubonly.='Part: '. $display_part.' ( ID '.$respid. ' )   '; + my @files; + if ($record{"resource.$partid.$respid.portfiles"}) { + my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio'; + foreach my $file (split(',',$record{"resource.$partid.$respid.portfiles"})) { + push(@files,$file_url.$file); + + &Apache::lonnet::logthis("found a portfolio file".$record{"resource.$partid.$respid.portfiles"}); + &Apache::lonnet::logthis("uploaded URL file".$record{"resource.$partid.$respid.uploadedurl"}); + } + } if ($record{"resource.$partid.$respid.uploadedurl"}) { - &Apache::lonnet::allowuploaded('/adm/grades', - $record{"resource.$partid.$respid.uploadedurl"}); - $lastsubonly.=' File uploaded by student Like all files provided by users, this file may contain virusses
'; + push(@files,$record{"resource.$partid.$respid.uploadedurl"}); + } + if (@files) { + $lastsubonly.='
Like all files provided by users, this file may contain virusses
'; + foreach my $file (@files) { + &Apache::lonnet::allowuploaded('/adm/grades',$file); + $lastsubonly.='
'.$file.''; + } + $lastsubonly.='
'; } $lastsubonly.='Submitted Answer: '. &cleanRecord($subval,$responsetype,$symb,$partid, @@ -2414,9 +2404,6 @@ sub viewgrades { my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'1'); my $ctr = 0; foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { - my $uname = $_; - $uname=~s/:/_/; - $result.=''."\n"; $ctr++; $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'}, $_,$$fullname{$_},\@parts,\%weight,$ctr); @@ -2440,18 +2427,21 @@ sub viewstudentgrade { my ($uname,$udom) = split(/:/,$student); $student=~s/:/_/; my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname); - my $result=''.$ctr.'  '. + my $result=''. + ''. + "\n".$ctr.'  '. ''.$fullname.' '. '('.$uname.($ENV{'user.domain'} eq $udom ? '' : ':'.$udom).')'."\n"; foreach my $apart (@$parts) { my ($part,$type) = &split_part_type($apart); my $score=$record{"resource.$part.$type"}; + $result.=''; if ($type eq 'awarded') { my $pts = $score eq '' ? '' : $score*$$weight{$part}; $result.=''."\n"; - $result.=''."\n"; @@ -2460,7 +2450,7 @@ sub viewstudentgrade { $status = 'nothing' if ($status eq ''); $result.=''."\n"; - $result.=' '. "\n"; - $result.=''."\n"; } @@ -3070,17 +3060,17 @@ sub getSymbMap { my $minder = 0; # Gather every sequence that has problems. - my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map(); }, 1); + my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map(); }, + 1,0,1); for my $sequence ($navmap->getById('0.0'), @sequences) { - if ($navmap->hasResource($sequence, sub { shift->is_problem(); }, 0) ) { +# if ($navmap->hasResource($sequence, sub { shift->is_problem(); }, 0) ) { + Apache->request->print($sequence->map_pc()."
"); my $title = $minder.'.'.$sequence->compTitle(); push @titles, $title; # minder in case two titles are identical $symbx{$title} = $sequence->symb(); $minder++; - } +# } } - - $navmap->untieHashes(); return \@titles,\%symbx; } @@ -3151,7 +3141,7 @@ sub displayPage { if($curRes == $iterator->BEGIN_MAP) { $depth++; } if($curRes == $iterator->END_MAP) { $depth--; } - if (ref($curRes) && $curRes->is_problem()) { + if (ref($curRes) && $curRes->is_problem() && !$curRes->randomout) { my $parts = $curRes->parts(); my $title = $curRes->compTitle(); my $symbx = $curRes->symb(); @@ -3213,8 +3203,6 @@ sub displayPage { $curRes = $iterator->next(); } - $navmap->untieHashes(); - $studentTable.=''."\n". ''. @@ -3227,9 +3215,12 @@ sub displayPage { sub displaySubByDates { my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_; + my $isCODE=0; + if (exists($record->{'resource.CODE'})) { $isCODE=1; } my $studentTable='
'. ''. ''. + ($isCODE?'':''). ''. ''; my ($version); @@ -3242,6 +3233,9 @@ sub displaySubByDates { for ($version=1;$version<=$$record{'version'};$version++) { my $timestamp = scalar(localtime($$record{$version.':timestamp'})); $studentTable.=''; + if ($isCODE) { + $studentTable.=''; + } my @versionKeys = split(/\:/,$$record{$version.':keys'}); my @displaySub = (); foreach my $partid (@{$parts}) { @@ -3410,8 +3404,6 @@ sub updateGradeByPage { $curRes = $iterator->next(); } - $navmap->untieHashes(); - $studentTable.='
Date/TimeCODESubmissionStatus 
'.$timestamp.''.$record->{$version.':resource.CODE'}.'
'; $studentTable.=&show_grading_menu_form($ENV{'form.symb'},$ENV{'form.url'}); my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' : @@ -3472,10 +3464,11 @@ sub scantron_filenames { } sub scantron_uploads { + my ($file2grade) = @_; my $result= '"; return $result; @@ -3500,7 +3493,7 @@ sub scantron_CODElist { my $cnum = $ENV{'course.'.$ENV{'request.course.id'}.'.num'}; my @names=&Apache::lonnet::getkeys('CODEs',$cdom,$cnum); my $namechoice=''; - foreach my $name (sort(@names)) { + foreach my $name (sort {uc($a) cmp uc($b)} @names) { if ($name =~ /^error: 2 /) { next; } $namechoice.=''; } @@ -3521,13 +3514,13 @@ sub scantron_CODEunique { } sub scantron_selectphase { - my ($r) = @_; + my ($r,$file2grade) = @_; my ($symb,$url)=&get_symb_and_url($r); if (!$symb) {return '';} my $sequence_selector=&getSequenceDropDown($r,$symb); my $default_form_data=&defaultFormData($symb,$url); my $grading_menu_button=&show_grading_menu_form($symb,$url); - my $file_selector=&scantron_uploads(); + my $file_selector=&scantron_uploads($file2grade); my $format_selector=&scantron_scantab(); my $CODE_selector=&scantron_CODElist(); my $CODE_unique=&scantron_CODEunique(); @@ -3537,8 +3530,8 @@ sub scantron_selectphase { $result.= < +
- $default_form_data @@ -3575,8 +3568,8 @@ sub scantron_selectphase {
-
- + + SCANTRONFORM @@ -3632,8 +3625,8 @@ SCANTRONFORM } $r->print(< - -
+ + @@ -3650,14 +3643,13 @@ SCANTRONFORM
-
- + + SCANTRONFORM $r->print(< - $grading_menu_button SCANTRONFORM @@ -3806,25 +3798,49 @@ sub scantron_parse_scanline { my $currentquest=substr($questions,0,$$scantron_config{'Qlength'}); substr($questions,0,$$scantron_config{'Qlength'})=''; if (length($currentquest) < $$scantron_config{'Qlength'}) { next; } - my @array=split($$scantron_config{'Qon'},$currentquest,-1); - if (length($array[0]) eq $$scantron_config{'Qlength'}) { - $record{"scantron.$questnum.answer"}=''; - if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) { - push(@{$record{"scantron.missingerror"}},$questnum); - } + if ($$scantron_config{'Qon'} eq 'letter') { + if (!$currentquest || $currentquest eq $$scantron_config{'Qoff'} || + $currentquest !~ /^[A-Z]$/) { + $record{"scantron.$questnum.answer"}=''; + if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) { + push(@{$record{"scantron.missingerror"}},$questnum); + } + } else { + $record{"scantron.$questnum.answer"}=$currentquest; + } + } elsif ($$scantron_config{'Qon'} eq 'number') { + if (!$currentquest || $currentquest eq $$scantron_config{'Qoff'} || + $currentquest !~ /^\d$/) { + $record{"scantron.$questnum.answer"}=''; + if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) { + push(@{$record{"scantron.missingerror"}},$questnum); + } + } else { + $record{"scantron.$questnum.answer"}= + $alphabet[$currentquest-1]; + } } else { - $record{"scantron.$questnum.answer"}=$alphabet[length($array[0])]; + my @array=split($$scantron_config{'Qon'},$currentquest,-1); + if (length($array[0]) eq $$scantron_config{'Qlength'}) { + $record{"scantron.$questnum.answer"}=''; + if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) { + push(@{$record{"scantron.missingerror"}},$questnum); + } + } else { + $record{"scantron.$questnum.answer"}= + $alphabet[length($array[0])]; + } + if (scalar(@array) gt 2) { + push(@{$record{'scantron.doubleerror'}},$questnum); + my @ans=@array; + my $i=length($ans[0]);shift(@ans); + while ($#ans) { + $i+=length($ans[0])+1; + $record{"scantron.$questnum.answer"}.=$alphabet[$i]; + shift(@ans); + } + } } - if (scalar(@array) gt 2) { - push(@{$record{'scantron.doubleerror'}},$questnum); - my @ans=@array; - my $i=length($ans[0]);shift(@ans); - while ($#ans) { - $i+=length($ans[0])+1; - $record{"scantron.$questnum.answer"}.=$alphabet[$i]; - shift(@ans); - } - } } $record{'scantron.maxquest'}=$questnum; return \%record; @@ -3854,7 +3870,8 @@ sub scantron_find_student { sub scantron_filter { my ($curres)=@_; - if (ref($curres) && $curres->is_problem() && !$curres->randomout) { + # randomout is dysfunctional at best for this purpose + if (ref($curres) && $curres->is_problem()) { #&& !$curres->randomout) { return 1; } return 0; @@ -3988,14 +4005,28 @@ sub scantron_do_warning { if (!$symb) {return '';} my $default_form_data=&defaultFormData($symb,$url); $r->print(&scantron_form_start().$default_form_data); - my $warning=&scantron_warning_screen('Validate Records'); - $r->print(<print("

You have forgetten to specify some information. Please go Back and try again.

"); + if ( $ENV{'form.selectpage'} eq '') { + $r->print('

You have not selected a Sequence to grade

'); + } + if ( $ENV{'form.scantron_selectfile'} eq '') { + $r->print('

You have not selected a file that contains the student\'s response data.

'); + } + if ( $ENV{'form.scantron_format'} eq '') { + $r->print('

You have not selected a the format of the student\'s response data.

'); + } + } else { + my $warning=&scantron_warning_screen('Validate Records'); + $r->print(< - STUFF - $r->print("
".&show_grading_menu_form($symb,$url).""); + } + $r->print("
".&show_grading_menu_form($symb,$url).""); return ''; } @@ -4006,7 +4037,7 @@ sub scantron_form_start { - + @@ -4326,8 +4357,8 @@ sub scantron_get_correction { } elsif ($error eq 'duplicateCODE') { $r->print("

The encoded CODE has also been used by a previous paper ".join(', ',@{$arg}).", and CODEs are supposed to be unique

\n"); } - $r->print("

The CODE on the form is ". - $$scan_record{'scantron.CODE'}."
\n"); + $r->print("

The CODE on the form is '". + $$scan_record{'scantron.CODE'}."'
\n"); $r->print("

The ID on the form is ". $$scan_record{'scantron.ID'}."
\n"); $r->print("The name on the paper is ". @@ -4473,13 +4504,21 @@ sub scantron_validate_CODE { $scan_data); my $CODE=$$scan_record{'scantron.CODE'}; my $error=0; - if (!exists($allcodes{$CODE}) && !$$scan_record{'scantron.useCODE'}) { + if (!&Apache::lonnet::validCODE($CODE)) { + &scantron_get_correction($r,$i,$scan_record, + \%scantron_config, + $line,'incorrectCODE',\%allcodes); + return(1,$currentphase); + } + if (%allcodes && !exists($allcodes{$CODE}) + && !$$scan_record{'scantron.useCODE'}) { &scantron_get_correction($r,$i,$scan_record, \%scantron_config, $line,'incorrectCODE',\%allcodes); return(1,$currentphase); } - if (exists($usedCODEs{$CODE}) && $ENV{'form.scantron_CODEunique'} + if (exists($usedCODEs{$CODE}) + && $ENV{'form.scantron_CODEunique'} eq 'yes' && !$$scan_record{'scantron.CODE_ignore_dup'}) { &scantron_get_correction($r,$i,$scan_record, \%scantron_config, @@ -4527,7 +4566,7 @@ sub scantron_get_maxbubble { my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); &Apache::lonnet::delenv('form.counter'); foreach my $resource (@resources) { - my $result=&Apache::lonnet::ssi($resource->src()); + my $result=&Apache::lonnet::ssi($resource->src().'?symb='.&Apache::lonnet::escape($resource->symb())); } &Apache::lonnet::delenv('scantron\.'); my $envfile=$ENV{'user.environment'}; @@ -4644,11 +4683,18 @@ SCANTRONFORM if (exists($scan_record->{'scantron.CODE'}) && $scan_record->{'scantron.CODE'}) { $form{'CODE'}=$scan_record->{'scantron.CODE'}; + } else { + $form{'CODE'}=''; } my $result=&Apache::lonnet::ssi($resource->src(),%form); - + if ($result ne '') { + &Apache::lonnet::logthis("scantron grading error -> $result"); + &Apache::lonnet::logthis("scantron grading error info name $uname domain $udom course $ENV{'request.course.id'} url ".$resource->src()); + } + if (&Apache::loncommon::connection_aborted($r)) { last; } } $completedstudents{$uname}={'line'=>$line}; + if (&Apache::loncommon::connection_aborted($r)) { last; } } continue { &Apache::lonnet::delenv('form.counter'); &Apache::lonnet::delenv('scantron\.'); @@ -4657,7 +4703,6 @@ SCANTRONFORM # my $lasttime = &Time::HiRes::time()-$start; # $r->print("

took $lasttime

"); - $navmap->untieHashes(); $r->print(""); $r->print(&show_grading_menu_form($symb,$url)); return ''; @@ -4718,7 +4763,8 @@ sub scantron_upload_scantron_data_save { } return ''; } - $r->print("Doing upload to ".$ENV{'form.courseid'}."
"); + my %coursedata=&Apache::lonnet::coursedescription($ENV{'form.domainid'}.'_'.$ENV{'form.courseid'}); + $r->print("Doing upload to ".$coursedata{'description'}."
"); my $home=&Apache::lonnet::homeserver($ENV{'form.courseid'}, $ENV{'form.domainid'}); my $fname=$ENV{'form.upfile.filename'}; @@ -4735,6 +4781,7 @@ sub scantron_upload_scantron_data_save { $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("Error: The file you attempted to upload, ".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"').", contained no information. Please check that you entered the correct filename."); @@ -4743,11 +4790,11 @@ sub scantron_upload_scantron_data_save { if ($result =~ m|^/uploaded/|) { $r->print("Success: Successfully uploaded ".(length($ENV{'form.upfile'})-1)." bytes of data into location ".$result.""); } else { - $r->print("Error: An error (".$result.") occured when attempting to upload the file, ".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"').""); + $r->print("Error: An error (".$result.") occurred when attempting to upload the file, ".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"').""); } } if ($symb) { - $r->print(&show_grading_menu_form($symb,$url)); + $r->print(&scantron_selectphase($r,$uploadedfile)); } else { $r->print($doanotherupload); } @@ -4803,7 +4850,6 @@ DOWNLOAD # #------------------------------------------------------------------- - #-------------------------- Menu interface ------------------------- # #--- Show a Grading Menu button - Calls the next routine --- @@ -4856,6 +4902,7 @@ sub gradingmenu { if (!checkReceiptNo(formname,'notOK')) { return false;} formname.submit(); } + if (val < 7) formname.submit(); } function checkReceiptNo(formname,nospace) { @@ -4908,7 +4955,7 @@ GRADINGMENUJS ($saveSec eq $_ ? 'selected="on"':'').'>'.$_.''."\n"; } } - $result.= '   '; $result.=&mt('Student Status').':'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef); @@ -4960,6 +5007,9 @@ GRADINGMENUJS '-'. ''."\n"; } + $result.=''. + ' access times.'."\n"; $result.=''."\n". ''."\n". @@ -5111,8 +5161,7 @@ sub send_header { sub send_footer { my ($request)= @_; - $request->print(''); - $request->print(&Apache::lontexconvert::footer()); + $request->print(''); } 1;