"MDL-20814, verify the file path, and print relevant information is there is bad...
[moodle.git] / mod / wiki / db / upgrade.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  * This file keeps track of upgrades to the wiki module
20  *
21  * Sometimes, changes between versions involve
22  * alterations to database structures and other
23  * major things that may break installations.
24  *
25  * The upgrade function in this file will attempt
26  * to perform all the necessary actions to upgrade
27  * your older installtion to the current version.
28  *
29  * @package mod-wiki-2.0
30  * @copyrigth 2009 Marc Alier, Jordi Piguillem marc.alier@upc.edu
31  * @copyrigth 2009 Universitat Politecnica de Catalunya http://www.upc.edu
32  *
33  * @author Jordi Piguillem
34  *
35  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
36  *
37  */
39 /**
40  *
41  * TODO LIST:
42  *
43  * 1. Add needed fields to wiki table. DONE
44  * 2. Rename other wiki tables. DONE
45  * 3. Create new wiki tables. DONE BUT NOT FINISHED, WATING FOR NEW TABLES
46  * 4. Move/Adapt/Transform configurations info to new structure
47  * 5. Migrate wiki entries to subwikis. DONE
48  * 6. Fill pages table with latest versions of every page. DONE
49  * 7. Migrate page history to new table (transforming formats). DONE, BUT STILL WORKING
50  * 8. Fill links table
51  * 9. Drop useless information
52  *
53  * ADITIONAL THINGS AFTER CHAT WITH ELOY:
54  *
55  * 1. addField is deprecated. DONE
56  * 2. Fix SQL error at block 3. DONE
57  * 3. Merge set_field_select with previous update sentence. DONE
58  * 4. Don't insert id fields on database (it won't work on mssql, oracle, pg). DONE.
59  * 5. Use upgrade_set_timeout function.
60  * 6. Use grafic of progess
61  *
62  * OTHER THINGS:
63  *
64  * 1. Use recordset instead of record when migrating historic
65  * 2. Select only usefull data on block 06
66  *
67  */
69 function xmldb_wiki_upgrade($oldversion) {
70     global $CFG, $DB, $OUTPUT;
72     $dbman = $DB->get_manager();
73     $result = true;
75     // Step 0: Add new fields to main wiki table
76     if ($result && $oldversion < 2010040100) {
77         require_once(dirname(__FILE__) . '/upgradelib.php');
78         echo $OUTPUT->notification('Adding new fields to wiki table', 'notifysuccess');
79         wiki_add_wiki_fields();
81         upgrade_mod_savepoint($result, 2010040100, 'wiki');
82     }
84     // Step 1: Rename old tables
85     if ($result && $oldversion < 2010040101) {
86         $tables = array('wiki_pages', 'wiki_locks', 'wiki_entries');
88         echo $OUTPUT->notification('Renaming old wiki module tables', 'notifysuccess');
89         foreach ($tables as $tablename) {
90             $table = new xmldb_table($tablename);
91             if ($dbman->table_exists($table)) {
92                 if ($dbman->table_exists($table)) {
93                     $dbman->rename_table($table, $tablename . '_old');
94                 }
95             }
96         }
97         upgrade_mod_savepoint($result, 2010040101, 'wiki');
98     }
100     // Step 2: Creating new tables
101     if ($result && $oldversion < 2010040102) {
102         require_once(dirname(__FILE__) . '/upgradelib.php');
103         echo $OUTPUT->notification('Installing new wiki module tables', 'notifysuccess');
104         wiki_upgrade_install_20_tables();
105         upgrade_mod_savepoint($result, 2010040102, 'wiki');
106     }
108     // Step 3: migrating wiki instances
109     if ($result && $oldversion < 2010040103) {
110         upgrade_set_timeout();
112         // Setting up wiki configuration
113         $sql = 'UPDATE {wiki} ' .
114             'SET intro = summary, ' .
115             'firstpagetitle = pagename, ' .
116             'defaultformat = ?';
117         $DB->execute($sql, array('html'));
119         $sql = 'UPDATE {wiki} ' .
120             'SET wikimode = ? ' .
121             'WHERE wtype = ?';
122         $DB->execute($sql, array('collaborative', 'group'));
124         $sql = 'UPDATE {wiki} ' .
125             'SET wikimode = ? ' .
126             'WHERE wtype != ?';
127         $DB->execute($sql, array('individual', 'group'));
129         // Removing edit & create capability to students in old teacher wikis
130         $studentroles = $DB->get_records('role', array('archetype' => 'student'));
131         $wikis = $DB->get_records('wiki');
132         foreach ($wikis as $wiki) {
133             echo $OUTPUT->notification('Migrating '.$wiki->wtype.' type wiki instance: '.$wiki->name, 'notifysuccess');
134             if ($wiki->wtype == 'teacher') {
135                 $cm = get_coursemodule_from_instance('wiki', $wiki->id);
136                 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
137                 foreach ($studentroles as $studentrole) {
138                     role_change_permission($studentrole->id, $context, 'mod/wiki:editpage', CAP_PROHIBIT);
139                     role_change_permission($studentrole->id, $context, 'mod/wiki:createpage', CAP_PROHIBIT);
140                 }
141             }
142         }
144         echo $OUTPUT->notification('Migrating old wikis to new wikis', 'notifysuccess');
145         upgrade_mod_savepoint($result, 2010040103, 'wiki');
146     }
148     // Step 4: migrating wiki entries to new subwikis
149     if ($result && $oldversion < 2010040104) {
150         /**
151          * Migrating wiki entries to new subwikis
152          */
153         $sql = 'INSERT into {wiki_subwikis} (wikiid, groupid, userid) ' .
154             'SELECT e.wikiid, e.groupid, e.userid ' .
155             'FROM {wiki_entries_old} e ';
156         echo $OUTPUT->notification('Migrating old entries to new subwikis', 'notifysuccess');
158         $DB->execute($sql, array());
160         upgrade_mod_savepoint($result, 2010040104, 'wiki');
161     }
163     // Step 5: Migrating pages
164     if ($result && $oldversion < 2010040105) {
165         /**
166          * Filling pages table with latest versions of every page.
167          *
168          * @TODO:   Ensure that ALL versions of every page are always in database and
169          *          they can be removed or cleaned.
170          *          That fact could let us rewrite the subselect to execute a count(*) to avoid
171          *          the order by and it would be much faster.
172          */
174         $sql = 'INSERT into {wiki_pages} (subwikiid, title, cachedcontent, timecreated, timemodified, userid, pageviews) ' .
175             'SELECT s.id, p.pagename, ?, p.created, p.lastmodified, p.userid, p.hits ' .
176             'FROM {wiki_pages_old} p '.
177             'LEFT OUTER JOIN {wiki_entries_old} e ON e.id = p.wiki ' .
178             'LEFT OUTER JOIN {wiki_subwikis} s ' .
179             'ON s.wikiid = e.wikiid AND s.groupid = e.groupid AND s.userid = e.userid ' .
180             'WHERE p.version = (' .
181             '   SELECT po.version ' .
182             '   FROM {wiki_pages_old} po ' .
183             '   WHERE p.pagename = po.pagename and ' .
184             '   p.wiki = po.wiki ' .
185             '   ORDER BY p.version DESC ' .
186             '   LIMIT 1)';
187         echo $OUTPUT->notification('Migrating old pages to new pages', 'notifysuccess');
189         $DB->execute($sql, array('**reparse needed**'));
191         upgrade_mod_savepoint($result, 2010040105, 'wiki');
192     }
194     // Step 6: Migrating versions
195     if ($result && $oldversion < 2010040106) {
196         require_once(dirname(__FILE__) . '/upgradelib.php');
197         echo $OUTPUT->notification('Migrating old history to new history', 'notifysuccess');
198         wiki_upgrade_migrate_versions();
199         upgrade_mod_savepoint($result, 2010040106, 'wiki');
200     }
202     // Step 7: refresh cachedcontent and fill wiki links table
203     if ($result && $oldversion < 2010040107) {
204         require_once($CFG->dirroot. '/mod/wiki/locallib.php');
205         upgrade_set_timeout();
207         $pages = $DB->get_recordset('wiki_pages');
209         while ($pages->valid()) {
210             $page = $pages->current();
211             wiki_refresh_cachedcontent($page);
212             $pages->next();
213         }
215         $pages->close();
217         echo $OUTPUT->notification('Caching content', 'notifysuccess');
218         upgrade_mod_savepoint($result, 2010040107, 'wiki');
219     }
220     // Step 8, migrating files
221     if ($result && $oldversion < 2010040108) {
222         $fs = get_file_storage();
223         $sql = "SELECT DISTINCT po.pagename, w.id AS wikiid, po.userid,
224             po.meta AS filemeta, eo.id AS entryid, eo.groupid, s.id AS subwiki,
225             w.course AS courseid, cm.id AS cmid
226             FROM {wiki_pages_old} po
227             LEFT OUTER JOIN {wiki_entries_old} eo
228             ON eo.id=po.wiki
229             LEFT OUTER JOIN {wiki} w
230             ON w.id = eo.wikiid
231             LEFT OUTER JOIN {wiki_subwikis} s
232             ON s.groupid = eo.groupid AND s.wikiid = eo.wikiid AND eo.userid = s.userid
233             JOIN {modules} m ON m.name = 'wiki'
234             JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = w.id)
235             ";
237         $rs = $DB->get_recordset_sql($sql);
238         foreach ($rs as $r) {
239             if (strpos($r->pagename, 'internal://') !== false) {
240                 // Found a file resource!
241                 $pattern = 'internal://';
242                 $matches = array();
243                 $filename = str_replace($pattern, '', $r->pagename);
244                 $orgifilename = $filename = clean_param($filename, PARAM_FILE);
245                 $context = get_context_instance(CONTEXT_MODULE, $r->cmid);
246                 $filemeta = unserialize($r->filemeta);
247                 $filesection = $filemeta['section'];
248                 // When attach a file to wiki page, user can customize the file name instead of original file name
249                 // if user did, old wiki will create two pages, internal://original_pagename and internal://renamed_pagename
250                 // internal://original_pagename record has renamed pagename in meta field
251                 // but all file have this field
252                 // old wiki will rename file names to filter space and special character
253                 if (!empty($filemeta['Content-Location'])) {
254                     $orgifilename = urldecode($filemeta['Content-Location']);
255                     $orgifilename = str_replace(' ', '_', $orgifilename);
256                 }
257                 $thefile = $CFG->dataroot . '/' . $r->courseid . '/moddata/wiki/' . $r->wikiid .'/' . $r->entryid . '/'. $filesection .'/'. $filename;
259                 if (is_file($thefile) && is_readable($thefile)) {
260                     $filerecord = array('contextid' => $context->id,
261                                         'filearea'  => 'wiki_attachments',
262                                         'itemid'    => $r->subwiki,
263                                         'filepath'  => '/',
264                                         'filename'  => $orgifilename,
265                                         'userid'    => $r->userid);
266                     if (!$fs->file_exists($context->id, 'wiki_attachments', $r->subwiki, '/', $orgifilename)) {
267                         //echo $OUTPUT->notification('Migrating file '.$orgifilename, 'notifysuccess');
268                         $storedfile = $fs->create_file_from_pathname($filerecord, $thefile);
269                     }
270                     // we have to create another file here to make sure interlinks work
271                     if (!$fs->file_exists($context->id, 'wiki_attachments', $r->subwiki, '/', $filename)) {
272                         $filerecord['filename'] = $filename;
273                         //echo $OUTPUT->notification('Migrating file '.$filename, 'notifysuccess');
274                         $storedfile = $fs->create_file_from_pathname($filerecord, $thefile);
275                     }
276                 } else {
277                     echo $OUTPUT->notification("Bad data found: $r->pagename <br/> Expected file path: $thefile Please fix the bad file path manually.");
278                     // print file meta info, which can help admin find missing file
279                     print_object($filemeta);
280                 }
281             }
282         }
283         $rs->close();
284         upgrade_mod_savepoint($result, 2010040108, 'wiki');
285     }
287     // Step 9: clean wiki table
288     if ($result && $oldversion < 2010040109) {
289         $fields = array('summary', 'pagename', 'wtype', 'ewikiprinttitle', 'htmlmode', 'ewikiacceptbinary', 'disablecamelcase', 'setpageflags', 'strippages', 'removepages', 'revertchanges', 'initialcontent');
290         $table = new xmldb_table('wiki');
291         foreach ($fields as $fieldname) {
292             $field = new xmldb_field($fieldname);
293             if ($dbman->field_exists($table, $field)) {
294                 $dbman->drop_field($table, $field);
295             }
297         }
298         echo $OUTPUT->notification('Cleaning wiki table', 'notifysuccess');
299         upgrade_mod_savepoint($result, 2010040109, 'wiki');
300     }
302     // TODO: Will hold the old tables so we will have chance to fix problems
303     // Will remove old tables once migrating 100% stable
304     // Step 10: delete old tables
305     if ($result && $oldversion < 2010040120) {
306         //$tables = array('wiki_pages', 'wiki_locks', 'wiki_entries');
308         //foreach ($tables as $tablename) {
309             //$table = new xmldb_table($tablename . '_old');
310             //if ($dbman->table_exists($table)) {
311                 //$dbman->drop_table($table);
312             //}
313         //}
314         //echo $OUTPUT->notification('Droping old tables', 'notifysuccess');
315         //upgrade_mod_savepoint($result, 2010040110, 'wiki');
316     }
318     return $result;