--- loncom/homework/grades.pm 2002/07/10 21:08:38 1.38
+++ loncom/homework/grades.pm 2002/09/20 23:41:47 1.50
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.38 2002/07/10 21:08:38 ng Exp $
+# $Id: grades.pm,v 1.50 2002/09/20 23:41:47 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,7 +30,7 @@
# 7/26 H.K. Ng
# 8/20 Gerd Kortemeyer
# Year 2002
-# June, July 2002 H.K. Ng
+# June-August H.K. Ng
#
package Apache::grades;
@@ -42,80 +42,37 @@ use Apache::loncommon;
use Apache::lonhomework;
use Apache::lonmsg qw(:user_normal_msg);
use Apache::Constants qw(:common);
-use Time::HiRes qw( gettimeofday tv_interval );
-sub moreinfo {
- my ($request,$reason) = @_;
- $request->print("Unable to process request: $reason");
- if ( $Apache::grades::viewgrades eq 'F' ) {
- $request->print('
');
- }
- return '';
-}
-
-sub verifyreceipt {
- my $request=shift;
- my $courseid=$ENV{'request.course.id'};
-# my $cdom=$ENV{"course.$courseid.domain"};
-# my $cnum=$ENV{"course.$courseid.num"};
- my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
- $ENV{'form.receipt'};
- $receipt=~s/[^\-\d]//g;
- my $symb=$ENV{'form.symb'};
- unless ($symb) {
- $symb=&Apache::lonnet::symbread($ENV{'form.url'});
- }
- if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {
- $request->print('
Verifying Submission Receipt '.$receipt.'
');
- my $matches=0;
- my ($classlist) = &getclasslist('all','0');
- foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
- my ($uname,$udom)=split(/\:/,$student);
- if ($receipt eq
- &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
- $request->print('Matching '.$student.' ');
- $matches++;
- }
- }
- $request->printf('
'.$matches." match%s
",$matches <= 1 ? '' : 'es');
-# needs to print who is matched
+# ----- These first few routines are general use routines.-----
+#
+# --- Retrieve the parts that matches stores_\d+ from the metadata file.---
+sub getpartlist {
+ my ($url) = @_;
+ my @parts =();
+ my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
+ foreach my $key (@metakeys) {
+ if ( $key =~ m/stores_([0-9]+)_.*/) {
+ push(@parts,$key);
+ }
}
- return '';
+ return @parts;
}
-sub student_gradeStatus {
- my ($url,$udom,$uname) = @_;
- my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
- my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
- foreach my $part (&getpartlist($url)) {
- my ($temp,$part,$type)=split(/_/,$part);
- if ($type eq 'solved') {
- my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);
- $status = 'partial' if ($foo =~ /^partially/);
- $status = 'nothing' if ($status eq '');
- return $type,$status;
- }
- }
- return '';
+# --- Get the symbolic name of a problem and the url
+sub get_symb_and_url {
+ my ($request) = @_;
+ (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 '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
+ 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 ($sname,$sdom) = @_;
+ my ($uname,$udom) = @_;
my %name=&Apache::lonnet::get('environment', ['lastname','generation',
- 'firstname','middlename'],
- $sdom,$sname);
+ 'firstname','middlename'],$udom,$uname);
my $fullname;
my ($tmp) = keys(%name);
if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
@@ -126,914 +83,408 @@ sub get_fullname {
return $fullname;
}
-sub listStudents {
- my ($request) = shift;
- my $cdom =$ENV{"course.$ENV{'request.course.id'}.domain"};
- my $cnum =$ENV{"course.$ENV{'request.course.id'}.num"};
- my $getsec =$ENV{'form.section'};
- my $submitonly=$ENV{'form.submitonly'};
-
- $request->print(< View Submissions for a Student or a Group of Students
- Resource: $ENV{'form.url'}
-
- View Problem: no
- yes
- Submissions:
- last sub only
- last sub & parts info
- all details
-
-
-
-
-
-
-
Select
Username
-
Fullname
Domain
-
Grade Status
-ENDTABLEST
- if ($ENV{'form.url'}) {
- $request->print(''."\n");
- }
- if ($ENV{'form.symb'}) {
- $request->print(''."\n");
- }
- $request->print(''."\n");
-
- my $t0=&Time::HiRes::time();
-
- my ($classlist) = &getclasslist($getsec,'0');
- my $t1=&Time::HiRes::time();
- print "getclasslist=",$t1-$t0," ";
-
- foreach my $student ( sort(@{ $$classlist{$getsec} }) ) {
- my ($sname,$sdom) = split(/:/,$student);
- my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$cdom,$sname);
- next if ($status eq 'nothing' && $submitonly eq 'yes');
-
- my $fullname = &get_fullname($sname,$sdom);
- if ( $Apache::grades::viewgrades eq 'F' ) {
- $request->print("\n".'
\n";
+# add id, section and fullname to the classlist.db
+# done to maintain backward compatibility with older versions
+sub reformat_classlist {
+ my ($classlist) = shift;
+ foreach (sort keys(%$classlist)) {
+ my ($unam,$udom) = split(/:/);
+ my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});
+ my $fullname = &get_fullname ($unam,$udom);
+ my %userid = &Apache::lonnet::idrget($udom,($unam));
+ $$classlist{$_} = $$classlist{$_}.':'.$userid{$unam}.':'.$section.':'.$fullname;
}
- }
- $result.='
';
- return $result;
+ my $putresult = &Apache::lonnet::put
+ ('classlist',\%$classlist,
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+
+ return %$classlist;
}
-#FIXME need to look at the metadata spec on what type of data to accept and provide an
-#interface based on that, also do that to above function.
-sub setstudentgrade {
- my ($url,$symb,$courseid,$student,@parts) = @_;
- print "set student grade parts=@parts ";
- my $result ='';
- my ($stuname,$domain) = split(/:/,$student);
- my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);
- my %newrecord;
-
- foreach my $part (@parts) {
- my ($temp,$part,$type)=split(/_/,$part);
- my $oldscore=$record{"resource.$part.$type"};
- my $newscore=$ENV{"form.GRADE.$student.$part.$type"};
- print "old=$oldscore:new=$newscore: ";
- if ($type eq 'solved') {
- my $update=0;
- if ($newscore eq 'nothing' ) {
- if ($oldscore ne '') {
- $update=1;
- $newscore = '';
- }
- } elsif ($oldscore !~ m/^$newscore/) {
- $update=1;
- $result.="Updating $stuname to $newscore \n";
- if ($newscore eq 'correct') { $newscore = 'correct_by_override'; }
- if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }
- if ($newscore eq 'excused') { $newscore = 'excused'; }
- if ($newscore eq 'ungraded') { $newscore = 'ungraded_attempted'; }
- if ($newscore eq 'partial') { $newscore = 'correct_partially_by_override'; }
- } else {
- #$result.="$stuname:$part:$type:unchanged $oldscore to $newscore: \n";
- }
- if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
+#find user domain
+sub finduser {
+ my ($name) = @_;
+ my $domain = '';
+ if ( $Apache::grades::viewgrades eq 'F' ) {
+ my %classlist=&Apache::lonnet::dump('classlist',
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+ my (@fields) = grep /^$name:/, keys %classlist;
+ ($name, $domain) = split(/:/,$fields[0]);
+ return ($name,$domain);
} else {
- if ($oldscore ne $newscore) {
- $newrecord{"resource.$part.$type"}=$newscore;
- $result.="Updating $student"."'s status for $part.$type to $newscore \n";
- } else {
- #$result.="$stuname:$part:$type:unchanged $oldscore to $newscore: \n";
- }
+ return ($ENV{'user.name'},$ENV{'user.domain'});
}
- }
- if ( scalar(keys(%newrecord)) > 0 ) {
- $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
-# &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);
-
- $result.="Stored away ".scalar(keys(%newrecord))." elements. \n";
- }
- return $result;
}
-#
-# --------------------------- show submissions of a student, option to grade --------
-sub submission {
- my ($request,$counter,$total) = @_;
-
- (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
- if ($ENV{'form.student'} eq '') { &moreinfo($request,'Need student login id'); return ''; }
- my ($uname,$udom) = &finduser($ENV{'form.student'});
- if ($uname eq '') { &moreinfo($request,'Unable to find student'); return ''; }
-
- 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 ''; }
- my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');
-
- # header info
- if ($counter == 0) {
- &sub_page_js($request);
- $request->print('
Submission Record
'.
- ' Resource: '.$url.'');
-
- # option to display problem, only once else it cause problems with the form later
- # since the problem has a form.
- if ($ENV{'form.vProb'} eq 'yes') {
- my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,
- $ENV{'request.course.id'});
- my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,
- $ENV{'request.course.id'});
- my $result.='
'."\n";
+
+ $matches++;
}
}
- @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
- return \@string,\@timestamp;
- }
-}
+ if ($matches == 0) {
+ $string = $title.'No match found for the above receipt.';
+ } else {
+ $string = &jscriptNform($url,$symb).$title.
+ 'The above receipt matches the following student'.
+ ($matches <= 1 ? '.' : 's.')."\n".
+ '
'."\n".
+ '
'."\n".
+ '
Fullname
'."\n".
+ '
Username
'."\n".
+ '
Domain
'."\n".
+ $contents.
+ '
'."\n";
+ }
+ return $string.&show_grading_menu_form($symb,$url);
+}
+
+#--- This is called by a number of programs.
+#--- Called from the Grading Menu - View/Grade an individual student
+#--- Also called directly when one clicks on the subm button
+# on the problem page.
+sub listStudents {
+ my ($request) = shift;
-sub keywords_highlight {
- my $string = shift;
- my $size = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};
- my $styleon = $ENV{'form.kwstyle'} eq '' ? '' : $ENV{'form.kwstyle'};
- (my $styleoff = $styleon) =~ s/\\<\//;
- my @keylist = split(/[,\s+]/,$ENV{'form.keywords'});
- foreach (@keylist) {
- # next if ($_ eq '');
- $string =~ s/\b$_(\b|\.)/\$styleon$_$styleoff\<\/font\>/gi;
- }
- return $string;
-}
+ my ($symb,$url) = &get_symb_and_url();
+ 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 $submitonly= $ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};
+
+ my $result;
+ my ($partlist,$handgrade) = &response_type($url);
+ for (sort keys(%$handgrade)) {
+ my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+ $ENV{'form.handgrade'} = 'yes' if ($handgrade eq 'yes');
+ $result.='
Part '.(split(/_/))[0].'
'.
+ '
Type: '.$responsetype.'
'.
+ '
Handgrade: '.$handgrade.'
';
+ }
+ $result.='';
+
+ my $viewgrade;
+ if ($ENV{'form.handgrade'} eq 'yes') {
+ $viewgrade = 'View/Grade';
+ } else {
+ $viewgrade = 'View';
+ }
-sub processHandGrade {
- my ($request) = shift;
- my $url = $ENV{'form.url'};
- my $symb = $ENV{'form.symb'};
- my $button = $ENV{'form.gradeOpt'};
- my $ngrade = $ENV{'form.NCT'};
- my $ntstu = $ENV{'form.NTSTU'};
-
- my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
- my %keyhash = ();
- $ENV{'form.keywords'} =~ s/,\s{0,}|\s+/ /g;
- $keyhash{$symb.'_handgrade'} = 'activated';
- $keyhash{$symb.'_keywords'} = $ENV{'form.keywords'};
- $keyhash{$symb.'_subject'} = $ENV{'form.msgsub'};
- $keyhash{$loginuser.'_kwclr'} = $ENV{'form.kwclr'};
- $keyhash{$loginuser.'_kwsize'} = $ENV{'form.kwsize'};
- $keyhash{$loginuser.'_kwstyle'} = $ENV{'form.kwstyle'};
-
- my ($ctr,$idx) = (1,1);
- while ($ctr <= $ENV{'form.savemsgN'}) {
- if ($ENV{'form.savemsg'.$ctr} ne '') {
- $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.savemsg'.$ctr};
- $idx++;
- }
- $ctr++;
- }
- $ctr = 0;
- while ($ctr < $ngrade) {
- if ($ENV{'form.newmsg'.$ctr} ne '') {
- $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};
- $ENV{'form.savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};
- $idx++;
- }
- $ctr++;
- }
- $ENV{'form.savemsgN'} = --$idx;
- $keyhash{$symb.'_savemsgN'} = $ENV{'form.savemsgN'};
- my $putresult = &Apache::lonnet::put
- ('nohist_handgrade',\%keyhash,
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
-
- my (@parts) = sort(&getpartlist($url));
-
- if ($button eq 'Save & Next') {
- my $ctr = 0;
- while ($ctr < $ngrade) {
- my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
- &saveHandGrade($url,$symb,$uname,$udom,$ctr,@parts);
-
- my $includemsg = $ENV{'form.includemsg'.$ctr};
- my ($subject,$message,$msgstatus) = ('','','');
- if ($includemsg =~ /savemsg|new$ctr/) {
- $subject = $ENV{'form.msgsub'} if ($includemsg =~ /^msgsub/);
- my (@msgnum) = split(/,/,$includemsg);
- foreach (@msgnum) {
- $message.=$ENV{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');
- }
- $message =~ s/\s+/ /g;
- $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,$ENV{'form.msgsub'},$message);
- }
- if ($ENV{'form.collaborator'.$ctr}) {
- my (@collaborators) = split(/:/,$ENV{'form.collaborator'.$ctr});
- foreach (@collaborators) {
- &saveHandGrade($url,$symb,$_,$udom,$ctr,@parts);
- if ($message ne '') {
- $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,$ENV{'form.msgsub'},$message);
- }
- }
- }
- $ctr++;
- }
- }
- my $firststu = $ENV{'form.unamedom0'};
- my $laststu = $ENV{'form.unamedom'.($ngrade-1)};
+ $result='
'.
+ $viewgrade.
+ ' Submissions for a Student or a Group of Students
'.
+ '
'.
+ 'Resource: '.$url.'
'.$result;
- my ($classlist) = &getclasslist($ENV{'form.section'},'0');
- my (@nextlist,@prevlist);
- my ($nextflg,$prevflg,$ctr,$ctprev) = (0,0,0,0);
- foreach my $student ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {
- my ($uname,$udom) = split(/:/,$student);
- my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname);
- next if ($status eq 'nothing' && $ENV{'form.submitonly'} eq 'yes');
-
- if ($nextflg == 1 && $button =~ /Next$/) {
- push @nextlist,$uname if ($ctr < $ntstu);
- $ctr++;
- }
- $nextflg = 1 if ($student eq $laststu);
- $prevflg = 1 if ($student eq $firststu);
- if ($prevflg == 0 && $button eq 'Previous') {
- push @prevlist,$uname;
- $ctprev++;
- }
- }
- if ($button eq 'Previous') {
- if ($ctprev <= $ntstu) {
- @nextlist = @prevlist;
- } else {
- my $idx = 0;
- my $start = $ctprev - $ntstu;
- while ($idx < $ntstu) {
- $nextlist[$idx] = $prevlist[$start+$idx];
- $idx++;
+ $request->print(<
+ function checkSelect(checkBox) {
+ var ctr=0;
+ var sense="";
+ if (checkBox.length > 1) {
+ for (var i=0; iLON-CAPA User Message '."\n";
- $the_end.='Message: No more students for this section or class.
'."\n";
- $the_end.='Click on the button below to return to the grading menu.
'."\n";
- $the_end.=&show_grading_menu_form ($symb,$url);
- $request->print($the_end);
- }
- return '';
-}
-
-sub saveHandGrade {
- my ($url,$symb,$stuname,$domain,$newflg,@parts) = @_;
- my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
- my %newrecord;
-
- foreach my $part (@parts) {
- my ($temp,$part,$type)=split(/_/,$part);
- my $oldscore=$record{"resource.$part.$type"};
- my $newscore;
- if ($type eq 'awarded' && $newflg >= 0) {
- my $pts = ($ENV{'form.GRADE_BOX'.$newflg} ne '' ?
- $ENV{'form.GRADE_BOX'.$newflg} : $ENV{'form.RADVAL'.$newflg});
- my $wgt = $ENV{'form.WGT'.$newflg};
-# my $sel = $ENV{'form.GRADE_SEL'.$newflg};
- $newscore = $pts/$wgt if ($wgt != 0);
- }
- if ($type eq 'solved') {
- $newscore = $ENV{'form.GRADE_SEL'.$newflg} if ($newflg >= 0);
- my $update=0;
- if ($newscore eq 'nothing' ) {
- if ($oldscore ne '') {
- $update=1;
- $newscore = '';
- }
- } elsif ($oldscore !~ m/^$newscore/) {
- $update=1;
- if ($newscore eq 'correct') { $newscore = 'correct_by_override'; }
- if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }
- if ($newscore eq 'excused') { $newscore = 'excused'; }
- if ($newscore eq 'ungraded') { $newscore = 'ungraded_attempted'; }
- if ($newscore eq 'partial') { $newscore = 'correct_partially_by_override'; }
- }
- if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
+ }
+ sense = "a student or group of students";
} else {
- if ($oldscore ne $newscore) {
- $newrecord{"resource.$part.$type"}=$newscore;
- }
+ if (checkBox.checked) {
+ ctr = 1;
+ }
+ sense = "the student";
+ }
+ if (ctr == 0) {
+ alert("Please select "+sense+" before clicking on the $viewgrade button.");
+ return false;
}
+ document.gradesub.submit();
}
- if ( scalar(keys(%newrecord)) > 0 ) {
- $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
-# while (my ($k,$v) = each %newrecord) {
-# print "k=$k:v=$v: \n";
-# }
-# print "symb=$symb,courseid=$ENV{'request.course.id'},dom=$domain,name=$stuname ";
-# &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$stuname);
- }
- return '';
-}
-
-sub get_symb_and_url {
- my ($request) = @_;
- (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 '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
- return ($symb,$url);
-}
-
-sub show_grading_menu_form {
- my ($symb,$url)=@_;
- my $result.='
'."\n";
- return $result;
-}
-
-sub viewgrades {
- my ($request) = @_;
- my $result='';
+ my $gradeTable='
'."\n".
+ ' View Problem: no '."\n".
+ ' yes '."\n".
+ ' Submissions: '."\n";
+ if ($ENV{'form.handgrade'} eq 'yes') {
+ $gradeTable.=' handgrade only'."\n";
+ }
+ $gradeTable.=' last sub only'."\n".
+ ' last sub & parts info'."\n".
+ ' all details'."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n".
+ ' '."\n".
+ ' '."\n".
+ ''."\n".
+ ''."\n".
+ 'To '.lc($viewgrade).' a submission, click on the check box next to the student\'s name. Then '."\n".
+ 'click on the '.$viewgrade.' button. To view the submissions for a group of students, click'."\n".
+ ' on the check boxes for the group of students. '."\n".
+ ''."\n".
+ ''."\n";
+
+ my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
+
+ $gradeTable.='
';
- return $result;
+#---- Called from the listStudents routine
+# Displays the submissions for one student or a group of students
+sub processGroup {
+ my ($request) = shift;
+ my $ctr = 0;
+ my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
+ : ($ENV{'form.stuinfo'}));
+ my $total = scalar(@stuchecked)-1;
+
+ foreach (@stuchecked) {
+ my ($uname,$udom,$fullname) = split(/:/);
+ $ENV{'form.student'} = $uname;
+ $ENV{'form.userdom'} = $udom;
+ $ENV{'form.fullname'} = $fullname;
+ &submission($request,$ctr,$total);
+ $ctr++;
+ }
+ return '';
}
+#------------------------------------------------------------------------------------
+#
+#-------------------------- Next few routines handles grading by student, essentially
+# handles essay response type problem/part
+#
+#--- Javascript to handle the submission page functionality ---
sub sub_page_js {
- my $request = shift;
- $request->print(<print(<
- function updateRadio(radioButton,formtextbox,formsel,wgt) {
+ function updateRadio(radioButton,formtextbox,formsel,scores,weight) {
var pts = formtextbox.value;
var resetbox =false;
if (isNaN(pts) || pts < 0) {
- alert("A number equal or greater than 0 is expected. Entered value = "+pts);
- for (var i=0; i weight) {
+ var resp = confirm("You entered a value ("+pts+
+ ") greater than the weight for the part. Accept?");
+ if (resp == false) {
+ formtextbox.value = "";
+ return;
+ }
}
for (var i=0; i 0 && pts < wgt) {
- formsel[4].selected = true;
+ function clearRadBox(radioButton,formbox,formsel,scores) {
+ for (var i=0; i"+msgchk);
re = /msgsub/;
var shwsel = "";
if (re.test(msgchk)) { shwsel = "checked" }
@@ -1166,7 +676,6 @@ sub sub_page_js {
pWin.document.write(" var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);");
pWin.document.write(" includemsg.value = msgchk;");
-// pWin.document.write(" alert(\\"slected=\\"+msgchk)");
pWin.document.write(" self.close()");
pWin.document.write("}");
@@ -1202,7 +711,7 @@ function displaySavedMsg(ctr,msg,shwsel)
pWin.document.write("
");
pWin.document.write("
New
");
pWin.document.write("
");
- pWin.document.write("
");
+ pWin.document.write("
");
}
function msgTail() {
@@ -1252,10 +761,14 @@ function displaySavedMsg(ctr,msg,shwsel)
hwdWin.document.write("Highlight Central");
hwdWin.document.write("
+VIEWJAVASCRIPT
+}
+
+#--- show scores for a section or whole class w/ option to change/update a score
+sub viewgrades {
+ my ($request) = shift;
+ &viewgrades_js($request);
+
+ my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'});
+ my $result='
Manual Grading
';
+
+ $result.='Resource: '.$ENV{'form.url'}.''."\n";
+
+ #view individual student submission form - called using Javascript viewOneStudent
+ $result.=&jscriptNform($url,$symb);
+
+ #beginning of class grading form
+ $result.= '
'."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n";
+ $result.='To assign the same score for all the students use the radio buttons or '.
+ 'text box below. To assign scores individually fill in the score boxes for '.
+ 'each student in the table below. A part that has already '.
+ 'been graded does not get changed using the radio buttons or text box. '.
+ 'If needed, it has to be changed individually.';
+
+ #radio buttons/text box for assigning points for a section or class.
+ #handles different parts of a problem
+ my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
+ my %weight = ();
+ my $ctsparts = 0;
+ $result.='
';
+ my %seen = ();
+ for (sort keys(%$handgrade)) {
+ my ($partid,$respid) = split (/_/);
+ next if $seen{$partid};
+ $seen{$partid}++;
+ my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+ my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
+ $weight{$partid} = $wgt eq '' ? '1' : $wgt;
+
+ $result.=''."\n";
+ $result.=''."\n";
+ $result.='
Part '.$partid.' Point:
';
+ $result.='
';
+ my $ctr = 0;
+ while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
+ $result.= '
'.$ctr."
\n";
+ $result.=(($ctr+1)%10 == 0 ? '
' : '');
+ $ctr++;
+ }
+ $result.='
';
+ $result.= '
or /'.
+ $weight{$partid}.' (problem weight)
'."\n";
+ $result.= '
'.
+ ''.
+ '
'."\n";
+ $ctsparts++;
+ }
+ $result.='
';
+ $result.=' ';
+ $result.=''."\n";
+
+ #table listing all the students in a section/class
+ #header of table
+ $result.= '
'."\n".
+ '
'.
+ '
Fullname
Username
Domain
'."\n";
+ my (@parts) = sort(&getpartlist($url));
+ foreach my $part (@parts) {
+ my $display=&Apache::lonnet::metadata($url,$part.'.display');
+ next if ($display =~ /^Number of Attempts/);
+ if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
+ if ($display =~ /^Partial Credit Factor/) {
+ $_ = $display;
+ my ($partid) = /.*?(\d+).*/;
+ $result.='
Score Part '.$partid.' (weight = '.
+ $weight{$partid}.')
';
+
+ #get info for each student
+ #list all the students - with points and grade status
+ my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
+ my $ctr = 0;
+ foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
+ my ($uname,$udom) = split(/:/);
+ $result.=''."\n";
+ $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},
+ $_,$$fullname{$_},\@parts,\%weight);
+ $ctr++;
+ }
+ $result.='
';
+ $result.=''."\n";
+ $result.='
'."\n";
+ $result.=&show_grading_menu_form($symb,$url);
+ return $result;
+}
+
+#--- call by previous routine to display each student
+sub viewstudentgrade {
+ my ($url,$symb,$courseid,$student,$fullname,$parts,$weight) = @_;
+ my ($uname,$udom) = split(/:/,$student);
+ my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);
+ my $result='
';
+ return $result;
+}
+
+#--- change scores for all the students in a section/class
+# record does not get update if unchanged
+sub editgrades {
+ my ($request) = @_;
+
+ my $symb=$ENV{'form.symb'};
+ my $url =$ENV{'form.url'};
+ my $title='
'."\n";
+ my $msg = 'Number of records updated = '.$rec_update.
+ ' for '.$count.' student'.($count <= 1 ? '' : 's').'. '.
+ 'Total number of students = '.$ENV{'form.total'}.' ';
+ return $title.$msg.$result;
+}
+#------------- end of section for handling grading by section/class ---------
+#
+#----------------------------------------------------------------------------
+
+
+#----------------------------------------------------------------------------
+#
+#-------------------------- Next few routines handles grading by csv upload
+#
+#--- Javascript to handle csv upload
sub csvupload_javascript_reverse_associate {
return(<print(<';
+ $result.='
Resource: '.$url.'
';
+ my ($partlist,$handgrade) = &response_type($url);
+ my ($resptype,$hdgrade)=('','no');
+ for (sort keys(%$handgrade)) {
+ my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+ $resptype = $responsetype;
+ $hdgrade = $handgrade if ($handgrade eq 'yes');
+ $result.='
Part '.(split(/_/))[0].'
'.
+ '
Type: '.$responsetype.'
'.
+ '
Handgrade: '.$handgrade.'
';
+ }
+ $result.='';
+ $request->print(<
-
Uploading Class Grades for resource $url
+
Uploading Class Grades
+$result
Identify fields
Total number of records found in file: $distotal
@@ -1412,28 +1942,28 @@ to this page if the data selected is ins
$javascript
ENDPICK
- return '';
+return '';
}
sub csvupload_fields {
- my ($url) = @_;
- my (@parts) = &getpartlist($url);
- my @fields=(['username','Student Username'],['domain','Student Domain']);
- foreach my $part (sort(@parts)) {
- my @datum;
- my $display=&Apache::lonnet::metadata($url,$part.'.display');
- my $name=$part;
- if (!$display) { $display = $name; }
- @datum=($name,$display);
- push(@fields,\@datum);
- }
- return (@fields);
+ my ($url) = @_;
+ my (@parts) = &getpartlist($url);
+ my @fields=(['username','Student Username'],['domain','Student Domain']);
+ foreach my $part (sort(@parts)) {
+ my @datum;
+ my $display=&Apache::lonnet::metadata($url,$part.'.display');
+ my $name=$part;
+ if (!$display) { $display = $name; }
+ @datum=($name,$display);
+ push(@fields,\@datum);
+ }
+ return (@fields);
}
sub csvuploadmap_footer {
- my ($request,$i,$keyfields) =@_;
- $request->print(<print(<
@@ -1443,205 +1973,390 @@ ENDPICK
}
sub csvuploadmap {
- my ($request)= @_;
- my ($symb,$url)=&get_symb_and_url($request);
- if (!$symb) {return '';}
- my $datatoken;
- if (!$ENV{'form.datatoken'}) {
- $datatoken=&Apache::loncommon::upfile_store($request);
- } else {
- $datatoken=$ENV{'form.datatoken'};
- &Apache::loncommon::load_tmp_file($request);
- }
- my @records=&Apache::loncommon::upfile_record_sep();
- &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
- my $i;
- my $keyfields;
- if (@records) {
- my @fields=&csvupload_fields($url);
- if ($ENV{'form.upfile_associate'} eq 'reverse') {
- &Apache::loncommon::csv_print_samples($request,\@records);
- $i=&Apache::loncommon::csv_print_select_table($request,\@records,
- \@fields);
- foreach (@fields) { $keyfields.=$_->[0].','; }
- chop($keyfields);
+ my ($request)= @_;
+ my ($symb,$url)=&get_symb_and_url($request);
+ if (!$symb) {return '';}
+ my $datatoken;
+ if (!$ENV{'form.datatoken'}) {
+ $datatoken=&Apache::loncommon::upfile_store($request);
} else {
- unshift(@fields,['none','']);
- $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
- \@fields);
- my %sone=&Apache::loncommon::record_sep($records[0]);
- $keyfields=join(',',sort(keys(%sone)));
+ $datatoken=$ENV{'form.datatoken'};
+ &Apache::loncommon::load_tmp_file($request);
}
- }
- &csvuploadmap_footer($request,$i,$keyfields);
- return '';
+ my @records=&Apache::loncommon::upfile_record_sep();
+ &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
+ my ($i,$keyfields);
+ if (@records) {
+ my @fields=&csvupload_fields($url);
+
+ if ($ENV{'form.upfile_associate'} eq 'reverse') {
+ &Apache::loncommon::csv_print_samples($request,\@records);
+ $i=&Apache::loncommon::csv_print_select_table($request,\@records,
+ \@fields);
+ foreach (@fields) { $keyfields.=$_->[0].','; }
+ chop($keyfields);
+ } else {
+ unshift(@fields,['none','']);
+ $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
+ \@fields);
+ my %sone=&Apache::loncommon::record_sep($records[0]);
+ $keyfields=join(',',sort(keys(%sone)));
+ }
+ }
+ &csvuploadmap_footer($request,$i,$keyfields);
+ return '';
}
sub csvuploadassign {
- my ($request)= @_;
- my ($symb,$url)=&get_symb_and_url($request);
- if (!$symb) {return '';}
- &Apache::loncommon::load_tmp_file($request);
- my @gradedata=&Apache::loncommon::upfile_record_sep();
- my @keyfields = split(/\,/,$ENV{'form.keyfields'});
- my %fields=();
- for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
- if ($ENV{'form.upfile_associate'} eq 'reverse') {
- if ($ENV{'form.f'.$i} ne 'none') {
- $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
- }
+ my ($request)= @_;
+ my ($symb,$url)=&get_symb_and_url($request);
+ if (!$symb) {return '';}
+ &Apache::loncommon::load_tmp_file($request);
+ my @gradedata = &Apache::loncommon::upfile_record_sep();
+ my @keyfields = split(/\,/,$ENV{'form.keyfields'});
+ my %fields=();
+ for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
+ if ($ENV{'form.upfile_associate'} eq 'reverse') {
+ if ($ENV{'form.f'.$i} ne 'none') {
+ $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
+ }
+ } else {
+ if ($ENV{'form.f'.$i} ne 'none') {
+ $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
+ }
+ }
+ }
+ $request->print('
Assigning Grades
');
+ my $courseid=$ENV{'request.course.id'};
+ my ($classlist) = &getclasslist('all','1');
+ my @skipped;
+ my $countdone=0;
+ foreach my $grade (@gradedata) {
+ my %entries=&Apache::loncommon::record_sep($grade);
+ my $username=$entries{$fields{'username'}};
+ my $domain=$entries{$fields{'domain'}};
+ if (!exists($$classlist{"$username:$domain"})) {
+ push(@skipped,"$username:$domain");
+ next;
+ }
+ my %grades;
+ foreach my $dest (keys(%fields)) {
+ if ($dest eq 'username' || $dest eq 'domain') { next; }
+ if ($entries{$fields{$dest}} eq '') { next; }
+ my $store_key=$dest;
+ $store_key=~s/^stores/resource/;
+ $store_key=~s/_/\./g;
+ $grades{$store_key}=$entries{$fields{$dest}};
+ }
+ $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
+ &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
+ $domain,$username);
+ $request->print('.');
+ $request->rflush();
+ $countdone++;
+ }
+ $request->print(" Stored $countdone students\n");
+ if (@skipped) {
+ $request->print(' Skipped Students ');
+ foreach my $student (@skipped) { $request->print(" $student"); }
+ }
+ $request->print(&view_edit_entire_class_form($symb,$url));
+ $request->print(&show_grading_menu_form($symb,$url));
+ return '';
+}
+#------------- end of section for handling csv file upload ---------
+#
+#-------------------------------------------------------------------
+
+#-------------------------- Menu interface -------------------------
+#
+#--- Show a Grading Menu button - Calls the next routine ---
+sub show_grading_menu_form {
+ my ($symb,$url)=@_;
+ my $result.='
'."\n";
+ return $result;
+}
+
+#--- Displays the main menu page -------
+sub gradingmenu {
+ my ($request) = @_;
+ my ($symb,$url)=&get_symb_and_url($request);
+ if (!$symb) {return '';}
+ my $result='
Select a Grading Method
';
+ $result.='
';
+ $result.='
Resource: '.$url.'
';
+ my ($partlist,$handgrade) = &response_type($url);
+ my ($resptype,$hdgrade)=('','no');
+ for (sort keys(%$handgrade)) {
+ my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+ $resptype = $responsetype;
+ $hdgrade = $handgrade if ($handgrade eq 'yes');
+ $result.='
Part '.(split(/_/))[0].'
'.
+ '
Type: '.$responsetype.'
'.
+ '
Handgrade: '.$handgrade.'
';
+ }
+ $result.='
';
+ $result.=&view_edit_entire_class_form($symb,$url).' ';
+ $result.=&upcsvScores_form($symb,$url).' ';
+ $result.=&viewGradeaStu_form($symb,$url,$resptype,$hdgrade).' ';
+ $result.=&verifyReceipt_form($symb,$url)
+ if ((&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) && ($symb));
+
+ return $result;
+}
+
+#--- Menu for grading a section or the whole class ---
+sub view_edit_entire_class_form {
+ my ($symb,$url)=@_;
+ my ($classlist,$sections) = &getclasslist('all','0');
+ my $result.='
');
- my $courseid=$ENV{'request.course.id'};
-# my $cdom=$ENV{"course.$courseid.domain"};
-# my $cnum=$ENV{"course.$courseid.num"};
- my ($classlist) = &getclasslist('all','1');
- my @skipped;
- my $countdone=0;
- foreach my $grade (@gradedata) {
- my %entries=&Apache::loncommon::record_sep($grade);
- my $username=$entries{$fields{'username'}};
- my $domain=$entries{$fields{'domain'}};
- if (!exists($$classlist{"$username:$domain"})) {
- push(@skipped,"$username:$domain");
- next;
- }
- my %grades;
- foreach my $dest (keys(%fields)) {
- if ($dest eq 'username' || $dest eq 'domain') { next; }
- if ($entries{$fields{$dest}} eq '') { next; }
- my $store_key=$dest;
- $store_key=~s/^stores/resource/;
- $store_key=~s/_/\./g;
- $grades{$store_key}=$entries{$fields{$dest}};
- }
- $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
- &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
- $domain,$username);
- $request->print('.');
- $request->rflush();
- $countdone++;
- }
- $request->print(" Stored $countdone students\n");
- if (@skipped) {
- $request->print(' Skipped Students ');
- foreach my $student (@skipped) { $request->print(" $student"); }
- }
- $request->print(&view_edit_entire_class_form($symb,$url));
- $request->print(&show_grading_menu_form($symb,$url));
- return '';
+ $result.='an Individual Student\'s Submission
'."\n";
+ $result.='
'."\n";
+ $result.='
'."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n".
+ ''."\n";
+
+ $result.=' Select section: '."\n";
+ $result.=' Display students who has: '.
+ ' submitted'.
+ ' everybody ';
+ if (ref($sections)) {
+ $result.=' (Section "no" implies the students were not assigned a section.) '
+ if (grep /no/,@$sections);
+ }
+
+
+ $result.=' '."\n".'
'."\n";
+ $result.='
'."\n";
+ $result.='
'."\n";
+ return $result;
+}
+
+#--- Form to input a receipt number ---
+sub verifyReceipt_form {
+ my ($symb,$url) = @_;
+ my $result = ''."\n";
+
+ my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});
+
+ $result.='
'."\n";
+ $result.='
'."\n";
+ $result.=' Verify a Submission Receipt Issued by this Server