MDL-20067 new IMS Content package module, includes migrate from old mod/resource...
[moodle.git] / mod / imscp / lib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
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.
14 //
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/>.
18 /**
19  * Mandatory public API of imscp module
20  *
21  * @package   mod-imscp
22  * @copyright 2009 Petr Skoda (http://skodak.org)
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 /**
27  * List of features supported in IMS CP module
28  * @param string $feature FEATURE_xx constant for requested feature
29  * @return mixed True if module supports feature, false if not, null if doesn't know
30  */
31 function imscp_supports($feature) {
32     switch($feature) {
33         case FEATURE_MOD_ARCHETYPE:           return MOD_ARCHETYPE_RESOURCE;
34         case FEATURE_GROUPS:                  return false;
35         case FEATURE_GROUPINGS:               return false;
36         case FEATURE_GROUPMEMBERSONLY:        return true;
37         case FEATURE_MOD_INTRO:               return true;
38         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
39         case FEATURE_GRADE_HAS_GRADE:         return false;
40         case FEATURE_GRADE_OUTCOMES:          return false;
42         default: return null;
43     }
44 }
46 /**
47  * Returns all other caps used in module
48  * @return array
49  */
50 function imscp_get_extra_capabilities() {
51     return array('moodle/site:accessallgroups');
52 }
54 /**
55  * This function is used by the reset_course_userdata function in moodlelib.
56  * @param $data the data submitted from the reset course.
57  * @return array status array
58  */
59 function imscp_reset_userdata($data) {
60     return array();
61 }
63 /**
64  * List of view style log actions
65  * @return array
66  */
67 function imscp_get_view_actions() {
68     return array('view', 'view all');
69 }
71 /**
72  * List of update style log actions
73  * @return array
74  */
75 function imscp_get_post_actions() {
76     return array('update', 'add');
77 }
79 /**
80  * Add imscp instance.
81  * @param object $data
82  * @param object $mform
83  * @return int new imscp instance id
84  */
85 function imscp_add_instance($data, $mform) {
86     global $CFG, $DB;
87     require_once("$CFG->dirroot/mod/imscp/locallib.php");
89     $cmid = $data->coursemodule;
91     $data->timemodified = time();
92     $data->revision     = 1;
93     $data->structure    = null;
95     $data->id = $DB->insert_record('imscp', $data);
97     // we need to use context now, so we need to make sure all needed info is already in db
98     $DB->set_field('course_modules', 'instance', $data->id, array('id'=>$cmid));
99     $context = get_context_instance(CONTEXT_MODULE, $cmid);
100     $imscp = $DB->get_record('imscp', array('id'=>$data->id), '*', MUST_EXIST);
102     if ($filename = $mform->get_new_filename('package')) {
103         if ($package = $mform->save_stored_file('package', $context->id, 'imscp_backup', 1, '/', $filename)) {
104             // extract package content
105             $packer = get_file_packer('application/zip');
106             $package->extract_to_storage($packer, $context->id, 'imscp_content', 1, '/');
107             $structure = imscp_parse_structure($imscp, $context);
108             $imscp->structure = is_array($structure) ? serialize($structure) : null;
109             $DB->update_record('imscp', $imscp);
110         }
111     }
113     return $data->id;
116 /**
117  * Update imscp instance.
118  * @param object $data
119  * @param object $mform
120  * @return bool true
121  */
122 function imscp_update_instance($data, $mform) {
123     global $CFG, $DB;
124     require_once("$CFG->dirroot/mod/imscp/locallib.php");
126     $cmid = $data->coursemodule;
128     $data->timemodified = time();
129     $data->id           = $data->instance;
130     $imscp->structure   = null; // better reparse structure after each update
132     $DB->update_record('imscp', $data);
134     $context = get_context_instance(CONTEXT_MODULE, $cmid);
135     $imscp = $DB->get_record('imscp', array('id'=>$data->id), '*', MUST_EXIST);
137     if ($filename = $mform->get_new_filename('package')) {
138         $fs = get_file_storage();
140         $imscp->revision++;
141         $DB->update_record('imscp', $imscp);
143         // get a list of existing packages before adding new package
144         if ($imscp->keepold > -1) {
145             $packages = $fs->get_area_files($context->id, 'imscp_backup', false, "itemid ASC", false);
146         } else {
147             $packages = array();
148         }
150         $package = $mform->save_stored_file('package', $context->id, 'imscp_backup', $imscp->revision, '/', $filename);
152         // purge all extracted content
153         $fs->delete_area_files($context->id, 'imscp_content');
155         // extract package content
156         if ($package) {
157             $packer = get_file_packer('application/zip');
158             $package->extract_to_storage($packer, $context->id, 'imscp_content', $imscp->revision, '/');
159         }
161         // cleanup old package files, keep current + keepold
162         while ($packages and (count($packages) > $imscp->keepold)) {
163             $package = array_shift($packages);
164             $fs->delete_area_files($context->id, 'imscp_backup', $package->get_itemid());
165         }
166     }
168     $structure = imscp_parse_structure($imscp, $context);
169     $imscp->structure = is_array($structure) ? serialize($structure) : null;
170     $DB->update_record('imscp', $imscp);
172     return true;
175 /**
176  * Delete imscp instance.
177  * @param int $id
178  * @return bool true
179  */
180 function imscp_delete_instance($id) {
181     global $DB;
183     if (!$imscp = $DB->get_record('imscp', array('id'=>$id))) {
184         return false;
185     }
187     // note: all context files are deleted automatically
189     $DB->delete_records('imscp', array('id'=>$imscp->id));
191     return true;
194 /**
195  * Return use outline
196  * @param object $course
197  * @param object $user
198  * @param object $mod
199  * @param object $imscp
200  * @return object|null
201  */
202 function imscp_user_outline($course, $user, $mod, $imscp) {
203     global $DB;
205     if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'imscp',
206                                               'action'=>'view', 'info'=>$imscp->id), 'time ASC')) {
208         $numviews = count($logs);
209         $lastlog = array_pop($logs);
211         $result = new object();
212         $result->info = get_string('numviews', '', $numviews);
213         $result->time = $lastlog->time;
215         return $result;
216     }
217     return NULL;
220 /**
221  * Return use complete
222  * @param object $course
223  * @param object $user
224  * @param object $mod
225  * @param object $imscp
226  */
227 function imscp_user_complete($course, $user, $mod, $imscp) {
228     global $CFG, $DB;
230     if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'imscp',
231                                               'action'=>'view', 'info'=>$imscp->id), 'time ASC')) {
232         $numviews = count($logs);
233         $lastlog = array_pop($logs);
235         $strmostrecently = get_string('mostrecently');
236         $strnumviews = get_string('numviews', '', $numviews);
238         echo "$strnumviews - $strmostrecently ".userdate($lastlog->time);
240     } else {
241         print_string('neverseen', 'imscp');
242     }
245 /**
246  * Returns the users with data in one imscp
247  *
248  * @param int $imscpid
249  * @return bool false
250  */
251 function imscp_get_participants($imscpid) {
252     return false;
255 /**
256  * Lists all browsable file areas
257  * @param object $course
258  * @param object $cm
259  * @param object $context
260  * @return array
261  */
262 function imscp_get_file_areas($course, $cm, $context) {
263     $areas = array();
264     if (has_capability('moodle/course:managefiles', $context)) {
265         $areas['imscp_content'] = get_string('areacontent', 'imscp');
266         $areas['imscp_backup']  = get_string('areabackup', 'imscp');
267     }
268     return $areas;
271 /**
272  * File browsing support for imscp module ontent area.
273  * @param object $browser
274  * @param object $areas
275  * @param object $course
276  * @param object $cm
277  * @param object $context
278  * @param string $filearea
279  * @param int $itemid
280  * @param string $filepath
281  * @param string $filename
282  * @return object file_info instance or null if not found
283  */
284 function imscp_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
285     global $CFG, $DB;
286     require_once("$CFG->dirroot/mod/imscp/locallib.php");
288     // note: imscp_intro handled in file_browser automatically
290     if (!has_capability('moodle/course:managefiles', $context)) {
291         // no peaking here, sorry
292         return null;
293     }
295     if ($filearea !== 'imscp_content' and $filearea !== 'imscp_backup') {
296         return null;
297     }
298     if (is_null($itemid)) {
299         return new imscp_file_info($browser, $course, $cm, $context, $areas, $filearea, $itemid);
300     }
302     $fs = get_file_storage();
303     $filepath = is_null($filepath) ? '/' : $filepath;
304     $filename = is_null($filename) ? '.' : $filename;
305     if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
306         return null;
307     }
309     // do not allow manual modification of any files!
310     $urlbase = $CFG->wwwroot.'/pluginfile.php';
311     return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemid, true, true, false, false);
314 /**
315  * Serves the imscp files.
316  *
317  * @param object $course
318  * @param object $cminfo
319  * @param object $context
320  * @param string $filearea
321  * @param array $args
322  * @param bool $forcedownload
323  * @return bool false if file not found, does not return if found - justsend the file
324  */
325 function imscp_pluginfile($course, $cminfo, $context, $filearea, $args, $forcedownload) {
326     global $CFG, $DB;
328     if (!$cminfo->uservisible) {
329         return false;
330     }
332     if (!$cm = get_coursemodule_from_instance('imscp', $cminfo->instance, $course->id)) {
333         return false;
334     }
336     if ($filearea === 'imscp_content') {
337         require_course_login($course, true, $cm);
338         $revision = array_shift($args);
339         $fs = get_file_storage();
340         $relativepath = '/'.implode('/', $args);
341         if ($relativepath === '/imsmanifest.xml') {
342             if (!has_capability('moodle/course:managefiles', $context)) {
343                 // no stealing of detailed package info ;-)
344                 return false;
345             }
346         }
347         $fullpath = $context->id.$filearea.$revision.$relativepath;
348         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
349             return false;
350         }
352         // finally send the file
353         send_stored_file($file, 86400, 0, $forcedownload);
355     } else if ($filearea === 'imscp_backup') {
356         require_login($course, false, $cm);
357         if (!has_capability('moodle/course:managefiles', $context)) {
358             // no stealing of package backups
359             return false;
360         }
361         $revision = array_shift($args);
362         $fs = get_file_storage();
363         $relativepath = '/'.implode('/', $args);
364         $fullpath = $context->id.$filearea.$revision.$relativepath;
365         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
366             return false;
367         }
369         // finally send the file
370         send_stored_file($file, 86400, 0, $forcedownload);
372     } else {
373         return false;
374     }