Annotation of loncom/homework/grades.pm, revision 1.34
1.17 albertel 1: # The LearningOnline Network with CAPA
1.13 albertel 2: # The LON-CAPA Grading handler
1.17 albertel 3: #
1.34 ! ng 4: # $Id: grades.pm,v 1.33 2002/06/27 21:34:18 ng Exp $
1.17 albertel 5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: #
10: # LON-CAPA is free software; you can redistribute it and/or modify
11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
14: #
15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
27: #
1.13 albertel 28: # 2/9,2/13 Guy Albertelli
1.8 www 29: # 6/8 Gerd Kortemeyer
1.13 albertel 30: # 7/26 H.K. Ng
1.14 www 31: # 8/20 Gerd Kortemeyer
1.30 ng 32: # Year 2002
33: # June 2002 H.K. Ng
34: #
1.1 albertel 35:
36: package Apache::grades;
37: use strict;
38: use Apache::style;
39: use Apache::lonxml;
40: use Apache::lonnet;
1.3 albertel 41: use Apache::loncommon;
1.1 albertel 42: use Apache::lonhomework;
43: use Apache::Constants qw(:common);
44:
1.2 albertel 45: sub moreinfo {
1.13 albertel 46: my ($request,$reason) = @_;
47: $request->print("Unable to process request: $reason");
48: if ( $Apache::grades::viewgrades eq 'F' ) {
49: $request->print('<form action="/adm/grades" method="post">'."\n");
1.16 albertel 50: if ($ENV{'form.url'}) {
51: $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
52: }
53: if ($ENV{'form.symb'}) {
54: $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
55: }
56: $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n");
57: $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n");
58: $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n");
59: $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");
1.13 albertel 60: $request->print('</form>');
61: }
62: return '';
1.2 albertel 63: }
64:
1.23 www 65: sub verifyreceipt {
66: my $request=shift;
67: my $courseid=$ENV{'request.course.id'};
1.34 ! ng 68: # my $cdom=$ENV{"course.$courseid.domain"};
! 69: # my $cnum=$ENV{"course.$courseid.num"};
1.23 www 70: my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
71: $ENV{'form.receipt'};
72: $receipt=~s/[^\-\d]//g;
73: my $symb=$ENV{'form.symb'};
74: unless ($symb) {
75: $symb=&Apache::lonnet::symbread($ENV{'form.url'});
76: }
77: if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {
78: $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');
79: my $matches=0;
1.34 ! ng 80: my ($classlist) = &getclasslist('all','0');
! 81: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1.23 www 82: my ($uname,$udom)=split(/\:/,$student);
83: if ($receipt eq
84: &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
85: $request->print('Matching '.$student.'<br>');
86: $matches++;
87: }
88: }
1.30 ng 89: $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');
1.33 ng 90: # needs to print who is matched
1.23 www 91: }
92: return '';
93: }
1.13 albertel 94:
1.32 ng 95: sub student_gradeStatus {
96: my ($url,$udom,$uname) = @_;
97: my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
98: my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
99: foreach my $part (&getpartlist($url)) {
100: my ($temp,$part,$type)=split(/_/,$part);
101: if ($type eq 'solved') {
102: my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);
1.34 ! ng 103: $status = 'partial' if ($foo =~ /^partially/);
1.32 ng 104: $status = 'nothing' if ($status eq '');
105: return $type,$status;
106: }
107: }
108: return '';
109: }
110:
1.34 ! ng 111: sub get_fullname {
! 112: my ($sname,$sdom) = @_;
! 113: my %name=&Apache::lonnet::get('environment', ['lastname','generation',
! 114: 'firstname','middlename'],
! 115: $sdom,$sname);
! 116: my $fullname;
! 117: my ($tmp) = keys(%name);
! 118: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
! 119: $fullname=$name{'lastname'}.$name{'generation'};
! 120: if ($fullname =~ /[^\s]+/) { $fullname.=', '; }
! 121: $fullname.=$name{'firstname'}.' '.$name{'middlename'};
! 122: }
! 123: return $fullname;
! 124: }
! 125:
1.30 ng 126: sub listStudents {
127: my ($request) = shift;
1.34 ! ng 128: my $cdom =$ENV{"course.$ENV{'request.course.id'}.domain"};
! 129: my $cnum =$ENV{"course.$ENV{'request.course.id'}.num"};
! 130: my $getsec =$ENV{'form.section'};
! 131: my $submitonly=$ENV{'form.submitonly'};
1.30 ng 132:
1.23 www 133: $request->print(<<ENDTABLEST);
1.34 ! ng 134: <h2><font color="#339933"> View Submissions for a Student or a Group of Students</font></h2>
! 135: <font size=+1><b>Resource:</b> $ENV{'form.url'}<br /><br />
! 136: <form action="/adm/grades" method="post"> <b>View Options</b></font><br />
! 137: <b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no
! 138: <input type="radio" name="vProb" value="yes"> yes
! 139: <b>Submissions: </b><input type="radio" name="lastSub" value="last" checked> last
! 140: <input type="radio" name="lastSub" value="all"> all
! 141: <input type="hidden" name="section" value="$getsec">
! 142: <input type="hidden" name="submitonly" value="$submitonly">
1.32 ng 143: <table border="0"><tr><td bgcolor="#777777">
1.34 ! ng 144: <table border="0"><tr bgcolor="#e6ffff">
! 145: <td><b> Select </b></td><td><b> Username </b></td>
! 146: <td><b> Fullname </b></td><td><b> Domain </b></td>
! 147: <td><b> Grade Status </b></td></tr>
1.23 www 148: ENDTABLEST
1.34 ! ng 149: if ($ENV{'form.url'}) {
! 150: $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
! 151: }
! 152: if ($ENV{'form.symb'}) {
! 153: $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
! 154: }
! 155: $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
! 156:
! 157: my ($classlist) = &getclasslist($getsec,'0');
! 158: foreach my $student ( sort(@{ $$classlist{$getsec} }) ) {
1.13 albertel 159: my ($sname,$sdom) = split(/:/,$student);
1.34 ! ng 160: my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$cdom,$sname);
! 161: next if ($status eq 'nothing' && $submitonly eq 'yes');
1.13 albertel 162:
1.34 ! ng 163: my $fullname = &get_fullname($sname,$sdom);
1.13 albertel 164: if ( $Apache::grades::viewgrades eq 'F' ) {
1.34 ! ng 165: $request->print("\n".'<tr bgcolor="#ffffe6">'.
! 166: '<td align="center"><input type=checkbox name="stuinfo" value="'.
! 167: $student.':'.$fullname.'"></td>'."\n".
! 168: '<td> '.$sname.' </td>'."\n".
! 169: '<td> '.$fullname.' </td>'."\n".
! 170: '<td align="middle"> '.$sdom.' </td>'."\n");
! 171: $request->print('<td align="middle"> '.$status.' </td>'."\n");
! 172:
! 173: $request->print('</tr>');
1.13 albertel 174: }
175: }
1.28 ng 176: $request->print('</table></td></tr></table>');
1.34 ! ng 177: $request->print('<input type="submit" name="submit" value="View/Grade" /><form />');
1.10 ng 178: }
179:
1.34 ! ng 180: sub processGroup {
! 181: my ($request) = shift;
! 182: my $ctr = 0;
! 183: my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
! 184: : ($ENV{'form.stuinfo'}) );
! 185: my $total = scalar(@stuchecked)-1;
! 186: foreach my $student (@stuchecked) {
! 187: my ($sname,$sdom,$fullname) = split(/:/,$student);
! 188: $ENV{'form.student'} = $sname;
! 189: $ENV{'form.fullname'} = $fullname;
! 190: &submission($request,$ctr,$total);
! 191: $ctr++;
! 192: }
! 193:
! 194: return 'The End';
! 195: }
1.13 albertel 196:
1.7 albertel 197: #FIXME - needs to handle multiple matches
1.2 albertel 198: sub finduser {
1.13 albertel 199: my ($name) = @_;
200: my $domain = '';
201:
202: if ( $Apache::grades::viewgrades eq 'F' ) {
203: #get classlist
1.34 ! ng 204: # my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});
1.24 albertel 205: #print "Found $cdom:$cnum<br />";
1.34 ! ng 206: my ($classlist) = &getclasslist('all','0');
! 207: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1.13 albertel 208: my ($posname,$posdomain) = split(/:/,$student);
209: if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
1.7 albertel 210: }
1.13 albertel 211: return ($name,$domain);
212: } else {
213: return ($ENV{'user.name'},$ENV{'user.domain'});
214: }
1.5 albertel 215: }
216:
217: sub getclasslist {
1.34 ! ng 218: my ($getsec,$hideexpired) = @_;
! 219: my ($coursedomain,$coursenum) = split(/_/,$ENV{'request.course.id'});
1.24 albertel 220: my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);
1.13 albertel 221: my $now = time;
1.34 ! ng 222: my (@holdsec,@sections);
1.24 albertel 223: foreach my $student (keys(%classlist)) {
224: my ($end,$start)=split(/:/,$classlist{$student});
1.13 albertel 225: # still a student?
226: if (($hideexpired) && ($end) && ($end < $now)) {
227: next;
228: }
1.34 ! ng 229: my ($unam,$udom) = split(/:/,$student,2);
! 230: my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});
! 231: push @holdsec,$section;
! 232: push (@{ $classlist{$getsec} }, $student) if ($getsec eq 'all' or $getsec == $section);
! 233: }
! 234: my %seen = ();
! 235: foreach my $item (@holdsec) {
! 236: push (@sections, $item) unless $seen{$item}++;
1.13 albertel 237: }
1.34 ! ng 238: return (\%classlist,\@sections);
1.5 albertel 239: }
240:
241: sub getpartlist {
1.13 albertel 242: my ($url) = @_;
243: my @parts =();
244: my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
245: foreach my $key (@metakeys) {
1.30 ng 246: if ( $key =~ m/stores_([0-9]+)_.*/) {
1.13 albertel 247: push(@parts,$key);
1.6 albertel 248: }
1.13 albertel 249: }
250: return @parts;
1.5 albertel 251: }
252:
253: sub viewstudentgrade {
1.13 albertel 254: my ($url,$symb,$courseid,$student,@parts) = @_;
255: my $result ='';
256: my $cellclr = '"#ffffdd"';
1.28 ng 257: my ($username,$domain) = split(/:/,$student);
1.13 albertel 258:
1.34 ! ng 259: my $fullname = &get_fullname($username,$domain);
1.28 ng 260: my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);
1.32 ng 261:
1.28 ng 262: $result.="<tr bgcolor=$cellclr><td>$username</td><td>$fullname</td><td align=\"middle\">$domain</td>\n";
1.13 albertel 263: foreach my $part (@parts) {
264: my ($temp,$part,$type)=split(/_/,$part);
1.31 ng 265: my $score=$record{"resource.$part.$type"};
266: if ($type eq 'awarded' || $type eq 'tries') {
267: $result.='<td align="middle"><input type="text" name="GRADE.'.$student.'.'.$part.'.'.$type.
268: '" value="'.$score.'" size="4" /></td>'."\n";
1.13 albertel 269: } elsif ($type eq 'solved') {
1.31 ng 270: my ($status,$foo)=split(/_/,$score,2);
1.28 ng 271: $result.="<td align=\"middle\"><select name=\"GRADE.$student.$part.$type\">\n";
1.31 ng 272: my $optsel = '<option>correct</option><option>incorrect</option><option>excused</option>'.
1.33 ng 273: '<option>ungraded</option><option>partial</option><option>nothing</option>'."\n";
1.31 ng 274: $status = 'nothing' if ($status eq '');
275: $optsel =~ s/<option>$status/<option selected="on">$status/;
276: $result.=$optsel;
1.13 albertel 277: $result.="</select></td>\n";
278: }
279: }
1.29 albertel 280: $result.='<td></td></tr>';
1.13 albertel 281: return $result;
1.5 albertel 282: }
1.31 ng 283:
284: #FIXME need to look at the metadata <stores> spec on what type of data to accept and provide an
1.6 albertel 285: #interface based on that, also do that to above function.
1.5 albertel 286: sub setstudentgrade {
1.13 albertel 287: my ($url,$symb,$courseid,$student,@parts) = @_;
1.34 ! ng 288: print "set student grade parts=@parts<br>";
1.13 albertel 289: my $result ='';
290: my ($stuname,$domain) = split(/:/,$student);
291: my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);
292: my %newrecord;
293:
294: foreach my $part (@parts) {
295: my ($temp,$part,$type)=split(/_/,$part);
296: my $oldscore=$record{"resource.$part.$type"};
297: my $newscore=$ENV{"form.GRADE.$student.$part.$type"};
1.32 ng 298: print "old=$oldscore:new=$newscore:<br>";
1.13 albertel 299: if ($type eq 'solved') {
300: my $update=0;
301: if ($newscore eq 'nothing' ) {
302: if ($oldscore ne '') {
303: $update=1;
304: $newscore = '';
1.6 albertel 305: }
1.13 albertel 306: } elsif ($oldscore !~ m/^$newscore/) {
307: $update=1;
308: $result.="Updating $stuname to $newscore<br />\n";
1.34 ! ng 309: if ($newscore eq 'correct') { $newscore = 'correct_by_override'; }
1.13 albertel 310: if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }
1.34 ! ng 311: if ($newscore eq 'excused') { $newscore = 'excused'; }
! 312: if ($newscore eq 'ungraded') { $newscore = 'ungraded_attempted'; }
! 313: if ($newscore eq 'partial') { $newscore = 'correct_partially_by_override'; }
1.13 albertel 314: } else {
315: #$result.="$stuname:$part:$type:unchanged $oldscore to $newscore:<br />\n";
316: }
317: if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
318: } else {
319: if ($oldscore ne $newscore) {
320: $newrecord{"resource.$part.$type"}=$newscore;
321: $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";
322: } else {
323: #$result.="$stuname:$part:$type:unchanged $oldscore to $newscore:<br />\n";
324: }
325: }
326: }
327: if ( scalar(keys(%newrecord)) > 0 ) {
1.32 ng 328: $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
329: print "grader=$newrecord{'resource.regrader'}:<br>records<br>";
330: while (my ($k,$v) = each %newrecord) {
331: print "k=$k:v=$v:<br>\n";
332: }
1.34 ! ng 333: # &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);
1.13 albertel 334:
335: $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";
336: }
337: return $result;
1.2 albertel 338: }
339:
1.33 ng 340: #
1.32 ng 341: # --------------------------- show submissions of a student, option to grade --------
1.2 albertel 342: sub submission {
1.34 ! ng 343: my ($request,$counter,$total) = @_;
1.33 ng 344:
1.34 ! ng 345: if ($counter == 0) {
! 346: $request->print(<<JAVASCRIPT);
1.32 ng 347: <script type="text/javascript" language="javascript">
1.33 ng 348: function updateRadio(radioButton,formtextbox,formsel,wgt) {
349: var pts = formtextbox.value;
350: var resetbox =false;
351: if (isNaN(pts) || pts < 0) {
352: alert("A number equal or greater than 0 is expected. Entered value = "+pts);
353: for (var i=0; i<radioButton.length; i++) {
354: if (radioButton[i].checked) {
355: formtextbox.value = i;
356: resetbox = true;
357: }
1.32 ng 358: }
1.33 ng 359: if (!resetbox) {
360: formtextbox.value = "";
361: }
362: return;
363: }
1.32 ng 364:
1.33 ng 365: for (var i=0; i<radioButton.length; i++) {
366: radioButton[i].checked=false;
367: if (pts == i) {
368: radioButton[i].checked=true;
1.32 ng 369: }
1.31 ng 370: }
1.33 ng 371: updateSelect(formsel,pts,wgt);
372: }
373:
374: function writeBox(formrad,formsel,pts,wgt) {
375: formrad.value = pts;
376: updateSelect(formsel,pts,wgt);
377: return;
378: }
379:
380: function updateSelect(formsel,pts,wgt) {
381: if (pts == 0) {
382: formsel[1].selected = true;
383: }
384: if (pts > 0 && pts < wgt) {
385: formsel[4].selected = true;
386: }
387: if (pts == wgt) {
388: formsel[0].selected = true;
389: }
390: return;
391: }
1.32 ng 392:
1.31 ng 393: </script>
394: JAVASCRIPT
1.34 ! ng 395: }
1.33 ng 396: (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.13 albertel 397: if ($ENV{'form.student'} eq '') { &moreinfo($request,"Need student login id"); return ''; }
398: my ($uname,$udom) = &finduser($ENV{'form.student'});
399: if ($uname eq '') { &moreinfo($request,"Unable to find student"); return ''; }
1.32 ng 400:
401: my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
1.13 albertel 402: if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
1.34 ! ng 403: my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');
1.31 ng 404: #
405: # header info
1.34 ! ng 406: if ($counter == 0) {
! 407: $request->print('<h2><font color="#339933">Submission Record</font></h2>');
! 408: }
! 409:
1.31 ng 410: #
1.34 ! ng 411: # option to display problem, only once else it cause problems with the form later since the problem has a form.
! 412: if ($ENV{'form.vProb'} eq 'yes' && $counter == 0) {
1.30 ng 413: my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,
1.17 albertel 414: $ENV{'request.course.id'});
1.30 ng 415: my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,
416: $ENV{'request.course.id'});
1.34 ! ng 417: my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">';
1.33 ng 418: $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">';
1.31 ng 419: $result.='<b>Student\'s view of the problem</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />';
1.30 ng 420: $result.='<b>Correct answer:</b><br />'.$companswer;
421: $result.='</td></tr></table>';
422: $result.='</td></tr></table><br />';
1.34 ! ng 423: $request->print($result);
! 424: }
! 425: #
! 426: # beginning of form
! 427: if ($counter == 0) {
! 428: $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".
! 429: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
! 430: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
! 431: '<input type="hidden" name="vProb" value="'.$ENV{'form.vProb'}.'" />'."\n".
! 432: '<input type="hidden" name="lastSub" value="'.$last.'" />'."\n".
! 433: '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'">'."\n".
! 434: '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".
! 435: '<input type="hidden" name="command" value="handgrade" />'."\n".
! 436: '<input type="hidden" name="NCT"'.
! 437: ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1').'" />'."\n");
1.30 ng 438: }
1.34 ! ng 439: #
! 440: # Student info
! 441: $request->print(($counter == 0 ? '' : '<br /><hr><br />'));
! 442: my $result.='<table border="0"><tr><td><b>Username: </b>'.$uname.
! 443: '</td><td><b>Fullname: </b>'.
! 444: ($ENV{'form.fullname'} ne '' ? $ENV{'form.fullname'} : &get_fullname($uname,$udom)).
! 445: '</td><td><b>Domain: </b>'.$udom.'</td></tr>';
! 446: $result.='<tr><td colspan=3><b>Resource: </b>'.$url.'</td></tr></table>';
! 447: $request->print($result);
! 448: #
! 449: # print student answer
1.30 ng 450: my $answer=&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
1.34 ! ng 451: $ENV{'request.course.id'},$last);
! 452: $request->print($answer);
! 453: $answer =~ m/.*<\/tr><tr.*?<td>.*?<td>(.*?)<td>(.*?)<\/td>/;
! 454: print "Submitted=$1:<br>$2;";
! 455: #
! 456: my $wgt = &Apache::lonnet::EXT('resource.partid.weight',$symb,$udom,$uname);
! 457: my $wgtmsg = ($wgt > 0 ? '(problem weight)' : '<font color="red">problem weight assigned by computer</font>');
! 458: $wgt = ($wgt > 0 ? $wgt : '1');
! 459: my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
! 460: my $score = ($record{'resource.0.awarded'} eq '' ? '' : $record{'resource.0.awarded'}*$wgt);
1.18 albertel 461:
1.34 ! ng 462: #
! 463: # display grading options
! 464: $result='<input type="hidden" name="WGT'.$counter.'" value="'.$wgt.'" />'.
1.33 ng 465: '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n";
1.32 ng 466: $result.='<table border="0"><tr><td><b>Points</b></td><td>';
1.31 ng 467: my $ctr = 0;
1.34 ! ng 468:
! 469: $result.='<table border="0"><tr>'; # display radio buttons in a nice table with 10 across
1.32 ng 470: while ($ctr<=$wgt) {
1.34 ! ng 471: $result.= '<td><input type="radio" name="RADVAL'.$counter.'" '.
1.33 ng 472: 'onclick="javascript:writeBox(this.form.GRADE_BOX'.$counter.
1.34 ! ng 473: ',this.form.GRADE_SEL'.$counter.','.$ctr.','.$wgt.')" '.
! 474: ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";
! 475: $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
1.31 ng 476: $ctr++;
477: }
1.34 ! ng 478: $result.='</tr></table>';
! 479:
1.31 ng 480: $result.='</td><td> <b>or</b> </td>';
1.33 ng 481: $result.='<td><input type="text" name="GRADE_BOX'.$counter.'"'.
1.32 ng 482: ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
1.33 ng 483: 'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.
484: ',this.form.GRADE_BOX'.$counter.
485: ',this.form.GRADE_SEL'.$counter.',\''.$wgt.'\')" /></td>'."\n";
1.34 ! ng 486: $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';
1.33 ng 487:
488: foreach my $part (&getpartlist($url)) {
489: my ($temp,$part,$type)=split(/_/,$part);
490: if ($type eq 'solved') {
491: my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);
1.34 ! ng 492: $status = 'partial' if ($foo =~ /partially/);
! 493: $status = 'nothing' if ($status eq '');
1.33 ng 494: $result.='<select name="GRADE_SEL'.$counter.'">'."\n";
495: my $optsel = '<option>correct</option><option>incorrect</option>'.
496: '<option>excused</option><option>ungraded</option>'.
497: '<option>partial</option><option>nothing</option>'."\n";
498: $optsel =~ s/<option>$status/<option selected="on">$status/;
499: $result.=$optsel;
500: $result.="</select></td></tr>\n";
501: }
502: }
1.34 ! ng 503: $result.='</table>';
! 504: $request->print($result);
! 505: #
! 506: # print end of form
! 507: if ($counter == $total) {
! 508: my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />';
! 509: my $ntstu ='<select name="NTSTU">'.
! 510: '<option>1</option><option>2</option>'.
! 511: '<option>3</option><option>5</option>'.
! 512: '<option>7</option><option>10</option></select>'."\n";
! 513: my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');
! 514: $ntstu =~ s/<option>$nsel/<option selected="on">$nsel/;
! 515: $endform.=$ntstu.'student(s) ';
! 516: $endform.='<input type="submit" name="gradeOpt" value="Next" /> ';
! 517: $endform.='<input type="submit" name="gradeOpt" value="Previous" /> ';
! 518: $endform.='(Next and Previous do not save the scores.)';
! 519: $endform.='</td><tr></table></form>';
! 520: $request->print($endform);
! 521: }
! 522: return '';
1.32 ng 523: }
1.30 ng 524:
1.32 ng 525: sub processHandGrade {
1.34 ! ng 526: my ($request) = shift;
1.33 ng 527: my $url = $ENV{'form.url'};
528: my $symb = $ENV{'form.symb'};
529: my $button = $ENV{'form.gradeOpt'};
530: my $ngrade = $ENV{'form.NCT'};
531: my $ntstu = $ENV{'form.NTSTU'};
1.34 ! ng 532: # my $vProb = $ENV{'form.vProb'};
! 533: # my $lastSub= $ENV{'form.lastSub'};
1.33 ng 534:
535: my (@parts) = sort(&getpartlist($url));
1.34 ! ng 536:
1.33 ng 537: if ($button eq 'Save & Next') {
538: my $ctr = 0;
539: while ($ctr < $ENV{'form.NCT'}) {
1.34 ! ng 540: # my $pts = ($ENV{'form.GRADE_BOX'.$ctr} ne '' ? $ENV{'form.GRADE_BOX'.$ctr} : $ENV{'form.RADVAL'.$ctr});
! 541: # my $wgt = $ENV{'form.WGT'.$ctr};
! 542: # my $sel = $ENV{'form.GRADE_SEL'.$ctr};
! 543: # my $score = $pts/$wgt if ($wgt != 0);
1.33 ng 544: my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
1.34 ! ng 545: &saveHandGrade($url,$symb,$uname,$udom,$ctr,@parts);
! 546: # &saveHandGrade($url,$symb,$uname,$udom,$score,@parts);
1.33 ng 547: $ctr++;
548: }
549: }
550: my $firststu = $ENV{'form.unamedom0'};
551: my $laststu = $ENV{'form.unamedom'.($ngrade-1)};
552:
553: #get classlist
1.34 ! ng 554: # my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});
! 555: my ($classlist) = &getclasslist('all','0');
1.33 ng 556:
557: my (@nextlist,@prevlist);
1.34 ! ng 558: my ($nextflg,$prevflg,$ctr,$ctprev) = (0,0,0,0);
! 559: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1.33 ng 560: my ($uname,$udom) = split(/:/,$student);
561: if ($nextflg == 1 && $button =~ /Next$/) {
1.34 ! ng 562: push @nextlist,$uname if ($ctr < $ntstu);
1.33 ng 563: $ctr++;
564: }
565: $nextflg = 1 if ($student eq $laststu);
566: $prevflg = 1 if ($student eq $firststu);
1.34 ! ng 567: if ($prevflg == 0 && $button eq 'Previous') {
! 568: push @prevlist,$uname;
! 569: $ctprev++;
! 570: }
1.33 ng 571: }
1.34 ! ng 572: if ($button eq 'Previous') {
! 573: if ($ctprev <= $ntstu) {
! 574: @nextlist = @prevlist;
! 575: } else {
! 576: my $idx = 0;
! 577: my $start = $ctprev - $ntstu;
! 578: while ($idx < $ntstu) {
! 579: $nextlist[$idx] = $prevlist[$start+$idx];
! 580: $idx++;
! 581: }
! 582: }
! 583: }
! 584: $ctr = 0;
! 585: my $total = scalar(@nextlist)-1;
1.33 ng 586: foreach my $student (@nextlist) {
587: $ENV{'form.student'} = $student;
1.34 ! ng 588: &submission($request,$ctr,$total);
! 589: $ctr++;
1.33 ng 590: }
591:
592: return 'The End';
593: }
594:
595: sub saveHandGrade {
1.34 ! ng 596: my ($url,$symb,$stuname,$domain,$newflg,@parts) = @_;
1.33 ng 597: # my ($stuname,$domain) = split(/:/,$student);
598: my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
1.32 ng 599: my %newrecord;
600:
601: foreach my $part (@parts) {
1.31 ng 602: my ($temp,$part,$type)=split(/_/,$part);
1.32 ng 603: my $oldscore=$record{"resource.$part.$type"};
1.34 ! ng 604: my $newscore;
! 605: if ($type eq 'awarded' && $newflg >= 0) {
! 606: my $pts = ($ENV{'form.GRADE_BOX'.$newflg} ne '' ? $ENV{'form.GRADE_BOX'.$newflg} : $ENV{'form.RADVAL'.$newflg});
! 607: my $wgt = $ENV{'form.WGT'.$newflg};
! 608: # my $sel = $ENV{'form.GRADE_SEL'.$newflg};
! 609: $newscore = $pts/$wgt if ($wgt != 0);
! 610: }
1.31 ng 611: if ($type eq 'solved') {
1.34 ! ng 612: $newscore = $ENV{'form.GRADE_SEL'.$newflg} if ($newflg >= 0);
1.32 ng 613: my $update=0;
614: if ($newscore eq 'nothing' ) {
615: if ($oldscore ne '') {
616: $update=1;
617: $newscore = '';
618: }
619: } elsif ($oldscore !~ m/^$newscore/) {
620: $update=1;
621: if ($newscore eq 'correct') { $newscore = 'correct_by_override'; }
622: if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }
623: if ($newscore eq 'excused') { $newscore = 'excused'; }
624: if ($newscore eq 'ungraded') { $newscore = 'ungraded_attempted'; }
1.34 ! ng 625: if ($newscore eq 'partial') { $newscore = 'correct_partially_by_override'; }
1.32 ng 626: }
627: if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
628: } else {
629: if ($oldscore ne $newscore) {
630: $newrecord{"resource.$part.$type"}=$newscore;
1.33 ng 631: }
1.32 ng 632: }
1.34 ! ng 633: }
! 634: if ( scalar(keys(%newrecord)) > 0 ) {
1.33 ng 635: $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
1.34 ! ng 636: while (my ($k,$v) = each %newrecord) {
! 637: print "k=$k:v=$v:<br>\n";
! 638: }
! 639: print "symb=$symb,courseid=$ENV{'request.course.id'},dom=$domain,name=$stuname<br>";
! 640: # &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$stuname);
1.31 ng 641: }
1.34 ! ng 642: return '';
1.2 albertel 643: }
644:
1.26 albertel 645: sub get_symb_and_url {
1.34 ! ng 646: my ($request) = @_;
! 647: (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.32 ng 648: my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
1.13 albertel 649: if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
1.34 ! ng 650: return ($symb,$url);
1.29 albertel 651: }
652:
653: sub show_grading_menu_form {
654: my ($symb,$url)=@_;
655: my $result.='<form action="/adm/grades" method="post">'."\n".
656: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
657: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
658: '<input type="hidden" name="command" value="gradingmenu" />'."\n".
659: '<input type="submit" name="submit" value="Grading Menu" />'."\n".
660: '</form>'."\n";
661: return $result;
662: }
663:
1.26 albertel 664: sub gradingmenu {
665: my ($request) = @_;
666: my ($symb,$url)=&get_symb_and_url($request);
667: if (!$symb) {return '';}
1.28 ng 668:
1.34 ! ng 669: my $result='<h2> <font color="#339933">Select a Grading Method</font></h2>';
! 670: $result.=' <font size=+1><b>Resource: </b>'.$url.'</font><br /><br />';
! 671:
! 672: $result.=&view_edit_entire_class_form($symb,$url).'<br />';
! 673: $result.=&upcsvScores_form($symb,$url).'<br />';
! 674: $result.=&viewGradeaStu_form($symb,$url).'<br />';
! 675: $result.=&verifyReceipt_form($symb,$url);
! 676: return $result;
! 677: }
! 678:
! 679: sub view_edit_entire_class_form {
! 680: my ($symb,$url)=@_;
! 681: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
! 682: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
! 683: $result.=' <b>View/Grade Entire Class</b></td></tr>'."\n";
1.28 ng 684: $result.='<tr bgcolor=#ffffe6><td>'."\n";
1.26 albertel 685: $result.='<form action="/adm/grades" method="post">'."\n".
1.34 ! ng 686: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
1.26 albertel 687: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
1.34 ! ng 688: '<input type="hidden" name="command" value="viewgrades" />'."\n";
! 689: $result.=' <b>Display students who has: </b>'.
! 690: '<input type="radio" name="submitonly" value="yes" checked> submitted'.
! 691: '<input type="radio" name="submitonly" value="all"> everybody <br /><br />';
! 692: $result.=' <input type="submit" name="submit" value="View/Grade" /></form>'."\n";
! 693: $result.='</td></tr></table>'."\n";
! 694: $result.='</td></tr></table>'."\n";
! 695: return $result;
! 696: }
! 697:
! 698: sub upcsvScores_form {
! 699: my ($symb,$url) = @_;
! 700: if (!$symb) {return '';}
! 701: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
! 702: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
! 703: $result.=' <b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";
! 704: $result.='<tr bgcolor=#ffffe6><td>'."\n";
! 705: my $upfile_select=&Apache::loncommon::upfile_select_html();
! 706: $result.=<<ENDUPFORM;
! 707: <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
! 708: <input type="hidden" name="symb" value="$symb" />
! 709: <input type="hidden" name="url" value="$url" />
! 710: <input type="hidden" name="command" value="csvuploadmap" />
! 711: $upfile_select
! 712: <br /> <input type="submit" name="submit" value="Upload Grades" />
! 713: </form>
! 714: ENDUPFORM
! 715: $result.='</td></tr></table>'."\n";
! 716: $result.='</td></tr></table>'."\n";
! 717: return $result;
! 718: }
! 719:
! 720: sub viewGradeaStu_form {
! 721: my ($symb,$url) = @_;
! 722: my ($classlist,$sections) = &getclasslist('all','0');
! 723: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
! 724: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
! 725: $result.=' <b>View/Grade an Individual Student\'s Submission</b></td></tr>'."\n";
! 726: $result.='<tr bgcolor=#ffffe6><td>'."\n";
1.26 albertel 727: $result.='<form action="/adm/grades" method="post">'."\n".
728: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
729: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
1.34 ! ng 730: '<input type="hidden" name="command" value="submission" />'."\n";
! 731:
! 732: $result.=' <b>Select section:</b> <select name="section">'."\n";
! 733: foreach my $section (sort (@$sections)) {
! 734: $result.= '<option>'.$section.'</option>'."\n";
! 735: }
! 736: $result.= '<option selected="on">all</select>'."\n";
! 737: $result.=' <b>Display students who has: </b>'.
! 738: '<input type="radio" name="submitonly" value="yes" checked> submitted'.
! 739: '<input type="radio" name="submitonly" value="all"> everybody <br />';
! 740: $result.=' (Section -1 implies the students were not assigned a section.)<br />' if (grep /-1/,@$sections);
! 741:
! 742: $result.='<br /> <input type="submit" name="submit" value="View/Grade" />'."\n".
! 743: '</form>'."\n";
! 744: $result.='</td></tr></table>'."\n";
! 745: $result.='</td></tr></table>'."\n";
! 746: return $result;
! 747: }
! 748:
! 749: sub verifyReceipt_form {
! 750: my ($symb,$url) = @_;
! 751: my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"};
! 752: my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"};
! 753: my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});
! 754:
! 755: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
! 756: $result.='<table width=100% border=0><tr><td bgcolor=#e6ffff>'."\n";
! 757: $result.=' <b>Verify a Submission Receipt Issued by this Server</td></tr>'."\n";
! 758: $result.='<tr bgcolor=#ffffe6><td>'."\n";
! 759: $result.='<form action="/adm/grades" method="post">'."\n";
! 760: $result.=' <tt>'.$hostver.'-<input type="text" name="receipt" size="4"></tt><br />'."\n";
! 761: $result.=' <input type="submit" name="submit" value="Verify Receipt">'."\n";
! 762: $result.='<input type="hidden" name="command" value="verify">'."\n";
! 763: if ($ENV{'form.url'}) {
! 764: $result.='<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />';
! 765: }
! 766: if ($ENV{'form.symb'}) {
! 767: $result.='<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />';
! 768: }
! 769: $result.='</form>';
1.28 ng 770: $result.='</td></tr></table>'."\n";
771: $result.='</td></tr></table>'."\n";
1.26 albertel 772: return $result;
773: }
774:
775: sub viewgrades {
776: my ($request) = @_;
777: my $result='';
778:
779: #get resource reference
780: my ($symb,$url)=&get_symb_and_url($request);
781: if (!$symb) {return '';}
1.13 albertel 782: #get classlist
783: my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});
1.24 albertel 784: #print "Found $cdom:$cnum<br />";
1.34 ! ng 785: my ($classlist) = &getclasslist('all','0');
1.13 albertel 786: my $headerclr = '"#ccffff"';
787: my $cellclr = '"#ffffcc"';
788:
789: #get list of parts for this problem
1.29 albertel 790: my (@parts) = sort(&getpartlist($url));
1.13 albertel 791:
1.28 ng 792: $request->print ("<h2><font color=\"#339933\">Manual Grading</font></h2>");
1.13 albertel 793:
794: #start the form
795: $result = '<form action="/adm/grades" method="post">'."\n".
1.16 albertel 796: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
797: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
1.13 albertel 798: '<input type="hidden" name="command" value="editgrades" />'."\n".
799: '<input type="submit" name="submit" value="Submit Changes" />'."\n".
1.32 ng 800: '<table border=0><tr><td bgcolor="#777777">'."\n".
1.13 albertel 801: '<table border=0>'."\n".
1.28 ng 802: '<tr bgcolor='.$headerclr.'><td><b>Username</b></td><td><b>Name</b></td><td><b>Domain</b></td>'."\n";
1.29 albertel 803: foreach my $part (@parts) {
1.13 albertel 804: my $display=&Apache::lonnet::metadata($url,$part.'.display');
805: if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
1.28 ng 806: $result.='<td><b>'.$display.'</b></td>'."\n";
1.30 ng 807: }
1.28 ng 808: $result.='</tr>';
1.13 albertel 809: #get info for each student
1.34 ! ng 810: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1.31 ng 811: my $display=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
812: # print "ID=$ENV{'request.course.id'}:STU=$student:DIS=$display:<br>\n";
1.13 albertel 813: $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
814: }
1.31 ng 815: $result.='</table></td></tr></table>';
816: $result.='<input type="submit" name="submit" value="Submit Changes" /></form>';
1.29 albertel 817: $result.=&show_grading_menu_form($symb,$url);
1.13 albertel 818: return $result;
1.5 albertel 819: }
820:
821: sub editgrades {
1.13 albertel 822: my ($request) = @_;
823: my $result='';
1.5 albertel 824:
1.13 albertel 825: my $symb=$ENV{'form.symb'};
826: if ($symb eq '') { $request->print("Unable to handle ambiguous references:$symb:$ENV{'form.url'}"); return ''; }
827: my $url=$ENV{'form.url'};
828: #get classlist
1.34 ! ng 829: # my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});
1.24 albertel 830: #print "Found $cdom:$cnum<br />";
1.34 ! ng 831: my ($classlist) = &getclasslist('all','0');
1.13 albertel 832:
833: #get list of parts for this problem
834: my (@parts) = &getpartlist($url);
835:
836: $result.='<form action="/adm/grades" method="post">'."\n".
837: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
838: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
839: '<input type="hidden" name="command" value="viewgrades" />'."\n".
840: '<input type="submit" name="submit" value="See Grades" /> <br />'."\n";
841:
1.34 ! ng 842: foreach my $student ( sort(@{ $$classlist{'all '} }) ) {
1.13 albertel 843: $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
844: }
1.5 albertel 845:
1.13 albertel 846: $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';
847: return $result;
1.5 albertel 848: }
849:
1.27 albertel 850: sub csvupload_javascript_reverse_associate {
851: return(<<ENDPICK);
852: function verify(vf) {
853: var foundsomething=0;
854: var founduname=0;
855: var founddomain=0;
856: for (i=0;i<=vf.nfields.value;i++) {
857: tw=eval('vf.f'+i+'.selectedIndex');
858: if (i==0 && tw!=0) { founduname=1; }
859: if (i==1 && tw!=0) { founddomain=1; }
860: if (i!=0 && i!=1 && tw!=0) { foundsomething=1; }
861: }
862: if (founduname==0 || founddomain==0) {
863: alert('You need to specify at both the username and domain');
864: return;
865: }
866: if (foundsomething==0) {
867: alert('You need to specify at least one grading field');
868: return;
869: }
870: vf.submit();
871: }
872: function flip(vf,tf) {
873: var nw=eval('vf.f'+tf+'.selectedIndex');
874: var i;
875: for (i=0;i<=vf.nfields.value;i++) {
876: //can not pick the same destination field for both name and domain
877: if (((i ==0)||(i ==1)) &&
878: ((tf==0)||(tf==1)) &&
879: (i!=tf) &&
880: (eval('vf.f'+i+'.selectedIndex')==nw)) {
881: eval('vf.f'+i+'.selectedIndex=0;')
882: }
883: }
884: }
885: ENDPICK
886: }
887:
888: sub csvupload_javascript_forward_associate {
889: return(<<ENDPICK);
890: function verify(vf) {
891: var foundsomething=0;
892: var founduname=0;
893: var founddomain=0;
894: for (i=0;i<=vf.nfields.value;i++) {
895: tw=eval('vf.f'+i+'.selectedIndex');
896: if (tw==1) { founduname=1; }
897: if (tw==2) { founddomain=1; }
898: if (tw>2) { foundsomething=1; }
899: }
900: if (founduname==0 || founddomain==0) {
901: alert('You need to specify at both the username and domain');
902: return;
903: }
904: if (foundsomething==0) {
905: alert('You need to specify at least one grading field');
906: return;
907: }
908: vf.submit();
909: }
910: function flip(vf,tf) {
911: var nw=eval('vf.f'+tf+'.selectedIndex');
912: var i;
913: //can not pick the same destination field twice
914: for (i=0;i<=vf.nfields.value;i++) {
915: if ((i!=tf) && (eval('vf.f'+i+'.selectedIndex')==nw)) {
916: eval('vf.f'+i+'.selectedIndex=0;')
917: }
918: }
919: }
920: ENDPICK
921: }
922:
1.26 albertel 923: sub csvuploadmap_header {
924: my ($request,$symb,$url,$datatoken,$distotal)= @_;
925: my $result;
926: my $javascript;
927: if ($ENV{'form.upfile_associate'} eq 'reverse') {
1.27 albertel 928: $javascript=&csvupload_javascript_reverse_associate();
1.26 albertel 929: } else {
1.27 albertel 930: $javascript=&csvupload_javascript_forward_associate();
1.26 albertel 931: }
932: $request->print(<<ENDPICK);
933: <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
934: <h3>Uploading Class Grades for resource $url</h3>
935: <hr>
936: <h3>Identify fields</h3>
937: Total number of records found in file: $distotal <hr />
938: Enter as many fields as you can. The system will inform you and bring you back
939: to this page if the data selected is insufficient to run your class.<hr />
940: <input type="button" value="Reverse Association" onClick="javascript:this.form.associate.value='Reverse Association';submit(this.form);" />
941: <input type="hidden" name="associate" value="" />
942: <input type="hidden" name="phase" value="three" />
943: <input type="hidden" name="datatoken" value="$datatoken" />
944: <input type="hidden" name="fileupload" value="$ENV{'form.fileupload'}" />
945: <input type="hidden" name="upfiletype" value="$ENV{'form.upfiletype'}" />
946: <input type="hidden" name="upfile_associate"
947: value="$ENV{'form.upfile_associate'}" />
948: <input type="hidden" name="symb" value="$symb" />
949: <input type="hidden" name="url" value="$url" />
950: <input type="hidden" name="command" value="csvuploadassign" />
951: <hr />
952: <script type="text/javascript" language="Javascript">
953: $javascript
954: </script>
955: ENDPICK
956: return '';
957:
958: }
959:
960: sub csvupload_fields {
961: my ($url) = @_;
962: my (@parts) = &getpartlist($url);
1.27 albertel 963: my @fields=(['username','Student Username'],['domain','Student Domain']);
964: foreach my $part (sort(@parts)) {
1.26 albertel 965: my @datum;
966: my $display=&Apache::lonnet::metadata($url,$part.'.display');
1.27 albertel 967: my $name=$part;
1.26 albertel 968: if (!$display) { $display = $name; }
969: @datum=($name,$display);
970: push(@fields,\@datum);
971: }
972: return (@fields);
973: }
974:
975: sub csvuploadmap_footer {
976: my ($request,$i,$keyfields) =@_;
977: $request->print(<<ENDPICK);
978: </table>
979: <input type="hidden" name="nfields" value="$i" />
980: <input type="hidden" name="keyfields" value="$keyfields" />
981: <input type="button" onClick="javascript:verify(this.form)" value="Assign Grades" /><br />
982: </form>
983: ENDPICK
984: }
985:
986: sub csvuploadmap {
987: my ($request)= @_;
988: my ($symb,$url)=&get_symb_and_url($request);
989: if (!$symb) {return '';}
990: my $datatoken;
991: if (!$ENV{'form.datatoken'}) {
992: $datatoken=&Apache::loncommon::upfile_store($request);
993: } else {
994: $datatoken=$ENV{'form.datatoken'};
995: &Apache::loncommon::load_tmp_file($request);
996: }
997: my @records=&Apache::loncommon::upfile_record_sep();
998: &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
999: my $i;
1000: my $keyfields;
1001: if (@records) {
1002: my @fields=&csvupload_fields($url);
1003: if ($ENV{'form.upfile_associate'} eq 'reverse') {
1004: &Apache::loncommon::csv_print_samples($request,\@records);
1005: $i=&Apache::loncommon::csv_print_select_table($request,\@records,
1006: \@fields);
1007: foreach (@fields) { $keyfields.=$_->[0].','; }
1008: chop($keyfields);
1009: } else {
1010: unshift(@fields,['none','']);
1011: $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
1012: \@fields);
1013: my %sone=&Apache::loncommon::record_sep($records[0]);
1014: $keyfields=join(',',sort(keys(%sone)));
1015: }
1016: }
1017: &csvuploadmap_footer($request,$i,$keyfields);
1018: return '';
1.27 albertel 1019: }
1020:
1021: sub csvuploadassign {
1022: my ($request)= @_;
1023: my ($symb,$url)=&get_symb_and_url($request);
1024: if (!$symb) {return '';}
1025: &Apache::loncommon::load_tmp_file($request);
1026: my @gradedata=&Apache::loncommon::upfile_record_sep();
1027: my @keyfields = split(/\,/,$ENV{'form.keyfields'});
1028: my %fields=();
1029: for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
1030: if ($ENV{'form.upfile_associate'} eq 'reverse') {
1031: if ($ENV{'form.f'.$i} ne 'none') {
1032: $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
1033: }
1034: } else {
1035: if ($ENV{'form.f'.$i} ne 'none') {
1036: $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
1037: }
1038: }
1039: }
1040: $request->print('<h3>Assigning Grades</h3>');
1041: my $courseid=$ENV{'request.course.id'};
1.34 ! ng 1042: # my $cdom=$ENV{"course.$courseid.domain"};
! 1043: # my $cnum=$ENV{"course.$courseid.num"};
! 1044: my ($classlist) = &getclasslist('all','1');
1.29 albertel 1045: my @skipped;
1046: my $countdone=0;
1047: foreach my $grade (@gradedata) {
1048: my %entries=&Apache::loncommon::record_sep($grade);
1049: my $username=$entries{$fields{'username'}};
1050: my $domain=$entries{$fields{'domain'}};
1.34 ! ng 1051: if (!exists($$classlist{"$username:$domain"})) {
1.29 albertel 1052: push(@skipped,"$username:$domain");
1053: next;
1.27 albertel 1054: }
1.29 albertel 1055: my %grades;
1056: foreach my $dest (keys(%fields)) {
1057: if ($dest eq 'username' || $dest eq 'domain') { next; }
1058: if ($entries{$fields{$dest}} eq '') { next; }
1059: my $store_key=$dest;
1060: $store_key=~s/^stores/resource/;
1061: $store_key=~s/_/\./g;
1062: $grades{$store_key}=$entries{$fields{$dest}};
1063: }
1064: $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
1065: &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
1066: $domain,$username);
1067: $request->print('.');
1068: $request->rflush();
1069: $countdone++;
1070: }
1071: $request->print("<br />Stored $countdone students\n");
1072: if (@skipped) {
1073: $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');
1074: foreach my $student (@skipped) { $request->print("<br />$student"); }
1.27 albertel 1075: }
1.29 albertel 1076: $request->print(&view_edit_entire_class_form($symb,$url));
1077: $request->print(&show_grading_menu_form($symb,$url));
1078: return '';
1.26 albertel 1079: }
1080:
1.2 albertel 1081: sub send_header {
1.13 albertel 1082: my ($request)= @_;
1083: $request->print(&Apache::lontexconvert::header());
1.6 albertel 1084: # $request->print("
1085: #<script>
1086: #remotewindow=open('','homeworkremote');
1087: #remotewindow.close();
1088: #</script>");
1.13 albertel 1089: $request->print('<body bgcolor="#FFFFFF">');
1.2 albertel 1090: }
1091:
1092: sub send_footer {
1.13 albertel 1093: my ($request)= @_;
1.2 albertel 1094: $request->print('</body>');
1095: $request->print(&Apache::lontexconvert::footer());
1096: }
1097:
1.1 albertel 1098: sub handler {
1.13 albertel 1099: my $request=$_[0];
1100:
1101: if ($ENV{'browser.mathml'}) {
1102: $request->content_type('text/xml');
1103: } else {
1104: $request->content_type('text/html');
1105: }
1106: $request->send_http_header;
1107: return OK if $request->header_only;
1.16 albertel 1108: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
1.13 albertel 1109: my $url=$ENV{'form.url'};
1110: my $symb=$ENV{'form.symb'};
1111: my $command=$ENV{'form.command'};
1.16 albertel 1112: if (!$url) {
1113: my ($temp1,$temp2);
1114: ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);
1115: $url = $ENV{'form.url'};
1116: }
1.13 albertel 1117: &send_header($request);
1118: if ($url eq '' && $symb eq '') {
1.14 www 1119: if ($ENV{'user.adv'}) {
1120: if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&
1121: ($ENV{'form.codethree'})) {
1122: my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.
1123: $ENV{'form.codethree'};
1124: my ($tsymb,$tuname,$tudom,$tcrsid)=
1125: &Apache::lonnet::checkin($token);
1126: if ($tsymb) {
1127: my ($map,$id,$url)=split(/\_\_\_/,$tsymb);
1128: if (&Apache::lonnet::allowed('mgr',$tcrsid)) {
1129: $request->print(
1130: &Apache::lonnet::ssi('/res/'.$url,
1131: ('grade_username' => $tuname,
1132: 'grade_domain' => $tudom,
1133: 'grade_courseid' => $tcrsid,
1134: 'grade_symb' => $tsymb)));
1135: } else {
1136: $request->print('<h1>Not authorized: '.$token.'</h1>');
1137: }
1138: } else {
1139: $request->print('<h1>Not a valid DocID: '.$token.'</h1>');
1140: }
1141: } else {
1142: $request->print(&Apache::lonxml::tokeninputfield());
1143: }
1144: }
1.13 albertel 1145: } else {
1.29 albertel 1146: #&Apache::lonhomework::showhashsubset(\%ENV,'^form');
1.13 albertel 1147: $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
1148: if ($command eq 'submission') {
1.20 albertel 1149: &listStudents($request) if ($ENV{'form.student'} eq '');
1.34 ! ng 1150: &submission($request,0,0) if ($ENV{'form.student'} ne '');
! 1151: } elsif ($command eq 'processGroup') {
! 1152: &processGroup($request);
1.26 albertel 1153: } elsif ($command eq 'gradingmenu') {
1154: $request->print(&gradingmenu($request));
1.13 albertel 1155: } elsif ($command eq 'viewgrades') {
1156: $request->print(&viewgrades($request));
1.33 ng 1157: } elsif ($command eq 'handgrade') {
1158: $request->print(&processHandGrade($request));
1.13 albertel 1159: } elsif ($command eq 'editgrades') {
1160: $request->print(&editgrades($request));
1.23 www 1161: } elsif ($command eq 'verify') {
1162: $request->print(&verifyreceipt($request));
1.26 albertel 1163: } elsif ($command eq 'csvupload') {
1164: $request->print(&csvupload($request));
1165: } elsif ($command eq 'csvuploadmap') {
1166: $request->print(&csvuploadmap($request));
1.34 ! ng 1167: # } elsif ($command eq 'receiptInput') {
! 1168: # &receiptInput($request);
1.26 albertel 1169: } elsif ($command eq 'csvuploadassign') {
1170: if ($ENV{'form.associate'} ne 'Reverse Association') {
1171: $request->print(&csvuploadassign($request));
1172: } else {
1173: if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {
1174: $ENV{'form.upfile_associate'} = 'reverse';
1175: } else {
1176: $ENV{'form.upfile_associate'} = 'forward';
1177: }
1178: $request->print(&csvuploadmap($request));
1179: }
1.12 harris41 1180: } else {
1.23 www 1181: $request->print("Unknown action: $command:");
1.2 albertel 1182: }
1.13 albertel 1183: }
1184: &send_footer($request);
1185: return OK;
1.1 albertel 1186: }
1187:
1188: 1;
1189:
1.13 albertel 1190: __END__;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>