Uses workshop renderer to display assessment page
[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
6e309973
DM
50/**
51 * The base class of workshop instances
52 *
a7c5b918 53 * It defines methods that are part of any activity module API and may be called by Moodle core.
6e309973
DM
54 * The class just wraps the database record from the {workshop} table and adds some
55 * methods that implement the compulsory activity module API.
a7c5b918 56 * For full-featured workshop class see {@link workshop_api}.
6e309973
DM
57 */
58class workshop {
59
a7c5b918 60 /** @var object course module record */
6e309973
DM
61 public $cm;
62
a7c5b918
DM
63 /** @var object course record */
64 public $courserecord;
65
6e309973 66 /**
6e309973
DM
67 *
68 * Initializes the object using the data from DB. Makes deep copy of all $dbrecord properties.
a7c5b918
DM
69 * Please do not confuse $this->course (integer property from the database record) and
70 * $this->courserecord (object containing the whole course record).
6e309973 71 *
a7c5b918
DM
72 * @param object $instance The instance data row from {workshop} table
73 * @param object $cm Course module record
74 * @param object $courserecord Course record
6e309973 75 */
a7c5b918 76 public function __construct(stdClass $instance, stdClass $cm, stdClass $courserecord) {
6e309973
DM
77 foreach ($instance as $key => $val) {
78 if (is_object($val) || (is_array($val))) {
79 // this should not happen if the $dbrecord is really just the record returned by $DB
80 $this->{$key} = unserialize(serialize($val));
81 } else {
82 $this->{$key} = $val;
83 }
84 }
85 $this->cm = $cm;
a7c5b918 86 $this->courserecord = $courserecord;
6e309973
DM
87 }
88
6e309973
DM
89 /**
90 * Saves a new instance of the workshop into the database
91 *
92 * Given an object containing all the necessary data,
93 * (defined by the form in mod_form.php) this function
94 * will save a new instance and return the id number
95 * of the new instance.
96 *
97 * @param object $data An object from the form in mod_form.php
98 * @return int The id of the newly inserted workshop record
99 */
100 public static function add_instance($data) {
101 global $DB;
102
103 $data->timecreated = time();
104 $data->timemodified = $data->timecreated;
105
106 return $DB->insert_record('workshop', $data);
107 }
108}
109
4eab2e7f
DM
110/**
111 * Given an object containing all the necessary data,
112 * (defined by the form in mod_form.php) this function
113 * will create a new instance and return the id number
114 * of the new instance.
115 *
6e309973 116 * @param object $data An object from the form in mod_form.php
4eab2e7f
DM
117 * @return int The id of the newly inserted workshop record
118 */
6e309973
DM
119function workshop_add_instance($data) {
120 return workshop::add_instance($data);
4eab2e7f
DM
121}
122
a7c5b918
DM
123// TODO convert following functions into workshop methods
124
4eab2e7f
DM
125/**
126 * Given an object containing all the necessary data,
127 * (defined by the form in mod_form.php) this function
128 * will update an existing instance with new data.
129 *
130 * @param object $workshop An object from the form in mod_form.php
131 * @return boolean Success/Fail
132 */
133function workshop_update_instance($workshop) {
134 global $DB;
135
136 $workshop->timemodified = time();
137 $workshop->id = $workshop->instance;
138
139 return $DB->update_record('workshop', $workshop);
140}
141
4eab2e7f
DM
142/**
143 * Given an ID of an instance of this module,
144 * this function will permanently delete the instance
145 * and any data that depends on it.
146 *
147 * @param int $id Id of the module instance
148 * @return boolean Success/Failure
149 */
150function workshop_delete_instance($id) {
151 global $DB;
152
153 if (! $workshop = $DB->get_record('workshop', array('id' => $id))) {
154 return false;
155 }
156
157 $result = true;
158
159 # Delete any dependent records here #
160
161 if (! $DB->delete_records('workshop', array('id' => $workshop->id))) {
162 $result = false;
163 }
164
165 return $result;
166}
167
4eab2e7f
DM
168/**
169 * Return a small object with summary information about what a
170 * user has done with a given particular instance of this module
171 * Used for user activity reports.
172 * $return->time = the time they did it
173 * $return->info = a short text description
174 *
175 * @return null
176 * @todo Finish documenting this function
177 */
178function workshop_user_outline($course, $user, $mod, $workshop) {
179 $return = new stdClass;
180 $return->time = 0;
181 $return->info = '';
182 return $return;
183}
184
4eab2e7f
DM
185/**
186 * Print a detailed representation of what a user has done with
187 * a given particular instance of this module, for user activity reports.
188 *
189 * @return boolean
190 * @todo Finish documenting this function
191 */
192function workshop_user_complete($course, $user, $mod, $workshop) {
193 return true;
194}
195
4eab2e7f
DM
196/**
197 * Given a course and a time, this module should find recent activity
198 * that has occurred in workshop activities and print it out.
199 * Return true if there was output, or false is there was none.
200 *
201 * @return boolean
202 * @todo Finish documenting this function
203 */
204function workshop_print_recent_activity($course, $isteacher, $timestart) {
205 return false; // True if anything was printed, otherwise false
206}
207
4eab2e7f
DM
208/**
209 * Function to be run periodically according to the moodle cron
210 * This function searches for things that need to be done, such
211 * as sending out mail, toggling flags etc ...
212 *
213 * @return boolean
214 * @todo Finish documenting this function
215 **/
216function workshop_cron () {
217 return true;
218}
219
4eab2e7f
DM
220/**
221 * Must return an array of user records (all data) who are participants
222 * for a given instance of workshop. Must include every user involved
223 * in the instance, independient of his role (student, teacher, admin...)
224 * See other modules as example.
225 *
226 * @param int $workshopid ID of an instance of this module
227 * @return mixed boolean/array of students
228 */
229function workshop_get_participants($workshopid) {
230 return false;
231}
232
4eab2e7f
DM
233/**
234 * This function returns if a scale is being used by one workshop
235 * if it has support for grading and scales. Commented code should be
236 * modified if necessary. See forum, glossary or journal modules
237 * as reference.
238 *
239 * @param int $workshopid ID of an instance of this module
240 * @return mixed
241 * @todo Finish documenting this function
242 */
243function workshop_scale_used($workshopid, $scaleid) {
244 $return = false;
245
246 //$rec = get_record("workshop","id","$workshopid","scale","-$scaleid");
247 //
248 //if (!empty($rec) && !empty($scaleid)) {
249 // $return = true;
250 //}
251
252 return $return;
253}
254
4eab2e7f
DM
255/**
256 * Checks if scale is being used by any instance of workshop.
257 * This function was added in 1.9
258 *
259 * This is used to find out if scale used anywhere
260 * @param $scaleid int
261 * @return boolean True if the scale is used by any workshop
262 */
263function workshop_scale_used_anywhere($scaleid) {
264 if ($scaleid and record_exists('workshop', 'grade', -$scaleid)) {
265 return true;
266 } else {
267 return false;
268 }
269}
270
4eab2e7f
DM
271/**
272 * Execute post-install custom actions for the module
273 * This function was added in 1.9
274 *
275 * @return boolean true if success, false on error
276 */
277function workshop_install() {
278 return true;
279}
280
4eab2e7f
DM
281/**
282 * Execute post-uninstall custom actions for the module
283 * This function was added in 1.9
284 *
285 * @return boolean true if success, false on error
286 */
287function workshop_uninstall() {
288 return true;
289}
290
53fad4b9
DM
291/**
292 * Returns the information if the module supports a feature
293 *
294 * @see plugin_supports() in lib/moodlelib.php
295 * @todo review and add features
296 * @param string $feature FEATURE_xx constant for requested feature
297 * @return mixed true if the feature is supported, null if unknown
298 */
299function workshop_supports($feature) {
300 switch($feature) {
301 case FEATURE_GROUPS: return true;
302 case FEATURE_GROUPINGS: return true;
303 case FEATURE_GROUPMEMBERSONLY: return true;
304 case FEATURE_MOD_INTRO: return true;
305 case FEATURE_GRADE_HAS_GRADE: return true;
306 default: return null;
307 }
308}
309
0dc47fb9
DM
310/**
311 * Returns all other caps used in the module
312 *
313 * @return array
314 */
315function workshop_get_extra_capabilities() {
316 return array('moodle/site:accessallgroups');
317}
318
b8ead2e6
DM
319////////////////////////////////////////////////////////////////////////////////
320// File API //
321////////////////////////////////////////////////////////////////////////////////
0dc47fb9
DM
322
323/**
b8ead2e6 324 * Serves the files from the workshop file areas
0dc47fb9 325 *
b8ead2e6
DM
326 * Apart from module intro (handled by pluginfile.php automatically), workshop files may be
327 * media inserted into submission content (like images) and submission attachments. For these two,
328 * the fileareas workshop_submission_content and workshop_submission_attachment are used.
329 * The access rights to the files are checked here. The user must be either a peer-reviewer
330 * of the submission or have capability ... (todo) to access the submission files.
0dc47fb9
DM
331 *
332 * @param object $course
333 * @param object $cminfo
334 * @param object $context
335 * @param string $filearea
336 * @param array $args
337 * @param bool $forcedownload
338 * @return bool false if file not found, does not return if found - justsend the file
339 */
340function workshop_pluginfile($course, $cminfo, $context, $filearea, $args, $forcedownload) {
341 global $DB;
342
343 if (!$cminfo->uservisible) {
344 return false;
345 }
346
347 $fileareas = array('workshop_submission_content', 'workshop_submission_attachment');
348 if (!in_array($filearea, $fileareas)) {
349 return false;
350 }
351
352 $submissionid = (int)array_shift($args);
353
354 if (!$cm = get_coursemodule_from_instance('workshop', $cminfo->instance, $course->id)) {
355 return false;
356 }
357
358 require_course_login($course, true, $cm);
359
360 if (!$submission = $DB->get_record('workshop_submissions', array('id' => $submissionid))) {
361 return false;
362 }
363
364 if (!$workshop = $DB->get_record('workshop', array('id' => $cminfo->instance))) {
365 return false;
366 }
367
368 $fs = get_file_storage();
369 $relativepath = '/' . implode('/', $args);
370 $fullpath = $context->id . $filearea . $submissionid . $relativepath;
371 if ((!$file = $fs->get_file_by_hash(sha1($fullpath))) || ($file->is_directory())) {
372 return false;
373 }
374 // TODO MDL-19941 make sure the user is allowed to see the submission
375
376 // finally send the file
377 send_stored_file($file, 0, 0, true); // download MUST be forced - security!
378}
379
380/**
381 * Returns the lists of all browsable file areas within the given module context
382 *
383 * The file area workshop_intro for the activity introduction field is added automatically
384 * by {@link file_browser::get_file_info_module()}
385 *
386 * @param object $course
387 * @param object $cm
388 * @param object $context
389 * @return array of [(string)filearea] => (string)description
390 */
391function workshop_get_file_areas($course, $cm, $context) {
392 $areas = array();
393 // todo re-think capability checking
394 if (has_capability('mod/workshop:submit', $context) || has_capability('mod/workshop:submitexamples', $context)) {
395 $areas['workshop_submission_content'] = get_string('areasubmissioncontent', 'workshop');
396 $areas['workshop_submission_attachment'] = get_string('areasubmissionattachment', 'workshop');
397 }
398 return $areas;
399}
400
401/**
402 * File browsing support for workshop file areas
403 *
404 * @param object $browser
405 * @param object $areas
406 * @param object $course
407 * @param object $cm
408 * @param object $context
409 * @param string $filearea
410 * @param int $itemid
411 * @param string $filepath
412 * @param string $filename
413 * @return object file_info instance or null if not found
414 */
415function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
416 global $CFG, $DB;
417 static $authors=null; // cache for submission authors
418
419 if (!($filearea == 'workshop_submission_content' || $filearea == 'workshop_submission_attachment')) {
420 return null;
421 }
422 if (is_null($itemid)) {
423 require_once($CFG->dirroot . '/mod/workshop/fileinfolib.php');
424 return new workshop_file_info($browser, $course, $cm, $context, $areas, $filearea);
425 }
426
427 $fs = get_file_storage();
428 $filepath = is_null($filepath) ? '/' : $filepath;
429 $filename = is_null($filename) ? '.' : $filename;
430 if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
431 return null;
432 }
433
434 if (is_null($authors)) {
435 $sql = 'SELECT s.id, u.lastname, u.firstname
436 FROM {workshop_submissions} s
437 JOIN {user} u ON (s.userid = u.id)
438 WHERE s.workshopid = ?';
439 $params[0] = $cm->instance;
440 $authors = $DB->get_records_sql($sql, $params);
441 }
442 $urlbase = $CFG->wwwroot . '/pluginfile.php';
443 $topvisiblename = fullname($authors[$itemid]);
444 // do not allow manual modification of any files!
445 return new file_info_stored($browser, $context, $storedfile, $urlbase, $topvisiblename, true, true, false, false);
446}
447
4eab2e7f
DM
448////////////////////////////////////////////////////////////////////////////////
449// Other functions needed by Moodle core follows. They can't be put into //
450// locallib.php because they are used by some core scripts (like modedit.php) //
451// where locallib.php is not included. //
452////////////////////////////////////////////////////////////////////////////////
453
454/**
455 * Return an array of numeric values that can be used as maximum grades
456 *
53fad4b9 457 * Used at several places where maximum grade for submission and grade for
4eab2e7f
DM
458 * assessment are defined via a HTML select form element. By default it returns
459 * an array 0, 1, 2, ..., 98, 99, 100.
53fad4b9 460 *
4eab2e7f
DM
461 * @access public
462 * @return array Array of integers
463 */
464function workshop_get_maxgrades() {
4eab2e7f
DM
465 $grades = array();
466 for ($i=100; $i>=0; $i--) {
467 $grades[$i] = $i;
468 }
469 return $grades;
470}
471
4eab2e7f
DM
472/**
473 * Return an array of possible numbers of assessments to be done
474 *
475 * Should always contain numbers 1, 2, 3, ... 10 and possibly others up to a reasonable value
476 *
477 * @return array Array of integers
478 */
479function workshop_get_numbers_of_assessments() {
4eab2e7f
DM
480 $options = array();
481 $options[30] = 30;
482 $options[20] = 20;
483 $options[15] = 15;
484 for ($i=10; $i>0; $i--) {
485 $options[$i] = $i;
486 }
487 return $options;
488}
489
4eab2e7f
DM
490/**
491 * Return an array of possible values for weight of teacher assessment
53fad4b9 492 *
4eab2e7f
DM
493 * @return array Array of integers 0, 1, 2, ..., 10
494 */
495function workshop_get_teacher_weights() {
4eab2e7f
DM
496 $weights = array();
497 for ($i=10; $i>=0; $i--) {
498 $weights[$i] = $i;
499 }
500 return $weights;
501}
502
4eab2e7f
DM
503/**
504 * Return an array of possible values of assessment dimension weight
53fad4b9 505 *
4eab2e7f
DM
506 * @return array Array of integers 0, 1, 2, ..., 16
507 */
508function workshop_get_dimension_weights() {
4eab2e7f
DM
509 $weights = array();
510 for ($i=16; $i>=0; $i--) {
511 $weights[$i] = $i;
512 }
513 return $weights;
514}
515
4eab2e7f
DM
516/**
517 * Return an array of the localized grading strategy names
518 *
519 * @access public
520 * $return array Array ['string' => 'string']
521 */
522function workshop_get_strategies() {
4eab2e7f
DM
523 $installed = get_list_of_plugins('mod/workshop/grading');
524 $forms = array();
525 foreach ($installed as $strategy) {
526 $forms[$strategy] = get_string('strategy' . $strategy, 'workshop');
527 }
528
529 return $forms;
530}
531
4eab2e7f
DM
532/**
533 * Return an array of available example assessment modes
534 *
535 * @return array Array 'mode DB code'=>'mode name'
536 */
537function workshop_get_example_modes() {
4eab2e7f
DM
538 $modes = array();
539 $modes[WORKSHOP_EXAMPLES_VOLUNTARY] = get_string('examplesvoluntary', 'workshop');
540 $modes[WORKSHOP_EXAMPLES_BEFORE_SUBMISSION] = get_string('examplesbeforesubmission', 'workshop');
541 $modes[WORKSHOP_EXAMPLES_BEFORE_ASSESSMENT] = get_string('examplesbeforeassessment', 'workshop');
542
543 return $modes;
544}
545
4eab2e7f
DM
546/**
547 * Return array of assessment comparison levels
548 *
549 * The assessment comparison level influence how the grade for assessment is calculated.
550 * Each object in the returned array provides information about the name of the level
551 * and the value of the factor to be used in the calculation.
552 * The structure of the returned array is
553 * array[code int] of object (
554 * ->name string,
555 * ->value number,
556 * )
557 * where code if the integer code that is actually stored in the database.
558 *
559 * @return array Array of objects
560 */
561function workshop_get_comparison_levels() {
4eab2e7f
DM
562 $levels = array();
563
564 $levels[WORKSHOP_COMPARISON_VERYHIGH] = new stdClass;
565 $levels[WORKSHOP_COMPARISON_VERYHIGH]->name = get_string('comparisonveryhigh', 'workshop');
566 $levels[WORKSHOP_COMPARISON_VERYHIGH]->value = 5.00;
567
568 $levels[WORKSHOP_COMPARISON_HIGH] = new stdClass;
569 $levels[WORKSHOP_COMPARISON_HIGH]->name = get_string('comparisonhigh', 'workshop');
570 $levels[WORKSHOP_COMPARISON_HIGH]->value = 3.00;
571
572 $levels[WORKSHOP_COMPARISON_NORMAL] = new stdClass;
573 $levels[WORKSHOP_COMPARISON_NORMAL]->name = get_string('comparisonnormal', 'workshop');
574 $levels[WORKSHOP_COMPARISON_NORMAL]->value = 2.50;
575
576 $levels[WORKSHOP_COMPARISON_LOW] = new stdClass;
577 $levels[WORKSHOP_COMPARISON_LOW]->name = get_string('comparisonlow', 'workshop');
578 $levels[WORKSHOP_COMPARISON_LOW]->value = 1.67;
579
580 $levels[WORKSHOP_COMPARISON_VERYLOW] = new stdClass;
581 $levels[WORKSHOP_COMPARISON_VERYLOW]->name = get_string('comparisonverylow', 'workshop');
582 $levels[WORKSHOP_COMPARISON_VERYLOW]->value = 1.00;
583
584 return $levels;
585}