1<?php 2/** 3 * DokuWiki Plugin bez (Action Component) 4 * 5 */ 6 7// must be run within Dokuwiki 8 9if (!defined('DOKU_INC')) die(); 10 11/** 12 * Class action_plugin_bez_migration 13 * 14 * Handle migrations that need more than just SQL 15 */ 16class action_plugin_ireadit_migration extends DokuWiki_Action_Plugin 17{ 18 /** 19 * @inheritDoc 20 */ 21 public function register(Doku_Event_Handler $controller) 22 { 23 $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'AFTER', $this, 'handle_migrations'); 24 } 25 26 /** 27 * Call our custom migrations when defined 28 * 29 * @param Doku_Event $event 30 * @param $param 31 */ 32 public function handle_migrations(Doku_Event $event, $param) 33 { 34 if ($event->data['sqlite']->getAdapter()->getDbname() !== 'ireadit') { 35 return; 36 } 37 $to = $event->data['to']; 38 39 if (is_callable([$this, "migration$to"])) { 40 $event->result = call_user_func([$this, "migration$to"], $event->data); 41 } 42 } 43 44 /** 45 * Convenience function to run an INSERT ... ON CONFLICT IGNORE operation 46 * 47 * The function takes a key-value array with the column names in the key and the actual value in the value, 48 * build the appropriate query and executes it. 49 * 50 * @param string $table the table the entry should be saved to (will not be escaped) 51 * @param array $entry A simple key-value pair array (only values will be escaped) 52 * @return bool|SQLiteResult 53 */ 54 protected function insertOrIgnore(helper_plugin_sqlite $sqlite, $table, $entry) { 55 $keys = join(',', array_keys($entry)); 56 $vals = join(',', array_fill(0,count($entry),'?')); 57 58 $sql = "INSERT OR IGNORE INTO $table ($keys) VALUES ($vals)"; 59 return $sqlite->query($sql, array_values($entry)); 60 } 61 62 protected function migration5($data) 63 { 64 /** @var DokuWiki_Auth_Plugin */ 65 global $auth; 66 67 /** @var helper_plugin_sqlite $sqlite */ 68 $sqlite = $data['sqlite']; 69 $db = $sqlite->getAdapter()->getDb(); 70 71 /** @var helper_plugin_ireadit $helper */ 72 $helper = plugin_load('helper', 'ireadit'); 73 74 //remove old rows 75 $sqlite->query('DELETE FROM ireadit WHERE timestamp IS NULL'); 76 77 $res = $sqlite->query('SELECT page,meta FROM meta'); 78 while ($row = $sqlite->res_fetch_assoc($res)) { 79 $page = $row['page']; 80 $meta = json_decode($row['meta'], true); 81 $user_set = $helper->users_set($meta); 82 $last_change_date = p_get_metadata($page, 'last_change date'); 83 84 $users = $auth->retrieveUsers(); 85 foreach ($users as $user => $info) { 86 $res2 = $sqlite->query('SELECT user FROM ireadit WHERE page=? AND rev=? AND user=?', $page, $last_change_date, $user); 87 $existsAlready = $sqlite->res2single($res2); 88 if (!$existsAlready && in_array($user, $user_set)) { 89 $sqlite->storeEntry('ireadit', [ 90 'page' => $page, 91 'rev' => $last_change_date, 92 'user' => $user 93 ]); 94 } 95 } 96 } 97 } 98 99 protected function migration3($data) 100 { 101 global $conf; 102 103 /** @var helper_plugin_sqlite $sqlite */ 104 $sqlite = $data['sqlite']; 105 $db = $sqlite->getAdapter()->getDb(); 106 107 $res = $sqlite->query('SELECT page,meta FROM meta'); 108 while ($row = $sqlite->res_fetch_assoc($res)) { 109 $last_change_date = p_get_metadata($row['page'], 'last_change date'); 110 $sqlite->storeEntry('meta2', [ 111 'page' => $row['page'], 112 'meta' => $row['meta'], 113 'last_change_date' => $last_change_date 114 ]); 115 } 116 $sqlite->query('DROP TABLE meta'); 117 $sqlite->query('ALTER TABLE meta2 RENAME TO meta'); 118 } 119 120 protected function migration2($data) 121 { 122 global $conf; 123 124 /** @var helper_plugin_sqlite $sqlite */ 125 $sqlite = $data['sqlite']; 126 $db = $sqlite->getAdapter()->getDb(); 127 128 /* @var \helper_plugin_ireadit $helper */ 129 $helper = plugin_load('helper', 'ireadit'); 130 131 132 $datadir = $conf['datadir']; 133 if (substr($datadir, -1) != '/') { 134 $datadir .= '/'; 135 } 136 137 $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($datadir)); 138 $pages = []; 139 foreach ($rii as $file) { 140 if ($file->isDir()){ 141 continue; 142 } 143 144 //remove start path and extension 145 $page = substr($file->getPathname(), strlen($datadir), -4); 146 $pages[] = str_replace('/', ':', $page); 147 } 148 149 $db->beginTransaction(); 150 151 foreach ($pages as $page) { 152 //import historic data 153 $meta = p_get_metadata($page, 'plugin ireadit'); 154 if (!$meta) continue; 155 156 $sqlite->storeEntry('meta', [ 157 'page' => $page, 158 'meta' => json_encode($meta) 159 ]); 160 } 161 $db->commit(); 162 163 164 } 165 166 protected function migration1($data) 167 { 168 global $conf; 169 170 /** @var helper_plugin_sqlite $sqlite */ 171 $sqlite = $data['sqlite']; 172 $db = $sqlite->getAdapter()->getDb(); 173 174 /* @var \helper_plugin_ireadit $helper */ 175 $helper = plugin_load('helper', 'ireadit'); 176 177 178 $datadir = $conf['datadir']; 179 if (substr($datadir, -1) != '/') { 180 $datadir .= '/'; 181 } 182 183 $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($datadir)); 184 $pages = []; 185 foreach ($rii as $file) { 186 if ($file->isDir()){ 187 continue; 188 } 189 190 //remove start path and extension 191 $page = substr($file->getPathname(), strlen($datadir), -4); 192 $pages[] = str_replace('/', ':', $page); 193 } 194 $db->beginTransaction(); 195 196 foreach ($pages as $page) { 197 //import historic data 198 $meta = p_get_metadata($page, 'plugin_ireadit'); 199 if (!$meta) continue; //no metadata or new metadata format 200 201 foreach ($meta as $rev => $data) { 202 if ($rev === '' || count($data) == 0) continue; 203 foreach ($data as $user_read) { 204 $sqlite->storeEntry('ireadit', [ 205 'page' => $page, 206 'rev' => $rev, 207 'user' => $user_read['client'], 208 'timestamp' => date('c', $user_read['time']) 209 ]); 210 } 211 } 212 213 //import current data 214 $content = file_get_contents($datadir . str_replace(':', '/', $page) . '.txt'); 215 $status = preg_match('/~~IREADIT.*~~/', $content, $matches); 216 //no ireadit on page 217 if ($status !== 1) continue; 218 219 $match = trim(substr($matches[0], strlen('~~IREADIT'), -2)); 220 $splits = preg_split('/\s+/', $match, -1, PREG_SPLIT_NO_EMPTY); 221 222 $users = []; 223 $groups = []; 224 foreach ($splits as $split) { 225 if ($split[0] == '@') { 226 $group = substr($split, 1); 227 $groups[] = $group; 228 } else { 229 $users[] = $split; 230 } 231 } 232 233 $usersToInsert = $helper->users_set($users, $groups); 234 235 if ($usersToInsert) { 236 $last_change_date = p_get_metadata($page, 'last_change date'); 237 foreach ($usersToInsert as $user) { 238 $this->insertOrIgnore($sqlite,'ireadit', [ 239 'page' => $page, 240 'rev' => $last_change_date, 241 'user' => $user 242 ]); 243 } 244 } 245 246 } 247 $db->commit(); 248 249 return true; 250 } 251} 252