MDL-33404 Fix defaults for ordinary files that are drag/dropped into the course page
[moodle.git] / mod / resource / 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  * @package    mod
20  * @subpackage resource
21  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die;
27 /**
28  * List of features supported in Resource module
29  * @param string $feature FEATURE_xx constant for requested feature
30  * @return mixed True if module supports feature, false if not, null if doesn't know
31  */
32 function resource_supports($feature) {
33     switch($feature) {
34         case FEATURE_MOD_ARCHETYPE:           return MOD_ARCHETYPE_RESOURCE;
35         case FEATURE_GROUPS:                  return false;
36         case FEATURE_GROUPINGS:               return false;
37         case FEATURE_GROUPMEMBERSONLY:        return true;
38         case FEATURE_MOD_INTRO:               return true;
39         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
40         case FEATURE_GRADE_HAS_GRADE:         return false;
41         case FEATURE_GRADE_OUTCOMES:          return false;
42         case FEATURE_BACKUP_MOODLE2:          return true;
43         case FEATURE_SHOW_DESCRIPTION:        return true;
45         default: return null;
46     }
47 }
49 /**
50  * Returns all other caps used in module
51  * @return array
52  */
53 function resource_get_extra_capabilities() {
54     return array('moodle/site:accessallgroups');
55 }
57 /**
58  * This function is used by the reset_course_userdata function in moodlelib.
59  * @param $data the data submitted from the reset course.
60  * @return array status array
61  */
62 function resource_reset_userdata($data) {
63     return array();
64 }
66 /**
67  * List of view style log actions
68  * @return array
69  */
70 function resource_get_view_actions() {
71     return array('view','view all');
72 }
74 /**
75  * List of update style log actions
76  * @return array
77  */
78 function resource_get_post_actions() {
79     return array('update', 'add');
80 }
82 /**
83  * Add resource instance.
84  * @param object $data
85  * @param object $mform
86  * @return int new resource instance id
87  */
88 function resource_add_instance($data, $mform) {
89     global $CFG, $DB;
90     require_once("$CFG->libdir/resourcelib.php");
91     require_once("$CFG->dirroot/mod/resource/locallib.php");
92     $cmid = $data->coursemodule;
93     $data->timemodified = time();
95     resource_set_display_options($data);
97     $data->id = $DB->insert_record('resource', $data);
99     // we need to use context now, so we need to make sure all needed info is already in db
100     $DB->set_field('course_modules', 'instance', $data->id, array('id'=>$cmid));
101     resource_set_mainfile($data);
102     return $data->id;
105 /**
106  * Update resource instance.
107  * @param object $data
108  * @param object $mform
109  * @return bool true
110  */
111 function resource_update_instance($data, $mform) {
112     global $CFG, $DB;
113     require_once("$CFG->libdir/resourcelib.php");
114     $data->timemodified = time();
115     $data->id           = $data->instance;
116     $data->revision++;
118     resource_set_display_options($data);
120     $DB->update_record('resource', $data);
121     resource_set_mainfile($data);
122     return true;
125 /**
126  * Updates display options based on form input.
127  *
128  * Shared code used by resource_add_instance and resource_update_instance.
129  *
130  * @param object $data Data object
131  */
132 function resource_set_display_options($data) {
133     $displayoptions = array();
134     if ($data->display == RESOURCELIB_DISPLAY_POPUP) {
135         $displayoptions['popupwidth']  = $data->popupwidth;
136         $displayoptions['popupheight'] = $data->popupheight;
137     }
138     if (in_array($data->display, array(RESOURCELIB_DISPLAY_AUTO, RESOURCELIB_DISPLAY_EMBED, RESOURCELIB_DISPLAY_FRAME))) {
139         $displayoptions['printheading'] = (int)!empty($data->printheading);
140         $displayoptions['printintro']   = (int)!empty($data->printintro);
141     }
142     if (!empty($data->showsize)) {
143         $displayoptions['showsize'] = 1;
144     }
145     if (!empty($data->showtype)) {
146         $displayoptions['showtype'] = 1;
147     }
148     $data->displayoptions = serialize($displayoptions);
151 /**
152  * Delete resource instance.
153  * @param int $id
154  * @return bool true
155  */
156 function resource_delete_instance($id) {
157     global $DB;
159     if (!$resource = $DB->get_record('resource', array('id'=>$id))) {
160         return false;
161     }
163     // note: all context files are deleted automatically
165     $DB->delete_records('resource', array('id'=>$resource->id));
167     return true;
170 /**
171  * Return use outline
172  * @param object $course
173  * @param object $user
174  * @param object $mod
175  * @param object $resource
176  * @return object|null
177  */
178 function resource_user_outline($course, $user, $mod, $resource) {
179     global $DB;
181     if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'resource',
182                                               'action'=>'view', 'info'=>$resource->id), 'time ASC')) {
184         $numviews = count($logs);
185         $lastlog = array_pop($logs);
187         $result = new stdClass();
188         $result->info = get_string('numviews', '', $numviews);
189         $result->time = $lastlog->time;
191         return $result;
192     }
193     return NULL;
196 /**
197  * Return use complete
198  * @param object $course
199  * @param object $user
200  * @param object $mod
201  * @param object $resource
202  */
203 function resource_user_complete($course, $user, $mod, $resource) {
204     global $CFG, $DB;
206     if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'resource',
207                                               'action'=>'view', 'info'=>$resource->id), 'time ASC')) {
208         $numviews = count($logs);
209         $lastlog = array_pop($logs);
211         $strmostrecently = get_string('mostrecently');
212         $strnumviews = get_string('numviews', '', $numviews);
214         echo "$strnumviews - $strmostrecently ".userdate($lastlog->time);
216     } else {
217         print_string('neverseen', 'resource');
218     }
221 /**
222  * Given a course_module object, this function returns any
223  * "extra" information that may be needed when printing
224  * this activity in a course listing.
225  *
226  * See {@link get_array_of_activities()} in course/lib.php
227  *
228  * @param cm_info $coursemodule
229  * @return cached_cm_info info
230  */
231 function resource_get_coursemodule_info($coursemodule) {
232     global $CFG, $DB;
233     require_once("$CFG->libdir/filelib.php");
234     require_once("$CFG->dirroot/mod/resource/locallib.php");
235     require_once($CFG->libdir.'/completionlib.php');
237     $context = get_context_instance(CONTEXT_MODULE, $coursemodule->id);
239     if (!$resource = $DB->get_record('resource', array('id'=>$coursemodule->instance),
240             'id, name, display, displayoptions, tobemigrated, revision, intro, introformat')) {
241         return NULL;
242     }
244     $info = new cached_cm_info();
245     $info->name = $resource->name;
246     if ($coursemodule->showdescription) {
247         // Convert intro to html. Do not filter cached version, filters run at display time.
248         $info->content = format_module_intro('resource', $resource, $coursemodule->id, false);
249     }
251     if ($resource->tobemigrated) {
252         $info->icon ='i/cross_red_big';
253         return $info;
254     }
255     $fs = get_file_storage();
256     $files = $fs->get_area_files($context->id, 'mod_resource', 'content', 0, 'sortorder DESC, id ASC', false); // TODO: this is not very efficient!!
257     if (count($files) >= 1) {
258         $mainfile = reset($files);
259         $info->icon = file_file_icon($mainfile);
260         $resource->mainfile = $mainfile->get_filename();
261     }
263     $display = resource_get_final_display_type($resource);
265     if ($display == RESOURCELIB_DISPLAY_POPUP) {
266         $fullurl = "$CFG->wwwroot/mod/resource/view.php?id=$coursemodule->id&amp;redirect=1";
267         $options = empty($resource->displayoptions) ? array() : unserialize($resource->displayoptions);
268         $width  = empty($options['popupwidth'])  ? 620 : $options['popupwidth'];
269         $height = empty($options['popupheight']) ? 450 : $options['popupheight'];
270         $wh = "width=$width,height=$height,toolbar=no,location=no,menubar=no,copyhistory=no,status=no,directories=no,scrollbars=yes,resizable=yes";
271         $info->onclick = "window.open('$fullurl', '', '$wh'); return false;";
273     } else if ($display == RESOURCELIB_DISPLAY_NEW) {
274         $fullurl = "$CFG->wwwroot/mod/resource/view.php?id=$coursemodule->id&amp;redirect=1";
275         $info->onclick = "window.open('$fullurl'); return false;";
277     }
279     // If any optional extra details are turned on, store in custom data
280     $info->customdata = resource_get_optional_details($resource, $coursemodule);
282     return $info;
285 /**
286  * Called when viewing course page. Shows extra details after the link if
287  * enabled.
288  *
289  * @param cm_info $cm Course module information
290  */
291 function resource_cm_info_view(cm_info $cm) {
292     $details = $cm->get_custom_data();
293     if ($details) {
294         $cm->set_after_link(' ' . html_writer::tag('span', $details,
295                 array('class' => 'resourcelinkdetails')));
296     }
299 /**
300  * Lists all browsable file areas
301  *
302  * @package  mod_resource
303  * @category files
304  * @param stdClass $course course object
305  * @param stdClass $cm course module object
306  * @param stdClass $context context object
307  * @return array
308  */
309 function resource_get_file_areas($course, $cm, $context) {
310     $areas = array();
311     $areas['content'] = get_string('resourcecontent', 'resource');
312     return $areas;
315 /**
316  * File browsing support for resource module content area.
317  *
318  * @package  mod_resource
319  * @category files
320  * @param stdClass $browser file browser instance
321  * @param stdClass $areas file areas
322  * @param stdClass $course course object
323  * @param stdClass $cm course module object
324  * @param stdClass $context context object
325  * @param string $filearea file area
326  * @param int $itemid item ID
327  * @param string $filepath file path
328  * @param string $filename file name
329  * @return file_info instance or null if not found
330  */
331 function resource_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
332     global $CFG;
334     if (!has_capability('moodle/course:managefiles', $context)) {
335         // students can not peak here!
336         return null;
337     }
339     $fs = get_file_storage();
341     if ($filearea === 'content') {
342         $filepath = is_null($filepath) ? '/' : $filepath;
343         $filename = is_null($filename) ? '.' : $filename;
345         $urlbase = $CFG->wwwroot.'/pluginfile.php';
346         if (!$storedfile = $fs->get_file($context->id, 'mod_resource', 'content', 0, $filepath, $filename)) {
347             if ($filepath === '/' and $filename === '.') {
348                 $storedfile = new virtual_root_file($context->id, 'mod_resource', 'content', 0);
349             } else {
350                 // not found
351                 return null;
352             }
353         }
354         require_once("$CFG->dirroot/mod/resource/locallib.php");
355         return new resource_content_file_info($browser, $context, $storedfile, $urlbase, $areas[$filearea], true, true, true, false);
356     }
358     // note: resource_intro handled in file_browser automatically
360     return null;
363 /**
364  * Serves the resource files.
365  *
366  * @package  mod_resource
367  * @category files
368  * @param stdClass $course course object
369  * @param stdClass $cm course module object
370  * @param stdClass $context context object
371  * @param string $filearea file area
372  * @param array $args extra arguments
373  * @param bool $forcedownload whether or not force download
374  * @param array $options additional options affecting the file serving
375  * @return bool false if file not found, does not return if found - just send the file
376  */
377 function resource_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
378     global $CFG, $DB;
379     require_once("$CFG->libdir/resourcelib.php");
381     if ($context->contextlevel != CONTEXT_MODULE) {
382         return false;
383     }
385     require_course_login($course, true, $cm);
386     if (!has_capability('mod/resource:view', $context)) {
387         return false;
388     }
390     if ($filearea !== 'content') {
391         // intro is handled automatically in pluginfile.php
392         return false;
393     }
395     array_shift($args); // ignore revision - designed to prevent caching problems only
397     $fs = get_file_storage();
398     $relativepath = implode('/', $args);
399     $fullpath = rtrim("/$context->id/mod_resource/$filearea/0/$relativepath", '/');
400     do {
401         if (!$file = $fs->get_file_by_hash(sha1($fullpath))) {
402             if ($fs->get_file_by_hash(sha1("$fullpath/."))) {
403                 if ($file = $fs->get_file_by_hash(sha1("$fullpath/index.htm"))) {
404                     break;
405                 }
406                 if ($file = $fs->get_file_by_hash(sha1("$fullpath/index.html"))) {
407                     break;
408                 }
409                 if ($file = $fs->get_file_by_hash(sha1("$fullpath/Default.htm"))) {
410                     break;
411                 }
412             }
413             $resource = $DB->get_record('resource', array('id'=>$cm->instance), 'id, legacyfiles', MUST_EXIST);
414             if ($resource->legacyfiles != RESOURCELIB_LEGACYFILES_ACTIVE) {
415                 return false;
416             }
417             if (!$file = resourcelib_try_file_migration('/'.$relativepath, $cm->id, $cm->course, 'mod_resource', 'content', 0)) {
418                 return false;
419             }
420             // file migrate - update flag
421             $resource->legacyfileslast = time();
422             $DB->update_record('resource', $resource);
423         }
424     } while (false);
426     // should we apply filters?
427     $mimetype = $file->get_mimetype();
428     if ($mimetype === 'text/html' or $mimetype === 'text/plain') {
429         $filter = $DB->get_field('resource', 'filterfiles', array('id'=>$cm->instance));
430         $CFG->embeddedsoforcelinktarget = true;
431     } else {
432         $filter = 0;
433     }
435     // finally send the file
436     send_stored_file($file, 86400, $filter, $forcedownload, $options);
439 /**
440  * Return a list of page types
441  * @param string $pagetype current page type
442  * @param stdClass $parentcontext Block's parent context
443  * @param stdClass $currentcontext Current context of block
444  */
445 function resource_page_type_list($pagetype, $parentcontext, $currentcontext) {
446     $module_pagetype = array('mod-resource-*'=>get_string('page-mod-resource-x', 'resource'));
447     return $module_pagetype;
450 /**
451  * Export file resource contents
452  *
453  * @return array of file content
454  */
455 function resource_export_contents($cm, $baseurl) {
456     global $CFG, $DB;
457     $contents = array();
458     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
459     $resource = $DB->get_record('resource', array('id'=>$cm->instance), '*', MUST_EXIST);
461     $fs = get_file_storage();
462     $files = $fs->get_area_files($context->id, 'mod_resource', 'content', 0, 'sortorder DESC, id ASC', false);
464     foreach ($files as $fileinfo) {
465         $file = array();
466         $file['type'] = 'file';
467         $file['filename']     = $fileinfo->get_filename();
468         $file['filepath']     = $fileinfo->get_filepath();
469         $file['filesize']     = $fileinfo->get_filesize();
470         $file['fileurl']      = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_resource/content/'.$resource->revision.$fileinfo->get_filepath().$fileinfo->get_filename(), true);
471         $file['timecreated']  = $fileinfo->get_timecreated();
472         $file['timemodified'] = $fileinfo->get_timemodified();
473         $file['sortorder']    = $fileinfo->get_sortorder();
474         $file['userid']       = $fileinfo->get_userid();
475         $file['author']       = $fileinfo->get_author();
476         $file['license']      = $fileinfo->get_license();
477         $contents[] = $file;
478     }
480     return $contents;
483 /**
484  * Register the ability to handle drag and drop file uploads
485  * @return array containing details of the files / types the mod can handle
486  */
487 function mod_resource_dndupload_register() {
488     return array('files' => array(
489                      array('extension' => '*', 'message' => get_string('dnduploadresource', 'mod_resource'))
490                  ));
493 /**
494  * Handle a file that has been uploaded
495  * @param object $uploadinfo details of the file / content that has been uploaded
496  * @return int instance id of the newly created mod
497  */
498 function mod_resource_dndupload_handle($uploadinfo) {
499     // Gather the required info.
500     $data = new stdClass();
501     $data->course = $uploadinfo->course->id;
502     $data->name = $uploadinfo->displayname;
503     $data->intro = '';
504     $data->introformat = FORMAT_HTML;
505     $data->coursemodule = $uploadinfo->coursemodule;
506     $data->files = $uploadinfo->draftitemid;
508     // Set the display options to the site defaults.
509     $config = get_config('resource');
510     $data->display = $config->display;
511     $data->popupheight = $config->popupheight;
512     $data->popupwidth = $config->popupwidth;
513     $data->printheading = $config->printheading;
514     $data->printintro = $config->printintro;
515     $data->showsize = $config->showsize;
516     $data->showtype = $config->showtype;
518     return resource_add_instance($data, null);