Commit | Line | Data |
---|---|---|
fe6ce234 | 1 | <?php |
fe6ce234 DC |
2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | /** | |
18 | * Library functions used by question/preview.php. | |
19 | * | |
06f8ed54 | 20 | * @package moodlecore |
fe6ce234 DC |
21 | * @subpackage questionengine |
22 | * @copyright 2010 The Open University | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
06f8ed54 | 26 | |
a17b297d TH |
27 | defined('MOODLE_INTERNAL') || die(); |
28 | ||
7a719748 TH |
29 | require_once($CFG->libdir . '/formslib.php'); |
30 | ||
31 | ||
06f8ed54 TH |
32 | /** |
33 | * Settings form for the preview options. | |
34 | * | |
f7970e3c TH |
35 | * @copyright 2009 The Open University |
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
06f8ed54 TH |
37 | */ |
38 | class preview_options_form extends moodleform { | |
39 | public function definition() { | |
40 | $mform = $this->_form; | |
41 | ||
42 | $hiddenofvisible = array( | |
43 | question_display_options::HIDDEN => get_string('notshown', 'question'), | |
44 | question_display_options::VISIBLE => get_string('shown', 'question'), | |
45 | ); | |
46 | ||
29034c3e | 47 | $mform->addElement('header', 'attemptoptionsheader', get_string('attemptoptions', 'question')); |
06f8ed54 | 48 | |
c014b989 TH |
49 | $behaviours = question_engine::get_behaviour_options( |
50 | $this->_customdata['quba']->get_preferred_behaviour()); | |
51 | $mform->addElement('select', 'behaviour', | |
52 | get_string('howquestionsbehave', 'question'), $behaviours); | |
c76145d3 | 53 | $mform->addHelpButton('behaviour', 'howquestionsbehave', 'question'); |
06f8ed54 | 54 | |
197e074e | 55 | $mform->addElement('float', 'maxmark', get_string('markedoutof', 'question'), |
c014b989 | 56 | array('size' => '5')); |
06f8ed54 | 57 | |
c014b989 TH |
58 | if ($this->_customdata['maxvariant'] > 1) { |
59 | $variants = range(1, $this->_customdata['maxvariant']); | |
60 | $mform->addElement('select', 'variant', get_string('questionvariant', 'question'), | |
61 | array_combine($variants, $variants)); | |
62 | } | |
7664182d | 63 | $mform->setType('variant', PARAM_INT); |
c014b989 | 64 | |
2443f3d2 TH |
65 | $mform->addElement('submit', 'saverestart', |
66 | get_string('restartwiththeseoptions', 'question')); | |
67 | ||
29034c3e | 68 | $mform->addElement('header', 'displayoptionsheader', get_string('displayoptions', 'question')); |
2443f3d2 | 69 | |
c014b989 TH |
70 | $mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'), |
71 | $hiddenofvisible); | |
06f8ed54 TH |
72 | |
73 | $marksoptions = array( | |
74 | question_display_options::HIDDEN => get_string('notshown', 'question'), | |
75 | question_display_options::MAX_ONLY => get_string('showmaxmarkonly', 'question'), | |
76 | question_display_options::MARK_AND_MAX => get_string('showmarkandmax', 'question'), | |
77 | ); | |
78 | $mform->addElement('select', 'marks', get_string('marks', 'question'), $marksoptions); | |
79 | ||
80 | $mform->addElement('select', 'markdp', get_string('decimalplacesingrades', 'question'), | |
81 | question_engine::get_dp_options()); | |
82 | ||
c014b989 TH |
83 | $mform->addElement('select', 'feedback', |
84 | get_string('specificfeedback', 'question'), $hiddenofvisible); | |
06f8ed54 | 85 | |
c014b989 TH |
86 | $mform->addElement('select', 'generalfeedback', |
87 | get_string('generalfeedback', 'question'), $hiddenofvisible); | |
06f8ed54 | 88 | |
c014b989 TH |
89 | $mform->addElement('select', 'rightanswer', |
90 | get_string('rightanswer', 'question'), $hiddenofvisible); | |
06f8ed54 | 91 | |
c014b989 TH |
92 | $mform->addElement('select', 'history', |
93 | get_string('responsehistory', 'question'), $hiddenofvisible); | |
06f8ed54 | 94 | |
599cc731 TL |
95 | $mform->addElement('submit', 'saveupdate', |
96 | get_string('updatedisplayoptions', 'question')); | |
06f8ed54 TH |
97 | } |
98 | } | |
99 | ||
100 | ||
101 | /** | |
102 | * Displays question preview options as default and set the options | |
103 | * Setting default, getting and setting user preferences in question preview options. | |
104 | * | |
f7970e3c TH |
105 | * @copyright 2010 The Open University |
106 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
06f8ed54 TH |
107 | */ |
108 | class question_preview_options extends question_display_options { | |
109 | /** @var string the behaviour to use for this preview. */ | |
110 | public $behaviour; | |
111 | ||
112 | /** @var number the maximum mark to use for this preview. */ | |
113 | public $maxmark; | |
114 | ||
c014b989 TH |
115 | /** @var int the variant of the question to preview. */ |
116 | public $variant; | |
117 | ||
06f8ed54 TH |
118 | /** @var string prefix to append to field names to get user_preference names. */ |
119 | const OPTIONPREFIX = 'question_preview_options_'; | |
120 | ||
121 | /** | |
122 | * Constructor. | |
123 | */ | |
124 | public function __construct($question) { | |
06f8ed54 TH |
125 | $this->behaviour = 'deferredfeedback'; |
126 | $this->maxmark = $question->defaultmark; | |
c014b989 | 127 | $this->variant = null; |
06f8ed54 TH |
128 | $this->correctness = self::VISIBLE; |
129 | $this->marks = self::MARK_AND_MAX; | |
c76145d3 | 130 | $this->markdp = get_config('quiz', 'decimalpoints'); |
06f8ed54 TH |
131 | $this->feedback = self::VISIBLE; |
132 | $this->numpartscorrect = $this->feedback; | |
133 | $this->generalfeedback = self::VISIBLE; | |
134 | $this->rightanswer = self::VISIBLE; | |
135 | $this->history = self::HIDDEN; | |
136 | $this->flags = self::HIDDEN; | |
137 | $this->manualcomment = self::HIDDEN; | |
138 | } | |
139 | ||
140 | /** | |
141 | * @return array names of the options we store in the user preferences table. | |
142 | */ | |
143 | protected function get_user_pref_fields() { | |
144 | return array('behaviour', 'correctness', 'marks', 'markdp', 'feedback', | |
145 | 'generalfeedback', 'rightanswer', 'history'); | |
146 | } | |
147 | ||
148 | /** | |
149 | * @return array names and param types of the options we read from the request. | |
150 | */ | |
151 | protected function get_field_types() { | |
152 | return array( | |
153 | 'behaviour' => PARAM_ALPHA, | |
197e074e | 154 | 'maxmark' => PARAM_LOCALISEDFLOAT, |
c014b989 | 155 | 'variant' => PARAM_INT, |
06f8ed54 TH |
156 | 'correctness' => PARAM_BOOL, |
157 | 'marks' => PARAM_INT, | |
158 | 'markdp' => PARAM_INT, | |
159 | 'feedback' => PARAM_BOOL, | |
160 | 'generalfeedback' => PARAM_BOOL, | |
161 | 'rightanswer' => PARAM_BOOL, | |
162 | 'history' => PARAM_BOOL, | |
163 | ); | |
164 | } | |
165 | ||
166 | /** | |
167 | * Load the value of the options from the user_preferences table. | |
168 | */ | |
169 | public function load_user_defaults() { | |
4125ded1 | 170 | $defaults = get_config('question_preview'); |
06f8ed54 TH |
171 | foreach ($this->get_user_pref_fields() as $field) { |
172 | $this->$field = get_user_preferences( | |
4125ded1 | 173 | self::OPTIONPREFIX . $field, $defaults->$field); |
06f8ed54 TH |
174 | } |
175 | $this->numpartscorrect = $this->feedback; | |
176 | } | |
177 | ||
178 | /** | |
179 | * Save a change to the user's preview options to the database. | |
180 | * @param object $newoptions | |
181 | */ | |
182 | public function save_user_preview_options($newoptions) { | |
183 | foreach ($this->get_user_pref_fields() as $field) { | |
184 | if (isset($newoptions->$field)) { | |
185 | set_user_preference(self::OPTIONPREFIX . $field, $newoptions->$field); | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | /** | |
191 | * Set the value of any fields included in the request. | |
192 | */ | |
193 | public function set_from_request() { | |
194 | foreach ($this->get_field_types() as $field => $type) { | |
195 | $this->$field = optional_param($field, $this->$field, $type); | |
196 | } | |
197 | $this->numpartscorrect = $this->feedback; | |
198 | } | |
199 | ||
200 | /** | |
201 | * @return string URL fragment. Parameters needed in the URL when continuing | |
202 | * this preview. | |
203 | */ | |
612106b3 TH |
204 | public function get_url_params() { |
205 | $params = array(); | |
06f8ed54 | 206 | foreach ($this->get_field_types() as $field => $notused) { |
c014b989 | 207 | if ($field == 'behaviour' || $field == 'maxmark' || is_null($this->$field)) { |
06f8ed54 TH |
208 | continue; |
209 | } | |
612106b3 | 210 | $params[$field] = $this->$field; |
06f8ed54 | 211 | } |
612106b3 | 212 | return $params; |
06f8ed54 TH |
213 | } |
214 | } | |
215 | ||
216 | ||
fe6ce234 DC |
217 | /** |
218 | * Called via pluginfile.php -> question_pluginfile to serve files belonging to | |
219 | * a question in a question_attempt when that attempt is a preview. | |
220 | * | |
d2b7803e DC |
221 | * @package core_question |
222 | * @category files | |
223 | * @param stdClass $course course settings object | |
224 | * @param stdClass $context context object | |
fe6ce234 DC |
225 | * @param string $component the name of the component we are serving files for. |
226 | * @param string $filearea the name of the file area. | |
f7970e3c TH |
227 | * @param int $qubaid the question_usage this image belongs to. |
228 | * @param int $slot the relevant slot within the usage. | |
fe6ce234 DC |
229 | * @param array $args the remaining bits of the file path. |
230 | * @param bool $forcedownload whether the user must be forced to download the file. | |
7a00d438 | 231 | * @param array $options additional options affecting the file serving |
fe6ce234 DC |
232 | * @return bool false if file not found, does not return if found - justsend the file |
233 | */ | |
234 | function question_preview_question_pluginfile($course, $context, $component, | |
2aad62e9 | 235 | $filearea, $qubaid, $slot, $args, $forcedownload, $fileoptions) { |
7a719748 | 236 | global $USER, $DB, $CFG; |
fe6ce234 | 237 | |
97f1137a TH |
238 | list($context, $course, $cm) = get_context_info_array($context->id); |
239 | require_login($course, false, $cm); | |
240 | ||
7a719748 | 241 | $quba = question_engine::load_questions_usage_by_activity($qubaid); |
fe6ce234 | 242 | |
64207dab | 243 | if (!question_has_capability_on($quba->get_question($slot, false), 'use')) { |
fe6ce234 DC |
244 | send_file_not_found(); |
245 | } | |
246 | ||
7a719748 TH |
247 | $options = new question_display_options(); |
248 | $options->feedback = question_display_options::VISIBLE; | |
249 | $options->numpartscorrect = question_display_options::VISIBLE; | |
250 | $options->generalfeedback = question_display_options::VISIBLE; | |
251 | $options->rightanswer = question_display_options::VISIBLE; | |
252 | $options->manualcomment = question_display_options::VISIBLE; | |
253 | $options->history = question_display_options::VISIBLE; | |
254 | if (!$quba->check_file_access($slot, $options, $component, | |
fe6ce234 DC |
255 | $filearea, $args, $forcedownload)) { |
256 | send_file_not_found(); | |
257 | } | |
258 | ||
259 | $fs = get_file_storage(); | |
260 | $relativepath = implode('/', $args); | |
f4fe3968 | 261 | $fullpath = "/{$context->id}/{$component}/{$filearea}/{$relativepath}"; |
fe6ce234 DC |
262 | if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { |
263 | send_file_not_found(); | |
264 | } | |
265 | ||
2aad62e9 | 266 | send_stored_file($file, 0, 0, $forcedownload, $fileoptions); |
fe6ce234 | 267 | } |
06f8ed54 TH |
268 | |
269 | /** | |
270 | * The the URL to use for actions relating to this preview. | |
f7970e3c TH |
271 | * @param int $questionid the question being previewed. |
272 | * @param int $qubaid the id of the question usage for this preview. | |
06f8ed54 TH |
273 | * @param question_preview_options $options the options in use. |
274 | */ | |
275 | function question_preview_action_url($questionid, $qubaid, | |
56a4ae46 | 276 | question_preview_options $options, $context) { |
612106b3 TH |
277 | $params = array( |
278 | 'id' => $questionid, | |
279 | 'previewid' => $qubaid, | |
280 | ); | |
56a4ae46 TH |
281 | if ($context->contextlevel == CONTEXT_MODULE) { |
282 | $params['cmid'] = $context->instanceid; | |
283 | } else if ($context->contextlevel == CONTEXT_COURSE) { | |
284 | $params['courseid'] = $context->instanceid; | |
285 | } | |
612106b3 TH |
286 | $params = array_merge($params, $options->get_url_params()); |
287 | return new moodle_url('/question/preview.php', $params); | |
06f8ed54 TH |
288 | } |
289 | ||
56a4ae46 TH |
290 | /** |
291 | * The the URL to use for actions relating to this preview. | |
292 | * @param int $questionid the question being previewed. | |
599cc731 TL |
293 | * @param context $context the current moodle context. |
294 | * @param int $previewid optional previewid to sign post saved previewed answers. | |
56a4ae46 | 295 | */ |
599cc731 | 296 | function question_preview_form_url($questionid, $context, $previewid = null) { |
56a4ae46 TH |
297 | $params = array( |
298 | 'id' => $questionid, | |
299 | ); | |
300 | if ($context->contextlevel == CONTEXT_MODULE) { | |
301 | $params['cmid'] = $context->instanceid; | |
302 | } else if ($context->contextlevel == CONTEXT_COURSE) { | |
303 | $params['courseid'] = $context->instanceid; | |
304 | } | |
599cc731 TL |
305 | if ($previewid) { |
306 | $params['previewid'] = $previewid; | |
307 | } | |
56a4ae46 TH |
308 | return new moodle_url('/question/preview.php', $params); |
309 | } | |
310 | ||
06f8ed54 TH |
311 | /** |
312 | * Delete the current preview, if any, and redirect to start a new preview. | |
f7970e3c TH |
313 | * @param int $previewid |
314 | * @param int $questionid | |
06f8ed54 | 315 | * @param object $displayoptions |
56a4ae46 | 316 | * @param object $context |
06f8ed54 | 317 | */ |
56a4ae46 | 318 | function restart_preview($previewid, $questionid, $displayoptions, $context) { |
c76145d3 TH |
319 | global $DB; |
320 | ||
06f8ed54 | 321 | if ($previewid) { |
c76145d3 | 322 | $transaction = $DB->start_delegated_transaction(); |
06f8ed54 | 323 | question_engine::delete_questions_usage_by_activity($previewid); |
c76145d3 | 324 | $transaction->allow_commit(); |
06f8ed54 | 325 | } |
c014b989 | 326 | redirect(question_preview_url($questionid, $displayoptions->behaviour, |
56a4ae46 | 327 | $displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context)); |
06f8ed54 | 328 | } |