Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
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
namespace qbank_previewquestion;
18
 
19
defined('MOODLE_INTERNAL') || die();
20
 
21
require_once($CFG->dirroot . '/question/editlib.php');
22
 
23
use action_menu;
24
use comment;
25
use context_module;
26
use context;
27
use core\plugininfo\qbank;
28
use core_question\local\bank\edit_menu_column;
29
use core_question\local\bank\view;
30
use core_question\local\bank\question_edit_contexts;
31
use moodle_url;
32
use question_bank;
33
use question_definition;
34
use question_display_options;
35
use question_engine;
36
use stdClass;
37
 
38
/**
39
 * Class helper contains all the helper functions.
40
 *
41
 * @package    qbank_previewquestion
42
 * @copyright  2010 The Open University
43
 * @author     2021 Safat Shahin <safatshahin@catalyst-au.net>
44
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45
 */
46
class helper {
47
 
48
    /**
49
     * Called via pluginfile.php -> question_pluginfile to serve files belonging to
50
     * a question in a question_attempt when that attempt is a preview.
51
     *
52
     * @param stdClass $course course settings object
53
     * @param stdClass $context context object
54
     * @param string $component the name of the component we are serving files for.
55
     * @param string $filearea the name of the file area.
56
     * @param int $qubaid the question_usage this image belongs to.
57
     * @param int $slot the relevant slot within the usage.
58
     * @param array $args the remaining bits of the file path.
59
     * @param bool $forcedownload whether the user must be forced to download the file.
60
     * @param array $fileoptions options for the stored files
61
     * @return void false if file not found, does not return if found - justsend the file
62
     */
63
    public static function question_preview_question_pluginfile($course, $context, $component,
64
            $filearea, $qubaid, $slot, $args, $forcedownload, $fileoptions): void {
65
        global $USER, $DB, $CFG;
66
 
67
        list($context, $course, $cm) = get_context_info_array($context->id);
68
        require_login($course, false, $cm);
69
 
70
        $quba = question_engine::load_questions_usage_by_activity($qubaid);
71
 
72
        if (!question_has_capability_on($quba->get_question($slot, false), 'use')) {
73
            send_file_not_found();
74
        }
75
 
76
        $options = new question_display_options();
77
        $options->feedback = question_display_options::VISIBLE;
78
        $options->numpartscorrect = question_display_options::VISIBLE;
79
        $options->generalfeedback = question_display_options::VISIBLE;
80
        $options->rightanswer = question_display_options::VISIBLE;
81
        $options->manualcomment = question_display_options::VISIBLE;
82
        $options->history = question_display_options::VISIBLE;
83
        if (!$quba->check_file_access($slot, $options, $component,
84
                $filearea, $args, $forcedownload)) {
85
            send_file_not_found();
86
        }
87
 
88
        $fs = get_file_storage();
89
        $relativepath = implode('/', $args);
90
        $fullpath = "/{$context->id}/{$component}/{$filearea}/{$relativepath}";
91
        if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
92
            send_file_not_found();
93
        }
94
 
95
        send_stored_file($file, 0, 0, $forcedownload, $fileoptions);
96
    }
97
 
98
    /**
99
     * The the URL to use for actions relating to this preview.
100
     *
101
     * @param int $questionid the question being previewed
102
     * @param int $qubaid the id of the question usage for this preview
103
     * @param question_preview_options $options the options in use
104
     * @param context $context context for the question preview
105
     * @param moodle_url $returnurl url of the page to return to
106
     * @param int|null $restartversion version of the question to use when next restarting the preview.
107
     * @return moodle_url
108
     */
109
    public static function question_preview_action_url($questionid, $qubaid,
110
            question_preview_options $options, $context, $returnurl = null, $restartversion = null): moodle_url {
111
        $params = [
112
                'id' => $questionid,
113
                'previewid' => $qubaid,
114
        ];
115
        if ($context->contextlevel == CONTEXT_MODULE) {
116
            $params['cmid'] = $context->instanceid;
117
        } else if ($context->contextlevel == CONTEXT_COURSE) {
118
            $params['courseid'] = $context->instanceid;
119
        }
120
        if ($returnurl !== null) {
121
            $params['returnurl'] = $returnurl;
122
        }
123
        if ($restartversion !== null) {
124
            $params['restartversion'] = $restartversion;
125
        }
126
        $params = array_merge($params, $options->get_url_params());
127
        return new moodle_url('/question/bank/previewquestion/preview.php', $params);
128
    }
129
 
130
    /**
131
     * The the URL to use for actions relating to this preview.
132
     *
133
     * @param int $questionid the question being previewed
134
     * @param context $context the current moodle context
135
     * @param int $previewid optional previewid to sign post saved previewed answers
136
     * @param moodle_url $returnurl url of the page to return to
137
     * @return moodle_url
138
     */
139
    public static function question_preview_form_url($questionid, $context, $previewid = null, $returnurl = null): moodle_url {
140
        $params = [
141
                'id' => $questionid,
142
        ];
143
        if ($context->contextlevel == CONTEXT_MODULE) {
144
            $params['cmid'] = $context->instanceid;
145
        } else if ($context->contextlevel == CONTEXT_COURSE) {
146
            $params['courseid'] = $context->instanceid;
147
        }
148
        if ($previewid) {
149
            $params['previewid'] = $previewid;
150
        }
151
        if ($returnurl !== null) {
152
            $params['returnurl'] = $returnurl;
153
        }
154
        return new moodle_url('/question/bank/previewquestion/preview.php', $params);
155
    }
156
 
157
    /**
158
     * Delete the current preview, if any, and redirect to start a new preview.
159
     *
160
     * @param int $previewid id of the preview while restarting it
161
     * @param int $questionid id of the question in preview
162
     * @param object $displayoptions display options for the question in preview
163
     * @param object $context context of the question for preview
164
     * @param moodle_url $returnurl url of the page to return to
165
     * @param int|null $restartversion version of the question to use when next restarting the preview.
166
     * @return void
167
     */
168
    public static function restart_preview($previewid, $questionid, $displayoptions, $context,
169
        $returnurl = null, $restartversion = null): void {
170
        global $DB;
171
 
172
        if ($previewid) {
173
            $transaction = $DB->start_delegated_transaction();
174
            question_engine::delete_questions_usage_by_activity($previewid);
175
            $transaction->allow_commit();
176
        }
177
        redirect(self::question_preview_url($questionid, $displayoptions->behaviour,
178
                $displayoptions->maxmark, $displayoptions, $displayoptions->variant,
179
                $context, $returnurl, $restartversion));
180
    }
181
 
182
    /**
183
     * Generate the URL for starting a new preview of a given question with the given options.
184
     *
185
     * @param integer $questionid the question to preview
186
     * @param string $preferredbehaviour the behaviour to use for the preview
187
     * @param float $maxmark the maximum to mark the question out of
188
     * @param question_display_options $displayoptions the display options to use
189
     * @param int $variant the variant of the question to preview. If null, one will
190
     *      be picked randomly
191
     * @param object $context context to run the preview in (affects things like
192
     *      filter settings, theme, lang, etc.) Defaults to $PAGE->context
193
     * @param moodle_url $returnurl url of the page to return to
194
     * @param int $restartversion The version of the question to use when restarting the preview.
195
     * @return moodle_url the URL
196
     */
197
    public static function question_preview_url($questionid, $preferredbehaviour = null,
198
            $maxmark = null, $displayoptions = null, $variant = null, $context = null, $returnurl = null,
199
            $restartversion = null): moodle_url {
200
 
201
        $params = ['id' => $questionid];
202
 
203
        if (!is_null($restartversion)) {
204
            $params['restartversion'] = $restartversion;
205
        }
206
        if (is_null($context)) {
207
            global $PAGE;
208
            $context = $PAGE->context;
209
        }
210
        if ($context->contextlevel == CONTEXT_MODULE) {
211
            $params['cmid'] = $context->instanceid;
212
        } else if ($context->contextlevel == CONTEXT_COURSE) {
213
            $params['courseid'] = $context->instanceid;
214
        }
215
 
216
        if (!is_null($preferredbehaviour)) {
217
            $params['behaviour'] = $preferredbehaviour;
218
        }
219
 
220
        if (!is_null($maxmark)) {
221
            $params['maxmark'] = format_float($maxmark, -1);
222
        }
223
 
224
        if (!is_null($displayoptions)) {
225
            $params['correctness']     = $displayoptions->correctness;
226
            $params['marks']           = $displayoptions->marks;
227
            $params['markdp']          = $displayoptions->markdp;
228
            $params['feedback']        = (bool) $displayoptions->feedback;
229
            $params['generalfeedback'] = (bool) $displayoptions->generalfeedback;
230
            $params['rightanswer']     = (bool) $displayoptions->rightanswer;
231
            $params['history']         = (bool) $displayoptions->history;
232
        }
233
 
234
        if (!is_null($returnurl)) {
235
            $params['returnurl'] = $returnurl;
236
        }
237
 
238
        if ($variant) {
239
            $params['variant'] = $variant;
240
        }
241
 
242
        return new moodle_url('/question/bank/previewquestion/preview.php', $params);
243
    }
244
 
245
    /**
246
     * Popup params for the question preview.
247
     *
248
     * @return array that can be passed as $params to the {@see popup_action} constructor.
249
     */
250
    public static function question_preview_popup_params(): array {
251
        return [
252
                'height' => 600,
253
                'width' => 800,
254
        ];
255
    }
256
 
257
    /**
258
     * Get the extra elements for preview from qbank plugins.
259
     *
260
     * @param  question_definition $question question definition object
261
     * @param  int $courseid id of the course
262
     * @return array
263
     */
264
    public static function get_preview_extra_elements(question_definition $question, int $courseid): array {
265
        $plugins = get_plugin_list_with_function('qbank', 'preview_display');
266
 
267
        $comment = '';
268
        $extrahtml = [];
269
        foreach ($plugins as $componentname => $plugin) {
270
            $pluginhtml = component_callback($componentname, 'preview_display', [$question, $courseid]);
271
            if ($componentname === 'qbank_comment') {
272
                $comment = $pluginhtml;
273
                continue;
274
            }
275
            $extrahtml[] = $pluginhtml;
276
        }
277
        return [$comment, $extrahtml];
278
    }
279
 
280
    /**
281
     * Checks if question is the latest version.
282
     *
283
     * @param string $version Question version to check
284
     * @param string $questionbankentryid Entry to check against
285
     * @return bool
286
     */
287
    public static function is_latest(string $version, string $questionbankentryid): bool {
288
        global $DB;
289
 
290
        $sql = 'SELECT MAX(version) AS max
291
                  FROM {question_versions}
292
                 WHERE questionbankentryid = ?';
293
        $latestversion = $DB->get_record_sql($sql, [$questionbankentryid]);
294
 
295
        if (isset($latestversion->max)) {
296
            return ($version === $latestversion->max) ? true : false;
297
        }
298
        return false;
299
    }
300
 
301
    /**
302
     * Loads question version ids for current question.
303
     *
304
     * @param  string $questionbankentryid Question bank entry id
305
     * @return array  $questionids Array containing question id as key and version as value.
306
     */
307
    public static function load_versions(string $questionbankentryid): array {
308
        global $DB;
309
 
310
        $questionids = [];
311
        $sql = 'SELECT version, questionid
312
                  FROM {question_versions}
313
                 WHERE questionbankentryid = ?
314
              ORDER BY version';
315
 
316
        $versions = $DB->get_records_sql($sql, [$questionbankentryid]);
317
        foreach ($versions as $key => $version) {
318
            $questionids[$version->questionid] = $key;
319
        }
320
        return $questionids;
321
    }
322
 
323
    /**
324
     * Return the question ID from the array of id => version that corresponds to the requested version.
325
     *
326
     * If the requested version is question_preview_options::ALWAYS_LATEST, this will return the latest version.
327
     *
328
     * @param array $versions
329
     * @param int $restartversion
330
     * @return ?int
331
     */
332
    public static function get_restart_id(array $versions, int $restartversion): ?int {
333
        if ($restartversion === question_preview_options::ALWAYS_LATEST) {
334
            return array_key_last($versions);
335
        } else {
336
            return array_search($restartversion, $versions) ?: null;
337
        }
338
    }
339
}