[system] / branches / gage_dev / webwork2 / lib / WeBWorK / ContentGenerator / Problem.pm Repository:
ViewVC logotype

Diff of /branches/gage_dev/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 6909 Revision 6943
13# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the 13# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14# Artistic License for more details. 14# Artistic License for more details.
15################################################################################ 15################################################################################
16 16
17package WeBWorK::ContentGenerator::Problem; 17package WeBWorK::ContentGenerator::Problem;
18use base qw(WeBWorK WeBWorK::ContentGenerator WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil); 18use base qw(WeBWorK::ContentGenerator);
19 19
20=head1 NAME 20=head1 NAME
21 21
22WeBWorK::ContentGenerator::Problem - Allow a student to interact with a problem. 22WeBWorK::ContentGenerator::Problem - Allow a student to interact with a problem.
23 23
35use WeBWorK::PG::IO; 35use WeBWorK::PG::IO;
36use WeBWorK::Utils qw(readFile writeLog writeCourseLog encodeAnswers decodeAnswers 36use WeBWorK::Utils qw(readFile writeLog writeCourseLog encodeAnswers decodeAnswers
37 ref2string makeTempDirectory path_is_subdir sortByName before after between); 37 ref2string makeTempDirectory path_is_subdir sortByName before after between);
38use WeBWorK::DB::Utils qw(global2user user2global); 38use WeBWorK::DB::Utils qw(global2user user2global);
39use URI::Escape; 39use URI::Escape;
40 40use WeBWorK::Localize;
41use WeBWorK::Utils::Tasks qw(fake_set fake_problem); 41use WeBWorK::Utils::Tasks qw(fake_set fake_problem);
42 42
43################################################################################ 43################################################################################
44# CGI param interface to this module (up-to-date as of v1.153) 44# CGI param interface to this module (up-to-date as of v1.153)
45################################################################################ 45################################################################################
191# Note: the substance of attemptResults is lifted into GatewayQuiz.pm, 191# Note: the substance of attemptResults is lifted into GatewayQuiz.pm,
192# with some changes to the output format 192# with some changes to the output format
193 193
194sub attemptResults { 194sub attemptResults {
195 my $self = shift; 195 my $self = shift;
196 my $r = $self->r;
196 my $pg = shift; 197 my $pg = shift;
197 my $showAttemptAnswers = shift; 198 my $showAttemptAnswers = shift;
198 my $showCorrectAnswers = shift; 199 my $showCorrectAnswers = shift;
199 my $showAttemptResults = $showAttemptAnswers && shift; 200 my $showAttemptResults = $showAttemptAnswers && shift;
200 my $showSummary = shift; 201 my $showSummary = shift;
232 my $showEvaluatedAnswers = $ce->{pg}->{options}->{showEvaluatedAnswers}; 233 my $showEvaluatedAnswers = $ce->{pg}->{options}->{showEvaluatedAnswers};
233 234
234 my $header; 235 my $header;
235 #$header .= CGI::th("Part"); 236 #$header .= CGI::th("Part");
236 if ($showEvaluatedAnswers) { 237 if ($showEvaluatedAnswers) {
237 $header .= $showAttemptAnswers ? CGI::th("Entered") : ""; 238 $header .= $showAttemptAnswers ? CGI::th($r->maketext("Entered")) : "";
238 } 239 }
239 $header .= $showAttemptPreview ? CGI::th("Answer Preview") : ""; 240 $header .= $showAttemptPreview ? CGI::th($r->maketext("Answer Preview")) : "";
240 $header .= $showCorrectAnswers ? CGI::th("Correct") : ""; 241 $header .= $showCorrectAnswers ? CGI::th($r->maketext("Correct")) : "";
241 $header .= $showAttemptResults ? CGI::th("Result") : ""; 242 $header .= $showAttemptResults ? CGI::th($r->maketext("Result")) : "";
242 $header .= $showMessages ? CGI::th("Messages") : ""; 243 $header .= $showMessages ? CGI::th($r->maketext("Messages")) : "";
243 my $fully = ''; 244 my $fully = '';
244 my @tableRows = ( $header ); 245 my @tableRows = ( $header );
245 my $numCorrect = 0; 246 my $numCorrect = 0;
246 my $numBlanks =0; 247 my $numBlanks =0;
247 my $tthPreambleCache; 248 my $tthPreambleCache;
256 my $answerScore = $answerResult->{score}; 257 my $answerScore = $answerResult->{score};
257 my $answerMessage = $showMessages ? $answerResult->{ans_message} : ""; 258 my $answerMessage = $showMessages ? $answerResult->{ans_message} : "";
258 $answerMessage =~ s/\n/<BR>/g; 259 $answerMessage =~ s/\n/<BR>/g;
259 $numCorrect += $answerScore >= 1; 260 $numCorrect += $answerScore >= 1;
260 $numBlanks++ unless $studentAnswer =~/\S/ || $answerScore >= 1; # unless student answer contains entry 261 $numBlanks++ unless $studentAnswer =~/\S/ || $answerScore >= 1; # unless student answer contains entry
261 my $resultString = $answerScore >= 1 ? CGI::span({class=>"ResultsWithoutError"}, "correct") : 262 my $resultString = $answerScore >= 1 ? CGI::span({class=>"ResultsWithoutError"}, $r->maketext("correct")) :
262 $answerScore > 0 ? int($answerScore*100)."% correct" : 263 $answerScore > 0 ? $r->maketext("[_1]% correct", int($answerScore*100)):
263 CGI::span({class=>"ResultsWithError"}, "incorrect"); 264 CGI::span({class=>"ResultsWithError"}, $r->maketext("incorrect"));
264 $fully = 'completely ' if $answerScore >0 and $answerScore < 1; 265 $fully = $r->maketext("completely ") if $answerScore >0 and $answerScore < 1;
265 266
267
268 #warn "answer $name score $answerScore";
266 push @correct_ids, $name if $answerScore == 1; 269 push @correct_ids, $name if $answerScore == 1;
267 push @incorrect_ids, $name if $answerScore < 1; 270 push @incorrect_ids, $name if $answerScore < 1;
268 271
269 # need to capture auxiliary answers as well and identify their ids. 272 # need to capture auxiliary answers as well and identify their ids.
270 273
297# . scalar @answerNames . " $numIncorrectNoun correct, for a score of $scorePercent."; 300# . scalar @answerNames . " $numIncorrectNoun correct, for a score of $scorePercent.";
298 my $summary = ""; 301 my $summary = "";
299 unless (defined($problemResult->{summary}) and $problemResult->{summary} =~ /\S/) { 302 unless (defined($problemResult->{summary}) and $problemResult->{summary} =~ /\S/) {
300 if (scalar @answerNames == 1) { #default messages 303 if (scalar @answerNames == 1) { #default messages
301 if ($numCorrect == scalar @answerNames) { 304 if ($numCorrect == scalar @answerNames) {
302 $summary .= CGI::div({class=>"ResultsWithoutError"},"The answer above is correct."); 305 $summary .= CGI::div({class=>"ResultsWithoutError"},$r->maketext("The answer above is correct."));
303 } else { 306 } else {
304 $summary .= CGI::div({class=>"ResultsWithError"},"The answer above is NOT ${fully}correct."); 307 $summary .= CGI::div({class=>"ResultsWithError"},$r->maketext("The answer above is NOT [_1]correct.", $fully));
305 } 308 }
306 } else { 309 } else {
307 if ($numCorrect == scalar @answerNames) { 310 if ($numCorrect == scalar @answerNames) {
308 $summary .= CGI::div({class=>"ResultsWithoutError"},"All of the answers above are correct."); 311 $summary .= CGI::div({class=>"ResultsWithoutError"},$r->maketext("All of the answers above are correct."));
309 } 312 }
310 #unless ($numCorrect + $numBlanks == scalar( @answerNames)) { # this allowed you to figure out if you got one answer right. 313 #unless ($numCorrect + $numBlanks == scalar( @answerNames)) { # this allowed you to figure out if you got one answer right.
311 elsif ($numBlanks != scalar( @answerNames)) { 314 elsif ($numBlanks != scalar( @answerNames)) {
312 $summary .= CGI::div({class=>"ResultsWithError"},"At least one of the answers above is NOT ${fully}correct."); 315 $summary .= CGI::div({class=>"ResultsWithError"},$r->maketext("At least one of the answers above is NOT [_1]correct.", $fully));
313 } 316 }
314 if ($numBlanks) { 317 if ($numBlanks) {
315 my $s = ($numBlanks>1)?'':'s'; 318 my $s = ($numBlanks>1)?'':'s';
316 $summary .= CGI::div({class=>"ResultsAlert"},"$numBlanks of the questions remain$s unanswered."); 319 $summary .= CGI::div({class=>"ResultsAlert"},$r->maketext("[quant,_1,of the questions remains,of the questions remain] unanswered.", $numBlanks));
317 } 320 }
318 } 321 }
319 } else { 322 } else {
320 $summary = $problemResult->{summary}; # summary has been defined by grader 323 $summary = $problemResult->{summary}; # summary has been defined by grader
321 } 324 }
598 601
599 # test for additional problem validity if it's not already invalid 602 # test for additional problem validity if it's not already invalid
600 } else { 603 } else {
601 $self->{invalidProblem} = !(defined $problem and ($set->visible || $authz->hasPermissions($userName, "view_hidden_sets"))); 604 $self->{invalidProblem} = !(defined $problem and ($set->visible || $authz->hasPermissions($userName, "view_hidden_sets")));
602 605
603 $self->addbadmessage(CGI::p("This problem will not count towards your grade.")) if $problem and not $problem->value and not $self->{invalidProblem}; 606 $self->addbadmessage(CGI::p($r->maketext("This problem will not count towards your grade."))) if $problem and not $problem->value and not $self->{invalidProblem};
604 } 607 }
605 608
606 $self->{userName} = $userName; 609 $self->{userName} = $userName;
607 $self->{effectiveUserName} = $effectiveUserName; 610 $self->{effectiveUserName} = $effectiveUserName;
608 $self->{user} = $user; 611 $self->{user} = $user;
747 750
748 return "" if ( $self->{invalidSet} ); 751 return "" if ( $self->{invalidSet} );
749 return $self->{pg}->{head_text} if $self->{pg}->{head_text}; 752 return $self->{pg}->{head_text} if $self->{pg}->{head_text};
750} 753}
751 754
752sub post_head {
753 my ($self) = @_;
754
755 return "" if ( $self->{invalidSet} );
756 return $self->{pg}->{head_text} if $self->{pg}->{post_header_text};
757}
758
759sub options { 755sub options {
760 my ($self) = @_; 756 my ($self) = @_;
761 #warn "doing options in Problem"; 757 #warn "doing options in Problem";
762 758
763 # don't show options if we don't have anything to show 759 # don't show options if we don't have anything to show
790 my $setID = $self->{set}->set_id; 786 my $setID = $self->{set}->set_id;
791 my $eUserID = $r->param("effectiveUser"); 787 my $eUserID = $r->param("effectiveUser");
792 my @problemIDs = sort { $a <=> $b } $db->listUserProblems($eUserID, $setID); 788 my @problemIDs = sort { $a <=> $b } $db->listUserProblems($eUserID, $setID);
793 789
794 print CGI::start_div({class=>"info-box", id=>"fisheye"}); 790 print CGI::start_div({class=>"info-box", id=>"fisheye"});
795 print CGI::h2("Problems"); 791 print CGI::h2($r->maketext("Problems"));
796 #print CGI::start_ul({class=>"LinksMenu"}); 792 #print CGI::start_ul({class=>"LinksMenu"});
797 #print CGI::start_li(); 793 #print CGI::start_li();
798 #print CGI::span({style=>"font-size:larger"}, "Problems"); 794 #print CGI::span({style=>"font-size:larger"}, "Problems");
799 print CGI::start_ul(); 795 print CGI::start_ul();
800 796
801 foreach my $problemID (@problemIDs) { 797 foreach my $problemID (@problemIDs) {
802 my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", 798 my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", $r,
803 courseID => $courseID, setID => $setID, problemID => $problemID); 799 courseID => $courseID, setID => $setID, problemID => $problemID);
804 print CGI::li(CGI::a( {href=>$self->systemLink($problemPage, 800 print CGI::li(CGI::a( {href=>$self->systemLink($problemPage,
805 params=>{ displayMode => $self->{displayMode}, 801 params=>{ displayMode => $self->{displayMode},
806 showOldAnswers => $self->{will}->{showOldAnswers} 802 showOldAnswers => $self->{will}->{showOldAnswers}
807 })}, "Problem $problemID") 803 })}, $r->maketext("Problem [_1]",$problemID))
808 ); 804 );
809 } 805 }
810 806
811 print CGI::end_ul(); 807 print CGI::end_ul();
812 #print CGI::end_li(); 808 #print CGI::end_li();
842 } 838 }
843 839
844 my @links; 840 my @links;
845 841
846 if ($prevID) { 842 if ($prevID) {
847 my $prevPage = $urlpath->newFromModule(__PACKAGE__, 843 my $prevPage = $urlpath->newFromModule(__PACKAGE__, $r,
848 courseID => $courseID, setID => $setID, problemID => $prevID); 844 courseID => $courseID, setID => $setID, problemID => $prevID);
849 push @links, "Previous Problem", $r->location . $prevPage->path, "navPrev"; 845 push @links, $r->maketext("Previous Problem"), $r->location . $prevPage->path, $r->maketext("navPrev");
850 } else { 846 } else {
851 push @links, "Previous Problem", "", "navPrevGrey"; 847 push @links, $r->maketext("Previous Problem"), "", $r->maketext("navPrevGrey");
852 } 848 }
853 849
854 if (defined($setID) && $setID ne 'Undefined_Set') { 850 if (defined($setID) && $setID ne 'Undefined_Set') {
855 push @links, "Problem List", $r->location . $urlpath->parent->path, "navProbList"; 851 push @links, $r->maketext("Problem List"), $r->location . $urlpath->parent->path, $r->maketext("navProbList");
856 } else { 852 } else {
857 push @links, "Problem List", "", "navProbListGrey"; 853 push @links, $r->maketext("Problem List"), "", $r->maketext("navProbListGrey");
858 } 854 }
859 855
860 if ($nextID) { 856 if ($nextID) {
861 my $nextPage = $urlpath->newFromModule(__PACKAGE__, 857 my $nextPage = $urlpath->newFromModule(__PACKAGE__, $r,
862 courseID => $courseID, setID => $setID, problemID => $nextID); 858 courseID => $courseID, setID => $setID, problemID => $nextID);
863 push @links, "Next Problem", $r->location . $nextPage->path, "navNext"; 859 push @links, $r->maketext("Next Problem"), $r->location . $nextPage->path, $r->maketext("navNext");
864 } else { 860 } else {
865 push @links, "Next Problem", "", "navNextGrey"; 861 push @links, $r->maketext("Next Problem"), "", $r->maketext("navNextGrey");
866 } 862 }
867 863
868 my $tail = ""; 864 my $tail = "";
869 865
870 $tail .= "&displayMode=".$self->{displayMode} if defined $self->{displayMode}; 866 $tail .= "&displayMode=".$self->{displayMode} if defined $self->{displayMode};
873 return $self->navMacro($args, $tail, @links); 869 return $self->navMacro($args, $tail, @links);
874} 870}
875 871
876sub title { 872sub title {
877 my ($self) = @_; 873 my ($self) = @_;
878 874 my $r = $self->r;
879 # using the url arguments won't break if the set/problem are invalid 875 # using the url arguments won't break if the set/problem are invalid
880 my $setID = WeBWorK::ContentGenerator::underscore2nbsp($self->r->urlpath->arg("setID")); 876 my $setID = WeBWorK::ContentGenerator::underscore2nbsp($self->r->urlpath->arg("setID"));
881 my $problemID = $self->r->urlpath->arg("problemID"); 877 my $problemID = $self->r->urlpath->arg("problemID");
882 878
883 return "$setID: Problem $problemID"; 879 return $r->maketext("[_1]: Problem [_2]",$setID, $problemID);
884} 880}
885 881
886
887# now altered to outsource most output operations to the template, main functions now are simply error checking and answer processing - ghe3
888# sub body {
889# my $self = shift;
890# my $r = $self->r;
891# my $ce = $r->ce;
892# my $db = $r->db;
893# my $authz = $r->authz;
894# my $urlpath = $r->urlpath;
895# my $user = $r->param('user');
896# my $effectiveUser = $r->param('effectiveUser');
897# if ( $self->{invalidSet} ) {
898# return CGI::div({class=>"ResultsWithError"},
899# CGI::p("The selected problem set (" .
900# $urlpath->arg("setID") . ") is not " .
901# "a valid set for $effectiveUser:"),
902# CGI::p($self->{invalidSet}));
903# }
904#
905# if ($self->{invalidProblem}) {
906# return CGI::div({class=>"ResultsWithError"},
907# CGI::p("The selected problem (" . $urlpath->arg("problemID") . ") is not a valid problem for set " . $self->{set}->set_id . "."));
908# }
909#
910# # unpack some useful variables
911# my $set = $self->{set};
912# my $problem = $self->{problem};
913# my $editMode = $self->{editMode};
914# my $submitAnswers = $self->{submitAnswers};
915# my $checkAnswers = $self->{checkAnswers};
916# my $previewAnswers = $self->{previewAnswers};
917# my %want = %{ $self->{want} };
918# my %can = %{ $self->{can} };
919# my %must = %{ $self->{must} };
920# my %will = %{ $self->{will} };
921# my $pg = $self->{pg};
922#
923# my $courseName = $urlpath->arg("courseID");
924#
925# # FIXME: move editor link to top, next to problem number.
926# # format as "[edit]" like we're doing with course info file, etc.
927# # add edit link for set as well.
928# my $editorLink = "";
929# # if we are here without a real homework set, carry that through
930# my $forced_field = [];
931# $forced_field = ['sourceFilePath' => $r->param("sourceFilePath")] if
932# ($set->set_id eq 'Undefined_Set');
933# if ($authz->hasPermissions($user, "modify_problem_sets")) {
934# my $editorPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
935# courseID => $courseName, setID => $set->set_id, problemID => $problem->problem_id);
936# my $editorURL = $self->systemLink($editorPage, params=>$forced_field);
937# $editorLink = CGI::p(CGI::a({href=>$editorURL,target =>'WW_Editor'}, "Edit this problem"));
938# }
939#
940# ##### translation errors? #####
941#
942# if ($pg->{flags}->{error_flag}) {
943# if ($authz->hasPermissions($user, "view_problem_debugging_info")) {
944# print $self->errorOutput($pg->{errors}, $pg->{body_text});
945# } else {
946# print $self->errorOutput($pg->{errors}, "You do not have permission to view the details of this error.");
947# }
948# print $editorLink;
949# return "";
950# }
951#
952# ##### answer processing #####
953# debug("begin answer processing");
954# # if answers were submitted:
955# my $scoreRecordedMessage;
956# my $pureProblem;
957# if ($submitAnswers) {
958# # get a "pure" (unmerged) UserProblem to modify
959# # this will be undefined if the problem has not been assigned to this user
960# $pureProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); # checked
961# if (defined $pureProblem) {
962# # store answers in DB for sticky answers
963# my %answersToStore;
964# my %answerHash = %{ $pg->{answers} };
965# $answersToStore{$_} = $self->{formFields}->{$_} #$answerHash{$_}->{original_student_ans} -- this may have been modified for fields with multiple values. Don't use it!!
966# foreach (keys %answerHash);
967#
968# # There may be some more answers to store -- one which are auxiliary entries to a primary answer. Evaluating
969# # matrices works in this way, only the first answer triggers an answer evaluator, the rest are just inputs
970# # however we need to store them. Fortunately they are still in the input form.
971# my @extra_answer_names = @{ $pg->{flags}->{KEPT_EXTRA_ANSWERS}};
972# $answersToStore{$_} = $self->{formFields}->{$_} foreach (@extra_answer_names);
973#
974# # Now let's encode these answers to store them -- append the extra answers to the end of answer entry order
975# my @answer_order = (@{$pg->{flags}->{ANSWER_ENTRY_ORDER}}, @extra_answer_names);
976# my $answerString = encodeAnswers(%answersToStore,
977# @answer_order);
978#
979# # store last answer to database
980# $problem->last_answer($answerString);
981# $pureProblem->last_answer($answerString);
982# $db->putUserProblem($pureProblem);
983#
984# # store state in DB if it makes sense
985# if ($will{recordAnswers}) {
986# $problem->status($pg->{state}->{recorded_score});
987# $problem->sub_status($pg->{state}->{sub_recorded_score});
988# $problem->attempted(1);
989# $problem->num_correct($pg->{state}->{num_of_correct_ans});
990# $problem->num_incorrect($pg->{state}->{num_of_incorrect_ans});
991# $pureProblem->status($pg->{state}->{recorded_score});
992# $pureProblem->sub_status($pg->{state}->{sub_recorded_score});
993# $pureProblem->attempted(1);
994# $pureProblem->num_correct($pg->{state}->{num_of_correct_ans});
995# $pureProblem->num_incorrect($pg->{state}->{num_of_incorrect_ans});
996# if ($db->putUserProblem($pureProblem)) {
997# $scoreRecordedMessage = "Your score was recorded.";
998# } else {
999# $scoreRecordedMessage = "Your score was not recorded because there was a failure in storing the problem record to the database.";
1000# }
1001# # write to the transaction log, just to make sure
1002# writeLog($self->{ce}, "transaction",
1003# $problem->problem_id."\t".
1004# $problem->set_id."\t".
1005# $problem->user_id."\t".
1006# $problem->source_file."\t".
1007# $problem->value."\t".
1008# $problem->max_attempts."\t".
1009# $problem->problem_seed."\t".
1010# $pureProblem->status."\t".
1011# $pureProblem->attempted."\t".
1012# $pureProblem->last_answer."\t".
1013# $pureProblem->num_correct."\t".
1014# $pureProblem->num_incorrect
1015# );
1016# } else {
1017# if (before($set->open_date) or after($set->due_date)) {
1018# $scoreRecordedMessage = "Your score was not recorded because this homework set is closed.";
1019# } else {
1020# $scoreRecordedMessage = "Your score was not recorded.";
1021# }
1022# }
1023# } else {
1024# $scoreRecordedMessage = "Your score was not recorded because this problem has not been assigned to you.";
1025# }
1026# }
1027#
1028# # logging student answers
1029#
1030# my $answer_log = $self->{ce}->{courseFiles}->{logs}->{'answer_log'};
1031# if ( defined($answer_log ) and defined($pureProblem)) {
1032# if ($submitAnswers && !$authz->hasPermissions($effectiveUser, "dont_log_past_answers")) {
1033# my $answerString = ""; my $scores = "";
1034# my %answerHash = %{ $pg->{answers} };
1035# # FIXME this is the line 552 error. make sure original student ans is defined.
1036# # The fact that it is not defined is probably due to an error in some answer evaluator.
1037# # But I think it is useful to suppress this error message in the log.
1038# foreach (sortByName(undef, keys %answerHash)) {
1039# my $orig_ans = $answerHash{$_}->{original_student_ans};
1040# my $student_ans = defined $orig_ans ? $orig_ans : '';
1041# $answerString .= $student_ans."\t";
1042# $scores .= $answerHash{$_}->{score} >= 1 ? "1" : "0";
1043# }
1044# $answerString = '' unless defined($answerString); # insure string is defined.
1045# writeCourseLog($self->{ce}, "answer_log",
1046# join("",
1047# '|', $problem->user_id,
1048# '|', $problem->set_id,
1049# '|', $problem->problem_id,
1050# '|', $scores, "\t",
1051# time(),"\t",
1052# $answerString,
1053# ),
1054# );
1055#
1056# }
1057# }
1058#
1059# debug("end answer processing");
1060# ##### javaScripts #############
1061# my $site_url = $ce->{webworkURLs}->{htdocs};
1062# print CGI::start_script({type=>"text/javascript", src=>"$site_url/js/wz_tooltip.js"}), CGI::end_script();
1063#
1064# ##### output #####
1065# # custom message for editor
1066# if ($authz->hasPermissions($user, "modify_problem_sets") and defined $editMode) {
1067# if ($editMode eq "temporaryFile") {
1068# print CGI::p(CGI::div({class=>'temporaryFile'}, "Viewing temporary file: ", $problem->source_file));
1069# } elsif ($editMode eq "savedFile") {
1070# # taken care of in the initialization phase
1071# }
1072# }
1073# print CGI::start_div({class=>"problemHeader"});
1074#
1075#
1076#
1077# # attempt summary
1078# #FIXME -- the following is a kludge: if showPartialCorrectAnswers is negative don't show anything.
1079# # until after the due date
1080# # do I need to check $will{showCorrectAnswers} to make preflight work??
1081# if (($pg->{flags}->{showPartialCorrectAnswers} >= 0 and $submitAnswers) ) {
1082# # print this if user submitted answers OR requested correct answers
1083#
1084# print $self->attemptResults($pg, 1,
1085# $will{showCorrectAnswers},
1086# $pg->{flags}->{showPartialCorrectAnswers}, 1, 1);
1087# } elsif ($checkAnswers) {
1088# # print this if user previewed answers
1089# print CGI::div({class=>'ResultsWithError'},"ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED"), CGI::br();
1090# print $self->attemptResults($pg, 1, $will{showCorrectAnswers}, 1, 1, 1);
1091# # show attempt answers
1092# # show correct answers if asked
1093# # show attempt results (correctness)
1094# # show attempt previews
1095# } elsif ($previewAnswers) {
1096# # print this if user previewed answers
1097# print CGI::div({class=>'ResultsWithError'},"PREVIEW ONLY -- ANSWERS NOT RECORDED"),CGI::br(),$self->attemptResults($pg, 1, 0, 0, 0, 1);
1098# # show attempt answers
1099# # don't show correct answers
1100# # don't show attempt results (correctness)
1101# # show attempt previews
1102# }
1103#
1104# print CGI::end_div();
1105#
1106#
1107# ###########################
1108# # print style sheet for correct and incorrect answers
1109# ###########################
1110# # always show colors for checkAnswers
1111# # show colors for submit answer if
1112# if (($self->{checkAnswers}) or ($self->{submitAnswers} and $pg->{flags}->{showPartialCorrectAnswers}) ) {
1113# print CGI::start_style({type=>"text/css"});
1114# #FIXME -- this hack is no longer needed?
1115# # my $string ="";
1116# # foreach my $ans_name (@{ $self->{correct_ids} }) {
1117# # $string .= '#'. ( $ans_name ). $ce->{pg}{options}{correct_answer}."\n";
1118# # }
1119# # print $string;
1120# # $string ="";
1121# # foreach my $ans_name (@{ $self->{incorrect_ids} }) {
1122# # $string .= '#'. ($ ans_name). $ce->{pg}{options}{incorrect_answer}."\n";
1123# # }
1124# # print $string;
1125# # the above method keeps one bad array ID from ruining all of the assignments.
1126# print '#'.join(', #', @{ $self->{correct_ids} }), $ce->{pg}{options}{correct_answer},"\n" if ref( $self->{correct_ids} )=~/ARRAY/; #correct green
1127# print '#'.join(', #', @{ $self->{incorrect_ids} }), $ce->{pg}{options}{incorrect_answer},"\n" if ref( $self->{incorrect_ids})=~/ARRAY/; #incorrect reddish
1128# print CGI::end_style();
1129# }
1130# ###########################
1131# # post_header material
1132# ###########################
1133# print CGI::p($pg->{post_header_text});
1134# ###########################
1135# # main form
1136# ###########################
1137# print "\n";
1138#
1139# print CGI::start_form(-method=>"POST", -action=> $r->uri,-name=>"problemMainForm", onsubmit=>"submitAction()");
1140# print $self->hidden_authen_fields;
1141# print "\n";
1142# print CGI::start_div({class=>"problem"});
1143# print CGI::p($pg->{body_text});
1144# print CGI::p(CGI::b("Note: "). CGI::i($pg->{result}->{msg})) if $pg->{result}->{msg};
1145# print $editorLink; # this is empty unless it is appropriate to have an editor link.
1146# print CGI::end_div();
1147#
1148# print CGI::start_p();
1149#
1150# if ($can{showCorrectAnswers}) {
1151# print CGI::checkbox(
1152# -name => "showCorrectAnswers",
1153# -checked => $will{showCorrectAnswers},
1154# -label => "Show correct answers",
1155# -value => 1,
1156# );
1157# }
1158# if ($can{showHints}) {
1159# print CGI::div({style=>"color:red"},
1160# CGI::checkbox(
1161# -name => "showHints",
1162# -checked => $will{showHints},
1163# -label => "Show Hints",
1164# -value =>1,
1165# )
1166# );
1167# }
1168# if ($can{showSolutions}) {
1169# print CGI::checkbox(
1170# -name => "showSolutions",
1171# -checked => $will{showSolutions},
1172# -label => "Show Solutions",
1173# -value => 1,
1174# );
1175# }
1176#
1177# if ($can{showCorrectAnswers} or $can{showHints} or $can{showSolutions}) {
1178# print CGI::br();
1179# }
1180#
1181# print CGI::submit(-name=>"previewAnswers", -label=>"Preview Answers");
1182# if ($can{checkAnswers}) {
1183# print CGI::submit(-name=>"checkAnswers", -label=>"Check Answers");
1184# }
1185# if ($can{getSubmitButton}) {
1186# if ($user ne $effectiveUser) {
1187# # if acting as a student, make it clear that answer submissions will
1188# # apply to the student's records, not the professor's.
1189# print CGI::submit(-name=>"submitAnswers", -label=>"Submit Answers for $effectiveUser");
1190# } else {
1191# #print CGI::submit(-name=>"submitAnswers", -label=>"Submit Answers", -onclick=>"alert('submit button clicked')");
1192# print CGI::submit(-name=>"submitAnswers", -label=>"Submit Answers", -onclick=>"");
1193# # FIXME for unknown reasons the -onclick label seems to have to be there in order to allow the forms onsubmit to trigger
1194# # WFT???
1195# }
1196# }
1197#
1198# print CGI::end_p();
1199#
1200# print CGI::start_div({class=>"scoreSummary"});
1201#
1202# # score summary
1203# my $attempts = $problem->num_correct + $problem->num_incorrect;
1204# my $attemptsNoun = $attempts != 1 ? "times" : "time";
1205# my $problem_status = $problem->status || 0;
1206# my $lastScore = sprintf("%.0f%%", $problem_status * 100); # Round to whole number
1207# my ($attemptsLeft, $attemptsLeftNoun);
1208# if ($problem->max_attempts == -1) {
1209# # unlimited attempts
1210# $attemptsLeft = "unlimited";
1211# $attemptsLeftNoun = "attempts";
1212# } else {
1213# $attemptsLeft = $problem->max_attempts - $attempts;
1214# $attemptsLeftNoun = $attemptsLeft == 1 ? "attempt" : "attempts";
1215# }
1216#
1217# my $setClosed = 0;
1218# my $setClosedMessage;
1219# if (before($set->open_date) or after($set->due_date)) {
1220# $setClosed = 1;
1221# if (before($set->open_date)) {
1222# $setClosedMessage = "This homework set is not yet open.";
1223# } elsif (after($set->due_date)) {
1224# $setClosedMessage = "This homework set is closed.";
1225# }
1226# }
1227# #if (before($set->open_date) or after($set->due_date)) {
1228# # $setClosed = 1;
1229# # $setClosedMessage = "This homework set is closed.";
1230# # if ($authz->hasPermissions($user, "view_answers")) {
1231# # $setClosedMessage .= " However, since you are a privileged user, additional attempts will be recorded.";
1232# # } else {
1233# # $setClosedMessage .= " Additional attempts will not be recorded.";
1234# # }
1235# #}
1236# unless (defined( $pg->{state}->{state_summary_msg}) and $pg->{state}->{state_summary_msg}=~/\S/) {
1237# my $notCountedMessage = ($problem->value) ? "" : "(This problem will not count towards your grade.)";
1238# print CGI::p(join("",
1239# $submitAnswers ? $scoreRecordedMessage . CGI::br() : "",
1240# "You have attempted this problem $attempts $attemptsNoun.", CGI::br(),
1241# $submitAnswers ?"You received a score of ".sprintf("%.0f%%", $pg->{result}->{score} * 100)." for this attempt.".CGI::br():'',
1242# $problem->attempted
1243# ? "Your overall recorded score is $lastScore. $notCountedMessage" . CGI::br()
1244# : "",
1245# $setClosed ? $setClosedMessage : "You have $attemptsLeft $attemptsLeftNoun remaining."
1246# ));
1247# }else {
1248# print CGI::p($pg->{state}->{state_summary_msg});
1249# }
1250#
1251# print CGI::end_div();
1252# print CGI::start_div();
1253#
1254# my $pgdebug = join(CGI::br(), @{$pg->{pgcore}->{flags}->{DEBUG_messages}} );
1255# my $pgwarning = join(CGI::br(), @{$pg->{pgcore}->{flags}->{WARNING_messages}} );
1256# my $pginternalerrors = join(CGI::br(), @{$pg->{pgcore}->get_internal_debug_messages} );
1257# my $pgerrordiv = $pgdebug||$pgwarning||$pginternalerrors; # is 1 if any of these are non-empty
1258#
1259# print CGI::p({style=>"color:red;"}, "Checking additional error messages") if $pgerrordiv ;
1260# print CGI::p("pg debug<br/> $pgdebug" ) if $pgdebug ;
1261# print CGI::p("pg warning<br/>$pgwarning" ) if $pgwarning ;
1262# print CGI::p("pg internal errors<br/> $pginternalerrors") if $pginternalerrors;
1263# print CGI::end_div() if $pgerrordiv ;
1264#
1265# # save state for viewOptions
1266# print CGI::hidden(
1267# -name => "showOldAnswers",
1268# -value => $will{showOldAnswers}
1269# ),
1270#
1271# CGI::hidden(
1272# -name => "displayMode",
1273# -value => $self->{displayMode}
1274# );
1275# print( CGI::hidden(
1276# -name => 'editMode',
1277# -value => $self->{editMode},
1278# )
1279# ) if defined($self->{editMode}) and $self->{editMode} eq 'temporaryFile';
1280#
1281# # this is a security risk -- students can use this to find the source code for the problem
1282#
1283# my $permissionLevel = $db->getPermissionLevel($user)->permission;
1284# my $professorPermissionLevel = $ce->{userRoles}->{professor};
1285# print( CGI::hidden(
1286# -name => 'sourceFilePath',
1287# -value => $self->{problem}->{source_file}
1288# )) if defined($self->{problem}->{source_file}) and $permissionLevel>= $professorPermissionLevel; # only allow this for professors
1289#
1290# print( CGI::hidden(
1291# -name => 'problemSeed',
1292# -value => $r->param("problemSeed")
1293# )) if defined($r->param("problemSeed")) and $permissionLevel>= $professorPermissionLevel; # only allow this for professors
1294#
1295#
1296# # end of main form
1297# print CGI::endform();
1298#
1299# print CGI::start_div({class=>"problemFooter"});
1300#
1301#
1302# my $pastAnswersPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::ShowAnswers",
1303# courseID => $courseName);
1304# my $showPastAnswersURL = $self->systemLink($pastAnswersPage, authen => 0); # no authen info for form action
1305#
1306# # print answer inspection button
1307# if ($authz->hasPermissions($user, "view_answers")) {
1308# print "\n",
1309# CGI::start_form(-method=>"POST",-action=>$showPastAnswersURL,-target=>"WW_Info"),"\n",
1310# $self->hidden_authen_fields,"\n",
1311# CGI::hidden(-name => 'courseID', -value=>$courseName), "\n",
1312# CGI::hidden(-name => 'problemID', -value=>$problem->problem_id), "\n",
1313# CGI::hidden(-name => 'setID', -value=>$problem->set_id), "\n",
1314# CGI::hidden(-name => 'studentUser', -value=>$problem->user_id), "\n",
1315# CGI::p( {-align=>"left"},
1316# CGI::submit(-name => 'action', -value=>'Show Past Answers')
1317# ), "\n",
1318# CGI::endform();
1319# }
1320#
1321#
1322# print $self->feedbackMacro(
1323# module => __PACKAGE__,
1324# set => $self->{set}->set_id,
1325# problem => $problem->problem_id,
1326# displayMode => $self->{displayMode},
1327# showOldAnswers => $will{showOldAnswers},
1328# showCorrectAnswers => $will{showCorrectAnswers},
1329# showHints => $will{showHints},
1330# showSolutions => $will{showSolutions},
1331# pg_object => $pg,
1332# );
1333#
1334# print CGI::end_div();
1335#
1336# # debugging stuff
1337# if (0) {
1338# print
1339# CGI::hr(),
1340# CGI::h2("debugging information"),
1341# CGI::h3("form fields"),
1342# ref2string($self->{formFields}),
1343# CGI::h3("user object"),
1344# ref2string($self->{user}),
1345# CGI::h3("set object"),
1346# ref2string($set),
1347# CGI::h3("problem object"),
1348# ref2string($problem),
1349# CGI::h3("PG object"),
1350# ref2string($pg, {'WeBWorK::PG::Translator' => 1});
1351# }
1352# debug("leaving body of Problem.pm");
1353# return "";
1354# }
1355
1356# now altered to outsource most output operations to the template, main functions now are simply error checking and answer processing - ghe3
1357sub body { 882sub body {
1358 my $self = shift; 883 my $self = shift;
884 my $r = $self->r;
885 my $ce = $r->ce;
886 my $db = $r->db;
887 my $authz = $r->authz;
888 my $urlpath = $r->urlpath;
889 my $user = $r->param('user');
890 my $effectiveUser = $r->param('effectiveUser');
891
892 if ( $self->{invalidSet} ) {
893 return CGI::div({class=>"ResultsWithError"},
894 CGI::p($r->maketext("The selected problem set ([_1]) is not a valid set for [_2]:", $urlpath->arg("setID"), $effectiveUser)), CGI::p($self->{invalidSet}));
895 }
896
897 if ($self->{invalidProblem}) {
898 return CGI::div({class=>"ResultsWithError"},
899 CGI::p($r->maketext("The selected problem([_1]) is not a valid problem for set [_2].", $urlpath->arg("problemID"), $self->{set}->set_id )));
900 }
901
902 # unpack some useful variables
1359 my $set = $self->{set}; 903 my $set = $self->{set};
1360 my $problem = $self->{problem}; 904 my $problem = $self->{problem};
905 my $editMode = $self->{editMode};
906 my $submitAnswers = $self->{submitAnswers};
907 my $checkAnswers = $self->{checkAnswers};
908 my $previewAnswers = $self->{previewAnswers};
909 my %want = %{ $self->{want} };
910 my %can = %{ $self->{can} };
911 my %must = %{ $self->{must} };
912 my %will = %{ $self->{will} };
1361 my $pg = $self->{pg}; 913 my $pg = $self->{pg};
1362 914
1363 my $valid = WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::check_invalid($self); 915 my $courseName = $urlpath->arg("courseID");
1364 unless($valid eq "valid"){ 916
1365 return $valid; 917 # FIXME: move editor link to top, next to problem number.
918 # format as "[edit]" like we're doing with course info file, etc.
919 # add edit link for set as well.
920 my $editorLink = "";
921 # if we are here without a real homework set, carry that through
922 my $forced_field = [];
923 $forced_field = ['sourceFilePath' => $r->param("sourceFilePath")] if
924 ($set->set_id eq 'Undefined_Set');
925 if ($authz->hasPermissions($user, "modify_problem_sets")) {
926 my $editorPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", $r,
927 courseID => $courseName, setID => $set->set_id, problemID => $problem->problem_id);
928 my $editorURL = $self->systemLink($editorPage, params=>$forced_field);
929 $editorLink = CGI::p(CGI::a({href=>$editorURL,target =>'WW_Editor'}, "Edit this problem"));
930 }
931
932 ##### translation errors? #####
933
934 if ($pg->{flags}->{error_flag}) {
935 if ($authz->hasPermissions($user, "view_problem_debugging_info")) {
936 print $self->errorOutput($pg->{errors}, $pg->{body_text});
937 } else {
938 print $self->errorOutput($pg->{errors}, $r->maketext("You do not have permission to view the details of this error."));
1366 } 939 }
1367 940 print $editorLink;
1368 ####################################################
1369 # Move to header in new templates
1370 #print $self->output_tabber_JS();
1371 print $self->output_coloring_JS();
1372
1373 ##### javaScripts #############
1374 # WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::output_JS($self);
1375 print $self->output_JS;
1376
1377 ####################################################
1378
1379 # my $editorLink = WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::process_editorLink($self);
1380 # if($editorLink eq "permission_error"){
1381 # return ""; 941 return "";
1382 # } 942 }
1383
1384 943
1385 ##### answer processing ##### 944 ##### answer processing #####
1386 debug("begin answer processing"); 945 debug("begin answer processing");
1387 # if answers were submitted: 946 # if answers were submitted:
1388 my $scoreRecordedMessage = WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::process_and_log_answer($self); 947 my $scoreRecordedMessage;
948 my $pureProblem;
949 if ($submitAnswers) {
950 # get a "pure" (unmerged) UserProblem to modify
951 # this will be undefined if the problem has not been assigned to this user
952 $pureProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); # checked
953 if (defined $pureProblem) {
954 # store answers in DB for sticky answers
955 my %answersToStore;
956 my %answerHash = %{ $pg->{answers} };
957 $answersToStore{$_} = $self->{formFields}->{$_} #$answerHash{$_}->{original_student_ans} -- this may have been modified for fields with multiple values. Don't use it!!
958 foreach (keys %answerHash);
959
960 # There may be some more answers to store -- one which are auxiliary entries to a primary answer. Evaluating
961 # matrices works in this way, only the first answer triggers an answer evaluator, the rest are just inputs
962 # however we need to store them. Fortunately they are still in the input form.
963 my @extra_answer_names = @{ $pg->{flags}->{KEPT_EXTRA_ANSWERS}};
964 $answersToStore{$_} = $self->{formFields}->{$_} foreach (@extra_answer_names);
965
966 # Now let's encode these answers to store them -- append the extra answers to the end of answer entry order
967 my @answer_order = (@{$pg->{flags}->{ANSWER_ENTRY_ORDER}}, @extra_answer_names);
968 my $answerString = encodeAnswers(%answersToStore,
969 @answer_order);
970
971 # store last answer to database
972 $problem->last_answer($answerString);
973 $pureProblem->last_answer($answerString);
974 $db->putUserProblem($pureProblem);
975
976 # store state in DB if it makes sense
977 if ($will{recordAnswers}) {
978 $problem->status($pg->{state}->{recorded_score});
979 $problem->sub_status($pg->{state}->{sub_recorded_score});
980 $problem->attempted(1);
981 $problem->num_correct($pg->{state}->{num_of_correct_ans});
982 $problem->num_incorrect($pg->{state}->{num_of_incorrect_ans});
983 $pureProblem->status($pg->{state}->{recorded_score});
984 $pureProblem->sub_status($pg->{state}->{sub_recorded_score});
985 $pureProblem->attempted(1);
986 $pureProblem->num_correct($pg->{state}->{num_of_correct_ans});
987 $pureProblem->num_incorrect($pg->{state}->{num_of_incorrect_ans});
988 if ($db->putUserProblem($pureProblem)) {
989 $scoreRecordedMessage = $r->maketext("Your score was recorded.");
990 } else {
991 $scoreRecordedMessage = $r->maketext("Your score was not recorded because there was a failure in storing the problem record to the database.");
992 }
993 # write to the transaction log, just to make sure
994 writeLog($self->{ce}, "transaction",
995 $problem->problem_id."\t".
996 $problem->set_id."\t".
997 $problem->user_id."\t".
998 $problem->source_file."\t".
999 $problem->value."\t".
1000 $problem->max_attempts."\t".
1001 $problem->problem_seed."\t".
1002 $pureProblem->status."\t".
1003 $pureProblem->attempted."\t".
1004 $pureProblem->last_answer."\t".
1005 $pureProblem->num_correct."\t".
1006 $pureProblem->num_incorrect
1007 );
1008 } else {
1009 if (before($set->open_date) or after($set->due_date)) {
1010 $scoreRecordedMessage = $r->maketext("Your score was not recorded because this homework set is closed.");
1011 } else {
1012 $scoreRecordedMessage = $r->maketext("Your score was not recorded.");
1013 }
1014 }
1015 } else {
1016 $scoreRecordedMessage = $r->maketext("Your score was not recorded because this problem has not been assigned to you.");
1017 }
1018 }
1019
1020 # logging student answers
1021
1022 my $answer_log = $self->{ce}->{courseFiles}->{logs}->{'answer_log'};
1023 if ( defined($answer_log ) and defined($pureProblem)) {
1024 if ($submitAnswers && !$authz->hasPermissions($effectiveUser, "dont_log_past_answers")) {
1025 my $answerString = ""; my $scores = "";
1026 my %answerHash = %{ $pg->{answers} };
1027 # FIXME this is the line 552 error. make sure original student ans is defined.
1028 # The fact that it is not defined is probably due to an error in some answer evaluator.
1029 # But I think it is useful to suppress this error message in the log.
1030 foreach (sortByName(undef, keys %answerHash)) {
1031 my $orig_ans = $answerHash{$_}->{original_student_ans};
1032 my $student_ans = defined $orig_ans ? $orig_ans : '';
1033 $answerString .= $student_ans."\t";
1034 $scores .= $answerHash{$_}->{score} >= 1 ? "1" : "0";
1035 }
1036 $answerString = '' unless defined($answerString); # insure string is defined.
1037 writeCourseLog($self->{ce}, "answer_log",
1038 join("",
1039 '|', $problem->user_id,
1040 '|', $problem->set_id,
1041 '|', $problem->problem_id,
1042 '|', $scores, "\t",
1043 time(),"\t",
1044 $answerString,
1045 ),
1046 );
1047
1048 }
1049 }
1050
1389 debug("end answer processing"); 1051 debug("end answer processing");
1052 ##### javaScripts #############
1053 my $site_url = $ce->{webworkURLs}->{htdocs};
1054 print CGI::start_script({type=>"text/javascript", src=>"$site_url/js/wz_tooltip.js"}), CGI::end_script();
1055
1056 ##### output #####
1057 # custom message for editor
1058 if ($authz->hasPermissions($user, "modify_problem_sets") and defined $editMode) {
1059 if ($editMode eq "temporaryFile") {
1060 print CGI::p(CGI::div({class=>'temporaryFile'}, $r->maketext("Viewing temporary file: "), $problem->source_file));
1061 } elsif ($editMode eq "savedFile") {
1062 # taken care of in the initialization phase
1063 }
1064 }
1065 print CGI::start_div({class=>"problemHeader"});
1066
1067
1068
1069 # attempt summary
1070 #FIXME -- the following is a kludge: if showPartialCorrectAnswers is negative don't show anything.
1071 # until after the due date
1072 # do I need to check $will{showCorrectAnswers} to make preflight work??
1073 if (($pg->{flags}->{showPartialCorrectAnswers} >= 0 and $submitAnswers) ) {
1074 # print this if user submitted answers OR requested correct answers
1075
1076 print $self->attemptResults($pg, 1,
1077 $will{showCorrectAnswers},
1078 $pg->{flags}->{showPartialCorrectAnswers}, 1, 1);
1079 } elsif ($checkAnswers) {
1080 # print this if user previewed answers
1081 print CGI::div({class=>'ResultsWithError'},$r->maketext("ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED")), CGI::br();
1082 print $self->attemptResults($pg, 1, $will{showCorrectAnswers}, 1, 1, 1);
1083 # show attempt answers
1084 # show correct answers if asked
1085 # show attempt results (correctness)
1086 # show attempt previews
1087 } elsif ($previewAnswers) {
1088 # print this if user previewed answers
1089 print CGI::div({class=>'ResultsWithError'},$r->maketext("PREVIEW ONLY -- ANSWERS NOT RECORDED")),CGI::br(),$self->attemptResults($pg, 1, 0, 0, 0, 1);
1090 # show attempt answers
1091 # don't show correct answers
1092 # don't show attempt results (correctness)
1093 # show attempt previews
1094 }
1095
1096 print CGI::end_div();
1097
1390 1098
1391 ########################### 1099 ###########################
1392 # print style sheet for correct and incorrect answers 1100 # print style sheet for correct and incorrect answers
1393 ########################### 1101 ###########################
1394 1102 # always show colors for checkAnswers
1395 # WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::output_CSS($self); 1103 # show colors for submit answer if
1396 print $self->output_CSS; 1104 if (($self->{checkAnswers}) or ($self->{submitAnswers} and $pg->{flags}->{showPartialCorrectAnswers}) ) {
1397 1105 print CGI::start_style({type=>"text/css"});
1398 1106 #FIXME -- this hack is no longer needed?
1107 # my $string ="";
1108# foreach my $ans_name (@{ $self->{correct_ids} }) {
1109# $string .= '#'. ( $ans_name ). $ce->{pg}{options}{correct_answer}."\n";
1110# }
1111# print $string;
1112# $string ="";
1113# foreach my $ans_name (@{ $self->{incorrect_ids} }) {
1114# $string .= '#'. ($ ans_name). $ce->{pg}{options}{incorrect_answer}."\n";
1115# }
1116# print $string;
1117 # the above method keeps one bad array ID from ruining all of the assignments.
1118 print '#'.join(', #', @{ $self->{correct_ids} }), $ce->{pg}{options}{correct_answer},"\n" if ref( $self->{correct_ids} )=~/ARRAY/; #correct green
1119 print '#'.join(', #', @{ $self->{incorrect_ids} }), $ce->{pg}{options}{incorrect_answer},"\n" if ref( $self->{incorrect_ids})=~/ARRAY/; #incorrect reddish
1120 print CGI::end_style();
1121 }
1399 ########################### 1122 ###########################
1400 # post_header material 1123 # post_header material
1401
1402 #FIXME -- this should be pulled by the template.
1403 ########################### 1124 ###########################
1404 print CGI::p($pg->{post_header_text}); 1125 print CGI::p($pg->{post_header_text});
1405
1406
1407 ##### output #####
1408 # WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::output_summary($self);
1409 print $self->output_custom_edit_message();
1410 print $self->output_summary();
1411 print $self->output_form_start();
1412 print $self->output_problem_body();
1413 print $self->output_message();
1414 print $self->output_editorLink();
1415 print $self->output_checkboxes();
1416 print $self->output_submit_buttons();
1417 print $self->output_score_summary();
1418 print $self->output_misc();
1419 print "\n</form>\n";
1420
1421
1422 $self->output_email_instructor();
1423 $self->output_past_answer_button();
1424
1425
1426#
1427#
1428# ########################### 1126 ###########################
1429# # main form 1127 # main form
1430# ########################### 1128 ###########################
1431# 1129 print "\n";
1432# # WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::output_main_form($self,$editorLink); 1130
1433# 1131 print CGI::start_form(-method=>"POST", -action=> $r->uri,-name=>"problemMainForm", onsubmit=>"submitAction()");
1434# # WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::output_footer($self); 1132 print $self->hidden_authen_fields;
1133 print "\n";
1134 print CGI::start_div({class=>"problem"});
1135 print CGI::p($pg->{body_text});
1136 print CGI::p(CGI::b("Note: "). CGI::i($pg->{result}->{msg})) if $pg->{result}->{msg};
1137 print $editorLink; # this is empty unless it is appropriate to have an editor link.
1138 print CGI::end_div();
1139
1140 print CGI::start_p();
1141
1142 if ($can{showCorrectAnswers}) {
1143 print CGI::checkbox(
1144 -name => "showCorrectAnswers",
1145 -checked => $will{showCorrectAnswers},
1146 -label => $r->maketext("Show correct answers"),
1147 -value => 1,
1148 );
1149 }
1150 if ($can{showHints}) {
1151 print CGI::div({style=>"color:red"},
1152 CGI::checkbox(
1153 -name => "showHints",
1154 -checked => $will{showHints},
1155 -label => $r->maketext("Show Hints"),
1156 -value =>1,
1157 )
1158 );
1159 }
1160 if ($can{showSolutions}) {
1161 print CGI::checkbox(
1162 -name => "showSolutions",
1163 -checked => $will{showSolutions},
1164 -label => $r->maketext("Show Solutions"),
1165 -value => 1,
1166 );
1167 }
1168
1169 if ($can{showCorrectAnswers} or $can{showHints} or $can{showSolutions}) {
1170 print CGI::br();
1171 }
1172
1173 print CGI::submit(-name=>"previewAnswers", -label=>$r->maketext("Preview Answers"));
1174 if ($can{checkAnswers}) {
1175 print CGI::submit(-name=>"checkAnswers", -label=>$r->maketext("Check Answers"));
1176 }
1177 if ($can{getSubmitButton}) {
1178 if ($user ne $effectiveUser) {
1179 # if acting as a student, make it clear that answer submissions will
1180 # apply to the student's records, not the professor's.
1181 print CGI::submit(-name=>"submitAnswers", -label=>$r->maketext("Submit answers for [_1]",$effectiveUser));
1182 } else {
1183 #print CGI::submit(-name=>"submitAnswers", -label=>"Submit Answers", -onclick=>"alert('submit button clicked')");
1184 print CGI::submit(-name=>"submitAnswers", -label=>$r->maketext("Submit answers"), -onclick=>"");
1185 # FIXME for unknown reasons the -onclick label seems to have to be there in order to allow the forms onsubmit to trigger
1186 # WTF???
1187 }
1188 }
1189
1190 print CGI::end_p();
1191
1192 print CGI::start_div({class=>"scoreSummary"});
1193
1194 # score summary
1195 my $attempts = $problem->num_correct + $problem->num_incorrect;
1196 #my $attemptsNoun = $attempts != 1 ? $r->maketext("times") : $r->maketext("time");
1197 my $problem_status = $problem->status || 0;
1198 my $lastScore = sprintf("%.0f%%", $problem_status * 100); # Round to whole number
1199 #my ($attemptsLeft, $attemptsLeftNoun);
1200 my $attemptsLeft = $problem->max_attempts - $attempts;
1201# if ($problem->max_attempts == -1) {
1202# # unlimited attempts
1203# $attemptsLeft = $r->maketext("unlimited");
1204# $attemptsLeftNoun = $r->maketext("attempts");
1205# } else {
1206# $attemptsLeft = $problem->max_attempts - $attempts;
1207# $attemptsLeftNoun = $attemptsLeft == 1 ? $r->maketext("attempt") : $r->maketext("attempts");
1208# }
1209
1210 my $setClosed = 0;
1211 my $setClosedMessage;
1212 if (before($set->open_date) or after($set->due_date)) {
1213 $setClosed = 1;
1214 if (before($set->open_date)) {
1215 $setClosedMessage = $r->maketext("This homework set is not yet open.");
1216 } elsif (after($set->due_date)) {
1217 $setClosedMessage = $r->maketext("This homework set is closed.");
1218 }
1219 }
1220 #if (before($set->open_date) or after($set->due_date)) {
1221 # $setClosed = 1;
1222 # $setClosedMessage = "This homework set is closed.";
1223 # if ($authz->hasPermissions($user, "view_answers")) {
1224 # $setClosedMessage .= " However, since you are a privileged user, additional attempts will be recorded.";
1225 # } else {
1226 # $setClosedMessage .= " Additional attempts will not be recorded.";
1227 # }
1228 #}
1229 unless (defined( $pg->{state}->{state_summary_msg}) and $pg->{state}->{state_summary_msg}=~/\S/) {
1230 my $notCountedMessage = ($problem->value) ? "" : $r->maketext("(This problem will not count towards your grade.)");
1231 print CGI::p(join("",
1232 $submitAnswers ? $scoreRecordedMessage . CGI::br() : "",
1233 $r->maketext("You have attempted this problem [quant,_1,time,times].",$attempts), CGI::br(),
1234 $submitAnswers ? $r->maketext("You received a score of [_1] for this attempt.",sprintf("%.0f%%", $pg->{result}->{score} * 100)) . CGI::br():'',
1235 $problem->attempted
1236 ? $r->maketext("Your overall recorded score is [_1]. [_2]",$lastScore,$notCountedMessage) . CGI::br()
1237 : "",
1238# $setClosed ? $setClosedMessage : $r->maketext("You have [_1] [_2] remaining.",$attemptsLeft,$attemptsLeftNoun)
1239 $setClosed ? $setClosedMessage : $r->maketext("You have [negquant,_1,unlimited attempts,attempt,attempts] remaining.",$attemptsLeft)
1240 ));
1241 }else {
1242 print CGI::p($pg->{state}->{state_summary_msg});
1243 }
1244
1245 print CGI::end_div();
1246 print CGI::start_div();
1247
1248 my $pgdebug = join(CGI::br(), @{$pg->{pgcore}->{flags}->{DEBUG_messages}} );
1249 my $pgwarning = join(CGI::br(), @{$pg->{pgcore}->{flags}->{WARNING_messages}} );
1250 my $pginternalerrors = join(CGI::br(), @{$pg->{pgcore}->get_internal_debug_messages} );
1251 my $pgerrordiv = $pgdebug||$pgwarning||$pginternalerrors; # is 1 if any of these are non-empty
1252
1253 print CGI::p({style=>"color:red;"}, "Checking additional error messages") if $pgerrordiv ;
1254 print CGI::p("pg debug<br/> $pgdebug" ) if $pgdebug ;
1255 print CGI::p("pg warning<br/>$pgwarning" ) if $pgwarning ;
1256 print CGI::p("pg internal errors<br/> $pginternalerrors") if $pginternalerrors;
1257 print CGI::end_div() if $pgerrordiv ;
1258
1259 # save state for viewOptions
1260 print CGI::hidden(
1261 -name => "showOldAnswers",
1262 -value => $will{showOldAnswers}
1263 ),
1264
1265 CGI::hidden(
1266 -name => "displayMode",
1267 -value => $self->{displayMode}
1268 );
1269 print( CGI::hidden(
1270 -name => 'editMode',
1271 -value => $self->{editMode},
1272 )
1273 ) if defined($self->{editMode}) and $self->{editMode} eq 'temporaryFile';
1274
1275 # this is a security risk -- students can use this to find the source code for the problem
1276
1277 my $permissionLevel = $db->getPermissionLevel($user)->permission;
1278 my $professorPermissionLevel = $ce->{userRoles}->{professor};
1279 print( CGI::hidden(
1280 -name => 'sourceFilePath',
1281 -value => $self->{problem}->{source_file}
1282 )) if defined($self->{problem}->{source_file}) and $permissionLevel>= $professorPermissionLevel; # only allow this for professors
1283
1284 print( CGI::hidden(
1285 -name => 'problemSeed',
1286 -value => $r->param("problemSeed")
1287 )) if defined($r->param("problemSeed")) and $permissionLevel>= $professorPermissionLevel; # only allow this for professors
1288
1289
1290 # end of main form
1291 print CGI::endform();
1292
1293 print CGI::start_div({class=>"problemFooter"});
1294
1295
1296 my $pastAnswersPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::ShowAnswers", $r,
1297 courseID => $courseName);
1298 my $showPastAnswersURL = $self->systemLink($pastAnswersPage, authen => 0); # no authen info for form action
1299
1300 # print answer inspection button
1301 if ($authz->hasPermissions($user, "view_answers")) {
1302 print "\n",
1303 CGI::start_form(-method=>"POST",-action=>$showPastAnswersURL,-target=>"WW_Info"),"\n",
1304 $self->hidden_authen_fields,"\n",
1305 CGI::hidden(-name => 'courseID', -value=>$courseName), "\n",
1306 CGI::hidden(-name => 'problemID', -value=>$problem->problem_id), "\n",
1307 CGI::hidden(-name => 'setID', -value=>$problem->set_id), "\n",
1308 CGI::hidden(-name => 'studentUser', -value=>$problem->user_id), "\n",
1309 CGI::p( {-align=>"left"},
1310 CGI::submit(-name => 'action', -value=>$r->maketext("Show Past Answers"))
1311 ), "\n",
1312 CGI::endform();
1313 }
1314
1315
1316 print $self->feedbackMacro(
1317 module => __PACKAGE__,
1318 set => $self->{set}->set_id,
1319 problem => $problem->problem_id,
1320 displayMode => $self->{displayMode},
1321 showOldAnswers => $will{showOldAnswers},
1322 showCorrectAnswers => $will{showCorrectAnswers},
1323 showHints => $will{showHints},
1324 showSolutions => $will{showSolutions},
1325 pg_object => $pg,
1326 );
1327
1328 print CGI::end_div();
1435 1329
1436 # debugging stuff 1330 # debugging stuff
1437 if (0) { 1331 if (0) {
1438 print 1332 print
1439 CGI::hr(), 1333 CGI::hr(),
1451 } 1345 }
1452 debug("leaving body of Problem.pm"); 1346 debug("leaving body of Problem.pm");
1453 return ""; 1347 return "";
1454} 1348}
1455 1349
1456# output_form_start subroutine
1457
1458# prints out the beginning of the main form, and the necessary hidden authentication fields
1459
1460sub output_form_start{
1461 my $self = shift;
1462 my $r = $self->r;
1463 print CGI::start_form(-method=>"POST", -action=> $r->uri,-name=>"problemMainForm", onsubmit=>"submitAction()");
1464 print $self->hidden_authen_fields;
1465 return "";
1466}
1467
1468# output_problem_body subroutine
1469
1470# prints out the body of the current problem
1471
1472sub output_problem_body{
1473 my $self = shift;
1474 my $pg = $self->{pg};
1475
1476 print "\n";
1477 print CGI::p($pg->{body_text});
1478 return "";
1479}
1480
1481# output_message subroutine
1482
1483# prints out a message about the problem
1484
1485sub output_message{
1486 my $self = shift;
1487 my $pg = $self->{pg};
1488
1489 print CGI::p(CGI::b("Note: "). CGI::i($pg->{result}->{msg})) if $pg->{result}->{msg};
1490 return "";
1491}
1492
1493# output_editorLink subroutine
1494
1495# processes and prints out the correct link to the editor of the current problem
1496
1497sub output_editorLink{
1498
1499 my $self = shift;
1500
1501 my $set = $self->{set};
1502 my $problem = $self->{problem};
1503 my $pg = $self->{pg};
1504
1505 my $r = $self->r;
1506
1507 my $authz = $r->authz;
1508 my $urlpath = $r->urlpath;
1509 my $user = $r->param('user');
1510
1511 my $courseName = $urlpath->arg("courseID");
1512
1513 # FIXME: move editor link to top, next to problem number.
1514 # format as "[edit]" like we're doing with course info file, etc.
1515 # add edit link for set as well.
1516 my $editorLink = "";
1517 # if we are here without a real homework set, carry that through
1518 my $forced_field = [];
1519 $forced_field = ['sourceFilePath' => $r->param("sourceFilePath")] if
1520 ($set->set_id eq 'Undefined_Set');
1521 if ($authz->hasPermissions($user, "modify_problem_sets")) {
1522 my $editorPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
1523 courseID => $courseName, setID => $set->set_id, problemID => $problem->problem_id);
1524 my $editorURL = $self->systemLink($editorPage, params=>$forced_field);
1525 $editorLink = CGI::p(CGI::a({href=>$editorURL,target =>'WW_Editor'}, "Edit this problem"));
1526 }
1527
1528 ##### translation errors? #####
1529
1530 if ($pg->{flags}->{error_flag}) {
1531 if ($authz->hasPermissions($user, "view_problem_debugging_info")) {
1532 print $self->errorOutput($pg->{errors}, $pg->{body_text});
1533 } else {
1534 print $self->errorOutput($pg->{errors}, "You do not have permission to view the details of this error.");
1535 }
1536 print "";
1537 }
1538 else{
1539 print $editorLink;
1540 }
1541 return "";
1542}
1543
1544# output_checkboxes subroutine
1545
1546# prints out the checkbox input elements that are available for the current problem
1547
1548sub output_checkboxes{
1549 my $self = shift;
1550 my %can = %{ $self->{can} };
1551 my %will = %{ $self->{will} };
1552
1553 if ($can{showCorrectAnswers}) {
1554 print WeBWorK::CGI_labeled_input(
1555 -type => "checkbox",
1556 -id => "showCorrectAnswers_id",
1557 -label_text => "Show correct answers",
1558 -input_attr => $will{showCorrectAnswers} ?
1559 {
1560 -name => "showCorrectAnswers",
1561 -checked => "checked",
1562 -value => 1,
1563 }
1564 :
1565 {
1566 -name => "showCorrectAnswers",
1567 -value => 1,
1568 }
1569 );
1570 }
1571 if ($can{showHints}) {
1572 print CGI::div({style=>"color:red"},
1573 WeBWorK::CGI_labeled_input(
1574 -type => "checkbox",
1575 -id => "showHints_id",
1576 -label_text => "Show Hints",
1577 -input_attr => $will{showHints} ?
1578 {
1579 -name => "showHints",
1580 -checked => "checked",
1581 -value => 1,
1582 }
1583 :
1584 {
1585 -name => "showCorrectAnswers",
1586 -value => 1,
1587 }
1588 )
1589 );
1590 }
1591 if ($can{showSolutions}) {
1592 print WeBWorK::CGI_labeled_input(
1593 -type => "checkbox",
1594 -id => "showSolutions_id",
1595 -label_text => "Show Solutions",
1596 -input_attr => $will{showSolutions} ?
1597 {
1598 -name => "showSolutions",
1599 -checked => "checked",
1600 -value => 1,
1601 }
1602 :
1603 {
1604 -name => "showCorrectAnswers",
1605 -value => 1,
1606 }
1607 );
1608 }
1609
1610 if ($can{showCorrectAnswers} or $can{showHints} or $can{showSolutions}) {
1611 print CGI::br();
1612 }
1613
1614 return "";
1615}
1616
1617# output_submit_buttons
1618
1619# prints out the submit button input elements that are available for the current problem
1620
1621sub output_submit_buttons{
1622 my $self = shift;
1623 my $r = $self->r;
1624 my %can = %{ $self->{can} };
1625
1626 my $user = $r->param('user');
1627 my $effectiveUser = $r->param('effectiveUser');
1628
1629 print WeBWorK::CGI_labeled_input(-type=>"submit", -id=>"previewAnswers_id", -input_attr=>{-name=>"previewAnswers", -value=>"Preview Answers"});
1630 if ($can{checkAnswers}) {
1631 print WeBWorK::CGI_labeled_input(-type=>"submit", -id=>"checkAnswers_id", -input_attr=>{-name=>"checkAnswers", -value=>"Check Answers"});
1632 }
1633 if ($can{getSubmitButton}) {
1634 if ($user ne $effectiveUser) {
1635 # if acting as a student, make it clear that answer submissions will
1636 # apply to the student's records, not the professor's.
1637 print WeBWorK::CGI_labeled_input(-type=>"submit", -id=>"submitAnswers_id", -input_attr=>{-name=>"submitAnswers", -value=>"Submit Answers for $effectiveUser"});
1638 } else {
1639 #print CGI::submit(-name=>"submitAnswers", -label=>"Submit Answers", -onclick=>"alert('submit button clicked')");
1640 print WeBWorK::CGI_labeled_input(-type=>"submit", -id=>"submitAnswers_id", -input_attr=>{-name=>"submitAnswers", -label=>"Submit Answers", -onclick=>""});
1641 # FIXME for unknown reasons the -onclick label seems to have to be there in order to allow the forms onsubmit to trigger
1642 # WFT???
1643 }
1644 }
1645
1646 return "";
1647}
1648
1649# output_score_summary subroutine
1650
1651# prints out a summary of the student's current progress and status on the current problem
1652
1653sub output_score_summary{
1654 my $self = shift;
1655 my $problem = $self->{problem};
1656 my $set = $self->{set};
1657 my $pg = $self->{pg};
1658 my $scoreRecordedMessage = "";
1659 unless(defined $self->{scoreRecordedMessage}){
1660 $scoreRecordedMessage = $self->{scoreRecordedMessage};
1661 }
1662 my $submitAnswers = $self->{submitAnswers};
1663
1664 # score summary
1665 my $attempts = $problem->num_correct + $problem->num_incorrect;
1666 my $attemptsNoun = $attempts != 1 ? "times" : "time";
1667 my $problem_status = $problem->status || 0;
1668 my $lastScore = sprintf("%.0f%%", $problem_status * 100); # Round to whole number
1669 my ($attemptsLeft, $attemptsLeftNoun);
1670 if ($problem->max_attempts == -1) {
1671 # unlimited attempts
1672 $attemptsLeft = "unlimited";
1673 $attemptsLeftNoun = "attempts";
1674 } else {
1675 $attemptsLeft = $problem->max_attempts - $attempts;
1676 $attemptsLeftNoun = $attemptsLeft == 1 ? "attempt" : "attempts";
1677 }
1678
1679 my $setClosed = 0;
1680 my $setClosedMessage;
1681 if (before($set->open_date) or after($set->due_date)) {
1682 $setClosed = 1;
1683 if (before($set->open_date)) {
1684 $setClosedMessage = "This homework set is not yet open.";
1685 } elsif (after($set->due_date)) {
1686 $setClosedMessage = "This homework set is closed.";
1687 }
1688 }
1689 #if (before($set->open_date) or after($set->due_date)) {
1690 # $setClosed = 1;
1691 # $setClosedMessage = "This homework set is closed.";
1692 # if ($authz->hasPermissions($user, "view_answers")) {
1693 # $setClosedMessage .= " However, since you are a privileged user, additional attempts will be recorded.";
1694 # } else {
1695 # $setClosedMessage .= " Additional attempts will not be recorded.";
1696 # }
1697 #}
1698 unless (defined( $pg->{state}->{state_summary_msg}) and $pg->{state}->{state_summary_msg}=~/\S/) {
1699 my $notCountedMessage = ($problem->value) ? "" : "(This problem will not count towards your grade.)";
1700 print CGI::p(join("",
1701 $submitAnswers ? $scoreRecordedMessage . CGI::br() : "",
1702 "You have attempted this problem $attempts $attemptsNoun.", CGI::br(),
1703 $submitAnswers ?"You received a score of ".sprintf("%.0f%%", $pg->{result}->{score} * 100)." for this attempt.".CGI::br():'',
1704 $problem->attempted
1705 ? "Your overall recorded score is $lastScore. $notCountedMessage" . CGI::br()
1706 : "",
1707 $setClosed ? $setClosedMessage : "You have $attemptsLeft $attemptsLeftNoun remaining."
1708 ));
1709 }else {
1710 print CGI::p($pg->{state}->{state_summary_msg});
1711 }
1712
1713 return "";
1714}
1715
1716# output_misc subroutine
1717
1718# prints out other necessary elements
1719
1720sub output_misc{
1721
1722 my $self = shift;
1723 my $r = $self->r;
1724 my $ce = $r->ce;
1725 my $db = $r->db;
1726 my $pg = $self->{pg};
1727 my %will = %{ $self->{will} };
1728 my $user = $r->param('user');
1729
1730 print CGI::start_div();
1731
1732 my $pgdebug = join(CGI::br(), @{$pg->{pgcore}->{flags}->{DEBUG_messages}} );
1733 my $pgwarning = join(CGI::br(), @{$pg->{pgcore}->{flags}->{WARNING_messages}} );
1734 my $pginternalerrors = join(CGI::br(), @{$pg->{pgcore}->get_internal_debug_messages} );
1735 my $pgerrordiv = $pgdebug||$pgwarning||$pginternalerrors; # is 1 if any of these are non-empty
1736
1737 print CGI::p({style=>"color:red;"}, "Checking additional error messages") if $pgerrordiv ;
1738 print CGI::p("pg debug<br/> $pgdebug" ) if $pgdebug ;
1739 print CGI::p("pg warning<br/>$pgwarning" ) if $pgwarning ;
1740 print CGI::p("pg internal errors<br/> $pginternalerrors") if $pginternalerrors;
1741 print CGI::end_div() if $pgerrordiv ;
1742
1743 # save state for viewOptions
1744 print CGI::hidden(
1745 -name => "showOldAnswers",
1746 -value => $will{showOldAnswers}
1747 ),
1748
1749 CGI::hidden(
1750 -name => "displayMode",
1751 -value => $self->{displayMode}
1752 );
1753 print( CGI::hidden(
1754 -name => 'editMode',
1755 -value => $self->{editMode},
1756 )
1757 ) if defined($self->{editMode}) and $self->{editMode} eq 'temporaryFile';
1758
1759 # this is a security risk -- students can use this to find the source code for the problem
1760
1761 my $permissionLevel = $db->getPermissionLevel($user)->permission;
1762 my $professorPermissionLevel = $ce->{userRoles}->{professor};
1763 print( CGI::hidden(
1764 -name => 'sourceFilePath',
1765 -value => $self->{problem}->{source_file}
1766 )) if defined($self->{problem}->{source_file}) and $permissionLevel>= $professorPermissionLevel; # only allow this for professors
1767
1768 print( CGI::hidden(
1769 -name => 'problemSeed',
1770 -value => $r->param("problemSeed")
1771 )) if defined($r->param("problemSeed")) and $permissionLevel>= $professorPermissionLevel; # only allow this for professors
1772
1773 return "";
1774}
1775
1776# output_summary subroutine
1777
1778# prints out the summary of the questions that the student has answered for the current problem, along with available information about correctness
1779
1780sub output_summary{
1781
1782 my $self = shift;
1783
1784 my $editMode = $self->{editMode};
1785 my $problem = $self->{problem};
1786 my $pg = $self->{pg};
1787 my $submitAnswers = $self->{submitAnswers};
1788 my %will = %{ $self->{will} };
1789 my $checkAnswers = $self->{checkAnswers};
1790 my $previewAnswers = $self->{previewAnswers};
1791
1792 my $r = $self->r;
1793
1794 my $authz = $r->authz;
1795 my $user = $r->param('user');
1796
1797 # attempt summary
1798 #FIXME -- the following is a kludge: if showPartialCorrectAnswers is negative don't show anything.
1799 # until after the due date
1800 # do I need to check $will{showCorrectAnswers} to make preflight work??
1801 if (($pg->{flags}->{showPartialCorrectAnswers} >= 0 and $submitAnswers) ) {
1802 # print this if user submitted answers OR requested correct answers
1803
1804 print $self->attemptResults($pg, 1,
1805 $will{showCorrectAnswers},
1806 $pg->{flags}->{showPartialCorrectAnswers}, 1, 1);
1807 } elsif ($checkAnswers) {
1808 # print this if user previewed answers
1809 print CGI::div({class=>'ResultsWithError'},"ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED"), CGI::br();
1810 print $self->attemptResults($pg, 1, $will{showCorrectAnswers}, 1, 1, 1);
1811 # show attempt answers
1812 # show correct answers if asked
1813 # show attempt results (correctness)
1814 # show attempt previews
1815 } elsif ($previewAnswers) {
1816 # print this if user previewed answers
1817 print CGI::div({class=>'ResultsWithError'},"PREVIEW ONLY -- ANSWERS NOT RECORDED"),CGI::br(),$self->attemptResults($pg, 1, 0, 0, 0, 1);
1818 # show attempt answers
1819 # don't show correct answers
1820 # don't show attempt results (correctness)
1821 # show attempt previews
1822 }
1823
1824 return "";
1825}
1826
1827# output_custom_edit_message
1828
1829# prints out a custom edit message
1830
1831sub output_custom_edit_message{
1832 my $self = shift;
1833 my $r = $self->r;
1834 my $authz = $r->authz;
1835 my $user = $r->param('user');
1836 my $editMode = $self->{editMode};
1837 my $problem = $self->{problem};
1838
1839 # custom message for editor
1840 if ($authz->hasPermissions($user, "modify_problem_sets") and defined $editMode) {
1841 if ($editMode eq "temporaryFile") {
1842 print CGI::p(CGI::div({class=>'temporaryFile'}, "Viewing temporary file: ", $problem->source_file));
1843 } elsif ($editMode eq "savedFile") {
1844 # taken care of in the initialization phase
1845 }
1846 }
1847
1848 return "";
1849}
1850
1851# output_JS subroutine
1852
1853# prints out the wz_tooltip.js script for the current site.
1854
1855sub output_JS{
1856
1857 my $self = shift;
1858 my $r = $self->r;
1859 my $ce = $r->ce;
1860
1861 my $site_url = $ce->{webworkURLs}->{htdocs};
1862 print CGI::start_script({type=>"text/javascript", src=>"$site_url/js/wz_tooltip.js"}), CGI::end_script();
1863 return "";
1864}
1865
1866# output_CSS subroutine
1867
1868# prints the CSS scripts to page. Does some PERL trickery to form the styles for the correct answers and the incorrect answers (which may be substituted with JS sometime in the future).
1869
1870sub output_CSS{
1871
1872 my $self = shift;
1873 my $r = $self->r;
1874 my $ce = $r->ce;
1875 my $pg = $self->{pg};
1876
1877 # always show colors for checkAnswers
1878 # show colors for submit answer if
1879 if (($self->{checkAnswers}) or ($self->{submitAnswers} and $pg->{flags}->{showPartialCorrectAnswers}) ) {
1880 print CGI::start_style({type=>"text/css"});
1881 print '#'.join(', #', @{ $self->{correct_ids} }), $ce->{pg}{options}{correct_answer} if ref( $self->{correct_ids} )=~/ARRAY/; #correct green
1882 print '#'.join(', #', @{ $self->{incorrect_ids} }), $ce->{pg}{options}{incorrect_answer} if ref( $self->{incorrect_ids})=~/ARRAY/; #incorrect reddish
1883 print CGI::end_style();
1884 }
1885
1886 return "";
1887}
1888
1889# output_past_answer_button
1890
1891# prints out the "Show Past Answers" button
1892
1893sub output_past_answer_button{
1894 my $self = shift;
1895 my $r = $self->r;
1896 my $problem = $self->{problem};
1897
1898 my $authz = $r->authz;
1899 my $urlpath = $r->urlpath;
1900 my $user = $r->param('user');
1901
1902 my $courseName = $urlpath->arg("courseID");
1903
1904 my $pastAnswersPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::ShowAnswers",
1905 courseID => $courseName);
1906 my $showPastAnswersURL = $self->systemLink($pastAnswersPage, authen => 0); # no authen info for form action
1907
1908 # print answer inspection button
1909 if ($authz->hasPermissions($user, "view_answers")) {
1910 print "\n",
1911 CGI::start_form(-method=>"POST",-action=>$showPastAnswersURL,-target=>"WW_Info"),"\n",
1912 $self->hidden_authen_fields,"\n",
1913 CGI::hidden(-name => 'courseID', -value=>$courseName), "\n",
1914 CGI::hidden(-name => 'problemID', -value=>$problem->problem_id), "\n",
1915 CGI::hidden(-name => 'setID', -value=>$problem->set_id), "\n",
1916 CGI::hidden(-name => 'studentUser', -value=>$problem->user_id), "\n",
1917 CGI::p( {-align=>"left"},
1918 CGI::submit(-name => 'action', -value=>'Show Past Answers')
1919 ), "\n",
1920 CGI::endform();
1921 }
1922
1923 return "";
1924}
1925
1926# output_email_instructor subroutine
1927
1928# prints out the "Email Instructor" button
1929
1930sub output_email_instructor{
1931 my $self = shift;
1932 my $problem = $self->{problem};
1933 my %will = %{ $self->{will} };
1934 my $pg = $self->{pg};
1935
1936 print $self->feedbackMacro(
1937 module => __PACKAGE__,
1938 set => $self->{set}->set_id,
1939 problem => $problem->problem_id,
1940 displayMode => $self->{displayMode},
1941 showOldAnswers => $will{showOldAnswers},
1942 showCorrectAnswers => $will{showCorrectAnswers},
1943 showHints => $will{showHints},
1944 showSolutions => $will{showSolutions},
1945 pg_object => $pg,
1946 );
1947
1948 return "";
1949}
1950
1951sub output_hidden_info{
1952 my $self = shift;
1953
1954 if(defined $self->{correct_ids}){
1955 my $correctRef = $self->{correct_ids};
1956 my @correct = @$correctRef;
1957 foreach(@correct){
1958 print CGI::hidden(-name=>"correct_ids", -value=>$_."_val");
1959 }
1960 }
1961 if(defined $self->{incorrect_ids}){
1962 my $incorrectRef = $self->{incorrect_ids};
1963 my @incorrect = @$incorrectRef;
1964 foreach(@incorrect){
1965 print CGI::hidden(-name=>"incorrect_ids", -value=>$_."_val");
1966 }
1967 }
1968
1969 return "";
1970}
1971
1972sub output_coloring_JS{
1973 my $self = shift;
1974 my $r = $self->r;
1975 my $ce = $r->ce;
1976
1977 my $site_url = $ce->{webworkURLs}->{htdocs};
1978 print CGI::start_script({type=>"text/javascript", src=>"$site_url/js/color.js"}), CGI::end_script();
1979 return "";
1980}
1981
19821; 13501;

Legend:
Removed from v.6909  
changed lines
  Added in v.6943

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9