![]() ![]() | ![]() |
Added some more help, fixed some tex typos.
1: # The LearningOnline Network with CAPA 2: # The LON-CAPA Homework handler 3: # 4: # $Id: lonhomework.pm,v 1.84 2002/07/31 14:56:34 bowersj2 Exp $ 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: # 28: # Guy Albertelli 29: # 11/30 Gerd Kortemeyer 30: # 6/1,8/17,8/18 Gerd Kortemeyer 31: # 7/18 Jeremy Bowers 32: 33: package Apache::lonhomework; 34: use strict; 35: use Apache::style(); 36: use Apache::lonxml(); 37: use Apache::lonnet(); 38: use Apache::lonplot(); 39: use Apache::inputtags(); 40: use Apache::structuretags(); 41: use Apache::randomlabel(); 42: use Apache::response(); 43: use Apache::hint(); 44: use Apache::outputtags(); 45: use Apache::caparesponse(); 46: use Apache::radiobuttonresponse(); 47: use Apache::optionresponse(); 48: use Apache::imageresponse(); 49: use Apache::essayresponse(); 50: use Apache::externalresponse(); 51: use Apache::Constants qw(:common); 52: use HTML::Entities(); 53: use Apache::loncommon(); 54: #use Time::HiRes qw( gettimeofday tv_interval ); 55: 56: BEGIN { 57: &Apache::lonxml::register_insert(); 58: } 59: 60: sub get_target { 61: if ( $ENV{'request.state'} eq "published") { 62: if ( defined($ENV{'form.grade_target'}) 63: && ($Apache::lonhomework::viewgrades == 'F' )) { 64: return ($ENV{'form.grade_target'}); 65: } 66: if ( defined($ENV{'form.submitted'})) { 67: return ('grade', 'web'); 68: } else { 69: return ('web'); 70: } 71: } elsif ($ENV{'request.state'} eq "construct") { 72: if ( defined($ENV{'form.grade_target'}) ) { 73: return ($ENV{'form.grade_target'}); 74: } 75: if ( defined($ENV{'form.preview'})) { 76: if ( defined($ENV{'form.submitted'})) { 77: return ('grade', 'web'); 78: } else { 79: return ('web'); 80: } 81: } else { 82: if ( $ENV{'form.problemmode'} eq 'View' ) { 83: if ( defined($ENV{'form.submitted'}) && 84: (!defined($ENV{'form.resetdata'})) ) { 85: return ('grade', 'web','answer'); 86: } else { 87: return ('web','answer'); 88: } 89: } elsif ( $ENV{'form.problemmode'} eq 'Edit' ) { 90: if ( $ENV{'form.submitted'} eq 'edit' ) { 91: if ( $ENV{'form.submit'} eq 'Submit Changes and View' ) { 92: return ('modified','web','answer'); 93: } else { 94: return ('modified','edit'); 95: } 96: } else { 97: return ('edit'); 98: } 99: } else { 100: return ('web'); 101: } 102: } 103: } 104: return (); 105: } 106: 107: sub setup_vars { 108: my ($target) = @_; 109: return ';' 110: # return ';$external::target='.$target.';'; 111: } 112: 113: sub send_header { 114: my ($request)= @_; 115: $request->print(&Apache::lontexconvert::header()); 116: # $request->print('<form name='.$ENV{'form.request.prefix'}.'lonhomework method="POST" action="'.$request->uri.'">'); 117: } 118: 119: sub createmenu { 120: my ($which,$request)=@_; 121: if ($which eq 'grade') { 122: $request->print('<script language="JavaScript"> 123: hwkmenu=window.open("/res/adm/pages/homeworkmenu.html","homeworkremote", 124: "height=350,width=150,menubar=no"); 125: </script>'); 126: } 127: } 128: 129: sub send_footer { 130: my ($request)= @_; 131: # $request->print('</form>'); 132: $request->print(&Apache::lontexconvert::footer()); 133: } 134: 135: $Apache::lonxml::browse=''; 136: 137: sub check_access { 138: my ($id) = @_; 139: my $date =''; 140: my $status = ''; 141: my $datemsg = ''; 142: my $lastdate = ''; 143: my $temp; 144: my $type; 145: my $passed; 146: &Apache::lonxml::debug("checking for part :$id:"); 147: &Apache::lonxml::debug("time:".time); 148: foreach $temp ("opendate","duedate","answerdate") { 149: $lastdate = $date; 150: $date = &Apache::lonnet::EXT("resource.$id.$temp"); 151: &Apache::lonxml::debug("found :$date: for :$temp:"); 152: if ($date eq '') { 153: $date = "an unknown date"; $passed = 0; 154: } elsif ($date eq 'con_lost') { 155: $date = "an indeterminate date"; $passed = 0; 156: } else { 157: if (time < $date) { $passed = 0; } else { $passed = 1; } 158: $date = localtime $date; 159: } 160: if (!$passed) { $type=$temp; last; } 161: } 162: &Apache::lonxml::debug("have :$type:$passed:"); 163: if ($passed) { 164: $status='SHOW_ANSWER'; 165: $datemsg=$date; 166: } elsif ($type eq 'opendate') { 167: $status='CLOSED'; 168: $datemsg = "will open on $date"; 169: } elsif ($type eq 'duedate') { 170: $status='CAN_ANSWER'; 171: $datemsg = "is due at $date"; 172: } elsif ($type eq 'answerdate') { 173: $status='CLOSED'; 174: $datemsg = "was due on $lastdate, and answers will be available on $date"; 175: } 176: if ($status eq 'CAN_ANSWER') { 177: #check #tries 178: my $tries = $Apache::lonhomework::history{"resource.$id.tries"}; 179: my $maxtries = &Apache::lonnet::EXT("resource.$id.maxtries"); 180: if ( $tries eq '' ) { $tries = '0'; } 181: if ( $maxtries eq '' ) { $maxtries = '2'; } 182: if ($tries >= $maxtries) { $status = 'CANNOT_ANSWER'; } 183: } 184: 185: if (($status ne 'CLOSED') && ($Apache::lonhomework::type eq 'exam') && 186: (!$Apache::lonhomework::history{"resource.0.outtoken"})) { 187: return ('UNCHECKEDOUT','needs to be checked out'); 188: } 189: 190: 191: &Apache::lonxml::debug("sending back :$status:$datemsg:"); 192: if (($Apache::lonhomework::browse eq 'F') && ($status eq 'CLOSED')) { 193: &Apache::lonxml::debug("should be allowed to browse a resource when closed"); 194: $status='CAN_ANSWER'; 195: $datemsg='is closed but you are allowed to view it'; 196: } 197: if ($ENV{'request.state'} eq "construct") { 198: &Apache::lonxml::debug("in construction ignoring dates"); 199: $status='CAN_ANSWER'; 200: $datemsg='is in under construction'; 201: } 202: return ($status,$datemsg); 203: } 204: 205: sub showhash { 206: my (%hash) = @_; 207: &showhashsubset(\%hash,''); 208: return ''; 209: } 210: 211: sub showhashsubset { 212: my ($hash,$keyre) = @_; 213: my $resultkey; 214: foreach $resultkey (sort keys %$hash) { 215: if ($resultkey =~ /$keyre/) { 216: if (ref($$hash{$resultkey})) { 217: if ($$hash{$resultkey} =~ /ARRAY/ ) { 218: my $string="$resultkey ---- ("; 219: foreach my $elm (@{ $$hash{$resultkey} }) { 220: $string.="$elm,"; 221: } 222: chop($string); 223: &Apache::lonxml::debug("$string)"); 224: } else { 225: &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}"); 226: } 227: } else { 228: &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}"); 229: } 230: } 231: } 232: &Apache::lonxml::debug("\n<br />restored values^</br>\n"); 233: return ''; 234: } 235: 236: sub setuppermissions { 237: $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$ENV{'request.filename'}); 238: $Apache::lonhomework::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}); 239: return '' 240: } 241: 242: sub setupheader { 243: my $request=$_[0]; 244: if ($ENV{'browser.mathml'}) { 245: $request->content_type('text/xml'); 246: } else { 247: $request->content_type('text/html'); 248: } 249: if (!$Apache::lonxml::debug && ($ENV{'REQUEST_METHOD'} eq 'GET')) { 250: &Apache::loncommon::no_cache($request); 251: } 252: $request->send_http_header; 253: return OK if $request->header_only; 254: return '' 255: } 256: 257: sub handle_save_or_undo { 258: my ($request,$problem,$result) = @_; 259: my $file = &Apache::lonnet::filelocation("",$request->uri); 260: my $filebak =$file.".bak"; 261: my $filetmp =$file.".tmp"; 262: my $error=0; 263: 264: if ($ENV{'form.Undo'} eq 'undo') { 265: my $error=0; 266: if (!copy($file,$filetmp)) { $error=1; } 267: if ((!$error) && (!copy($filebak,$file))) { $error=1; } 268: if ((!$error) && (!move($filetmp,$filebak))) { $error=1; } 269: if (!$error) { 270: $request->print("<p><b>Undid changes, Switched $filebak and $file</b></p>"); 271: } else { 272: $request->print("<p><font color=\"red\" size=\"+1\"><b>Unable to undo, unable to switch $filebak and $file</b></font></p>"); 273: $error=1; 274: } 275: } else { 276: my $fs=Apache::File->new(">$filebak"); 277: if (defined($fs)) { 278: print $fs $$problem; 279: $request->print("<b>Making Backup to $filebak</b><br />"); 280: } else { 281: $request->print("<font color=\"red\" size=\"+1\"><b>Unable to make backup $filebak</b></font>"); 282: $error=2; 283: } 284: my $fh=Apache::File->new(">$file"); 285: if (defined($fh)) { 286: print $fh $$result; 287: $request->print("<b>Saving Modifications to $file</b><br />"); 288: } else { 289: $request->print("<font color=\"red\" size=\"+1\"><b>Unable to write to $file</b></font>"); 290: $error|=4; 291: } 292: } 293: return $error; 294: } 295: 296: sub analyze { 297: my ($request,$file) = @_; 298: &Apache::lonxml::debug("Analyze"); 299: my $result=&Apache::lonnet::ssi($request->uri,('grade_target' => 'analyze')); 300: &Apache::lonxml::debug(":$result:"); 301: (my $garbage,$result)=split(/_HASH_REF__/,$result,2); 302: &showhash(&Apache::lonnet::str2hash($result)); 303: return $result; 304: } 305: 306: sub editxmlmode { 307: my ($request,$file) = @_; 308: my $result; 309: my $problem=&Apache::lonnet::getfile($file); 310: if ($problem == -1) { 311: &Apache::lonxml::error("<b> Unable to find <i>$file</i></b>"); 312: $problem=''; 313: } 314: if (defined($ENV{'form.editxmltext'}) || defined($ENV{'form.Undo'})) { 315: my $error=&handle_save_or_undo($request,\$problem, 316: \$ENV{'form.editxmltext'}); 317: if (!$error) { $problem=&Apache::lonnet::getfile($file); } 318: } 319: &Apache::lonhomework::showhashsubset(\%ENV,'^form'); 320: if ( $ENV{'form.submit'} eq 'Submit Changes and View' ) { 321: &Apache::lonhomework::showhashsubset(\%ENV,'^form'); 322: $ENV{'form.problemmode'}='View'; 323: &renderpage($request,$file); 324: } else { 325: my ($rows,$cols) = &Apache::edit::textarea_sizes(\$problem); 326: my $xml_help = Apache::loncommon::help_open_topic("Problem_Editor_XML_Index"); 327: if ($cols > 80) { $cols = 80; } 328: $result.='<html><body bgcolor="#FFFFFF"> 329: <form name="lonhomework" method="POST" action="'. 330: $ENV{'request.uri'}.'"> 331: <input type="hidden" name="problemmode" value="EditXML" /> 332: <input type="submit" name="problemmode" value="Discard Edits and View" /> 333: <input type="submit" name="problemmode" value="Edit" /> 334: <hr /> 335: <input type="submit" name="submit" value="Submit Changes" /> 336: <input type="submit" name="submit" value="Submit Changes and View" /> 337: <input type="submit" name="Undo" value="undo" /> 338: <hr /> 339: ' . $xml_help . ' Problem Help<br> 340: <textarea rows="'.$rows.'" cols="'.$cols.'" name="editxmltext">'. 341: &HTML::Entities::encode($problem).'</textarea> 342: </form></body></html>'; 343: $request->print($result); 344: } 345: return ''; 346: } 347: 348: sub renderpage { 349: my ($request,$file) = @_; 350: 351: my (@targets) = &get_target(); 352: &Apache::lonxml::debug("Running targets ".join(':',@targets)); 353: foreach my $target (@targets) { 354: #my $t0 = [&gettimeofday()]; 355: my $problem=&Apache::lonnet::getfile($file); 356: if ($problem == -1) { 357: &Apache::lonxml::error("<b> Unable to find <i>$file</i></b>"); 358: $problem=''; 359: } 360: 361: my %mystyle; 362: my $result = ''; 363: &Apache::inputtags::initialize_inputtags; 364: &Apache::edit::initialize_edit; 365: if ($target eq 'analyze') { %Apache::lonhomework::anaylze=(); } 366: if ($target eq 'web') { 367: my ($symb)=&Apache::lonxml::whichuser(); 368: if ($symb eq '') { 369: if ($ENV{'request.state'} eq "construct") { 370: } else { 371: my $help = Apache::loncommon::help_open_topic("Ambiguous_Reference"); 372: $request->print("Browsing or <a href=\"/adm/ambiguous\">ambiguous</a> reference, submissions ignored $help<br />"); 373: } 374: } 375: #if ($Apache::lonhomework::viewgrades eq 'F') {&createmenu('grade',$request); } 376: } 377: #if ($target eq 'grade') { &showhash(%Apache::lonhomework::history); } 378: #if ($target eq 'web') { &showhash(%ENV); } 379: 380: my $default=&Apache::lonnet::getfile('/home/httpd/html/res/adm/includes/default_homework.lcpm'); 381: if ($default == -1) { 382: &Apache::lonxml::error("<b>Unable to find <i>default_homework.lcpm</i></b>"); 383: $default=''; 384: } 385: &Apache::lonxml::debug("Should be parsing now"); 386: $result = &Apache::lonxml::xmlparse($request, $target, $problem, 387: $default.&setup_vars($target),%mystyle); 388: 389: #$request->print("Result follows:"); 390: if ($target eq 'modified') { 391: &handle_save_or_undo($request,\$problem,\$result); 392: } else { 393: if ($target eq 'analyze') { 394: $result=&Apache::lonnet::hashref2str(\%Apache::lonhomework::analyze); 395: undef(%Apache::lonhomework::analyze); 396: } 397: #my $td=&tv_interval($t0); 398: #if ( $Apache::lonxml::debug) { 399: #$result =~ s:</body>::; 400: #$result.="<br />Spent $td seconds processing target $target\n</body>"; 401: #} 402: $request->print($result); 403: } 404: #$request->print(":Result ends"); 405: #my $td=&tv_interval($t0); 406: } 407: } 408: 409: # with no arg it returns a HTML <option> list of the template titles 410: # with one arg it returns the filename associated with the arg passed 411: sub get_template_list { 412: my ($namewanted,$extension) = @_; 413: my $result; 414: &Apache::lonxml::debug("Looking for :$extension:"); 415: foreach my $file (</home/httpd/html/res/adm/includes/templates/*.$extension>) { 416: my $name=&Apache::lonnet::metadata($file,'title'); 417: if ($namewanted && ($name eq $namewanted)) { 418: $result=$file; 419: last; 420: } else { 421: $result.="<option>$name</option>"; 422: } 423: } 424: return $result; 425: } 426: 427: sub newproblem { 428: my ($request) = @_; 429: my $extension=$request->uri; 430: $extension=~s:^.*\.([\w]+)$:$1:; 431: &Apache::lonxml::debug("Looking for :$extension:"); 432: if ($ENV{'form.template'}) { 433: use File::Copy; 434: my $file = &get_template_list($ENV{'form.template'},$extension); 435: my $dest = &Apache::lonnet::filelocation("",$request->uri); 436: copy($file,$dest); 437: &renderpage($request,$dest); 438: } elsif($ENV{'form.newfile'}) { 439: # I don't like hard-coded filenames but for now, this will work. 440: use File::Copy; 441: my $templatefilename = 442: $request->dir_config('lonIncludes').'/templates/blank.problem'; 443: &Apache::lonxml::debug("$templatefilename"); 444: my $dest = &Apache::lonnet::filelocation("",$request->uri); 445: copy($templatefilename,$dest); 446: &renderpage($request,$dest); 447: }else { 448: my $templatelist=&get_template_list('',$extension); 449: my $url=$request->uri; 450: my $dest = &Apache::lonnet::filelocation("",$request->uri); 451: if (!defined($templatelist)) { 452: # We didn't find a template, so just create a blank problem. 453: $request->print(<<ENDNEWPROBLEM); 454: <body bgcolor="#FFFFFF"> 455: The requested file $url doesn\'t exist. You can create a new $extension <br /> 456: <form action="$url" method="POST"> 457: <input type="submit" name="newfile" value="New $extension"><br /> 458: </form> 459: </body> 460: ENDNEWPROBLEM 461: return ''; 462: } 463: $request->print(<<ENDNEWPROBLEM); 464: <body bgcolor="#FFFFFF"> 465: The requested file $url doesn\'t exist. You can create a new $extension <br /> 466: <form action="$url" method="POST"> 467: <input type="submit" value="New $extension"><br /> 468: <select name="template"> 469: $templatelist 470: </select> 471: </form> 472: </body> 473: ENDNEWPROBLEM 474: } 475: return ''; 476: } 477: 478: sub view_or_edit_menu { 479: my ($request) = @_; 480: my $url=$request->uri; 481: $request->print(<<EDITMENU); 482: <body bgcolor="#FFFFFF"> 483: <form action="$url" method="POST"> 484: Would you like to <input type="submit" name="problemmode" value="View"> or 485: <input type="submit" name="problemmode" value="Edit"> the problem. 486: </form> 487: </body> 488: EDITMENU 489: } 490: 491: sub handler { 492: #my $t0 = [&gettimeofday()]; 493: my $request=$_[0]; 494: 495: if ( $ENV{'user.name'} eq 'albertel' ) {$Apache::lonxml::debug=1;} 496: 497: if (&setupheader($request)) { return OK; } 498: $ENV{'request.uri'}=$request->uri; 499: 500: #setup permissions 501: $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$ENV{'request.filename'}); 502: $Apache::lonhomework::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}); 503: &Apache::lonxml::debug("Permissions:$Apache::lonhomework::browse:$Apache::lonhomework::viewgrades:"); 504: # some times multiple problemmodes are submitted, need to select 505: # the last one 506: &Apache::lonxml::debug("Problem Mode ".$ENV{'form.problemmode'}); 507: if ( defined($ENV{'form.problemmode'}) && 508: ref($ENV{'form.problemmode'}) ) { 509: &Apache::lonxml::debug("Problem Mode ".join(",",@$ENV{'form.problemmode'})); 510: my $mode=$ENV{'form.problemmode'}->[-1]; 511: undef $ENV{'form.problemmode'}; 512: $ENV{'form.problemmode'}=$mode; 513: } 514: &Apache::lonxml::debug("Problem Mode ".$ENV{'form.problemmode'}); 515: my $file=&Apache::lonnet::filelocation("",$request->uri); 516: 517: #check if we know where we are 518: if ($ENV{'request.course.fn'} && !&Apache::lonnet::symbread()) { 519: # if we are browsing we might not be able to know where we are 520: if ($Apache::lonhomework::browse ne 'F') { 521: #should know where we are, so ask 522: $request->internal_redirect('/adm/ambiguous'); return; 523: } 524: } 525: 526: if ($ENV{'request.state'} eq "construct") { 527: if ($ENV{'form.resetdata'} eq 'Reset Submissions') { 528: my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); 529: &Apache::lonnet::tmpreset($symb,'',$domain,$name); 530: } 531: if ( -e $file ) { 532: if (!(defined $ENV{'form.problemmode'})) { 533: #first visit to problem in construction space 534: #&view_or_edit_menu($request); 535: $ENV{'form.problemmode'}='View'; 536: &renderpage($request,$file); 537: } elsif ($ENV{'form.problemmode'} eq 'EditXML') { 538: &editxmlmode($request,$file); 539: } elsif ($ENV{'form.problemmode'} eq 'Answer Distribution') { 540: &analyze($request,$file); 541: } else { 542: &renderpage($request,$file); 543: } 544: } else { 545: # requested file doesn't exist in contruction space 546: &newproblem($request); 547: } 548: } else { 549: # just render the page normally outside of construction space 550: &Apache::lonxml::debug("not construct"); 551: &renderpage($request,$file); 552: } 553: #my $td=&tv_interval($t0); 554: #&Apache::lonxml::debug("Spent $td seconds processing"); 555: # &Apache::lonhomework::send_footer($request); 556: # always turn off debug messages 557: $Apache::lonxml::debug=0; 558: return OK; 559: 560: } 561: 562: 1; 563: __END__