MDL-33547: Fix for mod_assign portfolio export for a list of files.
[moodle.git] / mod / assign / portfolio_callback.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/>.
16 //
17 // this file contains all the functions that aren't needed by core moodle
18 // but start becoming required once we're actually inside the assignment module.
20 /**
21  * This file contains the callback class required by the portfolio api.
22  *
23  * @package   mod_assign
24  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
25  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
28 defined('MOODLE_INTERNAL') || die();
30 /** Include assign locallib.php */
31 require_once($CFG->dirroot . '/mod/assign/locallib.php');
32 /** Include portfolio caller.php */
33 require_once($CFG->libdir . '/portfolio/caller.php');
35 /**
36  * portfolio caller class for mod_assign.
37  *
38  * @package   mod_assign
39  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
40  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41  */
42 class assign_portfolio_caller extends portfolio_module_caller_base {
45     /** @var int callback arg - the id of submission we export */
46     protected $sid;
48     /** @var string callback arg - the area of submission files we export */
49     protected $area;
51     /** @var int callback arg - the id of file we export */
52     protected $fileid;
54     /** @var int callback arg - the cmid of the assignment we export */
55     protected $cmid;
57     /** @var string callback arg - the plugintype of the editor we export */
58     protected $plugin;
60     /** @var string callback arg - the name of the editor field we export */
61     protected $editor;
64    /**
65     * callback arg for a single file export
66     */
67     public static function expected_callbackargs() {
68         return array(
69             'cmid' => true,
70             'sid' => false,
71             'area' => false,
72             'component' => false,
73             'fileid' => false,
74             'plugin' => false,
75             'editor' => false,
76        );
77     }
79     /**
80      * the constructor
81      * @param array $callbackargs
82      */
83     function __construct($callbackargs) {
84         parent::__construct($callbackargs);
85         $this->cm = get_coursemodule_from_id('assign', $this->cmid, 0, false, MUST_EXIST);
86     }
88     /**
89      *
90      * Load data needed for the portfolio export
91      *
92      * If the assignment type implements portfolio_load_data(), the processing is delegated
93      * to it. Otherwise, the caller must provide either fileid (to export single file) or
94      * submissionid and filearea (to export all data attached to the given submission file area) via callback arguments.
95      *
96      * @throws     portfolio_caller_exception
97      */
98     public function load_data() {
100         $context = context_module::instance($this->cmid);
102         if (empty($this->fileid)) {
103             if (empty($this->sid) || empty($this->area)) {
104                 throw new portfolio_caller_exception('invalidfileandsubmissionid', 'mod_assign');
105             }
107         }
109         // export either an area of files or a single file (see function for more detail)
110         // the first arg is an id or null. If it is an id, the rest of the args are ignored
111         // if it is null, the rest of the args are used to load a list of files from get_areafiles
112         $this->set_file_and_format_data($this->fileid, $context->id, $this->component, $this->area, $this->sid, 'timemodified', false);
114     }
116     /**
117      * prepares the package up before control is passed to the portfolio plugin.
118      *
119      * @throws portfolio_caller_exception
120      * @return mixed
121      */
122     public function prepare_package() {
124         if ($this->plugin && $this->editor) {
125             $options = portfolio_format_text_options();
126             $context = context_module::instance($this->cmid);
127             $options->context = $context;
129             $plugin = $this->get_submission_plugin();
131             $text = $plugin->get_editor_text($this->editor, $this->sid);
132             $format = $plugin->get_editor_format($this->editor, $this->sid);
134             $html = format_text($text, $format, $options);
135             $html = portfolio_rewrite_pluginfile_urls($html, $context->id, 'mod_assign', $this->area, $this->sid, $this->exporter->get('format'));
137             if (in_array($this->exporter->get('formatclass'), array(PORTFOLIO_FORMAT_PLAINHTML, PORTFOLIO_FORMAT_RICHHTML))) {
138                 if ($files = $this->exporter->get('caller')->get('multifiles')) {
139                     foreach ($files as $file) {
140                         $this->exporter->copy_existing_file($file);
141                     }
142                 }
143                 return $this->exporter->write_new_file($html, 'assignment.html', !empty($files));
144             } else if ($this->exporter->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) {
145                 $leapwriter = $this->exporter->get('format')->leap2a_writer();
146                 $entry = new portfolio_format_leap2a_entry($this->area . $this->cmid, print_context_name($context), 'resource', $html);
148                 $entry->add_category('web', 'resource_type');
149                 $entry->author = $this->user;
150                 $leapwriter->add_entry($entry);
151                 if ($files = $this->exporter->get('caller')->get('multifiles')) {
152                     $leapwriter->link_files($entry, $files, $this->area . $this->cmid . 'file');
153                     foreach ($files as $file) {
154                         $this->exporter->copy_existing_file($file);
155                     }
156                 }
157                 return $this->exporter->write_new_file($leapwriter->to_xml(), $this->exporter->get('format')->manifest_name(), true);
158             } else {
159                 debugging('invalid format class: ' . $this->exporter->get('formatclass'));
160             }
162         }
165         if ($this->exporter->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) {
166             $leapwriter = $this->exporter->get('format')->leap2a_writer();
167             $files = array();
168             if ($this->singlefile) {
169                 $files[] = $this->singlefile;
170             } elseif ($this->multifiles) {
171                 $files = $this->multifiles;
172             } else {
173                 throw new portfolio_caller_exception('invalidpreparepackagefile', 'portfolio', $this->get_return_url());
174             }
176             $entryids = array();
177             foreach ($files as $file) {
178                 $entry = new portfolio_format_leap2a_file($file->get_filename(), $file);
179                 $entry->author = $this->user;
180                 $leapwriter->add_entry($entry);
181                 $this->exporter->copy_existing_file($file);
182                 $entryids[] = $entry->id;
183             }
184             if (count($files) > 1) {
185                 $baseid = 'assign' . $this->cmid . $this->area;
186                 $context = context_module::instance($this->cmid);
188                 // if we have multiple files, they should be grouped together into a folder
189                 $entry = new portfolio_format_leap2a_entry($baseid . 'group', print_context_name($context), 'selection');
190                 $leapwriter->add_entry($entry);
191                 $leapwriter->make_selection($entry, $entryids, 'Folder');
192             }
193             return $this->exporter->write_new_file($leapwriter->to_xml(), $this->exporter->get('format')->manifest_name(), true);
194         }
195         return $this->prepare_package_file();
196     }
198     /**
199      * fetch the plugin by its type
200      *
201      * @return assign_submission_plugin
202      */
203     private function get_submission_plugin() {
204         global $CFG;
205         if (!$this->plugin || !$this->cmid) {
206             return null;
207         }
209         require_once($CFG->dirroot . '/mod/assign/locallib.php');
211         $context = context_module::instance($this->cmid);
213         $assignment = new assign($context, null, null);
214         return $assignment->get_submission_plugin_by_type($this->plugin);
215     }
217     /**
218      * get sha1 file
219      * calculate a sha1 has of either a single file or a list
220      * of files based on the data set by load_data
221      *
222      * @return string
223      */
224     public function get_sha1() {
226         if ($this->plugin && $this->editor) {
227             $plugin = $this->get_submission_plugin();
228             $options = portfolio_format_text_options();
229             $options->context = context_module::instance($this->cmid);
231             $textsha1 = sha1(format_text($plugin->get_editor_text($this->editor, $this->sid),
232                                          $plugin->get_editor_format($this->editor, $this->sid), $options));
233             $filesha1 = '';
234             try {
235                 $filesha1 = $this->get_sha1_file();
236             } catch (portfolio_caller_exception $e) {} // no files
237             return sha1($textsha1 . $filesha1);
238         }
239         return $this->get_sha1_file();
240     }
242     /**
243      * calculate the time to transfer either a single file or a list
244      * of files based on the data set by load_data
245      *
246      * @return int
247      */
248     public function expected_time() {
249         return $this->expected_time_file();
250     }
252     /**
253      * checking the permissions
254      *
255      * @return bool
256      */
257     public function check_permissions() {
258         $context = context_module::instance($this->cmid);
259         return has_capability('mod/assign:exportownsubmission', $context);
260     }
262     /**
263      * display a module name
264      *
265      * @return string
266      */
267     public static function display_name() {
268         return get_string('modulename', 'assign');
269     }
271     /**
272      * return array of formats supported by this portfolio call back
273      * @return array
274      */
275     public static function base_supported_formats() {
277         return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_LEAP2A);
279     }