Moving some helper functions from the renderer to the workshop API
[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
DM
18/**
19 * Library of interface functions and constants for module workshop
20 *
53fad4b9 21 * All the core Moodle functions, neeeded to allow the module to work
4eab2e7f 22 * integrated in Moodle should be placed here.
53fad4b9
DM
23 * All the workshop specific functions, needed to implement all the module
24 * logic, should go to locallib.php. This will help to save some memory when
4eab2e7f
DM
25 * Moodle is performing actions across all modules.
26 *
27 * @package mod-workshop
28 * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30 */
31
6867e05d 32defined('MOODLE_INTERNAL') || die();
4eab2e7f 33
4eab2e7f
DM
34/**
35 * The internal codes of the example assessment modes
36 */
37define('WORKSHOP_EXAMPLES_VOLUNTARY', 0);
38define('WORKSHOP_EXAMPLES_BEFORE_SUBMISSION', 1);
39define('WORKSHOP_EXAMPLES_BEFORE_ASSESSMENT', 2);
40
4eab2e7f
DM
41/**
42 * The internal codes of the required level of assessment similarity
43 */
44define('WORKSHOP_COMPARISON_VERYLOW', 0); /* f = 1.00 */
45define('WORKSHOP_COMPARISON_LOW', 1); /* f = 1.67 */
46define('WORKSHOP_COMPARISON_NORMAL', 2); /* f = 2.50 */
47define('WORKSHOP_COMPARISON_HIGH', 3); /* f = 3.00 */
48define('WORKSHOP_COMPARISON_VERYHIGH', 4); /* f = 5.00 */
49
b761e6d9
DM
50/**
51 * Returns the information if the module supports a feature
52 *
53 * @see plugin_supports() in lib/moodlelib.php
54 * @param string $feature FEATURE_xx constant for requested feature
55 * @return mixed true if the feature is supported, null if unknown
56 */
57function workshop_supports($feature) {
58 switch($feature) {
59 case FEATURE_GRADE_HAS_GRADE: return true;
60 case FEATURE_GROUPS: return true;
61 case FEATURE_GROUPINGS: return true;
62 case FEATURE_GROUPMEMBERSONLY: return true;
63 case FEATURE_MOD_INTRO: return true;
64 case FEATURE_MOD_SUBPLUGINS: return array(
f05c168d 65 'workshopform' => 'mod/workshop/form',
b761e6d9
DM
66 'workshopallocation' => 'mod/workshop/allocation'
67 );
68 default: return null;
69 }
70}
71
6e309973 72/**
a39d7d87 73 * Saves a new instance of the workshop into the database
6e309973 74 *
4eab2e7f
DM
75 * Given an object containing all the necessary data,
76 * (defined by the form in mod_form.php) this function
a39d7d87 77 * will save a new instance and return the id number
4eab2e7f
DM
78 * of the new instance.
79 *
65ba104c 80 * @param stdClass $data An object from the form in mod_form.php
4eab2e7f
DM
81 * @return int The id of the newly inserted workshop record
82 */
6e309973 83function workshop_add_instance($data) {
454e8dd9
DM
84 global $CFG, $DB;
85 require_once(dirname(__FILE__) . '/locallib.php');
4eab2e7f 86
454e8dd9
DM
87 $data->phase = workshop::PHASE_SETUP;
88 $data->timecreated = time();
a39d7d87
DM
89 $data->timemodified = $data->timecreated;
90
6516b9e9
DM
91 // insert the new record so we get the id
92 $data->id = $DB->insert_record('workshop', $data);
93
94 // we need to use context now, so we need to make sure all needed info is already in db
95 $cmid = $data->coursemodule;
96 $DB->set_field('course_modules', 'instance', $data->id, array('id' => $cmid));
97 $context = get_context_instance(CONTEXT_MODULE, $cmid);
98
99 // process the custom wysiwyg editors
100 if ($draftitemid = $data->instructauthorseditor['itemid']) {
101 $data->instructauthors = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructauthors',
dbb3c728 102 0, workshop::instruction_editors_options($context), $data->instructauthorseditor['text']);
6516b9e9
DM
103 $data->instructauthorsformat = $data->instructauthorseditor['format'];
104 }
105
15d12b54
DM
106 if ($draftitemid = $data->instructreviewerseditor['itemid']) {
107 $data->instructreviewers = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructreviewers',
108 0, workshop::instruction_editors_options($context), $data->instructreviewerseditor['text']);
109 $data->instructreviewersformat = $data->instructreviewerseditor['format'];
110 }
111
6516b9e9
DM
112 // re-save the record with the replaced URLs in editor fields
113 $DB->update_record('workshop', $data);
114
115 return $data->id;
a39d7d87 116}
a7c5b918 117
4eab2e7f
DM
118/**
119 * Given an object containing all the necessary data,
120 * (defined by the form in mod_form.php) this function
121 * will update an existing instance with new data.
122 *
6516b9e9
DM
123 * @param stdClass $data An object from the form in mod_form.php
124 * @return bool success
4eab2e7f 125 */
6516b9e9
DM
126function workshop_update_instance($data) {
127 global $CFG, $DB;
128 require_once(dirname(__FILE__) . '/locallib.php');
129
130 $data->timemodified = time();
131 $data->id = $data->instance;
4eab2e7f 132
f05c168d
DM
133 // todo - if the grading strategy is being changed, we must replace all aggregated peer grades with nulls
134 // todo - if maximum grades are being changed, we should probably recalculate or invalidate them
135
6516b9e9
DM
136 $DB->update_record('workshop', $data);
137 $context = get_context_instance(CONTEXT_MODULE, $data->coursemodule);
4eab2e7f 138
6516b9e9
DM
139 // process the custom wysiwyg editors
140 if ($draftitemid = $data->instructauthorseditor['itemid']) {
141 $data->instructauthors = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructauthors',
dbb3c728 142 0, workshop::instruction_editors_options($context), $data->instructauthorseditor['text']);
6516b9e9
DM
143 $data->instructauthorsformat = $data->instructauthorseditor['format'];
144 }
145
15d12b54
DM
146 if ($draftitemid = $data->instructreviewerseditor['itemid']) {
147 $data->instructreviewers = file_save_draft_area_files($draftitemid, $context->id, 'workshop_instructreviewers',
148 0, workshop::instruction_editors_options($context), $data->instructreviewerseditor['text']);
149 $data->instructreviewersformat = $data->instructreviewerseditor['format'];
150 }
151
6516b9e9
DM
152 // re-save the record with the replaced URLs in editor fields
153 return $DB->update_record('workshop', $data);
4eab2e7f
DM
154}
155
4eab2e7f
DM
156/**
157 * Given an ID of an instance of this module,
158 * this function will permanently delete the instance
159 * and any data that depends on it.
160 *
161 * @param int $id Id of the module instance
162 * @return boolean Success/Failure
163 */
164function workshop_delete_instance($id) {
165 global $DB;
166
167 if (! $workshop = $DB->get_record('workshop', array('id' => $id))) {
168 return false;
169 }
8a1ba8ac
DM
170 // delete all associated aggregations
171 $DB->delete_records('workshop_aggregations', array('workshopid' => $workshop->id));
172 // get the list of ids of all submissions
173 $submissions = $DB->get_records('workshop_submissions', array('workshopid' => $workshop->id), '', 'id');
174 // get the list of all allocated assessments
175 $assessments = $DB->get_records_list('workshop_assessments', 'submissionid', array_keys($submissions), '', 'id');
176 // delete the associated records from the workshop core tables
177 $DB->delete_records_list('workshop_grades', 'assessmentid', array_keys($assessments));
178 $DB->delete_records_list('workshop_assessments', 'id', array_keys($assessments));
179 $DB->delete_records_list('workshop_submissions', 'id', array_keys($submissions));
180 // todo call the static clean-up methods of all available subplugins
181 // ...
182 // finally remove the workshop record itself
183 $DB->delete_records('workshop', array('id' => $workshop->id));
4eab2e7f 184
8a1ba8ac 185 return true;
4eab2e7f
DM
186}
187
4eab2e7f
DM
188/**
189 * Return a small object with summary information about what a
190 * user has done with a given particular instance of this module
191 * Used for user activity reports.
192 * $return->time = the time they did it
193 * $return->info = a short text description
194 *
195 * @return null
196 * @todo Finish documenting this function
197 */
198function workshop_user_outline($course, $user, $mod, $workshop) {
65ba104c 199 $return = new stdClass();
4eab2e7f
DM
200 $return->time = 0;
201 $return->info = '';
202 return $return;
203}
204
4eab2e7f
DM
205/**
206 * Print a detailed representation of what a user has done with
207 * a given particular instance of this module, for user activity reports.
208 *
209 * @return boolean
210 * @todo Finish documenting this function
211 */
212function workshop_user_complete($course, $user, $mod, $workshop) {
213 return true;
214}
215
4eab2e7f
DM
216/**
217 * Given a course and a time, this module should find recent activity
218 * that has occurred in workshop activities and print it out.
219 * Return true if there was output, or false is there was none.
220 *
221 * @return boolean
222 * @todo Finish documenting this function
223 */
224function workshop_print_recent_activity($course, $isteacher, $timestart) {
225 return false; // True if anything was printed, otherwise false
226}
227
4eab2e7f
DM
228/**
229 * Function to be run periodically according to the moodle cron
230 * This function searches for things that need to be done, such
231 * as sending out mail, toggling flags etc ...
232 *
233 * @return boolean
234 * @todo Finish documenting this function
235 **/
236function workshop_cron () {
237 return true;
238}
239
4eab2e7f
DM
240/**
241 * Must return an array of user records (all data) who are participants
242 * for a given instance of workshop. Must include every user involved
243 * in the instance, independient of his role (student, teacher, admin...)
244 * See other modules as example.
245 *
246 * @param int $workshopid ID of an instance of this module
247 * @return mixed boolean/array of students
248 */
249function workshop_get_participants($workshopid) {
250 return false;
251}
252
4eab2e7f
DM
253/**
254 * This function returns if a scale is being used by one workshop
255 * if it has support for grading and scales. Commented code should be
256 * modified if necessary. See forum, glossary or journal modules
257 * as reference.
258 *
259 * @param int $workshopid ID of an instance of this module
260 * @return mixed
261 * @todo Finish documenting this function
262 */
263function workshop_scale_used($workshopid, $scaleid) {
264 $return = false;
265
266 //$rec = get_record("workshop","id","$workshopid","scale","-$scaleid");
267 //
268 //if (!empty($rec) && !empty($scaleid)) {
269 // $return = true;
270 //}
271
272 return $return;
273}
274
4eab2e7f
DM
275/**
276 * Checks if scale is being used by any instance of workshop.
277 * This function was added in 1.9
278 *
279 * This is used to find out if scale used anywhere
280 * @param $scaleid int
281 * @return boolean True if the scale is used by any workshop
282 */
283function workshop_scale_used_anywhere($scaleid) {
284 if ($scaleid and record_exists('workshop', 'grade', -$scaleid)) {
285 return true;
286 } else {
287 return false;
288 }
289}
290
4eab2e7f
DM
291/**
292 * Execute post-install custom actions for the module
293 * This function was added in 1.9
294 *
295 * @return boolean true if success, false on error
296 */
297function workshop_install() {
298 return true;
299}
300
0dc47fb9
DM
301/**
302 * Returns all other caps used in the module
303 *
304 * @return array
305 */
306function workshop_get_extra_capabilities() {
307 return array('moodle/site:accessallgroups');
308}
309
b8ead2e6
DM
310////////////////////////////////////////////////////////////////////////////////
311// File API //
312////////////////////////////////////////////////////////////////////////////////
0dc47fb9 313
a39d7d87
DM
314/**
315 * Returns the lists of all browsable file areas within the given module context
316 *
317 * The file area workshop_intro for the activity introduction field is added automatically
318 * by {@link file_browser::get_file_info_module()}
319 *
65ba104c
DM
320 * @param stdClass $course
321 * @param stdClass $cm
322 * @param stdClass $context
a39d7d87
DM
323 * @return array of [(string)filearea] => (string)description
324 */
325function workshop_get_file_areas($course, $cm, $context) {
326 $areas = array();
327 if (has_capability('moodle/course:managefiles', $context)) {
6516b9e9 328 $areas['workshop_instructauthors'] = get_string('areainstructauthors', 'workshop');
a39d7d87
DM
329 $areas['workshop_submission_content'] = get_string('areasubmissioncontent', 'workshop');
330 $areas['workshop_submission_attachment'] = get_string('areasubmissionattachment', 'workshop');
331 }
332 return $areas;
333}
334
0dc47fb9 335/**
b8ead2e6 336 * Serves the files from the workshop file areas
0dc47fb9 337 *
b8ead2e6
DM
338 * Apart from module intro (handled by pluginfile.php automatically), workshop files may be
339 * media inserted into submission content (like images) and submission attachments. For these two,
340 * the fileareas workshop_submission_content and workshop_submission_attachment are used.
341 * The access rights to the files are checked here. The user must be either a peer-reviewer
342 * of the submission or have capability ... (todo) to access the submission files.
6516b9e9
DM
343 * Besides that, areas workshop_instructauthors and workshop_instructreviewers contain the media
344 * embedded using the mod_form.php.
0dc47fb9 345 *
65ba104c
DM
346 * @param stdClass $course
347 * @param stdClass $cminfo
348 * @param stdClass $context
0dc47fb9
DM
349 * @param string $filearea
350 * @param array $args
351 * @param bool $forcedownload
6516b9e9 352 * @return void this should never return to the caller
0dc47fb9 353 */
6516b9e9 354function workshop_pluginfile($course, $cminfo, $context, $filearea, array $args, $forcedownload) {
0dc47fb9
DM
355 global $DB;
356
357 if (!$cminfo->uservisible) {
6516b9e9 358 send_file_not_found();
0dc47fb9 359 }
0dc47fb9 360 if (!$cm = get_coursemodule_from_instance('workshop', $cminfo->instance, $course->id)) {
6516b9e9
DM
361 send_file_not_found();
362 }
363 require_login($course, true, $cm);
364
365 if ($filearea === 'workshop_instructauthors') {
366 // submission instructions may contain sensitive data
367 if (!has_any_capability(array('moodle/course:manageactivities', 'mod/workshop:submit'), $context)) {
368 send_file_not_found();
369 }
370
371 array_shift($args); // we do not use itemids here
372 $relativepath = '/' . implode('/', $args);
373 $fullpath = $context->id . $filearea . '0' . $relativepath; // beware, slashes are not used here!
374
375 $fs = get_file_storage();
376 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
15d12b54
DM
377 send_file_not_found();
378 }
379
380 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
381
382 // finally send the file
383 send_stored_file($file, $lifetime, 0);
384 }
385
386 if ($filearea === 'workshop_instructreviewers') {
387 // submission instructions may contain sensitive data
388 if (!has_any_capability(array('moodle/course:manageactivities', 'mod/workshop:peerassess'), $context)) {
389 send_file_not_found();
390 }
391
392 array_shift($args); // we do not use itemids here
393 $relativepath = '/' . implode('/', $args);
394 $fullpath = $context->id . $filearea . '0' . $relativepath; // beware, slashes are not used here!
395
396 $fs = get_file_storage();
397 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
6516b9e9
DM
398 send_file_not_found();
399 }
400
401 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
402
403 // finally send the file
404 send_stored_file($file, $lifetime, 0);
0dc47fb9 405 }
0dc47fb9 406
dbb3c728
DM
407 // the following file areas are for the files embedded into the assessment forms
408 if (in_array($filearea, array(
409 'workshopform_comments_description',
410 'workshopform_accumulative_description',
411 'workshopform_numerrors_description',
412 'workshopform_rubric_description',
413 ))) {
414 $itemid = (int)array_shift($args); // the id of the assessment form dimension
415 if (!$dimension = $DB->get_record('workshopform_numerrors', array('id' => $itemid))) {
416 send_file_not_found();
18cbfe9b
DM
417 }
418 if (!$workshop = $DB->get_record('workshop', array('id' => $cminfo->instance))) {
dbb3c728 419 send_file_not_found();
18cbfe9b
DM
420 }
421 if ($workshop->id !== $dimension->workshopid) {
422 // this should never happen but just in case
dbb3c728 423 send_file_not_found();
18cbfe9b
DM
424 }
425 // TODO now make sure the user is allowed to see the file
dbb3c728 426 // (media embedded into the dimension description)
18cbfe9b
DM
427 $fs = get_file_storage();
428 $relativepath = '/' . implode('/', $args);
429 $fullpath = $context->id . $filearea . $itemid . $relativepath;
430 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
431 return false;
432 }
433 // finally send the file
a39d7d87 434 send_stored_file($file);
18cbfe9b 435 }
0dc47fb9 436
18cbfe9b
DM
437 if ($filearea === 'workshop_submission_content' or $filearea === 'workshop_submission_attachment') {
438 $itemid = (int)array_shift($args);
439 if (!$submission = $DB->get_record('workshop_submissions', array('id' => $itemid))) {
440 return false;
441 }
442 if (!$workshop = $DB->get_record('workshop', array('id' => $cminfo->instance))) {
443 return false;
444 }
445 // TODO now make sure the user is allowed to see the file
446 $fs = get_file_storage();
447 $relativepath = '/' . implode('/', $args);
448 $fullpath = $context->id . $filearea . $itemid . $relativepath;
449 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
450 return false;
451 }
452 // finally send the file
453 // these files are uploaded by students - forcing download for security reasons
a39d7d87 454 send_stored_file($file, 0, 0, true);
0dc47fb9 455 }
18cbfe9b
DM
456
457 return false;
0dc47fb9
DM
458}
459
460/**
461 * File browsing support for workshop file areas
462 *
65ba104c
DM
463 * @param stdClass $browser
464 * @param stdClass $areas
465 * @param stdClass $course
466 * @param stdClass $cm
467 * @param stdClass $context
0dc47fb9
DM
468 * @param string $filearea
469 * @param int $itemid
470 * @param string $filepath
471 * @param string $filename
65ba104c 472 * @return stdClass file_info instance or null if not found
0dc47fb9
DM
473 */
474function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
475 global $CFG, $DB;
0dc47fb9 476
a39d7d87 477 if (!has_capability('moodle/course:managefiles', $context)) {
0dc47fb9
DM
478 return null;
479 }
0dc47fb9
DM
480
481 $fs = get_file_storage();
a39d7d87
DM
482
483 if ($filearea === 'workshop_submission_content' or $filearea === 'workshop_submission_attachment') {
484
485 if (is_null($itemid)) {
486 require_once($CFG->dirroot . '/mod/workshop/fileinfolib.php');
487 return new workshop_file_info_submissions_container($browser, $course, $cm, $context, $areas, $filearea);
488 }
489
490 // we are inside the submission container
491
492 $filepath = is_null($filepath) ? '/' : $filepath;
493 $filename = is_null($filename) ? '.' : $filename;
494
495 if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
496 if ($filepath === '/' and $filename === '.') {
497 $storedfile = new virtual_root_file($context->id, $filearea, $itemid);
498 } else {
499 // not found
500 return null;
501 }
502 }
503
504 // let us display the author's name instead of itemid (submission id)
fa159f43
DM
505 // todo some sort of caching should happen here
506
235b31c8 507 $sql = 'SELECT s.id, u.lastname, u.firstname
fa159f43 508 FROM {workshop_submissions} s
00aca3c1 509 INNER JOIN {user} u ON (s.authorid = u.id)
235b31c8 510 WHERE s.workshopid = ?';
fa159f43
DM
511 $params = array($cm->instance);
512 $authors = $DB->get_records_sql($sql, $params);
a39d7d87
DM
513 $urlbase = $CFG->wwwroot . '/pluginfile.php';
514 $topvisiblename = fullname($authors[$itemid]);
515 // do not allow manual modification of any files!
516 return new file_info_stored($browser, $context, $storedfile, $urlbase, $topvisiblename, true, true, false, false);
0dc47fb9
DM
517 }
518
f05c168d 519 /* todo was replaced by subplugins' areas
a39d7d87 520 if ($filearea === 'workshop_dimension_description') {
6516b9e9
DM
521 // always only itemid 0 - TODO not true, review
522
523 $filepath = is_null($filepath) ? '/' : $filepath;
524 $filename = is_null($filename) ? '.' : $filename;
525
526 $urlbase = $CFG->wwwroot.'/pluginfile.php';
527 if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
528 if ($filepath === '/' and $filename === '.') {
529 $storedfile = new virtual_root_file($context->id, $filearea, 0);
530 } else {
531 // not found
532 return null;
533 }
534 }
535 return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, true, false);
536 }
f05c168d 537 */
6516b9e9
DM
538
539 if ($filearea === 'workshop_instructauthors') {
a39d7d87
DM
540 // always only itemid 0
541
542 $filepath = is_null($filepath) ? '/' : $filepath;
543 $filename = is_null($filename) ? '.' : $filename;
544
545 $urlbase = $CFG->wwwroot.'/pluginfile.php';
546 if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
547 if ($filepath === '/' and $filename === '.') {
548 $storedfile = new virtual_root_file($context->id, $filearea, 0);
549 } else {
550 // not found
551 return null;
552 }
553 }
554 return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, true, false);
0dc47fb9 555 }
0dc47fb9
DM
556}
557
6516b9e9
DM
558////////////////////////////////////////////////////////////////////////////////
559// Navigation API //
560////////////////////////////////////////////////////////////////////////////////
561
39861053
DM
562/**
563 * Extends the global navigation tree by adding workshop nodes if there is a relevant content
564 *
b761e6d9
DM
565 * This can be called by an AJAX request so do not rely on $PAGE as it might not be set up properly.
566 *
39861053
DM
567 * @param navigation_node $navref An object representing the navigation tree node of the workshop module instance
568 * @param stdClass $course
569 * @param stdClass $module
570 * @param stdClass $cm
571 */
572function workshop_extend_navigation(navigation_node $navref, stdClass $course, stdClass $module, stdClass $cm) {
573 global $CFG;
574
575 if (has_capability('mod/workshop:submit', $cm->context)) {
576 $url = new moodle_url($CFG->wwwroot.'/mod/workshop/submission.php', array('cmid' => $cm->id));
b761e6d9
DM
577 $mysubmissionkey = $navref->add(get_string('mysubmission', 'workshop'), $url);
578 $navref->get($mysubmissionkey)->mainnavonly = true;
39861053
DM
579 }
580}
581
582/**
583 * Extends the settings navigation with the Workshop settings
584
b761e6d9
DM
585 * This function is called when the context for the page is a workshop module. This is not called by AJAX
586 * so it is safe to rely on the $PAGE.
39861053
DM
587 *
588 * @param settings_navigation $settingsnav {@link settings_navigation}
589 * @param stdClass $module
590 * @return void|mixed The key to the modules branch
591 */
592function workshop_extend_settings_navigation(settings_navigation $settingsnav, stdClass $module=null) {
593 global $CFG, $PAGE;
594
595 $workshopkey = $settingsnav->add(get_string('workshopadministration', 'workshop'));
596 $workshopnode = $settingsnav->get($workshopkey);
597 $workshopnode->forceopen = true;
598 //$workshopobject = $DB->get_record("workshop", array("id" => $PAGE->cm->instance));
599
b761e6d9 600 if (has_capability('mod/workshop:editdimensions', $PAGE->cm->context)) {
39861053 601 $url = new moodle_url($CFG->wwwroot . '/mod/workshop/editform.php', array('cmid' => $PAGE->cm->id));
b761e6d9 602 $workshopnode->add(get_string('editassessmentform', 'workshop'), $url, settings_navigation::TYPE_SETTING);
39861053
DM
603 }
604 if (has_capability('mod/workshop:allocate', $PAGE->context)) {
605 $url = new moodle_url($CFG->wwwroot . '/mod/workshop/allocation.php', array('cmid' => $PAGE->cm->id));
b761e6d9 606 $workshopnode->add(get_string('allocate', 'workshop'), $url, settings_navigation::TYPE_SETTING);
39861053
DM
607 }
608}
609
610
611
4eab2e7f
DM
612////////////////////////////////////////////////////////////////////////////////
613// Other functions needed by Moodle core follows. They can't be put into //
614// locallib.php because they are used by some core scripts (like modedit.php) //
615// where locallib.php is not included. //
616////////////////////////////////////////////////////////////////////////////////
617
618/**
619 * Return an array of numeric values that can be used as maximum grades
620 *
53fad4b9 621 * Used at several places where maximum grade for submission and grade for
4eab2e7f
DM
622 * assessment are defined via a HTML select form element. By default it returns
623 * an array 0, 1, 2, ..., 98, 99, 100.
53fad4b9 624 *
4eab2e7f
DM
625 * @return array Array of integers
626 */
627function workshop_get_maxgrades() {
4eab2e7f
DM
628 $grades = array();
629 for ($i=100; $i>=0; $i--) {
630 $grades[$i] = $i;
631 }
632 return $grades;
633}
634
4eab2e7f
DM
635/**
636 * Return an array of possible numbers of assessments to be done
637 *
638 * Should always contain numbers 1, 2, 3, ... 10 and possibly others up to a reasonable value
639 *
640 * @return array Array of integers
641 */
642function workshop_get_numbers_of_assessments() {
4eab2e7f
DM
643 $options = array();
644 $options[30] = 30;
645 $options[20] = 20;
646 $options[15] = 15;
647 for ($i=10; $i>0; $i--) {
648 $options[$i] = $i;
649 }
650 return $options;
651}
652
4eab2e7f
DM
653/**
654 * Return an array of possible values for weight of teacher assessment
53fad4b9 655 *
4eab2e7f
DM
656 * @return array Array of integers 0, 1, 2, ..., 10
657 */
658function workshop_get_teacher_weights() {
4eab2e7f
DM
659 $weights = array();
660 for ($i=10; $i>=0; $i--) {
661 $weights[$i] = $i;
662 }
663 return $weights;
664}
665
4eab2e7f
DM
666/**
667 * Return an array of possible values of assessment dimension weight
53fad4b9 668 *
4eab2e7f
DM
669 * @return array Array of integers 0, 1, 2, ..., 16
670 */
671function workshop_get_dimension_weights() {
4eab2e7f
DM
672 $weights = array();
673 for ($i=16; $i>=0; $i--) {
674 $weights[$i] = $i;
675 }
676 return $weights;
677}
678
4eab2e7f
DM
679/**
680 * Return an array of the localized grading strategy names
681 *
f05c168d 682 * @todo remove this function from lib.php
4eab2e7f
DM
683 * $return array Array ['string' => 'string']
684 */
685function workshop_get_strategies() {
f05c168d 686 $installed = get_plugin_list('workshopform');
4eab2e7f 687 $forms = array();
ed597c77 688 foreach ($installed as $strategy => $strategypath) {
f05c168d
DM
689 if (file_exists($strategypath . '/lib.php')) {
690 $forms[$strategy] = get_string('pluginname', 'workshopform_' . $strategy);
ed597c77 691 }
4eab2e7f 692 }
4eab2e7f
DM
693 return $forms;
694}
695
4eab2e7f
DM
696/**
697 * Return an array of available example assessment modes
698 *
699 * @return array Array 'mode DB code'=>'mode name'
700 */
701function workshop_get_example_modes() {
4eab2e7f
DM
702 $modes = array();
703 $modes[WORKSHOP_EXAMPLES_VOLUNTARY] = get_string('examplesvoluntary', 'workshop');
704 $modes[WORKSHOP_EXAMPLES_BEFORE_SUBMISSION] = get_string('examplesbeforesubmission', 'workshop');
705 $modes[WORKSHOP_EXAMPLES_BEFORE_ASSESSMENT] = get_string('examplesbeforeassessment', 'workshop');
706
707 return $modes;
708}
709
4eab2e7f
DM
710/**
711 * Return array of assessment comparison levels
712 *
713 * The assessment comparison level influence how the grade for assessment is calculated.
714 * Each object in the returned array provides information about the name of the level
715 * and the value of the factor to be used in the calculation.
716 * The structure of the returned array is
65ba104c 717 * array[code int] of stdClass (
4eab2e7f
DM
718 * ->name string,
719 * ->value number,
720 * )
721 * where code if the integer code that is actually stored in the database.
722 *
723 * @return array Array of objects
724 */
725function workshop_get_comparison_levels() {
4eab2e7f
DM
726 $levels = array();
727
65ba104c 728 $levels[WORKSHOP_COMPARISON_VERYHIGH] = new stdClass();
4eab2e7f
DM
729 $levels[WORKSHOP_COMPARISON_VERYHIGH]->name = get_string('comparisonveryhigh', 'workshop');
730 $levels[WORKSHOP_COMPARISON_VERYHIGH]->value = 5.00;
731
65ba104c 732 $levels[WORKSHOP_COMPARISON_HIGH] = new stdClass();
4eab2e7f
DM
733 $levels[WORKSHOP_COMPARISON_HIGH]->name = get_string('comparisonhigh', 'workshop');
734 $levels[WORKSHOP_COMPARISON_HIGH]->value = 3.00;
735
65ba104c 736 $levels[WORKSHOP_COMPARISON_NORMAL] = new stdClass();
4eab2e7f
DM
737 $levels[WORKSHOP_COMPARISON_NORMAL]->name = get_string('comparisonnormal', 'workshop');
738 $levels[WORKSHOP_COMPARISON_NORMAL]->value = 2.50;
739
65ba104c 740 $levels[WORKSHOP_COMPARISON_LOW] = new stdClass();
4eab2e7f
DM
741 $levels[WORKSHOP_COMPARISON_LOW]->name = get_string('comparisonlow', 'workshop');
742 $levels[WORKSHOP_COMPARISON_LOW]->value = 1.67;
743
65ba104c 744 $levels[WORKSHOP_COMPARISON_VERYLOW] = new stdClass();
4eab2e7f
DM
745 $levels[WORKSHOP_COMPARISON_VERYLOW]->name = get_string('comparisonverylow', 'workshop');
746 $levels[WORKSHOP_COMPARISON_VERYLOW]->value = 1.00;
747
748 return $levels;
749}