1<?php 2/** 3 * DokuWiki Plugin bez (Action Component) 4 * 5 */ 6 7// must be run within Dokuwiki 8 9use dokuwiki\plugin\approve\meta\ApproveConst; 10 11if (!defined('DOKU_INC')) die(); 12 13/** 14 * Class action_plugin_bez_migration 15 * 16 * Handle migrations that need more than just SQL 17 */ 18class action_plugin_approve_migration extends DokuWiki_Action_Plugin 19{ 20 /** 21 * @inheritDoc 22 */ 23 public function register(Doku_Event_Handler $controller) 24 { 25 $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'AFTER', $this, 'handle_migrations'); 26 } 27 28 /** 29 * Call our custom migrations when defined 30 * 31 * @param Doku_Event $event 32 * @param $param 33 */ 34 public function handle_migrations(Doku_Event $event, $param) 35 { 36 if ($event->data['sqlite']->getAdapter()->getDbname() !== 'approve') { 37 return; 38 } 39 $to = $event->data['to']; 40 41 if (is_callable([$this, "migration$to"])) { 42 $event->result = call_user_func([$this, "migration$to"], $event->data); 43 } 44 } 45 46 /** 47 * Convenience function to run an INSERT ... ON CONFLICT IGNORE operation 48 * 49 * The function takes a key-value array with the column names in the key and the actual value in the value, 50 * build the appropriate query and executes it. 51 * 52 * @param string $table the table the entry should be saved to (will not be escaped) 53 * @param array $entry A simple key-value pair array (only values will be escaped) 54 * @return bool|SQLiteResult 55 */ 56 protected function insertOrIgnore(helper_plugin_sqlite $sqlite, $table, $entry) { 57 $keys = join(',', array_keys($entry)); 58 $vals = join(',', array_fill(0,count($entry),'?')); 59 60 $sql = "INSERT OR IGNORE INTO $table ($keys) VALUES ($vals)"; 61 return $sqlite->query($sql, array_values($entry)); 62 } 63 64 protected function migration1($data) 65 { 66 global $conf; 67 68 /** @var helper_plugin_sqlite $sqlite */ 69 $sqlite = $data['sqlite']; 70 $db = $sqlite->getAdapter()->getDb(); 71 72 73 $datadir = $conf['datadir']; 74 if (substr($datadir, -1) != '/') { 75 $datadir .= '/'; 76 } 77 78 $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($datadir)); 79 $pages = []; 80 foreach ($rii as $file) { 81 if ($file->isDir()){ 82 continue; 83 } 84 85 //remove start path and extension 86 $page = substr($file->getPathname(), strlen($datadir), -4); 87 $pages[] = str_replace('/', ':', $page); 88 } 89 90 $db->beginTransaction(); 91 92 $apr_namespaces = preg_split('/\s+/', $this->getConf('apr_namespaces'), 93 -1,PREG_SPLIT_NO_EMPTY); 94 95 if (!$apr_namespaces) { 96 $sqlite->storeEntry('maintainer',[ 97 'namespace' => '**' 98 ]); 99 } else { 100 foreach ($apr_namespaces as $namespace) { 101 $namespace = rtrim($namespace, ':'); 102 $namespace .= ':**'; 103 $sqlite->storeEntry('maintainer',[ 104 'namespace' => $namespace 105 ]); 106 } 107 } 108 109 //store config 110 $no_apr_namespaces = $this->getConf('no_apr_namespaces'); 111 $sqlite->storeEntry('config',[ 112 'key' => 'no_apr_namespaces', 113 'value' => $no_apr_namespaces 114 ]); 115 116 $no_apr_namespaces_list = preg_split('/\s+/', $no_apr_namespaces,-1, 117 PREG_SPLIT_NO_EMPTY); 118 $no_apr_namespaces_list = array_map(function ($namespace) { 119 return trim($namespace, ':'); 120 }, $no_apr_namespaces_list); 121 122 foreach ($pages as $page) { 123 //import historic data 124 $versions = p_get_metadata($page, ApproveConst::METADATA_VERSIONS_KEY); 125 if (!$versions) { 126 $versions = $this->render_metadata_for_approved_page($page); 127 } 128 129// $last_change_date = p_get_metadata($page, 'last_change date'); 130 $last_change_date = @filemtime(wikiFN($page)); 131 $last_version = $versions[0]; 132 133 //remove current versions to not process it here 134 unset($versions[0]); 135 unset($versions[$last_change_date]); 136 137 foreach ($versions as $rev => $version) { 138 $data = [ 139 'page' => $page, 140 'rev' => $rev, 141 'approved' => date('c', $rev), 142 'version' => $version 143 ]; 144 $sqlite->storeEntry('revision', $data); 145 } 146 147 //process current data 148 $summary = p_get_metadata($page, 'last_change sum'); 149 $data = [ 150 'page' => $page, 151 'rev' => $last_change_date, 152 'current' => 1 153 ]; 154 if ($this->getConf('ready_for_approval') && 155 $summary == $this->getConf('sum ready for approval')) { 156 $data['ready_for_approval'] = date('c', $last_change_date); 157 } elseif($summary == $this->getConf('sum approved')) { 158 $data['approved'] = date('c', $last_change_date); 159 $data['version'] = $last_version; 160 } 161 $sqlite->storeEntry('revision', $data); 162 163 164 //empty apr_namespaces - all match 165 if (!$apr_namespaces) { 166 $in_apr_namespace = true; 167 } else { 168 $in_apr_namespace = false; 169 foreach ($apr_namespaces as $namespace) { 170 if (substr($page, 0, strlen($namespace)) == $namespace) { 171 $in_apr_namespace = true; 172 break; 173 } 174 } 175 } 176 177 if ($in_apr_namespace) { 178 $hidden = '0'; 179 foreach ($no_apr_namespaces_list as $namespace) { 180 if (substr($page, 0, strlen($namespace)) == $namespace) { 181 $hidden = '1'; 182 break; 183 } 184 } 185 $sqlite->storeEntry('page', [ 186 'page' => $page, 187 'hidden' => $hidden 188 ]); 189 } 190 } 191 192 193 $db->commit(); 194 195 return true; 196 } 197 198 /** 199 * Calculate current version 200 * 201 * @param $id 202 * @return array 203 */ 204 protected function render_metadata_for_approved_page($id, $currev=false) { 205 if (!$currev) $currev = @filemtime(wikiFN($id)); 206 207 $version = $this->approved($id); 208 //version for current page 209 $curver = $version + 1; 210 $versions = array(0 => $curver, $currev => $curver); 211 212 $changelog = new PageChangeLog($id); 213 $first = 0; 214 $num = 100; 215 while (count($revs = $changelog->getRevisions($first, $num)) > 0) { 216 foreach ($revs as $rev) { 217 $revInfo = $changelog->getRevisionInfo($rev); 218 if ($revInfo['sum'] == $this->getConf('sum approved')) { 219 $versions[$rev] = $version; 220 $version -= 1; 221 } 222 } 223 $first += $num; 224 } 225 226// p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions)); 227 228 return $versions; 229 } 230 231 /** 232 * Get the number of approved pages 233 * @param $id 234 * @return int 235 */ 236 protected function approved($id) { 237 $count = 0; 238 239 $changelog = new PageChangeLog($id); 240 $first = 0; 241 $num = 100; 242 while (count($revs = $changelog->getRevisions($first, $num)) > 0) { 243 foreach ($revs as $rev) { 244 $revInfo = $changelog->getRevisionInfo($rev); 245 if ($revInfo['sum'] == $this->getConf('sum approved')) { 246 $count += 1; 247 } 248 } 249 $first += $num; 250 } 251 252 return $count; 253 } 254} 255