--- loncom/homework/grades.pm 2004/07/27 15:14:52 1.206
+++ loncom/homework/grades.pm 2005/04/02 18:44:39 1.254
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.206 2004/07/27 15:14:52 albertel Exp $
+# $Id: grades.pm,v 1.254 2005/04/02 18:44:39 banghart 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,31 +91,12 @@ 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 {
my ($type,$fullname,$uname,$udom) = @_;
if ($type eq 'header') {
- return ' Fullname (Username) ';
+ return ' Fullname (Username)';
} else {
return ' '.$fullname.' ('.$uname.
($ENV{'user.domain'} eq $udom ? '' : ' ('.$udom.')').')';
@@ -167,6 +138,20 @@ sub response_type {
return \@partlist,\%handgrade,\%responseType;
}
+sub get_display_part {
+ my ($partID,$url,$symb)=@_;
+ if (!defined($symb) || $symb eq '') {
+ $symb=$ENV{'form.symb'};
+ if ($symb eq '') { $symb=&Apache::lonnet::symbread($url) }
+ }
+ my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',$symb);
+ if (defined($display) and $display ne '') {
+ $display.= " (id $partID)";
+ } else {
+ $display=$partID;
+ }
+ return $display;
+}
#--- Show resource title
#--- and parts and response type
sub showResourceInfo {
@@ -194,7 +179,8 @@ sub showResourceInfo {
}
$partsseen{$partID}=1;
}
- $result.='
Part '.$partID.' '.
+ my $display_part=&get_display_part($partID,$url);
+ $result.='
Part: '.$display_part.' '.
$resID.'
'.
'
Type: '.$responsetype.'
';
# '
Handgrade: '.$handgrade.'
';
@@ -678,20 +664,26 @@ LISTJAVASCRIPT
$gradeTable.='To '.lc($viewgrade).' a submission or a group of submissions, click on the check box(es) '.
'next to the student\'s name(s). Then click on the Next button. '."\n".
''."\n";
+
+# checkall buttons
+ $gradeTable.=&check_script('gradesub', 'stuinfo');
$gradeTable.='" />'."\n";
+ 'value="Next->" /> '."\n";
+ $gradeTable.=&check_buttons();
$gradeTable.='Check For Plagiarism';
- my (undef, undef, $fullname) = &getclasslist($getsec,'1');
+ my ($classlist, undef, $fullname) = &getclasslist($getsec,'1');
$gradeTable.='
'.
'
';
my $loop = 0;
while ($loop < 2) {
$gradeTable.='
No.
Select
'.
- '
'.&nameUserString('header').'
';
+ '
'.&nameUserString('header').' Section/Group
';
if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
foreach (sort(@$partlist)) {
- $gradeTable.='
Part '.(split(/_/))[0].' Status
';
+ my $display_part=&get_display_part((split(/_/))[0],$url,$symb);
+ $gradeTable.='
Part: '.$display_part.
+ ' Status
';
}
}
$loop++;
@@ -707,10 +699,12 @@ LISTJAVASCRIPT
(%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
my $submitted = 0;
my $graded = 0;
+ my $incorrect = 0;
foreach (keys(%status)) {
$submitted = 1 if ($status{$_} ne 'nothing');
- $graded = 1 if ($status{$_} !~ /^correct/);
-
+ $graded = 1 if ($status{$_} =~ /^ungraded/);
+ $incorrect = 1 if ($status{$_} =~ /^incorrect/);
+
my ($foo,$partid,$foo1) = split(/\./,$_);
if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
$submitted = 0;
@@ -720,20 +714,25 @@ LISTJAVASCRIPT
$status{'resource.'.$partid.'.submitted_by'}.'" />';
}
}
+
next if (!$submitted && ($submitonly eq 'yes' ||
$submitonly eq 'incorrect' ||
$submitonly eq 'graded'));
- next if (!$graded && ($submitonly eq 'graded' ||
- $submitonly eq 'incorrect'));
+ next if (!$graded && ($submitonly eq 'graded'));
+ next if (!$incorrect && $submitonly eq 'incorrect');
}
$ctr++;
+ my $section = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()];
+
if ( $perm{'vgr'} eq 'F' ) {
$gradeTable.='
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,
@@ -1996,10 +2063,12 @@ sub processHandGrade {
# my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
my %status=&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
my $submitted = 0;
- my $graded = 1;
+ my $ungraded = 0;
+ my $incorrect = 0;
foreach (keys(%status)) {
$submitted = 1 if ($status{$_} ne 'nothing');
- $graded = 0 if ($status{$_} =~ /^correct/);
+ $ungraded = 1 if ($status{$_} =~ /^ungraded/);
+ $incorrect = 1 if ($status{$_} =~ /^incorrect/);
my ($foo,$partid,$foo1) = split(/\./,$_);
if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
$submitted = 0;
@@ -2008,8 +2077,8 @@ sub processHandGrade {
next if (!$submitted && ($submitonly eq 'yes' ||
$submitonly eq 'incorrect' ||
$submitonly eq 'graded'));
- next if (!$graded && ($submitonly eq 'graded' ||
- $submitonly eq 'incorrect'));
+ next if (!$ungraded && ($submitonly eq 'graded'));
+ next if (!$incorrect && $submitonly eq 'incorrect');
}
push @nextlist,$student if ($ctr < $ntstu);
last if ($ctr == $ntstu);
@@ -2044,6 +2113,7 @@ sub saveHandGrade {
$ENV{'request.course.id'});
if (!&canmodify($usec)) { return('not_allowed'); }
my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
+ my @parts_graded;
my %newrecord = ();
my ($pts,$wgt) = ('','');
foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
@@ -2078,6 +2148,8 @@ sub saveHandGrade {
if ($partial eq $record{'resource.'.$_.'.awarded'}) {
#do not update score for part if not changed.
next;
+ } else {
+ push @parts_graded, $_;
}
if ($record{'resource.'.$_.'.awarded'} ne $partial) {
$newrecord{'resource.'.$_.'.awarded'} = $partial;
@@ -2101,12 +2173,56 @@ sub saveHandGrade {
}
}
if (scalar(keys(%newrecord)) > 0) {
+ &version_portfiles(\%record, \@parts_graded, $ENV{'request.course.id'}, $symb, $domain, $stuname);
&Apache::lonnet::cstore(\%newrecord,$symb,
$ENV{'request.course.id'},$domain,$stuname);
}
return '',$pts,$wgt;
}
+# ----------- Handles creating versions for portfolio files as answers
+sub version_portfiles {
+ my ($record, $parts_graded, $courseid, $symb, $domain, $stuname) = @_;
+ my $parts = join '|', @$parts_graded;
+ my $portfolio_root = &Apache::loncommon::propath($domain,
+ $stuname).
+ '/userfiles/portfolio';
+ foreach my $key (keys %$record) {
+ if ($key =~ /^resource\.($parts)\./ && $key =~ /\.portfiles$/) {
+ my @portfiles = split /,/,$$record{$key};
+ foreach my $file (@portfiles) {
+ my ($directory,$answer_file) =( $file =~ /^(.*?)([^\/]*$)/);
+ my $version = 0;
+ my @answer_file_parts = split /\./, $answer_file;
+ my @dir_list = &Apache::lonnet::dirlist($directory,$domain,$stuname,$portfolio_root);
+ my @file_names;
+ my @file_name_parts;
+ foreach my $row (@dir_list) {
+ @file_names = split (/\&/,$row,2);
+ @file_name_parts = split (/\./, $file_names[0]);
+ # ($file_name_parts[scalar @file_name_parts] eq $answer_file_parts[scalar @answer_file_parts])
+ if (($file_name_parts[0] eq $answer_file_parts[0]) &&
+ ($file_name_parts[-1] eq $answer_file_parts[-1])) {
+ # gets here if filename and extension match, regardless of version
+ if (scalar @file_name_parts == 3) { # a versioned file is found
+ # so save it for later
+ if ($file_name_parts[1] > $version) {$version = $file_name_parts[1]};
+ }
+ }
+ }
+ $version += 1;
+ &Apache::lonnet::logthis('answer file is '.$answer_file.
+ ' becomes '.$answer_file_parts[0].'.'.$version.'.'.$answer_file_parts[(scalar @answer_file_parts)-1]);
+ &Apache::lonnet::logthis('from dir list is '.$file_names[0].' has '.@file_name_parts.' parts');
+ }
+ &Apache::lonnet::logthis('found key portfiles '.$key);
+ &Apache::lonnet::logthis('found value portfiles '.$$record{$key});
+ }
+ }
+
+
+}
+
#--------------------------------------------------------------------------------------
#
#-------------------------- Next few routines handles grading by section or whole class
@@ -2335,7 +2451,8 @@ sub viewgrades {
$ctsparts.'" value="'.$partid.'" />'."\n";
$result.=''."\n";
- $result.='
Part '.$partid.' Point:
';
+ my $display_part=&get_display_part($partid,$url,$symb);
+ $result.='
Part: '.$display_part.' Point:
';
$result.='
';
my $ctr = 0;
while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
@@ -2374,14 +2491,17 @@ sub viewgrades {
my $display=&Apache::lonnet::metadata($url,$part.'.display');
$display =~ s|^Number of Attempts|Tries |; # makes the column narrower
if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
+ my ($partid) = &split_part_type($part);
+ my $display_part=&get_display_part($partid,$url,$symb);
if ($display =~ /^Partial Credit Factor/) {
- my ($partid) = &split_part_type($part);
- $result.='
Score Part '.$partid.' (weight = '.
- $weight{$partid}.')
'."\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";
@@ -2436,7 +2556,7 @@ sub viewstudentgrade {
$status = 'nothing' if ($status eq '');
$result.=''."\n";
- $result.='
';
}
$result .= '
';
@@ -2636,24 +2757,26 @@ sub split_part_type {
#
#--- Javascript to handle csv upload
sub csvupload_javascript_reverse_associate {
+ my $error1=&mt('You need to specify the username or ID');
+ my $error2=&mt('You need to specify at least one grading field');
return(<2) { foundsomething=1; }
- }
- if (founduname==0 || founddomain==0) {
- alert('You need to specify at both the username and domain');
- return;
+ if (tw==1) { foundID=1; }
+ if (tw==2) { founduname=1; }
+ if (tw>3) { foundsomething=1; }
+ }
+ if (founduname==0 && foundID==0) {
+ alert('$error1');
+ return;
}
if (foundsomething==0) {
- alert('You need to specify at least one grading field');
- return;
+ alert('$error2');
+ return;
}
vf.submit();
}
@@ -2718,7 +2843,8 @@ sub csvuploadmap_header {
}
my ($result) = &showResourceInfo($url,$ENV{'form.probTitle'});
-
+ my $checked=(($ENV{'form.noFirstLine'})?' checked="checked"':'');
+ my $ignore=&mt('Ignore First Line');
$request->print(<
Uploading Class Grades
@@ -2729,6 +2855,7 @@ Total number of records found in file: $
Enter as many fields as you can. The system will inform you and bring you back
to this page if the data selected is insufficient to run your class.
+
@@ -2740,7 +2867,7 @@ to this page if the data selected is ins
-
+