NOBUG wiki: Fixing wiki_scale_used_anywhere()
[moodle.git] / mod / workshop / lib.php
CommitLineData
4eab2e7f 1<?php
53fad4b9
DM
2
3// This file is part of Moodle - http://moodle.org/
4//
4eab2e7f
DM
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
53fad4b9 14//
4eab2e7f
DM
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
53fad4b9 17
4eab2e7f 18/**
365c2cc2 19 * Library of functions needed by Moodle core and other subsystems
4eab2e7f 20 *
365c2cc2
DM
21 * All the functions neeeded by Moodle core, gradebook, file subsystem etc
22 * are placed here.
4eab2e7f
DM
23 *
24 * @package mod-workshop
25 * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 */
28
6867e05d 29defined('MOODLE_INTERNAL') || die();
4eab2e7f 30
365c2cc2
DM
31////////////////////////////////////////////////////////////////////////////////
32// Moodle core API //
33////////////////////////////////////////////////////////////////////////////////
34
b761e6d9
DM
35/**
36 * Returns the information if the module supports a feature
37 *
38 * @see plugin_supports() in lib/moodlelib.php
39 * @param string $feature FEATURE_xx constant for requested feature
40 * @return mixed true if the feature is supported, null if unknown
41 */
42function workshop_supports($feature) {
43 switch($feature) {
44 case FEATURE_GRADE_HAS_GRADE: return true;
45 case FEATURE_GROUPS: return true;
46 case FEATURE_GROUPINGS: return true;
47 case FEATURE_GROUPMEMBERSONLY: return true;
48 case FEATURE_MOD_INTRO: return true;
b761e6d9
DM
49 default: return null;
50 }
51}
52
6e309973 53/**
a39d7d87 54 * Saves a new instance of the workshop into the database
6e309973 55 *
4eab2e7f
DM
56 * Given an object containing all the necessary data,
57 * (defined by the form in mod_form.php) this function
a39d7d87 58 * will save a new instance and return the id number
4eab2e7f
DM
59 * of the new instance.
60 *
7a789aa8 61 * @param stdclass $workshop An object from the form in mod_form.php
4eab2e7f
DM
62 * @return int The id of the newly inserted workshop record
63 */
7a789aa8 64function workshop_add_instance(stdclass $workshop) {
454e8dd9
DM
65 global $CFG, $DB;
66 require_once(dirname(__FILE__) . '/locallib.php');
4eab2e7f 67
0d0b7d99
DM
68 $workshop->phase = workshop::PHASE_SETUP;
69 $workshop->timecreated = time();
70 $workshop->timemodified = $workshop->timecreated;
71 $workshop->useexamples = (int)!empty($workshop->useexamples); // unticked checkbox hack
72 $workshop->usepeerassessment = (int)!empty($workshop->usepeerassessment); // unticked checkbox hack
73 $workshop->useselfassessment = (int)!empty($workshop->useselfassessment); // unticked checkbox hack
74 $workshop->latesubmissions = (int)!empty($workshop->latesubmissions); // unticked checkbox hack
a39d7d87 75
6516b9e9 76 // insert the new record so we get the id
365c2cc2 77 $workshop->id = $DB->insert_record('workshop', $workshop);
6516b9e9
DM
78
79 // we need to use context now, so we need to make sure all needed info is already in db
365c2cc2
DM
80 $cmid = $workshop->coursemodule;
81 $DB->set_field('course_modules', 'instance', $workshop->id, array('id' => $cmid));
6516b9e9
DM
82 $context = get_context_instance(CONTEXT_MODULE, $cmid);
83
84 // process the custom wysiwyg editors
365c2cc2
DM
85 if ($draftitemid = $workshop->instructauthorseditor['itemid']) {
86 $workshop->instructauthors = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructauthors',
87 0, workshop::instruction_editors_options($context), $workshop->instructauthorseditor['text']);
88 $workshop->instructauthorsformat = $workshop->instructauthorseditor['format'];
6516b9e9
DM
89 }
90
365c2cc2
DM
91 if ($draftitemid = $workshop->instructreviewerseditor['itemid']) {
92 $workshop->instructreviewers = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructreviewers',
93 0, workshop::instruction_editors_options($context), $workshop->instructreviewerseditor['text']);
94 $workshop->instructreviewersformat = $workshop->instructreviewerseditor['format'];
15d12b54
DM
95 }
96
6516b9e9 97 // re-save the record with the replaced URLs in editor fields
365c2cc2 98 $DB->update_record('workshop', $workshop);
6516b9e9 99
365c2cc2
DM
100 // update gradebook item
101 workshop_grade_item_update($workshop);
102
103 return $workshop->id;
a39d7d87 104}
a7c5b918 105
4eab2e7f
DM
106/**
107 * Given an object containing all the necessary data,
108 * (defined by the form in mod_form.php) this function
109 * will update an existing instance with new data.
110 *
7a789aa8 111 * @param stdclass $workshop An object from the form in mod_form.php
6516b9e9 112 * @return bool success
4eab2e7f 113 */
7a789aa8 114function workshop_update_instance(stdclass $workshop) {
6516b9e9
DM
115 global $CFG, $DB;
116 require_once(dirname(__FILE__) . '/locallib.php');
117
0d0b7d99
DM
118 $workshop->timemodified = time();
119 $workshop->id = $workshop->instance;
120 $workshop->useexamples = (int)!empty($workshop->useexamples); // unticked checkbox hack
121 $workshop->usepeerassessment = (int)!empty($workshop->usepeerassessment); // unticked checkbox hack
122 $workshop->useselfassessment = (int)!empty($workshop->useselfassessment); // unticked checkbox hack
123 $workshop->latesubmissions = (int)!empty($workshop->latesubmissions); // unticked checkbox hack
4eab2e7f 124
f05c168d
DM
125 // todo - if the grading strategy is being changed, we must replace all aggregated peer grades with nulls
126 // todo - if maximum grades are being changed, we should probably recalculate or invalidate them
127
365c2cc2
DM
128 $DB->update_record('workshop', $workshop);
129 $context = get_context_instance(CONTEXT_MODULE, $workshop->coursemodule);
4eab2e7f 130
6516b9e9 131 // process the custom wysiwyg editors
365c2cc2
DM
132 if ($draftitemid = $workshop->instructauthorseditor['itemid']) {
133 $workshop->instructauthors = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructauthors',
134 0, workshop::instruction_editors_options($context), $workshop->instructauthorseditor['text']);
135 $workshop->instructauthorsformat = $workshop->instructauthorseditor['format'];
6516b9e9
DM
136 }
137
365c2cc2
DM
138 if ($draftitemid = $workshop->instructreviewerseditor['itemid']) {
139 $workshop->instructreviewers = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructreviewers',
140 0, workshop::instruction_editors_options($context), $workshop->instructreviewerseditor['text']);
141 $workshop->instructreviewersformat = $workshop->instructreviewerseditor['format'];
15d12b54
DM
142 }
143
6516b9e9 144 // re-save the record with the replaced URLs in editor fields
365c2cc2
DM
145 $DB->update_record('workshop', $workshop);
146
147 // update gradebook item
148 workshop_grade_item_update($workshop);
149
150 return true;
4eab2e7f
DM
151}
152
4eab2e7f
DM
153/**
154 * Given an ID of an instance of this module,
155 * this function will permanently delete the instance
156 * and any data that depends on it.
157 *
158 * @param int $id Id of the module instance
159 * @return boolean Success/Failure
160 */
161function workshop_delete_instance($id) {
f7d3a965
DM
162 global $CFG, $DB;
163 require_once($CFG->libdir.'/gradelib.php');
164
4eab2e7f
DM
165
166 if (! $workshop = $DB->get_record('workshop', array('id' => $id))) {
167 return false;
168 }
8a1ba8ac
DM
169 // delete all associated aggregations
170 $DB->delete_records('workshop_aggregations', array('workshopid' => $workshop->id));
171 // get the list of ids of all submissions
172 $submissions = $DB->get_records('workshop_submissions', array('workshopid' => $workshop->id), '', 'id');
173 // get the list of all allocated assessments
174 $assessments = $DB->get_records_list('workshop_assessments', 'submissionid', array_keys($submissions), '', 'id');
175 // delete the associated records from the workshop core tables
176 $DB->delete_records_list('workshop_grades', 'assessmentid', array_keys($assessments));
177 $DB->delete_records_list('workshop_assessments', 'id', array_keys($assessments));
178 $DB->delete_records_list('workshop_submissions', 'id', array_keys($submissions));
179 // todo call the static clean-up methods of all available subplugins
180 // ...
181 // finally remove the workshop record itself
182 $DB->delete_records('workshop', array('id' => $workshop->id));
4eab2e7f 183
365c2cc2
DM
184 // gradebook cleanup
185 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 0, null, array('deleted' => true));
186 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 1, null, array('deleted' => true));
187
8a1ba8ac 188 return true;
4eab2e7f
DM
189}
190
4eab2e7f
DM
191/**
192 * Return a small object with summary information about what a
193 * user has done with a given particular instance of this module
194 * Used for user activity reports.
195 * $return->time = the time they did it
196 * $return->info = a short text description
197 *
198 * @return null
199 * @todo Finish documenting this function
200 */
201function workshop_user_outline($course, $user, $mod, $workshop) {
7a789aa8 202 $return = new stdclass();
4eab2e7f
DM
203 $return->time = 0;
204 $return->info = '';
205 return $return;
206}
207
4eab2e7f
DM
208/**
209 * Print a detailed representation of what a user has done with
210 * a given particular instance of this module, for user activity reports.
211 *
212 * @return boolean
213 * @todo Finish documenting this function
214 */
215function workshop_user_complete($course, $user, $mod, $workshop) {
216 return true;
217}
218
4eab2e7f
DM
219/**
220 * Given a course and a time, this module should find recent activity
221 * that has occurred in workshop activities and print it out.
222 * Return true if there was output, or false is there was none.
223 *
224 * @return boolean
225 * @todo Finish documenting this function
226 */
227function workshop_print_recent_activity($course, $isteacher, $timestart) {
228 return false; // True if anything was printed, otherwise false
229}
230
4eab2e7f
DM
231/**
232 * Function to be run periodically according to the moodle cron
233 * This function searches for things that need to be done, such
234 * as sending out mail, toggling flags etc ...
235 *
236 * @return boolean
237 * @todo Finish documenting this function
238 **/
239function workshop_cron () {
240 return true;
241}
242
4eab2e7f
DM
243/**
244 * Must return an array of user records (all data) who are participants
245 * for a given instance of workshop. Must include every user involved
246 * in the instance, independient of his role (student, teacher, admin...)
247 * See other modules as example.
248 *
249 * @param int $workshopid ID of an instance of this module
250 * @return mixed boolean/array of students
251 */
252function workshop_get_participants($workshopid) {
253 return false;
254}
255
4eab2e7f
DM
256/**
257 * This function returns if a scale is being used by one workshop
258 * if it has support for grading and scales. Commented code should be
259 * modified if necessary. See forum, glossary or journal modules
260 * as reference.
261 *
262 * @param int $workshopid ID of an instance of this module
263 * @return mixed
264 * @todo Finish documenting this function
265 */
266function workshop_scale_used($workshopid, $scaleid) {
267 $return = false;
268
269 //$rec = get_record("workshop","id","$workshopid","scale","-$scaleid");
270 //
271 //if (!empty($rec) && !empty($scaleid)) {
272 // $return = true;
273 //}
274
275 return $return;
276}
277
4eab2e7f
DM
278/**
279 * Checks if scale is being used by any instance of workshop.
280 * This function was added in 1.9
281 *
282 * This is used to find out if scale used anywhere
283 * @param $scaleid int
284 * @return boolean True if the scale is used by any workshop
285 */
286function workshop_scale_used_anywhere($scaleid) {
287 if ($scaleid and record_exists('workshop', 'grade', -$scaleid)) {
288 return true;
289 } else {
290 return false;
291 }
292}
293
0dc47fb9
DM
294/**
295 * Returns all other caps used in the module
296 *
297 * @return array
298 */
299function workshop_get_extra_capabilities() {
300 return array('moodle/site:accessallgroups');
301}
302
365c2cc2
DM
303////////////////////////////////////////////////////////////////////////////////
304// Gradebook API //
305////////////////////////////////////////////////////////////////////////////////
306
307/**
308 * Creates or updates grade items for the give workshop instance
309 *
310 * Needed by grade_update_mod_grades() in lib/gradelib.php. Also used by
311 * {@link workshop_update_grades()}.
312 *
7a789aa8
DM
313 * @param stdclass $workshop instance object with extra cmidnumber and modname property
314 * @param stdclass $submissiongrades data for the first grade item
315 * @param stdclass $assessmentgrades data for the second grade item
365c2cc2
DM
316 * @return void
317 */
7a789aa8 318function workshop_grade_item_update(stdclass $workshop, $submissiongrades=null, $assessmentgrades=null) {
365c2cc2
DM
319 global $CFG;
320 require_once($CFG->libdir.'/gradelib.php');
321
7a789aa8 322 $a = new stdclass();
365c2cc2
DM
323 $a->workshopname = clean_param($workshop->name, PARAM_NOTAGS);
324
325 $item = array();
326 $item['itemname'] = get_string('gradeitemsubmission', 'workshop', $a);
327 $item['idnumber'] = $workshop->cmidnumber;
328 $item['gradetype'] = GRADE_TYPE_VALUE;
329 $item['grademax'] = $workshop->grade;
330 $item['grademin'] = 0;
331 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 0, $submissiongrades , $item);
332
333 $item = array();
334 $item['itemname'] = get_string('gradeitemassessment', 'workshop', $a);
335 $item['idnumber'] = $workshop->cmidnumber;
336 $item['gradetype'] = GRADE_TYPE_VALUE;
337 $item['grademax'] = $workshop->gradinggrade;
338 $item['grademin'] = 0;
339 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 1, $assessmentgrades, $item);
340}
341
342/**
343 * Update workshop grades in the gradebook
344 *
345 * Needed by grade_update_mod_grades() in lib/gradelib.php
346 *
7a789aa8 347 * @param stdclass $workshop instance object with extra cmidnumber and modname property
365c2cc2
DM
348 * @param int $userid update grade of specific user only, 0 means all participants
349 * @return void
350 */
7a789aa8 351function workshop_update_grades(stdclass $workshop, $userid=0) {
365c2cc2
DM
352 global $CFG, $DB;
353 require_once($CFG->libdir.'/gradelib.php');
354
355 $whereuser = $userid ? ' AND authorid = :userid' : '';
10bc4bce
DM
356 $params = array('workshopid' => $workshop->id, 'userid' => $userid);
357 $sql = 'SELECT authorid, grade, gradeover, gradeoverby, feedbackauthor, feedbackauthorformat, timemodified, timegraded
365c2cc2
DM
358 FROM {workshop_submissions}
359 WHERE workshopid = :workshopid AND example=0' . $whereuser;
10bc4bce
DM
360 $records = $DB->get_records_sql($sql, $params);
361 $submissiongrades = array();
362 foreach ($records as $record) {
7a789aa8 363 $grade = new stdclass();
10bc4bce
DM
364 $grade->userid = $record->authorid;
365 if (!is_null($record->gradeover)) {
366 $grade->rawgrade = grade_floatval($workshop->grade * $record->gradeover / 100);
367 $grade->usermodified = $record->gradeoverby;
368 } else {
369 $grade->rawgrade = grade_floatval($workshop->grade * $record->grade / 100);
370 }
371 $grade->feedback = $record->feedbackauthor;
372 $grade->feedbackformat = $record->feedbackauthorformat;
373 $grade->datesubmitted = $record->timemodified;
374 $grade->dategraded = $record->timegraded;
375 $submissiongrades[$record->authorid] = $grade;
376 }
365c2cc2
DM
377
378 $whereuser = $userid ? ' AND userid = :userid' : '';
10bc4bce
DM
379 $params = array('workshopid' => $workshop->id, 'userid' => $userid);
380 $sql = 'SELECT userid, gradinggrade, timegraded
365c2cc2
DM
381 FROM {workshop_aggregations}
382 WHERE workshopid = :workshopid' . $whereuser;
10bc4bce
DM
383 $records = $DB->get_records_sql($sql, $params);
384 $assessmentgrades = array();
385 foreach ($records as $record) {
7a789aa8 386 $grade = new stdclass();
10bc4bce
DM
387 $grade->userid = $record->userid;
388 $grade->rawgrade = grade_floatval($workshop->gradinggrade * $record->gradinggrade / 100);
389 $grade->dategraded = $record->timegraded;
390 $assessmentgrades[$record->userid] = $grade;
391 }
365c2cc2
DM
392
393 workshop_grade_item_update($workshop, $submissiongrades, $assessmentgrades);
394}
395
b8ead2e6
DM
396////////////////////////////////////////////////////////////////////////////////
397// File API //
398////////////////////////////////////////////////////////////////////////////////
0dc47fb9 399
a39d7d87
DM
400/**
401 * Returns the lists of all browsable file areas within the given module context
402 *
403 * The file area workshop_intro for the activity introduction field is added automatically
404 * by {@link file_browser::get_file_info_module()}
405 *
7a789aa8
DM
406 * @param stdclass $course
407 * @param stdclass $cm
408 * @param stdclass $context
a39d7d87
DM
409 * @return array of [(string)filearea] => (string)description
410 */
411function workshop_get_file_areas($course, $cm, $context) {
412 $areas = array();
413 if (has_capability('moodle/course:managefiles', $context)) {
6516b9e9 414 $areas['workshop_instructauthors'] = get_string('areainstructauthors', 'workshop');
94ad199b 415 $areas['workshop_instructreviewers'] = get_string('areainstructreviewers', 'workshop');
a39d7d87
DM
416 $areas['workshop_submission_content'] = get_string('areasubmissioncontent', 'workshop');
417 $areas['workshop_submission_attachment'] = get_string('areasubmissionattachment', 'workshop');
418 }
419 return $areas;
420}
421
0dc47fb9 422/**
b8ead2e6 423 * Serves the files from the workshop file areas
0dc47fb9 424 *
b8ead2e6
DM
425 * Apart from module intro (handled by pluginfile.php automatically), workshop files may be
426 * media inserted into submission content (like images) and submission attachments. For these two,
427 * the fileareas workshop_submission_content and workshop_submission_attachment are used.
428 * The access rights to the files are checked here. The user must be either a peer-reviewer
429 * of the submission or have capability ... (todo) to access the submission files.
6516b9e9
DM
430 * Besides that, areas workshop_instructauthors and workshop_instructreviewers contain the media
431 * embedded using the mod_form.php.
0dc47fb9 432 *
7a789aa8
DM
433 * @param stdclass $course
434 * @param stdclass $cminfo
435 * @param stdclass $context
0dc47fb9
DM
436 * @param string $filearea
437 * @param array $args
438 * @param bool $forcedownload
6516b9e9 439 * @return void this should never return to the caller
0dc47fb9 440 */
6516b9e9 441function workshop_pluginfile($course, $cminfo, $context, $filearea, array $args, $forcedownload) {
0dc47fb9
DM
442 global $DB;
443
444 if (!$cminfo->uservisible) {
6516b9e9 445 send_file_not_found();
0dc47fb9 446 }
0dc47fb9 447 if (!$cm = get_coursemodule_from_instance('workshop', $cminfo->instance, $course->id)) {
6516b9e9
DM
448 send_file_not_found();
449 }
450 require_login($course, true, $cm);
451
452 if ($filearea === 'workshop_instructauthors') {
453 // submission instructions may contain sensitive data
454 if (!has_any_capability(array('moodle/course:manageactivities', 'mod/workshop:submit'), $context)) {
455 send_file_not_found();
456 }
457
458 array_shift($args); // we do not use itemids here
459 $relativepath = '/' . implode('/', $args);
460 $fullpath = $context->id . $filearea . '0' . $relativepath; // beware, slashes are not used here!
461
462 $fs = get_file_storage();
463 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
15d12b54
DM
464 send_file_not_found();
465 }
466
467 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
468
469 // finally send the file
470 send_stored_file($file, $lifetime, 0);
471 }
472
473 if ($filearea === 'workshop_instructreviewers') {
474 // submission instructions may contain sensitive data
475 if (!has_any_capability(array('moodle/course:manageactivities', 'mod/workshop:peerassess'), $context)) {
476 send_file_not_found();
477 }
478
479 array_shift($args); // we do not use itemids here
480 $relativepath = '/' . implode('/', $args);
481 $fullpath = $context->id . $filearea . '0' . $relativepath; // beware, slashes are not used here!
482
483 $fs = get_file_storage();
484 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
6516b9e9
DM
485 send_file_not_found();
486 }
487
488 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
489
490 // finally send the file
491 send_stored_file($file, $lifetime, 0);
0dc47fb9 492 }
0dc47fb9 493
dbb3c728 494 // the following file areas are for the files embedded into the assessment forms
f4b5c157 495 // TODO this should be rewritten to using callbacks into subplugins
dbb3c728
DM
496 if (in_array($filearea, array(
497 'workshopform_comments_description',
498 'workshopform_accumulative_description',
499 'workshopform_numerrors_description',
500 'workshopform_rubric_description',
501 ))) {
502 $itemid = (int)array_shift($args); // the id of the assessment form dimension
d524173e 503 if (!$workshop = $DB->get_record('workshop', array('id' => $cminfo->instance))) {
dbb3c728 504 send_file_not_found();
18cbfe9b 505 }
d524173e
DM
506 switch ($filearea) {
507 case 'workshopform_comments_description':
508 $dimension = $DB->get_record('workshopform_comments', array('id' => $itemid));
509 break;
510 case 'workshopform_accumulative_description':
511 $dimension = $DB->get_record('workshopform_accumulative', array('id' => $itemid));
512 break;
513 case 'workshopform_numerrors_description':
514 $dimension = $DB->get_record('workshopform_numerrors', array('id' => $itemid));
515 break;
516 case 'workshopform_rubric_description':
517 $dimension = $DB->get_record('workshopform_rubric', array('id' => $itemid));
518 break;
519 default:
520 $dimension = false;
521 }
522 if (empty($dimension)) {
dbb3c728 523 send_file_not_found();
18cbfe9b 524 }
d524173e 525 if ($workshop->id != $dimension->workshopid) {
18cbfe9b 526 // this should never happen but just in case
dbb3c728 527 send_file_not_found();
18cbfe9b
DM
528 }
529 // TODO now make sure the user is allowed to see the file
dbb3c728 530 // (media embedded into the dimension description)
18cbfe9b
DM
531 $fs = get_file_storage();
532 $relativepath = '/' . implode('/', $args);
533 $fullpath = $context->id . $filearea . $itemid . $relativepath;
534 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
535 return false;
536 }
537 // finally send the file
a39d7d87 538 send_stored_file($file);
18cbfe9b 539 }
0dc47fb9 540
d524173e 541 if ($filearea == 'workshop_submission_content' or $filearea == 'workshop_submission_attachment') {
18cbfe9b
DM
542 $itemid = (int)array_shift($args);
543 if (!$submission = $DB->get_record('workshop_submissions', array('id' => $itemid))) {
544 return false;
545 }
546 if (!$workshop = $DB->get_record('workshop', array('id' => $cminfo->instance))) {
547 return false;
548 }
549 // TODO now make sure the user is allowed to see the file
550 $fs = get_file_storage();
551 $relativepath = '/' . implode('/', $args);
552 $fullpath = $context->id . $filearea . $itemid . $relativepath;
553 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
554 return false;
555 }
556 // finally send the file
557 // these files are uploaded by students - forcing download for security reasons
a39d7d87 558 send_stored_file($file, 0, 0, true);
0dc47fb9 559 }
18cbfe9b
DM
560
561 return false;
0dc47fb9
DM
562}
563
564/**
565 * File browsing support for workshop file areas
566 *
7a789aa8
DM
567 * @param stdclass $browser
568 * @param stdclass $areas
569 * @param stdclass $course
570 * @param stdclass $cm
571 * @param stdclass $context
0dc47fb9
DM
572 * @param string $filearea
573 * @param int $itemid
574 * @param string $filepath
575 * @param string $filename
7a789aa8 576 * @return stdclass file_info instance or null if not found
0dc47fb9
DM
577 */
578function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
579 global $CFG, $DB;
0dc47fb9 580
a39d7d87 581 if (!has_capability('moodle/course:managefiles', $context)) {
0dc47fb9
DM
582 return null;
583 }
0dc47fb9
DM
584
585 $fs = get_file_storage();
a39d7d87
DM
586
587 if ($filearea === 'workshop_submission_content' or $filearea === 'workshop_submission_attachment') {
588
589 if (is_null($itemid)) {
590 require_once($CFG->dirroot . '/mod/workshop/fileinfolib.php');
591 return new workshop_file_info_submissions_container($browser, $course, $cm, $context, $areas, $filearea);
592 }
593
594 // we are inside the submission container
595
596 $filepath = is_null($filepath) ? '/' : $filepath;
597 $filename = is_null($filename) ? '.' : $filename;
598
599 if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
600 if ($filepath === '/' and $filename === '.') {
601 $storedfile = new virtual_root_file($context->id, $filearea, $itemid);
602 } else {
603 // not found
604 return null;
605 }
606 }
607
608 // let us display the author's name instead of itemid (submission id)
fa159f43
DM
609 // todo some sort of caching should happen here
610
235b31c8 611 $sql = 'SELECT s.id, u.lastname, u.firstname
fa159f43 612 FROM {workshop_submissions} s
00aca3c1 613 INNER JOIN {user} u ON (s.authorid = u.id)
235b31c8 614 WHERE s.workshopid = ?';
fa159f43
DM
615 $params = array($cm->instance);
616 $authors = $DB->get_records_sql($sql, $params);
a39d7d87
DM
617 $urlbase = $CFG->wwwroot . '/pluginfile.php';
618 $topvisiblename = fullname($authors[$itemid]);
619 // do not allow manual modification of any files!
620 return new file_info_stored($browser, $context, $storedfile, $urlbase, $topvisiblename, true, true, false, false);
0dc47fb9
DM
621 }
622
94ad199b 623 if ($filearea == 'workshop_instructauthors' or $filearea == 'workshop_instructreviewers') {
a39d7d87
DM
624 // always only itemid 0
625
626 $filepath = is_null($filepath) ? '/' : $filepath;
627 $filename = is_null($filename) ? '.' : $filename;
628
629 $urlbase = $CFG->wwwroot.'/pluginfile.php';
630 if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
631 if ($filepath === '/' and $filename === '.') {
632 $storedfile = new virtual_root_file($context->id, $filearea, 0);
633 } else {
634 // not found
635 return null;
636 }
637 }
638 return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, true, false);
0dc47fb9 639 }
0dc47fb9
DM
640}
641
6516b9e9
DM
642////////////////////////////////////////////////////////////////////////////////
643// Navigation API //
644////////////////////////////////////////////////////////////////////////////////
645
39861053
DM
646/**
647 * Extends the global navigation tree by adding workshop nodes if there is a relevant content
648 *
b761e6d9
DM
649 * This can be called by an AJAX request so do not rely on $PAGE as it might not be set up properly.
650 *
39861053 651 * @param navigation_node $navref An object representing the navigation tree node of the workshop module instance
7a789aa8
DM
652 * @param stdclass $course
653 * @param stdclass $module
654 * @param stdclass $cm
39861053 655 */
7a789aa8 656function workshop_extend_navigation(navigation_node $navref, stdclass $course, stdclass $module, stdclass $cm) {
39861053
DM
657 global $CFG;
658
4f0c2d00 659 if (has_capability('mod/workshop:submit', get_context_instance(CONTEXT_MODULE, $cm->id))) {
a6855934 660 $url = new moodle_url('/mod/workshop/submission.php', array('cmid' => $cm->id));
3406acde
SH
661 $mysubmission = $navref->add(get_string('mysubmission', 'workshop'), $url);
662 $mysubmission->mainnavonly = true;
39861053
DM
663 }
664}
665
666/**
667 * Extends the settings navigation with the Workshop settings
668
b761e6d9
DM
669 * This function is called when the context for the page is a workshop module. This is not called by AJAX
670 * so it is safe to rely on the $PAGE.
39861053
DM
671 *
672 * @param settings_navigation $settingsnav {@link settings_navigation}
0b29477b 673 * @param navigation_node $workshopnode {@link navigation_node}
39861053 674 */
0b29477b
SH
675function workshop_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $workshopnode=null) {
676 global $PAGE;
39861053 677
39861053
DM
678 //$workshopobject = $DB->get_record("workshop", array("id" => $PAGE->cm->instance));
679
b761e6d9 680 if (has_capability('mod/workshop:editdimensions', $PAGE->cm->context)) {
a6855934 681 $url = new moodle_url('/mod/workshop/editform.php', array('cmid' => $PAGE->cm->id));
b761e6d9 682 $workshopnode->add(get_string('editassessmentform', 'workshop'), $url, settings_navigation::TYPE_SETTING);
39861053 683 }
428a28e1 684 if (has_capability('mod/workshop:allocate', $PAGE->cm->context)) {
a6855934 685 $url = new moodle_url('/mod/workshop/allocation.php', array('cmid' => $PAGE->cm->id));
b761e6d9 686 $workshopnode->add(get_string('allocate', 'workshop'), $url, settings_navigation::TYPE_SETTING);
39861053
DM
687 }
688}