| … | |
… | |
| 48 | my $r = $self->{r}; |
48 | my $r = $self->{r}; |
| 49 | my $courseEnv = $self->{ce}; |
49 | my $courseEnv = $self->{ce}; |
| 50 | my $db = $self->{db}; |
50 | my $db = $self->{db}; |
| 51 | my $userName = $r->param('user'); |
51 | my $userName = $r->param('user'); |
| 52 | my $effectiveUserName = $r->param('effectiveUser'); |
52 | my $effectiveUserName = $r->param('effectiveUser'); |
| 53 | my $key = $r->param('key'); |
53 | my $key = $r->param('key'); |
| 54 | my $user = $db->getUser($userName); |
54 | my $user = $db->getUser($userName); |
| 55 | my $effectiveUser = $db->getUser($effectiveUserName); |
55 | my $effectiveUser = $db->getUser($effectiveUserName); |
| 56 | |
56 | my $permissionLevel = $db->getPermissionLevel($userName)->permission(); |
| 57 | # obtain the effective user set, or if that is not yet defined obtain global set |
57 | |
|
|
58 | # obtain the merged set for $effectiveUser |
| 58 | my $set = $db->getMergedSet($effectiveUserName, $setName); |
59 | my $set = $db->getMergedSet($effectiveUserName, $setName); |
|
|
60 | |
|
|
61 | # obtain the merged problem for $effectiveUser |
|
|
62 | my $problem = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); |
|
|
63 | |
|
|
64 | my $editMode = $r->param("editMode"); |
|
|
65 | |
|
|
66 | if ($permissionLevel > 0 and defined $editMode) { |
|
|
67 | # professors are allowed to fabricate sets and problems not |
|
|
68 | # assigned to them (or anyone). this allows them to use the |
|
|
69 | # editor to |
|
|
70 | |
|
|
71 | # if that is not yet defined obtain the global set, convert |
|
|
72 | # it to a user set, and add fake user data |
| 59 | unless (defined $set) { |
73 | unless (defined $set) { |
| 60 | my $userSetClass = $courseEnv->{dbLayout}->{set_user}->{record}; |
74 | my $userSetClass = $db->{set_user}->{record}; |
| 61 | $set = global2user($userSetClass, $db->getGlobalSet($setName)); |
75 | $set = global2user($userSetClass, |
|
|
76 | $db->getGlobalSet($setName)); |
|
|
77 | die "Set $setName does not exist" |
|
|
78 | unless defined $set; |
| 62 | $set->psvn('000'); |
79 | $set->psvn(0); |
| 63 | } |
80 | } |
| 64 | my $psvn = $set->psvn(); |
81 | |
| 65 | |
82 | # if that is not yet defined obtain the global problem, |
| 66 | # obtain the effective user problem, or if that is not yet defined obtain global problem |
83 | # convert it to a user problem, and add fake user data |
| 67 | my $problem = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); |
|
|
| 68 | unless (defined $problem) { |
84 | unless (defined $problem) { |
| 69 | my $userProblemClass = $courseEnv->{dbLayout}->{problem_user}->{record}; |
85 | my $userProblemClass = $db->{problem_user}->{record}; |
| 70 | $problem = global2user($userProblemClass, $db->getGlobalProblem($setName,$problemNumber)); |
86 | $problem = global2user($userProblemClass, |
| 71 | |
87 | $db->getGlobalProblem($setName,$problemNumber)); |
| 72 | # $problem->max_attempts(-1); # default is infinite number of attempts |
88 | die "Problem $problemNumber in set $setName does not exist" |
| 73 | # $problem->value; |
89 | unless defined $problem; |
|
|
90 | $problem->user_id($effectiveUserName); |
| 74 | # $problem->problem_seed; |
91 | $problem->problem_seed(0); |
| 75 | # $problem->source_file; |
|
|
| 76 | $problem->user_id($userName); # is this the right value for this unassigned problem? FIXME |
|
|
| 77 | $problem->status(0); |
92 | $problem->status(0); |
| 78 | $problem->attempted(0); |
93 | $problem->attempted(0); |
|
|
94 | $problem->last_answer(""); |
| 79 | $problem->num_correct(0); |
95 | $problem->num_correct(0); |
| 80 | $problem->num_incorrect(0); |
96 | $problem->num_incorrect(0); |
| 81 | $problem->last_answer(' '); |
|
|
| 82 | } |
97 | } |
| 83 | #$problem = $db->getGlobalProblem($setName, $problemNumber) unless defined($problem); |
98 | |
| 84 | # FIXME |
99 | # now we're sure we have valid UserSet and UserProblem objects |
| 85 | # a better solution at this point would be to take set and problem, convert them to global_user type |
100 | # yay! |
| 86 | # so that they have the right methods. |
101 | |
| 87 | # Stuff the local copy of $set and $problem with default data where it won't have been defined |
102 | # now deal with possible editor overrides: |
| 88 | # Make sure that nothing bad is stored back in the database. |
103 | |
| 89 | # It would be nice to store lastAnswer somewhere -- perhaps that could be done as a special case. |
104 | # if the caller is asking to override the source file, and |
|
|
105 | # editMode calls for a temporary file, do so |
|
|
106 | my $sourceFilePath = $r->param("sourceFilePath"); |
|
|
107 | if (defined $sourceFilePath and $editMode eq "temporaryFile") { |
|
|
108 | $problem->source_file($sourceFilePath); |
|
|
109 | } |
|
|
110 | |
|
|
111 | # if the caller is asking to override the problem seed, do so |
|
|
112 | my $problemSeed = $r->param("problemSeed"); |
|
|
113 | if (defined $problemSeed) { |
|
|
114 | $problem->problem_seed($problemSeed); |
|
|
115 | } |
|
|
116 | } else { |
|
|
117 | # students can't view problems not assigned to them |
|
|
118 | die "Set $setName is not assigned to $effectiveUserName" |
|
|
119 | unless defined $set; |
|
|
120 | die "Problem $problemNumber in set $setName is not assigned to $effectiveUserName" |
|
|
121 | unless defined $problem; |
|
|
122 | } |
| 90 | |
123 | |
| 91 | |
|
|
| 92 | # This supplies a psvn if $set doesn't have it. Unfortunately the problem is called on to provide |
|
|
| 93 | # data in many places and it might not even have methods defined. |
|
|
| 94 | |
|
|
| 95 | # global sets will not have a defined psvn |
|
|
| 96 | # my $psvn; |
|
|
| 97 | # if ($set->can('psvn') ) { |
|
|
| 98 | # $psvn = $set->psvn(); |
|
|
| 99 | # } else { # we are viewing an unassigned problem set, psvn's are irrelevant |
|
|
| 100 | # $psvn = '0000'; |
|
|
| 101 | # } |
|
|
| 102 | |
|
|
| 103 | my $permissionLevel = $db->getPermissionLevel($userName)->permission(); |
|
|
| 104 | |
|
|
| 105 | $self->{userName} = $userName; |
124 | $self->{userName} = $userName; |
|
|
125 | $self->{effectiveUserName} = $effectiveUserName; |
| 106 | $self->{user} = $user; |
126 | $self->{user} = $user; |
| 107 | $self->{effectiveUser} = $effectiveUser; |
127 | $self->{effectiveUser} = $effectiveUser; |
| 108 | $self->{set} = $set; |
|
|
| 109 | $self->{problem} = $problem; |
|
|
| 110 | $self->{permissionLevel} = $permissionLevel; |
128 | $self->{permissionLevel} = $permissionLevel; |
|
|
129 | $self->{set} = $set; |
|
|
130 | $self->{problem} = $problem; |
|
|
131 | $self->{editMode} = $editMode; |
| 111 | |
132 | |
| 112 | ##### form processing ##### |
133 | ##### form processing ##### |
| 113 | |
134 | |
| 114 | # set options from form fields (see comment at top of file for names) |
135 | # set options from form fields (see comment at top of file for names) |
| 115 | my $displayMode = $r->param("displayMode") || $courseEnv->{pg}->{options}->{displayMode}; |
136 | my $displayMode = $r->param("displayMode") || $courseEnv->{pg}->{options}->{displayMode}; |
| … | |
… | |
| 117 | my $submitAnswers = $r->param("submitAnswers"); |
138 | my $submitAnswers = $r->param("submitAnswers"); |
| 118 | my $checkAnswers = $r->param("checkAnswers"); |
139 | my $checkAnswers = $r->param("checkAnswers"); |
| 119 | my $previewAnswers = $r->param("previewAnswers"); |
140 | my $previewAnswers = $r->param("previewAnswers"); |
| 120 | |
141 | |
| 121 | # fields which may be defined when using Problem Editor |
142 | # fields which may be defined when using Problem Editor |
| 122 | my $override_seed = ($permissionLevel>=10) ? $r->param('problemSeed') : undef; |
143 | #my $override_seed = ($permissionLevel>=10) ? $r->param('problemSeed') : undef; |
| 123 | my $override_problem_source = ($permissionLevel>=10) ? $r->param('sourceFilePath') : undef; |
144 | #my $override_problem_source = ($permissionLevel>=10) ? $r->param('sourceFilePath') : undef; |
| 124 | my $editMode = undef; |
145 | #my $editMode = undef; |
| 125 | my $submit_button = $r->param('submit_button'); |
146 | #my $submit_button = $r->param('submit_button'); |
| 126 | if ( defined($submit_button ) ) { |
147 | #if ( defined($submit_button ) ) { |
| 127 | $editMode = "temporaryFile" if $submit_button eq 'Refresh'; |
148 | # $editMode = "temporaryFile" if $submit_button eq 'Refresh'; |
| 128 | $editMode = 'savedFile' if $submit_button eq 'Save'; |
149 | # $editMode = 'savedFile' if $submit_button eq 'Save'; |
| 129 | } |
150 | #} |
| 130 | |
151 | # |
| 131 | #override using the source file data from the form field |
152 | ##override using the source file data from the form field |
| 132 | $problem->source_file($override_problem_source) if defined($override_problem_source); |
153 | #$problem->source_file($override_problem_source) if defined($override_problem_source); |
| 133 | $problem->problem_seed($override_seed) if defined($override_seed); |
154 | #$problem->problem_seed($override_seed) if defined($override_seed); |
| 134 | |
155 | # |
| 135 | # store path to source file for title. |
156 | ## store path to source file for title. |
| 136 | $self->{problem_source_name} = $problem->source_file; |
157 | #$self->{problem_source_name} = $problem->source_file; |
| 137 | $self->{edit_mode} = $editMode; |
158 | #$self->{edit_mode} = $editMode; |
| 138 | # $self->{current_problem_source} = (defined($override_problem_source) ) ? |
159 | #$self->{current_problem_source} = (defined($override_problem_source) ) ? |
| 139 | # $override_problem_source : |
160 | |
| 140 | # $problem->source_file; |
|
|
| 141 | # coerce form fields into CGI::Vars format |
161 | # coerce form fields into CGI::Vars format |
| 142 | my $formFields = { WeBWorK::Form->new_from_paramable($r)->Vars }; |
162 | my $formFields = { WeBWorK::Form->new_from_paramable($r)->Vars }; |
| 143 | |
163 | |
| 144 | $self->{displayMode} = $displayMode; |
164 | $self->{displayMode} = $displayMode; |
| 145 | $self->{redisplay} = $redisplay; |
165 | $self->{redisplay} = $redisplay; |
| 146 | $self->{submitAnswers} = $submitAnswers; |
166 | $self->{submitAnswers} = $submitAnswers; |
| 147 | $self->{checkAnswers} = $checkAnswers; |
167 | $self->{checkAnswers} = $checkAnswers; |
| 148 | $self->{previewAnswers} = $previewAnswers; |
168 | $self->{previewAnswers} = $previewAnswers; |
| 149 | $self->{formFields} = $formFields; |
169 | $self->{formFields} = $formFields; |
| 150 | |
170 | |
| 151 | |
|
|
| 152 | ##### permissions ##### |
171 | ##### permissions ##### |
| 153 | |
172 | |
| 154 | # are we allowed to view this problem? |
173 | # are we allowed to view this problem? |
| 155 | $self->{isOpen} = time >= $set->open_date || $permissionLevel > 0; |
174 | $self->{isOpen} = time >= $set->open_date || $permissionLevel > 0; |
| 156 | return unless $self->{isOpen}; |
175 | return unless $self->{isOpen}; |
| … | |
… | |
| 207 | $courseEnv, |
226 | $courseEnv, |
| 208 | $effectiveUser, |
227 | $effectiveUser, |
| 209 | $key, |
228 | $key, |
| 210 | $set, |
229 | $set, |
| 211 | $problem, |
230 | $problem, |
| 212 | $psvn, |
231 | $set->psvn, # FIXME: this field should be removed |
| 213 | $formFields, |
232 | $formFields, |
| 214 | { # translation options |
233 | { # translation options |
| 215 | displayMode => $displayMode, |
234 | displayMode => $displayMode, |
| 216 | override_seed => $override_seed, |
|
|
| 217 | override_problem_source =>$override_problem_source, |
|
|
| 218 | showHints => $will{showHints}, |
235 | showHints => $will{showHints}, |
| 219 | showSolutions => $will{showSolutions}, |
236 | showSolutions => $will{showSolutions}, |
| 220 | refreshMath2img => $will{showHints} || $will{showSolutions}, |
237 | refreshMath2img => $will{showHints} || $will{showSolutions}, |
| 221 | processAnswers => 1, |
238 | processAnswers => 1, |
| 222 | }, |
239 | }, |
| … | |
… | |
| 329 | my $effectiveUser = $self->{r}->param("effectiveUser"); |
346 | my $effectiveUser = $self->{r}->param("effectiveUser"); |
| 330 | my $tail = "&displayMode=".$self->{displayMode}; |
347 | my $tail = "&displayMode=".$self->{displayMode}; |
| 331 | |
348 | |
| 332 | my @links = ("Problem List" , "$root/$courseName/$setName", "navProbList"); |
349 | my @links = ("Problem List" , "$root/$courseName/$setName", "navProbList"); |
| 333 | |
350 | |
|
|
351 | # FIXME: this could be faster |
| 334 | my $prevProblem = $db->getMergedProblem($effectiveUser, $setName, $problemNumber-1); |
352 | my $prevProblem = $db->getMergedProblem($effectiveUser, $setName, $problemNumber-1); |
| 335 | my $nextProblem = $db->getMergedProblem($effectiveUser, $setName, $problemNumber+1); |
353 | my $nextProblem = $db->getMergedProblem($effectiveUser, $setName, $problemNumber+1); |
| 336 | unshift @links, "Previous Problem" , ($prevProblem |
354 | unshift @links, "Previous Problem" , ($prevProblem |
| 337 | ? "$root/$courseName/$setName/".$prevProblem->problem_id |
355 | ? "$root/$courseName/$setName/".$prevProblem->problem_id |
| 338 | : "") , "navPrev"; |
356 | : "") , "navPrev"; |
| … | |
… | |
| 344 | } |
362 | } |
| 345 | |
363 | |
| 346 | sub title { |
364 | sub title { |
| 347 | my $self = shift; |
365 | my $self = shift; |
| 348 | my $setName = $self->{set}->set_id; |
366 | my $setName = $self->{set}->set_id; |
| 349 | |
|
|
| 350 | my $file_action; |
|
|
| 351 | my $edit_mode = $self->{edit_mode}; |
|
|
| 352 | if ( not defined($edit_mode) ) { |
|
|
| 353 | $file_action = ''; |
|
|
| 354 | } elsif ( $edit_mode eq 'temporaryFile') { |
|
|
| 355 | $file_action .= 'Editing temporary file : '. CGI::br() . $self->{problem_source_name}; |
|
|
| 356 | } elsif ( $edit_mode eq 'savedFile' ){ |
|
|
| 357 | $file_action .= 'Problem saved to : '. CGI::br() . $self->{problem_source_name}; |
|
|
| 358 | } |
|
|
| 359 | my $problemNumber = $self->{problem}->problem_id . " : " . $file_action; |
367 | my $problemNumber = $self->{problem}->problem_id; |
| 360 | |
368 | |
| 361 | return "$setName : Problem $problemNumber"; |
369 | return "$setName : Problem $problemNumber"; |
| 362 | } |
370 | } |
| 363 | |
371 | |
| 364 | sub body { |
372 | sub body { |
| … | |
… | |
| 370 | # unpack some useful variables |
378 | # unpack some useful variables |
| 371 | my $r = $self->{r}; |
379 | my $r = $self->{r}; |
| 372 | my $db = $self->{db}; |
380 | my $db = $self->{db}; |
| 373 | my $set = $self->{set}; |
381 | my $set = $self->{set}; |
| 374 | my $problem = $self->{problem}; |
382 | my $problem = $self->{problem}; |
|
|
383 | my $editMode = $self->{editMode}; |
| 375 | my $permissionLevel = $self->{permissionLevel}; |
384 | my $permissionLevel = $self->{permissionLevel}; |
| 376 | my $submitAnswers = $self->{submitAnswers}; |
385 | my $submitAnswers = $self->{submitAnswers}; |
| 377 | my $checkAnswers = $self->{checkAnswers}; |
386 | my $checkAnswers = $self->{checkAnswers}; |
| 378 | my $previewAnswers = $self->{previewAnswers}; |
387 | my $previewAnswers = $self->{previewAnswers}; |
| 379 | my %want = %{ $self->{want} }; |
388 | my %want = %{ $self->{want} }; |
| 380 | my %can = %{ $self->{can} }; |
389 | my %can = %{ $self->{can} }; |
| 381 | my %must = %{ $self->{must} }; |
390 | my %must = %{ $self->{must} }; |
| 382 | my %will = %{ $self->{will} }; |
391 | my %will = %{ $self->{will} }; |
| 383 | my $pg = $self->{pg}; |
392 | my $pg = $self->{pg}; |
| 384 | |
393 | |
| 385 | ##### translation errors? ##### |
394 | ##### translation errors? ##### |
| … | |
… | |
| 471 | |
480 | |
| 472 | ##### output ##### |
481 | ##### output ##### |
| 473 | |
482 | |
| 474 | print CGI::start_div({class=>"problemHeader"}); |
483 | print CGI::start_div({class=>"problemHeader"}); |
| 475 | |
484 | |
|
|
485 | # custom message for editor |
|
|
486 | if ($permissionLevel >= 10 and defined $editMode) { |
|
|
487 | if ($editMode eq "temporaryFile") { |
|
|
488 | print CGI::p(CGI::i("Editing temporary file: ", $problem->source_file)); |
|
|
489 | } elsif ($editMode eq "savedFile") { |
|
|
490 | print CGI::p(CGI::i("Problem saved to: ", $problem->source_file)); |
|
|
491 | } |
|
|
492 | } |
|
|
493 | |
| 476 | # attempt summary |
494 | # attempt summary |
| 477 | if ($submitAnswers or $will{showCorrectAnswers}) { |
495 | if ($submitAnswers or $will{showCorrectAnswers}) { |
| 478 | # print this if user submitted answers OR requested correct answers |
496 | # print this if user submitted answers OR requested correct answers |
| 479 | print $self->attemptResults($pg, $submitAnswers, |
497 | print $self->attemptResults($pg, $submitAnswers, |
| 480 | $will{showCorrectAnswers}, |
498 | $will{showCorrectAnswers}, |