You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(53) |
Feb
(56) |
Mar
|
Apr
|
May
(30) |
Jun
(78) |
Jul
(121) |
Aug
(155) |
Sep
(77) |
Oct
(61) |
Nov
(45) |
Dec
(94) |
2006 |
Jan
(116) |
Feb
(33) |
Mar
(11) |
Apr
(23) |
May
(60) |
Jun
(89) |
Jul
(130) |
Aug
(109) |
Sep
(124) |
Oct
(63) |
Nov
(82) |
Dec
(45) |
2007 |
Jan
(31) |
Feb
(35) |
Mar
(123) |
Apr
(36) |
May
(18) |
Jun
(134) |
Jul
(133) |
Aug
(241) |
Sep
(126) |
Oct
(31) |
Nov
(15) |
Dec
(5) |
2008 |
Jan
(11) |
Feb
(6) |
Mar
(16) |
Apr
(29) |
May
(43) |
Jun
(149) |
Jul
(27) |
Aug
(29) |
Sep
(37) |
Oct
(20) |
Nov
(4) |
Dec
(6) |
2009 |
Jan
(34) |
Feb
(30) |
Mar
(16) |
Apr
(6) |
May
(1) |
Jun
(32) |
Jul
(22) |
Aug
(7) |
Sep
(18) |
Oct
(50) |
Nov
(22) |
Dec
(8) |
2010 |
Jan
(17) |
Feb
(15) |
Mar
(10) |
Apr
(9) |
May
(67) |
Jun
(30) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
|
From: Sam H. v. a. <act...@de...> - 2005-01-07 20:32:49
|
Log Message: ----------- HEAD -> rel-2-1-patches backport: "help files now use module name instead of urlpath node name" Tags: ---- rel-2-1-patches Modified Files: -------------- webwork2/lib/WeBWorK: ContentGenerator.pm Added Files: ----------- webwork2/htdocs/helpFiles: Grades.html InstructorAddUsers.html InstructorAssigner.html InstructorFileManager.html InstructorFileTransfer.html InstructorPreflight.html InstructorProblemSetDetail.html InstructorProblemSetList.html InstructorScoring.html InstructorSendMail.html InstructorSetMaker.html InstructorStats.html InstructorUserList.html InstructorUsersAssignedToSet.html Options.html ProblemSets.html Problems.html Removed Files: ------------- webwork2/htdocs/helpFiles: add_users.html course_home.html file_manager.html file_transfer.html mail_merge.html preflight_log.html problems.html scoring_tools.html set_assigner.html set_list.html set_maker.html statistics.html student_grades.html user_list.html user_options.html users_assigned_to_set.html Revision Data ------------- --- htdocs/helpFiles/student_grades.html +++ /dev/null @@ -1,31 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/student_grades.html,v 1.1 2004/0= 7/12 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Student Grades Help Page</title> -</head> - -<body><br> -<p> -<p>The "Ind" column is : (totalNumberOfCorrectProblems / totalNumberOfP= roblems)^2/ AvgNumberOfAttemptsPerProblem), which is a more=20 -useful number when it comes to summarizing how well you are doing. -</p> -<p>In the problems section of the chart the upper letter represents whet= her or not the problem was answered correctly (C for=20 -correct) and the lower number is the number of times the problem was att= empted.</p> -</body> -</html> --- htdocs/helpFiles/file_manager.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html - PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -=09 -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/file_manager.html,v 1.1 2004/10/= 12 18:15:03 gage Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> -<head> -<title>File Manager Help Page</title> -</head> - -<body><br> -<h3>File Manager Help Page</h3> - -<p align=3D"left"> -The File Manager module will soon replace the File Transfer module. We'= ll keep -both available for the time being. -<p> -Locations of files: -<dl> - <dt>Set definition (".def") files</dt> - <dd>These are stored in the templates directory. To view the format f= or=20 - <strong>Set Definition files</strong> see - <a href=3D"http://webwork.math.rochester.edu/docs/docs/courseadmin/set= definitionformat.html" target=3D"Webworkdocs">Set Definition specificatio= n </a> - or download set0.def and copy that. Set definition files are mainly - useful for transferring set assignments from one course to another. - (For example from a calculus course taught the previous year.)They con= tain a - list of problems used and the dates and times. - These definitions can be imported into the current course and a set in= the current course - can be exported to a set definition files.</dd> - <dt>Class list (".lst") files</dt> - <dd>The classlist files are stored in the templates directory and prov= ide - a convenient way to enter a large number of students into your - class. To view the format for <strong>ClassList files</strong> see - <a href=3D"http://webhost.math.rochester.edu/webworkdocs/discuss/msgRe= ader$59#2397" target=3D"Webworkdocs">ClassList specification</a> - or download demoCourse.lst and use it as a model.=20 - ClassList files can be - prepared using a spreadsheet and then saved as .csv (comma separated - variables) text files. </dd> - <dt>Scoring (".csv") files</dt> - <dd>The scoring files are stored in the scoring directory and are prod= uced=20 - using the "Scoring" module or the scoring command in the "Instructor T= ools" module. - These files can be downloaded, modified in a spread sheet (for example= , add midterm scores) - and then uploaded again to the scoring directory to be merged with ema= il messages. (Use - a new file name, other than courseName_totals.csv, when uploading to p= revent the=20 - scoring module from overwriting an uploaded file.) - ) - </dd> - <dt>Problem template (".pg") files</dt> - <dd>These provide the template from which are problems are created and= =20 - are located in the template directory. They can be edited directly u= sing - the "edit problem" link on each problem page. The File Manager allows = you to - upload or download these files so that you can save them on your deskt= op.</dd> - <dt>html directory</dt> - <dd>This directory is accessible from the web. You can use it to store= html documents - or image documents that are used by the course. Do not store private = information in - this directory or in any subdirectory.These documents can be pointed t= o from within - problems using the htmlLink macro</dd> - <dt>templates/email directory</dt> - <dd>This is where email messages are saved. You can upload or downloa= d files in=20 - this directory if you wish to save the files for later.</dd> - <dt>templates/macros directory</dt> - <dd>Macro (".pl") files containing favorite macros for your course can= be stored here. Those - being used for many courses should be stored in pg/macros.</dd> -</dl> - - -</p> - =20 - -<p align=3D"left"> - -</p> - - -</body> -</html> --- /dev/null +++ htdocs/helpFiles/InstructorUsersAssignedToSet.html @@ -0,0 +1,27 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorUsersAssignedToSet.htm= l,v 1.1.2.1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Users Assigned to Set Help Page</title> +</head> + +<body><br> +<p>A student needs to be assigned a set in order for them to do it. Once= a student is unassigned a set, all the data for them is lost=20 +and there's no way to undo it. When unassigning be sure to change the op= tion to "Allow unassign".</p> +</body> +</html> --- /dev/null +++ htdocs/helpFiles/InstructorUserList.html @@ -0,0 +1,29 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorUserList.html,v 1.1.2.= 1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>User List Help Page</title> +</head> +<h3>Class List Editor Help Page</h3> +<body> +<p>Only one of the five actions may be taken at a time. After filling ou= t the options to the action the "Take Action" button must be=20 +pressed to do the action. After one action is completed another may be d= one.</p> +<p>The first option changes how many student's are shown below in the ta= ble.</p> + +</body> +</html> --- htdocs/helpFiles/course_home.html +++ /dev/null @@ -1,45 +0,0 @@ -<!DOCTYPE html - PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -=09 -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/course_home.html,v 1.1 2004/07/1= 0 18:17:06 gage Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> -<head> -<title>Course Home Help Page</title> -</head> - -<body><br> -<h3>Course Home Help Page</h3> -<p align=3D"left"> -This is the standard entry point for the course. -</p> - -<p align=3D"left"> -It lists the homework problem sets available for the students. -</p> - -<p align=3D"left"> -The information box on the right displays information is useful for -leaving course wide messages for students. It contains text from the fi= le=20 -templates/course_info.txt. Instructors can edit this file from the=20 -web (click on the "edit" link). -</p> -=20 -</body> -</html> --- /dev/null +++ htdocs/helpFiles/Grades.html @@ -0,0 +1,31 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/Grades.html,v 1.1.2.1 2005/01/07= 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Student Grades Help Page</title> +</head> + +<body><br> +<p> +<p>The "Ind" column is : (totalNumberOfCorrectProblems / totalNumberOfP= roblems)^2/ AvgNumberOfAttemptsPerProblem), which is a more=20 +useful number when it comes to summarizing how well you are doing. +</p> +<p>In the problems section of the chart the upper letter represents whet= her or not the problem was answered correctly (C for=20 +correct) and the lower number is the number of times the problem was att= empted.</p> +</body> +</html> --- /dev/null +++ htdocs/helpFiles/InstructorProblemSetDetail.html @@ -0,0 +1,184 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +=09 +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorProblemSetDetail.html,= v 1.1.2.1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> +<head> +<title>Set Detail Help Page</title> +</head> + +<body> + +<h2>Set Detail Help Page</h2> + + +<h3> Quick Links </h3> + +<ul> + <li> I do <i>foo</i> and nothing seems to happen! </li> + <li> My problems are in random order </li> + <li> My nose is leaking. </li> + <li> How does this work? </li> +</ul> + +<h3> "Modes" </h3> + +<p>The <strong>Set Detail</strong> page can be viewed in one of three di= stinct modes: + <ul> + <li> All students </li> + <li> One specific student </li> + <li> Many students </li> + </ul> + +This should be quite clear at the top of the page. If one or more of th= e students selected has not +had this set assigned to them, then those students will be ignored (they= are listed). This can be fixed +if needed by clicking on the link <a href=3D"#">x users</a> or the navig= ation link <a href=3D"#">Set Assigner</a> + +<p><small>Note: There is a subtle difference between editing a set for a= n entire class and editting it +for <i>every</i> student in the set at once. If you select all the stud= ents and edit the set for all +of them, any new students added after those changes will get the old, un= changed information. Unless you +have good reason, it is best to edit the set in general.</small> + +</p> + +<h3> Contents </h3> + +<ul type=3D"1"> + <li> <a href=3D"#form">Form buttons</a> + <li> <a href=3D"#general">General Information</a> + <li> <a href=3D"#headers">Headers</a> + <li> <a href=3D"#problems">Problems</a> +</ul> + + + + +<h4> <a name=3D"form">Form buttons</a> </h4> +<dl> + <dt> Save Changes </dt> + <dd>Occurs twice on the page, at the top and the bottom. <br>Any and = all changes made to any + part of the set will be saved with one important exception: When editt= ing the set for one + or more students, you can choose to override the default value (define= d for the set in=20 + general) by clicking on the checkbox and providing a value (or possibl= y leaving a blank). + If you do <strong>NOT</strong> check the checkbox, the override value = will be discarded. + <p><small>Example:</small> + <br><input type=3D"checkbox"> Weight <input value=3D2 size=3D5> 1 + <br><input type=3D"checkbox" checked> Weight <input value=3D2 size=3D5= > 1 + <br><small>The first value of 2 will be discarded because the checkbox= is not checked.</small> + </dd> + <dt> Reset Form </dt> + <dd>Discards any and all changes, reloading the page by re-reading the= database information + for this set. Also, resets the display modes.<p></dd> + <dt> Refresh Display </dt> + <dd>You can maintain a different display mode for the headers and for = the problems if you want. + <br>"Refresh Display" does not commit any of the changes currently in = the form, but it also + does not reset the form so you can safely change the display mode with= out making any permanent + changes to the set and without losing any work up to that point. + <p><small>Example:</small> + <br><strong>Display Mode: </strong> + <select> + <option>plainText</option> + <option>formattedText</option> + + <option selected>images</option> + <option>jsMath</option> + <option>asciimath</option> + <option>None</option> + </select> + <input type=3D"submit" value=3D"Refresh Display"> + <br><small>Change display mode to "images"</small> + </dd> + <dt> Reorder problems only </dt> + <dd>Sometimes it could be necessary to want to change the order of the= problems in a set=20 + without actually make any changes to the information about that proble= m. This can even + be done individually for one or more students. If all you want to is = reorder the problems, + this is <strong>much</strong> faster than "Save Changes". However, an= y changes made in the form and not yet + saved <strong>will be lost</strong>. + =09 + </dd> +</dl> + +<h4> <a name=3D"general">General Information</a> </h4> + + +<!-- +<p align=3D"left"> +The File Manager module will soon replace the File Transfer module. We'= ll keep +both available for the time being. +<p> +Locations of files: +<dl> + <dt>Set definition (".def") files</dt> + <dd>These are stored in the templates directory. To view the format f= or=20 + <strong>Set Definition files</strong> see + <a href=3D"http://webwork.math.rochester.edu/docs/docs/courseadmin/set= definitionformat.html" target=3D"Webworkdocs">Set Definition specificatio= n </a> + or download set0.def and copy that. Set definition files are mainly + useful for transferring set assignments from one course to another. + (For example from a calculus course taught the previous year.)They con= tain a + list of problems used and the dates and times. + These definitions can be imported into the current course and a set in= the current course + can be exported to a set definition files.</dd> + <dt>Class list (".lst") files</dt> + <dd>The classlist files are stored in the templates directory and prov= ide + a convenient way to enter a large number of students into your + class. To view the format for <strong>ClassList files</strong> see + <a href=3D"http://webhost.math.rochester.edu/webworkdocs/discuss/msgRe= ader$59#2397" target=3D"Webworkdocs">ClassList specification</a> + or download demoCourse.lst and use it as a model.=20 + ClassList files can be + prepared using a spreadsheet and then saved as .csv (comma separated + variables) text files. </dd> + <dt>Scoring (".csv") files</dt> + <dd>The scoring files are stored in the scoring directory and are prod= uced=20 + using the "Scoring" module or the scoring command in the "Instructor T= ools" module. + These files can be downloaded, modified in a spread sheet (for example= , add midterm scores) + and then uploaded again to the scoring directory to be merged with ema= il messages. (Use + a new file name, other than courseName_totals.csv, when uploading to p= revent the=20 + scoring module from overwriting an uploaded file.) + ) + </dd> + <dt>Problem template (".pg") files</dt> + <dd>These provide the template from which are problems are created and= =20 + are located in the template directory. They can be edited directly u= sing + the "edit problem" link on each problem page. The File Manager allows = you to + upload or download these files so that you can save them on your deskt= op.</dd> + <dt>html directory</dt> + <dd>This directory is accessible from the web. You can use it to store= html documents + or image documents that are used by the course. Do not store private = information in + this directory or in any subdirectory.These documents can be pointed t= o from within + problems using the htmlLink macro</dd> + <dt>templates/email directory</dt> + <dd>This is where email messages are saved. You can upload or downloa= d files in=20 + this directory if you wish to save the files for later.</dd> + <dt>templates/macros directory</dt> + <dd>Macro (".pl") files containing favorite macros for your course can= be stored here. Those + being used for many courses should be stored in pg/macros.</dd> +</dl> + + +</p> + =20 + +<p align=3D"left"> + +</p> + +--> +</body> +</html> --- htdocs/helpFiles/set_assigner.html +++ /dev/null @@ -1,27 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/set_assigner.html,v 1.1 2004/07/= 12 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Set Assigner Help Page</title> -</head> - -<body><br> -<p>Either list can be reordered by changing the criteria and pushing the= button. Then multiple sets can be assigned to a user, or=20 -multiple users to a set.</p> -</body> -</html> --- /dev/null +++ htdocs/helpFiles/InstructorSendMail.html @@ -0,0 +1,34 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorSendMail.html,v 1.1.2.= 1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Mail Merge Help Page</title> +</head> + +<body><br> +<p>Emails can be sent from this page to the class. Be sure to change all= blanks which read "fixme". The email can be sent to +all students, or some subset. To change the way the students are ordered= , after selecting the criteria, push the "Change Display=20 +Settings" button.</p> +<p>Personalized data can be inserted into the message using any of the v= ariables available in the drop down menu titled "list of=20 +insertable macros". Most of the personal data does not need a merge file= , but if you wish to include scoring data, you must select=20 +that scoring file as the merge file, and then enter the score into the m= essage by using what ever column the score is in. For example, +if the scores where in the 4 column of s0scr.cvs then I would set the me= rge file to that file, and then type $COL[4] to have that +be the score.</p> +<p>The size of the email box can be changed by changing the numbers in t= he "columns" and "rows" boxes and pressing enter.</p> +</body> +</html> --- /dev/null +++ htdocs/helpFiles/ProblemSets.html @@ -0,0 +1,45 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +=09 +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/ProblemSets.html,v 1.1.2.1 2005/= 01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> +<head> +<title>Course Home Help Page</title> +</head> + +<body><br> +<h3>Course Home Help Page</h3> +<p align=3D"left"> +This is the standard entry point for the course. +</p> + +<p align=3D"left"> +It lists the homework problem sets available for the students. +</p> + +<p align=3D"left"> +The information box on the right displays information is useful for +leaving course wide messages for students. It contains text from the fi= le=20 +templates/course_info.txt. Instructors can edit this file from the=20 +web (click on the "edit" link). +</p> +=20 +</body> +</html> --- /dev/null +++ htdocs/helpFiles/InstructorAssigner.html @@ -0,0 +1,27 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorAssigner.html,v 1.1.2.= 1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Set Assigner Help Page</title> +</head> + +<body><br> +<p>Either list can be reordered by changing the criteria and pushing the= button. Then multiple sets can be assigned to a user, or=20 +multiple users to a set.</p> +</body> +</html> --- htdocs/helpFiles/statistics.html +++ /dev/null @@ -1,30 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/statistics.html,v 1.1 2004/07/12= 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Statistics Help Page</title> -</head> - -<body><br> -<p>This page is a useful tool for Professors who want to see how their s= tudents are doing. Statistics can either be viewed for a single -set or for a single user simply by clicking on the link.</p> -<p>The "Ind" column is : (totalNumberOfCorrectProblems / totalNumberOfP= roblems)^2/ AvgNumberOfAttemptsPerProblem), which is a more=20 -useful number when it comes to summarizing how well students are doing.<= /p> -<p>The bottom most chart on the set statistics can be resorted by any co= lumn by clicking the blue link of that column's name.</p> -</body> -</html> --- /dev/null +++ htdocs/helpFiles/InstructorAddUsers.html @@ -0,0 +1,37 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +=09 +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorAddUsers.html,v 1.1.2.= 1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> +<head> +<title>Add User Help Page</title> +</head> + +<body><br> +<h3>Add User Help Page</h3> +<p>The number of rows can be changed by changing the number in the text = box and hitting the "create" button, but be careful,=20 +once some information is entered do not change the number of rows or all= the text in the boxes will be lost.</p> +<p>The only mandatory information is the "login" and the "Student ID", t= he Student ID will be the student's initial password.</p> +<p> Any other boxes may be left blank, but it may be useful to fill in s= ection and recitation as they can be used to seperate=20 +scores later on.</p> +<p>Multiple sets may be given to the user by holding down the shift key = while selecting from the list.</p> + +</body> +</html> --- htdocs/helpFiles/scoring_tools.html +++ /dev/null @@ -1,28 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/scoring_tools.html,v 1.1 2004/07= /12 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Scoring Tools Help Page</title> -</head> - -<body><br> -<p>The files created by this page contain all the scoring data in a comm= a delimited file. This file can easily be opened by a=20 -spreadsheet program. To download the file after it's been created click = on the link below, or go to the file transfer page -where scoring files may also be downloaded.</p> -</body> -</html> --- htdocs/helpFiles/problems.html +++ /dev/null @@ -1,29 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/problems.html,v 1.1 2004/07/12 1= 1:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Problems Help Page</title> -</head> - -<body><br> -<p>If you want to see the problems change the display mode and press "Re= fresh". The order of problems can be changed by changing the -numbers. After a problem is deleted (by checking delete and then the "Sa= ve Problem Changes" button on the bottom of the page)=20 -the number is left empty unless the option above the button is checked. = The -weight of a problem is how many points will be awarded for it during sco= ring.</p> -</body> -</html> --- /dev/null +++ htdocs/helpFiles/InstructorSetMaker.html @@ -0,0 +1,32 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorSetMaker.html,v 1.1.2.= 1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Problem Set Maker Help Page</title> +</head> + +<body><br> +<p>This page is used to create problem sets. The first step is to choose= which set your working on. If you need to name a new problem=20 +set fill in the blank next to the "Create a New Set in This Course" butt= on and then press the button. Then choose which set you want to +work on in the drop down menu.</p> +<p>Use the options in the uppermost box to pick a collection of problems= to look at, and then to add problems to the set select them=20 +and then hit update.</p> +<p>To set the open and close dates, assign the set to users, delete prob= lems from the set, or change their order, click on the=20 +"Edit Taget Set" button.</p> +</body> +</html> --- htdocs/helpFiles/users_assigned_to_set.html +++ /dev/null @@ -1,27 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/users_assigned_to_set.html,v 1.1= 2004/07/12 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Users Assigned to Set Help Page</title> -</head> - -<body><br> -<p>A student needs to be assigned a set in order for them to do it. Once= a student is unassigned a set, all the data for them is lost=20 -and there's no way to undo it. When unassigning be sure to change the op= tion to "Allow unassign".</p> -</body> -</html> --- htdocs/helpFiles/set_maker.html +++ /dev/null @@ -1,32 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/set_maker.html,v 1.1 2004/07/12 = 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Problem Set Maker Help Page</title> -</head> - -<body><br> -<p>This page is used to create problem sets. The first step is to choose= which set your working on. If you need to name a new problem=20 -set fill in the blank next to the "Create a New Set in This Course" butt= on and then press the button. Then choose which set you want to -work on in the drop down menu.</p> -<p>Use the options in the uppermost box to pick a collection of problems= to look at, and then to add problems to the set select them=20 -and then hit update.</p> -<p>To set the open and close dates, assign the set to users, delete prob= lems from the set, or change their order, click on the=20 -"Edit Taget Set" button.</p> -</body> -</html> --- htdocs/helpFiles/user_options.html +++ /dev/null @@ -1,28 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/user_options.html,v 1.1 2004/07/= 12 11:29:25 lr003k Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>User Option Help Page</title> -</head> - -<body><br> -<p>The password can be any combination of letters, numbers and special s= ymbols. Students are encouraged to use all three, and stay=20 -away from dictionary words. Also you should not use the same password yo= u use elsewhere, such as on your email account.</p> -<p>It is important that you enter your email address or you won't reciev= e any of the important emails your professor sends you.</p> -</body> -</html> --- htdocs/helpFiles/user_list.html +++ /dev/null @@ -1,29 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/user_list.html,v 1.2 2004/07/10 = 21:43:56 gage Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>User List Help Page</title> -</head> -<h3>Class List Editor Help Page</h3> -<body> -<p>Only one of the five actions may be taken at a time. After filling ou= t the options to the action the "Take Action" button must be=20 -pressed to do the action. After one action is completed another may be d= one.</p> -<p>The first option changes how many student's are shown below in the ta= ble.</p> - -</body> -</html> --- /dev/null +++ htdocs/helpFiles/InstructorProblemSetList.html @@ -0,0 +1,85 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorProblemSetList.html,v = 1.1.2.1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Set List Help Page</title> +</head> +<body> +<p> After selecting a task with the radio buttons (round buttons on the = left),=20 +click the "Take action" button. +</p> +<hr> +<dl> + <dt>Show</dt> + <dd>Display sets matching a selected criteria. =20 + Useful if there are many sets, such as in a library.</dd> + <dt>Sort</dt> + <dd>Sorts the lists displayed; by due date, name, etc.</dd> + <dt>Edit</dt> + <dd>The sets checked below will become available for editing the due d= ates and set headers.</dd> + <dt>Make visible/hidden</dt> + <dd>The sets checked below will be visible to students or hidden from = students. Useful for preparing sets + ahead of time, but not showing them to students; or for temporaril= y hiding a set which has a mistake in=20 + it while it is being fixed.</dd> + <dt>Import</dt> + <dd>Import a set from a set definition file.=20 + (Use "File Transfer" to upload/download set definition files.)</dd= > + <dt>Export</dt> + <dd>The sets checked below will written to set definition files, to be= saved for future use, or=20 + to be transferred to another course. The set definition files can= be uploaded/downloaded=20 + using "File Transfer". + </dd> + <dt>Score</dt> + <dd>Student scores for the sets selected below will be calculated. Th= is and other scoring operations + can also be done using the "Scoring Tools" link. </dd> + <dt>Create</dt> + <dd>Create a new, empty set. This can also be done directly from the = "Library Browser".</dd> + <dt>Delete</dt> + <dd>Delete the sets checked below. Be careful, this cannot be undone.<= /dd> +</dl> +<hr> +Other actions +<dl> + <dt>"Edit Problems" column</dt> + <dd>Indicates the number of problems in the set. Clicking on this lin= k allows you to edit the set headers, + change the problem order, specifying the number of allowed attempts an= d the weight (credit value) of each problem. + You can also inspect and edit the template of the problem and delete t= he problem entirely. =20 + <p> + To add new problems use the "Library Browser". + </dd> + <dt>"Edit Assigned Sets" column</dt> + <dd>Shows how many instructors and students have been assigned this pr= oblem set, out of the total number in the class.=20 + (While testing it is best to assign + the problem only to instructors and TA's; once the set is ready, a= ssign it to the entire class or section.) + Clicking on this link allows you to assign or unassign this set to= additional users and to individually edit=20 + the assignment to specific users. For changing dates for individua= l users there are also=20 + shortcuts from the "Instructor Tools" link. + </dd> + <dt>Changing dates</dt> + <dd>Dates for problem sets can be edited by clicking the pencil in the= "Edit Set Data" column next to the set name. + To change dates for several sets at once, click the check box in t= he "Select" column and=20 + choose "Edit selected" from the tasks above. + <p> + For those upgrading from WW2.0 to WW2.1: The headers have moved --= to edit them click in the "Edit problems" column. + </dd> + +</dl> + + +</body> +</html> --- htdocs/helpFiles/file_transfer.html +++ /dev/null @@ -1,50 +0,0 @@ -<!DOCTYPE html - PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -=09 -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/file_transfer.html,v 1.2 2004/07= /10 21:43:56 gage Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> -<head> -<title>File Transfer Help Page</title> -</head> - -<body><br> -<h3>File Transfer Help Page</h3> - -<p align=3D"left"> -To view the format for <strong>ClassList files</strong> see -<a href=3D"http://webhost.math.rochester.edu/webworkdocs/discuss/msgRead= er$59#2397" target=3D"Webworkdocs">ClassList specification</a> -or download demoCourse.lst and use it as a model.=20 -ClassList files can be -prepared using a spreadsheet and then saved as .csv (comma separated -variables) text files. -</p> - =20 - -<p align=3D"left"> -To view the format for <strong>Set Definition files</strong> see -<a href=3D"http://webwork.math.rochester.edu/docs/docs/courseadmin/setde= finitionformat.html" target=3D"Webworkdocs">Set Definition specification = </a> -or download set0.def and copy that. Set definition files are mainly -useful for transferring course assignments from one course to another. -(For example from a calculus course taught the previous year.) -</p> - - -</body> -</html> --- /dev/null +++ htdocs/helpFiles/InstructorFileTransfer.html @@ -0,0 +1,50 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +=09 +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorFileTransfer.html,v 1.= 1.2.1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> +<head> +<title>File Transfer Help Page</title> +</head> + +<body><br> +<h3>File Transfer Help Page</h3> + +<p align=3D"left"> +To view the format for <strong>ClassList files</strong> see +<a href=3D"http://webhost.math.rochester.edu/webworkdocs/discuss/msgRead= er$59#2397" target=3D"Webworkdocs">ClassList specification</a> +or download demoCourse.lst and use it as a model.=20 +ClassList files can be +prepared using a spreadsheet and then saved as .csv (comma separated +variables) text files. +</p> + =20 + +<p align=3D"left"> +To view the format for <strong>Set Definition files</strong> see +<a href=3D"http://webwork.math.rochester.edu/docs/docs/courseadmin/setde= finitionformat.html" target=3D"Webworkdocs">Set Definition specification = </a> +or download set0.def and copy that. Set definition files are mainly +useful for transferring course assignments from one course to another. +(For example from a calculus course taught the previous year.) +</p> + + +</body> +</html> --- /dev/null +++ htdocs/helpFiles/InstructorScoring.html @@ -0,0 +1,28 @@ +<html> +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorScoring.html,v 1.1.2.1= 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<head> +<title>Scoring Tools Help Page</title> +</head> + +<body><br> +<p>The files created by this page contain all the scoring data in a comm= a delimited file. This file can easily be opened by a=20 +spreadsheet program. To download the file after it's been created click = on the link below, or go to the file transfer page +where scoring files may also be downloaded.</p> +</body> +</html> --- /dev/null +++ htdocs/helpFiles/InstructorFileManager.html @@ -0,0 +1,92 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +=09 +<!-- +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork2/htdocs/helpFiles/InstructorFileManager.html,v 1.1= .2.1 2005/01/07 20:17:09 sh002i Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## +--> +<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en-US"> +<head> +<title>File Manager Help Page</title> +</head> + +<body><br> +<h3>File Manager Help Page</h3> + +<p align=3D"left"> +The File Manager module will soon replace the File Transfer module. We'= ll keep +both available for the time being. +<p> +Locations of files: +<dl> + <dt>Set definition (".def") files</dt> + <dd>These are stored in the templates directory. To view the format f= or=20 + <strong>Set Definition files</strong> see + <a href=3D"http://webwork.math.rochester.edu/docs/docs/courseadmin/set= definitionformat.html" target=3D"Webworkdocs">Set Definition specificatio= n </a> + or download set0.def and copy that. Set definition files are mainly + useful for transferring set assignments from one course to another. + (For example from a calculus course taught the previous year.)They con= tain a + list of problems used and the dates and times. + These definitions can be imported into the current course and a set in= the current course + can be exported to a set definition files.</dd> + <dt>Class list (".lst") files</dt> + <dd>The classlist files are stored in the templates directory and prov= ide + a convenient way to enter a large number of students into your + class. To view the format for <strong>ClassList files</strong> see + <a href=3D"http://webhost.math.rochester.edu/webworkdocs/discuss/msgRe= ader$59#2397" target=3D"Webworkdocs">ClassList specification</a> + or download demoCourse.lst and use it as a model.=20 + ClassList files can be + prepared using a spreadsheet and then saved as .csv (comma separated + variables) text files. </dd> + <dt>Scoring (".csv") files</dt> + <dd>The scoring files are stored in the scoring directory and are prod= uced=20 + using the "Scoring" module or the scoring command in the "Instructor T= ools" module. + These files can be downloaded, modified in a spread sheet (for example= , add midterm scores) + and then uploaded again to the scoring directory to be merged with ema= il messages. (Use + a new file name, other than courseName_totals.csv, when uploading to p= revent the=20 + scoring module from overwriting an uploaded file.) + ) + </dd> + <dt>Problem template (".pg") files</dt> + <dd>These provide the template from which are problems are created and= =20 + are located in the template directory. They can be edited directly u= sing + the "edit problem" link on each problem page. The File Manager allows = you to + upload or download these files so that you can save them on your deskt= op.</dd> + <dt>html directory</dt> + <dd>This directory is accessible from the web. You can use it to store= html documents + or image documents that are used by the course. Do not store private = information in + this directory or in any subdirectory.These documents can be pointed t= o from within + problems using the htmlLink macro</dd> + <dt>templates/email directory</dt> + <dd>This is where email messages are saved. You can upload or downloa= d files in=20 + this directory if you wish to save the files for later.</dd> + <dt>templates/macros directory</dt> + <dd>Macro (".pl") files containing favorite macros for your course can= be stored here. Those + being used for many courses should be stored in pg/macros.</dd> +</dl> + + +</p> + =20 + +<p align=3D"left"> + +</p> + + +</body> +</html> --- htdocs/helpFiles/set_list.html +++ /dev/null @@ -1,85 +0,0 @@ -<html> -<!-- -########################################################################= ######## -# WeBWorK Online Homework Delivery System -# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / -# $CVSHeader: webwork2/htdocs/helpFiles/set_list.html,v 1.5 2004/09/24 1= 2:36:50 gage Exp $ -#=20 -# This program is free software; you can redistribute it and/or modify i= t under -# the terms of either: (a) the GNU General Public License as published b= y the -# Free Software Foundation; either version 2, or (at your option) any la= ter -# version, or (b) the "Artistic License" which comes with this package. -#=20 -# This program is distributed in the hope that it will be useful, but WI= THOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS -# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the -# Artistic License for more details. -########################################################################= ######## ---> -<head> -<title>Set List Help Page</title> -</head> -<body> -<p> After selecting a task with the radio buttons (round buttons on the = left),=20 -click the "Take action" button. -</p> -<hr> -<dl> - <dt>Show</dt> - <dd>Display sets matching a selected criteria. =20 - Useful if there are many sets, such as in a library.</dd> - <dt>Sort</dt> - <dd>Sorts the lists displayed; by due date, name, etc.</dd> - <dt>Edit</dt> - <dd>The sets checked bel... [truncated message content] |
From: Sam H. v. a. <act...@de...> - 2005-01-06 21:20:25
|
Log Message: ----------- fixes to set assignment code Modified Files: -------------- webwork2/bin: ww_db_v2_to_v3 webwork2/lib/WeBWorK: DBv3.pm Revision Data ------------- Index: ww_db_v2_to_v3 =================================================================== RCS file: /webwork/cvs/system/webwork2/bin/ww_db_v2_to_v3,v retrieving revision 1.4 retrieving revision 1.5 diff -Lbin/ww_db_v2_to_v3 -Lbin/ww_db_v2_to_v3 -u -r1.4 -r1.5 --- bin/ww_db_v2_to_v3 +++ bin/ww_db_v2_to_v3 @@ -296,7 +296,7 @@ my $i = retrieve_all WeBWorK::DBv3::Role; while (my $Role = $i->next) { $role_names{$Role->name} = 1; - my @role_privs = sort $Role->priv_list; + my @role_privs = sort $Role->privs_list; foreach my $level (keys %levels) { if (listeq($levels{$level}, \@role_privs)) { @@ -325,8 +325,8 @@ my @privs = @{ $levels{$level} }; - my $Role = create WeBWorK::DBv3::Role({name => $name }); - $Role->priv_list(@privs); + my $Role = create WeBWorK::DBv3::Role({name => $name}); + $Role->privs_list(@privs); $Role->update; debug("Added role '", $Role->name, "' (ID $Role) with privileges '@privs'.\n"); $level_to_role_id{$level} = $Role->id; @@ -400,18 +400,15 @@ my $course_db = WeBWorK::DB->new($course_ce->{dbLayout}); - # First we see if this course already exists. If it does, there's a problem - # and we throw an exception. - if (search WeBWorK::DBv3::Course(name => $courseID)) { - die "Course '$courseID' exists in v3 DB"; - } - - debug("Course '$courseID' doesn't exist in v3 DB -- adding.\n"); - my $v3Course = create WeBWorK::DBv3::Course({name => $courseID}); + debug("Adding course '$courseID' to v3 DB.\n"); + my $v3Course = eval { create WeBWorK::DBv3::Course({name => $courseID}) }; + $@ =~ /Duplicate entry/ and die "Course '$courseID' exists in v3 DB.\n"; + $@ and die $@; copy_users($course_db, $v3Course, $abbrev_to_status_id, $level_to_role_id); - copy_abstract_data($course_db, $v3Course); + # { $globalSetID => [ $v3AbsSet->id, { $globalProblemID => $vAbsProb->id, ... }, ... } + my %global_set_id_to_abstract_set_data = copy_abstract_data($course_db, $v3Course); } ################################################################################ @@ -588,6 +585,8 @@ sub copy_abstract_data { my ($course_db, $v3Course) = @_; + my %global_set_id_to_abstract_set_data; + my @globalSetIDs = $course_db->listGlobalSets; my %GlobalSets; @GlobalSets{@globalSetIDs} = $course_db->getGlobalSets(@globalSetIDs); @@ -627,6 +626,9 @@ }); debug(" added abstract_set ID '$v3AbsSet'.\n"); + + my %problem_mapping; + my @globalProblemIDs = sort { $a <=> $b } $course_db->listGlobalProblems($globalSetID); warn "globalProblemIDs=@globalProblemIDs\n"; my %GlobalProblems; @GlobalProblems{@globalProblemIDs} @@ -665,6 +667,8 @@ debug(" added abstract_problem ID '$v3AbsProb'.\n"); push @problem_order, $v3AbsProb->id; + + $problem_mapping{$globalProblemID} = $v3AbsProb->id; } # update problem order @@ -672,20 +676,28 @@ $v3AbsSet->problem_order_list(@problem_order); $v3AbsSet->update; debug(" done.\n"); + + $global_set_id_to_abstract_set_data{$globalSetID} = [ $v3AbsSet->id, \%problem_mapping ]; } + + return %global_set_id_to_abstract_set_data; } +################################################################################ +sub copy_assignment_data { + my ($course_db, $v3Course, $global_set_id_to_abstract_set_data) = @_; + + my $participant_iter = WeBWorK::DBv3::Participant->search(course => $v3Course); + + while (my $Participant = $participant_iter->next) { + my @userSetIDs = $course_db->listUserSets($Participant->user->login_id); + $v3AbsSet-> + } +} - - - - - - - - - - - - +sub copy_single_assignment { + my ($course_db, $v3Course, $v3Participant, $v3AbsSet, $global_set_id_to_abstract_set_data) = @_; + + +} Index: DBv3.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DBv3.pm,v retrieving revision 1.8 retrieving revision 1.9 diff -Llib/WeBWorK/DBv3.pm -Llib/WeBWorK/DBv3.pm -u -r1.8 -r1.9 --- lib/WeBWorK/DBv3.pm +++ lib/WeBWorK/DBv3.pm @@ -660,11 +660,6 @@ sub assign_to_participant { my ($self, $Participant) = @_; - my $already_assigned = count_search_where WeBWorK::DBv3::SetAssignment( - abstract_set => $self, - participant => $Participant, - ); - my $SetAssignment = eval { create WeBWorK::DBv3::SetAssignment({ abstract_set => $self, @@ -675,27 +670,34 @@ "' is already assigned to participant '", $Participant->user->name, "'.\n"; $@ and die $@; - my @problem_order = $self->problem_order_list; + # order in which to assign abstract problems to participant + my @problem_assignment_order = $self->problem_order_list; + # if it's time to reorder, we do that now if ($self->reorder_time eq "assignment") { - my @new_problem_order = @problem_order; + # randomize? if ($self->reorder_type eq "none") { # leave order alone } elsif ($self->reorder_type eq "random") { # randomize - fisher_yates_shuffle(\@new_problem_order); + fisher_yates_shuffle(\@problem_assignment_order); } + # take a subset? if (defined $self->reorder_subset_size) { my $range = $self->reorder_subset_size; - if ($range < @new_problem_order) { - @new_problem_order = @new_problem_order[0 .. $range-1]; + if ($range < @problem_assignment_order) { + @problem_assignment_order = @problem_assignment_order[0 .. $range-1]; } } + } + + # order of assigned problems + my @assigned_problem_order; + + foreach my $abs_prob_id (@problem_assignment_order) { - # set problem order for assignment - $SetAssignment->problem_order_list(@new_problem_order); } } |
From: dpvc v. a. <act...@de...> - 2005-01-04 18:11:58
|
Log Message: ----------- Fixed index problem with matrix multiplciation. (It was returning the transpose!) Modified Files: -------------- pg/lib/Value: Matrix.pm Revision Data ------------- Index: Matrix.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Matrix.pm,v retrieving revision 1.12 retrieving revision 1.13 diff -Llib/Value/Matrix.pm -Llib/Value/Matrix.pm -u -r1.12 -r1.13 --- lib/Value/Matrix.pm +++ lib/Value/Matrix.pm @@ -233,9 +233,9 @@ # my @l = $l->value; my @r = $r->value; my @M = (); - foreach my $j (0..$dr[1]-1) { + foreach my $i (0..$dl[0]-1) { my @row = (); - foreach my $i (0..$dl[0]-1) { + foreach my $j (0..$dr[1]-1) { my $s = 0; foreach my $k (0..$dl[1]-1) {$s += $l[$i]->[$k] * $r[$k]->[$j]} push(@row,$s); |
From: Mike G. v. a. <act...@de...> - 2005-01-01 22:50:44
|
Log Message: ----------- Changes made to simplify the implementation of XMLRPC access to the functionality of WeBWorK. There is still a problem with making sure that the proper warning mechanism is passed into the problem rendering compartment. The proper permissions for creating directories also does not get transmitted properly. I would like to change the way that the defineEnvirVars subroutine is passed into the Local.pm object. I'd like to either pass the environment as a hash or explicitly pass a reference to define EnvirVars rather than inherit it from PG. In particular I'd like to be able to define environment variables directly in RenderProblem.pm instead of faking it by defining fake problem objects. Modified Files: -------------- webwork-modperl/lib: WebworkWebservice.pm webwork-modperl/lib/WeBWorK/PG: Local.pm webwork-modperl/lib/WebworkWebservice: LibraryActions.pm MathTranslators.pm RenderProblem.pm Revision Data ------------- Index: WebworkWebservice.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice.pm,v retrieving revision 1.1 retrieving revision 1.2 diff -Llib/WebworkWebservice.pm -Llib/WebworkWebservice.pm -u -r1.1 -r1.2 --- lib/WebworkWebservice.pm +++ lib/WebworkWebservice.pm @@ -3,6 +3,7 @@ BEGIN { + $main::VERSION = "2.1"; my $webwork_directory = $ENV{WEBWORK_ROOT}; eval "use lib '$webwork_directory/lib'"; die $@ if $@; @@ -22,12 +23,12 @@ $WebworkWebservice::HOST_NAME = Apache->server->server_hostname; $WebworkWebservice::HOST_PORT = Apache->server->port; #$WebworkWebservice::HOST_PATH = Apache->server->path(); - $WebworkWebservice::WebworkWebservice = 'geometry'; - $WebworkWebservice::COURSENAME = 'daemon_course'; # default course + $WebworkWebservice::PASSWORD = 'geometry'; + $WebworkWebservice::COURSENAME = 'daemon2_course'; # default course } use Apache; - +use WeBWorK::PG::Local; #use lib '/home/gage/webwork/webwork-modperl/lib'; #use lib '/home/gage/webwork/pg/lib'; @@ -37,13 +38,16 @@ #$Webservice::HOST_PATH .= ":$Webservice::HOST_PORT" # unless ($Webservice::HOST_PORT == 80 ); -warn "webwork_directory = $WebworkWebservice::WW_DIRECTORY\n\t"; -warn "pg_directory = $WebworkWebservice::PG_DIRECTORY\n\t"; -warn "seedCE = $WebworkWebservice::SeedCE\n\t"; -warn "host name = $WebworkWebservice::HOST_NAME\n\t"; -#warn "host port = $Webservice::HOST_PORT\n\t"; -#warn "host path = $Webservice::HOST_PATH\n\t"; -warn " password $WebworkWebservice::WebworkWebservice\n\t"; +# warn "webwork_directory = $WebworkWebservice::WW_DIRECTORY\n\t"; +# warn "pg_directory = $WebworkWebservice::PG_DIRECTORY\n\t"; +# warn "seedCE = $WebworkWebservice::SeedCE\n\t"; +# warn "host name = $WebworkWebservice::HOST_NAME\n\t"; + +#FIXME port is not being set! +# warn "host port = $Webservice::HOST_PORT\n\t"; + +# #warn "host path = $Webservice::HOST_PATH\n\t"; +# warn " password $WebworkWebservice::PASSWORD\n\t"; use strict; ############################################################################### @@ -122,7 +126,11 @@ my $in = shift; return( WebworkWebservice::LibraryActions::readFile($in) ); } - +sub tex2pdf { + my $self = shift; + my $in = shift; + return( WebworkWebservice::MathTranslators::tex2pdf($in) ); +} # -- SOAP::Lite -- guide.soaplite.com -- Copyright (C) 2001 Paul Kulchenko -- # test responses @@ -147,7 +155,7 @@ } sub echo { - return join("|",("begin ", @_, " end") ); + return join("|",("begin ", WebworkWebservice::pretty_print_rh(\@_), " end") ); } sub pretty_print_rh { @@ -177,7 +185,7 @@ ############utilities sub echo { - return "WWd package ".join("|",("begin ", @_, " end") ); + return "WWd package ".join("|",("begin ", WebworkWebservice::pretty_print_rh(\@_), " end") ); } sub listLib { Index: Local.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/PG/Local.pm,v retrieving revision 1.15 retrieving revision 1.16 diff -Llib/WeBWorK/PG/Local.pm -Llib/WeBWorK/PG/Local.pm -u -r1.15 -r1.16 --- lib/WeBWorK/PG/Local.pm +++ lib/WeBWorK/PG/Local.pm @@ -180,17 +180,39 @@ # store the problem source #warn "PG: storing the problem source\n"; - my $sourceFile = $problem->source_file; - $sourceFile = $ce->{courseDirs}->{templates}."/".$sourceFile - unless ($sourceFile =~ /^\//); - eval { $translator->source_string(readFile($sourceFile)) }; - if ($@) { + my $source =''; + my $sourceFilePath = ''; + my $readErrors = undef; + if (ref($translationOptions->{r_source}) ) { + # the source for the problem is already given to us as a reference to a string + $source = ${$translationOptions->{r_source}}; + } else { + # the source isn't given to us so we need to read it + # from a file defined by the problem + + # we grab the sourceFilePath from the problem + $sourceFilePath = $problem->source_file; + + # the path to the source file is usually given relative to the + # the templates directory. Unless the path starts with / assume + # that it is relative to the templates directory + + $sourceFilePath = $ce->{courseDirs}->{templates}."/" + .$sourceFilePath unless ($sourceFilePath =~ /^\//); + #now grab the source + eval {$source = readFile($sourceFilePath) }; + $readErrors = $@ if $@; + } + # put the source into the translator object + eval { $translator->source_string( $source ) } unless $readErrors; + $readErrors .="\n $@ " if $@; + if ($readErrors) { # well, we couldn't get the problem source, for some reason. return bless { translator => $translator, head_text => "", body_text => <<EOF, -WeBWorK::Utils::readFile($sourceFile) says: +WeBWorK::Utils::readFile($sourceFilePath) says: $@ EOF answers => {}, Index: MathTranslators.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice/MathTranslators.pm,v retrieving revision 1.1 retrieving revision 1.2 diff -Llib/WebworkWebservice/MathTranslators.pm -Llib/WebworkWebservice/MathTranslators.pm -u -r1.1 -r1.2 --- lib/WebworkWebservice/MathTranslators.pm +++ lib/WebworkWebservice/MathTranslators.pm @@ -9,7 +9,7 @@ #use lib '/home/gage/webwork/pg/lib'; #use lib '/home/gage/webwork/webwork-modperl/lib'; -package WebworkWebserice::MathTranslators; +package WebworkWebservice::MathTranslators; use WebworkWebservice; use base qw(WebworkWebservice); @@ -30,8 +30,9 @@ our $COURSENAME = $WebworkWebservice::COURSENAME; our $HOST_NAME = $WebworkWebservice::HOST_NAME; -our $ce = $WebworkWebservice::SeedCE; - +our $ce =$WebworkWebservice::SeedCE; +# create a local course environment for some course + $ce = WeBWorK::CourseEnvironment->new($WW_DIRECTORY, "", "", $COURSENAME); Index: RenderProblem.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice/RenderProblem.pm,v retrieving revision 1.2 retrieving revision 1.3 diff -Llib/WebworkWebservice/RenderProblem.pm -Llib/WebworkWebservice/RenderProblem.pm -u -r1.2 -r1.3 --- lib/WebworkWebservice/RenderProblem.pm +++ lib/WebworkWebservice/RenderProblem.pm @@ -2,16 +2,7 @@ # Copyright (C) 2001 Michael Gage -############################################################################### -# The initial code simply initializes variables, defines addresses -# for directories, defines some simple subroutines responders used in debugging -# and makes sure that the appropriate CPAN library modules -# are available. The main code begins below that with the initialization -# of the PGtranslator5 module. -############################################################################### -# use lib '/home/gage/webwork/pg/lib'; -# use lib '/home/gage/webwork/webwork-modperl/lib'; package WebworkWebservice::RenderProblem; use WebworkWebservice; @@ -31,15 +22,20 @@ use Apache; use WeBWorK::CourseEnvironment; use WeBWorK::PG::Translator; +use WeBWorK::PG::Local; use WeBWorK::DB; +use WeBWorK::DB::Record; +use WeBWorK::DB::Record::UserProblem; use WeBWorK::Constants; -use WeBWorK::Utils; +use WeBWorK::Utils qw(runtime_use formatDateTime makeTempDirectory); +use WeBWorK::DB::Utils qw(global2user user2global findDefaults); +use WeBWorK::Utils::Tasks qw(fake_set fake_problem); use WeBWorK::PG::IO; use WeBWorK::PG::ImageGenerator; use Benchmark; use MIME::Base64 qw( encode_base64 decode_base64); -print "rereading Webwork\n"; +#print "rereading Webwork\n"; our $WW_DIRECTORY = $WebworkWebservice::WW_DIRECTORY; @@ -48,13 +44,14 @@ our $HOST_NAME = $WebworkWebservice::HOST_NAME; our $HOSTURL ="http://$HOST_NAME:11002"; #FIXME our $ce =$WebworkWebservice::SeedCE; - +# create a local course environment for some course + $ce = WeBWorK::CourseEnvironment->new($WW_DIRECTORY, "", "", $COURSENAME); #print "\$ce = \n", WeBWorK::Utils::pretty_print_rh($ce); -print "webwork is realy ready\n\n"; +print "webwork is really ready\n\n"; #other services # File variables -my $WARNINGS=''; +#our $WARNINGS=''; # imported constants @@ -96,297 +93,294 @@ -############################################################################### -# Initialize renderProblem -############################################################################### +sub renderProblem { -my $displayMode = 'HTML_dpng'; - -my $PG_PL = "${pgMacrosDirectory}/PG.pl"; -my $DANGEROUS_MACROS_PL = "${pgMacrosDirectory}/dangerousMacros.pl"; -my $IO_PL = "${pgMacrosDirectory}/IO.pl"; -my @MODULE_LIST = ( "Exporter", "DynaLoader", "GD", "WWPlot", "Fun", - "Circle", "Label", "PGrandom", "Units", "Hermite", - "List", "Match","Multiple", "Select", "AlgParser", - "AnswerHash", "Fraction", "VectorField", "Complex1", - "Complex", "MatrixReal1", "Matrix","Distributions", - "Regression" - ); -my @EXTRA_PACKAGES = ( "AlgParserWithImplicitExpand", "Expr", - "ExprWithImplicitExpand", "AnswerEvaluator", -# "AnswerEvaluatorMaker" - ); -my $INITIAL_MACRO_PACKAGES = <<END_OF_TEXT; - DOCUMENT(); - loadMacros( - "PGbasicmacros.pl", - "PGchoicemacros.pl", - "PGanswermacros.pl", - "PGnumericalmacros.pl", - "PGgraphmacros.pl", - "PGauxiliaryFunctions.pl", - "PGmatrixmacros.pl", - "PGstatisticsmacros.pl", - "PGcomplexmacros.pl", - ); - - ENDDOCUMENT(); - -END_OF_TEXT - -############################################################################### -# -############################################################################### + my $rh = shift; -############################################################################### -############################################################################### +########################################### +# Grab the course name, if this request is going to depend on +# some course other than the default course +########################################### + my $courseName; + my $ce; + my $db; + my $user; + my $beginTime = new Benchmark; + if (defined($rh->{course}) and $rh->{course}=~/\S/ ) { + $courseName = $rh->{course}; + } else { + $courseName = $COURSENAME; + # use the default $ce + } + #FIXME put in check to make sure the course exists. + eval { + $ce = WeBWorK::CourseEnvironment->new($WW_DIRECTORY, "", "", $courseName); + # Create database object for this course + $db = WeBWorK::DB->new($ce->{dbLayout}); + }; + $ce->{pg}->{options}->{catchWarnings}; + #^FIXME need better way of determining whether the course actually exists. + if ($@) { + $ce = WeBWorK::CourseEnvironment->new($WW_DIRECTORY, "", "", $COURSENAME); + $db = WeBWorK::DB->new($ce->{dbLayout}); + } + my $user = $rh->{user}; + $user = 'gage' unless defined $user and $user =~/\S/; + +########################################### +# Authenticate this request +########################################### -#print STDERR "ok so far reading file /u/gage/xmlrpc/daemon/Webwork.pm\n"; - -############################################################################### -# The following code initializes an instantiation of the translator in the -# parent process. This initialized object is then shared with each of the -# children forked from this parent process by the daemon. -# -# As far as I can tell, the child processes don't share any variable values even -# though their namespaces are the same. -############################################################################### +########################################### +# Determine the authorization level (permissions) +########################################### -my $dummy_envir = { courseScriptsDirectory => $pgMacrosDirectory, - displayMode => $displayMode, - macroDirectory => $macroDirectory, - displayModeFailover => DISPLAY_MODE_FAILOVER(), - externalTTHPath => $ce->{externalPrograms}->{tth}, -}; -my $pt = new WeBWorK::PG::Translator; #pt stands for problem translator; -$pt ->rh_directories( { courseScriptsDirectory => $pgMacrosDirectory, - macroDirectory => $macroDirectory, - scriptDirectory => '' , - templateDirectory => $templateDirectory, - tempDirectory => $COURSE_TEMP_DIRECTORY, - } -); -$pt -> evaluate_modules( @MODULE_LIST); -#print STDERR "Completed loading of modules, now loading extra packages\n"; -$pt -> load_extra_packages( @EXTRA_PACKAGES ); -#print STDERR "Completed loading of packages, now loading environment\n"; -$pt -> environment($dummy_envir); -#print STDERR "Completed loading environment, next initialize\n"; -$pt->initialize(); -#print STDERR "Initialized. \n"; -$pt -> unrestricted_load($PG_PL ); -$pt -> unrestricted_load($DANGEROUS_MACROS_PL); -$pt -> unrestricted_load($IO_PL); -$pt-> set_mask(); -# -#print STDERR "Unrestricted loads completed.\n"; - -$INITIAL_MACRO_PACKAGES =~ tr /\r/\n/; -$pt->source_string( $INITIAL_MACRO_PACKAGES ); -#print STDERR "source strings read in\n"; -$pt ->rf_safety_filter( \&safetyFilter); # install blank safety filter -$pt ->translate(); - -print STDERR "New PGtranslator object inititialization completed.\n"; -################################################################################ -## This ends the initialization of the PGtranslator object -################################################################################ +########################################### +# Determine the method for accessing data +########################################### + my $problem_source_access = $rh->{problem_source_access}; + # One of + # source_from_course_set_problem + # source_from_source_file_path + # source_from_request + + my $data_access = $rh->{data_access}; + # One of + # data_from_course + # data_from_request + +########################################### +# Determine an effective user for this interaction +# or create one if it is not given +# In order: use effectiveUserName, studentLogin, or user or 'foobar' +########################################### + my $effectiveUserName; + if (defined($rh->{effectiveUser}) and $rh->{effectiveUser}=~/\S/ ) { + $effectiveUserName = $rh->{effectiveUser}; + } elsif (defined($rh->{envir}->{studentLogin}) and $rh->{envir}->{studentLogin}=~/\S/ ) { + $effectiveUserName = $rh->{envir}->{studentLogin}; + } elsif (defined($user) and $user =~ /\S/ ) { + $effectiveUserName = $user; + } else { + $effectiveUserName = 'foobar'; + } + ################################################## + my $effectiveUser = $db->getUser($effectiveUserName); # checked + my $effectiveUserPermissionLevel; + my $effectiveUserPassword; + unless (defined $effectiveUser ) { + $effectiveUser = $db->newUser; + $effectiveUserPermissionLevel = $db->newPermissionLevel; + $effectiveUserPassword = $db->newPassword; + $effectiveUser->user_id($effectiveUserName); + $effectiveUserPermissionLevel->user_id($effectiveUserName); + $effectiveUserPassword->user_id($effectiveUserName); + $effectiveUserPassword->password(''); + $effectiveUser->last_name($rh->{envir}->{studentName}|| 'foobar'); + $effectiveUser->first_name(''); + $effectiveUser->student_id($rh->{envir}->{studentID}|| 'foobar'); + $effectiveUser->email_address($rh->{envir}->{email}|| ''); + $effectiveUser->section($rh->{envir}->{section} ||''); + $effectiveUser->recitation($rh->{envir}->{recitation} ||''); + $effectiveUser->comment(''); + $effectiveUser->status('C'); + $effectiveUser->password($rh->{envir}->{studentID}|| 'foobar'); + $effectiveUserPermissionLevel->permission(0); + } + #FIXME these will fail if the keys are not defined within the environment. +########################################### +# Insure that set and problem are defined +# Define the set and problem information from +# data in the environment if necessary +########################################### + # determine the set name and the set problem number + my $setName = (defined($rh->{envir}->{setNumber}) ) ? $rh->{envir}->{setNumber} : ''; + my $problemNumber = (defined($rh->{envir}->{probNum}) ) ? $rh->{envir}->{probNum} : 1 ; + my $problemSeed = (defined($rh->{envir}->{problemSeed})) ? $rh->{envir}->{problemSeed} : 1 ; + my $psvn = (defined($rh->{envir}->{psvn}) ) ? $rh->{envir}->{psvn} : 1234 ; + my $problemStatus = $rh->{problem_state}->{recorded_score}|| 0 ; + my $problemValue = (defined($rh->{envir}->{problemValue})) ? $rh->{envir}->{problemValue} : 1 ; + my $num_correct = $rh->{problem_state}->{num_correct} || 0 ; + my $num_incorrect = $rh->{problem_state}->{num_incorrect} || 0 ; + my $problemAttempted = ($num_correct && $num_incorrect); + my $lastAnswer = ''; + + my $setRecord = $db->getMergedSet($effectiveUserName, $setName); + unless (defined($setRecord) and ref($setRecord) ) { + # if a User Set does not exist for this user and this set + # then we check the Global Set + # if that does not exist we create a fake set + # if it does, we add fake user data + my $userSetClass = $db->{set_user}->{record}; + my $globalSet = $db->getGlobalSet($setName); # checked + + if (not defined $globalSet) { + $setRecord = fake_set($db); + } else { + $setRecord = global2user($userSetClass, $globalSet); + } + # initializations + $setRecord->set_id($setName); + $setRecord->set_header(""); + $setRecord->hardcopy_header(""); + $setRecord->open_date(time()-60*60*24*7); # one week ago + $setRecord->due_date(time()+60*60*24*7*2); # in two weeks + $setRecord->answer_date(time()+60*60*24*7*3); # in three weeks + $setRecord->psvn($rh->{envir}->{psvn}||0); + } + #warn "set Record is $setRecord"; + # obtain the merged problem for $effectiveUser + my $problemRecord = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); + + # if that is not yet defined obtain the global problem, + # convert it to a user problem, and add fake user data + unless (defined $problemRecord) { + my $userProblemClass = $db->{problem_user}->{record}; + my $globalProblem = $db->getGlobalProblem($setName, $problemNumber); # checked + # if the global problem doesn't exist either, bail! + if(not defined $globalProblem) { + $problemRecord = fake_problem($db); + } else { + $problemRecord = global2user($userProblemClass, $globalProblem); + } + # initializations + $problemRecord->user_id($effectiveUserName); + $problemRecord->problem_id($problemNumber); + $problemRecord->set_id($setName); + $problemRecord->problem_seed($problemSeed); + $problemRecord->status($problemStatus); + $problemRecord->value($problemValue); + $problemRecord->attempted($problemAttempted); + $problemRecord->last_answer($lastAnswer); + $problemRecord->num_correct($num_correct); + $problemRecord->num_incorrect($num_incorrect); + } + # initialize problem source + my $problem_source; + my $r_problem_source =undef; + if (defined($rh->{source})) { + $problem_source = decode_base64($rh->{source}); + $problem_source =~ tr /\r/\n/; + $r_problem_source =\$problem_source; + } elsif (defined($rh->{sourceFilePath}) and $rh->{sourceFilePath} =/\S/) { + $problemRecord->source_file($rh->{sourceFilePath}); + } + $problemRecord->source_file('foobar') unless defined($problemRecord->source_file); + + #warn "problem Record is $problemRecord"; + # now we're sure we have valid UserSet and UserProblem objects + # yay! + +################################################## +# Other initializations +################################################## + my $translationOptions = { + displayMode => $rh->{envir}->{displayMode}, + showHints => $rh->{envir}->{showHints}, + showSolutions => $rh->{envir}->{showSolutions}, + refreshMath2img => $rh->{envir}->{showHints} || $rh->{envir}->{showSolutions}, + processAnswers => 1, + # methods for supplying the source, + r_source => $r_problem_source, # reference to a source file string. + # if reference is not defined then the path is obtained + # from the problem object. + r_envirOverrides => $rh, + }; + + my $formFields = $rh->{envir}->{inputs_ref}; + my $key = $rh->{envir}->{key} || ''; + + + #check definitions + #warn "setRecord is ", WebworkWebservice::pretty_print_rh($setRecord); + #warn "problemRecord is",WebworkWebservice::pretty_print_rh($problemRecord); +# warn "envir is\n ",WebworkWebservice::pretty_print_rh(__PACKAGE__->defineProblemEnvir( +# $ce, +# $effectiveUser, +# $key, +# $setRecord, +# $problemRecord, +# $psvn, +# $formFields, +# $translationOptions, +# )); +################################################# + +# Other options can be over ridden by modifying +# $ce->{pg} -############################################################################### -# This subroutine is called by the child process. It reinitializes its copy of the -# PGtranslator5 object. The unrestricted_load and loadMacros subroutines of PGtranslator5 -# have been modified so that if &_PG_init is already defined then nothing -# is read in but the initialization subroutine is run instead. -############################################################################### -sub renderProblem { - my $rh = shift; -# warn WebworkWebservice::pretty_print_rh($rh); - warn "Starting render Problem"; - my $beginTime = new Benchmark; - $WARNINGS = ""; - my $saveWARN = $SIG{__WARN__}; - local $SIG{__WARN__} =\&PG_warnings_handler; - - my $envir = $rh->{envir}; - foreach my $item (keys %PG_environment) { - $envir->{$item} = $PG_environment{$item}; - } - my $basename = 'equation-'.$envir->{psvn}. '.' .$envir->{probNum}; - $basename .= '.' . $envir->{problemSeed} if $envir->{problemSeed}; - - #FIXME debug line - #print STDERR "basename is $basename and psvn is ", $envir->{psvn}; - my $imagesModeOptions = $ce->{pg}->{displayModeOptions}->{images}; - - # Object for generating equation images - if ( $envir->{displayMode} eq 'HTML_dpng' ) { - $envir->{imagegen} = WeBWorK::PG::ImageGenerator->new( - tempDir => $ce->{webworkDirs}->{tmp}, # $Global::globalTmpDirectory, # global temp dir - latex => $ce->{externalPrograms}->{latex}, #$envir->{externalLaTeXPath}, - dvipng => $ce->{externalPrograms}->{dvipng}, # $envir ->{externalDvipngPath}, - useCache => 1, - cacheDir => $ce->{webworkDirs}->{equationCache}, - cacheURL => $HOSTURL.$ce->{webworkURLs}->{equationCache}, - cacheDB => $ce->{webworkFiles}->{equationCacheDB}, - useMarkers => ($imagesModeOptions->{dvipng_align} && $imagesModeOptions->{dvipng_align} eq 'mysql'), - dvipng_align => $imagesModeOptions->{dvipng_align}, - dvipng_depth_db => $imagesModeOptions->{dvipng_depth_db}, - ); - } - - $pt->environment($envir); - #$pt->{safe_cache} = $safe_cmpt_cache; - $pt->initialize(); - $pt -> unrestricted_load($PG_PL); - $pt -> unrestricted_load($DANGEROUS_MACROS_PL); - $pt -> unrestricted_load($IO_PL); - $pt-> set_mask(); - - my $string = decode_base64( $rh ->{source} ); - $string =~ tr /\r/\n/; - - $pt->source_string( $string ); - $pt ->rf_safety_filter( \&safetyFilter); # install blank safety filter - $pt ->translate(); - - # HTML_dpng, on the other hand, uses an ImageGenerator. We have to - # render the queued equations. - if ($envir->{imagegen}) { - my $sourceFile = ''; #$ce->{courseDirs}->{templates} . "/" . $problem->source_file; - my %mtimeOption = -e $sourceFile - ? (mtime => (stat $sourceFile)[9]) - : (); + +# We'll try to use this code instead so that Local does all of the work. +# Most of the configuration will take place in the fake course associated +# with XMLRPC responses +# problem needs to be loaded with the following: +# source_file +# status +# num_correct +# num_incorrect +# it doesn't seem that $effectiveUser, $set or $key is used in the subroutine +# except that it is passed on to defineProblemEnvironment + + my $pg; + $pg = WebworkWebservice::RenderProblem->new( + $ce, + $effectiveUser, + $key, + $setRecord, + $problemRecord, + $setRecord->psvn, # FIXME: this field should be removed + $formFields, + # translation options + $translationOptions, - $envir->{imagegen}->render( - refresh => 1, - %mtimeOption, - ); - } + ); + - # Determine which problem grader to use - #$pt->rf_problem_grader($pt->rf_std_problem_grader); #this is the default - my $problem_grader_to_use = $pt->rh_flags->{PROBLEM_GRADER_TO_USE}; - - if ( defined($problem_grader_to_use) and $problem_grader_to_use ) { # if defined and non-empty - if ($problem_grader_to_use eq 'std_problem_grader') { - # Reset problem grader to standard problem grader. - $pt->rf_problem_grader($pt->rf_std_problem_grader); - } elsif ($problem_grader_to_use eq 'avg_problem_grader') { - # Reset problem grader to average problem grader. - $pt->rf_problem_grader($pt->rf_avg_problem_grader); - } elsif (ref($problem_grader_to_use) eq 'CODE') { - # Set problem grader to instructor defined problem grader -- use cautiously. - $pt->rf_problem_grader($problem_grader_to_use) - } else { - warn "Error: Could not understand problem grader flag $problem_grader_to_use"; - #this is the default set by the translator and used if the flag is not understood - #$pt->rf_problem_grader($pt->rf_std_problem_grader); - } - - } else {#this is the default set by the translator and used if no flag is set. - $pt->rf_problem_grader($pt->rf_std_problem_grader); - } - - # creates and stores a hash of answer results: $rh_answer_results - $pt -> process_answers($rh->{envir}->{inputs_ref}); - - - $pt->rh_problem_state({ recorded_score => $rh->{problem_state}->{recorded_score}, - num_of_correct_ans => $rh->{problem_state}->{num_of_correct_ans} , - num_of_incorrect_ans => $rh->{problem_state}->{num_of_incorrect_ans} - } ); - my %PG_FLAGS = $pt->h_flags; - my $ra_answer_entry_order = ( defined($PG_FLAGS{ANSWER_ENTRY_ORDER}) ) ? - $PG_FLAGS{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ; - my $answers_submitted = 0; - $answers_submitted = 1 if defined( $rh->{answer_form_submitted} ) and 1 == $rh->{answer_form_submitted}; - - my ($rh_problem_result,$rh_problem_state) = $pt->grade_problem( answers_submitted => $answers_submitted, - ANSWER_ENTRY_ORDER => $ra_answer_entry_order - ); # grades the problem. - # protect image data for delivery via XML-RPC. - # Don't send code data. - my %PG_flag=(); - -# if($rh->{envir}->{displayMode} eq 'HTML_dpng') { -# my $forceRefresh=1; -# if ( (defined($inputs{'refreshCachedImages'}) and $inputs{'refreshCachedImages'}) || $main::refreshCachedImages -# || $displaySolutionsQ || $displayHintsQ) { -# $forceRefresh=1; -# } -# $imgen->render('refresh'=>$forceRefresh); # Can force new images -# } - my $out = { - text => encode_base64( ${$pt ->r_text()} ), - header_text => encode_base64( ${ $pt->r_header } ), - answers => $pt->rh_evaluated_answers, - errors => $pt-> errors(), - WARNINGS => encode_base64($WARNINGS ), - problem_result => $rh_problem_result, - problem_state => $rh_problem_state, - PG_flag => \%PG_flag - }; - local $SIG{__WARN__} = $saveWARN; - my $endTime = new Benchmark; - $out->{compute_time} = logTimingInfo($beginTime, $endTime); + # new version of output: + my $out2 = { + text => encode_base64( $pg->{body_text} ), + header_text => encode_base64( $pg->{head_text} ), + answers => $pg->{answers}, + errors => $pg->{errors}, + WARNINGS => encode_base64($pg->{warnings} ), + problem_result => $pg->{result}, + problem_state => $pg->{state}, + #PG_flag => $pg->{flags}, + + + }; # Hack to filter out CODE references - foreach my $ans (keys %{$out->{answers}}) { - foreach my $item (keys %{$out->{answers}->{$ans}}) { - my $contents = $out->{answers}->{$ans}->{$item}; + foreach my $ans (keys %{$out2->{answers}}) { + foreach my $item (keys %{$out2->{answers}->{$ans}}) { + my $contents = $out2->{answers}->{$ans}->{$item}; if (ref($contents) =~ /CODE/ ) { #warn "removing code at $ans $item "; - $out->{answers}->{$ans}->{$item} = undef; + $out2->{answers}->{$ans}->{$item} = undef; } } } - #warn WebworkWebservice::pretty_print_rh($pt->rh_evaluated_answers); - $out; + $out2->{PG_flag}->{PROBLEM_GRADER_TO_USE} = undef; + my $endTime = new Benchmark; + $out2->{compute_time} = logTimingInfo($beginTime, $endTime); + # warn "flags are" , WebworkWebservice::pretty_print_rh($pg->{flags}); + $out2; } -############################################################################### -# This ends the main subroutine executed by the child process in responding to -# a request. The other subroutines are auxiliary. -############################################################################### - - -sub safetyFilter { - my $answer = shift; # accepts one answer and checks it - my $submittedAnswer = $answer; - $answer = '' unless defined $answer; - my ($errorno, $answerIsCorrectQ); - $answer =~ tr/\000-\037/ /; - #### Return if answer field is empty ######## - unless ($answer =~ /\S/) { -# $errorno = "<BR>No answer was submitted."; - $errorno = 0; ## don't report blank answer as error - - return ($answer,$errorno); - } - - ######### Return if forbidden characters are found - unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\[\]\(\)\,\|]+$/ ) { - $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; - $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; - - return ($answer,$errorno); - } - - $errorno = 0; - return($answer, $errorno); -} + + sub logTimingInfo{ @@ -395,264 +389,194 @@ $out .= Benchmark::timestr( Benchmark::timediff($endTime , $beginTime) ); $out; } -###################################################################### -sub PG_warnings_handler { - my @input = @_; - my $msg_string = longmess(@_); - my @msg_array = split("\n",$msg_string); - my $out_string = ''; - - # Extra stack information is provided in this next block - # If the warning message does NOT end in \n then a line - # number is appended (see Perl manual about warn function) - # The presence of the line number is detected below and extra - # stack information is added. - # To suppress the line number and the extra stack information - # add \n to the end of a warn message (in .pl files. In .pg - # files add ~~n instead - - - if (@msg_array) { # if there are more details - $out_string .= "##More details. The calling sequence is: <BR>\n"; - foreach my $line (@msg_array) { - chomp($line); - next unless $line =~/\w+\:\:/; - $out_string .= "----" .$line . "<BR>\n"; - } - } - - $WARNINGS .="* " . join("<BR>",@input) . "<BR>\n" . $out_string . - "<BR>\n--------------------------------------<BR>\n<BR>\n"; -} - -my $CarpLevel = 0; # How many extra package levels to skip on carp. -my $MaxEvalLen = 0; # How much eval '...text...' to show. 0 = all. -sub longmess { - my $error = shift; - my $mess = ""; - my $i = 1 + $CarpLevel; - my ($pack,$file,$line,$sub,$eval,$require); - - while (($pack,$file,$line,$sub,undef,undef,$eval,$require) = caller($i++)) { - if ($error =~ m/\n$/) { - $mess .= $error; - } - else { - if (defined $eval) { - if ($require) { - $sub = "require $eval"; - } - else { - $eval =~ s/[\\\']/\\$&/g; - if ($MaxEvalLen && length($eval) > $MaxEvalLen) { - substr($eval,$MaxEvalLen) = '...'; - } - $sub = "eval '$eval'"; - } - } - elsif ($sub eq '(eval)') { - $sub = 'eval {...}'; - } - - $mess .= "\t$sub " if $error eq "called"; - $mess .= "$error at $file line $line\n"; - } - $error = "called"; - } - - $mess || $error; -} ###################################################################### - - -sub pretty_print_rh { - my $rh = shift; - my $out = ""; - my $type = ref($rh); - if ( ref($rh) =~/HASH/ ) { - foreach my $key (sort keys %{$rh}) { - $out .= " $key => " . pretty_print_rh( $rh->{$key} ) . "\n"; - } - } elsif ( ref($rh) =~ /SCALAR/ ) { - $out = "scalar reference ". ${$rh}; - } elsif ( ref($rh) =~/Base64/ ) { - $out .= "base64 reference " .$$rh; - } else { - $out = $rh; - } - if (defined($type) ) { - $out .= "type = $type \n"; - } - return $out; +sub new { + shift; # throw away invocant -- we don't need it + my ($ce, $user, $key, $set, $problem, $psvn, $formFields, + $translationOptions) = @_; + + my $renderer = 'WeBWorK::PG::Local'; + + runtime_use $renderer; + # the idea is to have Local call back to the defineProblemEnvir below. + return WeBWorK::PG::Local::new($renderer,@_); } -###################################################################### - -sub defineProblemEnvir { - my ( - $self, - $ce, - $user, - $key, - $set, - $problem, - $psvn, - $formFields, - $options, - ) = @_; - - my %envir; - - # ---------------------------------------------------------------------- - - # PG environment variables - # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 - # any changes are noted by "ADDED:" or "REMOVED:" - - # Vital state information - # ADDED: displayModeFailover, displayHintsQ, displaySolutionsQ, - # refreshMath2img, texDisposition - - $envir{psvn} = $set->psvn; - $envir{psvnNumber} = $envir{psvn}; - $envir{probNum} = $problem->problem_id; - $envir{questionNumber} = $envir{probNum}; - $envir{fileName} = $problem->source_file; - $envir{probFileName} = $envir{fileName}; - $envir{problemSeed} = $problem->problem_seed; - $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); - $envir{languageMode} = $envir{displayMode}; - $envir{outputMode} = $envir{displayMode}; - $envir{displayHintsQ} = $options->{showHints}; - $envir{displaySolutionsQ} = $options->{showSolutions}; - $envir{texDisposition} = "pdf"; # in webwork2, we use pdflatex - - # Problem Information - # ADDED: courseName, formatedDueDate - - $envir{openDate} = $set->open_date; - $envir{formattedOpenDate} = formatDateTime($envir{openDate}, $ce->{siteDefaults}{timezone}); - $envir{dueDate} = $set->due_date; - $envir{formattedDueDate} = formatDateTime($envir{dueDate}, $ce->{siteDefaults}{timezone}); - $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files - $envir{answerDate} = $set->answer_date; - $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}, $ce->{siteDefaults}{timezone}); - $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0); - $envir{problemValue} = $problem->value; - $envir{sessionKey} = $key; - $envir{courseName} = $ce->{courseName}; - - # Student Information - # ADDED: studentID - - $envir{sectionName} = $user->section; - $envir{sectionNumber} = $envir{sectionName}; - $envir{recitationName} = $user->recitation; - $envir{recitationNumber} = $envir{recitationName}; - $envir{setNumber} = $set->set_id; - $envir{studentLogin} = $user->user_id; - $envir{studentName} = $user->first_name . " " . $user->last_name; - $envir{studentID} = $user->student_id; - - # Answer Information - # REMOVED: refSubmittedAnswers - - $envir{inputs_ref} = $formFields; - - # External Programs - # ADDED: externalLaTeXPath, externalDvipngPath, - # externalGif2EpsPath, externalPng2EpsPath - - $envir{externalTTHPath} = $ce->{externalPrograms}->{tth}; - $envir{externalLaTeXPath} = $ce->{externalPrograms}->{latex}; - $envir{externalDvipngPath} = $ce->{externalPrograms}->{dvipng}; - $envir{externalGif2EpsPath} = $ce->{externalPrograms}->{gif2eps}; - $envir{externalPng2EpsPath} = $ce->{externalPrograms}->{png2eps}; - $envir{externalGif2PngPath} = $ce->{externalPrograms}->{gif2png}; - - # Directories and URLs - # REMOVED: courseName - # ADDED: dvipngTempDir - # ADDED: jsMathURL - # ADDED: asciimathURL - - $envir{cgiDirectory} = undef; - $envir{cgiURL} = undef; - $envir{classDirectory} = undef; - $envir{courseScriptsDirectory} = $ce->{pg}->{directories}->{macros}."/"; - $envir{htmlDirectory} = $ce->{courseDirs}->{html}."/"; - $envir{htmlURL} = $ce->{courseURLs}->{html}."/"; - $envir{macroDirectory} = $ce->{courseDirs}->{macros}."/"; - $envir{templateDirectory} = $ce->{courseDirs}->{templates}."/"; - $envir{tempDirectory} = $ce->{courseDirs}->{html_temp}."/"; - $envir{tempURL} = $ce->{courseURLs}->{html_temp}."/"; - $envir{scriptDirectory} = undef; - $envir{webworkDocsURL} = $ce->{webworkURLs}->{docs}."/"; - $envir{localHelpURL} = $ce->{webworkURLs}->{local_help}."/"; - $envir{jsMathURL} = $ce->{webworkURLs}->{jsMath}; - $envir{asciimathURL} = $ce->{webworkURLs}->{asciimath}; - - # Information for sending mail - - $envir{mailSmtpServer} = $ce->{mail}->{smtpServer}; - $envir{mailSmtpSender} = $ce->{mail}->{smtpSender}; - $envir{ALLOW_MAIL_TO} = $ce->{mail}->{allowedRecipients}; - - # Default values for evaluating answers - - my $ansEvalDefaults = $ce->{pg}->{ansEvalDefaults}; - $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); - - # ---------------------------------------------------------------------- - - my $basename = "equation-$envir{psvn}.$envir{probNum}"; - $basename .= ".$envir{problemSeed}" if $envir{problemSeed}; - - # to make grabbing these options easier, we'll pull them out now... - my %imagesModeOptions = %{$ce->{pg}->{displayModeOptions}->{images}}; - - # Object for generating equation images - $envir{imagegen} = WeBWorK::PG::ImageGenerator->new( - tempDir => $ce->{webworkDirs}->{tmp}, # global temp dir - latex => $envir{externalLaTeXPath}, - dvipng => $envir{externalDvipngPath}, - useCache => 1, - cacheDir => $ce->{webworkDirs}->{equationCache}, - cacheURL => $ce->{webworkURLs}->{equationCache}, - cacheDB => $ce->{webworkFiles}->{equationCacheDB}, - useMarkers => ($imagesModeOptions{dvipng_align} && $imagesModeOptions{dvipng_align} eq 'mysql'), - dvipng_align => $imagesModeOptions{dvipng_align}, - dvipng_depth_db => $imagesModeOptions{dvipng_depth_db}, - ); - - # ADDED: jsMath options - $envir{jsMath} = {%{$ce->{pg}{displayModeOptions}{jsMath}}}; - - # Other things... - $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes - $envir{PROBLEM_GRADER_TO_USE} = $ce->{pg}->{options}->{grader}; - $envir{PRINT_FILE_NAMES_FOR} = $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR}; - - # ADDED: __files__ - # an array for mapping (eval nnn) to filenames in error messages - $envir{__files__} = { - root => $ce->{webworkDirs}{root}, # used to shorten filenames - pg => $ce->{pg}{directories}{root}, # ditto - tmpl => $ce->{courseDirs}{templates}, # ditto - }; - - # variables for interpreting capa problems and other things to be - # seen in a pg file - my $specialPGEnvironmentVarHash = $ce->{pg}->{specialPGEnvironmentVars}; - for my $SPGEV (keys %{$specialPGEnvironmentVarHash}) { - $envir{$SPGEV} = $specialPGEnvironmentVarHash->{$SPGEV}; - } - - return \%envir; -} +#FIXME +# Save these subroutines. +# I'd like to use this version of defineProblemEnvir instead of the +# the version in PG.pm That adds flexibility. + + +# sub translateDisplayModeNames($) { +# my $name = shift; +# return DISPLAY_MODES()->{$name}; +# } +# sub defineProblemEnvir { +# my ( +# $self, +# $ce, +# $user, +# $key, +# $set, +# $problem, +# $psvn, +# $formFields, +# $options, +# ) = @_; +# +# my %envir; +# +# # ---------------------------------------------------------------------- +# +# # PG environment variables +# # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 +# # any changes are noted by "ADDED:" or "REMOVED:" +# +# # Vital state information +# # ADDED: displayModeFailover, displayHintsQ, displaySolutionsQ, +# # refreshMath2img, texDisposition +# +# $envir{psvn} = $set->psvn; +# $envir{psvnNumber} = $envir{psvn}; +# $envir{probNum} = $problem->problem_id; +# $envir{questionNumber} = $envir{probNum}; +# $envir{fileName} = $problem->source_file; +# $envir{probFileName} = $envir{fileName}; +# $envir{problemSeed} = $problem->problem_seed; +# $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); +# $envir{languageMode} = $envir{displayMode}; +# $envir{outputMode} = $envir{displayMode}; +# $envir{displayHintsQ} = $options->{showHints}; +# $envir{displaySolutionsQ} = $options->{showSolutions}; +# $envir{texDisposition} = "pdf"; # in webwork2, we use pdflatex +# +# # Problem Information +# # ADDED: courseName, formatedDueDate +# +# $envir{openDate} = $set->open_date; +# $envir{formattedOpenDate} = formatDateTime($envir{openDate}, $ce->{siteDefaults}{timezone}); +# $envir{dueDate} = $set->due_date; +# $envir{formattedDueDate} = formatDateTime($envir{dueDate}, $ce->{siteDefaults}{timezone}); +# $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files +# $envir{answerDate} = $set->answer_date; +# $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}, $ce->{siteDefaults}{timezone}); +# $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0); +# $envir{problemValue} = $problem->value; +# $envir{sessionKey} = $key; +# $envir{courseName} = $ce->{courseName}; +# +# # Student Information +# # ADDED: studentID +# +# $envir{sectionName} = $user->section; +# $envir{sectionNumber} = $envir{sectionName}; +# $envir{recitationName} = $user->recitation; +# $envir{recitationNumber} = $envir{recitationName}; +# $envir{setNumber} = $set->set_id; +# $envir{studentLogin} = $user->user_id; +# $envir{studentName} = $user->first_name . " " . $user->last_name; +# $envir{studentID} = $user->student_id; +# +# # Answer Information +# # REMOVED: refSubmittedAnswers +# +# $envir{inputs_ref} = $formFields; +# +# # External Programs +# # ADDED: externalLaTeXPath, externalDvipngPath, +# # externalGif2EpsPath, externalPng2EpsPath +# +# $envir{externalTTHPath} = $ce->{externalPrograms}->{tth}; +# $envir{externalLaTeXPath} = $ce->{externalPrograms}->{latex}; +# $envir{externalDvipngPath} = $ce->{externalPrograms}->{dvipng}; +# $envir{externalGif2EpsPath} = $ce->{externalPrograms}->{gif2eps}; +# $envir{externalPng2EpsPath} = $ce->{externalPrograms}->{png2eps}; +# $envir{externalGif2PngPath} = $ce->{externalPrograms}->{gif2png}; +# +# # Directories and URLs +# # REMOVED: courseName +# # ADDED: dvipngTempDir +# # ADDED: jsMathURL +# # ADDED: asciimathURL +# +# $envir{cgiDirectory} = undef; +# $envir{cgiURL} = undef; +# $envir{classDirectory} = undef; +# $envir{courseScriptsDirectory} = $ce->{pg}->{directories}->{macros}."/"; +# $envir{htmlDirectory} = $ce->{courseDirs}->{html}."/"; +# $envir{htmlURL} = $ce->{courseURLs}->{html}."/"; +# $envir{macroDirectory} = $ce->{courseDirs}->{macros}."/"; +# $envir{templateDirectory} = $ce->{courseDirs}->{templates}."/"; +# $envir{tempDirectory} = $ce->{courseDirs}->{html_temp}."/"; +# $envir{tempURL} = $ce->{courseURLs}->{html_temp}."/"; +# $envir{scriptDirectory} = undef; +# $envir{webworkDocsURL} = $ce->{webworkURLs}->{docs}."/"; +# $envir{localHelpURL} = $ce->{webworkURLs}->{local_help}."/"; +# $envir{jsMathURL} = $ce->{webworkURLs}->{jsMath}; +# $envir{asciimathURL} = $ce->{webworkURLs}->{asciimath}; +# +# # Information for sending mail +# +# $envir{mailSmtpServer} = $ce->{mail}->{smtpServer}; +# $envir{mailSmtpSender} = $ce->{mail}->{smtpSender}; +# $envir{ALLOW_MAIL_TO} = $ce->{mail}->{allowedRecipients}; +# +# # Default values for evaluating answers +# +# my $ansEvalDefaults = $ce->{pg}->{ansEvalDefaults}; +# $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); +# +# # ---------------------------------------------------------------------- +# +# my $basename = "equation-$envir{psvn}.$envir{probNum}"; +# $basename .= ".$envir{problemSeed}" if $envir{problemSeed}; +# +# # to make grabbing these options easier, we'll pull them out now... +# my %imagesModeOptions = %{$ce->{pg}->{displayModeOptions}->{images}}; +# +# # Object for generating equation images +# $envir{imagegen} = WeBWorK::PG::ImageGenerator->new( +# tempDir => $ce->{webworkDirs}->{tmp}, # global temp dir +# latex => $envir{externalLaTeXPath}, +# dvipng => $envir{externalDvipngPath}, +# useCache => 1, +# cacheDir => $ce->{webworkDirs}->{equationCache}, +# cacheURL => $ce->{webworkURLs}->{equationCache}, +# cacheDB => $ce->{webworkFiles}->{equationCacheDB}, +# useMarkers => ($imagesModeOptions{dvipng_align} && $imagesModeOptions{dvipng_align} eq 'mysql'), +# dvipng_align => $imagesModeOptions{dvipng_align}, +# dvipng_depth_db => $imagesModeOptions{dvipng_depth_db}, +# ); +# +# # ADDED: jsMath options +# $envir{jsMath} = {%{$ce->{pg}{displayModeOptions}{jsMath}}}; +# +# # Other things... +# $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes +# $envir{PROBLEM_GRADER_TO_USE} = $ce->{pg}->{options}->{grader}; +# $envir{PRINT_FILE_NAMES_FOR} = $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR}; +# +# # ADDED: __files__ +# # an array for mapping (eval nnn) to filenames in error messages +# $envir{__files__} = { +# root => $ce->{webworkDirs}{root}, # used to shorten filenames +# pg => $ce->{pg}{directories}{root}, # ditto +# tmpl => $ce->{courseDirs}{templates}, # ditto +# }; +# +# # variables for interpreting capa problems and other things to be +# # seen in a pg file +# my $specialPGEnvironmentVarHash = $ce->{pg}->{specialPGEnvironmentVars}; +# for my $SPGEV (keys %{$specialPGEnvironmentVarHash}) { +# $envir{$SPGEV} = $specialPGEnvironmentVarHash->{$SPGEV}; +# } +# +# return \%envir; +# } Index: LibraryActions.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice/LibraryActions.pm,v retrieving revision 1.1 retrieving revision 1.2 diff -Llib/WebworkWebservice/LibraryActions.pm -Llib/WebworkWebservice/LibraryActions.pm -u -r1.1 -r1.2 --- lib/WebworkWebservice/LibraryActions.pm +++ lib/WebworkWebservice/LibraryActions.pm @@ -36,14 +36,14 @@ our $PASSWORD = $WebworkWebservice::PASSWORD; our $ce = WeBWorK::CourseEnvironment->new($WW_DIRECTORY, "", "", $COURSENAME); #warn "library ce \n ", WebworkWebservice::pretty_print_rh($ce); -warn "LibraryActions is ready"; +#warn "LibraryActions is ready"; ############################################## # Obtain basic information about local libraries ############################################## my %prob_libs = %{$ce->{courseFiles}->{problibs} }; - warn pretty_print_rh(\%prob_libs); + #warn pretty_print_rh(\%prob_libs); # replace library names with full paths my $templateDir = $ce->{courseDirs}->{templates}; @@ -110,7 +110,7 @@ $out->{error} = "Could not find library:".$rh->{library_name}.":"; return($out); } - warn "library directory path is $dirPath"; + #warn "library directory path is $dirPath"; my @outListLib; my $wanted = sub { my $name = $File::Find::name; @@ -125,7 +125,7 @@ my $command = $rh->{command}; $command = 'all' unless defined($command); - $command eq 'all' && do {print "$dirPath\n\n"; + $command eq 'all' && do {#print "$dirPath\n\n"; find($wanted, $dirPath); @outListLib = sort @outListLib; $out->{ra_out} = \@outListLib; @@ -148,13 +148,14 @@ }; $command eq 'listSet' && do {@outListLib=(); - my $dirPath2 = $dirPath . $rh->{set}; + my $separator = ($dirPath =~m|/$|) ?'' : '/'; + my $dirPath2 = $dirPath . $separator . $rh->{set}; if ( -e $dirPath2) { find($wanted, $dirPath2); $out ->{text} = join("\n", sort @outListLib ); } else { - $out->{error} = "Can't open directory $dirPath2"; + $out->{error} = "Can't open directory $dirPath2"; } return($out); |
From: Mike G. v. a. <act...@de...> - 2005-01-01 22:45:04
|
Log Message: ----------- Temporary modifications which allow the Warning mechanisms to work when using the XML access methods. This needs to be looked at again. There is also a problem with defining permissions for creating directories. There is a temporary #FIXME that seems to work. Modified Files: -------------- pg/lib/WeBWorK/PG: IO.pm Translator.pm Revision Data ------------- Index: Translator.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WeBWorK/PG/Translator.pm,v retrieving revision 1.9 retrieving revision 1.10 diff -Llib/WeBWorK/PG/Translator.pm -Llib/WeBWorK/PG/Translator.pm -u -r1.9 -r1.10 --- lib/WeBWorK/PG/Translator.pm +++ lib/WeBWorK/PG/Translator.pm @@ -653,50 +653,7 @@ $self->{errors}; } -# sub DESTROY { -# my $self = shift; -# my $nameSpace = $self->nameSpace; -# no strict 'refs'; -# my $nm = "${nameSpace}::"; -# my $nsp = \%{"$nm"}; -# my @list = keys %$nsp; -# while (@list) { -# my $name = pop(@list); -# if ( defined(&{$nsp->{$name}}) ) { -# #print "checking \&$name\n"; -# unless (exists( $shared_subroutine_hash{"\&$name"} ) ) { -# undef( &{$nsp->{$name}} ); -# #print "destroying \&$name\n"; -# } else { -# #delete( $nsp->{$name} ); -# #print "what is left",join(" ",%$nsp) ,"\n\n"; -# } -# -# } -# if ( defined(${$nsp->{$name}}) ) { -# #undef( ${$nsp->{$name}} ); ## unless commented out download hardcopy bombs with Perl 5.6 -# #print "destroying \$$name\n"; -# } -# if ( defined(@{$nsp->{$name}}) ) { -# undef( @{$nsp->{$name}} ); -# #print "destroying \@$name\n"; -# } -# if ( defined(%{$nsp->{$name}}) ) { -# undef( %{$nsp->{$name}} ) unless $name =~ /::/ ; -# #print "destroying \%$name\n"; -# } -# # changed for Perl 5.6 -# delete ( $nsp->{$name} ) if defined($nsp->{$name}); # this must be uncommented in Perl 5.6 to reinitialize variables -# # changed for Perl 5.6 -# #print "deleting $name\n"; -# #undef( @{$nsp->{$name}} ) if defined(@{$nsp->{$name}}); -# #undef( %{$nsp->{$name}} ) if defined(%{$nsp->{$name}}) and $name ne "main::"; -# } -# -# use strict; -# #print "\nObject going bye-bye\n"; -# -# } + =head2 set_mask @@ -837,7 +794,8 @@ unless defined( $self->{envir} ); # reset the error detection my $save_SIG_warn_trap = $SIG{__WARN__}; - $SIG{__WARN__} = sub {&$save_SIG_warn_trap(PG_errorMessage('message',@_))}; +# $SIG{__WARN__} = sub {&$save_SIG_warn_trap(PG_errorMessage('message',@_))}; + $SIG{__WARN__} = sub {CORE::die(PG_errorMessage('message',@_))}; my $save_SIG_die_trap = $SIG{__DIE__}; $SIG{__DIE__} = sub {CORE::die(PG_errorMessage('traceback',@_))}; @@ -1123,10 +1081,6 @@ # in case the answer evaluator forgets to check $self->{safe}->share('$rf_fun','$temp_ans'); - # reset the error detection - my $save_SIG_warn_trap = $SIG{__WARN__}; - $SIG{__WARN__} = sub {&$save_SIG_warn_trap(PG_errorMessage('message',@_))}; - my $save_SIG_die_trap = $SIG{__DIE__}; local %errorTable; $SIG{__DIE__} = sub { # @@ -1142,7 +1096,13 @@ $error .= "\n"; $errorTable{$error} = $fullerror; CORE::die($error); - }; + }; + # reset the error detection + my $save_SIG_warn_trap = $SIG{__WARN__}; + $SIG{__WARN__} = sub {&$save_SIG_warn_trap(PG_errorMessage('message',@_))}; + + my $save_SIG_die_trap = $SIG{__DIE__}; + my $rh_ans_evaluation_result; if (ref($rf_fun) eq 'CODE' ) { $rh_ans_evaluation_result = $self->{safe} ->reval( '&{ $rf_fun }($temp_ans)' ) ; Index: IO.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WeBWorK/PG/IO.pm,v retrieving revision 1.2 retrieving revision 1.3 diff -Llib/WeBWorK/PG/IO.pm -Llib/WeBWorK/PG/IO.pm -u -r1.2 -r1.3 --- lib/WeBWorK/PG/IO.pm +++ lib/WeBWorK/PG/IO.pm @@ -193,6 +193,9 @@ sub createDirectory { my ($dirName, $permission, $numgid) = @_; + $permission = (defined($permission)) ? $permission : '0770'; + # FIXME -- find out where the permission is supposed to be defined. + #warn "dirName is $dirName and permission is $permission"; mkdir($dirName, $permission) or warn "Can't do mkdir($dirName, $permission): $!"; chmod($permission, $dirName) |
From: Mike G. v. a. <act...@de...> - 2004-12-28 05:14:52
|
Log Message: ----------- Modifications that allow the XMLRPC modules to function. Modified Files: -------------- webwork-modperl/conf: devel.apache-config.dist webwork.apache-config.dist Revision Data ------------- Index: devel.apache-config.dist =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/conf/devel.apache-config.dist,v retrieving revision 1.4 retrieving revision 1.5 diff -Lconf/devel.apache-config.dist -Lconf/devel.apache-config.dist -u -r1.4 -r1.5 --- conf/devel.apache-config.dist +++ conf/devel.apache-config.dist @@ -26,8 +26,8 @@ # central location. # # The second part is the stock webwork.apache-config file that is used for -# normal installations. Customize this file, setting $webwork_dir appropriatly -# for your development server. +# normal installations. Customize this file, setting the $webwork_url, +# $webwork_dir, $pg_dir, etc. appropriatly for your development server. # # The third part is this file. It contains the user-specific directives that are # specific to each developer's server. Index: webwork.apache-config.dist =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/conf/webwork.apache-config.dist,v retrieving revision 1.4 retrieving revision 1.5 diff -Lconf/webwork.apache-config.dist -Lconf/webwork.apache-config.dist -u -r1.4 -r1.5 --- conf/webwork.apache-config.dist +++ conf/webwork.apache-config.dist @@ -26,7 +26,10 @@ <Perl> # Set this variable to the path to your WeBWorK installation. -my $webwork_dir = "/opt/webwork2"; +my $webwork_dir = "/home/gage/webwork/webwork-modperl"; + +$ENV{WEBWORK_ROOT} = $webwork_dir; #allows the XMLRPC modules to find + # the webwork root directory # This code reads global.conf and extracts the remaining configuration # variables. There is no need to modify it. @@ -40,6 +43,10 @@ my $webwork_courses_url = $ce->{webwork_courses_url}; my $webwork_courses_dir = $ce->{webwork_courses_dir}; eval "use lib '$pg_dir/lib'"; die $@ if $@; + +eval "use WebworkWebservice";die $@ if $@; #FIXME, is there another way to initialize this? +# allows Webservice access to WeBWorK + $WeBWorK::SeedCE{webwork_dir} = $webwork_dir; # Between the line below and the "EOF" line are the three configuration stanzas @@ -85,6 +92,15 @@ AllowOverride None </Directory> + ########## XMLRPC installation ########## +<Location /mod_xmlrpc> + SetHandler perl-script + PerlHandler Apache::XMLRPC::Lite + PerlSetVar dispatch_to "WebworkXMLRPC" + PerlSetVar options "compress_threshold => 10000" + Order Allow,Deny + Allow from All +</Location> EOF </Perl> |
From: Mike G. v. a. <act...@de...> - 2004-12-28 05:11:39
|
Log Message: ----------- Added modifications that support the creation of blank problems to be added to sets. blankProblem.pg is stationery for a new=20 problem. Modified Files: -------------- webwork-modperl/conf: global.conf.dist Added Files: ----------- webwork-modperl/conf/snippets: blankProblem.pg Revision Data ------------- Index: global.conf.dist =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /webwork/cvs/system/webwork-modperl/conf/global.conf.dist,v retrieving revision 1.114 retrieving revision 1.115 diff -Lconf/global.conf.dist -Lconf/global.conf.dist -u -r1.114 -r1.115 --- conf/global.conf.dist +++ conf/global.conf.dist @@ -252,6 +252,9 @@ # The set header is displayed on the problem set page. It is a PG file. $webworkFiles{screenSnippets}{setHeader} =3D "$webworkDirs{conf}/= snippets/setHeader.pg"; # screenSetHeader.pg" =20 +$webworkFiles{screenSnippets}{blankProblem} =3D "$webworkDirs{conf}/s= nippets/blankProblem.pg"; # screenSetHeader.pg" + + ########################################################################= ######## # Course-specific files ########################################################################= ######## --- /dev/null +++ conf/snippets/blankProblem.pg @@ -0,0 +1,41 @@ +########################################################################= ######## +# WeBWorK Online Homework Delivery System +# Copyright =A9 2000-2003 The WeBWorK Project, http://openwebwork.sf.net= / +# $CVSHeader: webwork-modperl/conf/snippets/blankProblem.pg,v 1.1 2004/1= 2/28 04:56:27 gage Exp $ +#=20 +# This program is free software; you can redistribute it and/or modify i= t under +# the terms of either: (a) the GNU General Public License as published b= y the +# Free Software Foundation; either version 2, or (at your option) any la= ter +# version, or (b) the "Artistic License" which comes with this package. +#=20 +# This program is distributed in the hope that it will be useful, but WI= THOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or = FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License o= r the +# Artistic License for more details. +########################################################################= ######## + +DOCUMENT(); + +# Load whatever macros you need for the problem +loadMacros("PG.pl", + "PGbasicmacros.pl", + "PGchoicemacros.pl", + "PGanswermacros.pl", + "PGauxiliaryFunctions.pl", + "PGgraphmacros.pl", + ); +=20 +## Do NOT show partial correct answers +$showPartialCorrectAnswers =3D 0; +TEXT(beginproblem()); + +BEGIN_TEXT + +Enter a value for \(\pi\) + +\{ans_rule()\} +END_TEXT + +ANS(num_cmp(3.14159)); + +ENDDOCUMENT(); |
From: Mike G. v. a. <act...@de...> - 2004-12-27 21:56:02
|
Log Message: ----------- Minimal code for a client which will connect to the xmlrpc access within webwork 2 Use at your own risk :-) Added Files: ----------- webwork-modperl/clients: README input.txt xmlrpc_client4.pl Revision Data ------------- --- /dev/null +++ clients/input.txt @@ -0,0 +1,99 @@ +##DESCRIPTION +## A very simple first problem +##ENDDESCRIPTION +##KEYWORDS('algebra') +DOCUMENT(); # This should be the first executable line in the problem. +loadMacros( +"PG.pl", +"PGbasicmacros.pl", +"PGchoicemacros.pl", +"PGanswermacros.pl", +"PGauxiliaryFunctions.pl" +); + +TEXT(&beginproblem); +$showPartialCorrectAnswers = 1; +$a = random(-10,-1,1); +$b = random(1,11,1); +$c = random(1,11,1); +$d = random(1,11,1); + +BEGIN_TEXT +$PAR +displayMode is $displayMode $BR +$PAR +This problem demonstrates how you enter numerical answers into WeBWorK. $PAR +Evaluate the expression \(3($a )($b -$c -2($d ))\): + + \{ ans_rule(10) \} + +$BR +END_TEXT +$ans = 3*($a)*($b-$c-2*($d)); + +&ANS(strict_num_cmp($ans)); + +BEGIN_TEXT + +In the case above you need to enter a number, since we're testing whether you can multiply +out these numbers. (You can use a calculator if you want.) +$PAR +For most problems, you will be able to get WeBWorK to +do some of the work for you. For example +$BR +Calculate ($a) * ($b): \{ ans_rule()\} +$BR +END_TEXT +$ans = $a*$b; + +&ANS(std_num_cmp($ans)); + +BEGIN_TEXT +The asterisk is what most computers use to denote multiplication and you can use this with WeBWorK. +But WeBWorK will also allow use to use a space to denote multiplication. +You can either \($a * $b\) or \{$a*$b\} or even \($a \ $b\). All will work. Try them. +$PAR +Now try calculating the sine of 45 degrees ( that's sine of pi over 4 in radians +and numerically sin(pi/4) equals \{1/sqrt(2)\} or, more precisely, \(1/\sqrt{2} \) ). +You can enter this as sin(pi/4) , as +sin(3.1415926/4), as 1/sqrt(2), as 2**(-.5), etc. This is because WeBWorK knows about +functions like sin and sqrt (square root). (Note: exponents +can be indicated by either a "caret" or **). Try it.$BR \( \sin(\pi/4) = \) \{ ans_rule(20) \}$PAR + Here's the +\{ +htmlLink(qq!http://webwork.math.rochester.edu/webwork_system_html/docs/docs/pglanguage/availablefunctions.html!,"list +of the functions") \} + which WeBWorK understands. WeBWorK ALWAYS uses radian mode for trig functions. + $PAR +END_TEXT + +&ANS( std_num_cmp(sin(3.1415926/4)) ); +BEGIN_TEXT +You can also use juxtaposition to denote multiplication. E.g. enter \( 2\sin(3\pi/2) \). +You can enter this as 2*sin(3*pi/2) or more simply as 2sin(3pi/2). Try it: $BR +\{ ans_rule(20) \}$PAR + +END_TEXT + +$pi = 4*atan(1); +&ANS( std_num_cmp(2*sin(3*$pi/2)) ); + +BEGIN_TEXT +Sometimes you need to use ( )'s to make your meaning clear. E.g. 1/2+3 is 3.5, but 1/(2+3) is .2 Why? +Try entering both and use the ${LQ}Preview${RQ} button below to see the difference. In addition to +( )'s, you can also use [ ]'s and $LB ${RB}'s. $BR +\{ ans_rule(20) \}$PAR +END_TEXT + +&ANS( std_num_cmp(.2)); + +BEGIN_TEXT +You can always try to enter answers and let WeBWorK do the calculating. +WeBWorK will tell you if the problem requires a strict numerical answer. +The way we use WeBWorK in this class there is no penalty for getting an answer wrong. What counts +is that you get the answer right eventually (before the due date). For complicated answers, +you should use the ${LQ}Preview${RQ} button to check for syntax errors and also to check that the answer +you enter is really what you think it is. +END_TEXT + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ clients/xmlrpc_client4.pl @@ -0,0 +1,259 @@ +#!/usr/bin/perl -w +use MIME::Base64 qw( encode_base64 decode_base64); + + +# -- SOAP::Lite -- soaplite.com -- Copyright (C) 2001 Paul Kulchenko -- + +# use XMLRPC::Lite; +# +# print XMLRPC::Lite +# -> proxy('http://devel.webwork.rochester.edu:11002/mod_xmlrpc') +# -> call('Demo:bye', 25) +# -> result; +print STDERR "inputs are ", join (" | ", @ARGV), "\n"; +our $source; + +if (@ARGV) { + my $command = $ARGV[0]; + + warn "executing WebworkXMLRPC.$command"; + $source = `cat $ARGV[1]`; + xmlrpcCall($command); + + +} else { + + print STDERR "Useage: .xmlrpc_client4.pl command file_name"; + +} + + + + + + +sub xmlrpcCall { + my $command = shift; + $command = 'listLibraries' unless $command; + use XMLRPC::Lite; + my $xmlrpc = XMLRPC::Lite + # ->uri('http://webwork-db.math.rochester.edu/Demo/') + -> proxy('http://devel.webwork.rochester.edu:11002/mod_xmlrpc'); + + my $test = [3,4,5,6]; + my $input = setInputTable(); + local( $result); + eval { $result = $xmlrpc->call("WebworkXMLRPC.$command",$input) }; + print STDERR "There were a lot of errors" if $@; + print "Errors: \n $@\n End Errors\n" if $@; + + + + unless (ref($result) and $result->fault) { + if (defined($result->result()->{text}) ) { + $result->result()->{text} = decode_base64($result->result()->{text}); + } + print pretty_print_rh($result->result()),"\n"; #$result->result() + } else { + print 'oops ', join ', ', + $result->faultcode, + $result->faultstring; + } +} + +sub source { + encode_base64($source); +} +sub pretty_print_rh { + shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + my $rh = shift; + my $indent = shift || 0; + my $out = ""; + my $type = ref($rh); + + if (defined($type) and $type) { + $out .= " type = $type; "; + } elsif (! defined($rh )) { + $out .= " type = UNDEFINED; "; + } + if ( ref($rh) =~/HASH/ or "$rh" =~/HASH/ ) { + $out .= "{\n"; + $indent++; + foreach my $key (sort keys %{$rh}) { + $out .= " "x$indent."$key => " . pretty_print_rh( $rh->{$key}, $indent ) . "\n"; + } + $indent--; + $out .= "\n"." "x$indent."}\n"; + + } elsif (ref($rh) =~ /ARRAY/ or "$rh" =~/ARRAY/) { + $out .= " ( "; + foreach my $elem ( @{$rh} ) { + $out .= pretty_print_rh($elem, $indent); + + } + $out .= " ) \n"; + } elsif ( ref($rh) =~ /SCALAR/ ) { + $out .= "scalar reference ". ${$rh}; + } elsif ( ref($rh) =~/Base64/ ) { + $out .= "base64 reference " .$$rh; + } else { + $out .= $rh; + } + + return $out." "; +} + +sub setInputTable_for_listLib { + $out = { + #password => 'geometry', + pw => 'geometry', + set => 'set0', + library_name => 'rochesterLibrary', + command => 'all', + }; + + $out; +} +sub setInputTable { + $out = { + #password => 'geometry', + pw => 'geometry', + set => 'set0', + library_name => 'rochesterLibrary', + command => 'all', + answer_form_submitted => 1, + course => 'daemon_course', + extra_packages_to_load => [qw( AlgParserWithImplicitExpand Expr + ExprWithImplicitExpand AnswerEvaluator + AnswerEvaluatorMaker + )], + mode => undef, + modules_to_evaluate => [ qw( +Exporter + +DynaLoader + + +GD +WWPlot +Fun +Circle +Label + + +PGrandom +Units +Hermite + +List + + +Match +Multiple +Select + + +AlgParser + +AnswerHash + + +Fraction +VectorField + + +Complex1 +Complex + + +MatrixReal1 Matrix + + +Distributions + +Regression + + )], + envir => environment(), + problem_state => { + + num_of_correct_ans => 2, + num_of_incorrect_ans => 4, + recorded_score => 1.0, + }, + source => source(), #base64 encoded + + + + }; + + $out; +} + +sub environment { + my $envir = { + answerDate => '4014438528', + CAPA_Graphics_URL=>'http://webwork-db.math.rochester.edu/capa_graphics/', + CAPA_GraphicsDirectory =>'/ww/webwork/CAPA/CAPA_Graphics/', + CAPA_MCTools=>'/ww/webwork/CAPA/CAPA_MCTools/', + CAPA_Tools=>'/ww/webwork/CAPA/CAPA_Tools/', + cgiDirectory=>'Not defined', + cgiURL => 'Not defined', + classDirectory=> 'Not defined', + courseName=>'Not defined', + courseScriptsDirectory=>'/ww/webwork/system/courseScripts/', + displayMode=>'HTML_dpng', + dueDate=> '4014438528', + externalGif2EpsPath=>'not defined', + externalPng2EpsPath=>'not defined', + externalTTHPath=>'/usr/local/bin/tth', + fileName=>'set0/prob1a.pg', + formattedAnswerDate=>'6/19/00', + formattedDueDate=>'6/19/00', + formattedOpenDate=>'6/19/00', + functAbsTolDefault=> 0.0000001, + functLLimitDefault=>0, + functMaxConstantOfIntegration=> 1000000000000.0, + functNumOfPoints=> 5, + functRelPercentTolDefault=> 0.000001, + functULimitDefault=>1, + functVarDefault=> 'x', + functZeroLevelDefault=> 0.000001, + functZeroLevelTolDefault=>0.000001, + htmlDirectory =>'/ww/webwork/courses/gage_course/html/', + htmlURL =>'http://webwork-db.math.rochester.edu/gage_course/', + inputs_ref => { + AnSwEr1 => '', + AnSwEr2 => '', + AnSwEr3 => '', + }, + macroDirectory=>'/ww/webwork/courses/gage_course/templates/macros/', + numAbsTolDefault=>0.0000001, + numFormatDefault=>'%0.13g', + numOfAttempts=> 0, + numRelPercentTolDefault => 0.0001, + numZeroLevelDefault =>0.000001, + numZeroLevelTolDefault =>0.000001, + openDate=> '3014438528', + PRINT_FILE_NAMES_FOR => [ 'gage'], + probFileName => 'set0/prob1a.pg', + problemSeed => 1234, + problemValue =>1, + probNum => 13, + psvn => 54321, + psvnNumber=> 54321, + questionNumber => 1, + scriptDirectory => 'Not defined', + sectionName => 'Gage', + sectionNumber => 1, + sessionKey=> 'Not defined', + setNumber =>'MAAtutorial', + studentLogin =>'gage', + studentName => 'Mike Gage', + tempDirectory => '/ww/htdocs/tmp/gage_course/', + templateDirectory=>'/ww/webwork/courses/gage_course/templates/', + tempURL=>'http://webwork-db.math.rochester.edu/tmp/gage_course/', + webworkDocsURL => 'http://webwork.math.rochester.edu/webwork_gage_system_html', + }; + $envir; +}; --- /dev/null +++ clients/README @@ -0,0 +1,7 @@ +Minimal commands to make this client work: + +./xmlrpc_client4.pl renderProblem input.txt >foo.txt + +You may need to adjust some hardwired parameters in xmlrpc_client4. :-) + +The |
From: Mike G. v. a. <act...@de...> - 2004-12-27 21:53:38
|
Update of /webwork/cvs/system/webwork-modperl/clients In directory devel.webwork.rochester.edu:/home/gage/webwork/webwork-modperl/clients Log Message: Directory /webwork/cvs/system/webwork-modperl/clients added to the repository |
From: Mike G. v. a. <act...@de...> - 2004-12-27 18:25:54
|
Log Message: ----------- Fixed problem that was preventing HTML_dpng from working. Several initialization problems are currently hacked. I'd like to be able to get the initial request object from SOAP::Lite; I also don't know how to get the port that the server is using: $Apache->server->server_hostname works but $Apache->server->port doesn't Still no support for jsMath mode Modified Files: -------------- webwork-modperl/lib/WebworkWebservice: RenderProblem.pm Revision Data ------------- Index: RenderProblem.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice/RenderProblem.pm,v retrieving revision 1.1 retrieving revision 1.2 diff -Llib/WebworkWebservice/RenderProblem.pm -Llib/WebworkWebservice/RenderProblem.pm -u -r1.1 -r1.2 --- lib/WebworkWebservice/RenderProblem.pm +++ lib/WebworkWebservice/RenderProblem.pm @@ -46,7 +46,7 @@ our $PG_DIRECTORY = $WebworkWebservice::PG_DIRECTORY; our $COURSENAME = $WebworkWebservice::COURSENAME; our $HOST_NAME = $WebworkWebservice::HOST_NAME; -our $HOSTURL ="$HOST_NAME:11002"; #FIXME +our $HOSTURL ="http://$HOST_NAME:11002"; #FIXME our $ce =$WebworkWebservice::SeedCE; #print "\$ce = \n", WeBWorK::Utils::pretty_print_rh($ce); @@ -261,7 +261,7 @@ # HTML_dpng, on the other hand, uses an ImageGenerator. We have to # render the queued equations. if ($envir->{imagegen}) { - my $sourceFile = 'foobar'; #$ce->{courseDirs}->{templates} . "/" . $problem->source_file; + my $sourceFile = ''; #$ce->{courseDirs}->{templates} . "/" . $problem->source_file; my %mtimeOption = -e $sourceFile ? (mtime => (stat $sourceFile)[9]) : (); @@ -317,14 +317,14 @@ # Don't send code data. my %PG_flag=(); - if($rh->{envir}->{displayMode} eq 'HTML_dpng') { - my $forceRefresh=1; -# if($inputs{'refreshCachedImages'} || $main::refreshCachedImages -# || $displaySolutionsQ || $displayHintsQ) { -# $forceRefresh=1; -# } -# $imgen->render('refresh'=>$forceRefresh); # Can force new images - } +# if($rh->{envir}->{displayMode} eq 'HTML_dpng') { +# my $forceRefresh=1; +# if ( (defined($inputs{'refreshCachedImages'}) and $inputs{'refreshCachedImages'}) || $main::refreshCachedImages +# || $displaySolutionsQ || $displayHintsQ) { +# $forceRefresh=1; +# } +# $imgen->render('refresh'=>$forceRefresh); # Can force new images +# } my $out = { text => encode_base64( ${$pt ->r_text()} ), |
From: Mike G. v. a. <act...@de...> - 2004-12-27 17:35:14
|
Log Message: ----------- Catch multiply defined user warning. Modified Files: -------------- webwork-modperl/lib/WeBWorK: Constants.pm ContentGenerator.pm Revision Data ------------- Index: Constants.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/Constants.pm,v retrieving revision 1.22 retrieving revision 1.23 diff -Llib/WeBWorK/Constants.pm -Llib/WeBWorK/Constants.pm -u -r1.22 -r1.23 --- lib/WeBWorK/Constants.pm +++ lib/WeBWorK/Constants.pm @@ -54,7 +54,7 @@ # If non-empty, timing data will be sent to the file named rather than STDERR. # -$WeBWorK::Timing::Logfile = ""; +$WeBWorK::Timing::Logfile = "/home/gage/webwork2/logs/timing.log"; ################################################################################ # WeBWorK::ContentGenerator::Hardcopy Index: ContentGenerator.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator.pm,v retrieving revision 1.127 retrieving revision 1.128 diff -Llib/WeBWorK/ContentGenerator.pm -Llib/WeBWorK/ContentGenerator.pm -u -r1.127 -r1.128 --- lib/WeBWorK/ContentGenerator.pm +++ lib/WeBWorK/ContentGenerator.pm @@ -1498,7 +1498,8 @@ } elsif (defined $r->param($name)) { @values = $r->param($name); } - + #FIXME -- evntually we'd like to catch where this happens + croak "internal error -- user has been multiply defined!" if $name eq 'user' and @values >1; if (@values) { if ($first) { $url .= "?"; |
From: Mike G. v. a. <act...@de...> - 2004-12-27 17:34:00
|
Log Message: ----------- More files for supporting access to problems via XMLRPC code (see comment for WebworkWebservice.pm) Added Files: ----------- webwork-modperl/lib/WebworkWebservice: LibraryActions.pm MathTranslators.pm RenderProblem.pm Revision Data ------------- --- /dev/null +++ lib/WebworkWebservice/MathTranslators.pm @@ -0,0 +1,193 @@ +#!/usr/local/bin/perl -w + +# Copyright (C) 2002 Michael Gage + +############################################################################### +# Web service which translates TeX to pdf or to HTML +############################################################################### + +#use lib '/home/gage/webwork/pg/lib'; +#use lib '/home/gage/webwork/webwork-modperl/lib'; + +package WebworkWebserice::MathTranslators; +use WebworkWebservice; +use base qw(WebworkWebservice); + +use strict; +use sigtrap; +use Carp; +use Safe; +use Apache; +use WeBWorK::PG::Translator; +use WeBWorK::PG::IO; +use Benchmark; +use MIME::Base64 qw( encode_base64 decode_base64); + + + +our $WW_DIRECTORY = $WebworkWebservice::WW_DIRECTORY; +our $PG_DIRECTORY = $WebworkWebservice::PG_DIRECTORY; +our $COURSENAME = $WebworkWebservice::COURSENAME; +our $HOST_NAME = $WebworkWebservice::HOST_NAME; + +our $ce = $WebworkWebservice::SeedCE; + + + + +my $debugOn = 1; +my $PASSWORD = $WebworkWebservice::PASSWORD; + + +my $TEMPDIRECTORY = $ce->{webworkDirs}->{htdocs_temp}; +my $TEMP_BASE_URL = $ce->{webworkURLs}->{htdocs_temp}; +my $externalLatexPath = $ce->{externalPrograms}->{latex}; +# my $externalDvipsPath = $Global::externalDvipsPath; +my $externalpdflatexPath = $ce->{externalPrograms}->{pdflatex};; +# my $externalGsPath = $Global::externalGsPath; + + +# variables formerly set in Global + $Global::tmp_directory_permission = 0775; + $Global::numericalGroupID='100'; # group ID for wwdev + +my $tmp_directory_permission = $Global::tmp_directory_permission; +my $numericalGroupID = $Global::numericalGroupID; # group ID for webadmin + +sub tex2pdf { + + my $rh = shift; + local($|) = 1; + my $out = {}; + unless ($rh->{pw} eq $PASSWORD ) { + $out->{error} = 404; + return($out); + } + #obtain the path to the file + my $filePath = $rh->{fileName}; + my @pathElements = split("/", $filePath); + + # grab the last element as the fileName + #remove the extension from the file name + my $fileName = pop @pathElements; + $fileName =~ s/\.pg$//; + + #Create the full url and the full directory path -- If pathElements is empty this can give an extra //? Should I worry? maybe + my $url = $TEMP_BASE_URL. join("/",@pathElements); + $url .= '/' unless $url =~ m|/$|; # only add / if it is needed. + $url .= "$fileName.pdf"; + my $texFileBasePath = $TEMPDIRECTORY.join("/",@pathElements); + $texFileBasePath .= '/' unless $texFileBasePath =~ m|/$|; + $texFileBasePath .= "$fileName"; + + # create the intermediate directories if they don't exists + # create a dummy .pdf file + surePathToTmpFile2($texFileBasePath.'.pdf'); +# my $filePermission = '0775'; +# chmod("$filePermission","$texFileBasePath.pdf") +# or die "Can't change file permissions on $texFileBasePath.pdf to $filePermission"; + + # Decode and cleanup the tex string + my $texString = decode_base64( $rh->{'texString'}); + #Make sure the line endings are correct + $texString=~s/\r\n/\n/g; + $texString=~s/\r/\n/g; + + # Make sure that TeX is run in batchmode so that the tex program doesn't hang on errors + $texString = "\\batchmode\n".$texString; # force errors to log. + + # Remove any old files + unlink("$texFileBasePath.tex","$texFileBasePath.dvi","$texFileBasePath.log","$texFileBasePath.aux", + "$texFileBasePath.ps","$texFileBasePath.pdf"); + # Create the texfile of the problem. + local(*TEX); + open(TEX,"> $texFileBasePath.tex") or die "Can't open $texFileBasePath.tex to store tex code"; + local($/)=undef; + print TEX $texString; + close(TEX); + + + # my $dviCommandLine = "$externalLatexPath $texFileBasePath.tex";# >/dev/null 2>/dev/null"; + # my $psCommandLine = "$externalDvipsPath -o $texFileBasePath.ps $texFileBasePath.dvi >/dev/null";# 2>/dev/null"; + # my $pdfCommandLine = "$externalGsPath -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$texFileBasePath.pdf -c save pop -f $texFileBasePath.ps"; + # print "dviCommandLine: $dviCommandLine\n"; + # print "psCommandLine: $psCommandLine\n"; + # print "pdfCommandLine: $pdfCommandLine\n"; + #print "execute pdflatex", `$externalpdflatexPath $texFileBasePath.tex`, "\n"; + #print "done $externalpdflatexPath $texFileBasePath.tex\n"; + # Change to the working directory and create the pdf files. + my $wd = $TEMPDIRECTORY.join("/",@pathElements); # working directory + # print "---cd $wd && $externalpdflatexPath $fileName.tex\n"; + + system "cd $wd && $externalpdflatexPath $fileName.tex >>$fileName.log"; + chmod 0777, "$texFileBasePath.pdf"; + unless ($debugOn) { + unlink("$texFileBasePath.tex","$texFileBasePath.log","$texFileBasePath.aux", + ); + } + return({pdfURL => $url}); + + + + +} + +sub surePathToTmpFile2 { # constructs intermediate directories if needed beginning at ${Global::htmlDirectory}tmp/ + # the input path must be either the full path, or the path relative to this tmp sub directory + my $path = shift; + my $delim = getDirDelim(); + my $tmpDirectory = $TEMPDIRECTORY; + # if the path starts with $tmpDirectory (which is permitted but optional) remove this initial segment + print "Original path $path\n"; + $path =~ s|^$tmpDirectory|| if $path =~ m|^$tmpDirectory|; + $path = convertPath($path); + print "Creating path to $path using $delim\n"; + # find the nodes on the given path + my @nodes = split("$delim",$path); + # create new path + $path = convertPath("$tmpDirectory"); + print "Creating path: $path\n "; + while (@nodes>1 ) { + + $path = convertPath($path . shift (@nodes) ."/"); + print "Creating path: $path\n "; + unless (-e $path) { + # system("mkdir $path"); + createDirectory($path,$tmp_directory_permission, $numericalGroupID) || + die "Failed to create directory $path"; + + } + + } + $path = convertPath($path . shift(@nodes)); + print "Creating path: $path\n "; + # system(qq!echo "" > $path! ); + +$path; + +} + + +sub pretty_print_rh { + my $rh = shift; + my $out = ""; + my $type = ref($rh); + if ( ref($rh) =~/HASH/ ) { + foreach my $key (sort keys %{$rh}) { + $out .= " $key => " . pretty_print_rh( $rh->{$key} ) . "\n"; + } + } elsif ( ref($rh) =~ /SCALAR/ ) { + $out = "scalar reference ". ${$rh}; + } elsif ( ref($rh) =~/Base64/ ) { + $out .= "base64 reference " .$$rh; + } else { + $out = $rh; + } + if (defined($type) ) { + $out .= "type = $type \n"; + } + return $out; +} + + +1; --- /dev/null +++ lib/WebworkWebservice/RenderProblem.pm @@ -0,0 +1,660 @@ +#!/usr/local/bin/perl -w + +# Copyright (C) 2001 Michael Gage + +############################################################################### +# The initial code simply initializes variables, defines addresses +# for directories, defines some simple subroutines responders used in debugging +# and makes sure that the appropriate CPAN library modules +# are available. The main code begins below that with the initialization +# of the PGtranslator5 module. +############################################################################### + +# use lib '/home/gage/webwork/pg/lib'; +# use lib '/home/gage/webwork/webwork-modperl/lib'; + +package WebworkWebservice::RenderProblem; +use WebworkWebservice; +use base qw(WebworkWebservice); + + +BEGIN { + $main::VERSION = "2.1"; +} + + + +use strict; +use sigtrap; +use Carp; +use Safe; +use Apache; +use WeBWorK::CourseEnvironment; +use WeBWorK::PG::Translator; +use WeBWorK::DB; +use WeBWorK::Constants; +use WeBWorK::Utils; +use WeBWorK::PG::IO; +use WeBWorK::PG::ImageGenerator; +use Benchmark; +use MIME::Base64 qw( encode_base64 decode_base64); + +print "rereading Webwork\n"; + + +our $WW_DIRECTORY = $WebworkWebservice::WW_DIRECTORY; +our $PG_DIRECTORY = $WebworkWebservice::PG_DIRECTORY; +our $COURSENAME = $WebworkWebservice::COURSENAME; +our $HOST_NAME = $WebworkWebservice::HOST_NAME; +our $HOSTURL ="$HOST_NAME:11002"; #FIXME +our $ce =$WebworkWebservice::SeedCE; + +#print "\$ce = \n", WeBWorK::Utils::pretty_print_rh($ce); + +print "webwork is realy ready\n\n"; +#other services +# File variables +my $WARNINGS=''; + + +# imported constants + +my $COURSE_TEMP_DIRECTORY = $ce->{courseDirs}->{html_tmp}; +my $COURSE_TEMP_URL = $HOSTURL.$ce->{courseURLs}->{html_tmp}; + +my $pgMacrosDirectory = $ce->{pg_dir}.'/macros/'; +my $macroDirectory = $ce->{courseDirs}->{macros}.'/'; +my $templateDirectory = $ce->{courseDirs}->{templates}; + +my %PG_environment = $ce->{pg}->{specialPGEnvironmentVars}; + + +use constant DISPLAY_MODES => { + # display name # mode name + tex => "TeX", + plainText => "HTML", + formattedText => "HTML_tth", + images => "HTML_dpng", + jsMath => "HTML_jsMath", + asciimath => "HTML_asciimath", +}; + +use constant DISPLAY_MODE_FAILOVER => { + TeX => [], + HTML => [], + HTML_tth => [ "HTML", ], + HTML_dpng => [ "HTML_tth", "HTML", ], + HTML_jsMath => [ "HTML_dpng", "HTML_tth", "HTML", ], + HTML_asciimath => [ "HTML_dpng", "HTML_tth", "HTML", ], + # legacy modes -- these are not supported, but some problems might try to + # set the display mode to one of these values manually and some macros may + # provide rendered versions for these modes but not the one we want. + Latex2HTML => [ "TeX", "HTML", ], + HTML_img => [ "HTML_dpng", "HTML_tth", "HTML", ], +}; + + + + +############################################################################### +# Initialize renderProblem +############################################################################### + + + + +my $displayMode = 'HTML_dpng'; + +my $PG_PL = "${pgMacrosDirectory}/PG.pl"; +my $DANGEROUS_MACROS_PL = "${pgMacrosDirectory}/dangerousMacros.pl"; +my $IO_PL = "${pgMacrosDirectory}/IO.pl"; +my @MODULE_LIST = ( "Exporter", "DynaLoader", "GD", "WWPlot", "Fun", + "Circle", "Label", "PGrandom", "Units", "Hermite", + "List", "Match","Multiple", "Select", "AlgParser", + "AnswerHash", "Fraction", "VectorField", "Complex1", + "Complex", "MatrixReal1", "Matrix","Distributions", + "Regression" + ); +my @EXTRA_PACKAGES = ( "AlgParserWithImplicitExpand", "Expr", + "ExprWithImplicitExpand", "AnswerEvaluator", +# "AnswerEvaluatorMaker" + ); +my $INITIAL_MACRO_PACKAGES = <<END_OF_TEXT; + DOCUMENT(); + loadMacros( + "PGbasicmacros.pl", + "PGchoicemacros.pl", + "PGanswermacros.pl", + "PGnumericalmacros.pl", + "PGgraphmacros.pl", + "PGauxiliaryFunctions.pl", + "PGmatrixmacros.pl", + "PGstatisticsmacros.pl", + "PGcomplexmacros.pl", + ); + + ENDDOCUMENT(); + +END_OF_TEXT + +############################################################################### +# +############################################################################### + +############################################################################### +############################################################################### + +#print STDERR "ok so far reading file /u/gage/xmlrpc/daemon/Webwork.pm\n"; + + + +############################################################################### +# The following code initializes an instantiation of the translator in the +# parent process. This initialized object is then shared with each of the +# children forked from this parent process by the daemon. +# +# As far as I can tell, the child processes don't share any variable values even +# though their namespaces are the same. +############################################################################### + + +my $dummy_envir = { courseScriptsDirectory => $pgMacrosDirectory, + displayMode => $displayMode, + macroDirectory => $macroDirectory, + displayModeFailover => DISPLAY_MODE_FAILOVER(), + externalTTHPath => $ce->{externalPrograms}->{tth}, +}; +my $pt = new WeBWorK::PG::Translator; #pt stands for problem translator; +$pt ->rh_directories( { courseScriptsDirectory => $pgMacrosDirectory, + macroDirectory => $macroDirectory, + scriptDirectory => '' , + templateDirectory => $templateDirectory, + tempDirectory => $COURSE_TEMP_DIRECTORY, + } +); +$pt -> evaluate_modules( @MODULE_LIST); +#print STDERR "Completed loading of modules, now loading extra packages\n"; +$pt -> load_extra_packages( @EXTRA_PACKAGES ); +#print STDERR "Completed loading of packages, now loading environment\n"; +$pt -> environment($dummy_envir); +#print STDERR "Completed loading environment, next initialize\n"; +$pt->initialize(); +#print STDERR "Initialized. \n"; +$pt -> unrestricted_load($PG_PL ); +$pt -> unrestricted_load($DANGEROUS_MACROS_PL); +$pt -> unrestricted_load($IO_PL); +$pt-> set_mask(); +# +#print STDERR "Unrestricted loads completed.\n"; + +$INITIAL_MACRO_PACKAGES =~ tr /\r/\n/; +$pt->source_string( $INITIAL_MACRO_PACKAGES ); +#print STDERR "source strings read in\n"; +$pt ->rf_safety_filter( \&safetyFilter); # install blank safety filter +$pt ->translate(); + +print STDERR "New PGtranslator object inititialization completed.\n"; +################################################################################ +## This ends the initialization of the PGtranslator object +################################################################################ + + + +############################################################################### +# This subroutine is called by the child process. It reinitializes its copy of the +# PGtranslator5 object. The unrestricted_load and loadMacros subroutines of PGtranslator5 +# have been modified so that if &_PG_init is already defined then nothing +# is read in but the initialization subroutine is run instead. +############################################################################### + +sub renderProblem { + my $rh = shift; +# warn WebworkWebservice::pretty_print_rh($rh); + warn "Starting render Problem"; + my $beginTime = new Benchmark; + $WARNINGS = ""; + my $saveWARN = $SIG{__WARN__}; + local $SIG{__WARN__} =\&PG_warnings_handler; + + my $envir = $rh->{envir}; + foreach my $item (keys %PG_environment) { + $envir->{$item} = $PG_environment{$item}; + } + my $basename = 'equation-'.$envir->{psvn}. '.' .$envir->{probNum}; + $basename .= '.' . $envir->{problemSeed} if $envir->{problemSeed}; + + #FIXME debug line + #print STDERR "basename is $basename and psvn is ", $envir->{psvn}; + my $imagesModeOptions = $ce->{pg}->{displayModeOptions}->{images}; + + # Object for generating equation images + if ( $envir->{displayMode} eq 'HTML_dpng' ) { + $envir->{imagegen} = WeBWorK::PG::ImageGenerator->new( + tempDir => $ce->{webworkDirs}->{tmp}, # $Global::globalTmpDirectory, # global temp dir + latex => $ce->{externalPrograms}->{latex}, #$envir->{externalLaTeXPath}, + dvipng => $ce->{externalPrograms}->{dvipng}, # $envir ->{externalDvipngPath}, + useCache => 1, + cacheDir => $ce->{webworkDirs}->{equationCache}, + cacheURL => $HOSTURL.$ce->{webworkURLs}->{equationCache}, + cacheDB => $ce->{webworkFiles}->{equationCacheDB}, + useMarkers => ($imagesModeOptions->{dvipng_align} && $imagesModeOptions->{dvipng_align} eq 'mysql'), + dvipng_align => $imagesModeOptions->{dvipng_align}, + dvipng_depth_db => $imagesModeOptions->{dvipng_depth_db}, + ); + } + + $pt->environment($envir); + #$pt->{safe_cache} = $safe_cmpt_cache; + $pt->initialize(); + $pt -> unrestricted_load($PG_PL); + $pt -> unrestricted_load($DANGEROUS_MACROS_PL); + $pt -> unrestricted_load($IO_PL); + $pt-> set_mask(); + + my $string = decode_base64( $rh ->{source} ); + $string =~ tr /\r/\n/; + + $pt->source_string( $string ); + $pt ->rf_safety_filter( \&safetyFilter); # install blank safety filter + $pt ->translate(); + + # HTML_dpng, on the other hand, uses an ImageGenerator. We have to + # render the queued equations. + if ($envir->{imagegen}) { + my $sourceFile = 'foobar'; #$ce->{courseDirs}->{templates} . "/" . $problem->source_file; + my %mtimeOption = -e $sourceFile + ? (mtime => (stat $sourceFile)[9]) + : (); + + $envir->{imagegen}->render( + refresh => 1, + %mtimeOption, + ); + } + + # Determine which problem grader to use + #$pt->rf_problem_grader($pt->rf_std_problem_grader); #this is the default + my $problem_grader_to_use = $pt->rh_flags->{PROBLEM_GRADER_TO_USE}; + + if ( defined($problem_grader_to_use) and $problem_grader_to_use ) { # if defined and non-empty + if ($problem_grader_to_use eq 'std_problem_grader') { + # Reset problem grader to standard problem grader. + $pt->rf_problem_grader($pt->rf_std_problem_grader); + } elsif ($problem_grader_to_use eq 'avg_problem_grader') { + # Reset problem grader to average problem grader. + $pt->rf_problem_grader($pt->rf_avg_problem_grader); + } elsif (ref($problem_grader_to_use) eq 'CODE') { + # Set problem grader to instructor defined problem grader -- use cautiously. + $pt->rf_problem_grader($problem_grader_to_use) + } else { + warn "Error: Could not understand problem grader flag $problem_grader_to_use"; + #this is the default set by the translator and used if the flag is not understood + #$pt->rf_problem_grader($pt->rf_std_problem_grader); + } + + } else {#this is the default set by the translator and used if no flag is set. + $pt->rf_problem_grader($pt->rf_std_problem_grader); + } + + # creates and stores a hash of answer results: $rh_answer_results + $pt -> process_answers($rh->{envir}->{inputs_ref}); + + + $pt->rh_problem_state({ recorded_score => $rh->{problem_state}->{recorded_score}, + num_of_correct_ans => $rh->{problem_state}->{num_of_correct_ans} , + num_of_incorrect_ans => $rh->{problem_state}->{num_of_incorrect_ans} + } ); + my %PG_FLAGS = $pt->h_flags; + my $ra_answer_entry_order = ( defined($PG_FLAGS{ANSWER_ENTRY_ORDER}) ) ? + $PG_FLAGS{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ; + my $answers_submitted = 0; + $answers_submitted = 1 if defined( $rh->{answer_form_submitted} ) and 1 == $rh->{answer_form_submitted}; + + my ($rh_problem_result,$rh_problem_state) = $pt->grade_problem( answers_submitted => $answers_submitted, + ANSWER_ENTRY_ORDER => $ra_answer_entry_order + ); # grades the problem. + # protect image data for delivery via XML-RPC. + # Don't send code data. + my %PG_flag=(); + + if($rh->{envir}->{displayMode} eq 'HTML_dpng') { + my $forceRefresh=1; +# if($inputs{'refreshCachedImages'} || $main::refreshCachedImages +# || $displaySolutionsQ || $displayHintsQ) { +# $forceRefresh=1; +# } +# $imgen->render('refresh'=>$forceRefresh); # Can force new images + } + + my $out = { + text => encode_base64( ${$pt ->r_text()} ), + header_text => encode_base64( ${ $pt->r_header } ), + answers => $pt->rh_evaluated_answers, + errors => $pt-> errors(), + WARNINGS => encode_base64($WARNINGS ), + problem_result => $rh_problem_result, + problem_state => $rh_problem_state, + PG_flag => \%PG_flag + }; + local $SIG{__WARN__} = $saveWARN; + my $endTime = new Benchmark; + $out->{compute_time} = logTimingInfo($beginTime, $endTime); + + # Hack to filter out CODE references + foreach my $ans (keys %{$out->{answers}}) { + foreach my $item (keys %{$out->{answers}->{$ans}}) { + my $contents = $out->{answers}->{$ans}->{$item}; + if (ref($contents) =~ /CODE/ ) { + #warn "removing code at $ans $item "; + $out->{answers}->{$ans}->{$item} = undef; + } + } + + } + #warn WebworkWebservice::pretty_print_rh($pt->rh_evaluated_answers); + $out; + +} + +############################################################################### +# This ends the main subroutine executed by the child process in responding to +# a request. The other subroutines are auxiliary. +############################################################################### + + +sub safetyFilter { + my $answer = shift; # accepts one answer and checks it + my $submittedAnswer = $answer; + $answer = '' unless defined $answer; + my ($errorno, $answerIsCorrectQ); + $answer =~ tr/\000-\037/ /; + #### Return if answer field is empty ######## + unless ($answer =~ /\S/) { +# $errorno = "<BR>No answer was submitted."; + $errorno = 0; ## don't report blank answer as error + + return ($answer,$errorno); + } + + ######### Return if forbidden characters are found + unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\[\]\(\)\,\|]+$/ ) { + $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; + $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; + + return ($answer,$errorno); + } + + $errorno = 0; + return($answer, $errorno); +} + + +sub logTimingInfo{ + my ($beginTime,$endTime,) = @_; + my $out = ""; + $out .= Benchmark::timestr( Benchmark::timediff($endTime , $beginTime) ); + $out; +} +###################################################################### +sub PG_warnings_handler { + my @input = @_; + my $msg_string = longmess(@_); + my @msg_array = split("\n",$msg_string); + my $out_string = ''; + + # Extra stack information is provided in this next block + # If the warning message does NOT end in \n then a line + # number is appended (see Perl manual about warn function) + # The presence of the line number is detected below and extra + # stack information is added. + # To suppress the line number and the extra stack information + # add \n to the end of a warn message (in .pl files. In .pg + # files add ~~n instead + + + if (@msg_array) { # if there are more details + $out_string .= "##More details. The calling sequence is: <BR>\n"; + foreach my $line (@msg_array) { + chomp($line); + next unless $line =~/\w+\:\:/; + $out_string .= "----" .$line . "<BR>\n"; + } + } + + $WARNINGS .="* " . join("<BR>",@input) . "<BR>\n" . $out_string . + "<BR>\n--------------------------------------<BR>\n<BR>\n"; +} + +my $CarpLevel = 0; # How many extra package levels to skip on carp. +my $MaxEvalLen = 0; # How much eval '...text...' to show. 0 = all. +sub longmess { + my $error = shift; + my $mess = ""; + my $i = 1 + $CarpLevel; + my ($pack,$file,$line,$sub,$eval,$require); + + while (($pack,$file,$line,$sub,undef,undef,$eval,$require) = caller($i++)) { + if ($error =~ m/\n$/) { + $mess .= $error; + } + else { + if (defined $eval) { + if ($require) { + $sub = "require $eval"; + } + else { + $eval =~ s/[\\\']/\\$&/g; + if ($MaxEvalLen && length($eval) > $MaxEvalLen) { + substr($eval,$MaxEvalLen) = '...'; + } + $sub = "eval '$eval'"; + } + } + elsif ($sub eq '(eval)') { + $sub = 'eval {...}'; + } + + $mess .= "\t$sub " if $error eq "called"; + $mess .= "$error at $file line $line\n"; + } + + $error = "called"; + } + + $mess || $error; +} + +###################################################################### + + +sub pretty_print_rh { + my $rh = shift; + my $out = ""; + my $type = ref($rh); + if ( ref($rh) =~/HASH/ ) { + foreach my $key (sort keys %{$rh}) { + $out .= " $key => " . pretty_print_rh( $rh->{$key} ) . "\n"; + } + } elsif ( ref($rh) =~ /SCALAR/ ) { + $out = "scalar reference ". ${$rh}; + } elsif ( ref($rh) =~/Base64/ ) { + $out .= "base64 reference " .$$rh; + } else { + $out = $rh; + } + if (defined($type) ) { + $out .= "type = $type \n"; + } + return $out; +} + +###################################################################### + +sub defineProblemEnvir { + my ( + $self, + $ce, + $user, + $key, + $set, + $problem, + $psvn, + $formFields, + $options, + ) = @_; + + my %envir; + + # ---------------------------------------------------------------------- + + # PG environment variables + # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 + # any changes are noted by "ADDED:" or "REMOVED:" + + # Vital state information + # ADDED: displayModeFailover, displayHintsQ, displaySolutionsQ, + # refreshMath2img, texDisposition + + $envir{psvn} = $set->psvn; + $envir{psvnNumber} = $envir{psvn}; + $envir{probNum} = $problem->problem_id; + $envir{questionNumber} = $envir{probNum}; + $envir{fileName} = $problem->source_file; + $envir{probFileName} = $envir{fileName}; + $envir{problemSeed} = $problem->problem_seed; + $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); + $envir{languageMode} = $envir{displayMode}; + $envir{outputMode} = $envir{displayMode}; + $envir{displayHintsQ} = $options->{showHints}; + $envir{displaySolutionsQ} = $options->{showSolutions}; + $envir{texDisposition} = "pdf"; # in webwork2, we use pdflatex + + # Problem Information + # ADDED: courseName, formatedDueDate + + $envir{openDate} = $set->open_date; + $envir{formattedOpenDate} = formatDateTime($envir{openDate}, $ce->{siteDefaults}{timezone}); + $envir{dueDate} = $set->due_date; + $envir{formattedDueDate} = formatDateTime($envir{dueDate}, $ce->{siteDefaults}{timezone}); + $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files + $envir{answerDate} = $set->answer_date; + $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}, $ce->{siteDefaults}{timezone}); + $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0); + $envir{problemValue} = $problem->value; + $envir{sessionKey} = $key; + $envir{courseName} = $ce->{courseName}; + + # Student Information + # ADDED: studentID + + $envir{sectionName} = $user->section; + $envir{sectionNumber} = $envir{sectionName}; + $envir{recitationName} = $user->recitation; + $envir{recitationNumber} = $envir{recitationName}; + $envir{setNumber} = $set->set_id; + $envir{studentLogin} = $user->user_id; + $envir{studentName} = $user->first_name . " " . $user->last_name; + $envir{studentID} = $user->student_id; + + # Answer Information + # REMOVED: refSubmittedAnswers + + $envir{inputs_ref} = $formFields; + + # External Programs + # ADDED: externalLaTeXPath, externalDvipngPath, + # externalGif2EpsPath, externalPng2EpsPath + + $envir{externalTTHPath} = $ce->{externalPrograms}->{tth}; + $envir{externalLaTeXPath} = $ce->{externalPrograms}->{latex}; + $envir{externalDvipngPath} = $ce->{externalPrograms}->{dvipng}; + $envir{externalGif2EpsPath} = $ce->{externalPrograms}->{gif2eps}; + $envir{externalPng2EpsPath} = $ce->{externalPrograms}->{png2eps}; + $envir{externalGif2PngPath} = $ce->{externalPrograms}->{gif2png}; + + # Directories and URLs + # REMOVED: courseName + # ADDED: dvipngTempDir + # ADDED: jsMathURL + # ADDED: asciimathURL + + $envir{cgiDirectory} = undef; + $envir{cgiURL} = undef; + $envir{classDirectory} = undef; + $envir{courseScriptsDirectory} = $ce->{pg}->{directories}->{macros}."/"; + $envir{htmlDirectory} = $ce->{courseDirs}->{html}."/"; + $envir{htmlURL} = $ce->{courseURLs}->{html}."/"; + $envir{macroDirectory} = $ce->{courseDirs}->{macros}."/"; + $envir{templateDirectory} = $ce->{courseDirs}->{templates}."/"; + $envir{tempDirectory} = $ce->{courseDirs}->{html_temp}."/"; + $envir{tempURL} = $ce->{courseURLs}->{html_temp}."/"; + $envir{scriptDirectory} = undef; + $envir{webworkDocsURL} = $ce->{webworkURLs}->{docs}."/"; + $envir{localHelpURL} = $ce->{webworkURLs}->{local_help}."/"; + $envir{jsMathURL} = $ce->{webworkURLs}->{jsMath}; + $envir{asciimathURL} = $ce->{webworkURLs}->{asciimath}; + + # Information for sending mail + + $envir{mailSmtpServer} = $ce->{mail}->{smtpServer}; + $envir{mailSmtpSender} = $ce->{mail}->{smtpSender}; + $envir{ALLOW_MAIL_TO} = $ce->{mail}->{allowedRecipients}; + + # Default values for evaluating answers + + my $ansEvalDefaults = $ce->{pg}->{ansEvalDefaults}; + $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); + + # ---------------------------------------------------------------------- + + my $basename = "equation-$envir{psvn}.$envir{probNum}"; + $basename .= ".$envir{problemSeed}" if $envir{problemSeed}; + + # to make grabbing these options easier, we'll pull them out now... + my %imagesModeOptions = %{$ce->{pg}->{displayModeOptions}->{images}}; + + # Object for generating equation images + $envir{imagegen} = WeBWorK::PG::ImageGenerator->new( + tempDir => $ce->{webworkDirs}->{tmp}, # global temp dir + latex => $envir{externalLaTeXPath}, + dvipng => $envir{externalDvipngPath}, + useCache => 1, + cacheDir => $ce->{webworkDirs}->{equationCache}, + cacheURL => $ce->{webworkURLs}->{equationCache}, + cacheDB => $ce->{webworkFiles}->{equationCacheDB}, + useMarkers => ($imagesModeOptions{dvipng_align} && $imagesModeOptions{dvipng_align} eq 'mysql'), + dvipng_align => $imagesModeOptions{dvipng_align}, + dvipng_depth_db => $imagesModeOptions{dvipng_depth_db}, + ); + + # ADDED: jsMath options + $envir{jsMath} = {%{$ce->{pg}{displayModeOptions}{jsMath}}}; + + # Other things... + $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes + $envir{PROBLEM_GRADER_TO_USE} = $ce->{pg}->{options}->{grader}; + $envir{PRINT_FILE_NAMES_FOR} = $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR}; + + # ADDED: __files__ + # an array for mapping (eval nnn) to filenames in error messages + $envir{__files__} = { + root => $ce->{webworkDirs}{root}, # used to shorten filenames + pg => $ce->{pg}{directories}{root}, # ditto + tmpl => $ce->{courseDirs}{templates}, # ditto + }; + + # variables for interpreting capa problems and other things to be + # seen in a pg file + my $specialPGEnvironmentVarHash = $ce->{pg}->{specialPGEnvironmentVars}; + for my $SPGEV (keys %{$specialPGEnvironmentVarHash}) { + $envir{$SPGEV} = $specialPGEnvironmentVarHash->{$SPGEV}; + } + + return \%envir; +} + + + + + +1; --- /dev/null +++ lib/WebworkWebservice/LibraryActions.pm @@ -0,0 +1,190 @@ +#!/usr/local/bin/perl -w + +# Copyright (C) 2002 Michael Gage + +############################################################################### +# Web service which fetches WeBWorK problems from a library. +############################################################################### + + +#use lib '/home/gage/webwork/pg/lib'; +#use lib '/home/gage/webwork/webwork-modperl/lib'; + +package WebworkWebservice::LibraryActions; +use WebworkWebservice; +use base qw(WebworkWebservice); + +use strict; +use sigtrap; +use Carp; +use Safe; +use Apache; +use WeBWorK::Utils; +use WeBWorK::CourseEnvironment; +use WeBWorK::PG::Translator; +use WeBWorK::PG::IO; +use Benchmark; +use MIME::Base64 qw( encode_base64 decode_base64); + +############################################## +# Obtain basic information about directories, course name and host +############################################## +our $WW_DIRECTORY = $WebworkWebservice::WW_DIRECTORY; +our $PG_DIRECTORY = $WebworkWebservice::PG_DIRECTORY; +our $COURSENAME = $WebworkWebservice::COURSENAME; +our $HOST_NAME = $WebworkWebservice::HOST_NAME; +our $PASSWORD = $WebworkWebservice::PASSWORD; +our $ce = WeBWorK::CourseEnvironment->new($WW_DIRECTORY, "", "", $COURSENAME); +#warn "library ce \n ", WebworkWebservice::pretty_print_rh($ce); +warn "LibraryActions is ready"; + +############################################## +# Obtain basic information about local libraries +############################################## + my %prob_libs = %{$ce->{courseFiles}->{problibs} }; + + warn pretty_print_rh(\%prob_libs); + # replace library names with full paths + + my $templateDir = $ce->{courseDirs}->{templates}; +# warn "template Directory is $templateDir"; + foreach my $key (keys %prob_libs) { + $prob_libs{$key} = "$templateDir/$key"; + } + #warn "prob libraries", WebworkWebservice::pretty_print_rh(\%prob_libs); + +sub listLibraries { + my $rh = shift; + return [sort keys %prob_libs]; +} + +use File::stat; +sub readFile { + my $rh = shift; + local($|)=1; + my $out = {}; + my $filePath = $rh->{filePath}; + unless ($rh->{pw} eq $PASSWORD ) { + $out->{error} =404; + return($out); + } + if ( defined($prob_libs{$rh->{library_name}} ) ) { + $filePath = $prob_libs{$rh->{library_name}} .'/'. $filePath; + } else { + $out->{error} = "Could not find library:".$rh->{library_name}.":"; + return($out); + } + + if (-r $filePath) { + open IN, "<$filePath"; + local($/)=undef; + my $text = <IN>; + $out->{text}= encode_base64($text); + my $sb=stat($filePath); + $out->{size}=$sb->size; + $out->{path}=$filePath; + $out->{permissions}=$sb->mode&07777; + $out->{modTime}=scalar localtime $sb->mtime; + close(IN); + } else { + $out->{error} = "Could not read file at |$filePath|"; + } + return($out); +} + + + +use File::Find; +sub listLib { + my $rh = shift; + my $out = {}; + my $dirPath; + unless ($rh->{pw} eq $PASSWORD ) { + $out->{error}=" 404 $PASSWORD and ".$rh->{pw}; + return($out); + } + + if ( defined($prob_libs{$rh->{library_name}} ) ) { + $dirPath = $prob_libs{$rh->{library_name}} ; + } else { + $out->{error} = "Could not find library:".$rh->{library_name}.":"; + return($out); + } + warn "library directory path is $dirPath"; + my @outListLib; + my $wanted = sub { + my $name = $File::Find::name; + my @out=(); + if ($name =~/\S/ ) { + $name =~ s|^$dirPath/*||o; # cut the first directory + # $name =~ s|^\w*\/||; # cut the set name + push(@outListLib, "$name") if $name =~/\.pg/; + + } + }; + + my $command = $rh->{command}; + $command = 'all' unless defined($command); + $command eq 'all' && do {print "$dirPath\n\n"; + find($wanted, $dirPath); + @outListLib = sort @outListLib; + $out->{ra_out} = \@outListLib; + $out->{text} = join("\n", @outListLib); + return($out); + }; + $command eq 'setsOnly' && do { + if ( opendir(DIR, $dirPath) ) { + my @fileList=(); + while (defined(my $file = readdir(DIR))) { + push(@fileList,$file) if -d "$dirPath/$file"; + + } + $out->{text} = join("\n",sort @fileList); + closedir(DIR); + } else { + $out->{error}= "Can't open directory $dirPath"; + } + return($out); + }; + + $command eq 'listSet' && do {@outListLib=(); + my $dirPath2 = $dirPath . $rh->{set}; + + if ( -e $dirPath2) { + find($wanted, $dirPath2); + $out ->{text} = join("\n", sort @outListLib ); + } else { + $out->{error} = "Can't open directory $dirPath2"; + } + return($out); + + }; + # else + $out->{error}="Unrecognized command $command"; + $out; +} + + +sub pretty_print_rh { + my $rh = shift; + my $out = ""; + my $type = ref($rh); + if ( ref($rh) =~/HASH/ ) { + foreach my $key (sort keys %{$rh}) { + $out .= " $key => " . pretty_print_rh( $rh->{$key} ) . "\n"; + } + } elsif ( ref($rh) =~ /SCALAR/ ) { + $out = "scalar reference ". ${$rh}; + } elsif ( ref($rh) =~/Base64/ ) { + $out .= "base64 reference " .$$rh; + } else { + $out = $rh; + } + if (defined($type) ) { + $out .= "type = $type \n"; + } + return $out; +} + + +1; |
From: Mike G. v. a. <act...@de...> - 2004-12-27 17:33:20
|
Log Message: ----------- Adding support for an XMLRPC mode which allows access to some of Webworks functionality. These files largely duplicate the functionality of the daemons running on devel.webwork and webwork.math which support the display of the Problem Library. There are still some problems with displaying equations in HTML_dpng and also in jsMath mode. There is a lot of overlap code with PG.pm which needs to be factored out eventually. I'm uploading the code now so that others can suggest improvements and ideas for factoring code. Added Files: ----------- webwork-modperl/lib: WebworkWebservice.pm Revision Data ------------- --- /dev/null +++ lib/WebworkWebservice.pm @@ -0,0 +1,304 @@ + +# FIXME need way to find the basic libraries and such. + + +BEGIN { + my $webwork_directory = $ENV{WEBWORK_ROOT}; + + eval "use lib '$webwork_directory/lib'"; die $@ if $@; + eval "use WeBWorK::CourseEnvironment"; die $@ if $@; + my $ce = new WeBWorK::CourseEnvironment({ webwork_dir => $webwork_directory }); + my $webwork_url = $ce->{webwork_url}; + my $pg_dir = $ce->{pg_dir}; +# my $webwork_htdocs_url = $ce->{webwork_htdocs_url}; +# my $webwork_htdocs_dir = $ce->{webwork_htdocs_dir}; +# my $webwork_courses_url = $ce->{webwork_courses_url}; +# my $webwork_courses_dir = $ce->{webwork_courses_dir}; + eval "use lib '$pg_dir/lib'"; die $@ if $@; + + $WebworkWebservice::WW_DIRECTORY = $webwork_directory; + $WebworkWebservice::PG_DIRECTORY = $pg_dir; + $WebworkWebservice::SeedCE = $ce; + $WebworkWebservice::HOST_NAME = Apache->server->server_hostname; + $WebworkWebservice::HOST_PORT = Apache->server->port; + #$WebworkWebservice::HOST_PATH = Apache->server->path(); + $WebworkWebservice::WebworkWebservice = 'geometry'; + $WebworkWebservice::COURSENAME = 'daemon_course'; # default course + +} +use Apache; + + +#use lib '/home/gage/webwork/webwork-modperl/lib'; +#use lib '/home/gage/webwork/pg/lib'; + + +#$Webservice::HOST_PATH = "http://$Webservice::HOST_NAME"; +#$Webservice::HOST_PATH .= ":$Webservice::HOST_PORT" +# unless ($Webservice::HOST_PORT == 80 ); + +warn "webwork_directory = $WebworkWebservice::WW_DIRECTORY\n\t"; +warn "pg_directory = $WebworkWebservice::PG_DIRECTORY\n\t"; +warn "seedCE = $WebworkWebservice::SeedCE\n\t"; +warn "host name = $WebworkWebservice::HOST_NAME\n\t"; +#warn "host port = $Webservice::HOST_PORT\n\t"; +#warn "host path = $Webservice::HOST_PATH\n\t"; +warn " password $WebworkWebservice::WebworkWebservice\n\t"; + +use strict; +############################################################################### + +package WebworkWebservice; + +sub pretty_print_rh { + shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + my $rh = shift; + my $indent = shift || 0; + my $out = ""; + my $type = ref($rh); + + if (defined($type) and $type) { + $out .= " type = $type; "; + } elsif ($rh == undef) { + $out .= " type = UNDEFINED; "; + } + if ( ref($rh) =~/HASH/ or "$rh" =~/HASH/ ) { + $out .= "{\n"; + $indent++; + foreach my $key (sort keys %{$rh}) { + $out .= " "x$indent."$key => " . pretty_print_rh( $rh->{$key}, $indent ) . "\n"; + } + $indent--; + $out .= "\n"." "x$indent."}\n"; + + } elsif (ref($rh) =~ /ARRAY/ or "$rh" =~/ARRAY/) { + $out .= " ( "; + foreach my $elem ( @{$rh} ) { + $out .= pretty_print_rh($elem, $indent); + + } + $out .= " ) \n"; + } elsif ( ref($rh) =~ /SCALAR/ ) { + $out .= "scalar reference ". ${$rh}; + } elsif ( ref($rh) =~/Base64/ ) { + $out .= "base64 reference " .$$rh; + } else { + $out .= $rh; + } + + return $out." "; +} + + +use WebworkWebservice::RenderProblem; +use WebworkWebservice::LibraryActions; +use WebworkWebservice::MathTranslators; + +############################################################################### +package WebworkXMLRPC; +use WebworkWebservice; +use base qw(WebworkWebservice); + + + +# respond to xmlrpc requests +sub listLib { + my $self = shift; + my $in = shift; + return( WebworkWebservice::LibraryActions::listLib($in) ); +} +sub listLibraries { + my $self = shift; + my $in = shift; + return( WebworkWebservice::LibraryActions::listLibraries($in) ); +} +sub renderProblem { + my $self = shift; + my $in = shift; + return( WebworkWebservice::RenderProblem::renderProblem($in) ); +} +sub readFile { + my $self = shift; + my $in = shift; + return( WebworkWebservice::LibraryActions::readFile($in) ); +} + + +# -- SOAP::Lite -- guide.soaplite.com -- Copyright (C) 2001 Paul Kulchenko -- +# test responses + +sub hi { shift if UNIVERSAL::isa($_[0] => __PACKAGE__); # grabs class reference + return "hello, world"; +} +sub hello2 { shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + #print "Receiving request for hello world\n"; + return "Hello world2"; +} +sub bye {shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + return "goodbye, sad cruel world"; +} + +sub languages {shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + return ["Perl", "C", "sh"]; +} + +sub echo_self { + my $self = shift; +} + +sub echo { + return join("|",("begin ", @_, " end") ); +} + +sub pretty_print_rh { + WebworkWebservice::pretty_print_rh(@_); +} + + +sub tth {shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + my $in = shift; + my $tthpath = "/usr/local/bin/tth"; + # $tthpath -L -f5 -r 2>/dev/null " . $inputString; + return $in; + +} + + + + +package WWd; + +#use lib '/home/gage/webwork/xmlrpc/daemon'; +#use WebworkXMLRPC; + + + + +############utilities + +sub echo { + return "WWd package ".join("|",("begin ", @_, " end") ); +} + +sub listLib { + shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + my $in = shift; + return( Webwork::listLib($in) ); +} +sub renderProblem { + shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + my $in = shift; + return( Filter::filterObject( Webwork::renderProblem($in) ) ); +} +sub readFile { + shift if UNIVERSAL::isa($_[0] => __PACKAGE__); + my $in = shift; + return( Webwork::readFile($in) ); +} +# sub hello { +# shift if UNIVERSAL::isa($_[0] => __PACKAGE__); +# print "Receiving request for hello world\n"; +# return "Hello world?"; +# } + + +# sub tth { +# shift if UNIVERSAL::isa($_[0] => __PACKAGE__); +# my $in = shift; +# my $tthpath = "/usr/local/bin/tth"; +# my $out; +# $inputString = "<<END_OF_TTH_INPUT_STRING;\n\n\n" . $in . "\nEND_OF_TTH_INPUT_STRING\necho \"\" >/dev/null"; +# #it's not clear why another command is needed. +# +# if (-x $tthpath ) { +# my $tthcmd = "$tthpath -L -f5 -r 2>/dev/null " . $inputString; +# if (open(TTH, "$tthcmd |")) { +# local($/); +# $/ = undef; +# $out = <TTH>; +# $/ = "\n"; +# close(TTH); +# }else { +# $out = "<BR>there has been an error in executing $tthcmd<BR>"; +# } +# } else { +# $out = "<BR> Can't execute the program tth at |$tthpath|<BR>"; +# } +# +# #return "<!-- \r\n" . $in . "\r\n-->\r\n\r\n" . $out . "\r\n\r\n"; +# return $out; +# +# } + +package Filter; + + + + + + + + + + +sub is_hash_ref { + my $in =shift; + my $save_SIG_die_trap = $SIG{__DIE__}; + $SIG{__DIE__} = sub {CORE::die(@_) }; + my $out = eval{ %{ $in } }; + $out = ($@ eq '') ? 1 : 0; + $@=''; + $SIG{__DIE__} = $save_SIG_die_trap; + $out; +} +sub is_array_ref { + my $in =shift; + my $save_SIG_die_trap = $SIG{__DIE__}; + $SIG{__DIE__} = sub {CORE::die(@_) }; + my $out = eval{ @{ $in } }; + $out = ($@ eq '') ? 1 : 0; + $@=''; + $SIG{__DIE__} = $save_SIG_die_trap; + $out; +} +sub filterObject { + + my $is_hash = 0; + my $is_array =0; + my $obj = shift; + #print "Enter filterObject ", ref($obj), "\n"; + my $type = ref($obj); + unless ($type) { + #print "leave filterObject with nothing\n"; + return($obj); + } + + + if ( is_hash_ref($obj) ) { + #print "enter hash ", %{$obj},"\n"; + my %obj_container= %{$obj}; + foreach my $key (keys %obj_container) { + $obj_container{$key} = filterObject( $obj_container{$key} ); + #print $key, " ", ref($obj_container{$key})," ", $obj_container{$key}, "\n"; + } + #print "leave filterObject with HASH\n"; + return( bless(\%obj_container,'HASH')); + }; + + + + if ( is_array_ref($obj) ) { + #print "enter array ( ", @{$obj}," )\n"; + my @obj_container= @{$obj}; + foreach my $i (0..$#obj_container) { + $obj_container[$i] = filterObject( $obj_container[$i] ); + #print "\[$i\] ", ref($obj_container[$i])," ", $obj_container[$i], "\n"; + } + #print "leave filterObject with ARRAY\n"; + return( bless(\@obj_container,'ARRAY')); + }; + +} + + +1; |
From: Mike G. v. a. <act...@de...> - 2004-12-27 17:28:45
|
Update of /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice In directory devel.webwork.rochester.edu:/home/gage/webwork/webwork-modperl/lib/WebworkWebservice Log Message: Directory /webwork/cvs/system/webwork-modperl/lib/WebworkWebservice added to the repository |
From: dpvc v. a. <act...@de...> - 2004-12-23 02:30:10
|
Log Message: ----------- Work around MSIE bug. (Can't do height:100% for the size of the scrolling list. Every other browser in the world seems to be able to handle this.) Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor: FileManager.pm Revision Data ------------- Index: FileManager.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm,v retrieving revision 1.5 retrieving revision 1.6 diff -Llib/WeBWorK/ContentGenerator/Instructor/FileManager.pm -Llib/WeBWorK/ContentGenerator/Instructor/FileManager.pm -u -r1.5 -r1.6 --- lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm +++ lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm @@ -224,7 +224,7 @@ print CGI::Tr({valign=>"middle"}, CGI::td(CGI::scrolling_list( -name => "files", id => "files", - -style => "font-family:monospace; width:30em; height:100%", + -style => "font-family:monospace; width:30em", -size => 15, -multiple => 1, -values => $files, |
From: Mike G. v. a. <act...@de...> - 2004-12-21 18:59:41
|
Log Message: ----------- fixed error when set number or problem number is not defined Kept fix that keeps set 0 and problem 0 from being replaced by blanks. Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor: PGProblemEditor.pm Revision Data ------------- Index: PGProblemEditor.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v retrieving revision 1.50 retrieving revision 1.51 diff -Llib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm -Llib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm -u -r1.50 -r1.51 --- lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm +++ lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm @@ -548,7 +548,11 @@ my $inputFilePath = $self->{inputFilePath}; # path to the file for input, (might be a .tmp file) my $setName = $r->urlpath->arg("setID") ; my $problemNumber = $r->urlpath->arg("problemID") ; - + $setName = defined($setName) ? $setName : ''; # we need this instead of using the || construction + # to keep set 0 from being set to the + # empty string. + $problemNumber = defined($problemNumber) ? $problemNumber : ''; + ######################################################################### # Find the text for the problem, either in the tmp file, if it exists @@ -574,7 +578,7 @@ } else { #warn "obtaining input from r_problemContents"; } - + my $protected_file = not -w $inputFilePath; my $header = CGI::i("Editing problem".CGI::b("set $setName/ problem $problemNumber</emphasis>").CGI::br()." in file $inputFilePath"); $header = ($inputFilePath =~ /$TEMPFILESUFFIX/) ? CGI::div({class=>'temporaryFile'},$header) : $header; # use colors if temporary file |
From: Robert V. D. v. a. <act...@de...> - 2004-12-21 18:02:48
|
Log Message: ----------- Fixed minor display problem where empty (not-overriden) date values were being displayed as 12/31/1969 Closes #748 Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor: ProblemSetDetail.pm Revision Data ------------- Index: ProblemSetDetail.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm,v retrieving revision 1.15 retrieving revision 1.16 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm -u -r1.15 -r1.16 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm @@ -85,7 +85,7 @@ size => "26", override => "any", labels => { - 0 => "None Specified", + #0 => "None Specified", "" => "None Specified", }, }, @@ -95,7 +95,7 @@ size => "26", override => "any", labels => { - 0 => "None Specified", + #0 => "None Specified", "" => "None Specified", }, }, @@ -105,7 +105,7 @@ size => "26", override => "any", labels => { - 0 => "None Specified", + #0 => "None Specified", "" => "None Specified", }, }, @@ -208,8 +208,8 @@ if ($forUsers) { $output .= CGI::Tr( CGI::th({colspan=>"2"}, " "), - CGI::th({colspan=>"1"}, "Individual set dates"), - CGI::th({}, "Class set dates"), + CGI::th({colspan=>"1"}, "User Values"), + CGI::th({}, "Class values"), ); } @@ -274,8 +274,8 @@ $userValue = (defined($userValue)) ? ($labels{$userValue || ""} || $userValue) : ""; if ($field =~ /_date/) { - $globalValue = $self->formatDateTime($globalValue) if $globalValue; - $userValue = $self->formatDateTime($userValue) if $userValue; + $globalValue = $self->formatDateTime($globalValue) if defined $globalValue && $globalValue ne $labels{""}; + $userValue = $self->formatDateTime($userValue) if defined $userValue && $userValue ne $labels{""}; } # check to make sure that a given value can be overridden @@ -319,7 +319,7 @@ name => "$recordType.$recordID.$field.override", label => "", value => $field, - checked => $r->param("$recordType.$recordID.$field.override") || ($userValue ne "" ? 1 : 0), + checked => $r->param("$recordType.$recordID.$field.override") || ($userValue ne ($labels{""} || "") ? 1 : 0), }) : "", $properties{name}, $inputType, @@ -518,15 +518,15 @@ my ($open_date, $due_date, $answer_date); my $error = 0; if (defined $r->param('submit_changes')) { + my @names = ("open_date", "due_date", "answer_date"); + + my %dates = map { $_ => $r->param("set.$setID.$_") } @names; + %dates = map { + my $unlabel = $undoLabels{$_}->{$dates{$_}}; + $_ => defined $unlabel ? $setRecord->$_ : $self->parseDateTime($dates{$_}) + } @names; - my $od_param = $r->param("set.$setID.open_date"); - my $dd_param = $r->param("set.$setID.due_date"); - my $ad_param = $r->param("set.$setID.answer_date"); - #my $setRecord = $db->getGlobalSet($setID); # already fetched above --sam - - $open_date = $od_param ? $self->parseDateTime($od_param) : $setRecord->open_date; - $due_date = $dd_param ? $self->parseDateTime($dd_param) : $setRecord->due_date; - $answer_date = $ad_param ? $self->parseDateTime($ad_param) : $setRecord->answer_date; + ($open_date, $due_date, $answer_date) = map { $dates{$_} } @names; if ($answer_date < $due_date || $answer_date < $open_date) { $self->addbadmessage("Answers cannot be made available until on or after the due date!"); @@ -557,20 +557,23 @@ foreach my $record (@userRecords) { foreach my $field ( @{ SET_FIELDS() } ) { next unless canChange($forUsers, $field); - my $override = $r->param("set.$setID.$field.override"); + if (defined $override && $override eq $field) { my $param = $r->param("set.$setID.$field"); $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - $param = $undoLabels{$field}->{$param} || $param; + my $unlabel = $undoLabels{$field}->{$param}; + $param = $unlabel if defined $unlabel; +# $param = $undoLabels{$field}->{$param} || $param; if ($field =~ /_date/) { - $param = $self->parseDateTime($param); + $param = $self->parseDateTime($param) unless defined $unlabel; } $record->$field($param); } else { $record->$field(undef); } + } $db->putUserSet($record); } @@ -580,9 +583,10 @@ my $param = $r->param("set.$setID.$field"); $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - $param = $undoLabels{$field}->{$param} || $param; + my $unlabel = $undoLabels{$field}->{$param}; + $param = $unlabel if defined $unlabel; if ($field =~ /_date/) { - $param = $self->parseDateTime($param); + $param = $self->parseDateTime($param) unless defined $unlabel; } $setRecord->$field($param); } @@ -619,7 +623,8 @@ my $param = $r->param("problem.$problemID.$field"); $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - $param = $undoLabels{$field}->{$param} || $param; + my $unlabel = $undoLabels{$field}->{$param}; + $param = $unlabel if defined $unlabel; $changed ||= changed($record->$field, $param); $record->$field($param); } else { @@ -634,7 +639,8 @@ my $param = $r->param("problem.$problemID.$field"); $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - $param = $undoLabels{$field}->{$param} || $param; + my $unlabel = $undoLabels{$field}->{$param}; + $param = $unlabel if defined $unlabel; $changed ||= changed($record->$field, $param); $record->$field($param); } @@ -652,7 +658,8 @@ my $param = $r->param("problem.$problemID.$field"); $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - $param = $undoLabels{$field}->{$param} || $param; + my $unlabel = $undoLabels{$field}->{$param}; + $param = $unlabel if defined $unlabel; $changed ||= changed($problemRecord->$field, $param); $problemRecord->$field($param); } @@ -684,7 +691,8 @@ my $param = $r->param("problem.$problemID.$field"); $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - $param = $undoLabels{$field}->{$param} || $param; + my $unlabel = $undoLabels{$field}->{$param}; + $param = $unlabel if defined $unlabel; $changed ||= changed($record->$field, $param); $record->$field($param); } @@ -709,7 +717,6 @@ my @userProblemIDs = map { [$_, $setID, $problemID] } ($forUsers ? @editForUser : $db->listProblemUsers($setID, $problemID)); my @userProblemRecords = $db->getUserProblems(@userProblemIDs); foreach my $record (@userProblemRecords) { -$self->addbadmessage($record->user_id); if (defined $record && ($record->status eq "" || $record->status < 1)) { $record->status(1); $record->attempted(1); |
From: Robert V. D. v. a. <act...@de...> - 2004-12-21 15:44:49
|
Log Message: ----------- Added the following features: * Searching on any user data field * Sorting by any two fields * Reports duplicate names on classlist import Closes #654, #664, and #684 Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor: UserList.pm Revision Data ------------- Index: UserList.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm,v retrieving revision 1.60 retrieving revision 1.61 diff -Llib/WeBWorK/ContentGenerator/Instructor/UserList.pm -Llib/WeBWorK/ContentGenerator/Instructor/UserList.pm -u -r1.60 -r1.61 --- lib/WeBWorK/ContentGenerator/Instructor/UserList.pm +++ lib/WeBWorK/ContentGenerator/Instructor/UserList.pm @@ -68,7 +68,7 @@ use Apache::Constants qw(:common REDIRECT DONE); #FIXME -- this should be called higher up in the object tree. use constant HIDE_USERS_THRESHHOLD => 50; use constant EDIT_FORMS => [qw(cancelEdit saveEdit)]; -use constant VIEW_FORMS => [qw(filter edit import export add delete)]; +use constant VIEW_FORMS => [qw(filter sort edit import export add delete)]; # permissions needed to perform a given action use constant FORM_PERMS => { @@ -86,7 +86,7 @@ sets => "assign_problem_sets", }; -use constant STATE_PARAMS => [qw(user effectiveUser key visible_users no_visible_users prev_visible_users no_prev_visible_users editMode sortField)]; +use constant STATE_PARAMS => [qw(user effectiveUser key visible_users no_visible_users prev_visible_users no_prev_visible_users editMode primarySortField secondarySortField)]; use constant SORT_SUBS => { user_id => \&byUserID, @@ -295,6 +295,7 @@ "Perm. Level" ); + $self->{prettyFieldNames} = \%prettyFieldNames; ########## set initial values for state fields my @allUserIDs = $db->listUsers; @@ -327,7 +328,8 @@ if $self->{editMode} and not $authz->hasPermissions($user, "modify_student_data"); - $self->{sortField} = $r->param("sortField") || "last_name"; + $self->{primarySortField} = $r->param("primarySortField") || "last_name"; + $self->{secondarySortField} = $r->param("secondarySortField") || "first_name"; my @allUsers = $db->getUsers(@allUserIDs); my (%sections, %recitations); @@ -373,7 +375,8 @@ my @prevVisibleUserIDs = @{ $self->{prevVisibleUserIDs} }; my @selectedUserIDs = @{ $self->{selectedUserIDs} }; my $editMode = $self->{editMode}; - my $sortField = $self->{sortField}; + my $primarySortField = $self->{primarySortField}; + my $secondarySortField = $self->{secondarySortField}; #warn "visibleUserIDs=@visibleUserIDs\n"; #warn "prevVisibleUserIDs=@prevVisibleUserIDs\n"; @@ -383,12 +386,15 @@ ########## get required users my @Users = grep { defined $_ } @visibleUserIDs ? $db->getUsers(@visibleUserIDs) : (); - - # presort users + my %sortSubs = %{ SORT_SUBS() }; - my $sortSub = $sortSubs{$sortField}; - #@Users = sort $sortSub @Users; - @Users = sort byLnFnUid @Users; + my $primarySortSub = $sortSubs{$primarySortField}; + my $secondarySortSub = $sortSubs{$secondarySortField}; + + # don't forget to sort in opposite order of importance + @Users = sort $secondarySortSub @Users; + @Users = sort $primarySortSub @Users; + #@Users = sort byLnFnUid @Users; my @PermissionLevels; @@ -435,7 +441,8 @@ print CGI::hidden(-name=>"editMode", -value=>$editMode); - print CGI::hidden(-name=>"sortField", -value=>$sortField); + print CGI::hidden(-name=>"primarySortField", -value=>$primarySortField); + print CGI::hidden(-name=>"secondarySortField", -value=>$secondarySortField); print "\n<!-- state data here -->\n"; @@ -529,19 +536,23 @@ my ($self, $onChange, %actionParams) = @_; #return CGI::table({}, CGI::Tr({-valign=>"top"}, # CGI::td({}, + + my %prettyFieldNames = %{ $self->{prettyFieldNames} }; + return join("", "Show ", CGI::popup_menu( -name => "action.filter.scope", - -values => [qw(all none selected match_ids match_section match_recitation)], - -default => $actionParams{"action.filter.scope"}->[0] || "match_ids", + -values => [qw(all none selected match_regex)], + -default => $actionParams{"action.filter.scope"}->[0] || "match_regex", -labels => { all => "all users", none => "no users", selected => "users checked below", - match_ids => "users with matching user IDs:", - match_section => "users in selected section", - match_recitation => "users in selected recitation", +# match_ids => "users with matching user IDs:", + match_regex => "users who match:", +# match_section => "users in selected section", +# match_recitation => "users in selected recitation", }, -onchange => $onChange, ), @@ -552,22 +563,30 @@ -width => "50", -onchange => $onChange, ), - " (separate multiple IDs with commas)", - CGI::br(), - "sections: ", +# " (separate multiple IDs with commas)", +# CGI::br(), +# "sections: ", +# CGI::popup_menu( +# -name => "action.filter.section", +# -values => [ keys %{ $self->{sections} } ], +# -default => $actionParams{"action.filter.section"}->[0] || "", +# -labels => { $self->menuLabels($self->{sections}) }, +# -onchange => $onChange, +# ), +# " recitations: ", +# CGI::popup_menu( +# -name => "action.filter.recitation", +# -values => [ keys %{ $self->{recitations} } ], +# -default => $actionParams{"action.filter.recitation"}->[0] || "", +# -labels => { $self->menuLabels($self->{recitations}) }, +# -onchange => $onChange, +# ), + " in their ", CGI::popup_menu( - -name => "action.filter.section", - -values => [ keys %{ $self->{sections} } ], - -default => $actionParams{"action.filter.section"}->[0] || "", - -labels => { $self->menuLabels($self->{sections}) }, - -onchange => $onChange, - ), - " recitations: ", - CGI::popup_menu( - -name => "action.filter.recitation", - -values => [ keys %{ $self->{recitations} } ], - -default => $actionParams{"action.filter.recitation"}->[0] || "", - -labels => { $self->menuLabels($self->{recitations}) }, + -name => "action.filter.field", + -value => [ keys %{ FIELD_PROPERTIES() } ], + -default => $actionParams{"action.filter.field"}->[0] || "user_id", + -labels => \%prettyFieldNames, -onchange => $onChange, ), ); @@ -580,6 +599,9 @@ sub filter_handler { my ($self, $genericParams, $actionParams, $tableParams) = @_; + my $r = $self->r; + my $db = $r->db; + my $result; my $scope = $actionParams->{"action.filter.scope"}->[0]; @@ -592,6 +614,17 @@ } elsif ($scope eq "selected") { $result = "showing selected users"; $self->{visibleUserIDs} = $genericParams->{selected_users}; # an arrayref + } elsif ($scope eq "match_regex") { + $result = "showing matching users"; + my $regex = $actionParams->{"action.filter.user_ids"}->[0]; + my $field = $actionParams->{"action.filter.field"}->[0]; + my @userRecords = $db->getUsers(@{$self->{allUserIDs}}); + my @userIDs; + foreach my $record (@userRecords) { + next unless $record; + push @userIDs, $record->user_id if $record->{$field} =~ /^$regex/i; + } + $self->{visibleUserIDs} = \@userIDs; } elsif ($scope eq "match_ids") { my @userIDs = split /\s*,\s*/, $actionParams->{"action.filter.user_ids"}->[0]; $self->{visibleUserIDs} = \@userIDs; @@ -606,6 +639,76 @@ return $result; } +sub sort_form { + my ($self, $onChange, %actionParams) = @_; + return join ("", + "Primary sort: ", + CGI::popup_menu( + -name => "action.sort.primary", + -values => [qw(user_id first_name last_name email_address student_id status section recitation comment permission)], + -default => $actionParams{"action.sort.primary"}->[0] || "last_name", + -labels => { + user_id => "Login Name", + first_name => "First Name", + last_name => "Last Name", + email_address => "Email address", + student_id => "Student ID", + status => "Enrollment Status", + section => "Section", + recitation => "Recitation", + comment => "Comment", + permission => "Perm. Level" + }, + -onchange => $onChange, + ), + " Secondary sort: ", + CGI::popup_menu( + -name => "action.sort.secondary", + -values => [qw(user_id first_name last_name email_address student_id status section recitation comment permission)], + -default => $actionParams{"action.sort.secondary"}->[0] || "first_name", + -labels => { + user_id => "Login Name", + first_name => "First Name", + last_name => "Last Name", + email_address => "Email address", + student_id => "Student ID", + status => "Enrollment Status", + section => "Section", + recitation => "Recitation", + comment => "Comment", + permission => "Perm. Level" + }, + -onchange => $onChange, + ), + ".", + ); +} + +sub sort_handler { + my ($self, $genericParams, $actionParams, $tableParams) = @_; + + my $primary = $actionParams->{"action.sort.primary"}->[0]; + my $secondary = $actionParams->{"action.sort.secondary"}->[0]; + + $self->{primarySortField} = $primary; + $self->{secondarySortField} = $secondary; + + my %names = ( + user_id => "Login Name", + first_name => "First Name", + last_name => "Last Name", + email_address => "Email address", + student_id => "Student ID", + status => "Enrollment Status", + section => "Section", + recitation => "Recitation", + comment => "Comment", + permission => "Perm. Level" + ); + + return "Users sorted by $names{$primary} and then by $names{$secondary}."; +} + sub edit_form { my ($self, $onChange, %actionParams) = @_; @@ -791,7 +894,8 @@ return $numReplaced . " user" . ($numReplaced == 1 ? "" : "s") . " replaced, " . $numAdded . " user" . ($numAdded == 1 ? "" : "s") . " added, " - . $numSkipped . " user" . ($numSkipped == 1 ? "" : "s") . " skipped."; + . $numSkipped . " user" . ($numSkipped == 1 ? "" : "s") . " skipped" + . " (" . join (", ", @$skipped) . ") "; } sub export_form { @@ -934,8 +1038,8 @@ ################################################################################ sub byUserID { lc $a->user_id cmp lc $b->user_id } -sub byFirstName { (defined $a->first_name && defined $b->first_name) ? lc $a->first_name cmp lc $b->first_name : 0 } -sub byLastName { (defined $a->last_name && defined $b->last_name ) ? lc $a->last_name cmp lc $b->last_name : 0 } +sub byFirstName { (defined $a->first_name && defined $b->first_name) ? lc $a->first_name cmp lc $b->first_name : 0; } +sub byLastName { (defined $a->last_name && defined $b->last_name ) ? lc $a->last_name cmp lc $b->last_name : 0; } sub byEmailAddress { lc $a->email_address cmp lc $b->email_address } sub byStudentID { lc $a->student_id cmp lc $b->student_id } sub byStatus { lc $a->status cmp lc $b->status } |
From: Sam H. v. a. <act...@de...> - 2004-12-21 04:56:19
|
Log Message: ----------- Added course renaming to CourseManagement, CourseAdmin. It works like this: - move the course directory - move any course subdirectories that are still at their old locations (like if they were outside the course directory) - create a new database using addCourseHelper() - copy the course data into the new course database using copyCourseDataHelper() (INSERT INTO $new SELECT * FROM $old) - delete the old course database using deleteCourseHelper() TODO: * write helpers for gdbm and sql layouts * write command-line script Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator: CourseAdmin.pm webwork2/lib/WeBWorK/Utils: CourseManagement.pm webwork2/lib/WeBWorK/Utils/CourseManagement: sql_single.pm Revision Data ------------- Index: CourseAdmin.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm,v retrieving revision 1.32 retrieving revision 1.33 diff -Llib/WeBWorK/ContentGenerator/CourseAdmin.pm -Llib/WeBWorK/ContentGenerator/CourseAdmin.pm -u -r1.32 -r1.33 --- lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -30,7 +30,7 @@ use File::Temp qw/tempfile/; use WeBWorK::CourseEnvironment; use WeBWorK::Utils qw(cryptPassword writeLog); -use WeBWorK::Utils::CourseManagement qw(addCourse deleteCourse listCourses); +use WeBWorK::Utils::CourseManagement qw(addCourse renameCourse deleteCourse listCourses); use WeBWorK::Utils::DBImportExport qw(dbExport dbImport); # put the following database layouts at the top of the list, in this order @@ -57,10 +57,6 @@ return; } - # get result and send to message - my $status_message = $r->param("status_message"); - $self->addmessage(CGI::p("$status_message")) if $status_message; - ## if the user is asking for the downloaded database... #if (defined $r->param("download_exported_database")) { # my $courseID = $r->param("export_courseID"); @@ -98,6 +94,19 @@ } } + elsif ($subDisplay eq "rename_course") { + if (defined $r->param("rename_course")) { + @errors = $self->rename_course_validate; + if (@errors) { + $method_to_call = "rename_course_form"; + } else { + $method_to_call = "do_rename_course"; + } + } else { + $method_to_call = "rename_course_form"; + } + } + elsif ($subDisplay eq "delete_course") { if (defined $r->param("delete_course")) { # validate or confirm @@ -212,6 +221,8 @@ print CGI::p({style=>"text-align: center"}, CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"add_course"})}, "Add Course"), " | ", + CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"rename_course"})}, "Rename Course"), + " | ", CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"delete_course"})}, "Delete Course"), " | ", CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"export_database"})}, "Export Database"), @@ -656,7 +667,7 @@ if ($add_admin_users ne "") { foreach my $userID ($db->listUsers) { if ($userID eq $add_initial_userID) { - $self->addbadmessage( "User '$userID' will not be copied from admin course as it is the initial instructor."); + warn "User '$userID' will not be copied from admin course as it is the initial instructor."; next; } my $User = $db->getUser($userID); @@ -746,6 +757,256 @@ } +} + +################################################################################ + +sub rename_course_form { + my ($self) = @_; + my $r = $self->r; + my $ce = $r->ce; + #my $db = $r->db; + #my $authz = $r->authz; + #my $urlpath = $r->urlpath; + + my $rename_oldCourseID = $r->param("rename_oldCourseID") || ""; + my $rename_newCourseID = $r->param("rename_newCourseID") || ""; + + my $rename_sql_host = $r->param("rename_sql_host") || ""; + my $rename_sql_port = $r->param("rename_sql_port") || ""; + my $rename_sql_username = $r->param("rename_sql_username") || ""; + my $rename_sql_password = $r->param("rename_sql_password") || ""; + my $rename_sql_oldDatabase = $r->param("rename_sql_oldDatabase") || ""; + my $rename_sql_newDatabase = $r->param("rename_sql_newDatabase") || ""; + my $rename_sql_wwhost = $r->param("rename_sql_wwhost") || ""; + + my @courseIDs = listCourses($ce); + @courseIDs = sort @courseIDs; + + my %courseLabels; # records... heh. + foreach my $courseID (@courseIDs) { + my $tempCE = WeBWorK::CourseEnvironment->new( + $ce->{webworkDirs}->{root}, + $ce->{webworkURLs}->{root}, + $ce->{pg}->{directories}->{root}, + $courseID, + ); + $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")"; + } + + print CGI::h2("Rename Course"); + + print CGI::start_form("POST", $r->uri); + print $self->hidden_authen_fields; + print $self->hidden_fields("subDisplay"); + + print CGI::p("Select a course to rename."); + + print CGI::table({class=>"FormLayout"}, + CGI::Tr( + CGI::th({class=>"LeftHeader"}, "Course Name:"), + CGI::td( + CGI::scrolling_list( + -name => "rename_oldCourseID", + -values => \@courseIDs, + -default => $rename_oldCourseID, + -size => 10, + -multiple => 0, + -labels => \%courseLabels, + ), + ), + ), + CGI::Tr( + CGI::th({class=>"LeftHeader"}, "New Name:"), + CGI::td(CGI::textfield("rename_newCourseID", $rename_newCourseID, 25)), + ), + ); + + print CGI::p( + "If the course's database layout (indicated in parentheses above) is " + . CGI::b("sql") . ", supply the SQL connections information requested below." + ); + + print CGI::start_table({class=>"FormLayout"}); + print CGI::Tr(CGI::td({colspan=>2}, + "Enter the user ID and password for an SQL account with sufficient permissions to create and delete databases." + ) + ); + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"), + CGI::td(CGI::textfield("rename_sql_username", $rename_sql_username, 25)), + ); + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"), + CGI::td(CGI::password_field("rename_sql_password", $rename_sql_password, 25)), + ); + + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "SQL Server Host:"), + CGI::td( + CGI::textfield("rename_sql_host", $rename_sql_host, 25), + CGI::br(), + CGI::small("Leave blank to use the default host."), + ), + ); + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "SQL Server Port:"), + CGI::td( + CGI::textfield("rename_sql_port", $rename_sql_port, 25), + CGI::br(), + CGI::small("Leave blank to use the default port."), + ), + ); + + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "SQL Current Database Name:"), + CGI::td( + CGI::textfield("rename_sql_database", $rename_sql_oldDatabase, 25), + CGI::br(), + CGI::small("Leave blank to use the name ", CGI::tt("webwork_COURSENAME"), "."), + ), + ); + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "SQL New Database Name:"), + CGI::td( + CGI::textfield("rename_sql_database", $rename_sql_newDatabase, 25), + CGI::br(), + CGI::small("Leave blank to use the name ", CGI::tt("webwork_COURSENAME"), "."), + ), + ); + print CGI::Tr( + CGI::th({class=>"LeftHeader"}, "WeBWorK Host:"), + CGI::td( + CGI::textfield("rename_sql_wwhost", $rename_sql_wwhost || "localhost", 25), + CGI::br(), + CGI::small("If the SQL server does not run on the same host as WeBWorK, enter the host name of the WeBWorK server as seen by the SQL server."), + ), + ); + print CGI::end_table(); + + print CGI::p({style=>"text-align: center"}, CGI::submit("rename_course", "Rename Course")); + + print CGI::end_form(); +} + +sub rename_course_validate { + my ($self) = @_; + my $r = $self->r; + my $ce = $r->ce; + #my $db = $r->db; + #my $authz = $r->authz; + #my $urlpath = $r->urlpath; + + my $rename_oldCourseID = $r->param("rename_oldCourseID") || ""; + my $rename_newCourseID = $r->param("rename_newCourseID") || ""; + + my $rename_sql_host = $r->param("rename_sql_host") || ""; + my $rename_sql_port = $r->param("rename_sql_port") || ""; + my $rename_sql_username = $r->param("rename_sql_username") || ""; + my $rename_sql_password = $r->param("rename_sql_password") || ""; + my $rename_sql_oldDatabase = $r->param("rename_sql_oldDatabase") || ""; + my $rename_sql_newDatabase = $r->param("rename_sql_newDatabase") || ""; + my $rename_sql_wwhost = $r->param("rename_sql_wwhost") || ""; + + my @errors; + + if ($rename_oldCourseID eq "") { + push @errors, "You must select a course to rename."; + } + if ($rename_newCourseID eq "") { + push @errors, "You must specify a new name for the course."; + } + if ($rename_oldCourseID eq $rename_newCourseID) { + push @errors, "Can't rename to the same name."; + } + unless ($rename_newCourseID =~ /^[\w-]*$/) { # regex copied from CourseAdministration.pm + push @errors, "Course ID may only contain letters, numbers, hyphens, and underscores."; + } + if (grep { $rename_newCourseID eq $_ } listCourses($ce)) { + push @errors, "A course with ID $rename_newCourseID already exists."; + } + + my $ce2 = WeBWorK::CourseEnvironment->new( + $ce->{webworkDirs}->{root}, + $ce->{webworkURLs}->{root}, + $ce->{pg}->{directories}->{root}, + $rename_oldCourseID, + ); + + if ($ce2->{dbLayoutName} eq "sql") { + push @errors, "You must specify the SQL admin username." if $rename_sql_username eq ""; + #push @errors, "You must specify the SQL admin password." if $rename_sql_password eq ""; + #push @errors, "You must specify the current SQL database name." if $rename_sql_oldDatabase eq ""; + #push @errors, "You must specify the new SQL database name." if $rename_sql_newDatabase eq ""; + } + + return @errors; +} + +sub do_rename_course { + my ($self) = @_; + my $r = $self->r; + my $ce = $r->ce; + my $db = $r->db; + #my $authz = $r->authz; + my $urlpath = $r->urlpath; + + my $rename_oldCourseID = $r->param("rename_oldCourseID") || ""; + my $rename_newCourseID = $r->param("rename_newCourseID") || ""; + + my $rename_sql_host = $r->param("rename_sql_host") || ""; + my $rename_sql_port = $r->param("rename_sql_port") || ""; + my $rename_sql_username = $r->param("rename_sql_username") || ""; + my $rename_sql_password = $r->param("rename_sql_password") || ""; + my $rename_sql_oldDatabase = $r->param("rename_sql_oldDatabase") || ""; + my $rename_sql_newDatabase = $r->param("rename_sql_newDatabase") || ""; + my $rename_sql_wwhost = $r->param("rename_sql_wwhost") || ""; + + my $ce2 = WeBWorK::CourseEnvironment->new( + $ce->{webworkDirs}->{root}, + $ce->{webworkURLs}->{root}, + $ce->{pg}->{directories}->{root}, + $rename_oldCourseID, + ); + + my $dbLayoutName = $ce->{dbLayoutName}; + + my %dbOptions; + if ($dbLayoutName eq "sql") { + $dbOptions{host} = $rename_sql_host if $rename_sql_host ne ""; + $dbOptions{port} = $rename_sql_port if $rename_sql_port ne ""; + $dbOptions{username} = $rename_sql_username; + $dbOptions{password} = $rename_sql_password; + $dbOptions{old_database} = $rename_sql_oldDatabase || "webwork_$rename_oldCourseID"; + $dbOptions{new_database} = $rename_sql_newDatabase || "webwork_$rename_newCourseID"; + $dbOptions{wwhost} = $rename_sql_wwhost; + } + + eval { + renameCourse( + courseID => $rename_oldCourseID, + ce => $ce2, + dbOptions => \%dbOptions, + newCourseID => $rename_newCourseID, + ); + }; + if ($@) { + my $error = $@; + print CGI::div({class=>"ResultsWithError"}, + CGI::p("An error occured while renaming the course $rename_oldCourseID to $rename_newCourseID:"), + CGI::tt(CGI::escapeHTML($error)), + ); + } else { + print CGI::div({class=>"ResultsWithoutError"}, + CGI::p("Successfully renamed the course $rename_oldCourseID to $rename_newCourseID"), + ); + my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", + courseID => $rename_newCourseID); + my $newCourseURL = $self->systemLink($newCoursePath, authen => 0); + print CGI::div({style=>"text-align: center"}, + CGI::a({href=>$newCourseURL}, "Log into $rename_newCourseID"), + ); + } } ################################################################################ Index: CourseManagement.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Utils/CourseManagement.pm,v retrieving revision 1.20 retrieving revision 1.21 diff -Llib/WeBWorK/Utils/CourseManagement.pm -Llib/WeBWorK/Utils/CourseManagement.pm -u -r1.20 -r1.21 --- lib/WeBWorK/Utils/CourseManagement.pm +++ lib/WeBWorK/Utils/CourseManagement.pm @@ -233,15 +233,45 @@ } -=item renameCourse($webworkRoot, $oldCourseID, $newCourseID) +=item renameCourse(%options) -Rename the course named $oldCourseID to $newCourseID. +%options must contain: -The name course directory is set to $newCourseID. + courseID => $courseID, + ce => $ce, + dbOptions => $dbOptions, + newCourseID => $newCourseID, + +Rename the course named $courseID to $newCourseID. + +$ce is a WeBWorK::CourseEnvironment object that describes the existing course's +environment. + +$dbOptions is a reference to a hash containing information required to create +the course's new database and delete the course's old database. + + if dbLayout == "sql": + + host => host to connect to + port => port to connect to + username => user to connect as (must have CREATE, DELETE, FILE, INSERT, + SELECT, UPDATE privileges, WITH GRANT OPTION.) + password => password to supply + old_database => the name of the database to delete + new_database => the name of the database to create + wwhost => the host from which the webwork database users will be allowed + to connect. (if host is set to localhost, this should be set to + localhost too.) + +The name of the course's directory is changed to $newCourseID. + +If the course's database layout is C<sql_single>, new tables are created in the +current database, course data is copied from the old tables to the new tables, +and the old tables are deleted. If the course's database layout is C<sql>, a new database is created, course -data is exported from the old database and imported into the new database, and -the old database is deleted. +data is copied from the old database to the new database, and the old database +is deleted. If the course's database layout is C<gdbm>, the DBM files are simply renamed on disk. @@ -253,9 +283,108 @@ =cut sub renameCourse { - my ($webworkRoot, $oldCourseID, $newCourseID) = @_; + my (%options) = @_; + + # renameCourseHelper needs: + # $fromCourseID ($oldCourseID) + # $fromCE ($oldCE) + # $toCourseID ($newCourseID) + # $toCE (construct from $oldCE) + # $dbLayoutName ($oldCE->{dbLayoutName}) + # %options ($dbOptions) + + my $oldCourseID = $options{courseID}; + my $oldCE = $options{ce}; + my %dbOptions = defined $options{dbOptions} ? %{ $options{dbOptions} } : (); + my $newCourseID = $options{newCourseID}; + + # get the database layout out of the options hash + my $dbLayoutName = $oldCE->{dbLayoutName}; + + die "I happen to know that renameCourse() will only succeed for sql_single courses. Bug sam to write support for gdbm and sql courses.\n" + unless $dbLayoutName eq "sql_single"; + + # collect some data + my $coursesDir = $oldCE->{webworkDirs}->{courses}; + my $oldCourseDir = "$coursesDir/$oldCourseID"; + my $newCourseDir = "$coursesDir/$newCourseID"; + + # fail if the target course already exists + if (-e $newCourseDir) { + croak "$newCourseID: course exists"; + } + + # fail if the source course does not exist + unless (-e $oldCourseDir) { + croak "$oldCourseID: course not found"; + } + + ##### step 1: move course directory ##### - return 0; + # move top-level course directory + my $mvCmd = $oldCE->{externalPrograms}->{mv}; + debug("moving course dir: $mvCmd $oldCourseDir $newCourseDir\n"); + my $mvResult = system $mvCmd, $oldCourseDir, $newCourseDir; + $mvResult and die "failed to move course directory with command: '$mvCmd $oldCourseDir $newCourseDir' (errno: $mvResult): $!\n"; + + # get new course environment + my $newCE = $oldCE->new( + $oldCE->{webworkDirs}->{root}, + $oldCE->{webworkURLs}->{root}, + $oldCE->{pg}->{directories}->{root}, + $newCourseID, + ); + + # find the course dirs that still exist in their original locations + # (i.e. are not subdirs of $courseDir) + my %oldCourseDirs = %{ $oldCE->{courseDirs} }; + my %newCourseDirs = %{ $newCE->{courseDirs} }; + my @courseDirNames = sort { $oldCourseDirs{$a} cmp $oldCourseDirs{$b} } keys %oldCourseDirs; + foreach my $courseDirName (@courseDirNames) { + my $oldDir = $oldCourseDirs{$courseDirName}; + my $newDir = $newCourseDirs{$courseDirName}; + if (-e $oldDir) { + debug("oldDir $oldDir still exists. might move it...\n"); + if (-e $newDir) { + warn "Can't move '$oldDir' to '$newDir', since the target already exists"; + } else { + debug("Going to move $oldDir to $newDir...\n"); + my $mvResult = system $mvCmd, $oldDir, $newDir; + $mvResult and die "failed to move directory with command: '$mvCmd $oldDir $newDir' (errno: $mvResult): $!\n"; + } + } else { + debug("oldDir $oldDir was already moved.\n"); + } + } + + ##### step 2: create new database ##### + + # munge DB options to move new_database => database + my %createDBOptions = %dbOptions; + if (exists $createDBOptions{new_database}) { + $createDBOptions{database} = $createDBOptions{new_database}; + delete $createDBOptions{new_database}; + } + + my $createHelperResult = addCourseHelper($oldCourseID, $newCE, $dbLayoutName, %dbOptions); + die "$oldCourseID: course database creation failed.\n" unless $createHelperResult; + + ##### step 3: copy course data ##### + + my $copyCourseDataResult = copyCourseDataHelper($oldCourseID, $oldCE, $newCourseID, $newCE, $dbLayoutName, %dbOptions); + die "$oldCourseID: failed to copy course data from $oldCourseID to $newCourseID.\n" unless $copyCourseDataResult; + + ##### step 4: delete old database ##### + + # munge DB options to move old_database => database + my %deleteDBOptions = %dbOptions; + if (exists $deleteDBOptions{old_database}) { + $deleteDBOptions{database} = $deleteDBOptions{old_database}; + delete $deleteDBOptions{old_database}; + } + + my $deleteHelperResult = deleteCourseHelper($oldCourseID, $newCE, $dbLayoutName, %dbOptions); + die "$oldCourseID: course database creation failed.\n" unless $deleteHelperResult; } =item deleteCourse(%options) @@ -282,7 +411,7 @@ username => user to connect as (must have CREATE, DELETE, FILE, INSERT, SELECT, UPDATE privileges, WITH GRANT OPTION.) password => password to supply - database => the name of the database to create + database => the name of the database to delete Deletes the course named $courseID. The course directory is removed. @@ -392,11 +521,9 @@ =head1 DATABASE-LAYOUT SPECIFIC HELPER FUNCTIONS -The addCourseHelper(), renameCourseHelper(), and deleteCourseHelper() functions -are used by addCourse(), renameCourse(), and deleteCourse() to perform -database-layout specific operations, such as creating a database. They are -called after the course directory structure has been created, but before the -database is initialized. +The addCourseHelper(), copyCourseDataHelper(), and deleteCourseHelper() +functions are used to perform database-layout specific operations, such as +creating a database. The implementations in this class do nothing, but if an appropriate function exists in a class with the name @@ -411,18 +538,21 @@ =cut sub addCourseHelper { - my $result = callHelperIfExists("addCourseHelper", @_); + my ($courseID, $ce, $dbLayoutName, %options) = @_; + my $result = callHelperIfExists("addCourseHelper", $dbLayoutName, @_); return $result; } -=item renameCourseHelper($oldCourseID, $newCourseID, $ce, $dbLayoutName, %options) +=item copyCourseDataHelper($fromCourseID, $fromCE, $toCourseID, $toCE, $dbLayoutName, %options) -Perform database-layout specific operations for renaming a course. +Perform database-layout specific operations for copying a course's data from one +database to another. =cut -sub renameCourseHelper { - return callHelperIfExists("renameCourseHelper", @_); +sub copyCourseDataHelper { + my ($fromCourseID, $fromCE, $toCourseID, $toCE, $dbLayoutName, %options) = @_; + return callHelperIfExists("copyCourseDataHelper", $dbLayoutName, @_); } =item deleteCourseHelper($courseID, $ce, $dbLayoutName, %options) @@ -432,7 +562,8 @@ =cut sub deleteCourseHelper { - return callHelperIfExists("deleteCourseHelper", @_); + my ($courseID, $ce, $dbLayoutName, %options) = @_; + return callHelperIfExists("deleteCourseHelper", $dbLayoutName, @_); } =back @@ -448,7 +579,7 @@ =over -=item callHelperIfExists($helperName, $args) +=item callHelperIfExists($helperName, $dbLayoutName, @args) Call a database-specific helper function, if a database-layout specific helper class exists and contains a function named "${helperName}Helper". @@ -456,8 +587,7 @@ =cut sub callHelperIfExists { - my $helperName = shift; - my ($courseID, $ce, $dbLayoutName, %options) = @_; + my ($helperName, $dbLayoutName, @args) = @_; my $result; @@ -476,7 +606,7 @@ my %syms = do { no strict 'refs'; %{$package."::"} }; if (exists $syms{$helperName}) { my $func = do { no strict 'refs'; \&{$package."::".$helperName} }; - $result = $func->(@_); + $result = $func->(@args); } else { #warn "No helper defined for operation '$helperName'.\n"; $result = 1; Index: sql_single.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Utils/CourseManagement/sql_single.pm,v retrieving revision 1.3 retrieving revision 1.4 diff -Llib/WeBWorK/Utils/CourseManagement/sql_single.pm -Llib/WeBWorK/Utils/CourseManagement/sql_single.pm -u -r1.3 -r1.4 --- lib/WeBWorK/Utils/CourseManagement/sql_single.pm +++ lib/WeBWorK/Utils/CourseManagement/sql_single.pm @@ -25,9 +25,11 @@ use strict; use warnings; +use Data::Dumper; use DBI; use WeBWorK::Debug; use WeBWorK::Utils qw(runtime_use undefstr); +use WeBWorK::Utils::CourseManagement qw/dbLayoutSQLSources/; =head1 HELPER FUNCTIONS @@ -160,6 +162,148 @@ } $dbh->disconnect; + + return 1; +} + +=item renameCourseHelper($fromCourseID, $fromCE, $toCourseID, $toCE, $dbLayoutName, %options) + +Uses addCourseHelper() to create a new course database on the same server. +Copies the data from the old course database to the new one. Uses +deleteCourseHelper() to delete the old course database. + +=cut + +sub copyCourseDataHelper { + my ($fromCourseID, $fromCE, $toCourseID, $toCE, $dbLayoutName, %options) = @_; + debug("fromCourseID=$fromCourseID, fromCE=$fromCE toCourseID=$toCourseID toCE=$toCE dbLayoutName=$dbLayoutName\n"); + + ##### get list of tables to copy data FROM ##### + + my $fromDBLayout = $fromCE->{dbLayouts}->{$dbLayoutName}; + debug("fromDBLayout=$fromDBLayout\n"); + my %fromSources = dbLayoutSQLSources($fromDBLayout); + debug("fromSources: ", Dumper(\%fromSources)); + my $fromSource = mostPopularSource(%fromSources); + debug("fromSource=$fromSource\n"); + my %fromSource = %{ $fromSources{$fromSource} }; + my @fromTables = @{ $fromSource{tables} }; + my $fromUsername = $fromSource{username}; + my $fromPassword = $fromSource{password}; + + ##### get list of tables to copy data TO ##### + + my $toDBLayout = $toCE->{dbLayouts}->{$dbLayoutName}; + my %toSources = dbLayoutSQLSources($toDBLayout); + my $toSource = mostPopularSource(%toSources); + my %toSource = %{ $toSources{$toSource} }; + my @toTables = @{ $toSource{tables} }; + my $toUsername = $toSource{username}; + my $toPassword = $toSource{password}; + + ##### make sure the same tables are present in each list ##### + + my %fromTables; @fromTables{@fromTables} = (); + + foreach my $toTable (@toTables) { + if (exists $fromTables{$toTable}) { + # present in both + delete $fromTables{$toTable}; + } else { + die "Table '$toTable' exists in \@toTables but not in \@fromTables. Can't continue"; + } + } + + if (keys %fromTables) { + my @leftovers = keys %fromTables; + die "Tables '@leftovers' exist in \@fromTables but not in \@toTables. Can't continue"; + } + + if ($fromUsername ne $toUsername) { + die "Usernames for from/to sources don't match. Can't continue"; + } + + if ($fromPassword ne $toPassword) { + die "Passwords for from/to sources don't match. Can't continue"; + } + + ##### consruct SQL statements to copy the data in each table ##### + + my @stmts; + + foreach my $table (@fromTables) { + debug("Table: $table\n"); + my $fromTable = do { + my $fromParamsRef = $fromDBLayout->{$table}->{params}; + if ($fromParamsRef) { + if (exists $fromParamsRef->{tableOverride}) { + $fromParamsRef->{tableOverride} + } else { + ""; # no override + } + } else { + ""; # no params + } + } || $table; + debug("sql \"from\" table name: $fromTable\n"); + + my $toTable = do { + my $toParamsRef = $toDBLayout->{$table}->{params}; + if ($toParamsRef) { + if (exists $toParamsRef->{tableOverride}) { + $toParamsRef->{tableOverride}; + } else { + ""; # no override + } + } else { + ""; # no params + } + } || $table; + debug("sql \"to\" table name: $toTable\n"); + + my $stmt = "INSERT INTO `$toTable` SELECT * FROM `$fromTable`"; + debug("stmt = $stmt\n"); + push @stmts, $stmt; + } + + ##### issue SQL statements ##### + + my $dbh = DBI->connect($fromSource, $fromUsername, $fromPassword); + unless (defined $dbh) { + die "sql_single: failed to connect to DBI source '$fromSource': $DBI::errstr\n"; + } + + foreach my $stmt (@stmts) { + my $rows = $dbh->do($stmt); + unless (defined $rows) { + die "sql_single: failed to execute SQL statement '$stmt': $DBI::errstr\n"; + } + } + + $dbh->disconnect; + + return 1; +} + +# returns the name of the source with the most tables +sub mostPopularSource { + my (%sources) = @_; + + my $source; + if (keys %sources > 1) { + # more than one -- warn and select the most popular source + debug("more than one SQL source defined.\n"); + foreach my $curr (keys %sources) { + $source = $curr if not defined $source or @{ $sources{$curr}->{tables} } > @{ $sources{$source}->{tables} }; + } + debug("only handling tables with source \"$source\".\n"); + debug("others will have to be handled manually (or not at all).\n"); + } else { + # there's only one + ($source) = keys %sources; + } + + return $source; } =item deleteCourseHelper($courseID, $ce, $dbLayoutName, %options) @@ -270,6 +414,8 @@ } $dbh->disconnect; + + return 1; } =back |
From: Sam H. v. a. <act...@de...> - 2004-12-20 21:23:19
|
Log Message: ----------- expansion of Mike's caching fixes. see below: * separate setCachedUser($userID) method allows explicit setting of user to cache. This is needed because $r->param("user") is not always set (i.e. in the case of the initial request for a guest login. * don't store a copy of a reference to %permissionLevels, as this isn't any more efficient than accessing the course environment directly. * always construct the Authz instance. * fall back on accessing the database if hasPermissions() is called with a user other than the cached user (or if no user is cached). * warning output (and assume no permission) if PermissionLevel record doesn't exist or permission level is empty. * warn (and assume no permission) if activity is not found in the %permissionLevels hash. * don't pass $ce and $db to new(), since they are available in $r. Modified Files: -------------- webwork2/lib/WeBWorK: Authz.pm webwork2/lib: WeBWorK.pm Revision Data ------------- Index: Authz.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Authz.pm,v retrieving revision 1.18 retrieving revision 1.19 diff -Llib/WeBWorK/Authz.pm -Llib/WeBWorK/Authz.pm -u -r1.18 -r1.19 --- lib/WeBWorK/Authz.pm +++ lib/WeBWorK/Authz.pm @@ -20,52 +20,184 @@ WeBWorK::Authz - check user permissions. +=head1 SYNOPSIS + + # create new authorizer -- $r is a WeBWorK::Request object. + my $authz = new WeBWorK::Authz($r); + + # tell authorizer to cache permission level of user spammy. + $authz->setCachedUser("spammy"); + + # this call will use the cached data. + if ($authz->hasPermissions("spammy", "eat_breakfast")) { + eat_breakfast(); + } + + # this call will not use the cached data, and will cause a database lookup. + if ($authz->hasPermissions("hammy", "go_to_bed")) { + go_to_bed(); + } + +=head1 DESCRIPTION + +WeBWorK::Authen determines if a user is authorized to perform a specific +activity, based on the user's PermissionLevel record in the WeBWorK database and +the contents of the %permissionLevels hash in the course environment. + +=head2 Format of the %permissionLevels hash + +%permissionLevels maps text strings describing activities to numeric permission +levels. The definitive list of activities is contained in the default version of +%permissionLevels, in the file F<conf/global.conf.dist>. + +A user is able to engage in an activity if their permission level is greater +than or equal to the level associated with the activity. If the level associated +with an activity is undefiend, then no user is permitted to perform the +activity, regardless of their permission level. + =cut use strict; use warnings; +################################################################################ + +=head1 CONSTRUCTOR + +=over + +=item WeBWorK::Authz->new($r) + +Creates a new authorizer instance. $r is a WeBWorK::Request object. It must +already have its C<ce> and C<db> fields set. + +=cut sub new { - my ($invocant, $r, $ce, $db) = @_; + my ($invocant, $r) = @_; my $class = ref($invocant) || $invocant; my $self = { r => $r, }; - my $user = $r->param("user"); - return 0 unless defined($user); - my $Permission = $db->getPermissionLevel($user); # checked - return 0 unless defined $Permission; - my $permissionLevel = $Permission->permission(); - return 0 unless defined $permissionLevel and $permissionLevel ne ""; - - my $permissionLevels = $ce->{permissionLevels}; - $self->{permissionLevels} = $permissionLevels; - $self->{permissionLevel} = $permissionLevel; bless $self, $class; return $self; } -# This module assumes that neither the permissionLevels nor the permissionLevel -# changes between the time an authz module is created and the time it's used. +=back + +=cut + +################################################################################ + +=head1 METHODS + +=over + +=item setCachedUser($userID) + +Caches the PermissionLevel of the user $userID in an existing authorizer. If a +user's PermissionLevel is cached, it will be used whenever hasPermissions() is +called on the same user. Only one user can be cached at a time. This is used by +WeBWorK to cache the "real" user. + +=cut + +sub setCachedUser { + my ($self, $userID) = @_; + my $r = $self->{r}; + my $db = $r->db; + + delete $self->{userID}; + delete $self->{PermissionLevel}; + + if (defined $userID) { + $self->{userID} = $userID; + my $PermissionLevel = $db->getPermissionLevel($userID); # checked + if (defined $PermissionLevel) { + # store permission level record in database to avoid later database calls + $self->{PermissionLevel} = $PermissionLevel; + } + } else { + warn "setCachedUser() called with userID undefined.\n"; + } +} + +=item hasPermissions($userID, $activity) + +Checks the %permissionLevels hash in the course environment to determine if the +user $userID has permission to engage in the activity $activity. If the user's +permission level is greater than or equal to the level associated with $activty, +a true value is returned. Otherwise, a false value is returned. + +If $userID has been cached using the setCachedUser() call, the cached data is +used. Otherwise, the user's PermissionLevel is looked up in the WeBWorK +database. + +If the user does not have a PermissionLevel record, the permission level record +is empty, or the activity does not appear in %permissionLevels, hasPermissions() +assumes that the user does not have permission. + +=cut # This currently only uses two of it's arguments, but it accepts any number, in # case in the future calculating certain permissions requires more information. sub hasPermissions { - my ($self, $user, $activity) = @_; - my $permissionLevels = $self->{permissionLevels}; - my $permissionLevel = $self->{permissionLevel}; + my ($self, $userID, $activity) = @_; + my $r = $self->{r}; + my $ce = $r->ce; + my $db = $r->db; + + my $PermissionLevel; + + my $cachedUserID = $self->{userID}; + if (defined $cachedUserID and $cachedUserID ne "" and $cachedUserID eq $userID) { + # this is the same user -- we can skip the database call + $PermissionLevel = $self->{PermissionLevel}; + } else { + # a different user, or no user was defined before + my $prettyCachedUserID = defined $cachedUserID ? "'$cachedUserID'" : "undefined"; + #warn "hasPermissions called with user '$userID', but cached user is $prettyCachedUserID. Accessing database.\n"; + $PermissionLevel = $db->getPermissionLevel($userID); # checked + } + + my $permission_level; + + if (defined $PermissionLevel) { + $permission_level = $PermissionLevel->permission; + } else { + # uh, oh. this user has no permission level record! + warn "User '$userID' has no PermissionLevel record -- assuming no permission.\n"; + return 0; + } + + unless (defined $permission_level and $permission_level ne "") { + warn "User '$userID' has empty permission level -- assuming no permission.\n"; + return 0; + } + + my $permissionLevels = $ce->{permissionLevels}; if (exists $permissionLevels->{$activity}) { if (defined $permissionLevels->{$activity}) { - return $permissionLevel >= $permissionLevels->{$activity}; + return $permission_level >= $permissionLevels->{$activity}; } else { - return 0; + return 0; # nobody has permission to do this } } else { - die "Activity '$activity' not found in %permissionLevels. Can't continue.\n"; + warn "Activity '$activity' not found in %permissionLevels -- assuming no permission.\n"; + return 0; } - } + +=back + +=cut + +=head1 AUTHOR + +Written by Dennis Lambe, malsyned at math.rochester.edu. Modified by Sam +Hathaway, sh002i at math.rochester.edu. + +=cut 1; Index: WeBWorK.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK.pm,v retrieving revision 1.69 retrieving revision 1.70 diff -Llib/WeBWorK.pm -Llib/WeBWorK.pm -u -r1.69 -r1.70 --- lib/WeBWorK.pm +++ lib/WeBWorK.pm @@ -224,7 +224,7 @@ } debug("Create an authz object (Authen needs it to check login permission)...\n"); - $authz = new WeBWorK::Authz($r, $ce, $db); + $authz = new WeBWorK::Authz($r); debug("(here's the authz object: $authz)\n"); $r->authz($authz); @@ -234,6 +234,9 @@ if ($authenOK) { my $userID = $r->param("user"); debug("Hi, $userID, glad you made it.\n"); + + # tell authorizer to cache this user's permission level + $authz->setCachedUser($userID); debug("Now we deal with the effective user:\n"); my $eUserID = $r->param("effectiveUser") || $userID; |
From: Mike G. v. a. <act...@de...> - 2004-12-20 16:36:33
|
Log Message: ----------- Fixed double declaration of $user Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor: Assigner.pm Revision Data ------------- Index: Assigner.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/Assigner.pm,v retrieving revision 1.26 retrieving revision 1.27 diff -Llib/WeBWorK/ContentGenerator/Instructor/Assigner.pm -Llib/WeBWorK/ContentGenerator/Instructor/Assigner.pm -u -r1.26 -r1.27 --- lib/WeBWorK/ContentGenerator/Instructor/Assigner.pm +++ lib/WeBWorK/ContentGenerator/Instructor/Assigner.pm @@ -64,7 +64,7 @@ my @Users = $db->getUsers(@userIDs); ## Mark's Edits for filtering my @myUsers; - my $user = $r->param("user"); + my (@viewable_sections, @viewable_recitations); |
From: Sam H. v. a. <act...@de...> - 2004-12-20 15:39:02
|
Log Message: ----------- escaped hyphen in r.e. to avoid interpretation as range operator. Modified Files: -------------- webwork2/lib/WeBWorK: DB.pm Revision Data ------------- Index: DB.pm =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB.pm,v retrieving revision 1.61 retrieving revision 1.62 diff -Llib/WeBWorK/DB.pm -Llib/WeBWorK/DB.pm -u -r1.61 -r1.62 --- lib/WeBWorK/DB.pm +++ lib/WeBWorK/DB.pm @@ -343,7 +343,7 @@ $self->{set_user}->{driver}->connect("ro") or return 0, @results, "Failed to connect to set_user database."; =09 - # get PSVNs for global user (=95N) + # get PSVNs for global user (=EFN) # this reads from "login<>global_user" my @globalUserPSVNs =3D $self->{set_user}->getPSVNsForUser($globalUser= ID); #warn "found ", scalar @globalUserPSVNs, " PSVNs for the global user.\= n"; @@ -358,7 +358,7 @@ #warn "got setID '$setID'\n"; } =09 - # get PSVNs for each setID (=95N*M) + # get PSVNs for each setID (=EFN*M) # this reads from "set<>$_" my @okPSVNs =3D map { $self->{set_user}->getPSVNsForSet($_) } @globalU= serSetIDs; #warn "found ", scalar @okPSVNs, " PSVNs for sets assigned to the glob= al user.\n"; @@ -1971,7 +1971,7 @@ unless $value =3D~ m/^\d*$/; } else { croak "checkKeyfields: invalid characters in $keyfield field: $value = (valid characters are [A-Za-z0-9_.])" - unless $value =3D~ m/^[.\w-]*$/; + unless $value =3D~ m/^[.\w\-]*$/; } } } |
From: Mike G. v. a. <act...@de...> - 2004-12-19 22:56:15
|
Log Message: ----------- Fixed small bug in the message passing facility Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator: Problem.pm Revision Data ------------- Index: Problem.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Problem.pm,v retrieving revision 1.169 retrieving revision 1.170 diff -Llib/WeBWorK/ContentGenerator/Problem.pm -Llib/WeBWorK/ContentGenerator/Problem.pm -u -r1.169 -r1.170 --- lib/WeBWorK/ContentGenerator/Problem.pm +++ lib/WeBWorK/ContentGenerator/Problem.pm @@ -472,12 +472,8 @@ $self->{formFields} = $formFields; # get result and send to message -# my $success = $r->param("success"); -# my $failure = $r->param("failure"); my $status_message = $r->param("status_message"); -# $self->addbadmessage(CGI::p($failure)) if $failure; -# $self->addgoodmessage(CGI::p($success)) if $success; - $self->addgoodmessage(CGI::p("$status_message")) if $status_message; + $self->addmessage(CGI::p("$status_message")) if $status_message; # now that we've set all the necessary variables quit out if the set or problem is invalid return if $self->{invalidSet} || $self->{invalidProblem}; |
From: Mike G. v. a. <act...@de...> - 2004-12-19 22:54:43
|
Log Message: ----------- Changed message passing when there is a duplicate administrator. use addbadmessage() facility instead of warn Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator: CourseAdmin.pm Revision Data ------------- Index: CourseAdmin.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm,v retrieving revision 1.31 retrieving revision 1.32 diff -Llib/WeBWorK/ContentGenerator/CourseAdmin.pm -Llib/WeBWorK/ContentGenerator/CourseAdmin.pm -u -r1.31 -r1.32 --- lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -57,6 +57,10 @@ return; } + # get result and send to message + my $status_message = $r->param("status_message"); + $self->addmessage(CGI::p("$status_message")) if $status_message; + ## if the user is asking for the downloaded database... #if (defined $r->param("download_exported_database")) { # my $courseID = $r->param("export_courseID"); @@ -652,7 +656,7 @@ if ($add_admin_users ne "") { foreach my $userID ($db->listUsers) { if ($userID eq $add_initial_userID) { - warn "User '$userID' will not be copied from admin course as it is the initial instructor."; + $self->addbadmessage( "User '$userID' will not be copied from admin course as it is the initial instructor."); next; } my $User = $db->getUser($userID); |
From: Mike G. v. a. <act...@de...> - 2004-12-19 22:23:24
|
Log Message: ----------- The permission levels are now checked when the authz instance is created. This reduces the number of calls to the database. It could cause trouble if there is a change in permission status between the time when the instance is created and when it is used. Since this all occurs while rendering one webpage, I don't think that this time difference will ever cause trouble. -- Mike Modified Files: -------------- webwork-modperl/lib/WeBWorK: Authz.pm Revision Data ------------- Index: Authz.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/Authz.pm,v retrieving revision 1.17 retrieving revision 1.18 diff -Llib/WeBWorK/Authz.pm -Llib/WeBWorK/Authz.pm -u -r1.17 -r1.18 --- lib/WeBWorK/Authz.pm +++ lib/WeBWorK/Authz.pm @@ -25,30 +25,37 @@ use strict; use warnings; + sub new { - my ($invocant, $r) = @_; + my ($invocant, $r, $ce, $db) = @_; my $class = ref($invocant) || $invocant; my $self = { r => $r, }; + + my $user = $r->param("user"); + return 0 unless defined($user); + my $Permission = $db->getPermissionLevel($user); # checked + return 0 unless defined $Permission; + my $permissionLevel = $Permission->permission(); + return 0 unless defined $permissionLevel and $permissionLevel ne ""; + + my $permissionLevels = $ce->{permissionLevels}; + $self->{permissionLevels} = $permissionLevels; + $self->{permissionLevel} = $permissionLevel; bless $self, $class; return $self; } +# This module assumes that neither the permissionLevels nor the permissionLevel +# changes between the time an authz module is created and the time it's used. + # This currently only uses two of it's arguments, but it accepts any number, in # case in the future calculating certain permissions requires more information. sub hasPermissions { my ($self, $user, $activity) = @_; - my $r = $self->{r}; - my $ce = $r->ce; - my $db = $r->db; - - my $Permission = $db->getPermissionLevel($user); # checked - return 0 unless defined $Permission; - my $permissionLevel = $Permission->permission(); - return 0 unless defined $permissionLevel and $permissionLevel ne ""; - - my $permissionLevels = $ce->{permissionLevels}; + my $permissionLevels = $self->{permissionLevels}; + my $permissionLevel = $self->{permissionLevel}; if (exists $permissionLevels->{$activity}) { if (defined $permissionLevels->{$activity}) { return $permissionLevel >= $permissionLevels->{$activity}; @@ -58,6 +65,7 @@ } else { die "Activity '$activity' not found in %permissionLevels. Can't continue.\n"; } + } 1; |