From 0fc67ba23c36d383ee56e7b95ece3a0ee5752f7a Mon Sep 17 00:00:00 2001 From: "William H. Wheeler" Date: Thu, 9 Aug 2012 20:22:45 -0400 Subject: [PATCH 01/27] (1) This update comments out the line in Logout.pm that transmits the username to Login.pm if the "Log in Again" button is pressed. This change is needed to suppress an error message in the Login screen that would appear if Login.pm is sent a username but no other credentials. (2) This update adds documentation to authen_LTI.conf.dist that was lost when authen_LTI.conf.dist was created, probably due to an out-of-date version of global.conf having been used to create authen_LTI.conf.dist. --- conf/authen_LTI.conf.dist | 17 +++++++++++++++++ lib/WeBWorK/ContentGenerator/Logout.pm | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/conf/authen_LTI.conf.dist b/conf/authen_LTI.conf.dist index 1a72e285f2..011d92efdd 100644 --- a/conf/authen_LTI.conf.dist +++ b/conf/authen_LTI.conf.dist @@ -23,6 +23,23 @@ $authen{user_module} = [ #module but the sequence includes an internal authentication #system, e.g., Basic_TheLastOption, then the following line #must be uncommented for use by WeBWorK::Logout. +# If it is uncommented and the value = 1, +# then, if the authentication sequence reaches +# Basic_TheLastOption, then WeBWorK::Login +# will display a screen directing the user +# back to an external authentication system. +# On the other hand, if the value = 0 or +# the line is commented out, then WeBWorK::Login +# will display the traditional passwork login screen. +# Upon logging out, if the line is not commented out +# and the value = 1, then the Logout screen will NOT +# show a "Login Again" button and will display +# a message directing the user to go to the +# external authentication system. +# On the other hand, if the line is commented out +# or if the value = 0, then the Logout screen WILL +# display a "Login Again" button that will take +# the user to a pasword login screen. #$external_auth=1; diff --git a/lib/WeBWorK/ContentGenerator/Logout.pm b/lib/WeBWorK/ContentGenerator/Logout.pm index 035571e241..2a686c123b 100644 --- a/lib/WeBWorK/ContentGenerator/Logout.pm +++ b/lib/WeBWorK/ContentGenerator/Logout.pm @@ -158,7 +158,7 @@ sub body { "authentication system. Please go there to login again."); } else { print CGI::start_form(-method=>"POST", -action=>$loginURL); - print CGI::hidden("user", $userID); + # print CGI::hidden("user", $userID); ### Line Commented out to suppress error message when this button is used. WHW print CGI::hidden("force_passwd_authen", 1); print CGI::p({align=>"center"}, CGI::submit(-name=>"submit", -label=>$r->maketext("Log In Again"))); print CGI::end_form(); From 58d06493ca8a8de1185af0b1339ec27104d7164c Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sat, 8 Sep 2012 18:50:04 -0400 Subject: [PATCH 02/27] Replace include() by require(). Include() is not defined in this context. --- bin/OPL-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/OPL-update b/bin/OPL-update index 11e05bd494..d8a0aedb01 100755 --- a/bin/OPL-update +++ b/bin/OPL-update @@ -99,7 +99,7 @@ sub dbug { my %tables; if( -e "$libraryRoot/VERSION") { - include("$libraryRoot/VERSION"); + require("$libraryRoot/VERSION"); if($OPL_VERSION eq '2.5.0') { %tables = %OPLtables; my $lib = 'OPL'; From 432be72dc98b8a680f7e3f4c650b20cee3a030f0 Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sun, 9 Sep 2012 13:12:40 -0400 Subject: [PATCH 03/27] Allow admin course data tables and directories to be updated This gets rid of strange errors which occur for example when you try to delete a user in the admin classlist directory. The delete command tries to delete tables and fields that don't exist --- lib/WeBWorK/ContentGenerator/CourseAdmin.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm index b64cebbd32..9d90e215d1 100644 --- a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -2163,7 +2163,7 @@ sub upgrade_course_form { print $self->hidden_fields("subDisplay"); foreach my $courseID ( @courseIDs) { - next if $courseID eq "admin"; # done already above + #next if $courseID eq "admin"; # done already above # on second thought even admin courses have to upgrade. next if $courseID eq "modelCourse"; # modelCourse isn't a real course so don't create missing directories, etc next unless $courseID =~/\S/; # skip empty courseIDs (there shouldn't be any my $urlpath = $r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", $r, courseID => $courseID); From ee91f7178357146a0e05eb049c81f5ecd1037704 Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sun, 9 Sep 2012 16:00:45 -0400 Subject: [PATCH 04/27] Automatically create achievements directories. If defaults.config file does not have listings for the achievement directores then nothing happens. All of these upgrade checks are skipped. Check that modelCourses has the templates/achievements and html/achievements directories. If not then modelCourses needs to be updated first -- issue a message to that effect. If the course is missing either the templates/directory or the html/achievements directory then create it from the corresponding directory in modelCourse. --- conf/defaults.config | 1 + lib/WeBWorK/Utils/CourseIntegrityCheck.pm | 34 +++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/conf/defaults.config b/conf/defaults.config index e36eb7640c..8529016d28 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -275,6 +275,7 @@ $courseDirs{templates} = "$courseDirs{root}/templates"; # Location of course achievement files. $courseDirs{achievements} = "$courseDirs{templates}/achievements"; +$courseDirs{achievements_html} = "$courseDirs{html}/achievements"; #contains badge icons $courseURLs{achievements} = "$courseURLs{html}/achievements"; # Location of course-specific macro files. diff --git a/lib/WeBWorK/Utils/CourseIntegrityCheck.pm b/lib/WeBWorK/Utils/CourseIntegrityCheck.pm index 7bc51586b7..e6428e6bfa 100644 --- a/lib/WeBWorK/Utils/CourseIntegrityCheck.pm +++ b/lib/WeBWorK/Utils/CourseIntegrityCheck.pm @@ -333,10 +333,40 @@ sub updateCourseDirectories { my $ce = $self->{ce}; my @webworkDirectories = keys %{$ce->{webworkDirs}}; my @courseDirectories = keys %{$ce->{courseDirs}}; - my %updateable_directories = (html_temp=>1,mailmerge=>1,tmpEditFileDir=>1); #FIXME this is hardwired for the time being. - foreach my $dir (sort @courseDirectories) { + #HACK for upgrading the achievements directory + if ($dir eq "achievements") { + my $modelCourseAchievementsDir = $ce->{webworkDirs}{courses}."/modelCourse/templates/achievements"; + my $modelCourseAchievementsHtmlDir = $ce->{webworkDirs}{courses}."/modelCourse/html/achievements"; + my $courseAchievementsDir = $ce->{courseDirs}{achievements}; + my $courseAchievementsHtmlDir = $ce->{courseDirs}{achievements_html}; + my $courseTemplatesDir = $ce->{courseDirs}{templates}; + my $courseHtmlDir = $ce->{courseDirs}{html}; + unless (-e $modelCourseAchievementsDir and -e $modelCourseAchievementsHtmlDir ) { + print CGI::p( {style=>"color:red"},"Your modelCourse in the 'courses' directory is out of date or missing. + Please update it from webwork/webwork2/courses.dist directory before upgrading the other courses."); + } else { + unless (-e $courseAchievementsDir and -e $courseAchievementsHtmlDir ) { + print CGI::p( {style=>"color:green"},"we'll try to update the achievements + directory for ".$ce->{courseDirs}{root}); + if (-e $courseAchievementsDir) { + print CGI::p({style=>"color:green"}, "Achievements directory is already present"); + } else { + system "cp -RPpi $modelCourseAchievementsDir $courseTemplatesDir "; + print CGI::p({style=>"color:green"}, "Achievements directory created"); + } + if (-e $courseAchievementsHtmlDir) { + print CGI::p({style=>"color:green"}, "Achievements html directory is already present"); + } else { + system "cp -RPpi $modelCourseAchievementsHtmlDir $courseHtmlDir "; + print CGI::p({style=>"color:green"}, "Achievements html directory created"); + } + } + + } + #print "done with achievements for ",$ce->{courseDirs}{root},"
"; + } # end HACK for upgrading achivements next unless exists $updateable_directories{$dir}; my $path = $ce->{courseDirs}->{$dir}; unless ( -e $path) { # if by some unlucky chance the tmpDirectory hasn't been created, create it. From a2f471f0f77ba2733f4e71a8a6d4051e42f359d6 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Sun, 9 Sep 2012 18:53:26 -0500 Subject: [PATCH 05/27] Fixes bug 2419: In the case of a single answer blank a student could have the answer only partially correct, for example where the answer is a list. Although this would be graded correctly with a status strictly between 0 and 1, the student would still see a green bar below the problem stating "Your answer is correct." This fix gives a more appropriate response: "Part of your answer is NOT correct." --- lib/WeBWorK/ContentGenerator/GatewayQuiz.pm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm index b61401d911..0bffc01334 100644 --- a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -353,6 +353,7 @@ sub attemptResults { $resultsRows{$_} = ""; } + my $answerScore = 0; my $numCorrect = 0; my $numAns = 0; foreach my $name (@answerNames) { @@ -362,7 +363,7 @@ sub attemptResults { ? $self->previewAnswer($answerResult, $imgGen) : ""); my $correctAnswer = $answerResult->{correct_ans}; - my $answerScore = $answerResult->{score}; + $answerScore = $answerResult->{score}; my $answerMessage = $showMessages ? $answerResult->{ans_message} : ""; #FIXME --Can we be sure that $answerScore is an integer-- could the problem give partial credit? $numCorrect += $answerScore > 0; @@ -407,10 +408,12 @@ sub attemptResults { # . scalar @answerNames . " $numIncorrectNoun correct, for a score of $scorePercent."; my $summary = ""; - if (scalar @answerNames == 1) { - if ($numCorrect == scalar @answerNames) { + if (scalar @answerNames == 1) { #Here there is just one answer blank + if ($answerScore == 1) { #The student might be totally right $summary .= CGI::div({class=>"gwCorrect"},"This answer is correct."); - } else { + } elsif ($answerScore && $answerScore < 1) { #The student might be partially right + $summary .= CGI::div({class=>"gwIncorrect"},"Part of this answer is NOT correct."); + } else { #The student might be completely wrong. $summary .= CGI::div({class=>"gwIncorrect"},"This answer is NOT correct."); } } else { From 369483a38e6efadb53869373e7941f9954c596c7 Mon Sep 17 00:00:00 2001 From: Paul Pearson Date: Tue, 18 Sep 2012 18:53:41 -0300 Subject: [PATCH 06/27] Finally fix the bar graph completely Fixed tickmark labels on horizontal axis. --- .../ContentGenerator/Instructor/Stats.pm | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm b/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm index 80b510638e..fc11bb5cfa 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm @@ -1,6 +1,6 @@ ################################################################################ # WeBWorK Online Homework Delivery System -# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# Copyright � 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ # $CVSHeader: webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm,v 1.68 2007/08/13 22:59:56 sh002i Exp $ # # This program is free software; you can redistribute it and/or modify it under @@ -532,7 +532,7 @@ my $yaxislabel = ""; foreach my $i (0..5) { $yaxislabelypixel = $topmargin + 5 + ($i * sprintf("%d",$plotwindowheight/5)); $yaxislabel = 20*(5 - $i); - $svg = $svg . "". $yaxislabel ." %\n"; + $svg = $svg . "". $yaxislabel ."%\n"; } my $yaxisruleypixel = 0; @@ -549,16 +549,20 @@ my $barheight = 0; my $barxpixel = 0; my $barypixel = 0; my $problabelxpixel = 0; -my $problabelypixel = 0; +#my $problabelypixel = 0; +my $problabelypixel = $topmargin + $plotwindowheight - $barheight + 15; + foreach my $probID (@problemIDs) { $linkstring = $self->systemLink($problemPage{$probID}); - $percentcorrect = sprintf("%0.0f",100*$correct_answers_for_problem{$probID}/$number_of_students_attempting_problem{$probID}); + + $percentcorrect = ($number_of_students_attempting_problem{$probID})? + sprintf("%0.0f",100*$correct_answers_for_problem{$probID}/$number_of_students_attempting_problem{$probID}) + : 0; #avoid division by zero $barheight = sprintf("%d", $percentcorrect * $plotwindowheight / 100 ); - $barxpixel = $leftmargin + $probID * ($barwidth + 2*$barsep) + $barsep; + $barxpixel = $leftmargin + ($probID-1) * ($barwidth + 2*$barsep) + $barsep; $barypixel = $topmargin + $plotwindowheight - $barheight; - $problabelxpixel = $leftmargin + ($probID-1) * $totalbarwidth + $barsep; - $problabelypixel = $topmargin + $plotwindowheight - $barheight; - $svg = $svg . "". $probID ."\n"; + $problabelxpixel = $leftmargin + ($probID-1) * $totalbarwidth + $barsep+sprintf("%d",$barwidth/2); + $svg = $svg . "". $probID ."\n"; } $svg = $svg . ""; From f3320e5331e8c7f4ef649b08250663f0f9cc9f99 Mon Sep 17 00:00:00 2001 From: Geoff Goehle Date: Fri, 21 Sep 2012 18:11:17 -0400 Subject: [PATCH 07/27] Fixed uninitialized score variable --- .../Instructor/ProblemSetDetail.pm | 27 ++++++++++--------- .../ContentGenerator/Instructor/Stats.pm | 4 --- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm b/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm index 9c8b0a5bb6..024afc86ea 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm @@ -270,12 +270,14 @@ use constant FIELD_PROPERTIES => { type => "edit", size => 6, override => "any", + default => "1", }, max_attempts => { name => "Max attempts", type => "edit", size => 6, override => "any", + default => "unlimited", labels => { "-1" => "unlimited", }, @@ -292,7 +294,7 @@ use constant FIELD_PROPERTIES => { type => "edit", size => 6, override => "one", - default => 0, + default => "0", }, attempted => { name => "Attempted", @@ -303,7 +305,7 @@ use constant FIELD_PROPERTIES => { 1 => "Yes", 0 => "No", }, - default => 0, + default => "0", }, last_answer => { name => "Last Answer", @@ -314,13 +316,13 @@ use constant FIELD_PROPERTIES => { name => "Correct", type => "hidden", override => "none", - default => 0, + default => "0", }, num_incorrect => { name => "Incorrect", type => "hidden", override => "none", - default => 0, + default => "0", }, }; @@ -989,9 +991,9 @@ sub initialize { if (defined $override && $override eq $field) { - my $param = $r->param("set.$setID.$field"); - $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - my $unlabel = $undoLabels{$field}->{$param}; + my $param = $r->param("set.$setID.$field"); + $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" unless defined $param && $param ne ""; + my $unlabel = $undoLabels{$field}->{$param}; $param = $unlabel if defined $unlabel; # $param = $undoLabels{$field}->{$param} || $param; if ($field =~ /_date/) { @@ -1097,8 +1099,7 @@ sub initialize { next unless canChange($forUsers, $field); my $param = $r->param("set.$setID.$field"); - $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; - + $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" unless defined $param && $param ne ""; my $unlabel = $undoLabels{$field}->{$param}; $param = $unlabel if defined $unlabel; if ($field =~ /_date/) { @@ -1285,7 +1286,7 @@ sub initialize { if (defined $override && $override eq $field) { my $param = $r->param("problem.$problemID.$field"); - $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; + $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" unless defined $param && $param ne ""; my $unlabel = $undoLabels{$field}->{$param}; $param = $unlabel if defined $unlabel; #protect exploits with source_file @@ -1311,7 +1312,7 @@ sub initialize { next unless canChange($forUsers, $field); my $param = $r->param("problem.$problemID.$field"); - $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; + $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" unless defined $param && $param ne ""; my $unlabel = $undoLabels{$field}->{$param}; $param = $unlabel if defined $unlabel; #protect exploits with source_file @@ -1344,7 +1345,7 @@ sub initialize { next unless canChange($forUsers, $field); my $param = $r->param("problem.$problemID.$field"); - $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; + $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" unless defined $param && $param ne ""; my $unlabel = $undoLabels{$field}->{$param}; $param = $unlabel if defined $unlabel; @@ -1388,7 +1389,7 @@ sub initialize { next unless canChange($forUsers, $field); my $param = $r->param("problem.$problemID.$field"); - $param = $properties{$field}->{default} || "" unless defined $param && $param ne ""; + $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" unless defined $param && $param ne ""; my $unlabel = $undoLabels{$field}->{$param}; $param = $unlabel if defined $unlabel; $changed ||= changed($record->$field, $param); diff --git a/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm b/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm index e0f94822cd..9df0d975f4 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm @@ -561,12 +561,8 @@ foreach my $probID (@problemIDs) { $barheight = sprintf("%d", $percentcorrect * $plotwindowheight / 100 ); $barxpixel = $leftmargin + ($probID-1) * ($barwidth + 2*$barsep) + $barsep; $barypixel = $topmargin + $plotwindowheight - $barheight; -<<<<<<< HEAD $problabelxpixel = $leftmargin + ($probID-1) * $totalbarwidth + $barsep; $problabelypixel = $topmargin + $plotwindowheight - $barheight; -======= - $problabelxpixel = $leftmargin + ($probID-1) * $totalbarwidth + $barsep+sprintf("%d",$barwidth/2); ->>>>>>> 369483a38e6efadb53869373e7941f9954c596c7 $svg = $svg . "". $probID ."\n"; } From 09cf2fadded772d6b601bb55e94dc4f509d1405b Mon Sep 17 00:00:00 2001 From: apizer Date: Wed, 10 Oct 2012 14:55:27 -0500 Subject: [PATCH 08/27] Use Storable::nfreeze instead of freeze. This fixes abug discussed in http://webwork.maa.org/moodle/mod/forum/discuss.php?d=2562 --- lib/WeBWorK/AchievementEvaluator.pm | 10 +++++----- lib/WeBWorK/Utils.pm | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/WeBWorK/AchievementEvaluator.pm b/lib/WeBWorK/AchievementEvaluator.pm index 10d619dc38..4137b61dc7 100644 --- a/lib/WeBWorK/AchievementEvaluator.pm +++ b/lib/WeBWorK/AchievementEvaluator.pm @@ -28,7 +28,7 @@ use WeBWorK::CGI; use WeBWorK::Utils qw(before after readFile sortAchievements); use Safe; -use Storable qw(freeze thaw); +use Storable qw(nfreeze thaw); sub checkForAchievements { @@ -225,15 +225,15 @@ sub checkForAchievements { $achievementPoints += $points; } - #update counter, freeze localData and store + #update counter, nfreeze localData and store $userAchievement->counter($counter); - $userAchievement->frozen_hash(freeze($localData)); + $userAchievement->frozen_hash(nfreeze($localData)); $db->putUserAchievement($userAchievement); } #end for loop - #freeze globalData and store - $globalUserAchievement->frozen_hash(freeze($globalData)); + #nfreeze globalData and store + $globalUserAchievement->frozen_hash(nfreeze($globalData)); $db->putGlobalUserAchievement($globalUserAchievement); return $cheevoMessage; diff --git a/lib/WeBWorK/Utils.pm b/lib/WeBWorK/Utils.pm index 28e1b3461f..f40d04255d 100644 --- a/lib/WeBWorK/Utils.pm +++ b/lib/WeBWorK/Utils.pm @@ -875,7 +875,7 @@ sub encodeAnswers(\%\@) { foreach my $key (@order) { push @ordered_hash, $key, $hash{$key}; } - return Storable::freeze( \@ordered_hash); + return Storable::nfreeze( \@ordered_hash); } From d9f3aca29b1a5dad715038baf114d788638b96a7 Mon Sep 17 00:00:00 2001 From: apizer Date: Fri, 12 Oct 2012 15:18:21 -0500 Subject: [PATCH 09/27] Move course tmp files from the course directory to WeBWorK's tmp directory. Changed the default location of all WeBWorK tmp files to .../webwork2/htdocs/tmp. We only had to change where course tmp files are put. Thhey now go to .../webwork2/htdocs/tmp/course_name/ So .../webwork2/htdocs/tmp is set up in exactly the same way we suggest people set up /var/www/wwtmp. There is no real reason now for people to have to set up /var/www/wwtmp. --- conf/defaults.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/defaults.config b/conf/defaults.config index 8529016d28..50e174eb70 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -261,8 +261,8 @@ $courseDirs{html_images} = "$courseDirs{html}/images"; # Location of web-accessible, course-specific temporary files, like static and # dynamically-generated PG graphics. -$courseDirs{html_temp} = "$courseDirs{html}/tmp"; -$courseURLs{html_temp} = "$courseURLs{html}/tmp"; +$courseDirs{html_temp} = "$webworkDirs{htdocs_temp}/$courseName"; +$courseURLs{html_temp} = "$webworkURLs{htdocs_temp}/$courseName"; # Location of course-specific logs, like the transaction log. $courseDirs{logs} = "$courseDirs{root}/logs"; From f38350c2a62f92144c02be813183e400aefd6440 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Wed, 24 Oct 2012 15:33:07 -0500 Subject: [PATCH 10/27] removed errant submodule references --- htdocs/themes/math2/codemirror2 | 1 - htdocs/themes/ubc/codemirror2 | 1 - 2 files changed, 2 deletions(-) delete mode 160000 htdocs/themes/math2/codemirror2 delete mode 160000 htdocs/themes/ubc/codemirror2 diff --git a/htdocs/themes/math2/codemirror2 b/htdocs/themes/math2/codemirror2 deleted file mode 160000 index 73edae2aaa..0000000000 --- a/htdocs/themes/math2/codemirror2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73edae2aaabf867f45119804b7816a339762414e diff --git a/htdocs/themes/ubc/codemirror2 b/htdocs/themes/ubc/codemirror2 deleted file mode 160000 index 73edae2aaa..0000000000 --- a/htdocs/themes/ubc/codemirror2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73edae2aaabf867f45119804b7816a339762414e From 198edbf52e140e3f6f37c1e381a1753222d01059 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Wed, 24 Oct 2012 16:05:59 -0500 Subject: [PATCH 11/27] Removed errant submodule references --- htdocs/themes/math2/codemirror2 | 1 - htdocs/themes/ubc/codemirror2 | 1 - 2 files changed, 2 deletions(-) delete mode 160000 htdocs/themes/math2/codemirror2 delete mode 160000 htdocs/themes/ubc/codemirror2 diff --git a/htdocs/themes/math2/codemirror2 b/htdocs/themes/math2/codemirror2 deleted file mode 160000 index 73edae2aaa..0000000000 --- a/htdocs/themes/math2/codemirror2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73edae2aaabf867f45119804b7816a339762414e diff --git a/htdocs/themes/ubc/codemirror2 b/htdocs/themes/ubc/codemirror2 deleted file mode 160000 index 73edae2aaa..0000000000 --- a/htdocs/themes/ubc/codemirror2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73edae2aaabf867f45119804b7816a339762414e From c1ceb3755941e70af505477469eeffbc39a7510c Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Fri, 12 Oct 2012 13:05:58 -0500 Subject: [PATCH 12/27] Fixed OPL-update to use libraryVersion from \$ce rather than a VERSION file Changed cherry-picked from webwork2/master 4663e15316233ec81d56ff75ca7113d5ded9ca1b --- bin/OPL-update | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/bin/OPL-update b/bin/OPL-update index d8a0aedb01..ea022d4d9a 100755 --- a/bin/OPL-update +++ b/bin/OPL-update @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # This is the script formerly known as loadDB2, and then known as NPL-update. @@ -84,6 +84,7 @@ my $dbh = DBI->connect( my $passwd = $ce->{database_password}; my $user = $ce->{database_username}; my $libraryRoot = $ce->{problemLibrary}->{root}; +my $libraryVersion = $ce->{problemLibrary}->{version}; my $verbose = 0; my $cnt2 = 0; @@ -98,21 +99,14 @@ sub dbug { ##Figure out which set of tables to use my %tables; -if( -e "$libraryRoot/VERSION") { - require("$libraryRoot/VERSION"); - if($OPL_VERSION eq '2.5.0') { +if($libraryVersion eq '2.5') { %tables = %OPLtables; my $lib = 'OPL'; - print "Got OPLtables!\n"; - } else { - %tables = %NPLtables; - my $lib = 'NPL'; - print "Got NPLtables! (1)\n"; - } + warn "Library version is $libraryVersion; using OPLtables!\n"; } else { %tables = %NPLtables; my $lib = 'NPL'; - print "Got NPLtables! (2)\n"; + print "Library version is $libraryVersion; NPLtables! \n"; } @create_tables = ( From 0d0535ce0c2aff7abcc5fafcd9112f7374e0c850 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Wed, 24 Oct 2012 17:06:49 -0500 Subject: [PATCH 13/27] CONFIG-README directions out of date and superceeded by directions in README" --- conf/CONFIG-README | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 conf/CONFIG-README diff --git a/conf/CONFIG-README b/conf/CONFIG-README deleted file mode 100644 index 47258870c7..0000000000 --- a/conf/CONFIG-README +++ /dev/null @@ -1,37 +0,0 @@ - -FIRST TIME RECONFIGURATION - -RENAME global.conf to global.save in order to make sure that the global.conf.dist is read. -Otherwise the global.conf file will be read instead of global.conf.dist. prelocal.conf and postlocal.conf -and the behavior will be the same as with the old system. - -COPY prelocal.conf.dist to prelocal.conf. -COPY postlocal.conf.dist to postlocal.conf. - -MODIFY prelocal.conf using the data from your global.conf file. -In particular you will need to fill in the server name, the -password for the database and any modifications you have made as to the -location of the temporary files directory. Notice that the location of the temporary files directory -is used to define several other related subdirectories, so this modification needs to be made -in prelocal.conf BEFORE the standard global.conf.dist file is read. - - -INSPECT and possibly modify postlocal.conf to add any further local modifications that you had -made to your global.conf file. - -Use the prelocal.conf and postlocal.conf files to make modifications. - -The prelocal.conf file is read before the global.conf.dist file is processed. Non-local variables in this file -are then available for use in global.conf.dist. - -The postlocal.conf file is read after the global.conf.dist file is processed and will overright configurations in global.conf.dist - -This new configuration system should greatly simplify the process of -updating webwork2 since it is less likely -that one will need to modify the config files when upgrading. Default configurations or permissions for -new features will be defined in global.conf.dist and will allow automatic upgrades. - -Overrides for these new features can be added later to postlocal.conf - - - From c6a5871db0ec8883fa75e6eed1b0b6a90422c42e Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Sun, 4 Nov 2012 12:06:15 -0600 Subject: [PATCH 14/27] Added wwapache2ctl and webwork2.komodoproject to .gitignore (the last is a project file generated by an IDE I'm trying out). --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 50679cec15..d384242114 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ logs/* conf/*.conf conf/*.apache2-config htdocs/site_info.txt +bin/wwapache2ctl +webwork2.komodoproject #courses.dist/* From 1051ffe217297daf4651d2a178c864981b326510 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Sun, 4 Nov 2012 12:13:16 -0600 Subject: [PATCH 15/27] Sometimes users change user_id's. Given a course_id, an existing user_id in that course, and a different user_id, this script will (a) create a user for the new user_id if the account doesn't exist and (b) will also copy all existing data in the database associated with the old user_id to the new user_id. TODO: Currently copies all user set and problem data, but does not yet copy achievment data. We also want it to modify answer_log data so that the new user_id gets the same past answers. --- bin/change_user_id | 107 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 bin/change_user_id diff --git a/bin/change_user_id b/bin/change_user_id new file mode 100644 index 0000000000..7bbd6c1ccf --- /dev/null +++ b/bin/change_user_id @@ -0,0 +1,107 @@ +#!/usr/bin/env perl +# +#Sometimes a webwork user id changes. This script transfers the webwork data for the old user_id to the new user_id +# Update database tables +#user +#permission +#password +#key +#set_user +#problem_user +#set_locations_user +#global_achievement_user +#achievement_user +# +# Update answer_log + +use strict; +use warnings; + +BEGIN { + die "WEBWORK_ROOT not found in environment.\n" + unless exists $ENV{WEBWORK_ROOT}; +} + +use lib "$ENV{WEBWORK_ROOT}/lib"; +use WeBWorK::CourseEnvironment; +use WeBWorK::DB; +use WeBWorK::Utils qw(runtime_use readFile cryptPassword); +use Data::Dumper; + +if((scalar(@ARGV) != 3)) { + print "\nSyntax is: change_user_id course_id old_user_id new_user_id"; + print "\n (e.g. newpassword MAT_123 jjones jsmith\n\n"; + exit(); +} + +my $courseID = shift; +my $old_user_id = shift; +my $new_user_id = shift; + +my $ce = WeBWorK::CourseEnvironment->new({ + webwork_dir => $ENV{WEBWORK_ROOT}, + courseName => $courseID +}); + +my $db = new WeBWorK::DB($ce->{dbLayout}); +die "Error: $old_user_id does not exist!" unless $db->existsUser($old_user_id); + +unless($db->existsUser($new_user_id)) { + my $user = $db->getUser($old_user_id); + $user->{user_id}=$new_user_id; + $user->{comment} = $user->{comment}."Record created from $old_user_id record"; + $db->addUser($user); +} + +unless($db->existsPassword($new_user_id)) { + my $password = $db->getPassword($old_user_id); + $password->{user_id} = $new_user_id; + $db->addPassword($password); +} + +unless($db->existsPermissionLevel($new_user_id)) { + my $permission = $db->getPermissionLevel($old_user_id); + $permission->{user_id} = $new_user_id; + $db->addPermissionLevel($permission); +} + + +my @old_user_sets = $db->listUserSets($old_user_id); +foreach(@old_user_sets) { + my $set_id = $_; + my $new_set = $db->newUserSet; + $new_set->user_id($new_user_id); + $new_set->set_id($set_id); + eval{$db->addUserSet($new_set)}; + my $old_set = $db->getUserSet($old_user_id,$set_id); + foreach(keys %$old_set) { + next if /user_id|set_id/; + $new_set->$_($old_set->$_); + } + + $db->putUserSet($new_set) unless $db->existsUserSet($new_user_id,$set_id); + my @global_problems = grep { defined $_} $db->getAllGlobalProblems($set_id); + foreach(@global_problems) { + if($db->existsUserProblem($old_user_id,$set_id,$_->{problem_id})) { + my $old_user_problem = $db->getUserProblem($old_user_id,$set_id,$_->{problem_id}); + my $new_user_problem = $db->newUserProblem; + $new_user_problem->user_id($new_user_id); + $new_user_problem->set_id($set_id); + $new_user_problem->problem_id($_->{problem_id}); + $db->addUserProblem($new_user_problem) unless $db->existsUserProblem($new_user_id,$set_id,$_->{problem_id}); + foreach(keys %$old_user_problem) { + next if /(user_id|set_id|problem_id)/; + $new_user_problem->$_($old_user_problem->$_); + } + $db->putUserProblem($new_user_problem); + } + } +} + +my $answer_log = $ce->{courseFiles}->{logs}->{answer_log}; +open(my $fh,">>",$answer_log); +foreach(<$fh>) { + s/$// +} + + From d63615088c284e7c11301d137b4ba7afda36d677 Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Sun, 4 Nov 2012 14:48:20 -0500 Subject: [PATCH 16/27] Add a cleanup routine to PG so that MathObjects that are part of the output or answer checkers are freed (in order to prevent errors about missing packages). --- lib/WeBWorK.pm | 5 ----- lib/WeBWorK/ContentGenerator/Problem.pm | 7 +++++++ lib/WeBWorK/PG.pm | 13 +++++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/WeBWorK.pm b/lib/WeBWorK.pm index d7fc724447..759b8e540e 100644 --- a/lib/WeBWorK.pm +++ b/lib/WeBWorK.pm @@ -377,11 +377,6 @@ sub dispatch($) { writeTimingLogEntry($ce, "[".$r->uri."]", sprintf("runTime = %.3f sec", $cg_duration)." ".$ce->{dbLayoutName}, ""); debug("returning result: " . (defined $result ? $result : "UNDEF") . "\n"); - #@LimitedPolynomial::BOP::ISA; #FIXME this is needed to zero out - #@LimitedPolynomial::UOP::ISA; - #\@LimitedPolynomial::BOP::ISA and prevent error messages of the form - #[Sat May 15 14:23:08 2010] [warn] [client 127.0.0.1] [/webwork2/gage_course/test_set/6/] - #Can't locate package LimitedPolynomial::BOP for @LimitedPolynomial::BOP::add::ISA at /opt/webwork/webwork2/lib/Apache/WeBWorK.pm line 115., referer: http://localhost/webwork2/gage_course/test_set/6/ no one knows why return $result; } diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index cefd5ca099..4e541a6598 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -472,6 +472,13 @@ sub previewCorrectAnswer { # Template escape implementations ################################################################################ +sub content { + my $self = shift; + my $result = $self->SUPER::content(@_); + $self->{pg}->free if $self->{pg}; # be sure to clean up PG environment when the page is done + return $result; +} + sub pre_header_initialize { my ($self) = @_; my $r = $self->r; diff --git a/lib/WeBWorK/PG.pm b/lib/WeBWorK/PG.pm index dffa5107c1..651518ffe2 100644 --- a/lib/WeBWorK/PG.pm +++ b/lib/WeBWorK/PG.pm @@ -53,6 +53,19 @@ sub new { return $renderer->new(@_); } +sub free { + my $self = shift; + # + # If certain MathObjects (e.g. LimitedPolynomials) are left in the PG structure, then + # freeing them later can cause "Can't locate package ..." errors in the log during + # perl garbage collection. So free them here. + # + $self->{pgcore}{OUTPUT_ARRAY} = []; + $self->{answers} = {}; + undef $self->{translator}; + foreach (keys %{$self->{pgcore}{PG_ANSWERS_HASH}}) {undef $self->{pgcore}{PG_ANSWERS_HASH}{$_}} +} + sub defineProblemEnvir { my ( $self, From 26d297985aa745398210a4dd51fc2ca394bfd26f Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Tue, 6 Nov 2012 09:07:25 -0600 Subject: [PATCH 17/27] I think having the shebang line '/usr/bin/env perl' is more portable than /usr/bin/perl. It works on all *nix's and also allows for the script to work unmodified when a local administrator changes the perl path --- bin/check_modules.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/check_modules.pl b/bin/check_modules.pl index fcca289b6b..d0fd873afd 100755 --- a/bin/check_modules.pl +++ b/bin/check_modules.pl @@ -1,5 +1,5 @@ -#!/usr/bin/perl - +#!/usr/bin/env perl +# use strict; use warnings; From e96d5a50d84774170b6018475d28b6aff4d49823 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Tue, 6 Nov 2012 11:02:53 -0600 Subject: [PATCH 18/27] Added code to back up existing answer_log and then replace old user_id with new user_id --- bin/change_user_id | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) mode change 100644 => 100755 bin/change_user_id diff --git a/bin/change_user_id b/bin/change_user_id old mode 100644 new mode 100755 index 7bbd6c1ccf..3cd0bde055 --- a/bin/change_user_id +++ b/bin/change_user_id @@ -16,6 +16,8 @@ use strict; use warnings; +use File::Copy; +use File::Basename; BEGIN { die "WEBWORK_ROOT not found in environment.\n" @@ -99,9 +101,11 @@ foreach(@old_user_sets) { } my $answer_log = $ce->{courseFiles}->{logs}->{answer_log}; -open(my $fh,">>",$answer_log); -foreach(<$fh>) { - s/$// +my $dirname = dirname($answer_log); +copy($answer_log,"$dirname/answer_log.bak"); +open(my $in,'<',"$dirname/answer_log.bak") or die "Can't open $dirname/answer_log.bak:$!"; +open(my $out,'>',$answer_log); +while(<$in>) { + s/$old_user_id/$new_user_id/g; + print $out $_; } - - From d42b671eb7e42289d7ea1e76647570d3d48d91cb Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Tue, 6 Nov 2012 11:03:58 -0600 Subject: [PATCH 19/27] Modified DB.pm to fix issue #68 --- lib/WeBWorK/DB.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/WeBWorK/DB.pm b/lib/WeBWorK/DB.pm index d118257e79..7e44575519 100644 --- a/lib/WeBWorK/DB.pm +++ b/lib/WeBWorK/DB.pm @@ -779,10 +779,10 @@ sub addKey { my ($userID, $proctorID) = ($1, $2); croak "addKey: user $userID not found" # unless $self->{user}->exists($userID); - unless $Key -> key eq "nonce" or $self->{user}->exists($Key->user_id); + unless $Key -> key eq "nonce" or $self->{user}->exists($userID); croak "addKey: proctor $proctorID not found" # unless $self->{user}->exists($proctorID); - unless $Key -> key eq "nonce" or $self->{user}->exists($Key->user_id); + unless $Key -> key eq "nonce" or $self->{user}->exists($proctorID); } else { croak "addKey: user ", $Key->user_id, " not found" # unless $self->{user}->exists($Key->user_id); From 0010fb8dc59f73398e27740d2ad0e1311c5b9acd Mon Sep 17 00:00:00 2001 From: Paul Vojta Date: Sun, 9 Dec 2012 11:19:39 -0600 Subject: [PATCH 20/27] CAS authentication module, associated conf file and changes to Login.pm and Logout.pm --- conf/authen_CAS.conf.dist | 36 +++++++ lib/WeBWorK/Authen/CAS.pm | 136 +++++++++++++++++++++++++ lib/WeBWorK/ContentGenerator/Login.pm | 10 ++ lib/WeBWorK/ContentGenerator/Logout.pm | 3 + 4 files changed, 185 insertions(+) create mode 100644 conf/authen_CAS.conf.dist create mode 100644 lib/WeBWorK/Authen/CAS.pm diff --git a/conf/authen_CAS.conf.dist b/conf/authen_CAS.conf.dist new file mode 100644 index 0000000000..62417696a1 --- /dev/null +++ b/conf/authen_CAS.conf.dist @@ -0,0 +1,36 @@ +#!perl + +######################################################################################## +# authen_CAS.conf.dist +# Copy this file to authen_CAS.conf. Then configure it to match your server's CAS configuration. +# Then to activate add the following line to localOverrides.conf: +# include("conf/authen_CAS.conf") +######################################################################################## + +# Set CAS as the authentication module to use. +$authen{user_module} = { + "*" => "WeBWorK::Authen::CAS", +}; + +$authen{cas_options} = { + # Options to pass to the AuthCAS module. + # Note that this is (plain) AuthCAS, not Apache::AuthCAS + # or Apache2::AuthCAS. + # You need at least casUrl and CAFile; others can be set as well. + AuthCAS_opts => { + # URL of CAS server. Edit the host below. + casURL => '', #e.g. 'https://auth.berkeley.edu/cas', + + # Path of certificate file for CAS server. + CAFile => '', #e.g. '/etc/pki/tls/certs/ca-bundle.crt', + }, + # There are no options specific to CAS at this time. If there were, + # though, they would go here. + + # For debugging: + #su_from => '8315', + su_to => '999999', +}; + + +1; #final line of the file to reassure perl that it was read properly. diff --git a/lib/WeBWorK/Authen/CAS.pm b/lib/WeBWorK/Authen/CAS.pm new file mode 100644 index 0000000000..1cc78fea15 --- /dev/null +++ b/lib/WeBWorK/Authen/CAS.pm @@ -0,0 +1,136 @@ +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ + +package WeBWorK::Authen::CAS; +use base qw/WeBWorK::Authen/; + +use strict; +use warnings; +use AuthCAS; + +use WeBWorK::Debug; +#$WeBWorK::Debug::Enabled = 1; +#$WeBWorK::Debug::Logfile = "/opt/webwork/webwork2/logs/cas-debug.log"; +#$WeBWorK::Debug::AllowSubroutineOutput = "get_credentials"; + +sub get_credentials { + my ($self) = @_; + my $r = $self->{r}; + my $ce = $r->ce; + + # if we come in with a user_id, then we've already authenticated + # through the CAS. So just check the provided user and session key. + $self->{external_auth} = 1; + if (defined $r->param('key') && defined $r->param('user')) { + # These lines were copied from the superclass get_credentials. + $self->{session_key} = $r->param('key'); + $self->{user_id} = $r->param('user'); + $self->{login_type} = 'normal'; + $self->{credential_source} = 'params'; + debug("CAS params user '", $self->{user_id}, + "' key '", $self->{session_key}, "'"); + # Check session key and user here. Otherwise, a student can + # determine the enrollment status of any other student if + # they know the userid (which is public information at + # Berkeley). That would be a privacy violation. + my $Key = $r->db->getKey($self->{user_id}); + unless (defined $Key && $Key->key eq $self->{session_key}) { + debug('undefined or invalid session key: $Key->key = ', + defined $Key ? $Key->key : undef, ', user value = ', + $self->{session_key}); + $self->{error} = "Invalid session key"; + return 0; + } + return 1; + #debug("falling back to superclass get_credentials"); + #return $self->SUPER::get_credentials( @_ ); + } else { + #my $cas_url = $ce->{authen}{cas_options}{url}; + #my $cas_certs = $ce->{authen}{cas_options}{certs}; + #my $cas = new AuthCAS(casUrl => $cas_url, + # CAFile => $cas_certs); + my $cas = new AuthCAS( + %{ $ce->{authen}{cas_options}{AuthCAS_opts} }); + + my $service = $ce->{apache_root_url} . $r->location . '/' + . $r->urlpath->arg('courseID') . '/'; + debug("service = $service"); + my $ticket = $r->param('ticket') || 0; + unless ($ticket) { + # there's no ticket, so redirect to get one + # + my $go_to = $cas->getServerLoginURL($service); + #$go_to = 'http://math.berkeley.edu/'; # for debugging + debug("no ticket. Redirecting to $go_to"); + $self->{redirect} = $go_to; + return 0; + } + # We have a ticket. Validate it. + my $user_id = $cas->validateST($service, $ticket); + if (!defined $user_id) { + my $err = $cas->get_errors(); + $err = '' unless defined $err; + $self->{error} = $err; + debug("ticket error $err"); + #return $self->SUPER::get_credentials( @_ ); + return 0; + } else { + debug("ticket is good, user is $user_id"); + if (defined $ce->{authen}{cas_options}{su_from} + && $user_id eq $ce->{authen}{cas_options}{su_from} + && defined $ce->{authen}{cas_options}{su_to}) { + $user_id = $ce->{authen}{cas_options}{su_to}; + debug("hackily changing user to $user_id"); + } + $self->{'user_id'} = $user_id; + $self->{r}->param('user', $user_id); + $self->{session_key} = undef; + $self->{password} = "not\tvalid"; + $self->{login_type} = 'normal'; + $self->{credential_source} = 'cas'; + return 1; + } + } +} + +# There's no need to provide site_checkPassword, since it's only accessed +# from checkPassword, which we're replacing. + +sub checkPassword { + my ( $self, $userID, $clearTextPassword ) = @_; + # if we got here, we know we've already successfully authenticated + # against the CAS + return 1; +} + +# Handle logout by redirecting to the relevant CAS url. + +sub logout_user { + my ($self) = @_; + + my $ce = $self->{r}->ce; + + # Using AuthCAS::getServerLogoutURL($service) would be overkill, + # and (more important) it would send us back here after logging out, + # so we'd end up back at the CAS login screen. + + my $go_to = $ce->{authen}{cas_options}{AuthCAS_opts}{casUrl} + . '/logout'; + debug("logging out. Redirecting to $go_to"); + $self->{redirect} = $go_to; +} + +1; diff --git a/lib/WeBWorK/ContentGenerator/Login.pm b/lib/WeBWorK/ContentGenerator/Login.pm index 80ea73c2a1..851913e228 100644 --- a/lib/WeBWorK/ContentGenerator/Login.pm +++ b/lib/WeBWorK/ContentGenerator/Login.pm @@ -117,6 +117,16 @@ sub links { return( @return); } +sub pre_header_initialize { + my ($self) = @_; + my $authen = $self->r->authen; + + if ( defined($authen->{redirect}) && $authen->{redirect} ) { + $self->reply_with_redirect($authen->{redirect}); + } +} + + sub body { my ($self) = @_; my $r = $self->r; diff --git a/lib/WeBWorK/ContentGenerator/Logout.pm b/lib/WeBWorK/ContentGenerator/Logout.pm index 4ea4cde833..643deed077 100644 --- a/lib/WeBWorK/ContentGenerator/Logout.pm +++ b/lib/WeBWorK/ContentGenerator/Logout.pm @@ -82,6 +82,9 @@ sub pre_header_initialize { } $self->{keyError} = $keyError; + # Do any special processing needed by external authentication + $authen->logout_user() if $authen->can('logout_user'); + # if we have an authen redirect, all of those errors may be # moot, but I think that's unavoidable (-glarose) if ( defined($authen->{redirect}) && $authen->{redirect} ) { From 3dcb38f6be76026d97ee62b0c1fa98890e05e1f1 Mon Sep 17 00:00:00 2001 From: Paul Vojta Date: Wed, 2 Jan 2013 14:02:00 -0800 Subject: [PATCH 21/27] Added support for URLs as provided in WWfeedback messages I had inadvertently provided an older version of CAS.pm when submitting the original version. This brings CAS.pm up to date. The only change was/is to add support to keep params on the URL being sent to the CAS server (so that URLs provided by WWfeedback messages work properly). --- lib/WeBWorK/Authen/CAS.pm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/WeBWorK/Authen/CAS.pm b/lib/WeBWorK/Authen/CAS.pm index 1cc78fea15..a128c0b21e 100644 --- a/lib/WeBWorK/Authen/CAS.pm +++ b/lib/WeBWorK/Authen/CAS.pm @@ -65,8 +65,12 @@ sub get_credentials { my $cas = new AuthCAS( %{ $ce->{authen}{cas_options}{AuthCAS_opts} }); - my $service = $ce->{apache_root_url} . $r->location . '/' - . $r->urlpath->arg('courseID') . '/'; + my $service = $r->unparsed_uri(); + # Remove the "ticket=..." parameter that the CAS server added + # (Not sure if the second test is really needed.) + $service =~ s/[?&]ticket=[^&]*$// + or $service =~ s/([?&])ticket=[^&]*&/$1/; + $service = $ce->{apache_root_url} . $service; debug("service = $service"); my $ticket = $r->param('ticket') || 0; unless ($ticket) { From cb0a29158d5b05f311b0142724227e7f5a679f6e Mon Sep 17 00:00:00 2001 From: Paul Vojta Date: Wed, 2 Jan 2013 14:06:41 -0800 Subject: [PATCH 22/27] Fixed copyright date, and minor code cleanup --- lib/WeBWorK/Authen/CAS.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/WeBWorK/Authen/CAS.pm b/lib/WeBWorK/Authen/CAS.pm index a128c0b21e..c3ed38da15 100644 --- a/lib/WeBWorK/Authen/CAS.pm +++ b/lib/WeBWorK/Authen/CAS.pm @@ -1,6 +1,6 @@ ################################################################################ # WeBWorK Online Homework Delivery System -# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# Copyright © 2012 The WeBWorK Project, http://openwebwork.sf.net/ # $CVSHeader: $ # # This program is free software; you can redistribute it and/or modify it under @@ -72,8 +72,8 @@ sub get_credentials { or $service =~ s/([?&])ticket=[^&]*&/$1/; $service = $ce->{apache_root_url} . $service; debug("service = $service"); - my $ticket = $r->param('ticket') || 0; - unless ($ticket) { + my $ticket = $r->param('ticket'); + unless (defined $ticket) { # there's no ticket, so redirect to get one # my $go_to = $cas->getServerLoginURL($service); From b7afc277a57dd40b00e60de14bc5838e1a3dbf32 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Fri, 4 Jan 2013 10:02:13 -0600 Subject: [PATCH 23/27] Fixed typo in authen_CAS.conf.dist --- conf/authen_CAS.conf.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/authen_CAS.conf.dist b/conf/authen_CAS.conf.dist index 62417696a1..60f4c62e60 100644 --- a/conf/authen_CAS.conf.dist +++ b/conf/authen_CAS.conf.dist @@ -19,7 +19,7 @@ $authen{cas_options} = { # You need at least casUrl and CAFile; others can be set as well. AuthCAS_opts => { # URL of CAS server. Edit the host below. - casURL => '', #e.g. 'https://auth.berkeley.edu/cas', + casUrl => '', #e.g. 'https://auth.berkeley.edu/cas', # Path of certificate file for CAS server. CAFile => '', #e.g. '/etc/pki/tls/certs/ca-bundle.crt', From ba90466c1faf487e431aec43ada56bf0380cc7e0 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 4 Jan 2013 17:05:27 -0800 Subject: [PATCH 24/27] Enable comma escaping, unicode chars in classlists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Classlists files as processed by the addcourse script can't deal with users who, for one reason or another, has a comma in either their first or last name. Using the Text::CSV module for CSV parsing instead of split() enables comma escaping values by putting them in double quotes. Users who have non-ASCII characters in their name gets their name (e.g.: Frøystein) mangled after going through addcourse. This commit forces Perl to open the the classlist file with UTF8 encoding. This way the unicode characters survive intact into the database. --- bin/check_modules.pl | 1 + lib/WeBWorK/File/Classlist.pm | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/check_modules.pl b/bin/check_modules.pl index d0fd873afd..c1b95fc31e 100755 --- a/bin/check_modules.pl +++ b/bin/check_modules.pl @@ -84,6 +84,7 @@ Socket SQL::Abstract String::ShellQuote + Text::CSV Text::Wrap Tie::IxHash Time::HiRes diff --git a/lib/WeBWorK/File/Classlist.pm b/lib/WeBWorK/File/Classlist.pm index cd6312f085..0f28ba7904 100644 --- a/lib/WeBWorK/File/Classlist.pm +++ b/lib/WeBWorK/File/Classlist.pm @@ -26,6 +26,7 @@ WeBWorK::File::Classlist - parse and write classlist files. use strict; use warnings; use IO::File; +use Text::CSV; our $MIN_FIELDS = 9; our $MAX_FIELDS = 11; @@ -38,10 +39,13 @@ our @EXPORT = qw/parse_classlist write_classlist/; sub parse_classlist($) { my ($file) = @_; + use open qw( :encoding(UTF-8) :std ); # assume classlist is utf8 encoded my $fh = new IO::File($file, "<") or die "Failed to open classlist '$file' for reading: $!\n"; my (@records); + + my $csv = Text::CSV->new({ binary => 1 }); # binary for utf8 compat while (<$fh>) { chomp; @@ -50,7 +54,12 @@ sub parse_classlist($) { s/^\s*//; s/\s*$//; - my @fields = split /\s*,\s*/, $_, -1; # -1 == don't delete empty trailing fields + if (!$csv->parse($_)) { + warn "Unable to parse line $. of classlist '$file' as CSV."; + next; + } + my @fields = $csv->fields; + my $fields = @fields; if ($fields < $MIN_FIELDS) { warn "Skipped invalid line $. of classlist '$file': expected at least $MIN_FIELDS fields, got $fields fields.\n"; From 4d6aad603921565740f84b0c805e0ffef3078b28 Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Fri, 11 Jan 2013 12:23:57 -0800 Subject: [PATCH 25/27] Fixed OPL-update to symlink applets to web accessible directory --- bin/OPL-update | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/OPL-update b/bin/OPL-update index ea022d4d9a..6b075d409e 100755 --- a/bin/OPL-update +++ b/bin/OPL-update @@ -416,6 +416,10 @@ sub pgfiles { my ($edition, $textauthor, $textsection, $textproblem, $tagged); %textinfo=(); my @textproblems = (-1); + if ($name =~ /swf$/ { + my $applet_file = basename($name); + symlink($name,"$webworkDirs{htdocs}/applets/$applet_file"); + } if ($name =~ /pg$/) { $pgfile = basename($name); $pgpath = dirname($name); From 64af8b9bfcdf372031fca158ec8fe616072d95be Mon Sep 17 00:00:00 2001 From: Jason Aubrey Date: Fri, 11 Jan 2013 15:21:19 -0800 Subject: [PATCH 26/27] OPL-update now symlinks swf applets in the OPL to webwork2/htdocs/applets so they can be used in problems easily --- bin/OPL-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/OPL-update b/bin/OPL-update index 6b075d409e..b55f406195 100755 --- a/bin/OPL-update +++ b/bin/OPL-update @@ -416,9 +416,9 @@ sub pgfiles { my ($edition, $textauthor, $textsection, $textproblem, $tagged); %textinfo=(); my @textproblems = (-1); - if ($name =~ /swf$/ { + if ($name =~ /swf$/) { my $applet_file = basename($name); - symlink($name,"$webworkDirs{htdocs}/applets/$applet_file"); + symlink($name,$ce->{webworkDirs}->{htdocs}."/applets/".$applet_file); } if ($name =~ /pg$/) { $pgfile = basename($name); From 3e4dbda26711ba887222546eefed088161c4b824 Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Thu, 17 Jan 2013 12:44:03 -0500 Subject: [PATCH 27/27] Remove LimitedPolynomials and Inequalities::common from the preloaded list (now that the package errors are resolved). Must put back the original contextLimitedPolynomials.pl and contextInequalities.pl as well --- conf/defaults.config | 2 -- 1 file changed, 2 deletions(-) diff --git a/conf/defaults.config b/conf/defaults.config index 50e174eb70..3afe7dcac6 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -938,9 +938,7 @@ ${pg}{modules} = [ [qw(Fraction)], [qw(Fun)], [qw(Hermite)], - [qw(Inequalities::common)], [qw(Label)], - [qw(LimitedPolynomial)], [qw(ChoiceList)], [qw(Match)], [qw(MatrixReal1)], # required by Matrix