--- loncom/homework/grades.pm 2002/07/26 20:28:42 1.42
+++ loncom/homework/grades.pm 2002/08/06 20:46:30 1.46
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.42 2002/07/26 20:28:42 ng Exp $
+# $Id: grades.pm,v 1.46 2002/08/06 20:46:30 ng 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,74 +42,33 @@ 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
}
- return '';
+ return @parts;
}
-sub student_gradeStatus {
- my ($url,$udom,$uname,$partlist) = @_;
+# --- 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)));
- my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
- my %partstatus = ();
- foreach (@$partlist) {
- my ($status,$foo)=split(/_/,$record{"resource.$_.solved"},2);
- $status = 'nothing' if ($status eq '');
- $partstatus{$_} = $status;
- $partstatus{"resource.$_.submitted_by"} = $record{"resource.$_.submitted_by"}
- if ($record{"resource.$_.submitted_by"} ne '');
- }
- return %partstatus;
+ 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 ($uname,$udom) = @_;
my %name=&Apache::lonnet::get('environment', ['lastname','generation',
@@ -124,14 +83,15 @@ sub get_fullname {
return $fullname;
}
+#--- 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 ($url) = shift;
my $allkeys = &Apache::lonnet::metadata($url,'keys');
-# print "allkeys=>$allkeys ";
my %seen = ();
my (@partlist,%handgrade);
foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
- if (/^\w+response_\d{1,2}.*/) {
+ if (/^\w+response_\d+.*/) {
my ($responsetype,$part) = split(/_/,$_,2);
my ($partid,$respid) = split(/_/,$part);
$handgrade{$part} = $responsetype.':'.($allkeys =~ /parameter_$part\_handgrade/ ? 'yes' : 'no');
@@ -143,202 +103,717 @@ sub response_type {
return \@partlist,\%handgrade;
}
+#--- Dumps the class list with usernames,list of sections,
+#--- section, ids and fullnames for each user.
+sub getclasslist {
+ my ($getsec,$hideexpired) = @_;
+ my $now = time;
+ my %classlist=&Apache::lonnet::dump('classlist',
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+ # codes to check for fields in the classlist
+ # should contain end:start:id:section:fullname
+ for (keys %classlist) {
+ my (@fields) = split(/:/,$classlist{$_});
+ %classlist = &reformat_classlist(\%classlist) if (scalar(@fields) <= 2);
+ last;
+ }
+
+ my (@holdsec,@sections,%allids,%stusec,%fullname);
+ foreach (keys(%classlist)) {
+ my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
+ # still a student?
+ if (($hideexpired) && ($end) && ($end < $now)) {
+ next;
+ }
+ $section = ($section ne '' ? $section : 'no');
+ push @holdsec,$section;
+ if ($getsec eq 'all' || $getsec eq $section) {
+ push (@{ $classlist{$getsec} }, $_);
+ $allids{$_} =$id;
+ $stusec{$_} =$section;
+ $fullname{$_}=$fullname;
+ }
+ }
+ my %seen = ();
+ foreach my $item (@holdsec) {
+ push (@sections, $item) unless $seen{$item}++;
+ }
+ return (\%classlist,\@sections,\%allids,\%stusec,\%fullname);
+}
+
+# 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;
+ }
+ my $putresult = &Apache::lonnet::put
+ ('classlist',\%$classlist,
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+ return %$classlist;
+}
+
+#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 {
+ return ($ENV{'user.name'},$ENV{'user.domain'});
+ }
+}
+
+#--- Prompts a user to enter a username.
+sub moreinfo {
+ my ($request,$reason) = @_;
+ $request->print("Unable to process request: $reason");
+ if ( $Apache::grades::viewgrades eq 'F' ) {
+ $request->print('');
+ }
+ return '';
+}
+
+#--- Retrieve the grade status of a student for all the parts
+sub student_gradeStatus {
+ my ($url,$symb,$udom,$uname,$partlist) = @_;
+ my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
+ my %partstatus = ();
+ foreach (@$partlist) {
+ my ($status,$foo) = split(/_/,$record{"resource.$_.solved"},2);
+ $status = 'nothing' if ($status eq '');
+ $partstatus{$_} = $status;
+ my $subkey = "resource.$_.submitted_by";
+ $partstatus{$subkey} = $record{$subkey} if ($record{$subkey} ne '');
+ }
+ return %partstatus;
+}
+
+# hidden form and javascript that calls the form
+# Use by verifyscript and viewgrades
+# Shows a student's view of problem and submission
+sub jscriptNform {
+ my ($url,$symb) = @_;
+ my $jscript=''."\n";
+ $jscript.= ''."\n";
+ return $jscript;
+}
+
+#------------------ End of general use routines --------------------
+#-------------------------------------------------------------------
+
+#------------------------------------ Receipt Verification Routines
+#
+#--- Check whether a receipt number is valid.---
+sub verifyreceipt {
+ my $request = shift;
+
+ my $courseid = $ENV{'request.course.id'};
+ my $receipt = unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
+ $ENV{'form.receipt'};
+ $receipt =~ s/[^\-\d]//g;
+ my $url = $ENV{'form.url'};
+ my $symb = $ENV{'form.symb'};
+ unless ($symb) {
+ $symb = &Apache::lonnet::symbread($url);
+ }
+
+ my $title.='
Verifying Submission Receipt '.
+ $receipt.'
'."\n".
+ 'Resource: '.$ENV{'form.url'}.'
'."\n";
+
+ my ($string,$contents,$matches) = ('','',0);
+ my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0');
+
+ foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
+ my ($uname,$udom)=split(/\:/);
+ if ($receipt eq
+ &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
+ $contents.='
'."\n";
+
+ $matches++;
+ }
+ }
+ 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;
- 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'};
+ $request->print(<
+ function checkSelect(checkBox) {
+ var ctr=0;
+ var sense="";
+ if (checkBox.length > 1) {
+ for (var i=0; i
+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 $submitonly= $ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};
- my $result='
View Submissions for a Student or a Group of Students
';
+ my $result='
'.
+ 'View/Grade Submissions for a Student or a Group of Students
';
$result.='
';
- $result.='
Resource: '.$ENV{'form.url'}.'
';
+ $result.='
'.
+ 'Resource: '.$ENV{'form.url'}.'
';
my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
for (sort keys(%$handgrade)) {
my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
$ENV{'form.handgrade'} = 'yes' if ($handgrade eq 'yes');
- $result.='
Part id: '.$_.'
'.
+ $result.='
Part '.(split(/_/))[0].'
'.
'
Type: '.$responsetype.'
'.
'
Handgrade: '.$handgrade.'
';
}
$result.='
';
$request->print($result);
- $request->print(<
- View Problem: no
- yes
- Submissions:
- handgrade only
- last sub only
- last sub & parts info
- all details
-
-
-
-
-
-
-ENDTABLEST
- if ($ENV{'form.url'}) {
- $request->print(''."\n");
- }
- if ($ENV{'form.symb'}) {
- $request->print(''."\n");
- }
- $request->print(''."\n");
-
+ my $checkhdgrade = $ENV{'form.handgrade'} eq 'yes' ? 'checked' : '';
+ my $checklastsub = $ENV{'form.handgrade'} eq 'yes' ? '' : 'checked';
+
+ my $gradeTable='
'."\n";
+ if ($ctr == 0) {
+ $gradeTable=' '.
+ 'No submission found for this resource. ';
+ $gradeTable.=&show_grading_menu_form ($ENV{'form.symb'},$ENV{'form.url'});
+ } elsif ($ctr == 1) {
+ $gradeTable =~ s/type=checkbox/type=checkbox checked/;
+ }
+ $request->print($gradeTable);
+ return '';
}
+#---- 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;
- if ($stuchecked[0] eq '') {
- &userError($request,'No student was selected for viewing/grading.');
- return;
- }
+
foreach (@stuchecked) {
my ($uname,$udom,$fullname) = split(/:/);
- $ENV{'form.student'} = $uname;
- $ENV{'form.fullname'} = $fullname;
+ $ENV{'form.student'} = $uname;
+ $ENV{'form.userdom'} = $udom;
+ $ENV{'form.fullname'} = $fullname;
&submission($request,$ctr,$total);
$ctr++;
}
return '';
}
-sub userError {
- my ($request, $reason, $step) = @_;
- $request->print('
LON-CAPA User Error
'."\n");
- $request->print('Reason: '.$reason.'
'."\n");
- $request->print('Step: '.($step ne '' ? $step : 'Use your browser back button to correct')
- .'
'."\n");
- return '';
-}
-
-#FIXME - needs to handle multiple matches
-sub finduser {
- my ($name) = @_;
- my $domain = '';
- if ( $Apache::grades::viewgrades eq 'F' ) {
- my ($classlist) = &getclasslist('all','0');
- foreach ( sort(@{ $$classlist{'all'} }) ) {
- my ($posname,$posdomain) = split(/:/);
- if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
+#------------------------------------------------------------------------------------
+#
+#-------------------------- 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(<
+ 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;
+ }
}
-}
-sub getclasslist {
- my ($getsec,$hideexpired) = @_;
- my $now = time;
- my %classlist=&Apache::lonnet::dump('classlist',
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
- my (@holdsec,@sections,%allids,%stusec,%fullname);
- foreach (keys(%classlist)) {
- my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
- # still a student?
- if (($hideexpired) && ($end) && ($end < $now)) {
- next;
+ for (var i=0; iprint('
Key
Value
');
- for (sort keys (%$hash)) {
- $request->print('
'.$_.'
'.$$hash{$_}.'
');
+//===================== Script to add keyword(s) ==================
+ function getSel() {
+ if (document.getSelection) txt = document.getSelection();
+ else if (document.selection) txt = document.selection.createRange().text;
+ else return;
+ var cleantxt = txt.replace(new RegExp('([\\f\\n\\r\\t\\v ])+', 'g')," ");
+ if (cleantxt=="") {
+ alert("Please select a word or group of words from document and then click this link.");
+ return;
}
- $request->print('
');
- return '';
+ var nret = prompt("Add selection to keyword list? Edit if desired.",cleantxt);
+ if (nret==null) return;
+ var curlist = document.SCORE.keywords.value;
+ document.SCORE.keywords.value = curlist+" "+nret;
+ document.SCORE.refresh.value = "on";
+ if (document.SCORE.keywords.value != "") {
+ document.SCORE.submit();
+ }
+ return;
+ }
+
+//====================== Script for composing message ==============
+ function msgCenter(msgform,usrctr,fullname) {
+ var Nmsg = msgform.savemsgN.value;
+ savedMsgHeader(Nmsg,usrctr,fullname);
+ var subject = msgform.msgsub.value;
+ var rtrchk = eval("document.SCORE.includemsg"+usrctr);
+ var msgchk = rtrchk.value;
+ re = /msgsub/;
+ var shwsel = "";
+ if (re.test(msgchk)) { shwsel = "checked" }
+ displaySubject(subject,shwsel);
+ for (var i=1; i<=Nmsg; i++) {
+ var testpt = "savemsg"+i+",";
+ re = /testpt/;
+ shwsel = "";
+ if (re.test(msgchk)) { shwsel = "checked" }
+ var message = eval("document.SCORE.savemsg"+i+".value");
+ displaySavedMsg(i,message,shwsel);
+ }
+ newmsg = eval("document.SCORE.newmsg"+usrctr+".value");
+ shwsel = "";
+ re = /newmsg/;
+ if (re.test(msgchk)) { shwsel = "checked" }
+ newMsg(newmsg,shwsel);
+ msgTail();
+ return;
+ }
+
+ function savedMsgHeader(Nmsg,usrctr,fullname) {
+ var height = 30*Nmsg+250;
+ var scrollbar = "no";
+ if (height > 600) {
+ height = 600;
+ scrollbar = "yes";
+ }
+/* if (window.pWin)
+ window.pWin.close(); */
+ pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx=70,screeny=75,width=600,height='+height);
+ pWin.document.write("");
+ pWin.document.write("Message Central");
+
+ pWin.document.write("
+SUBJAVASCRIPT
+}
+
+
+# --------------------------- 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 ''; }
+# if ($ENV{'form.student'} eq '') { &moreinfo($request,'Need student login id'); return ''; }
+ my ($uname,$udom) = ($ENV{'form.student'},$ENV{'form.userdom'});
+ ($uname,$udom) = &finduser($uname) if $udom eq '';
+ $ENV{'form.fullname'} = &get_fullname ($uname,$udom) if $ENV{'form.fullname'} eq '';
+# 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 ''; }
@@ -349,11 +824,11 @@ sub submission {
# header info
if ($counter == 0) {
&sub_page_js($request);
- $request->print('
Submission Record
'.
- ' Resource: '.$url.'');
+ $request->print('
Submission Record
'."\n".
+ ' Resource: '.$url.''."\n");
- # option to display problem, only once else it cause problems with the form later
- # since the problem has a form.
+ # 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'});
@@ -361,14 +836,16 @@ sub submission {
$ENV{'request.course.id'});
my $result.='
';
$result.='
';
- $result.='Student\'s view of the problem
'.$rendered.' ';
+ $result.=' View of the problem - '.$ENV{'form.fullname'}.
+ '
';
$request->print($result);
}
- # kwclr is the only variable that is guaranteed to be non blank if this subroutine has been called once.
+ # kwclr is the only variable that is guaranteed to be non blank
+ # if this subroutine has been called once.
my %keyhash = ();
if ($ENV{'form.kwclr'} eq '') {
%keyhash = &Apache::lonnet::dump('nohist_handgrade',
@@ -385,6 +862,7 @@ sub submission {
$ENV{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
}
+
$request->print('
'."\n".
''."\n".
''."\n".
@@ -425,31 +903,37 @@ sub submission {
KEYWORDS
}
}
+
my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
my ($partlist,$handgrade) = &response_type($url);
-# &print_hash($request,\%record);
- # Student info
+ # Display student info
$request->print(($counter == 0 ? '' : ' '));
- my $fullname = ($ENV{'form.fullname'} ne '' ? $ENV{'form.fullname'} : &get_fullname($uname,$udom));
- my $result='
'.
- '
';
-
- $result.='
Fullname: '.$fullname.
- '
Username: '.$uname.
- '
Domain: '.$udom.'
';
+ my $result='
'."\n".
+ '
'."\n";
+
+ $result.='Fullname: '.$ENV{'form.fullname'}.
+ ' Username: '.$uname.''.
+ ' Domain: '.$udom.' '."\n";
+ $result.=''."\n";
+
+ # If this is handgraded, then check for collaborators
+ my @col_fullnames;
if ($ENV{'form.handgrade'} eq 'yes') {
my @col_list;
($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0');
for (keys (%$handgrade)) {
- my $ncol = &Apache::lonnet::EXT('resource.'.$_.'.maxcollaborators',$symb,$udom,$uname);
+ my $ncol = &Apache::lonnet::EXT('resource.'.$_.
+ '.maxcollaborators',$symb,$udom,$uname);
if ($ncol > 0) {
s/\_/\./g;
if ($record{'resource.'.$_.'.collaborators'} ne '') {
- my (@collaborators) = split(/,?\s+/,$record{'resource.'.$_.'.collaborators'});
+ my (@collaborators) = split(/,?\s+/,
+ $record{'resource.'.$_.'.collaborators'});
my (@badcollaborators);
if (scalar(@collaborators) != 0) {
- $result.='
'."\n");
+ $request->print($result."\n");
- # print student answer
+ # print student answer/submission
+ # Options are (1) Handgaded submission only
+ # (2) Last submission, includes submission that is not handgraded
+ # (for multi-response type part)
+ # (3) Last submission plus the parts info
+ # (4) The whole record for this student
if ($ENV{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {
if ($ENV{'form.'.$uname.':'.$udom.':submitted_by'}) {
- my $submitby='
'."\n");
+ $result=''."\n";
+ my $ctr = 0;
+ while ($ctr < scalar(@partlist)) {
+ $result.=''."\n";
+ $ctr++;
+ }
+ $request->print($result.''."\n");
# print end of form
if ($counter == $total) {
- my $endform.='
';
- my $ntstu =''."\n";
- my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');
- $ntstu =~ s/
';
+ my $endform='
'.
+ ''."\n";
+ if ($ENV{'form.handgrade'} eq 'yes') {
+ $endform.=' '."\n";
+ my $ntstu =''."\n";
+ my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');
+ $ntstu =~ s/
';
$request->print($endform);
}
return '';
}
+#--- Retrieve the last submission for all the parts
sub get_last_submission {
- my ($symb,$username,$domain,$course)=@_;
- if ($symb) {
- my (@string,$timestamp);
- my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);
- if ($returnhash{'version'}) {
- my %lasthash=();
- my ($version);
- for ($version=1;$version<=$returnhash{'version'};$version++) {
- foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
- $lasthash{$_}=$returnhash{$version.':'.$_};
- }
+ my (%returnhash)=@_;
+ my (@string,$timestamp);
+ if ($returnhash{'version'}) {
+ my %lasthash=();
+ my ($version);
+ for ($version=1;$version<=$returnhash{'version'};$version++) {
+ foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
+ $lasthash{$_}=$returnhash{$version.':'.$_};
+ if ($returnhash{$version.':'.$_} =~ /(SUBMITTED|DRAFT)$/) {
+ $timestamp = scalar(localtime($returnhash{$version.':timestamp'}));
+ }
}
- foreach ((keys %lasthash)) {
- if ($_ =~ /\.submission$/) {push @string, (join(':',$_,$lasthash{$_}))}
- if ($_ =~ /timestamp/) {$timestamp = scalar(localtime($lasthash{$_}))};
+ }
+ foreach ((keys %lasthash)) {
+ if ($_ =~ /\.submission$/) {
+ my ($partid,$foo) = split(/submission$/,$_);
+ my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ?
+ 'Draft Copy ' : '';
+ push @string, (join(':',$_,$draft.$lasthash{$_}));
}
}
- @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
- return \@string,\$timestamp;
}
+ @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
+ return \@string,\$timestamp;
}
+#--- High light keywords, with style choosen by user.
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 $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'});
+ my @keylist = split(/[,\s+]/,$ENV{'form.keywords'});
foreach (@keylist) {
$string =~ s/\b$_(\b|\.)/\$styleon$_$styleoff\<\/font\>/gi;
}
return $string;
}
+#--- Called from submission routine
sub processHandGrade {
my ($request) = shift;
my $url = $ENV{'form.url'};
@@ -649,16 +1183,56 @@ sub processHandGrade {
my $ngrade = $ENV{'form.NCT'};
my $ntstu = $ENV{'form.NTSTU'};
+ if ($button eq 'Save & Next') {
+ my $ctr = 0;
+ while ($ctr < $ngrade) {
+ my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
+ my ($errorflag) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr);
+
+ 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($request,$url,$symb,$_,$udom,$ctr,
+ $ENV{'form.unamedom'.$ctr});
+ if ($message ne '') {
+ $msgstatus = &Apache::lonmsg::user_normal_msg ($_,$udom,
+ $ENV{'form.msgsub'},
+ $message);
+ }
+ }
+ }
+ $ctr++;
+ }
+ }
+
+ # Keywords sorted in alphabatical order
my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
my %keyhash = ();
$ENV{'form.keywords'} =~ s/,\s{0,}|\s+/ /g;
$ENV{'form.keywords'} =~ s/^\s+|\s+$//;
+ my (@keywords) = sort(split(/\s+/,$ENV{'form.keywords'}));
+ $ENV{'form.keywords'} = join(' ',@keywords);
$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'};
+ # message center - Order of message gets changed. Blank line is eliminated.
+ # New messages are saved in ENV for the next student.
+ # All messages are saved in nohist_handgrade.db
my ($ctr,$idx) = (1,1);
while ($ctr <= $ENV{'form.savemsgN'}) {
if ($ENV{'form.savemsg'.$ctr} ne '') {
@@ -683,51 +1257,19 @@ sub processHandGrade {
$ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
$ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+ # Called by Save & Refresh from Highlight Attribute Window
if ($ENV{'form.refresh'} eq 'on') {
my $ctr = 0;
$ENV{'form.NTSTU'}=$ngrade;
while ($ctr < $ngrade) {
- ($ENV{'form.student'},my $udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
+ ($ENV{'form.student'},$ENV{'form.userdom'}) = split(/:/,$ENV{'form.unamedom'.$ctr});
&submission($request,$ctr,$ngrade-1);
$ctr++;
}
return '';
}
- if ($button eq 'Save & Next') {
- my $ctr = 0;
- while ($ctr < $ngrade) {
- my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
- my ($errorflg) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr);
- return '' if ($errorflg eq 'error');
-
- 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($request,$url,$symb,$_,$udom,$ctr,
- $ENV{'form.unamedom'.$ctr});
- if ($message ne '') {
- $msgstatus = &Apache::lonmsg::user_normal_msg ($_,$udom,
- $ENV{'form.msgsub'},
- $message);
- }
- }
- }
- $ctr++;
- }
- }
+ # Get the next/previous one or group of students
my $firststu = $ENV{'form.unamedom0'};
my $laststu = $ENV{'form.unamedom'.($ngrade-1)};
$ctr = 2;
@@ -736,11 +1278,11 @@ sub processHandGrade {
$ctr++;
$laststu = $firststu if ($ctr > $ngrade);
}
- my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
+ my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
my (@parsedlist,@nextlist);
my ($nextflg) = 0;
- foreach ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {
+ foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
if ($nextflg == 1 && $button =~ /Next$/) {
push @parsedlist,$_;
}
@@ -756,11 +1298,11 @@ sub processHandGrade {
foreach my $student (@parsedlist) {
my ($uname,$udom) = split(/:/,$student);
if ($ENV{'form.submitonly'} eq 'yes') {
- my (%status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname,$partlist) ;
+ my (%status) = &student_gradeStatus($ENV{'form.url'},$symb,$udom,$uname,$partlist) ;
my $statusflg = '';
foreach (keys(%status)) {
$statusflg = 1 if ($status{$_} ne 'nothing');
- my ($foo,$partid,$foo) = split(/\./,$_);
+ my ($foo,$partid,$foo1) = split(/\./);
$statusflg = '' if ($status{'resource.'.$partid.'.submitted_by'} ne '');
}
next if ($statusflg eq '');
@@ -774,7 +1316,8 @@ sub processHandGrade {
foreach (sort @nextlist) {
my ($uname,$udom,$submitter) = split(/:/);
- $ENV{'form.student'} = $uname;
+ $ENV{'form.student'} = $uname;
+ $ENV{'form.userdom'} = $udom;
$ENV{'form.fullname'} = $$fullname{$_};
# $ENV{'form.'.$_.':submitted_by'} = $submitter;
# print "submitter=$ENV{'form.'.$_.':submitted_by'}= $submitter: ";
@@ -791,244 +1334,56 @@ sub processHandGrade {
return '';
}
+#---- Save the score and award for each student, if changed
sub saveHandGrade {
my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter) = @_;
-# my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
+ my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
my %newrecord;
foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
- if ($ENV{'form.GRADE_SEL'.$newflg.'_'.$_} eq 'excused') {
- $newrecord{'resource.'.$_.'.solved'} = 'excused';
+ if ($ENV{'form.GD_SEL'.$newflg.'_'.$_} eq 'excused') {
+ $newrecord{'resource.'.$_.'.solved'} = 'excused'
+ if ($record{'resource.'.$_.'.solved'} ne 'excused');
} else {
- my $pts = ($ENV{'form.GRADE_BOX'.$newflg.'_'.$_} ne '' ?
- $ENV{'form.GRADE_BOX'.$newflg.'_'.$_} : $ENV{'form.RADVAL'.$newflg.'_'.$_});
- if ($pts eq '') {
- &userError($request,'No point was assigned for part id '.$_.' and for username '.$stuname.'.');
- return 'error';
- }
- my $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : $ENV{'form.WGT'.$newflg.'_'.$_};
+ my $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ?
+ $ENV{'form.GD_BOX'.$newflg.'_'.$_} :
+ $ENV{'form.RADVAL'.$newflg.'_'.$_});
+ my $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 :
+ $ENV{'form.WGT'.$newflg.'_'.$_};
my $partial= $pts/$wgt;
- $newrecord{'resource.'.$_.'.awarded'} = $partial;
+ $newrecord{'resource.'.$_.'.awarded'} = $partial
+ if ($record{'resource.'.$_.'.awarded'} ne $partial);
+ my $reckey = 'resource.'.$_.'.solved';
if ($partial == 0) {
- $newrecord{'resource.'.$_.'.solved'} = 'incorrect_by_override';
+ $newrecord{$reckey} = 'incorrect_by_override'
+ if ($record{$reckey} ne 'incorrect_by_override');
} else {
- $newrecord{'resource.'.$_.'.solved'} = 'correct_by_override';
+ $newrecord{$reckey} = 'correct_by_override'
+ if ($record{$reckey} ne 'correct_by_override');
}
- $newrecord{'resource.'.$_.'.submitted_by'} = $submitter if ($submitter);
+ $newrecord{'resource.'.$_.'.submitted_by'} = $submitter
+ if ($submitter && ($record{'resource.'.$_.'.submitted_by'} ne $submitter));
}
}
-
- if ( scalar(keys(%newrecord)) > 0 ) {
+
+ if (scalar(keys(%newrecord)) > 0) {
$newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
-# &print_hash($request,\%newrecord);
- &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$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;
-}
-
+#--------------------------------------------------------------------------------------
+#
+#-------------------------- Next few routines handles grading by section or whole class
+#
+#--- Javascript to handle grading by section or whole class
sub viewgrades_js {
my ($request) = shift;
$request->print(<
- function viewOneStudent(user) {
- document.onestudent.student.value = user;
- document.onestudent.submit();
- }
-
- function writePoint(partid,weight,point) {
+ function writePoint(partid,weight,point) {
var radioButton = eval("document.classgrade.RADVAL_"+partid);
var textbox = eval("document.classgrade.TEXTVAL_"+partid);
if (point == "textval") {
@@ -1047,6 +1402,14 @@ sub viewgrades_js {
}
return;
}
+ if (point > weight) {
+ var resp = confirm("You entered a value ("+point+
+ ") greater than the weight for the part. Accept?");
+ if (resp == false) {
+ textbox.value = "";
+ return;
+ }
+ }
for (var i=0; i weight) {
+ var resp = confirm("You entered a value ("+point+
+ ") greater than the weight of the part. Accept?");
+ if (resp == false) {
+ textbox.value = "";
+ return;
+ }
+ }
selval[0].selected = true;
}
function changeOneScore(partid,user) {
- var selval = eval("document.classgrade.GRADE_"+user+'_'+partid+"_solved");
+ var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
if (selval[1].selected) {
- var boxval = eval("document.classgrade.GRADE_"+user+'_'+partid+"_awarded");
+ var boxval = eval("document.classgrade.GD_"+user+'_'+partid+"_aw");
boxval.value = "";
}
}
@@ -1127,72 +1524,74 @@ sub viewgrades_js {
selval[0].selected = true;
for (i=0;i
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'});
- $request->print ('
Manual Grading
');
+ my $result='
Manual Grading
';
- my $result='Resource: '.$ENV{'form.url'}.''."\n";
+ $result.='Resource: '.$ENV{'form.url'}.''."\n";
#view individual student submission form - called using Javascript viewOneStudent
- $result.= '
'."\n";
+ $result.=&jscriptNform($url,$symb);
- #start the form
+ #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 score that has already '.
+ '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 ($responsetype,$handgrade)=split(/:/,$$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.='
';
my $ctr = 0;
while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
@@ -1203,8 +1602,10 @@ sub viewgrades {
$ctr++;
}
$result.='
';
- $result.= '
or /'.
+ $result.= '
or /'.
$weight{$partid}.' (problem weight)
'."\n";
$result.= '
'.
@@ -1214,13 +1615,15 @@ sub viewgrades {
}
$result.='
';
$result.='   ';
- $result.= ''."\n";
+ 'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self> ';
+ $result.=''."\n";
+ #table listing all the students in a section/class
+ #header of table
$result.= '
'."\n".
'
'.
- '
Username
Fullname
Domain
'."\n";
- #get list of parts for this problem
+ '
Fullname
Username
Domain
'."\n";
my (@parts) = sort(&getpartlist($url));
foreach my $part (@parts) {
my $display=&Apache::lonnet::metadata($url,$part.'.display');
@@ -1237,30 +1640,35 @@ sub viewgrades {
$result.='
'.$display.'
'."\n";
}
$result.='
';
+
#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(@{ $$classlist{$ENV{'form.section'}} }) ) {
- (my $username = $_) = split(/:/);
- $result.=''."\n";
+ 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.='
';
+ $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 ($username,$domain) = split(/:/,$student);
- my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);
+ my ($uname,$udom) = split(/:/,$student);
+ my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);
my $result='