MDL-50015 mod_imscp: New WS mod_imscp_view_imscp
[moodle.git] / mod / book / lib.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  * Book module core interaction API
19  *
20  * @package    mod_book
21  * @copyright  2004-2011 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  * Returns list of available numbering types
29  * @return array
30  */
31 function book_get_numbering_types() {
32     global $CFG; // required for the include
34     require_once(dirname(__FILE__).'/locallib.php');
36     return array (
37         BOOK_NUM_NONE       => get_string('numbering0', 'mod_book'),
38         BOOK_NUM_NUMBERS    => get_string('numbering1', 'mod_book'),
39         BOOK_NUM_BULLETS    => get_string('numbering2', 'mod_book'),
40         BOOK_NUM_INDENTED   => get_string('numbering3', 'mod_book')
41     );
42 }
44 /**
45  * Returns list of available navigation link types.
46  * @return array
47  */
48 function book_get_nav_types() {
49     require_once(dirname(__FILE__).'/locallib.php');
51     return array (
52         BOOK_LINK_TOCONLY   => get_string('navtoc', 'mod_book'),
53         BOOK_LINK_IMAGE     => get_string('navimages', 'mod_book'),
54         BOOK_LINK_TEXT      => get_string('navtext', 'mod_book'),
55     );
56 }
58 /**
59  * Returns list of available navigation link CSS classes.
60  * @return array
61  */
62 function book_get_nav_classes() {
63     return array ('navtoc', 'navimages', 'navtext');
64 }
66 /**
67  * Returns all other caps used in module
68  * @return array
69  */
70 function book_get_extra_capabilities() {
71     // used for group-members-only
72     return array('moodle/site:accessallgroups');
73 }
75 /**
76  * Add book instance.
77  *
78  * @param stdClass $data
79  * @param stdClass $mform
80  * @return int new book instance id
81  */
82 function book_add_instance($data, $mform) {
83     global $DB;
85     $data->timecreated = time();
86     $data->timemodified = $data->timecreated;
87     if (!isset($data->customtitles)) {
88         $data->customtitles = 0;
89     }
91     return $DB->insert_record('book', $data);
92 }
94 /**
95  * Update book instance.
96  *
97  * @param stdClass $data
98  * @param stdClass $mform
99  * @return bool true
100  */
101 function book_update_instance($data, $mform) {
102     global $DB;
104     $data->timemodified = time();
105     $data->id = $data->instance;
106     if (!isset($data->customtitles)) {
107         $data->customtitles = 0;
108     }
110     $DB->update_record('book', $data);
112     $book = $DB->get_record('book', array('id'=>$data->id));
113     $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
115     return true;
118 /**
119  * Delete book instance by activity id
120  *
121  * @param int $id
122  * @return bool success
123  */
124 function book_delete_instance($id) {
125     global $DB;
127     if (!$book = $DB->get_record('book', array('id'=>$id))) {
128         return false;
129     }
131     $DB->delete_records('book_chapters', array('bookid'=>$book->id));
132     $DB->delete_records('book', array('id'=>$book->id));
134     return true;
137 /**
138  * Given a course and a time, this module should find recent activity
139  * that has occurred in book activities and print it out.
140  *
141  * @param stdClass $course
142  * @param bool $viewfullnames
143  * @param int $timestart
144  * @return bool true if there was output, or false is there was none
145  */
146 function book_print_recent_activity($course, $viewfullnames, $timestart) {
147     return false;  //  True if anything was printed, otherwise false
150 /**
151  * This function is used by the reset_course_userdata function in moodlelib.
152  * @param $data the data submitted from the reset course.
153  * @return array status array
154  */
155 function book_reset_userdata($data) {
156     return array();
159 /**
160  * No cron in book.
161  *
162  * @return bool
163  */
164 function book_cron () {
165     return true;
168 /**
169  * No grading in book.
170  *
171  * @param int $bookid
172  * @return null
173  */
174 function book_grades($bookid) {
175     return null;
178 /**
179  * This function returns if a scale is being used by one book
180  * it it has support for grading and scales. Commented code should be
181  * modified if necessary. See book, glossary or journal modules
182  * as reference.
183  *
184  * @param int $bookid
185  * @param int $scaleid
186  * @return boolean True if the scale is used by any journal
187  */
188 function book_scale_used($bookid, $scaleid) {
189     return false;
192 /**
193  * Checks if scale is being used by any instance of book
194  *
195  * This is used to find out if scale used anywhere
196  *
197  * @param int $scaleid
198  * @return bool true if the scale is used by any book
199  */
200 function book_scale_used_anywhere($scaleid) {
201     return false;
204 /**
205  * Return read actions.
206  *
207  * Note: This is not used by new logging system. Event with
208  *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
209  *       be considered as view action.
210  *
211  * @return array
212  */
213 function book_get_view_actions() {
214     global $CFG; // necessary for includes
216     $return = array('view', 'view all');
218     $plugins = core_component::get_plugin_list('booktool');
219     foreach ($plugins as $plugin => $dir) {
220         if (file_exists("$dir/lib.php")) {
221             require_once("$dir/lib.php");
222         }
223         $function = 'booktool_'.$plugin.'_get_view_actions';
224         if (function_exists($function)) {
225             if ($actions = $function()) {
226                 $return = array_merge($return, $actions);
227             }
228         }
229     }
231     return $return;
234 /**
235  * Return write actions.
236  *
237  * Note: This is not used by new logging system. Event with
238  *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
239  *       will be considered as post action.
240  *
241  * @return array
242  */
243 function book_get_post_actions() {
244     global $CFG; // necessary for includes
246     $return = array('update');
248     $plugins = core_component::get_plugin_list('booktool');
249     foreach ($plugins as $plugin => $dir) {
250         if (file_exists("$dir/lib.php")) {
251             require_once("$dir/lib.php");
252         }
253         $function = 'booktool_'.$plugin.'_get_post_actions';
254         if (function_exists($function)) {
255             if ($actions = $function()) {
256                 $return = array_merge($return, $actions);
257             }
258         }
259     }
261     return $return;
264 /**
265  * Supported features
266  *
267  * @param string $feature FEATURE_xx constant for requested feature
268  * @return mixed True if module supports feature, false if not, null if doesn't know
269  */
270 function book_supports($feature) {
271     switch($feature) {
272         case FEATURE_MOD_ARCHETYPE:           return MOD_ARCHETYPE_RESOURCE;
273         case FEATURE_GROUPS:                  return false;
274         case FEATURE_GROUPINGS:               return false;
275         case FEATURE_MOD_INTRO:               return true;
276         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
277         case FEATURE_GRADE_HAS_GRADE:         return false;
278         case FEATURE_GRADE_OUTCOMES:          return false;
279         case FEATURE_BACKUP_MOODLE2:          return true;
280         case FEATURE_SHOW_DESCRIPTION:        return true;
282         default: return null;
283     }
286 /**
287  * Adds module specific settings to the settings block
288  *
289  * @param settings_navigation $settingsnav The settings navigation object
290  * @param navigation_node $booknode The node to add module settings to
291  * @return void
292  */
293 function book_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $booknode) {
294     global $USER, $PAGE;
296     $plugins = core_component::get_plugin_list('booktool');
297     foreach ($plugins as $plugin => $dir) {
298         if (file_exists("$dir/lib.php")) {
299             require_once("$dir/lib.php");
300         }
301         $function = 'booktool_'.$plugin.'_extend_settings_navigation';
302         if (function_exists($function)) {
303             $function($settingsnav, $booknode);
304         }
305     }
307     $params = $PAGE->url->params();
309     if (!empty($params['id']) and !empty($params['chapterid']) and has_capability('mod/book:edit', $PAGE->cm->context)) {
310         if (!empty($USER->editing)) {
311             $string = get_string("turneditingoff");
312             $edit = '0';
313         } else {
314             $string = get_string("turneditingon");
315             $edit = '1';
316         }
317         $url = new moodle_url('/mod/book/view.php', array('id'=>$params['id'], 'chapterid'=>$params['chapterid'], 'edit'=>$edit, 'sesskey'=>sesskey()));
318         $booknode->add($string, $url, navigation_node::TYPE_SETTING);
319     }
323 /**
324  * Lists all browsable file areas
325  * @param object $course
326  * @param object $cm
327  * @param object $context
328  * @return array
329  */
330 function book_get_file_areas($course, $cm, $context) {
331     $areas = array();
332     $areas['chapter'] = get_string('chapters', 'mod_book');
333     return $areas;
336 /**
337  * File browsing support for book module chapter area.
338  * @param object $browser
339  * @param object $areas
340  * @param object $course
341  * @param object $cm
342  * @param object $context
343  * @param string $filearea
344  * @param int $itemid
345  * @param string $filepath
346  * @param string $filename
347  * @return object file_info instance or null if not found
348  */
349 function book_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
350     global $CFG, $DB;
352     // note: 'intro' area is handled in file_browser automatically
354     if (!has_capability('mod/book:read', $context)) {
355         return null;
356     }
358     if ($filearea !== 'chapter') {
359         return null;
360     }
362     require_once(dirname(__FILE__).'/locallib.php');
364     if (is_null($itemid)) {
365         return new book_file_info($browser, $course, $cm, $context, $areas, $filearea);
366     }
368     $fs = get_file_storage();
369     $filepath = is_null($filepath) ? '/' : $filepath;
370     $filename = is_null($filename) ? '.' : $filename;
371     if (!$storedfile = $fs->get_file($context->id, 'mod_book', $filearea, $itemid, $filepath, $filename)) {
372         return null;
373     }
375     // modifications may be tricky - may cause caching problems
376     $canwrite = has_capability('mod/book:edit', $context);
378     $chaptername = $DB->get_field('book_chapters', 'title', array('bookid'=>$cm->instance, 'id'=>$itemid));
379     $chaptername = format_string($chaptername, true, array('context'=>$context));
381     $urlbase = $CFG->wwwroot.'/pluginfile.php';
382     return new file_info_stored($browser, $context, $storedfile, $urlbase, $chaptername, true, true, $canwrite, false);
385 /**
386  * Serves the book attachments. Implements needed access control ;-)
387  *
388  * @param stdClass $course course object
389  * @param cm_info $cm course module object
390  * @param context $context context object
391  * @param string $filearea file area
392  * @param array $args extra arguments
393  * @param bool $forcedownload whether or not force download
394  * @param array $options additional options affecting the file serving
395  * @return bool false if file not found, does not return if found - just send the file
396  */
397 function book_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
398     global $CFG, $DB;
400     if ($context->contextlevel != CONTEXT_MODULE) {
401         return false;
402     }
404     require_course_login($course, true, $cm);
406     if ($filearea !== 'chapter') {
407         return false;
408     }
410     if (!has_capability('mod/book:read', $context)) {
411         return false;
412     }
414     $chid = (int)array_shift($args);
416     if (!$book = $DB->get_record('book', array('id'=>$cm->instance))) {
417         return false;
418     }
420     if (!$chapter = $DB->get_record('book_chapters', array('id'=>$chid, 'bookid'=>$book->id))) {
421         return false;
422     }
424     if ($chapter->hidden and !has_capability('mod/book:viewhiddenchapters', $context)) {
425         return false;
426     }
428     // Download the contents of a chapter as an html file.
429     if ($args[0] == 'index.html') {
430         $filename = "index.html";
432         // Remove @@PLUGINFILE@@/.
433         $content = str_replace('@@PLUGINFILE@@/', '', $chapter->content);
435         $titles = "";
436         // Format the chapter titles.
437         if (!$book->customtitles) {
438             require_once(dirname(__FILE__).'/locallib.php');
439             $chapters = book_preload_chapters($book);
441             if (!$chapter->subchapter) {
442                 $currtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context);
443                 // Note that we can't use the $OUTPUT->heading() in WS_SERVER mode.
444                 $titles = "<h3>$currtitle</h3>";
445             } else {
446                 $currtitle = book_get_chapter_title($chapters[$chapter->id]->parent, $chapters, $book, $context);
447                 $currsubtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context);
448                 // Note that we can't use the $OUTPUT->heading() in WS_SERVER mode.
449                 $titles = "<h3>$currtitle</h3>";
450                 $titles .= "<h4>$currsubtitle</h4>";
451             }
452         }
454         $formatoptions = new stdClass;
455         $formatoptions->noclean = true;
456         $formatoptions->overflowdiv = true;
457         $formatoptions->context = $context;
459         $content = $titles . format_text($content, $chapter->contentformat, $formatoptions);
461         send_file($content, $filename, 0, 0, true, true);
462     } else {
463         $fs = get_file_storage();
464         $relativepath = implode('/', $args);
465         $fullpath = "/$context->id/mod_book/chapter/$chid/$relativepath";
466         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
467             return false;
468         }
470         // Nasty hack because we do not have file revisions in book yet.
471         $lifetime = $CFG->filelifetime;
472         if ($lifetime > 60 * 10) {
473             $lifetime = 60 * 10;
474         }
476         // Finally send the file.
477         send_stored_file($file, $lifetime, 0, $forcedownload, $options);
478     }
481 /**
482  * Return a list of page types
483  *
484  * @param string $pagetype current page type
485  * @param stdClass $parentcontext Block's parent context
486  * @param stdClass $currentcontext Current context of block
487  * @return array
488  */
489 function book_page_type_list($pagetype, $parentcontext, $currentcontext) {
490     $module_pagetype = array('mod-book-*'=>get_string('page-mod-book-x', 'mod_book'));
491     return $module_pagetype;
494 /**
495  * Export book resource contents
496  *
497  * @param  stdClass $cm     Course module object
498  * @param  string $baseurl  Base URL for file downloads
499  * @return array of file content
500  */
501 function book_export_contents($cm, $baseurl) {
502     global $DB;
504     $contents = array();
505     $context = context_module::instance($cm->id);
507     $book = $DB->get_record('book', array('id' => $cm->instance), '*', MUST_EXIST);
509     $fs = get_file_storage();
511     $chapters = $DB->get_records('book_chapters', array('bookid' => $book->id), 'pagenum');
513     $structure = array();
514     $currentchapter = 0;
516     foreach ($chapters as $chapter) {
517         if ($chapter->hidden) {
518             continue;
519         }
521         // Generate the book structure.
522         $thischapter = array(
523             "title"     => format_string($chapter->title, true, array('context' => $context)),
524             "href"      => $chapter->id . "/index.html",
525             "level"     => 0,
526             "subitems"  => array()
527         );
529         // Main chapter.
530         if (!$chapter->subchapter) {
531             $currentchapter = $chapter->pagenum;
532             $structure[$currentchapter] = $thischapter;
533         } else {
534             // Subchapter.
535             $thischapter['level'] = 1;
536             $structure[$currentchapter]["subitems"][] = $thischapter;
537         }
539         // Export the chapter contents.
541         // Main content (html).
542         $filename = 'index.html';
543         $chapterindexfile = array();
544         $chapterindexfile['type']         = 'file';
545         $chapterindexfile['filename']     = $filename;
546         // Each chapter in a subdirectory.
547         $chapterindexfile['filepath']     = "/{$chapter->id}/";
548         $chapterindexfile['filesize']     = 0;
549         $chapterindexfile['fileurl']      = moodle_url::make_webservice_pluginfile_url(
550                     $context->id, 'mod_book', 'chapter', $chapter->id, '/', 'index.html')->out(false);
551         $chapterindexfile['timecreated']  = $book->timecreated;
552         $chapterindexfile['timemodified'] = $book->timemodified;
553         $chapterindexfile['content']      = format_string($chapter->title, true, array('context' => $context));
554         $chapterindexfile['sortorder']    = 0;
555         $chapterindexfile['userid']       = null;
556         $chapterindexfile['author']       = null;
557         $chapterindexfile['license']      = null;
558         $contents[] = $chapterindexfile;
560         // Chapter files (images usually).
561         $files = $fs->get_area_files($context->id, 'mod_book', 'chapter', $chapter->id, 'sortorder DESC, id ASC', false);
562         foreach ($files as $fileinfo) {
563             $file = array();
564             $file['type']         = 'file';
565             $file['filename']     = $fileinfo->get_filename();
566             $file['filepath']     = "/{$chapter->id}/";
567             $file['filesize']     = $fileinfo->get_filesize();
568             $file['fileurl']      = moodle_url::make_webservice_pluginfile_url(
569                                         $context->id, 'mod_book', 'chapter', $chapter->id,
570                                         $fileinfo->get_filepath(), $fileinfo->get_filename())->out(false);
571             $file['timecreated']  = $fileinfo->get_timecreated();
572             $file['timemodified'] = $fileinfo->get_timemodified();
573             $file['sortorder']    = $fileinfo->get_sortorder();
574             $file['userid']       = $fileinfo->get_userid();
575             $file['author']       = $fileinfo->get_author();
576             $file['license']      = $fileinfo->get_license();
577             $contents[] = $file;
578         }
579     }
581     // First content is the structure in encoded JSON format.
582     $structurefile = array();
583     $structurefile['type']         = 'content';
584     $structurefile['filename']     = 'structure';
585     $structurefile['filepath']     = "/";
586     $structurefile['filesize']     = 0;
587     $structurefile['fileurl']      = null;
588     $structurefile['timecreated']  = $book->timecreated;
589     $structurefile['timemodified'] = $book->timemodified;
590     $structurefile['content']      = json_encode(array_values($structure));
591     $structurefile['sortorder']    = 0;
592     $structurefile['userid']       = null;
593     $structurefile['author']       = null;
594     $structurefile['license']      = null;
596     // Add it as first element.
597     array_unshift($contents, $structurefile);
599     return $contents;