Annotation of loncom/homework/grades.pm, revision 1.39
1.17 albertel 1: # The LearningOnline Network with CAPA
1.13 albertel 2: # The LON-CAPA Grading handler
1.17 albertel 3: #
1.39 ! ng 4: # $Id: grades.pm,v 1.38 2002/07/10 21:08:38 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
1.35 ng 33: # June, July 2002 H.K. Ng
1.30 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;
1.38 ng 43: use Apache::lonmsg qw(:user_normal_msg);
1.1 albertel 44: use Apache::Constants qw(:common);
1.39 ! ng 45: #use Time::HiRes qw( gettimeofday tv_interval );
1.1 albertel 46:
1.2 albertel 47: sub moreinfo {
1.13 albertel 48: my ($request,$reason) = @_;
49: $request->print("Unable to process request: $reason");
50: if ( $Apache::grades::viewgrades eq 'F' ) {
51: $request->print('<form action="/adm/grades" method="post">'."\n");
1.16 albertel 52: if ($ENV{'form.url'}) {
53: $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
54: }
55: if ($ENV{'form.symb'}) {
56: $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
57: }
1.35 ng 58: # $request->print('<input type="hidden" name="command" value="submission" />'."\n");
1.16 albertel 59: $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n");
60: $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n");
61: $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n");
62: $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");
1.13 albertel 63: $request->print('</form>');
64: }
65: return '';
1.2 albertel 66: }
67:
1.23 www 68: sub verifyreceipt {
69: my $request=shift;
70: my $courseid=$ENV{'request.course.id'};
1.34 ng 71: # my $cdom=$ENV{"course.$courseid.domain"};
72: # my $cnum=$ENV{"course.$courseid.num"};
1.23 www 73: my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
74: $ENV{'form.receipt'};
75: $receipt=~s/[^\-\d]//g;
76: my $symb=$ENV{'form.symb'};
77: unless ($symb) {
78: $symb=&Apache::lonnet::symbread($ENV{'form.url'});
79: }
80: if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {
81: $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');
82: my $matches=0;
1.34 ng 83: my ($classlist) = &getclasslist('all','0');
84: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1.23 www 85: my ($uname,$udom)=split(/\:/,$student);
86: if ($receipt eq
87: &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
88: $request->print('Matching '.$student.'<br>');
89: $matches++;
90: }
91: }
1.30 ng 92: $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');
1.33 ng 93: # needs to print who is matched
1.23 www 94: }
95: return '';
96: }
1.13 albertel 97:
1.32 ng 98: sub student_gradeStatus {
1.39 ! ng 99: my ($url,$udom,$uname,$partlist) = @_;
! 100: my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
! 101: my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
! 102: my %partstatus = ();
! 103: foreach (@$partlist) {
! 104: my ($status,$foo)=split(/_/,$record{"resource.$_.solved"},2);
1.32 ng 105: $status = 'nothing' if ($status eq '');
1.39 ! ng 106: $partstatus{$_} = $status;
! 107: }
! 108: return %partstatus;
1.32 ng 109: }
110:
1.34 ng 111: sub get_fullname {
1.39 ! ng 112: my ($uname,$udom) = @_;
1.34 ng 113: my %name=&Apache::lonnet::get('environment', ['lastname','generation',
114: 'firstname','middlename'],
1.39 ! ng 115: $udom,$uname);
1.34 ng 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.39 ! ng 126: sub response_type {
! 127: my ($url) = shift;
! 128: my $allkeys = &Apache::lonnet::metadata($url,'keys');
! 129: my %seen = ();
! 130: my (@partlist,%handgrade);
! 131: foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
! 132: if (/^\w+response_\d{1,2}.*/) {
! 133: my ($responsetype,$part) = split(/_/,$_,2);
! 134: my ($partid,$respid) = split(/_/,$part);
! 135: $handgrade{$part} = $responsetype.':'.($allkeys =~ /parameter_$part\_handgrade/ ? 'yes' : 'no');
! 136: next if ($seen{$partid} > 0);
! 137: $seen{$partid}++;
! 138: push @partlist,$partid;
! 139: }
! 140: }
! 141: return \@partlist,\%handgrade;
! 142: }
! 143:
! 144:
1.30 ng 145: sub listStudents {
146: my ($request) = shift;
1.34 ng 147: my $cdom =$ENV{"course.$ENV{'request.course.id'}.domain"};
148: my $cnum =$ENV{"course.$ENV{'request.course.id'}.num"};
149: my $getsec =$ENV{'form.section'};
150: my $submitonly=$ENV{'form.submitonly'};
1.30 ng 151:
1.39 ! ng 152: my $result='<h2><font color="#339933"> View Submissions for a Student or a Group of Students</font></h2>';
! 153: $result.='<table border="0">';
! 154: $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font></td></tr>';
! 155: my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
! 156: for (sort keys(%$handgrade)) {
! 157: my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
! 158: $result.='<tr><td><b>Part id: </b>'.$_.'</td>'.
! 159: '<td><b>Type: </b>'.$responsetype.'</td>'.
! 160: '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
! 161: }
! 162: $result.='</table>';
! 163: $request->print($result);
! 164:
1.23 www 165: $request->print(<<ENDTABLEST);
1.39 ! ng 166: <form action="/adm/grades" method="post">
1.34 ng 167: <b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no
1.37 ng 168: <input type="radio" name="vProb" value="yes"> yes <br />
169: <b>Submissions: </b>
1.39 ! ng 170: <input type="radio" name="lastSub" value="lastonly" checked /> last sub only
! 171: <input type="radio" name="lastSub" value="last" /> last sub & parts info
! 172: <input type="radio" name="lastSub" value="all" /> all details
! 173: <input type="hidden" name="section" value="$getsec" />
! 174: <input type="hidden" name="submitonly" value="$submitonly" />
! 175: <input type="hidden" name="response" value="$ENV{'form.response'}" />
! 176: <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}" />
! 177: <input type="submit" name="submit" value="View/Grade" />
1.23 www 178: ENDTABLEST
1.34 ng 179: if ($ENV{'form.url'}) {
180: $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
181: }
182: if ($ENV{'form.symb'}) {
183: $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
184: }
185: $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
186:
1.39 ! ng 187: my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
1.38 ng 188:
1.39 ! ng 189: $result='<table border="0"><tr><td bgcolor="#777777">'.
! 190: '<table border="0"><tr bgcolor="#e6ffff">'.
! 191: '<td><b> Select </b></td><td><b> Username </b></td>'.
! 192: '<td><b> Fullname </b></td><td><b> Domain </b></td>';
! 193: foreach (sort(@$partlist)) {
! 194: $result.='<td><b> Part ID '.$_.' Status </b></td>';
! 195: }
! 196: $request->print($result.'</tr>'."\n");
! 197:
! 198: foreach my $student (sort(@{ $$classlist{$getsec} }) ) {
! 199: my ($uname,$udom) = split(/:/,$student);
! 200: my (%status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname,$partlist);
! 201: my $statusflg = '';
! 202: foreach (keys(%status)) {
! 203: $statusflg = 1 if ($status{$_} ne 'nothing');
! 204: }
! 205: next if ($statusflg eq '' && $submitonly eq 'yes');
1.13 albertel 206:
207: if ( $Apache::grades::viewgrades eq 'F' ) {
1.39 ! ng 208: $result='<tr bgcolor="#ffffe6">'.
! 209: '<td align="center"><input type=checkbox name="stuinfo" value="'.
! 210: $student.':'.$$fullname{$student}.'"></td>'."\n".
! 211: '<td> '.$uname.' </td>'."\n".
! 212: '<td> '.$$fullname{$student}.' </td>'."\n".
! 213: '<td align="middle"> '.$udom.' </td>'."\n";
1.34 ng 214:
1.39 ! ng 215: foreach (sort keys(%status)) {
! 216: $result.='<td align="middle"> '.$status{$_}.' </td>'."\n";
! 217: }
! 218: $request->print($result.'</tr>'."\n");
1.13 albertel 219: }
220: }
1.28 ng 221: $request->print('</table></td></tr></table>');
1.34 ng 222: $request->print('<input type="submit" name="submit" value="View/Grade" /><form />');
1.10 ng 223: }
224:
1.34 ng 225: sub processGroup {
226: my ($request) = shift;
227: my $ctr = 0;
228: my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
1.35 ng 229: : ($ENV{'form.stuinfo'}));
1.34 ng 230: my $total = scalar(@stuchecked)-1;
1.35 ng 231: if ($stuchecked[0] eq '') {
232: &userError($request,'No student was selected for viewing/grading.');
233: return;
234: }
235: foreach (@stuchecked) {
1.39 ! ng 236: my ($uname,$udom,$fullname) = split(/:/);
! 237: $ENV{'form.student'} = $uname;
1.34 ng 238: $ENV{'form.fullname'} = $fullname;
239: &submission($request,$ctr,$total);
240: $ctr++;
241: }
1.39 ! ng 242: return '';
1.35 ng 243: }
1.34 ng 244:
1.35 ng 245: sub userError {
246: my ($request, $reason, $step) = @_;
247: $request->print('<h3><font color="red">LON-CAPA User Error</font></h3><br />'."\n");
248: $request->print('<b>Reason: </b>'.$reason.'<br /><br />'."\n");
249: $request->print('<b>Step: </b>'.($step ne '' ? $step : 'Use your browser back button to correct')
250: .'<br /><br />'."\n");
251: return '';
1.34 ng 252: }
1.13 albertel 253:
1.7 albertel 254: #FIXME - needs to handle multiple matches
1.2 albertel 255: sub finduser {
1.13 albertel 256: my ($name) = @_;
257: my $domain = '';
258: if ( $Apache::grades::viewgrades eq 'F' ) {
1.34 ng 259: my ($classlist) = &getclasslist('all','0');
1.35 ng 260: foreach ( sort(@{ $$classlist{'all'} }) ) {
261: my ($posname,$posdomain) = split(/:/);
1.13 albertel 262: if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
1.7 albertel 263: }
1.13 albertel 264: return ($name,$domain);
265: } else {
266: return ($ENV{'user.name'},$ENV{'user.domain'});
267: }
1.5 albertel 268: }
269:
270: sub getclasslist {
1.39 ! ng 271: my ($getsec,$hideexpired) = @_;
! 272: my %classlist=&Apache::lonnet::dump('classlist',
! 273: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
! 274: $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
! 275: my $now = time;
! 276: my (@holdsec,@sections,%allids,%stusec,%fullname);
! 277: foreach (keys(%classlist)) {
! 278: my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
! 279: # still a student?
! 280: if (($hideexpired) && ($end) && ($end < $now)) {
! 281: next;
! 282: }
! 283: $section = ($section ne '' ? $section : 'no');
! 284: push @holdsec,$section;
! 285: if ($getsec eq 'all' || $getsec eq $section) {
! 286: push (@{ $classlist{$getsec} }, $_);
! 287: $allids{$_}=$id;
! 288: $stusec{$_}=$section;
! 289: $fullname{$_}=$fullname;
! 290: }
! 291: }
! 292: my %seen = ();
! 293: foreach my $item (@holdsec) {
! 294: push (@sections, $item) unless $seen{$item}++;
! 295: }
! 296: return (\%classlist,\@sections,\%allids,\%stusec,\%fullname);
1.5 albertel 297: }
298:
299: sub getpartlist {
1.13 albertel 300: my ($url) = @_;
301: my @parts =();
302: my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
303: foreach my $key (@metakeys) {
1.30 ng 304: if ( $key =~ m/stores_([0-9]+)_.*/) {
1.13 albertel 305: push(@parts,$key);
1.6 albertel 306: }
1.13 albertel 307: }
308: return @parts;
1.5 albertel 309: }
310:
311: sub viewstudentgrade {
1.13 albertel 312: my ($url,$symb,$courseid,$student,@parts) = @_;
313: my $cellclr = '"#ffffdd"';
1.28 ng 314: my ($username,$domain) = split(/:/,$student);
1.13 albertel 315:
1.34 ng 316: my $fullname = &get_fullname($username,$domain);
1.28 ng 317: my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);
1.32 ng 318:
1.39 ! ng 319: my $result="<tr bgcolor=$cellclr><td>$username</td><td>$fullname</td><td align=\"middle\">$domain</td>\n";
1.13 albertel 320: foreach my $part (@parts) {
321: my ($temp,$part,$type)=split(/_/,$part);
1.31 ng 322: my $score=$record{"resource.$part.$type"};
323: if ($type eq 'awarded' || $type eq 'tries') {
324: $result.='<td align="middle"><input type="text" name="GRADE.'.$student.'.'.$part.'.'.$type.
325: '" value="'.$score.'" size="4" /></td>'."\n";
1.13 albertel 326: } elsif ($type eq 'solved') {
1.31 ng 327: my ($status,$foo)=split(/_/,$score,2);
1.28 ng 328: $result.="<td align=\"middle\"><select name=\"GRADE.$student.$part.$type\">\n";
1.31 ng 329: my $optsel = '<option>correct</option><option>incorrect</option><option>excused</option>'.
1.39 ! ng 330: '<option>ungraded</option><option>nothing</option>'."\n";
1.31 ng 331: $status = 'nothing' if ($status eq '');
332: $optsel =~ s/<option>$status/<option selected="on">$status/;
333: $result.=$optsel;
1.13 albertel 334: $result.="</select></td>\n";
335: }
336: }
1.38 ng 337: $result.='</td></tr>';
1.13 albertel 338: return $result;
1.5 albertel 339: }
1.31 ng 340:
341: #FIXME need to look at the metadata <stores> spec on what type of data to accept and provide an
1.6 albertel 342: #interface based on that, also do that to above function.
1.5 albertel 343: sub setstudentgrade {
1.13 albertel 344: my ($url,$symb,$courseid,$student,@parts) = @_;
1.34 ng 345: print "set student grade parts=@parts<br>";
1.13 albertel 346: my $result ='';
347: my ($stuname,$domain) = split(/:/,$student);
348: my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);
349: my %newrecord;
350:
351: foreach my $part (@parts) {
352: my ($temp,$part,$type)=split(/_/,$part);
353: my $oldscore=$record{"resource.$part.$type"};
354: my $newscore=$ENV{"form.GRADE.$student.$part.$type"};
1.32 ng 355: print "old=$oldscore:new=$newscore:<br>";
1.13 albertel 356: if ($type eq 'solved') {
357: my $update=0;
358: if ($newscore eq 'nothing' ) {
359: if ($oldscore ne '') {
360: $update=1;
361: $newscore = '';
1.6 albertel 362: }
1.13 albertel 363: } elsif ($oldscore !~ m/^$newscore/) {
364: $update=1;
365: $result.="Updating $stuname to $newscore<br />\n";
1.34 ng 366: if ($newscore eq 'correct') { $newscore = 'correct_by_override'; }
1.13 albertel 367: if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }
1.34 ng 368: if ($newscore eq 'excused') { $newscore = 'excused'; }
369: if ($newscore eq 'ungraded') { $newscore = 'ungraded_attempted'; }
1.39 ! ng 370: # if ($newscore eq 'partial') { $newscore = 'correct_partially_by_override'; }
1.13 albertel 371: } else {
372: #$result.="$stuname:$part:$type:unchanged $oldscore to $newscore:<br />\n";
373: }
374: if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
375: } else {
376: if ($oldscore ne $newscore) {
377: $newrecord{"resource.$part.$type"}=$newscore;
378: $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";
379: } else {
380: #$result.="$stuname:$part:$type:unchanged $oldscore to $newscore:<br />\n";
381: }
382: }
383: }
384: if ( scalar(keys(%newrecord)) > 0 ) {
1.32 ng 385: $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
1.34 ng 386: # &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);
1.13 albertel 387:
388: $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";
389: }
390: return $result;
1.2 albertel 391: }
392:
1.33 ng 393: #
1.32 ng 394: # --------------------------- show submissions of a student, option to grade --------
1.2 albertel 395: sub submission {
1.34 ng 396: my ($request,$counter,$total) = @_;
1.33 ng 397:
1.38 ng 398: (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
399: if ($ENV{'form.student'} eq '') { &moreinfo($request,'Need student login id'); return ''; }
400: my ($uname,$udom) = &finduser($ENV{'form.student'});
401: if ($uname eq '') { &moreinfo($request,'Unable to find student'); return ''; }
402:
403: my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
404: if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
405: my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');
406:
407: # header info
1.34 ng 408: if ($counter == 0) {
1.38 ng 409: &sub_page_js($request);
410: $request->print('<h2> <font color="#339933">Submission Record</font></h2>'.
411: '<font size=+1> <b>Resource: </b>'.$url.'</font>');
412:
413: # option to display problem, only once else it cause problems with the form later
414: # since the problem has a form.
415: if ($ENV{'form.vProb'} eq 'yes') {
416: my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,
417: $ENV{'request.course.id'});
418: my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,
419: $ENV{'request.course.id'});
420: my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">';
421: $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">';
422: $result.='<b>Student\'s view of the problem</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />';
423: $result.='<b>Correct answer:</b><br />'.$companswer;
424: $result.='</td></tr></table>';
425: $result.='</td></tr></table><br />';
426: $request->print($result);
427: }
428:
1.39 ! ng 429: # kwclr is the only variable that is guaranteed to be non blank if this subroutine has been called once.
1.38 ng 430: my %keyhash = ();
431: if ($ENV{'form.kwclr'} eq '') {
432: %keyhash = &Apache::lonnet::dump('nohist_handgrade',
433: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
434: $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
435:
436: my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
437: $ENV{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';
438: $ENV{'form.kwclr'} = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';
439: $ENV{'form.kwsize'} = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';
440: $ENV{'form.kwstyle'} = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';
441: $ENV{'form.msgsub'} = $keyhash{$symb.'_subject'} ne '' ?
442: $keyhash{$symb.'_subject'} : &Apache::lonnet::metadata($url,'title');
443: $ENV{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
444:
445: }
446: $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".
447: '<input type="hidden" name="command" value="handgrade" />'."\n".
1.39 ! ng 448: '<input type="hidden" name="refresh" value="off" />'."\n".
1.38 ng 449: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
450: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
451: '<input type="hidden" name="vProb" value="'.$ENV{'form.vProb'}.'" />'."\n".
452: '<input type="hidden" name="lastSub" value="'.$ENV{'form.lastSub'}.'" />'."\n".
453: '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'">'."\n".
454: '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".
455: '<input type="hidden" name="response" value="'.$ENV{'form.response'}.'">'."\n".
456: '<input type="hidden" name="handgrade" value="'.$ENV{'form.handgrade'}.'">'."\n".
457: '<input type="hidden" name="keywords" value="'.$ENV{'form.keywords'}.'" />'."\n".
458: '<input type="hidden" name="kwclr" value="'.$ENV{'form.kwclr'}.'" />'."\n".
459: '<input type="hidden" name="kwsize" value="'.$ENV{'form.kwsize'}.'" />'."\n".
460: '<input type="hidden" name="kwstyle" value="'.$ENV{'form.kwstyle'}.'" />'."\n".
461: '<input type="hidden" name="msgsub" value="'.$ENV{'form.msgsub'}.'" />'."\n".
462: '<input type="hidden" name="savemsgN" value="'.$ENV{'form.savemsgN'}.'" />'."\n".
463: '<input type="hidden" name="NCT"'.
464: ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : $total+1).'" />'."\n");
465:
466: my ($cts,$prnmsg) = (1,'');
467: while ($cts <= $ENV{'form.savemsgN'}) {
468: $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.
469: ($keyhash{$symb.'_savemsg'.$cts} eq '' ? $ENV{'form.savemsg'.$cts} : $keyhash{$symb.'_savemsg'.$cts}).
470: '" />'."\n";
471: $cts++;
472: }
473: $request->print($prnmsg);
1.32 ng 474:
1.38 ng 475: if ($ENV{'form.handgrade'} eq 'yes') {
476: $request->print(<<KEYWORDS);
477: <b>Keyword Options:</b>
478: <a href="javascript:keywords(document.SCORE.keywords)"; TARGET=_self>List</a>
479: <a href="#" onMouseDown="javascript:getSel(); return false"
480: CLASS="page">Paste Selection to List</a>
481: <a href="javascript:kwhighlight()"; TARGET=_self>Highlight Attribute</a><br /><br />
482: KEYWORDS
483: }
1.33 ng 484: }
485:
1.38 ng 486: # Student info
487: $request->print(($counter == 0 ? '' : '<br />'));
488: my $fullname = ($ENV{'form.fullname'} ne '' ? $ENV{'form.fullname'} : &get_fullname($uname,$udom));
489: my $result.='<table border="0" width=100%><tr><td bgcolor="#777777">'.
490: '<table border="0" width=100%><tr bgcolor="#ffffff"><td>';
1.39 ! ng 491: $result.='<table border="0"><tr bgcolor="#ffffff"><td><b>Fullname: </b>'.$fullname.
! 492: '</td><td> <b>Username: </b>'.$uname.
! 493: '</td><td> <b>Domain: </b>'.$udom.'</td></tr>';
1.38 ng 494: if ($ENV{'form.handgrade'} eq 'yes') {
495: # my $subonly = &get_last_submission($symb,$uname,$udom,$ENV{'request.course.id'});
496: my ($classlist) = &getclasslist('all','0');
497: my @collaborators;
498: # foreach ( sort(@{ $$classlist{'all'} }) ) {
1.39 ! ng 499: # my ($uname,$udom) = split(/:/);
! 500: # push @collaborators,$uname if (grep /\b$uname(\b|\.)/i,$subonly);
1.38 ng 501: # }
502: # push @collaborators,'leede','carlandmm','freyniks'; # as a test to display collaborators.
503: if (scalar(@collaborators) != 0) {
504: $result.='<tr bgcolor="#ffffff"><td colspan=3><b>Collaborators: </b>';
505: foreach (@collaborators) {
506: $result.=$_.' ('.&get_fullname($_,$udom).') ';
507: }
508: $result.='</td></tr>'."\n";
509: $result.='<input type="hidden" name="collaborator'.$counter.
510: '" value="'.(join ':',@collaborators).'" />'."\n";
511: }
1.33 ng 512: }
1.38 ng 513: $result.='</table>'."\n";
514: $request->print($result);
1.33 ng 515:
1.39 ! ng 516: my ($partlist,$handgrade) = &response_type($url);
! 517:
1.38 ng 518: # print student answer
519: if ($ENV{'form.lastSub'} eq 'lastonly') {
520: my ($string,$timestamp)=&get_last_submission ($symb,$uname,$udom,$ENV{'request.course.id'});
521: my $lastsubonly='<table border="0" width=100%><tr><td bgcolor="#777777">';
522: $lastsubonly.='<table border="0" width=100%><tr bgcolor="#ddffff">';
523: $lastsubonly.='<td><b>Last Submission Only</b>'.
1.39 ! ng 524: ($$timestamp eq '' ? '' : ' <b>Date Submitted:</b> '.$$timestamp).'</td></tr>';
! 525: if ($$timestamp eq '') {
! 526: $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0].'</td></tr>';
! 527: } else {
! 528: for my $part (sort keys(%$handgrade)) {
! 529: foreach (@$string) {
! 530: my ($partid,$respid) = /^resource\.(\d{1,2})\.(\d{1,2})\.submission/;
! 531: if ($part eq ($partid.'_'.$respid)) {
! 532: my ($ressub,$subval) = split(/:/,$_,2);
! 533: $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part ID</b> '.
! 534: $partid.' <b>Response ID</b> '.$respid.
! 535: ' <b>Submission</b> '.&keywords_highlight($subval).'</td></tr>';
! 536: }
! 537: }
! 538: }
! 539: }
1.38 ng 540: $lastsubonly.='</td></tr></table></td></tr></table>'."\n";
541: $request->print($lastsubonly);
542: } else {
543: $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
544: $ENV{'request.course.id'},$last,
545: '.submission','Apache::grades::keywords_highlight'));
1.33 ng 546: }
1.32 ng 547:
1.39 ! ng 548: $result='<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n".
! 549: '<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n".
! 550: '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n";
! 551: $result.=' <a href="javascript:msgCenter(document.SCORE,'.$counter.
! 552: ',\''.$fullname.'\')"; TARGET=_self>Compose Message</a><br />'."\n" if ($ENV{'form.handgrade'} eq 'yes');
! 553: $request->print($result);
! 554:
! 555: my %seen = ();
! 556: my @partlist;
! 557: for (sort keys(%$handgrade)) {
! 558: my ($partid,$respid) = split(/_/);
! 559: next if ($seen{$partid} > 0);
! 560: $seen{$partid}++;
! 561: next if ($$handgrade{$_} =~ /:no$/);
! 562: push @partlist,$partid;
! 563: my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
! 564: my $wgtmsg = ($wgt > 0 ? '(problem weight)' : '<font color="red">problem weight assigned by computer</font>');
! 565: $wgt = ($wgt > 0 ? $wgt : '1');
! 566: my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
! 567: my $score = ($record{'resource.0.awarded'} eq '' ? '' : $record{'resource.0.awarded'}*$wgt);
! 568:
! 569: # display grading options
! 570: $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />';
1.38 ng 571:
1.39 ! ng 572: $result.='<table border="0"><tr><td><b>Part </b>'.$partid.' <b>Points</b></td><td>';
1.35 ng 573:
1.39 ! ng 574: my $ctr = 0;
! 575: $result.='<table border="0"><tr>'; # display radio buttons in a nice table 10 across
! 576: while ($ctr<=$wgt) {
! 577: $result.= '<td><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
! 578: 'onclick="javascript:writeBox(this.form.GRADE_BOX'.$counter.'_'.$partid.
! 579: ',this.form.GRADE_SEL'.$counter.'_'.$partid.','.$ctr.
! 580: ',this.form.stores'.$counter.'_'.$partid.')" '.
! 581: ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";
! 582: $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
! 583: $ctr++;
! 584: }
! 585: $result.='</tr></table>';
1.38 ng 586:
1.39 ! ng 587: $result.='</td><td> <b>or</b> </td>';
! 588: $result.='<td><input type="text" name="GRADE_BOX'.$counter.'_'.$partid.'"'.
! 589: ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
! 590: 'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.'_'.$partid.
! 591: ',this.form.GRADE_BOX'.$counter.'_'.$partid.
! 592: ',this.form.GRADE_SEL'.$counter.'_'.$partid.
! 593: ',this.form.stores'.$counter.'_'.$partid.')" /></td>'."\n";
! 594: $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';
! 595:
! 596: $result.='<select name="GRADE_SEL'.$counter.'_'.$partid.'" '.
! 597: 'onChange="javascript:clearRadBox(this.form.RADVAL'.$counter.'_'.$partid.
! 598: ',this.form.GRADE_BOX'.$counter.'_'.$partid.
! 599: ',this.form.GRADE_SEL'.$counter.'_'.$partid.
! 600: ',this.form.stores'.$counter.'_'.$partid.')" />'."\n".
! 601: '<option selected="on"> </option>'.
! 602: '<option>excused</option></select>'."  \n";
! 603: $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="0" />';
! 604: $result.='</td></tr></table>';
! 605: $request->print($result);
1.38 ng 606: }
1.39 ! ng 607: $request->print('<input type="hidden" name="partlist'.$counter.'" value="'.(join ":",@partlist).'" />'."\n");
! 608: $request->print('</td></tr></table></td></tr></table>'."\n");
1.38 ng 609:
610: # print end of form
611: if ($counter == $total) {
612: my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />';
613: my $ntstu ='<select name="NTSTU">'.
614: '<option>1</option><option>2</option>'.
615: '<option>3</option><option>5</option>'.
616: '<option>7</option><option>10</option></select>'."\n";
617: my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');
618: $ntstu =~ s/<option>$nsel/<option selected="on">$nsel/;
619: $endform.=$ntstu.'student(s) ';
620: $endform.='<input type="submit" name="gradeOpt" value="Next" /> ';
621: $endform.='<input type="submit" name="gradeOpt" value="Previous" /> ';
622: $endform.='(Next and Previous do not save the scores.)';
623: $endform.='</td><tr></table></form>';
624: $request->print($endform);
1.36 ng 625: }
626:
1.38 ng 627: return '';
628: }
629:
630: sub get_last_submission {
631: my ($symb,$username,$domain,$course)=@_;
632: if ($symb) {
1.39 ! ng 633: my (@string,$timestamp);
! 634: my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);
! 635: if ($returnhash{'version'}) {
! 636: my %lasthash=();
! 637: my ($version);
! 638: for ($version=1;$version<=$returnhash{'version'};$version++) {
! 639: foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
! 640: $lasthash{$_}=$returnhash{$version.':'.$_};
! 641: }
! 642: }
! 643: foreach ((keys %lasthash)) {
! 644: if ($_ =~ /\.submission$/) {push @string, (join(':',$_,$lasthash{$_}))}
! 645: if ($_ =~ /timestamp/) {$timestamp = scalar(localtime($lasthash{$_}))};
1.38 ng 646: }
1.39 ! ng 647: }
! 648: @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
! 649: return \@string,\$timestamp;
1.35 ng 650: }
1.38 ng 651: }
1.35 ng 652:
1.38 ng 653: sub keywords_highlight {
654: my $string = shift;
655: my $size = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};
656: my $styleon = $ENV{'form.kwstyle'} eq '' ? '' : $ENV{'form.kwstyle'};
657: (my $styleoff = $styleon) =~ s/\</\<\//;
658: my @keylist = split(/[,\s+]/,$ENV{'form.keywords'});
659: foreach (@keylist) {
660: $string =~ s/\b$_(\b|\.)/\<font color\=$ENV{'form.kwclr'} $size\>$styleon$_$styleoff\<\/font\>/gi;
661: }
662: return $string;
663: }
1.36 ng 664:
1.38 ng 665: sub processHandGrade {
666: my ($request) = shift;
667: my $url = $ENV{'form.url'};
668: my $symb = $ENV{'form.symb'};
669: my $button = $ENV{'form.gradeOpt'};
670: my $ngrade = $ENV{'form.NCT'};
671: my $ntstu = $ENV{'form.NTSTU'};
672:
673: my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
674: my %keyhash = ();
675: $ENV{'form.keywords'} =~ s/,\s{0,}|\s+/ /g;
1.39 ! ng 676: $ENV{'form.keywords'} =~ s/^\s+|\s+$//;
1.38 ng 677: $keyhash{$symb.'_keywords'} = $ENV{'form.keywords'};
678: $keyhash{$symb.'_subject'} = $ENV{'form.msgsub'};
679: $keyhash{$loginuser.'_kwclr'} = $ENV{'form.kwclr'};
680: $keyhash{$loginuser.'_kwsize'} = $ENV{'form.kwsize'};
681: $keyhash{$loginuser.'_kwstyle'} = $ENV{'form.kwstyle'};
682:
683: my ($ctr,$idx) = (1,1);
684: while ($ctr <= $ENV{'form.savemsgN'}) {
685: if ($ENV{'form.savemsg'.$ctr} ne '') {
686: $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.savemsg'.$ctr};
687: $idx++;
688: }
689: $ctr++;
690: }
691: $ctr = 0;
692: while ($ctr < $ngrade) {
693: if ($ENV{'form.newmsg'.$ctr} ne '') {
694: $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};
695: $ENV{'form.savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};
696: $idx++;
697: }
698: $ctr++;
699: }
700: $ENV{'form.savemsgN'} = --$idx;
701: $keyhash{$symb.'_savemsgN'} = $ENV{'form.savemsgN'};
702: my $putresult = &Apache::lonnet::put
703: ('nohist_handgrade',\%keyhash,
704: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
705: $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
1.36 ng 706:
1.39 ! ng 707: if ($ENV{'form.refresh'} eq 'on') {
! 708: my $ctr = 0;
! 709: while ($ctr < $ntstu) {
! 710: ($ENV{'form.student'},my $udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
! 711: &submission($request,$ctr,$ntstu-1);
! 712: $ctr++;
! 713: }
! 714: return '';
! 715: }
1.36 ng 716:
1.38 ng 717: if ($button eq 'Save & Next') {
718: my $ctr = 0;
719: while ($ctr < $ngrade) {
720: my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
1.39 ! ng 721: my ($errorflg) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr);
! 722: return '' if ($errorflg eq 'error');
1.36 ng 723:
1.38 ng 724: my $includemsg = $ENV{'form.includemsg'.$ctr};
725: my ($subject,$message,$msgstatus) = ('','','');
726: if ($includemsg =~ /savemsg|new$ctr/) {
727: $subject = $ENV{'form.msgsub'} if ($includemsg =~ /^msgsub/);
728: my (@msgnum) = split(/,/,$includemsg);
729: foreach (@msgnum) {
730: $message.=$ENV{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');
731: }
732: $message =~ s/\s+/ /g;
733: $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,$ENV{'form.msgsub'},$message);
734: }
735: if ($ENV{'form.collaborator'.$ctr}) {
736: my (@collaborators) = split(/:/,$ENV{'form.collaborator'.$ctr});
737: foreach (@collaborators) {
1.39 ! ng 738: &saveHandGrade($request,$url,$symb,$_,$udom,$ctr);
1.38 ng 739: if ($message ne '') {
740: $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,$ENV{'form.msgsub'},$message);
741: }
742: }
743: }
744: $ctr++;
745: }
746: }
747: my $firststu = $ENV{'form.unamedom0'};
748: my $laststu = $ENV{'form.unamedom'.($ngrade-1)};
1.36 ng 749:
1.38 ng 750: my ($classlist) = &getclasslist($ENV{'form.section'},'0');
751: my (@nextlist,@prevlist);
1.39 ! ng 752: my ($nextflg,$ctr,$ctprev) = (0,0,0);
! 753: my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
1.38 ng 754: foreach my $student ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {
755: my ($uname,$udom) = split(/:/,$student);
1.39 ! ng 756: my (%status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname,$partlist);
! 757: my $statusflg = '';
! 758: foreach (keys(%status)) {
! 759: $statusflg = 1 if ($status{$_} ne 'nothing');
! 760: }
! 761: next if ($statusflg eq '' && $ENV{'form.submitonly'} eq 'yes');
1.36 ng 762:
1.38 ng 763: if ($nextflg == 1 && $button =~ /Next$/) {
764: push @nextlist,$uname if ($ctr < $ntstu);
765: $ctr++;
1.39 ! ng 766: last if ($ctr == $ntstu);
1.38 ng 767: }
768: $nextflg = 1 if ($student eq $laststu);
1.39 ! ng 769: if ($button eq 'Previous') {
! 770: last if ($student eq $firststu);
1.38 ng 771: push @prevlist,$uname;
772: $ctprev++;
773: }
774: }
1.39 ! ng 775:
1.38 ng 776: if ($button eq 'Previous') {
777: if ($ctprev <= $ntstu) {
778: @nextlist = @prevlist;
779: } else {
780: my $idx = 0;
781: my $start = $ctprev - $ntstu;
782: while ($idx < $ntstu) {
783: $nextlist[$idx] = $prevlist[$start+$idx];
784: $idx++;
785: }
786: }
787: }
1.39 ! ng 788:
1.38 ng 789: $ctr = 0;
790: my $total = scalar(@nextlist)-1;
791: foreach my $student (@nextlist) {
792: $ENV{'form.student'} = $student;
793: &submission($request,$ctr,$total);
794: $ctr++;
795: }
796: if ($total < 0) {
797: my $the_end = '<h3><font color="red">LON-CAPA User Message</font></h3><br />'."\n";
798: $the_end.='<b>Message: </b> No more students for this section or class.<br /><br />'."\n";
799: $the_end.='Click on the button below to return to the grading menu.<br /><br />'."\n";
800: $the_end.=&show_grading_menu_form ($symb,$url);
801: $request->print($the_end);
802: }
803: return '';
804: }
1.36 ng 805:
1.38 ng 806: sub saveHandGrade {
1.39 ! ng 807: my ($request,$url,$symb,$stuname,$domain,$newflg) = @_;
! 808: # my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
1.38 ng 809: my %newrecord;
1.39 ! ng 810: foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
! 811: if ($ENV{'form.GRADE_SEL'.$newflg.'_'.$_} eq 'excused') {
! 812: $newrecord{'resource.'.$_.'.solved'} = 'excused';
! 813: } else {
! 814: my $pts = ($ENV{'form.GRADE_BOX'.$newflg.'_'.$_} ne '' ?
! 815: $ENV{'form.GRADE_BOX'.$newflg.'_'.$_} : $ENV{'form.RADVAL'.$newflg.'_'.$_});
! 816: if ($pts eq '') {
! 817: &userError($request,'No point was assigned for part id '.$_.' and for username '.$stuname.'.');
! 818: return 'error';
! 819: }
! 820: my $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : $ENV{'form.WGT'.$newflg.'_'.$_};
! 821: my $partial= $pts/$wgt;
! 822: $newrecord{'resource.'.$_.'.awarded'} = $partial;
! 823: if ($partial == 0) {
! 824: $newrecord{'resource.'.$_.'.solved'} = 'incorrect_by_override';
! 825: } else {
! 826: $newrecord{'resource.'.$_.'.solved'} = 'correct_by_override';
! 827: }
1.38 ng 828: }
829: }
1.39 ! ng 830:
1.38 ng 831: if ( scalar(keys(%newrecord)) > 0 ) {
832: $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
1.39 ! ng 833: while (my ($k,$v) = each %newrecord) {
! 834: print "k=$k:v=$v:<br>\n";
! 835: }
1.38 ng 836: # &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$stuname);
837: }
838: return '';
1.36 ng 839: }
1.38 ng 840:
841: sub get_symb_and_url {
842: my ($request) = @_;
843: (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
844: my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
845: if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
846: return ($symb,$url);
1.36 ng 847: }
848:
1.38 ng 849: sub show_grading_menu_form {
850: my ($symb,$url)=@_;
851: my $result.='<form action="/adm/grades" method="post">'."\n".
852: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
853: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
854: '<input type="hidden" name="command" value="gradingmenu" />'."\n".
855: '<input type="submit" name="submit" value="Grading Menu" />'."\n".
856: '</form>'."\n";
857: return $result;
1.36 ng 858: }
859:
1.38 ng 860: sub gradingmenu {
861: my ($request) = @_;
862: my ($symb,$url)=&get_symb_and_url($request);
863: if (!$symb) {return '';}
864: my $result='<h2> <font color="#339933">Select a Grading Method</font></h2>';
865: $result.='<table border="0">';
1.39 ! ng 866: $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$url.'</font></td></tr>';
! 867: my ($partlist,$handgrade) = &response_type($url);
! 868: my ($resptype,$hdgrade)=('','no');
! 869: for (sort keys(%$handgrade)) {
! 870: my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
! 871: $resptype = $responsetype;
! 872: $hdgrade = $handgrade if ($handgrade eq 'yes');
! 873: $result.='<tr><td><b>Part id: </b>'.$_.'</td>'.
! 874: '<td><b>Type: </b>'.$responsetype.'</td>'.
! 875: '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
! 876: }
1.38 ng 877: $result.='</table>';
878: $result.=&view_edit_entire_class_form($symb,$url).'<br />';
879: $result.=&upcsvScores_form($symb,$url).'<br />';
1.39 ! ng 880: $result.=&viewGradeaStu_form($symb,$url,$resptype,$hdgrade).'<br />';
! 881: $result.=&verifyReceipt_form($symb,$url).'<br />';
! 882: $result.=&view_classlist_form($symb,$url);
! 883:
! 884: return $result;
! 885: }
! 886:
! 887: sub view_classlist_form {
! 888: my ($symb,$url)=@_;
! 889: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
! 890: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
! 891: $result.=' <b>View Class List</b></td></tr>'."\n";
! 892: $result.='<tr bgcolor=#ffffe6><td>'."\n";
! 893: $result.='<form action="/adm/grades" method="post">'."\n".
! 894: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
! 895: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
! 896: '<input type="hidden" name="command" value="viewclasslist" />'."\n";
! 897: $result.=' <input type="submit" name="submit" value="View Class" /></form>'."\n";
! 898: $result.='</td></tr></table>'."\n";
! 899: $result.='</td></tr></table>'."\n";
1.38 ng 900: return $result;
1.36 ng 901: }
902:
1.39 ! ng 903: sub viewclasslist {
! 904: my ($request) = shift;
! 905: my ($coursedomain,$coursenum) = split(/_/,$ENV{'request.course.id'});
! 906: my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);
! 907: $request->print('<table border=1>');
! 908: foreach (sort keys(%classlist)) {
! 909: # my ($unam,$udom) = split(/:/,$_,2);
! 910: # my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});
! 911: # my $fullname = &get_fullname ($unam,$udom);
! 912: # my @uname;
! 913: # $uname[0]=$unam;
! 914: # my %userid=&Apache::lonnet::idrget($udom,@uname);
! 915: # my $value=$classlist{$_}.':'.$userid{$unam}.':'.$section.':'.$fullname;
! 916: # $classlist{$_}=$value;
! 917: $request->print('<tr><td>'.$_.' </td><td><pre> '.$classlist{$_}.'</pre></td></tr>');
! 918: }
! 919: $request->print('</table>');
! 920: # my $putresult = &Apache::lonnet::put
! 921: # ('classlist',\%classlist,
! 922: # $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
! 923: # $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
! 924:
! 925: return '';
! 926: }
! 927:
1.38 ng 928: sub view_edit_entire_class_form {
929: my ($symb,$url)=@_;
930: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
931: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
932: $result.=' <b>View/Grade Entire Class</b></td></tr>'."\n";
933: $result.='<tr bgcolor=#ffffe6><td>'."\n";
934: $result.='<form action="/adm/grades" method="post">'."\n".
935: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
936: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
937: '<input type="hidden" name="command" value="viewgrades" />'."\n";
938: $result.=' <b>Display students who has: </b>'.
939: '<input type="radio" name="submitonly" value="yes" checked> submitted'.
940: '<input type="radio" name="submitonly" value="all"> everybody <br /><br />';
941: $result.=' <input type="submit" name="submit" value="View/Grade" /></form>'."\n";
942: $result.='</td></tr></table>'."\n";
943: $result.='</td></tr></table>'."\n";
944: return $result;
1.36 ng 945: }
946:
1.38 ng 947: sub upcsvScores_form {
948: my ($symb,$url) = @_;
949: if (!$symb) {return '';}
950: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
951: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
952: $result.=' <b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";
953: $result.='<tr bgcolor=#ffffe6><td>'."\n";
954: my $upfile_select=&Apache::loncommon::upfile_select_html();
955: $result.=<<ENDUPFORM;
956: <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
957: <input type="hidden" name="symb" value="$symb" />
958: <input type="hidden" name="url" value="$url" />
959: <input type="hidden" name="command" value="csvuploadmap" />
960: $upfile_select
961: <br /> <input type="submit" name="submit" value="Upload Grades" />
962: </form>
963: ENDUPFORM
964: $result.='</td></tr></table>'."\n";
965: $result.='</td></tr></table>'."\n";
966: return $result;
967: }
968:
969: sub viewGradeaStu_form {
970: my ($symb,$url,$response,$handgrade) = @_;
971: my ($classlist,$sections) = &getclasslist('all','0');
972: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
973: $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
974: $result.=' <b>View/Grade an Individual Student\'s Submission</b></td></tr>'."\n";
975: $result.='<tr bgcolor=#ffffe6><td>'."\n";
976: $result.='<form action="/adm/grades" method="post">'."\n".
977: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
978: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
979: '<input type="hidden" name="response" value="'.$response.'" />'."\n".
980: '<input type="hidden" name="handgrade" value="'.$handgrade.'" />'."\n".
981: '<input type="hidden" name="command" value="submission" />'."\n";
1.36 ng 982:
1.38 ng 983: $result.=' <b>Select section:</b> <select name="section">'."\n";
1.39 ! ng 984: foreach (sort (@$sections)) {
! 985: $result.= '<option>'.$_.'</option>'."\n";
1.38 ng 986: }
987: $result.= '<option selected="on">all</select>'."\n";
988: $result.=' <b>Display students who has: </b>'.
989: '<input type="radio" name="submitonly" value="yes" checked> submitted'.
990: '<input type="radio" name="submitonly" value="all"> everybody <br />';
991: $result.=' (Section "no" implies the students were not assigned a section.)<br />'
992: if (grep /no/,@$sections);
1.36 ng 993:
1.38 ng 994: $result.='<br /> <input type="submit" name="submit" value="View/Grade" />'."\n".
995: '</form>'."\n";
996: $result.='</td></tr></table>'."\n";
997: $result.='</td></tr></table>'."\n";
998: return $result;
1.36 ng 999: }
1000:
1.38 ng 1001: sub verifyReceipt_form {
1002: my ($symb,$url) = @_;
1003: my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"};
1004: my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"};
1005: my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});
1.36 ng 1006:
1.38 ng 1007: my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
1008: $result.='<table width=100% border=0><tr><td bgcolor=#e6ffff>'."\n";
1009: $result.=' <b>Verify a Submission Receipt Issued by this Server</td></tr>'."\n";
1010: $result.='<tr bgcolor=#ffffe6><td>'."\n";
1011: $result.='<form action="/adm/grades" method="post">'."\n";
1012: $result.=' <tt>'.$hostver.'-<input type="text" name="receipt" size="4"></tt><br />'."\n";
1013: $result.=' <input type="submit" name="submit" value="Verify Receipt">'."\n";
1014: $result.='<input type="hidden" name="command" value="verify">'."\n";
1015: if ($ENV{'form.url'}) {
1016: $result.='<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />';
1017: }
1018: if ($ENV{'form.symb'}) {
1019: $result.='<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />';
1020: }
1021: $result.='</form>';
1022: $result.='</td></tr></table>'."\n";
1023: $result.='</td></tr></table>'."\n";
1024: return $result;
1.36 ng 1025: }
1026:
1.38 ng 1027: sub viewgrades {
1028: my ($request) = @_;
1029: my $result='';
1030:
1031: #get resource reference
1032: my ($symb,$url)=&get_symb_and_url($request);
1033: if (!$symb) {return '';}
1034: #get classlist
1035: my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});
1036: #print "Found $cdom:$cnum<br />";
1037: my ($classlist) = &getclasslist('all','0');
1038: my $headerclr = '"#ddffff"';
1039: my $cellclr = '"#ffffdd"';
1040:
1041: #get list of parts for this problem
1042: my (@parts) = sort(&getpartlist($url));
1.32 ng 1043:
1.38 ng 1044: $request->print ("<h2><font color=\"#339933\">Manual Grading</font></h2>");
1.37 ng 1045:
1.38 ng 1046: #start the form
1047: $result = '<form action="/adm/grades" method="post">'."\n".
1048: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
1049: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
1050: '<input type="hidden" name="command" value="editgrades" />'."\n".
1051: '<input type="submit" name="submit" value="Submit Changes" />'."\n".
1052: '<table border=0><tr><td bgcolor="#777777">'."\n".
1053: '<table border=0>'."\n".
1054: '<tr bgcolor='.$headerclr.'><td><b>Username</b></td><td><b>Fullname</b></td><td><b>Domain</b></td>'."\n";
1055: foreach my $part (@parts) {
1056: my $display=&Apache::lonnet::metadata($url,$part.'.display');
1057: if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
1058: $result.='<td><b>'.$display.'</b></td>'."\n";
1059: }
1060: $result.='</tr>';
1061: #get info for each student
1062: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1063: # my $display=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
1064: # print "ID=$ENV{'request.course.id'}:STU=$student:DIS=$display:<br>\n";
1065: $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
1.34 ng 1066: }
1.38 ng 1067: $result.='</table></td></tr></table>';
1068: $result.='<input type="submit" name="submit" value="Submit Changes" /></form>';
1069: $result.=&show_grading_menu_form($symb,$url);
1070: return $result;
1071: }
1072:
1073: sub editgrades {
1074: my ($request) = @_;
1075: my $result='';
1.34 ng 1076:
1.38 ng 1077: my $symb=$ENV{'form.symb'};
1078: if ($symb eq '') { $request->print("Unable to handle ambiguous references:$symb:$ENV{'form.url'}"); return ''; }
1079: my $url=$ENV{'form.url'};
1080: #get classlist
1081: # my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});
1082: #print "Found $cdom:$cnum<br />";
1083: my ($classlist) = &getclasslist('all','0');
1.37 ng 1084:
1.38 ng 1085: #get list of parts for this problem
1086: my (@parts) = &getpartlist($url);
1.37 ng 1087:
1.38 ng 1088: $result.='<form action="/adm/grades" method="post">'."\n".
1089: '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
1090: '<input type="hidden" name="url" value="'.$url.'" />'."\n".
1091: '<input type="hidden" name="command" value="viewgrades" />'."\n".
1092: '<input type="submit" name="submit" value="See Grades" /> <br />'."\n";
1.35 ng 1093:
1.38 ng 1094: foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
1095: $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
1.30 ng 1096: }
1.35 ng 1097:
1.38 ng 1098: $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';
1099: return $result;
1100: }
1101:
1102: sub sub_page_js {
1103: my $request = shift;
1104: $request->print(<<SUBJAVASCRIPT);
1105: <script type="text/javascript" language="javascript">
1.39 ! ng 1106: function updateRadio(radioButton,formtextbox,formsel,scores) {
1.38 ng 1107: var pts = formtextbox.value;
1108: var resetbox =false;
1109: if (isNaN(pts) || pts < 0) {
1110: alert("A number equal or greater than 0 is expected. Entered value = "+pts);
1111: for (var i=0; i<radioButton.length; i++) {
1112: if (radioButton[i].checked) {
1113: formtextbox.value = i;
1114: resetbox = true;
1115: }
1116: }
1117: if (!resetbox) {
1118: formtextbox.value = "";
1119: }
1120: return;
1121: }
1.37 ng 1122:
1.38 ng 1123: for (var i=0; i<radioButton.length; i++) {
1124: radioButton[i].checked=false;
1125: if (pts == i) {
1126: radioButton[i].checked=true;
1127: }
1128: }
1.39 ! ng 1129: updateSelect(formsel);
! 1130: scores.value = "0";
1.37 ng 1131: }
1132:
1.39 ! ng 1133: function writeBox(formrad,formsel,pts,scores) {
1.38 ng 1134: formrad.value = pts;
1.39 ! ng 1135: scores.value = "0";
! 1136: updateSelect(formsel,pts);
1.38 ng 1137: return;
1.31 ng 1138: }
1.34 ng 1139:
1.39 ! ng 1140: function clearRadBox(radioButton,formbox,formsel,scores) {
! 1141: for (var i=0; i<formsel.length; i++) {
! 1142: if (formsel[i].selected) {
! 1143: var selectx=i;
! 1144: }
1.38 ng 1145: }
1.39 ! ng 1146: if (selectx == scores.value) { return };
! 1147: formbox.value = "";
! 1148: for (var i=0; i<radioButton.length; i++) {
! 1149: radioButton[i].checked=false;
1.33 ng 1150: }
1.39 ! ng 1151: scores.value = selectx;
! 1152: }
! 1153:
! 1154: function updateSelect(formsel) {
! 1155: formsel[0].selected = true;
1.38 ng 1156: return;
1.33 ng 1157: }
1.37 ng 1158:
1.39 ! ng 1159: //===================== Show list of keywords ====================
1.38 ng 1160: function keywords(keyform) {
1161: var keywds = keyform.value;
1162: var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);
1163: if (nret==null) return;
1164: keyform.value = nret;
1165: return;
1.34 ng 1166: }
1.30 ng 1167:
1.38 ng 1168: //===================== Script to add keyword(s) ==================
1169: function getSel() {
1170: if (document.getSelection) txt = document.getSelection();
1171: else if (document.selection) txt = document.selection.createRange().text;
1172: else return;
1173: var cleantxt = txt.replace(new RegExp('([\\f\\n\\r\\t\\v ])+', 'g')," ");
1174: if (cleantxt=="") {
1175: alert("Select a word or group of words from document and then click this link.");
1176: return;
1.35 ng 1177: }
1.38 ng 1178: var nret = prompt("Add selection to keyword list? Edit if desired.",cleantxt);
1179: if (nret==null) return;
1180: var curlist = document.SCORE.keywords.value;
1181: document.SCORE.keywords.value = curlist+" "+nret;
1182: return;
1.35 ng 1183: }
1184:
1.38 ng 1185: //====================== Script for composing message ==============
1186: function msgCenter(msgform,usrctr,fullname) {
1187: var Nmsg = msgform.savemsgN.value;
1188: savedMsgHeader(Nmsg,usrctr,fullname);
1189: var subject = msgform.msgsub.value;
1190: var rtrchk = eval("document.SCORE.includemsg"+usrctr);
1191: var msgchk = rtrchk.value;
1192: // alert("checked=>"+msgchk);
1193: re = /msgsub/;
1194: var shwsel = "";
1195: if (re.test(msgchk)) { shwsel = "checked" }
1196: displaySubject(subject,shwsel);
1197: for (var i=1; i<=Nmsg; i++) {
1198: var testpt = "savemsg"+i+",";
1199: re = /testpt/;
1200: shwsel = "";
1201: if (re.test(msgchk)) { shwsel = "checked" }
1202: var message = eval("document.SCORE.savemsg"+i+".value");
1203: displaySavedMsg(i,message,shwsel);
1204: }
1205: newmsg = eval("document.SCORE.newmsg"+usrctr+".value");
1206: shwsel = "";
1207: re = /newmsg/;
1208: if (re.test(msgchk)) { shwsel = "checked" }
1209: newMsg(newmsg,shwsel);
1210: msgTail();
1211: return;
1.35 ng 1212: }
1213:
1.38 ng 1214: function savedMsgHeader(Nmsg,usrctr,fullname) {
1215: var height = 30*Nmsg+250;
1216: var scrollbar = "no";
1217: if (height > 600) {
1218: height = 600;
1219: scrollbar = "yes";
1220: }
1221: /* if (window.pWin)
1222: window.pWin.close(); */
1223: pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx=70,screeny=75,width=600,height='+height);
1224: pWin.document.write("<html><head>");
1225: pWin.document.write("<title>Message Central</title>");
1.37 ng 1226:
1.38 ng 1227: pWin.document.write("<script language=javascript>");
1228: pWin.document.write("function checkInput() {");
1229: pWin.document.write(" opener.document.SCORE.msgsub.value = document.msgcenter.msgsub.value;");
1230: pWin.document.write(" var nmsg = opener.document.SCORE.savemsgN.value;");
1231: pWin.document.write(" var usrctr = document.msgcenter.usrctr.value;");
1232: pWin.document.write(" var newval = eval(\\"opener.document.SCORE.newmsg\\"+usrctr);");
1233: pWin.document.write(" newval.value = document.msgcenter.newmsg.value;");
1.37 ng 1234:
1.38 ng 1235: pWin.document.write(" var msgchk = \\"\\";");
1236: pWin.document.write(" if (document.msgcenter.subchk.checked) {");
1237: pWin.document.write(" msgchk = \\"msgsub,\\";");
1238: pWin.document.write(" }");
1239: pWin.document.write( "for (var i=1; i<=nmsg; i++) {");
1240: pWin.document.write(" var opnmsg = eval(\\"opener.document.SCORE.savemsg\\"+i);");
1241: pWin.document.write(" var frmmsg = eval(\\"document.msgcenter.msg\\"+i);");
1242: pWin.document.write(" opnmsg.value = frmmsg.value;");
1243: pWin.document.write(" var chkbox = eval(\\"document.msgcenter.msgn\\"+i);");
1244: pWin.document.write(" if (chkbox.checked) {");
1245: pWin.document.write(" msgchk += \\"savemsg\\"+i+\\",\\";");
1246: pWin.document.write(" }");
1247: pWin.document.write(" }");
1248: pWin.document.write(" if (document.msgcenter.newmsgchk.checked) {");
1249: pWin.document.write(" msgchk += \\"newmsg\\"+usrctr;");
1250: pWin.document.write(" }");
1251: pWin.document.write(" var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);");
1252: pWin.document.write(" includemsg.value = msgchk;");
1.37 ng 1253:
1.38 ng 1254: // pWin.document.write(" alert(\\"slected=\\"+msgchk)");
1255: pWin.document.write(" self.close()");
1.37 ng 1256:
1.38 ng 1257: pWin.document.write("}");
1.34 ng 1258:
1.38 ng 1259: pWin.document.write("<");
1260: pWin.document.write("/script>");
1.33 ng 1261:
1.38 ng 1262: pWin.document.write("</head><body bgcolor=white>");
1.37 ng 1263:
1.38 ng 1264: pWin.document.write("<form action=\\"inactive\\" name=\\"msgcenter\\">");
1265: pWin.document.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">");
1266: pWin.document.write("<font color=\\"green\\" size=+1> Compose Message for \"+fullname+\"</font><br><br>");
1.34 ng 1267:
1.38 ng 1268: pWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
1269: pWin.document.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
1270: pWin.document.write("<td><b>Type</b></td><td><b>Include</b></td><td><b>Message</td></tr>");
1271: }
1272: function displaySubject(msg,shwsel) {
1273: pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
1274: pWin.document.write("<td>Subject</td>");
1275: pWin.document.write("<td align=\\"center\\"><input name=\\"subchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
1276: pWin.document.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+" \\"size=\\"60\\" maxlength=\\"80\\"></td></tr>");
1.34 ng 1277: }
1278:
1.38 ng 1279: function displaySavedMsg(ctr,msg,shwsel) {
1280: pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
1281: pWin.document.write("<td align=\\"center\\">"+ctr+"</td>");
1282: pWin.document.write("<td align=\\"center\\"><input name=\\"msgn"+ctr+"\\" type=\\"checkbox\\"" +shwsel+"></td>");
1283: pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
1.34 ng 1284: }
1285:
1.38 ng 1286: function newMsg(newmsg,shwsel) {
1287: pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
1288: pWin.document.write("<td align=\\"center\\">New</td>");
1289: pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
1.39 ! ng 1290: pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
1.34 ng 1291: }
1292:
1.38 ng 1293: function msgTail() {
1294: pWin.document.write("</table>");
1295: pWin.document.write("</td></tr></table> ");
1296: pWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:checkInput()\\"> ");
1297: pWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
1298: pWin.document.write("</form>");
1299: pWin.document.write("</body></html>");
1300: }
1.34 ng 1301:
1.38 ng 1302: //====================== Script for keyword highlight options ==============
1303: function kwhighlight() {
1304: var kwclr = document.SCORE.kwclr.value;
1305: var kwsize = document.SCORE.kwsize.value;
1306: var kwstyle = document.SCORE.kwstyle.value;
1307: var redsel = "";
1308: var grnsel = "";
1309: var blusel = "";
1310: if (kwclr=="red") {var redsel="checked"};
1311: if (kwclr=="green") {var grnsel="checked"};
1312: if (kwclr=="blue") {var blusel="checked"};
1313: var sznsel = "";
1314: var sz1sel = "";
1315: var sz2sel = "";
1316: if (kwsize=="0") {var sznsel="checked"};
1317: if (kwsize=="+1") {var sz1sel="checked"};
1318: if (kwsize=="+2") {var sz2sel="checked"};
1319: var synsel = "";
1320: var syisel = "";
1321: var sybsel = "";
1322: if (kwstyle=="") {var synsel="checked"};
1323: if (kwstyle=="<i>") {var syisel="checked"};
1324: if (kwstyle=="<b>") {var sybsel="checked"};
1325: highlightCentral();
1326: highlightbody('red','red',redsel,'0','normal',sznsel,'','normal',synsel);
1327: highlightbody('green','green',grnsel,'+1','+1',sz1sel,'<i>','italic',syisel);
1328: highlightbody('blue','blue',blusel,'+2','+2',sz2sel,'<b>','bold',sybsel);
1329: highlightend();
1330: return;
1.34 ng 1331: }
1332:
1333:
1.38 ng 1334: function highlightCentral() {
1335: hwdWin = window.open('', 'KeywordHighlightCentral', 'toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx=100,screeny=75');
1336: hwdWin.document.write("<html><head>");
1337: hwdWin.document.write("<title>Highlight Central</title>");
1.34 ng 1338:
1.38 ng 1339: hwdWin.document.write("<script language=javascript>");
1.39 ! ng 1340: hwdWin.document.write("function updateChoice(flag) {");
1.38 ng 1341: hwdWin.document.write(" opener.document.SCORE.kwclr.value = radioSelection(document.hlCenter.kwdclr);");
1342: hwdWin.document.write(" opener.document.SCORE.kwsize.value = radioSelection(document.hlCenter.kwdsize);");
1343: hwdWin.document.write(" opener.document.SCORE.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");
1.39 ! ng 1344: hwdWin.document.write(" if (flag==1){");
! 1345: hwdWin.document.write(" opener.document.SCORE.refresh.value = \\"on\\";");
! 1346: hwdWin.document.write(" opener.document.SCORE.submit();");
! 1347: hwdWin.document.write(" }");
1.38 ng 1348: hwdWin.document.write(" self.close()");
1349: hwdWin.document.write("}");
1.26 albertel 1350:
1.38 ng 1351: hwdWin.document.write("function radioSelection(radioButton) {");
1352: hwdWin.document.write(" var selection=null;");
1353: hwdWin.document.write(" for (var i=0; i<radioButton.length; i++) {");
1354: hwdWin.document.write(" if (radioButton[i].checked) {");
1355: hwdWin.document.write(" selection=radioButton[i].value;");
1356: hwdWin.document.write(" return selection;");
1357: hwdWin.document.write(" }");
1358: hwdWin.document.write(" }");
1359: hwdWin.document.write("}");
1.26 albertel 1360:
1.38 ng 1361: hwdWin.document.write("<");
1362: hwdWin.document.write("/script>");
1.13 albertel 1363:
1.38 ng 1364: hwdWin.document.write("</head><body bgcolor=white>");
1.13 albertel 1365:
1.38 ng 1366: hwdWin.document.write("<form action=\\"inactive\\" name=\\"hlCenter\\">");
1367: hwdWin.document.write("<font color=\\"green\\" size=+1> Keyword Highlight Options</font><br><br>");
1.13 albertel 1368:
1.38 ng 1369: hwdWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
1370: hwdWin.document.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
1371: hwdWin.document.write("<td><b>Text Color</b></td><td><b>Font Size</b></td><td><b>Font Style</td></tr>");
1.30 ng 1372: }
1.38 ng 1373:
1374: function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) {
1375: hwdWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
1376: hwdWin.document.write("<td align=\\"left\\">");
1377: hwdWin.document.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+"> "+clrtxt+"</td>");
1378: hwdWin.document.write("<td align=\\"left\\">");
1379: hwdWin.document.write("<input name=\\"kwdsize\\" type=\\"radio\\" value=\\""+szval+"\\" "+szsel+"> "+sztxt+"</td>");
1380: hwdWin.document.write("<td align=\\"left\\">");
1381: hwdWin.document.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+"> "+sytxt+"</td>");
1382: hwdWin.document.write("</tr>");
1.13 albertel 1383: }
1.5 albertel 1384:
1.38 ng 1385: function highlightend() {
1386: hwdWin.document.write("</table>");
1387: hwdWin.document.write("</td></tr></table> ");
1.39 ! ng 1388: hwdWin.document.write("<input type=\\"button\\" value=\\"Refresh\\" onClick=\\"javascript:updateChoice(1)\\"> ");
! 1389: hwdWin.document.write("<input type=\\"button\\" value=\\"Set Options\\" onClick=\\"javascript:updateChoice(0)\\"> ");
1.38 ng 1390: hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
1391: hwdWin.document.write("</form>");
1392: hwdWin.document.write("</body></html>");
1.13 albertel 1393: }
1.5 albertel 1394:
1.38 ng 1395: </script>
1396: SUBJAVASCRIPT
1.5 albertel 1397: }
1398:
1.27 albertel 1399: sub csvupload_javascript_reverse_associate {
1400: return(<<ENDPICK);
1401: function verify(vf) {
1402: var foundsomething=0;
1403: var founduname=0;
1404: var founddomain=0;
1405: for (i=0;i<=vf.nfields.value;i++) {
1406: tw=eval('vf.f'+i+'.selectedIndex');
1407: if (i==0 && tw!=0) { founduname=1; }
1408: if (i==1 && tw!=0) { founddomain=1; }
1409: if (i!=0 && i!=1 && tw!=0) { foundsomething=1; }
1410: }
1411: if (founduname==0 || founddomain==0) {
1412: alert('You need to specify at both the username and domain');
1413: return;
1414: }
1415: if (foundsomething==0) {
1416: alert('You need to specify at least one grading field');
1417: return;
1418: }
1419: vf.submit();
1420: }
1421: function flip(vf,tf) {
1422: var nw=eval('vf.f'+tf+'.selectedIndex');
1423: var i;
1424: for (i=0;i<=vf.nfields.value;i++) {
1425: //can not pick the same destination field for both name and domain
1426: if (((i ==0)||(i ==1)) &&
1427: ((tf==0)||(tf==1)) &&
1428: (i!=tf) &&
1429: (eval('vf.f'+i+'.selectedIndex')==nw)) {
1430: eval('vf.f'+i+'.selectedIndex=0;')
1431: }
1432: }
1433: }
1434: ENDPICK
1435: }
1436:
1437: sub csvupload_javascript_forward_associate {
1438: return(<<ENDPICK);
1439: function verify(vf) {
1440: var foundsomething=0;
1441: var founduname=0;
1442: var founddomain=0;
1443: for (i=0;i<=vf.nfields.value;i++) {
1444: tw=eval('vf.f'+i+'.selectedIndex');
1445: if (tw==1) { founduname=1; }
1446: if (tw==2) { founddomain=1; }
1447: if (tw>2) { foundsomething=1; }
1448: }
1449: if (founduname==0 || founddomain==0) {
1450: alert('You need to specify at both the username and domain');
1451: return;
1452: }
1453: if (foundsomething==0) {
1454: alert('You need to specify at least one grading field');
1455: return;
1456: }
1457: vf.submit();
1458: }
1459: function flip(vf,tf) {
1460: var nw=eval('vf.f'+tf+'.selectedIndex');
1461: var i;
1462: //can not pick the same destination field twice
1463: for (i=0;i<=vf.nfields.value;i++) {
1464: if ((i!=tf) && (eval('vf.f'+i+'.selectedIndex')==nw)) {
1465: eval('vf.f'+i+'.selectedIndex=0;')
1466: }
1467: }
1468: }
1469: ENDPICK
1470: }
1471:
1.26 albertel 1472: sub csvuploadmap_header {
1473: my ($request,$symb,$url,$datatoken,$distotal)= @_;
1474: my $result;
1475: my $javascript;
1476: if ($ENV{'form.upfile_associate'} eq 'reverse') {
1.27 albertel 1477: $javascript=&csvupload_javascript_reverse_associate();
1.26 albertel 1478: } else {
1.27 albertel 1479: $javascript=&csvupload_javascript_forward_associate();
1.26 albertel 1480: }
1481: $request->print(<<ENDPICK);
1482: <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
1483: <h3>Uploading Class Grades for resource $url</h3>
1484: <hr>
1485: <h3>Identify fields</h3>
1486: Total number of records found in file: $distotal <hr />
1487: Enter as many fields as you can. The system will inform you and bring you back
1488: to this page if the data selected is insufficient to run your class.<hr />
1489: <input type="button" value="Reverse Association" onClick="javascript:this.form.associate.value='Reverse Association';submit(this.form);" />
1490: <input type="hidden" name="associate" value="" />
1491: <input type="hidden" name="phase" value="three" />
1492: <input type="hidden" name="datatoken" value="$datatoken" />
1493: <input type="hidden" name="fileupload" value="$ENV{'form.fileupload'}" />
1494: <input type="hidden" name="upfiletype" value="$ENV{'form.upfiletype'}" />
1495: <input type="hidden" name="upfile_associate"
1496: value="$ENV{'form.upfile_associate'}" />
1497: <input type="hidden" name="symb" value="$symb" />
1498: <input type="hidden" name="url" value="$url" />
1499: <input type="hidden" name="command" value="csvuploadassign" />
1500: <hr />
1501: <script type="text/javascript" language="Javascript">
1502: $javascript
1503: </script>
1504: ENDPICK
1505: return '';
1506:
1507: }
1508:
1509: sub csvupload_fields {
1510: my ($url) = @_;
1511: my (@parts) = &getpartlist($url);
1.27 albertel 1512: my @fields=(['username','Student Username'],['domain','Student Domain']);
1513: foreach my $part (sort(@parts)) {
1.26 albertel 1514: my @datum;
1515: my $display=&Apache::lonnet::metadata($url,$part.'.display');
1.27 albertel 1516: my $name=$part;
1.26 albertel 1517: if (!$display) { $display = $name; }
1518: @datum=($name,$display);
1519: push(@fields,\@datum);
1520: }
1521: return (@fields);
1522: }
1523:
1524: sub csvuploadmap_footer {
1525: my ($request,$i,$keyfields) =@_;
1526: $request->print(<<ENDPICK);
1527: </table>
1528: <input type="hidden" name="nfields" value="$i" />
1529: <input type="hidden" name="keyfields" value="$keyfields" />
1530: <input type="button" onClick="javascript:verify(this.form)" value="Assign Grades" /><br />
1531: </form>
1532: ENDPICK
1533: }
1534:
1535: sub csvuploadmap {
1536: my ($request)= @_;
1537: my ($symb,$url)=&get_symb_and_url($request);
1538: if (!$symb) {return '';}
1539: my $datatoken;
1540: if (!$ENV{'form.datatoken'}) {
1541: $datatoken=&Apache::loncommon::upfile_store($request);
1542: } else {
1543: $datatoken=$ENV{'form.datatoken'};
1544: &Apache::loncommon::load_tmp_file($request);
1545: }
1546: my @records=&Apache::loncommon::upfile_record_sep();
1547: &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
1548: my $i;
1549: my $keyfields;
1550: if (@records) {
1551: my @fields=&csvupload_fields($url);
1552: if ($ENV{'form.upfile_associate'} eq 'reverse') {
1553: &Apache::loncommon::csv_print_samples($request,\@records);
1554: $i=&Apache::loncommon::csv_print_select_table($request,\@records,
1555: \@fields);
1556: foreach (@fields) { $keyfields.=$_->[0].','; }
1557: chop($keyfields);
1558: } else {
1559: unshift(@fields,['none','']);
1560: $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
1561: \@fields);
1562: my %sone=&Apache::loncommon::record_sep($records[0]);
1563: $keyfields=join(',',sort(keys(%sone)));
1564: }
1565: }
1566: &csvuploadmap_footer($request,$i,$keyfields);
1567: return '';
1.27 albertel 1568: }
1569:
1570: sub csvuploadassign {
1571: my ($request)= @_;
1572: my ($symb,$url)=&get_symb_and_url($request);
1573: if (!$symb) {return '';}
1574: &Apache::loncommon::load_tmp_file($request);
1575: my @gradedata=&Apache::loncommon::upfile_record_sep();
1576: my @keyfields = split(/\,/,$ENV{'form.keyfields'});
1577: my %fields=();
1578: for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
1579: if ($ENV{'form.upfile_associate'} eq 'reverse') {
1580: if ($ENV{'form.f'.$i} ne 'none') {
1581: $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
1582: }
1583: } else {
1584: if ($ENV{'form.f'.$i} ne 'none') {
1585: $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
1586: }
1587: }
1588: }
1589: $request->print('<h3>Assigning Grades</h3>');
1590: my $courseid=$ENV{'request.course.id'};
1.34 ng 1591: # my $cdom=$ENV{"course.$courseid.domain"};
1592: # my $cnum=$ENV{"course.$courseid.num"};
1593: my ($classlist) = &getclasslist('all','1');
1.29 albertel 1594: my @skipped;
1595: my $countdone=0;
1596: foreach my $grade (@gradedata) {
1597: my %entries=&Apache::loncommon::record_sep($grade);
1598: my $username=$entries{$fields{'username'}};
1599: my $domain=$entries{$fields{'domain'}};
1.34 ng 1600: if (!exists($$classlist{"$username:$domain"})) {
1.29 albertel 1601: push(@skipped,"$username:$domain");
1602: next;
1.27 albertel 1603: }
1.29 albertel 1604: my %grades;
1605: foreach my $dest (keys(%fields)) {
1606: if ($dest eq 'username' || $dest eq 'domain') { next; }
1607: if ($entries{$fields{$dest}} eq '') { next; }
1608: my $store_key=$dest;
1609: $store_key=~s/^stores/resource/;
1610: $store_key=~s/_/\./g;
1611: $grades{$store_key}=$entries{$fields{$dest}};
1612: }
1613: $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
1614: &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
1615: $domain,$username);
1616: $request->print('.');
1617: $request->rflush();
1618: $countdone++;
1619: }
1620: $request->print("<br />Stored $countdone students\n");
1621: if (@skipped) {
1622: $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');
1623: foreach my $student (@skipped) { $request->print("<br />$student"); }
1.27 albertel 1624: }
1.29 albertel 1625: $request->print(&view_edit_entire_class_form($symb,$url));
1626: $request->print(&show_grading_menu_form($symb,$url));
1627: return '';
1.26 albertel 1628: }
1629:
1.2 albertel 1630: sub send_header {
1.13 albertel 1631: my ($request)= @_;
1632: $request->print(&Apache::lontexconvert::header());
1.6 albertel 1633: # $request->print("
1634: #<script>
1635: #remotewindow=open('','homeworkremote');
1636: #remotewindow.close();
1637: #</script>");
1.13 albertel 1638: $request->print('<body bgcolor="#FFFFFF">');
1.2 albertel 1639: }
1640:
1641: sub send_footer {
1.13 albertel 1642: my ($request)= @_;
1.2 albertel 1643: $request->print('</body>');
1644: $request->print(&Apache::lontexconvert::footer());
1645: }
1646:
1.1 albertel 1647: sub handler {
1.13 albertel 1648: my $request=$_[0];
1649:
1650: if ($ENV{'browser.mathml'}) {
1651: $request->content_type('text/xml');
1652: } else {
1653: $request->content_type('text/html');
1654: }
1655: $request->send_http_header;
1656: return OK if $request->header_only;
1.16 albertel 1657: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
1.13 albertel 1658: my $url=$ENV{'form.url'};
1659: my $symb=$ENV{'form.symb'};
1660: my $command=$ENV{'form.command'};
1.16 albertel 1661: if (!$url) {
1662: my ($temp1,$temp2);
1663: ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);
1664: $url = $ENV{'form.url'};
1665: }
1.13 albertel 1666: &send_header($request);
1667: if ($url eq '' && $symb eq '') {
1.14 www 1668: if ($ENV{'user.adv'}) {
1669: if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&
1670: ($ENV{'form.codethree'})) {
1671: my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.
1672: $ENV{'form.codethree'};
1673: my ($tsymb,$tuname,$tudom,$tcrsid)=
1674: &Apache::lonnet::checkin($token);
1675: if ($tsymb) {
1676: my ($map,$id,$url)=split(/\_\_\_/,$tsymb);
1677: if (&Apache::lonnet::allowed('mgr',$tcrsid)) {
1678: $request->print(
1679: &Apache::lonnet::ssi('/res/'.$url,
1680: ('grade_username' => $tuname,
1681: 'grade_domain' => $tudom,
1682: 'grade_courseid' => $tcrsid,
1683: 'grade_symb' => $tsymb)));
1684: } else {
1685: $request->print('<h1>Not authorized: '.$token.'</h1>');
1686: }
1687: } else {
1688: $request->print('<h1>Not a valid DocID: '.$token.'</h1>');
1689: }
1690: } else {
1691: $request->print(&Apache::lonxml::tokeninputfield());
1692: }
1693: }
1.13 albertel 1694: } else {
1.29 albertel 1695: #&Apache::lonhomework::showhashsubset(\%ENV,'^form');
1.13 albertel 1696: $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
1697: if ($command eq 'submission') {
1.20 albertel 1698: &listStudents($request) if ($ENV{'form.student'} eq '');
1.34 ng 1699: &submission($request,0,0) if ($ENV{'form.student'} ne '');
1700: } elsif ($command eq 'processGroup') {
1701: &processGroup($request);
1.26 albertel 1702: } elsif ($command eq 'gradingmenu') {
1703: $request->print(&gradingmenu($request));
1.13 albertel 1704: } elsif ($command eq 'viewgrades') {
1705: $request->print(&viewgrades($request));
1.33 ng 1706: } elsif ($command eq 'handgrade') {
1707: $request->print(&processHandGrade($request));
1.13 albertel 1708: } elsif ($command eq 'editgrades') {
1709: $request->print(&editgrades($request));
1.23 www 1710: } elsif ($command eq 'verify') {
1711: $request->print(&verifyreceipt($request));
1.26 albertel 1712: } elsif ($command eq 'csvupload') {
1713: $request->print(&csvupload($request));
1.39 ! ng 1714: } elsif ($command eq 'viewclasslist') {
! 1715: $request->print(&viewclasslist($request));
1.26 albertel 1716: } elsif ($command eq 'csvuploadmap') {
1717: $request->print(&csvuploadmap($request));
1.34 ng 1718: # } elsif ($command eq 'receiptInput') {
1719: # &receiptInput($request);
1.26 albertel 1720: } elsif ($command eq 'csvuploadassign') {
1721: if ($ENV{'form.associate'} ne 'Reverse Association') {
1722: $request->print(&csvuploadassign($request));
1723: } else {
1724: if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {
1725: $ENV{'form.upfile_associate'} = 'reverse';
1726: } else {
1727: $ENV{'form.upfile_associate'} = 'forward';
1728: }
1729: $request->print(&csvuploadmap($request));
1730: }
1.12 harris41 1731: } else {
1.23 www 1732: $request->print("Unknown action: $command:");
1.2 albertel 1733: }
1.13 albertel 1734: }
1735: &send_footer($request);
1736: return OK;
1.1 albertel 1737: }
1738:
1739: 1;
1740:
1.13 albertel 1741: __END__;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>