MDL-36289: Assignment - Prevent feedback files being copied to the next user when...
[moodle.git] / mod / assign / assignmentplugin.php
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/>.
17 /**
18  * This file contains the functions for assign_plugin abstract class
19  *
20  *
21  * @package   mod_assign
22  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 /**
29  * Abstract class for assign_plugin (submission/feedback).
30  *
31  * @package   mod_assign
32  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
33  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 abstract class assign_plugin {
37     /** @var assign $assignment the assignment record that contains the global settings for this assign instance */
38     protected $assignment;
39     /** @var string $type assignment plugin type */
40     private $type = '';
41     /** @var string $error error message */
42     private $error = '';
45     /**
46      * Constructor for the abstract plugin type class
47      *
48      * @param assign $assignment
49      * @param string $type
50      */
51     public final function __construct(assign $assignment, $type) {
52         $this->assignment = $assignment;
53         $this->type = $type;
54     }
56     /**
57      * Is this the first plugin in the list?
58      *
59      * @return bool
60      */
61     public final function is_first() {
62         $order = get_config($this->get_subtype() . '_' . $this->get_type(), 'sortorder');
64         if ($order == 0) {
65             return true;
66         }
67         return false;
68     }
70     /**
71      * Is this the last plugin in the list?
72      *
73      * @return bool
74      */
75     public final function is_last() {
76         if ((count(get_plugin_list($this->get_subtype()))-1) == get_config($this->get_subtype() . '_' . $this->get_type(), 'sortorder')) {
77             return true;
78         }
80         return false;
81     }
83     /**
84      * This function should be overridden to provide an array of elements that can be added to a moodle
85      * form for display in the settings page for the assignment.
86      * @param MoodleQuickForm $mform The form to add the elements to
87      * @return $array
88      */
89     public function get_settings(MoodleQuickForm $mform) {
90         return;
91     }
93     /**
94      * Allows the plugin to update the defaultvalues passed in to
95      * the settings form (needed to set up draft areas for editor
96      * and filemanager elements)
97      * @param array $defaultvalues
98      */
99     public function data_preprocessing(&$defaultvalues) {
100         return;
101     }
103     /**
104      * The assignment subtype is responsible for saving it's own settings as the database table for the
105      * standard type cannot be modified.
106      *
107      * @param stdClass $formdata - the data submitted from the form
108      * @return bool - on error the subtype should call set_error and return false.
109      */
110     public function save_settings(stdClass $formdata) {
111         return true;
112     }
114     /**
115      * Save the error message from the last error
116      *
117      * @param string $msg - the error description
118      */
119     protected final function set_error($msg) {
120         $this->error = $msg;
121     }
123     /**
124      * What was the last error?
125      *
126      *
127      * @return string
128      */
129     public final function get_error() {
130         return $this->error;
131     }
133     /**
134      * Should return the name of this plugin type.
135      *
136      * @return string - the name
137      */
138     public abstract function get_name();
140     /**
141      * Should return the subtype of this plugin.
142      *
143      * @return string - either 'assignsubmission' or 'feedback'
144      */
145     public abstract function get_subtype();
147     /**
148      * Should return the type of this plugin.
149      *
150      * @return string - the type
151      */
152     public final function get_type() {
153         return $this->type;
154     }
156     /**
157      * Get the installed version of this plugin
158      *
159      * @return string
160      */
161     public final function get_version() {
162         $version = get_config($this->get_subtype() . '_' . $this->get_type(), 'version');
163         if ($version) {
164             return $version;
165         } else {
166             return '';
167         }
168     }
170     /**
171      * Get the required moodle version for this plugin
172      *
173      * @return string
174      */
175     public final function get_requires() {
176         $requires = get_config($this->get_subtype() . '_' . $this->get_type(), 'requires');
177         if ($requires) {
178             return $requires;
179         } else {
180             return '';
181         }
182     }
184     /**
185      * Save any custom data for this form submission
186      *
187      * @param stdClass $submissionorgrade - assign_submission or assign_grade
188      *              For submission plugins this is the submission data, for feedback plugins it is the grade data
189      * @param stdClass $data - the data submitted from the form
190      * @return bool - on error the subtype should call set_error and return false.
191      */
192     public function save(stdClass $submissionorgrade, stdClass $data) {
193         return true;
194     }
196     /**
197      * Set this plugin to enabled
198      *
199      * @return bool
200      */
201     public final function enable() {
202         return $this->set_config('enabled', 1);
203     }
205     /**
206      * Set this plugin to disabled
207      *
208      * @return bool
209      */
210     public final function disable() {
211         return $this->set_config('enabled', 0);
212     }
214     /**
215      * Allows hiding this plugin from the submission/feedback screen if it is not enabled.
216      *
217      * @return bool - if false - this plugin will not accept submissions / feedback
218      */
219     public final function is_enabled() {
220         return $this->get_config('enabled');
221     }
224     /**
225      * Get any additional fields for the submission/grading form for this assignment.
226      *
227      * @param mixed $submissionorgrade submission|grade - For submission plugins this is the submission data,
228      *                                                    for feedback plugins it is the grade data
229      * @param MoodleQuickForm $mform - This is the form
230      * @param stdClass $data - This is the form data that can be modified for example by a filemanager element
231      * @param int $userid - This is the userid for the current submission.
232      *                      This is passed separately as there may not yet be a submission or grade.
233      * @return boolean - true if we added anything to the form
234      */
235     public function get_form_elements_for_user($submissionorgrade, MoodleQuickForm $mform, stdClass $data, $userid) {
236         return $this->get_form_elements($submissionorgrade, $mform, $data);
237     }
239     /**
240      * Get any additional fields for the submission/grading form for this assignment.
241      * This function is retained for backwards compatibility - new plugins should override {@link get_form_elements_for_user()}.
242      *
243      * @param mixed $submissionorgrade submission|grade - For submission plugins this is the submission data, for feedback plugins it is the grade data
244      * @param MoodleQuickForm $mform - This is the form
245      * @param stdClass $data - This is the form data that can be modified for example by a filemanager element
246      * @return boolean - true if we added anything to the form
247      */
248     public function get_form_elements($submissionorgrade, MoodleQuickForm $mform, stdClass $data) {
249         return false;
250     }
252     /**
253      * Should not output anything - return the result as a string so it can be consumed by webservices.
254      *
255      * @param stdClass $submissionorgrade assign_submission or assign_grade
256      *                 For submission plugins this is the submission data, for feedback plugins it is the grade data
257      * @return string - return a string representation of the submission in full
258      */
259     public function view(stdClass $submissionorgrade) {
260         return '';
261     }
263     /**
264      * Get the numerical sort order for this plugin
265      *
266      * @return int
267      */
268     public final function get_sort_order() {
269         $order = get_config($this->get_subtype() . '_' . $this->get_type(), 'sortorder');
270         return $order?$order:0;
271     }
273     /**
274      * Is this plugin enaled?
275      *
276      * @return bool
277      */
278     public final function is_visible() {
279         $disabled = get_config($this->get_subtype() . '_' . $this->get_type(), 'disabled');
280         return !$disabled;
281     }
284     /**
285      * Has this plugin got a custom settings.php file?
286      *
287      * @return bool
288      */
289     public final function has_admin_settings() {
290         global $CFG;
292         return file_exists($CFG->dirroot . '/mod/assign/' . substr($this->get_subtype(), strlen('assign')) . '/' . $this->get_type() . '/settings.php');
293     }
295     /**
296      * Set a configuration value for this plugin
297      *
298      * @param string $name The config key
299      * @param string $value The config value
300      * @return bool
301      */
302     public final function set_config($name, $value) {
303         global $DB;
305         $current = $DB->get_record('assign_plugin_config', array('assignment'=>$this->assignment->get_instance()->id, 'subtype'=>$this->get_subtype(), 'plugin'=>$this->get_type(), 'name'=>$name), '*', IGNORE_MISSING);
307         if ($current) {
308             $current->value = $value;
309             return $DB->update_record('assign_plugin_config', $current);
310         } else {
311             $setting = new stdClass();
312             $setting->assignment = $this->assignment->get_instance()->id;
313             $setting->subtype = $this->get_subtype();
314             $setting->plugin = $this->get_type();
315             $setting->name = $name;
316             $setting->value = $value;
318             return $DB->insert_record('assign_plugin_config', $setting) > 0;
319         }
320     }
322     /**
323      * Get a configuration value for this plugin
324      *
325      * @param mixed $setting The config key (string) or null
326      * @return mixed string | false
327      */
328     public final function get_config($setting = null) {
329         global $DB;
331         if ($setting) {
332             if (!$this->assignment->has_instance()) {
333                 return false;
334             }
335             $assignment = $this->assignment->get_instance();
336             if ($assignment) {
337                 $result = $DB->get_record('assign_plugin_config', array('assignment'=>$assignment->id, 'subtype'=>$this->get_subtype(), 'plugin'=>$this->get_type(), 'name'=>$setting), '*', IGNORE_MISSING);
338                 if ($result) {
339                     return $result->value;
340                 }
341             }
342             return false;
343         }
344         $results = $DB->get_records('assign_plugin_config', array('assignment'=>$this->assignment->get_instance()->id, 'subtype'=>$this->get_subtype(), 'plugin'=>$this->get_type()));
346         $config = new stdClass();
347         if (is_array($results)) {
348             foreach ($results as $setting) {
349                 $name = $setting->name;
350                 $config->$name = $setting->value;
351             }
352         }
353         return $config;
354     }
356     /**
357      * Should not output anything - return the result as a string so it can be consumed by webservices.
358      *
359      * @param stdClass $submissionorgrade assign_submission or assign_grade
360      *                 For submission plugins this is the submission data, for feedback plugins it is the grade data
361      * @param bool $showviewlink Modifed to return whether or not to show a link to the full submission/feedback
362      * @return string - return a string representation of the submission in full
363      */
364     public function view_summary(stdClass $submissionorgrade, & $showviewlink) {
365         return '';
366     }
368     /**
369      * Given a field name, should return the text of an editor field that is part of
370      * this plugin. This is used when exporting to portfolio.
371      *
372      * @param string $name Name of the field.
373      * @param int $submissionid The id of the submission
374      * @return string - The text for the editor field
375      */
376     public function get_editor_text($name, $submissionid) {
377         return '';
378     }
380     /**
381      * Produce a list of files suitable for export that represent this feedback or submission
382      *
383      * @param stdClass $submissionorgrade assign_submission or assign_grade
384      *                 For submission plugins this is the submission data, for feedback plugins it is the grade data
385      * @return array - return an array of files indexed by filename
386      */
387     public function get_files(stdClass $submissionorgrade) {
388         return array();
389     }
391      /**
392      * Given a field name, should return the format of an editor field that is part of
393      * this plugin. This is used when exporting to portfolio.
394      *
395      * @param string $name Name of the field.
396      * @param int $submissionid The id of the submission
397      * @return int - The format for the editor field
398      */
399     public function get_editor_format($name, $submissionid) {
400         return 0;
401     }
403      /**
404      * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type
405      * and version.
406      *
407      * @param string $type The old assignment subtype
408      * @param int $version The old assignment version
409      * @return bool True if upgrade is possible
410      */
411     public function can_upgrade($type, $version) {
412         return false;
413     }
415      /**
416      * Upgrade the settings from the old assignment to the new one
417      *
418      * @param context $oldcontext The context for the old assignment module
419      * @param stdClass $oldassignment The data record for the old assignment
420      * @param string $log Record upgrade messages in the log
421      * @return bool true or false - false will trigger a rollback
422      */
423     public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) {
424         $log = $log . ' ' . get_string('upgradenotimplemented', 'mod_assign', array('type'=>$this->type, 'subtype'=>$this->get_subtype()));
425         return false;
426     }
428     /**
429      * Upgrade the submission from the old assignment to the new one
430      *
431      * @param context $oldcontext The data record for the old context
432      * @param stdClass $oldassignment The data record for the old assignment
433      * @param stdClass $oldsubmissionorgrade The data record for the old submission
434      * @param stdClass $submissionorgrade assign_submission or assign_grade The new submission or grade
435      * @param string $log Record upgrade messages in the log
436      * @return boolean true or false - false will trigger a rollback
437      */
438     public function upgrade(context $oldcontext, stdClass $oldassignment, stdClass $oldsubmissionorgrade, stdClass $submissionorgrade, & $log) {
439         $log = $log . ' ' . get_string('upgradenotimplemented', 'mod_assign', array('type'=>$this->type, 'subtype'=>$this->get_subtype()));
440         return false;
441     }
443     /**
444      * Formatting for log info
445      *
446      * @param stdClass $submissionorgrade assign_submission or assign_grade The new submission or grade
447      * @return string
448      */
449     public function format_for_log(stdClass $submissionorgrade) {
450         // format the info for each submission plugin add_to_log
451         return '';
452     }
454     /**
455      * The assignment has been deleted - remove the plugin specific data
456      *
457      * @return bool
458      */
459     public function delete_instance() {
460         return true;
461     }
463     /**
464      * Run cron for this plugin
465      */
466     public static function cron() {
467     }
469     /**
470      * Is this assignment plugin empty? (ie no submission or feedback)
471      * @param stdClass $submissionorgrade assign_submission or assign_grade
472      * @return bool
473      */
474     public function is_empty(stdClass $submissionorgrade) {
475         return true;
476     }
478     /**
479      * Get file areas returns a list of areas this plugin stores files
480      * @return array - An array of fileareas (keys) and descriptions (values)
481      */
482     public function get_file_areas() {
483         return array();
484     }
487     /**
488      * Default implementation of file_get_info for plugins.
489      * This is used by the filebrowser to browse a plugins file areas.
490      *
491      * This implementation should work for most plugins but can be overridden if required.
492      * @param file_browser $browser
493      * @param string $filearea
494      * @param int $itemid
495      * @param string $filepath
496      * @param string $filename
497      * @return file_info_stored
498      */
499     public function get_file_info($browser, $filearea, $itemid, $filepath, $filename) {
500         global $CFG, $DB, $USER;
501         $urlbase = $CFG->wwwroot.'/pluginfile.php';
503         // permission check on the itemid
505         if ($this->get_subtype() == 'assignsubmission') {
506             if ($itemid) {
507                 $record = $DB->get_record('assign_submission', array('id'=>$itemid), 'userid', IGNORE_MISSING);
508                 if (!$record) {
509                     return null;
510                 }
511                 if (!$this->assignment->can_view_submission($record->userid)) {
512                     return null;
513                 }
514             }
515         } else {
516             // not supported for feedback plugins
517             return null;
518         }
520         $fs = get_file_storage();
521         $filepath = is_null($filepath) ? '/' : $filepath;
522         $filename = is_null($filename) ? '.' : $filename;
523         if (!($storedfile = $fs->get_file($this->assignment->get_context()->id,
524                                           $this->get_subtype() . '_' . $this->get_type(),
525                                           $filearea,
526                                           $itemid,
527                                           $filepath,
528                                           $filename))) {
529             return null;
530         }
531         return new file_info_stored($browser,
532                                     $this->assignment->get_context(),
533                                     $storedfile,
534                                     $urlbase,
535                                     $filearea,
536                                     $itemid,
537                                     true,
538                                     true,
539                                     false);
540     }