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