MDL-25501 reverting PULL-95
[moodle.git] / mod / wiki / locallib.php
CommitLineData
00710f4c
DC
1<?php
2
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/>.
17
18/**
19 * This contains functions and classes that will be used by scripts in wiki module
20 *
21 * @package mod-wiki-2.0
22 * @copyrigth 2009 Marc Alier, Jordi Piguillem marc.alier@upc.edu
23 * @copyrigth 2009 Universitat Politecnica de Catalunya http://www.upc.edu
24 *
25 * @author Jordi Piguillem
26 * @author Marc Alier
27 * @author David Jimenez
28 * @author Josep Arus
29 * @author Daniel Serrano
30 * @author Kenneth Riba
31 *
32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 */
34
35require_once($CFG->dirroot . '/mod/wiki/lib.php');
36require_once($CFG->dirroot . '/mod/wiki/parser/parser.php');
37
38define('WIKI_REFRESH_CACHE_TIME', 30); // @TODO: To be deleted.
39define('FORMAT_CREOLE', '37');
40define('FORMAT_NWIKI', '38');
41define('NO_VALID_RATE', '-999');
42define('IMPROVEMENT', '+');
43define('EQUAL', '=');
44define('WORST', '-');
45
46define('LOCK_TIMEOUT', 30);
47
48/**
49 * Get a wiki instance
50 * @param int $wikiid the instance id of wiki
51 */
52function wiki_get_wiki($wikiid) {
53 global $DB;
54
55 return $DB->get_record('wiki', array('id' => $wikiid));
56}
57
58/**
59 * Get sub wiki instances with same wiki id
60 * @param int $wikiid
61 */
62function wiki_get_subwikis($wikiid) {
63 global $DB;
64 return $DB->get_records('wiki_subwikis', array('wikiid' => $wikiid));
65}
66
67/**
68 * Get a sub wiki instance by wiki id and group id
69 * @param int $wikiid
70 * @param int $groupid
71 * @return object
72 */
73function wiki_get_subwiki_by_group($wikiid, $groupid, $userid = 0) {
74 global $DB;
75 return $DB->get_record('wiki_subwikis', array('wikiid' => $wikiid, 'groupid' => $groupid, 'userid' => $userid));
76}
77
78/**
79 * Get a sub wiki instace by instance id
80 * @param int $subwikiid
81 * @return object
82 */
83function wiki_get_subwiki($subwikiid) {
84 global $DB;
85 return $DB->get_record('wiki_subwikis', array('id' => $subwikiid));
86
87}
88
89/**
90 * Add a new sub wiki instance
91 * @param int $wikiid
92 * @param int $groupid
93 * @return int $insertid
94 */
95function wiki_add_subwiki($wikiid, $groupid, $userid = 0) {
96 global $DB;
97
98 $record = new StdClass();
99 $record->wikiid = $wikiid;
100 $record->groupid = $groupid;
101 $record->userid = $userid;
102
103 $insertid = $DB->insert_record('wiki_subwikis', $record);
104 return $insertid;
105}
106
107/**
108 * Get a wiki instance by pageid
109 * @param int $pageid
110 * @return object
111 */
112function wiki_get_wiki_from_pageid($pageid) {
113 global $DB;
114
9730c555
JP
115 $sql = "SELECT w.*
116 FROM {wiki} w, {wiki_subwikis} s, {wiki_pages} p
117 WHERE p.id = ? AND
118 p.subwikiid = s.id AND
119 s.wikiid = w.id";
00710f4c
DC
120
121 return $DB->get_record_sql($sql, array($pageid));
122}
123
124/**
125 * Get a wiki page by pageid
126 * @param int $pageid
127 * @return object
128 */
129function wiki_get_page($pageid) {
130 global $DB;
131 return $DB->get_record('wiki_pages', array('id' => $pageid));
132}
133
134/**
135 * Get latest version of wiki page
136 * @param int $pageid
137 * @return object
138 */
139function wiki_get_current_version($pageid) {
140 global $DB;
141
9730c555
JP
142 // @TODO: Fix this query
143 $sql = "SELECT *
144 FROM {wiki_versions}
145 WHERE pageid = ?
70b082fa
AB
146 ORDER BY version DESC";
147 return array_pop($DB->get_records_sql($sql, array($pageid), 0, 1));
00710f4c
DC
148
149}
150
151/**
152 * Alias of wiki_get_current_version
153 * @TODO, does the exactly same thing as wiki_get_current_version, should be removed
154 * @param int $pageid
155 * @return object
156 */
157function wiki_get_last_version($pageid) {
158 return wiki_get_current_version($pageid);
159}
160
161/**
162 * Get page section
163 * @param int $pageid
164 * @param string $section
165 */
166function wiki_get_section_page($page, $section) {
167
168 $version = wiki_get_current_version($page->id);
169 return wiki_parser_proxy::get_section($version->content, $version->contentformat, $section);
170}
171
172/**
173 * Get a wiki page by page title
174 * @param int $swid, sub wiki id
175 * @param string $title
176 * @return object
177 */
178function wiki_get_page_by_title($swid, $title) {
179 global $DB;
180 return $DB->get_record('wiki_pages', array('subwikiid' => $swid, 'title' => $title));
181}
182
183/**
184 * Get a version record by record id
185 * @param int $versionid, the version id
186 * @return object
187 */
188function wiki_get_version($versionid) {
189 global $DB;
190 return $DB->get_record('wiki_versions', array('id' => $versionid));
191}
192
193/**
194 * Get first page of wiki instace
195 * @param int $subwikiid
196 * @param int $module, wiki instance object
197 */
37dcd4b6 198function wiki_get_first_page($subwikid, $module = null) {
00710f4c 199 global $DB, $USER;
00710f4c 200
9730c555
JP
201 $sql = "SELECT p.*
202 FROM {wiki} w, {wiki_subwikis} s, {wiki_pages} p
203 WHERE s.id = ? AND
204 s.wikiid = w.id AND
205 w.firstpagetitle = p.title AND
206 p.subwikiid = s.id";
00710f4c
DC
207 return $DB->get_record_sql($sql, array($subwikid));
208}
209
210function wiki_save_section($wikipage, $sectiontitle, $sectioncontent, $userid) {
211
212 $wiki = wiki_get_wiki_from_pageid($wikipage->id);
213 $cm = get_coursemodule_from_instance('wiki', $wiki->id);
214 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
215
216 if (has_capability('mod/wiki:editpage', $context)) {
217 $version = wiki_get_current_version($wikipage->id);
218 $content = wiki_parser_proxy::get_section($version->content, $version->contentformat, $sectiontitle, true);
219
220 $newcontent = $content[0] . $sectioncontent . $content[2];
221
222 return wiki_save_page($wikipage, $newcontent, $userid);
223 } else {
224 return false;
225 }
226}
227
228/**
229 * Save page content
230 * @param object $wikipage
231 * @param string $newcontent
232 * @param int $userid
233 */
234function wiki_save_page($wikipage, $newcontent, $userid) {
235 global $DB;
236
237 $wiki = wiki_get_wiki_from_pageid($wikipage->id);
238 $cm = get_coursemodule_from_instance('wiki', $wiki->id);
239 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
240
241 if (has_capability('mod/wiki:editpage', $context)) {
242 $version = wiki_get_current_version($wikipage->id);
243
244 $version->content = $newcontent;
245 $version->userid = $userid;
246 $version->version++;
247 $version->timecreated = time();
a9637e7d 248 $versionid = $DB->insert_record('wiki_versions', $version);
00710f4c
DC
249
250 $wikipage->timemodified = $version->timecreated;
251 $wikipage->userid = $userid;
252 $return = wiki_refresh_cachedcontent($wikipage, $newcontent);
253
254 return $return;
255 } else {
256 return false;
257 }
258}
259
260function wiki_refresh_cachedcontent($page, $newcontent = null) {
261 global $DB;
262
263 $version = wiki_get_current_version($page->id);
264 if (!isset($newcontent)) {
265 $newcontent = $version->content;
266 }
267
268 $options = array('swid' => $page->subwikiid, 'pageid' => $page->id);
269 $parseroutput = wiki_parse_content($version->contentformat, $newcontent, $options);
270 $page->cachedcontent = $parseroutput['toc'] . $parseroutput['parsed_text'];
271 $page->timerendered = time();
272 $DB->update_record('wiki_pages', $page);
273
274 wiki_refresh_page_links($page, $parseroutput['link_count']);
275
276 return array('page' => $page, 'sections' => $parseroutput['repeated_sections'], 'version' => $version->version);
277}
278/**
279 * Restore a page
280 */
281function wiki_restore_page($wikipage, $newcontent, $userid) {
282 $return = wiki_save_page($wikipage, $newcontent, $userid);
283 return $return['page'];
284}
285
286function wiki_refresh_page_links($page, $links) {
287 global $DB;
288
289 $DB->delete_records('wiki_links', array('frompageid' => $page->id));
290 foreach ($links as $linkname => $linkinfo) {
291
292 $newlink = new stdClass();
293 $newlink->subwikiid = $page->subwikiid;
294 $newlink->frompageid = $page->id;
295
296 if ($linkinfo['new']) {
297 $newlink->tomissingpage = $linkname;
298 } else {
299 $newlink->topageid = $linkinfo['pageid'];
300 }
301
90c42e0f 302 $DB->insert_record('wiki_links', $newlink);
00710f4c
DC
303
304 }
305}
306
307/**
308 * Create a new wiki page, if the page exists, return existing pageid
309 * @param int $swid
310 * @param string $title
311 * @param string $format
312 * @param int $userid
313 */
314function wiki_create_page($swid, $title, $format, $userid) {
3b5e2acb 315 global $DB, $PAGE;
7bc03dd5
JP
316 $subwiki = wiki_get_subwiki($swid);
317 $cm = get_coursemodule_from_instance('wiki', $subwiki->wikiid);
318 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
319 require_capability('mod/wiki:editpage', $context);
00710f4c
DC
320 // if page exists
321 if ($page = wiki_get_page_by_title($swid, $title)) {
322 return $page->id;
323 }
324
325 // Creating a new empty version
326 $version = new stdClass();
327 $version->content = '';
328 $version->contentformat = $format;
329 $version->version = 0;
330 $version->timecreated = time();
331 $version->userid = $userid;
332
333 $versionid = null;
a9637e7d 334 $versionid = $DB->insert_record('wiki_versions', $version);
00710f4c
DC
335
336 // Createing a new empty page
337 $page = new stdClass();
338 $page->subwikiid = $swid;
339 $page->title = $title;
340 $page->cachedcontent = '';
341 $page->timecreated = $version->timecreated;
342 $page->timemodified = $version->timecreated;
343 $page->timerendered = $version->timecreated;
344 $page->userid = $userid;
345 $page->pageviews = 0;
346 $page->readonly = 0;
347
348 $pageid = $DB->insert_record('wiki_pages', $page);
349
350 // Setting the pageid
351 $version->id = $versionid;
352 $version->pageid = $pageid;
353 $DB->update_record('wiki_versions', $version);
354
355 wiki_make_cache_expire($page->title);
356 return $pageid;
357}
358
359function wiki_make_cache_expire($pagename) {
360 global $DB;
361
9730c555
JP
362 $sql = "UPDATE {wiki_pages}
363 SET timerendered = 0
364 WHERE id IN ( SELECT l.frompageid
365 FROM {wiki_links} l
366 WHERE l.tomissingpage = ?
367 )";
00710f4c
DC
368 $DB->execute ($sql, array($pagename));
369}
370
371/**
372 * Get a specific version of page
373 * @param int $pageid
374 * @param int $version
375 */
376function wiki_get_wiki_page_version($pageid, $version) {
377 global $DB;
378 return $DB->get_record('wiki_versions', array('pageid' => $pageid, 'version' => $version));
379}
380
381/**
382 * Get version list
383 * @param int $pageid
384 * @param int $limitfrom
385 * @param int $limitnum
386 */
387function wiki_get_wiki_page_versions($pageid, $limitfrom, $limitnum) {
388 global $DB;
389 return $DB->get_records('wiki_versions', array('pageid' => $pageid), 'version DESC', '*', $limitfrom, $limitnum);
390}
391
392/**
393 * Count the number of page version
394 * @param int $pageid
395 */
396function wiki_count_wiki_page_versions($pageid) {
397 global $DB;
398 return $DB->count_records('wiki_versions', array('pageid' => $pageid));
399}
400
401/**
402 * Get linked from page
403 * @param int $pageid
404 */
405function wiki_get_linked_to_pages($pageid) {
406 global $DB;
407 return $DB->get_records('wiki_links', array('frompageid' => $pageid));
408}
409
410/**
411 * Get linked from page
412 * @param int $pageid
413 */
414function wiki_get_linked_from_pages($pageid) {
415 global $DB;
416 return $DB->get_records('wiki_links', array('topageid' => $pageid));
417}
418
419/**
420 * Get pages which user have been edited
421 * @param int $swid
422 * @param int $userid
423 */
424function wiki_get_contributions($swid, $userid) {
425 global $DB;
426
9730c555
JP
427 $sql = "SELECT v.*
428 FROM {wiki_versions} v, {wiki_pages} p
429 WHERE p.subwikiid = ? AND
430 v.pageid = p.id AND
431 v.userid = ?";
00710f4c
DC
432
433 return $DB->get_records_sql($sql, array($swid, $userid));
434}
435
436/**
437 * Get missing or empty pages in wiki
438 * @param int $swid sub wiki id
439 */
440function wiki_get_missing_or_empty_pages($swid) {
441 global $DB;
442
9730c555
JP
443 $sql = "SELECT DISTINCT p.title, p.id, p.subwikiid
444 FROM {wiki} w, {wiki_subwikis} s, {wiki_pages} p
445 WHERE s.wikiid = w.id and
446 s.id = ? and
447 w.firstpagetitle != p.title and
448 p.subwikiid = ? and
449 1 = (SELECT count(*)
450 FROM {wiki_versions} v
451 WHERE v.pageid = p.id)
452 UNION
453 SELECT DISTINCT l.tomissingpage as title, 0 as id, l.subwikiid
454 FROM {wiki_links} l
455 WHERE l.subwikiid = ? and
456 l.topageid = 0";
00710f4c
DC
457
458 return $DB->get_records_sql($sql, array($swid, $swid, $swid));
459}
460
461/**
462 * Get pages list in wiki
463 * @param int $swid sub wiki id
464 */
465function wiki_get_page_list($swid) {
466 global $DB;
467 $records = $DB->get_records('wiki_pages', array('subwikiid' => $swid), 'title ASC');
468 return $records;
469}
470
471/**
472 * Return a list of orphaned wikis for one specific subwiki
473 * @global object
474 * @param int $swid sub wiki id
475 */
476function wiki_get_orphaned_pages($swid) {
477 global $DB;
478
9730c555
JP
479 $sql = "SELECT p.id, p.title
480 FROM {wiki_pages} p, {wiki} w , {wiki_subwikis} s
481 WHERE p.subwikiid = ?
482 AND s.id = ?
483 AND w.id = s.wikiid
484 AND p.title != w.firstpagetitle
485 AND p.id NOT IN (SELECT topageid FROM {wiki_links} WHERE subwikiid = ?);";
00710f4c 486
9730c555 487 return $DB->get_records_sql($sql, array($swid, $swid, $swid));
00710f4c
DC
488}
489
490/**
491 * Search wiki title
492 * @param int $swid sub wiki id
493 * @param string $search
494 */
495function wiki_search_title($swid, $search) {
496 global $DB;
75b986e7
JP
497
498 return $DB->get_records_select('wiki_pages', "subwikiid = ? AND title LIKE ?", array($swid, '%'.$search.'%'));
00710f4c
DC
499}
500
501/**
502 * Search wiki content
503 * @param int $swid sub wiki id
504 * @param string $search
505 */
506function wiki_search_content($swid, $search) {
507 global $DB;
75b986e7
JP
508
509 return $DB->get_records_select('wiki_pages', "subwikiid = ? AND cachedcontent LIKE ?", array($swid, '%'.$search.'%'));
00710f4c
DC
510}
511
512/**
513 * Search wiki title and content
514 * @param int $swid sub wiki id
515 * @param string $search
516 */
517function wiki_search_all($swid, $search) {
518 global $DB;
75b986e7
JP
519
520 return $DB->get_records_select('wiki_pages', "subwikiid = ? AND (cachedcontent LIKE ? OR title LIKE ?)", array($swid, '%'.$search.'%', '%'.$search.'%'));
00710f4c
DC
521}
522
523/**
9ffd2726 524 * Get user data
00710f4c
DC
525 */
526function wiki_get_user_info($userid) {
9ffd2726
JP
527 global $DB;
528 return $DB->get_record('user', array('id' => $userid));
00710f4c
DC
529}
530
531/**
532 * Increase page view nubmer
533 * @param int $page, database record
534 */
535function wiki_increment_pageviews($page) {
536 global $DB;
537
538 $page->pageviews++;
539 $DB->update_record('wiki_pages', $page);
540}
541
542//----------------------------------------------------------
543//----------------------------------------------------------
544
545/**
546 * Text format supported by wiki module
547 */
548function wiki_get_formats() {
44c0751b 549 return array('html', 'creole', 'nwiki');
00710f4c
DC
550}
551
552/**
553 * Parses a string with the wiki markup language in $markup.
554 *
555 * @return Array or false when something wrong has happened.
556 *
557 * Returned array contains the following fields:
558 * 'parsed_text' => String. Contains the parsed wiki content.
559 * 'unparsed_text' => String. Constains the original wiki content.
560 * 'link_count' => Array of array('destination' => ..., 'new' => "is new?"). Contains the internal wiki links found in the wiki content.
561 * 'deleted_sections' => the list of deleted sections.
562 * '' =>
563 *
564 * @author Josep Arús Pous
565 **/
566function wiki_parse_content($markup, $pagecontent, $options = array()) {
567 global $PAGE;
568
569 $subwiki = wiki_get_subwiki($options['swid']);
570 $cm = get_coursemodule_from_instance("wiki", $subwiki->wikiid);
571 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
572
64f93798 573 $parser_options = array('link_callback' => '/mod/wiki/locallib.php:wiki_parser_link', 'link_callback_args' => array('swid' => $options['swid']), 'table_callback' => '/mod/wiki/locallib.php:wiki_parser_table', 'real_path_callback' => '/mod/wiki/locallib.php:wiki_parser_real_path', 'real_path_callback_args' => array('context' => $context, 'component' => 'mod_wiki', 'filearea' => 'attachments', 'pageid' => $options['pageid']), 'pageid' => $options['pageid'], 'pretty_print' => (isset($options['pretty_print']) && $options['pretty_print']), 'printable' => (isset($options['printable']) && $options['printable']));
00710f4c
DC
574
575 return wiki_parser_proxy::parse($pagecontent, $markup, $parser_options);
576}
577
578/**
579 * This function is the parser callback to parse wiki links.
580 *
581 * It returns the necesary information to print a link.
582 *
583 * NOTE: Empty pages and non-existent pages must be print in red color.
584 *
585 * @param link name of a page
586 * @param $options
587 *
588 * @return
589 *
590 * @TODO Doc return and options
591 */
592function wiki_parser_link($link, $options = null) {
593 global $CFG;
594
595 if (is_object($link)) {
596 $parsedlink = array('content' => $link->title, 'url' => $CFG->wwwroot . '/mod/wiki/view.php?pageid=' . $link->id, 'new' => false, 'link_info' => array('link' => $link->title, 'pageid' => $link->id, 'new' => false));
597
598 $version = wiki_get_current_version($link->id);
599 if ($version->version == 0) {
600 $parsedlink['new'] = true;
601 }
602 return $parsedlink;
603 } else {
604 $swid = $options['swid'];
605
606 if ($page = wiki_get_page_by_title($swid, $link)) {
607 $parsedlink = array('content' => $link, 'url' => $CFG->wwwroot . '/mod/wiki/view.php?pageid=' . $page->id, 'new' => false, 'link_info' => array('link' => $link, 'pageid' => $page->id, 'new' => false));
608
609 $version = wiki_get_current_version($page->id);
610 if ($version->version == 0) {
611 $parsedlink['new'] = true;
612 }
613
614 return $parsedlink;
615
616 } else {
617 return array('content' => $link, 'url' => $CFG->wwwroot . '/mod/wiki/create.php?swid=' . $swid . '&amp;title=' . urlencode($link) . '&amp;action=new', 'new' => true, 'link_info' => array('link' => $link, 'new' => true, 'pageid' => 0));
618 }
619 }
620}
621
622/**
623 * Returns the table fully parsed (HTML)
624 *
625 * @return HTML for the table $table
626 * @author Josep Arús Pous
627 *
628 **/
629function wiki_parser_table($table) {
630 global $OUTPUT;
631
632 $htmltable = new html_table();
633
634 $headers = $table[0];
635 $htmltable->head = array();
636 foreach ($headers as $h) {
637 $htmltable->head[] = $h[1];
638 }
639
640 array_shift($table);
641 $htmltable->data = array();
642 foreach ($table as $row) {
643 $row_data = array();
644 foreach ($row as $r) {
645 $row_data[] = $r[1];
646 }
647 $htmltable->data[] = $row_data;
648 }
649
650 return html_writer::table($htmltable);
651}
652
653/**
654 * Returns an absolute path link, unless there is no such link.
655 *
44d8a940
PS
656 * @param string url Link's URL
657 * @param stdClass context filearea params
658 * @param string filearea
659 * @param int fileareaid
00710f4c
DC
660 *
661 * @return File full path
662 */
663
664function wiki_parser_real_path($url, $context, $filearea, $fileareaid) {
665 global $CFG;
666
667 if (preg_match("/^(?:http|ftp)s?\:\/\//", $url)) {
668 return $url;
669 } else {
670 return "{$CFG->wwwroot}/pluginfile.php/{$context->id}/$filearea/$fileareaid/$url";
671 }
672}
673
674/**
675 * Returns the token used by a wiki language to represent a given tag or "object" (bold -> **)
676 *
677 * @return A string when it has only one token at the beginning (f. ex. lists). An array composed by 2 strings when it has 2 tokens, one at the beginning and one at the end (f. ex. italics). Returns false otherwise.
678 * @author Josep Arús Pous
679 **/
680function wiki_parser_get_token($markup, $name) {
681
682 return wiki_parser_proxy::get_token($name, $markup);
683}
684
685/**
686 * Checks if current user can view a subwiki
687 *
688 * @param $subwiki
689 */
690function wiki_user_can_view($subwiki) {
691 global $USER;
692
693 $wiki = wiki_get_wiki($subwiki->wikiid);
694 $cm = get_coursemodule_from_instance('wiki', $wiki->id);
695 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
696
697 // Working depending on activity groupmode
698 switch (groups_get_activity_groupmode($cm)) {
699 case NOGROUPS:
700
701 if ($wiki->wikimode == 'collaborative') {
702 // Collaborative Mode:
703 // There is one wiki for all the class.
704 //
705 // Only view capbility needed
cece1791 706 return has_capability('mod/wiki:viewpage', $context);
00710f4c
DC
707 } else if ($wiki->wikimode == 'individual') {
708 // Individual Mode:
709 // Each person owns a wiki.
710 if ($subwiki->userid == $USER->id) {
711 // Only the owner of the wiki can view it
cece1791 712 return has_capability('mod/wiki:viewpage', $context);
00710f4c
DC
713 } else { // User has special capabilities
714 // User must have:
715 // mod/wiki:viewpage capability
716 // and
717 // mod/wiki:managewiki capability
cece1791
DC
718 $view = has_capability('mod/wiki:viewpage', $context);
719 $manage = has_capability('mod/wiki:managewiki', $context);
00710f4c
DC
720
721 return $view && $manage;
722 }
723 } else {
724 //Error
725 return false;
726 }
727 case SEPARATEGROUPS:
728 // Collaborative and Individual Mode
729 //
730 // Collaborative Mode:
731 // There is one wiki per group.
732 // Individual Mode:
733 // Each person owns a wiki.
734 if ($wiki->wikimode == 'collaborative' || $wiki->wikimode == 'individual') {
735 // Only members of subwiki group could view that wiki
736 if ($subwiki->groupid == groups_get_activity_group($cm)) {
737 // Only view capability needed
cece1791 738 return has_capability('mod/wiki:viewpage', $context);
00710f4c
DC
739
740 } else { // User is not part of that group
741 // User must have:
742 // mod/wiki:managewiki capability
743 // or
744 // moodle/site:accessallgroups capability
745 // and
746 // mod/wiki:viewpage capability
cece1791
DC
747 $view = has_capability('mod/wiki:viewpage', $context);
748 $manage = has_capability('mod/wiki:managewiki', $context);
749 $access = has_capability('moodle/site:accessallgroups', $context);
00710f4c 750 return ($manage || $access) && $view;
37dcd4b6 751 }
00710f4c
DC
752 } else {
753 //Error
754 return false;
755 }
756 case VISIBLEGROUPS:
757 // Collaborative and Individual Mode
758 //
759 // Collaborative Mode:
760 // There is one wiki per group.
761 // Individual Mode:
762 // Each person owns a wiki.
763 if ($wiki->wikimode == 'collaborative' || $wiki->wikimode == 'individual') {
764 // Everybody can read all wikis
765 //
766 // Only view capability needed
cece1791 767 return has_capability('mod/wiki:viewpage', $context);
00710f4c
DC
768 } else {
769 //Error
770 return false;
771 }
772 default: // Error
773 return false;
774 }
775}
776
777/**
778 * Checks if current user can edit a subwiki
779 *
780 * @param $subwiki
781 */
782function wiki_user_can_edit($subwiki) {
783 global $USER;
784
785 $wiki = wiki_get_wiki($subwiki->wikiid);
786 $cm = get_coursemodule_from_instance('wiki', $wiki->id);
787 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
788
789 // Working depending on activity groupmode
790 switch (groups_get_activity_groupmode($cm)) {
791 case NOGROUPS:
792
793 if ($wiki->wikimode == 'collaborative') {
794 // Collaborative Mode:
795 // There is a wiki for all the class.
796 //
797 // Only edit capbility needed
cece1791 798 return has_capability('mod/wiki:editpage', $context);
00710f4c
DC
799 } else if ($wiki->wikimode == 'individual') {
800 // Individual Mode
801 // There is a wiki per user
802
803 // Only the owner of that wiki can edit it
804 if ($subwiki->userid == $USER->id) {
cece1791 805 return has_capability('mod/wiki:editpage', $context);
00710f4c
DC
806 } else { // Current user is not the owner of that wiki.
807
808 // User must have:
809 // mod/wiki:editpage capability
810 // and
811 // mod/wiki:managewiki capability
cece1791
DC
812 $edit = has_capability('mod/wiki:editpage', $context);
813 $manage = has_capability('mod/wiki:managewiki', $context);
00710f4c
DC
814
815 return $edit && $manage;
816 }
817 } else {
818 //Error
819 return false;
820 }
821 case SEPARATEGROUPS:
822 if ($wiki->wikimode == 'collaborative') {
823 // Collaborative Mode:
824 // There is one wiki per group.
825 //
826 // Only members of subwiki group could edit that wiki
827 if ($subwiki->groupid == groups_get_activity_group($cm)) {
828 // Only edit capability needed
cece1791 829 return has_capability('mod/wiki:editpage', $context);
00710f4c
DC
830 } else { // User is not part of that group
831 // User must have:
832 // mod/wiki:managewiki capability
833 // and
834 // moodle/site:accessallgroups capability
835 // and
836 // mod/wiki:editpage capability
cece1791
DC
837 $manage = has_capability('mod/wiki:managewiki', $context);
838 $access = has_capability('moodle/site:accessallgroups', $context);
839 $edit = has_capability('mod/wiki:editpage', $context);
00710f4c
DC
840 return $manage && $access && $edit;
841 }
842 } else if ($wiki->wikimode == 'individual') {
843 // Individual Mode:
844 // Each person owns a wiki.
845 //
846 // Only the owner of that wiki can edit it
847 if ($subwiki->userid == $USER->id) {
cece1791 848 return has_capability('mod/wiki:editpage', $context);
00710f4c
DC
849 } else { // Current user is not the owner of that wiki.
850 // User must have:
851 // mod/wiki:managewiki capability
852 // and
853 // moodle/site:accessallgroups capability
854 // and
855 // mod/wiki:editpage capability
cece1791
DC
856 $manage = has_capability('mod/wiki:managewiki', $context);
857 $access = has_capability('moodle/site:accessallgroups', $context);
858 $edit = has_capability('mod/wiki:editpage', $context);
00710f4c
DC
859 return $manage && $access && $edit;
860 }
861 } else {
862 //Error
863 return false;
864 }
865 case VISIBLEGROUPS:
866 if ($wiki->wikimode == 'collaborative') {
867 // Collaborative Mode:
868 // There is one wiki per group.
869 //
870 // Only members of subwiki group could edit that wiki
871 if ($subwiki->groupid == groups_get_activity_group($cm)) {
872 // Only edit capability needed
cece1791 873 return has_capability('mod/wiki:editpage', $context);
00710f4c
DC
874 } else { // User is not part of that group
875 // User must have:
876 // mod/wiki:managewiki capability
877 // and
878 // mod/wiki:editpage capability
cece1791
DC
879 $manage = has_capability('mod/wiki:managewiki', $context);
880 $edit = has_capability('mod/wiki:editpage', $context);
00710f4c
DC
881 return $manage && $edit;
882 }
883 } else if ($wiki->wikimode == 'individual') {
884 // Individual Mode:
885 // Each person owns a wiki.
886 //
887 // Only the owner of that wiki can edit it
888 if ($subwiki->userid == $USER->id) {
cece1791 889 return has_capability('mod/wiki:editpage', $context);
00710f4c
DC
890 } else { // Current user is not the owner of that wiki.
891 // User must have:
892 // mod/wiki:managewiki capability
893 // and
894 // mod/wiki:editpage capability
cece1791
DC
895 $manage = has_capability('mod/wiki:managewiki', $context);
896 $edit = has_capability('mod/wiki:editpage', $context);
00710f4c
DC
897 return $manage && $edit;
898 }
899 } else {
900 //Error
901 return false;
902 }
903 default: // Error
904 return false;
905 }
906}
907
908//----------------
909// Locks
910//----------------
911
912/**
913 * Checks if a page-section is locked.
914 *
915 * @return true if the combination of section and page is locked, FALSE otherwise.
916 */
917function wiki_is_page_section_locked($pageid, $userid, $section = null) {
918 global $DB;
919
920 $sql = "pageid = ? AND lockedat > ? AND userid != ?";
921 $params = array($pageid, time(), $userid);
922
923 if (!empty($section)) {
924 $sql .= " AND (sectionname = ? OR sectionname IS null)";
925 $params[] = $section;
926 }
927
928 return $DB->record_exists_select('wiki_locks', $sql, $params);
929}
930
931/**
932 * Inserts or updates a wiki_locks record.
933 */
934function wiki_set_lock($pageid, $userid, $section = null, $insert = false) {
935 global $DB;
936
937 if (wiki_is_page_section_locked($pageid, $userid, $section)) {
938 return false;
939 }
940
941 $params = array('pageid' => $pageid, 'userid' => $userid, 'sectionname' => $section);
942
943 $lock = $DB->get_record('wiki_locks', $params);
944
945 if (!empty($lock)) {
946 $DB->update_record('wiki_locks', array('id' => $lock->id, 'lockedat' => time() + LOCK_TIMEOUT));
947 } else if ($insert) {
948 $DB->insert_record('wiki_locks', array('pageid' => $pageid, 'sectionname' => $section, 'userid' => $userid, 'lockedat' => time() + 30));
949 }
950
951 return true;
952}
953
954/**
955 * Deletes wiki_locks that are not in use. (F.Ex. after submitting the changes). If no userid is present, it deletes ALL the wiki_locks of a specific page.
956 */
957function wiki_delete_locks($pageid, $userid = null, $section = null, $delete_from_db = true, $delete_section_and_page = false) {
958 global $DB;
959
960 $params = array('pageid' => $pageid);
961
962 if (!empty($userid)) {
963 $params['userid'] = $userid;
964 }
965
966 if (!empty($section)) {
967 $params['sectionname'] = $section;
968 }
969
970 if ($delete_from_db) {
971 $DB->delete_records('wiki_locks', $params);
972 if ($delete_section_and_page && !empty($section)) {
973 $params['sectionname'] = null;
974 $DB->delete_records('wiki_locks', $params);
975 }
976 } else {
977 $DB->set_field('wiki_locks', 'lockedat', time(), $params);
978 }
979}
980
981/**
982 * Deletes wiki_locks that expired 1 hour ago.
983 */
984function wiki_delete_old_locks() {
985 global $DB;
986
987 $DB->delete_records_select('wiki_locks', "lockedat < ?", array(time() - 3600));
988}
989
990/**
991 * File processing
992 */
993
994/**
995 * Uploads files to permanent disk space.
996 *
44d8a940
PS
997 * @param int draftitemid Draft space ID
998 * @param int contextid
00710f4c
DC
999 *
1000 * @return array of files that have not been inserted.
1001 */
1002
1003function wiki_process_attachments($draftitemid, $deleteuploads, $contextid, $filearea, $itemid, $options = null) {
1004 global $CFG, $USER;
1005
1006 if (empty($options)) {
1007 $options = page_wiki_edit::$attachmentoptions;
1008 }
1009
1010 $errors = array();
1011
1012 $usercontext = get_context_instance(CONTEXT_USER, $USER->id);
1013 $fs = get_file_storage();
1014
64f93798 1015 $oldfiles = $fs->get_area_files($contextid, 'mod_wiki', 'attachments', $itemid, 'id');
00710f4c
DC
1016
1017 foreach ($oldfiles as $file) {
1018 if (in_array($file->get_pathnamehash(), $deleteuploads)) {
1019 $file->delete();
1020 }
1021 }
1022
64f93798
PS
1023 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id');
1024 $oldfiles = $fs->get_area_files($contextid, 'mod_wiki', 'attachments', $itemid, 'id');
00710f4c 1025
9730c555 1026 $file_record = array('contextid' => $contextid, 'component' => 'mod_wiki', 'filearea' => 'attachments', 'itemid' => $itemid);
00710f4c
DC
1027 //more or less a merge...
1028 $newhashes = array();
1029 foreach ($draftfiles as $file) {
64f93798 1030 $newhash = sha1("/$contextid/mod_wiki/attachments/$itemid" . $file->get_filepath() . $file->get_filename());
00710f4c
DC
1031 $newhashes[$newhash] = $file;
1032 }
1033
1034 $filecount = 0;
1035 foreach ($oldfiles as $file) {
1036 $oldhash = $file->get_pathnamehash();
1037 if (!$file->is_directory() && isset($newhashes[$oldhash])) {
1038 //repeated file: ERROR!!!
1039 unset($newhashes[$oldhash]);
1040 $errors[] = $file;
1041 }
1042
1043 if (!$file->is_directory()) {
1044 $filecount++;
1045 }
1046 }
1047
1048 foreach ($newhashes as $file) {
1049 if ($file->get_filepath() !== '/' or $file->is_directory()) {
1050 continue;
1051 }
1052
1053 if ($options['maxfiles'] and $options['maxfiles'] <= $filecount) {
1054 break;
1055 }
1056
1057 if (!$file->is_directory()) {
1058 $filecount++;
1059 $fs->create_file_from_storedfile($file_record, $file);
1060 }
1061 }
1062
1063 //delete all draft files
64f93798 1064 $fs->delete_area_files($usercontext->id, 'user', 'draft', $draftitemid);
00710f4c
DC
1065
1066 return $errors;
1067}
1068
9bf1b716
JP
1069function wiki_get_comment($commentid){
1070 global $DB;
becf81c7 1071 return $DB->get_record('comments', array('id' => $commentid));
9bf1b716
JP
1072}
1073
00710f4c
DC
1074/**
1075 * Returns all comments by context and pageid
1076 *
1077 * @param $context. Current context
1078 * @param $pageid. Current pageid
1079 **/
9ffd2726 1080function wiki_get_comments($contextid, $pageid) {
00710f4c
DC
1081 global $DB;
1082
9ffd2726 1083 return $DB->get_records('comments', array('contextid' => $contextid, 'itemid' => $pageid, 'commentarea' => 'wiki_page'));
00710f4c
DC
1084}
1085
1086/**
1087 * Add comments ro database
1088 *
1089 * @param object $context. Current context
1090 * @param int $pageid. Current pageid
1091 * @param string $content. Content of the comment
1092 * @param string editor. Version of editor we are using.
1093 **/
1094function wiki_add_comment($context, $pageid, $content, $editor) {
1095 global $CFG;
1096 require_once($CFG->dirroot . '/comment/lib.php');
1097
1098 list($context, $course, $cm) = get_context_info_array($context->id);
1099 $cmt = new stdclass();
1100 $cmt->context = $context;
1101 $cmt->itemid = $pageid;
ab422920 1102 $cmt->area = 'wiki_page';
00710f4c 1103 $cmt->course = $course;
d846488e 1104 $cmt->component = 'mod_wiki';
00710f4c
DC
1105
1106 $manager = new comment($cmt);
1107
1108 if ($editor == 'creole') {
1109 $manager->add($content, FORMAT_CREOLE);
1110 } else if ($editor == 'html') {
1111 $manager->add($content, FORMAT_HTML);
1112 } else if ($editor == 'nwiki') {
1113 $manager->add($content, FORMAT_NWIKI);
1114 }
1115
1116}
1117
1118/**
1119 * Delete comments from database
1120 *
1121 * @param $idcomment. Id of comment which will be deleted
1122 * @param $context. Current context
1123 * @param $pageid. Current pageid
1124 **/
1125function wiki_delete_comment($idcomment, $context, $pageid) {
1126 global $CFG;
1127 require_once($CFG->dirroot . '/comment/lib.php');
1128
1129 list($context, $course, $cm) = get_context_info_array($context->id);
6bdfef5d 1130 $cmt = new stdClass();
00710f4c
DC
1131 $cmt->context = $context;
1132 $cmt->itemid = $pageid;
ab422920 1133 $cmt->area = 'wiki_page';
00710f4c 1134 $cmt->course = $course;
d846488e 1135 $cmt->component = 'mod_wiki';
00710f4c
DC
1136
1137 $manager = new comment($cmt);
1138 $manager->delete($idcomment);
1139
1140}
1141
1142/**
1143 * Delete al comments from wiki
1144 *
1145 **/
1146function wiki_delete_comments_wiki() {
1147 global $PAGE, $DB;
1148
1149 $cm = $PAGE->cm;
1150 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1151
1152 $table = 'comments';
1153 $select = 'contextid = ?';
1154
1155 $DB->delete_records_select($table, $select, array($context->id));
1156
1157}
1158
1159function wiki_add_progress($pageid, $oldversionid, $versionid, $progress) {
1160 global $DB;
1161 for ($v = $oldversionid + 1; $v <= $versionid; $v++) {
1162 $user = wiki_get_wiki_page_id($pageid, $v);
1163
1164 $DB->insert_record('wiki_progress', array('userid' => $user->userid, 'pageid' => $pageid, 'versionid' => $v, 'progress' => $progress));
1165 }
1166}
1167
1168function wiki_get_wiki_page_id($pageid, $id) {
1169 global $DB;
1170 return $DB->get_record('wiki_versions', array('pageid' => $pageid, 'id' => $id));
1171}
1172
1173function wiki_print_page_content($page, $context, $subwikiid) {
1174 global $OUTPUT, $CFG;
1175
1176 if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) {
1177 $content = wiki_refresh_cachedcontent($page);
1178 $page = $content['page'];
1179 }
1180
1181 if (isset($content)) {
1182 $box = '';
1183 foreach ($content['sections'] as $s) {
1184 $box .= '<p>' . get_string('repeatedsection', 'wiki', $s) . '</p>';
1185 }
1186
1187 if (!empty($box)) {
1188 echo $OUTPUT->box($box);
1189 }
1190 }
64f93798 1191 $html = file_rewrite_pluginfile_urls($page->cachedcontent, 'pluginfile.php', $context->id, 'mod_wiki', 'attachments', $subwikiid);
367a75fa 1192 $html = format_text($html, FORMAT_MOODLE, array('overflowdiv'=>true));
00710f4c
DC
1193 echo $OUTPUT->box($html);
1194
1195 if (!empty($CFG->usetags)) {
f0f77dfa 1196 $tags = tag_get_tags_array('wiki_pages', $page->id);
7b8b3662 1197 echo $OUTPUT->container_start('wiki-tags');
cc26cb3b 1198 echo '<span class="wiki-tags-title">'.get_string('tags').': </span>';
7b8b3662
DC
1199 $links = array();
1200 foreach ($tags as $tagid=>$tag) {
1201 $url = new moodle_url('/tag/index.php', array('tag'=>$tag));
cc26cb3b 1202 $links[] = html_writer::link($url, $tag, array('title'=>get_string('tagtitle', 'wiki', $tag)));
7b8b3662
DC
1203 }
1204 echo join($links, ", ");
1205 echo $OUTPUT->container_end();
00710f4c
DC
1206 }
1207
1208 wiki_increment_pageviews($page);
1209}
1210
1211/**
1212 * This function trims any given text and returns it with some dots at the end
1213 *
1214 * @param string $text
1215 * @param string $limit
1216 *
1217 * @return string
1218 */
1219function wiki_trim_string($text, $limit = 25) {
1220
1221 if (strlen($text) > $limit) {
1222 $text = substr($text, 0, $limit) . '...';
1223 }
1224
1225 return $text;
1226}
1227
1228/**
1229 * Prints default edit form fields and buttons
1230 *
1231 * @param string $format Edit form format (html, creole...)
1232 * @param integer $version Version number. A negative number means no versioning.
1233 */
1234
1235function wiki_print_edit_form_default_fields($format, $pageid, $version = -1, $upload = false, $deleteuploads = array()) {
1236 global $CFG, $PAGE, $OUTPUT;
1237
1238 echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
1239
1240 if ($version >= 0) {
1241 echo '<input type="hidden" name="version" value="' . $version . '" />';
1242 }
1243
1244 echo '<input type="hidden" name="format" value="' . $format . '"/>';
1245
1246 //attachments
1247 require_once($CFG->dirroot . '/lib/form/filemanager.php');
1248
1249 $filemanager = new MoodleQuickForm_filemanager('attachments', get_string('wikiattachments', 'wiki'), array('id' => 'attachments'), array('subdirs' => false, 'maxfiles' => 99, 'maxbytes' => $CFG->maxbytes));
1250
1251 $value = file_get_submitted_draft_itemid('attachments');
1252 if (!empty($value) && !$upload) {
1253 $filemanager->setValue($value);
1254 }
1255
1256 echo "<fieldset class=\"wiki-upload-section clearfix\"><legend class=\"ftoggler\">" . get_string("uploadtitle", 'wiki') . "</legend>";
1257
1258 echo $OUTPUT->container_start('mdl-align wiki-form-center aaaaa');
1259 print $filemanager->toHtml();
1260 echo $OUTPUT->container_end();
1261
1262 $cm = $PAGE->cm;
1263 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1264
1265 echo $OUTPUT->container_start('mdl-align wiki-form-center wiki-upload-table');
1266 wiki_print_upload_table($context, 'wiki_upload', $pageid, $deleteuploads);
1267 echo $OUTPUT->container_end();
1268
1269 echo "</fieldset>";
1270
1271 echo '<input class="wiki_button" type="submit" name="editoption" value="' . get_string('save', 'wiki') . '"/>';
1272 echo '<input class="wiki_button" type="submit" name="editoption" value="' . get_string('upload', 'wiki') . '"/>';
1273 echo '<input class="wiki_button" type="submit" name="editoption" value="' . get_string('preview') . '"/>';
1274 echo '<input class="wiki_button" type="submit" name="editoption" value="' . get_string('cancel') . '" />';
1275}
1276
1277/**
1278 * Prints a table with the files attached to a wiki page
1279 * @param object $context
1280 * @param string $filearea
1281 * @param int $fileitemid
1282 * @param array deleteuploads
1283 */
1284function wiki_print_upload_table($context, $filearea, $fileitemid, $deleteuploads = array()) {
1285 global $CFG, $OUTPUT;
1286
1287 $htmltable = new html_table();
1288
1289 $htmltable->head = array(get_string('deleteupload', 'wiki'), get_string('uploadname', 'wiki'), get_string('uploadactions', 'wiki'));
1290
1291 $fs = get_file_storage();
64f93798 1292 $files = $fs->get_area_files($context->id, 'mod_wiki', $filearea, $fileitemid); //TODO: this is weird (skodak)
00710f4c
DC
1293
1294 foreach ($files as $file) {
1295 if (!$file->is_directory()) {
1296 $checkbox = '<input type="checkbox" name="deleteupload[]", value="' . $file->get_pathnamehash() . '"';
1297
1298 if (in_array($file->get_pathnamehash(), $deleteuploads)) {
1299 $checkbox .= ' checked="checked"';
1300 }
1301
1302 $checkbox .= " />";
1303
1304 $htmltable->data[] = array($checkbox, '<a href="' . file_encode_url($CFG->wwwroot . '/pluginfile.php', '/' . $context->id . '/wiki_upload/' . $fileitemid . '/' . $file->get_filename()) . '">' . $file->get_filename() . '</a>', "");
1305 }
1306 }
1307
1308 print '<h3 class="upload-table-title">' . get_string('uploadfiletitle', 'wiki') . "</h3>";
1309 print html_writer::table($htmltable);
1310}
1311
1312/**
1313 * Generate wiki's page tree
1314 *
1315 * @param $page. A wiki page object
1316 * @param $node. Starting navigation_node
1317 * @param $keys. An array to store keys
1318 * @return an array with all tree nodes
1319 */
1320function wiki_build_tree($page, $node, &$keys) {
1321 $content = array();
1322 static $icon;
1323 $icon = new pix_icon('f/odt', '');
1324 $pages = wiki_get_linked_pages($page->id);
1325 foreach ($pages as $p) {
1326 $key = $page->id . ':' . $p->id;
1327 if (in_array($key, $keys)) {
1328 break;
1329 }
1330 array_push($keys, $key);
1331 $l = wiki_parser_link($p);
1332 $link = new moodle_url('/mod/wiki/view.php', array('pageid' => $p->id));
1333 $nodeaux = $node->add($p->title, $link, null, null, null, $icon);
1334 if ($l['new']) {
1335 $nodeaux->add_class('wiki_newentry');
1336 }
1337 wiki_build_tree($p, $nodeaux, $keys);
1338 }
1339 $content[] = $node;
1340 return $content;
1341}
1342
1343/**
1344 * Get linked pages from page
1345 * @param int $pageid
1346 */
1347function wiki_get_linked_pages($pageid) {
1348 global $DB;
1349
9730c555 1350 $sql = "SELECT p.id, p.title
e22465c7
PS
1351 FROM {wiki_pages} p
1352 JOIN {wiki_links} l ON l.topageid = p.id
9730c555
JP
1353 WHERE l.frompageid = ?
1354 ORDER BY p.title ASC";
37dcd4b6
JP
1355 return $DB->get_records_sql($sql, array($pageid));
1356}
1357
1358/**
1359 * Get updated pages from wiki
1360 * @param int $pageid
1361 */
1362function wiki_get_updated_pages_by_subwiki($swid) {
1363 global $DB, $USER;
1364
9730c555
JP
1365 $sql = "SELECT *
1366 FROM {wiki_pages}
1367 WHERE subwikiid = ? AND timemodified > ?
1368 ORDER BY timemodified DESC";
37dcd4b6 1369 return $DB->get_records_sql($sql, array($swid, $USER->lastlogin));
00710f4c 1370}