1<?php 2 3// must be run within Dokuwiki 4if (!defined('DOKU_INC')) die(); 5class helper_plugin_approve extends DokuWiki_Plugin { 6 7 /** 8 * @param helper_plugin_sqlite $sqlite 9 * @return string 10 */ 11 public function no_apr_namespace(helper_plugin_sqlite $sqlite) { 12 //check for config update 13 $key = 'no_apr_namespaces'; 14 $res = $sqlite->query('SELECT value FROM config WHERE key=?', $key); 15 $no_apr_namespaces_db = $sqlite->res2single($res); 16 $no_apr_namespaces_conf = $this->getConf($key); 17 //update internal config 18 if ($no_apr_namespaces_db != $no_apr_namespaces_conf) { 19 $sqlite->query('UPDATE config SET value=? WHERE key=?', $no_apr_namespaces_conf, $key); 20 21 $res = $sqlite->query('SELECT page, hidden FROM page'); 22 $pages = $sqlite->res2arr($res); 23 foreach ($pages as $page) { 24 $id = $page['page']; 25 $hidden = $page['hidden']; 26 $in_hidden_namespace = $this->in_hidden_namespace($sqlite, $id, $no_apr_namespaces_conf); 27 $new_hidden = $in_hidden_namespace ? '1' : '0'; 28 29 if ($hidden != $new_hidden) { 30 $sqlite->query('UPDATE page SET hidden=? WHERE page=?', $new_hidden, $id); 31 } 32 } 33 } 34 35 return $no_apr_namespaces_conf; 36 } 37 38 /** 39 * @param helper_plugin_sqlite $sqlite 40 * @param $id 41 * @param null $approver 42 * @return bool 43 */ 44 public function use_approve_here(helper_plugin_sqlite $sqlite, $id, &$approver=null) { 45 46 //check if we should update no_apr_namespace 47 $this->no_apr_namespace($sqlite); 48 49 $res = $sqlite->query('SELECT page, approver FROM page WHERE page=? AND hidden=0', $id); 50 $row = $sqlite->res2row($res); 51 $approver = $row['approver']; 52 if ($row) { 53 return true; 54 } 55 return false; 56 } 57 58 /** 59 * @param helper_plugin_sqlite $sqlite 60 * @param $id 61 * @return bool|string 62 */ 63 public function find_last_approved(helper_plugin_sqlite $sqlite, $id) { 64 $res = $sqlite->query('SELECT rev FROM revision 65 WHERE page=? AND approved IS NOT NULL 66 ORDER BY rev DESC LIMIT 1', $id); 67 return $sqlite->res2single($res); 68 } 69 70 /** 71 * @param helper_plugin_sqlite $sqlite 72 * @param null $no_apr_namespaces 73 * @return array|array[]|false|string[] 74 */ 75 public function get_hidden_namespaces_list(helper_plugin_sqlite $sqlite, $no_apr_namespaces=null) { 76 if (!$no_apr_namespaces) { 77 $no_apr_namespaces = $this->no_apr_namespace($sqlite); 78 } 79 80 $no_apr_namespaces_list = preg_split('/\s+/', $no_apr_namespaces,-1, 81 PREG_SPLIT_NO_EMPTY); 82 $no_apr_namespaces_list = array_map(function ($namespace) { 83 return ltrim($namespace, ':'); 84 }, $no_apr_namespaces_list); 85 86 return $no_apr_namespaces_list; 87 } 88 89 /** 90 * @param helper_plugin_sqlite $sqlite 91 * @param $id 92 * @param null $no_apr_namespaces 93 * @return bool|string 94 */ 95 public function in_hidden_namespace(helper_plugin_sqlite $sqlite, $id, $no_apr_namespaces=null) { 96 $no_apr_namespaces_list = $this->get_hidden_namespaces_list($sqlite, $no_apr_namespaces); 97 $id = ltrim($id, ':'); 98 foreach ($no_apr_namespaces_list as $namespace) { 99 if (substr($id, 0, strlen($namespace)) == $namespace) { 100 return true; 101 } 102 } 103 return false; 104 } 105 106 /** 107 * @param helper_plugin_sqlite $sqlite 108 * @return array 109 */ 110 public function weighted_assignments(helper_plugin_sqlite $sqlite) { 111 $res = $sqlite->query('SELECT id,namespace,approver FROM maintainer'); 112 $assignments = $sqlite->res2arr($res); 113 114 $weighted_assignments = []; 115 foreach ($assignments as $assignment) { 116 $ns = $assignment['namespace']; 117 //more general namespaces are overridden by more specific ones. 118 if (substr($ns, -1) == '*') { 119 $weight = substr_count($ns, ':'); 120 } else { 121 $weight = PHP_INT_MAX; 122 } 123 124 $assignment['weight'] = $weight; 125 $weighted_assignments[] = $assignment; 126 } 127 array_multisort(array_column($weighted_assignments, 'weight'), $weighted_assignments); 128 129 return $weighted_assignments; 130 } 131 132 /** 133 * @param helper_plugin_sqlite $sqlite 134 * @param $id 135 * @param null $pageApprover 136 * @param null $weighted_assignments 137 * @return bool 138 */ 139 public function isPageAssigned(helper_plugin_sqlite $sqlite, $id, &$pageApprover=null, $weighted_assignments=null) { 140 if (!$weighted_assignments) { 141 $weighted_assignments = $this->weighted_assignments($sqlite); 142 } 143 foreach ($weighted_assignments as $assignment) { 144 $ns = ltrim($assignment['namespace'], ':'); 145 $approver = $assignment['approver']; 146 if (substr($ns, -2) == '**') { 147 //remove '**' 148 $ns = substr($ns, 0, -2); 149 if (substr($id, 0, strlen($ns)) == $ns) { 150 $newAssignment = true; 151 $pageApprover = $approver; 152 } 153 } elseif (substr($ns, -1) == '*') { 154 //remove '*' 155 $ns = substr($ns, 0, -1); 156 $noNS = substr($id, strlen($id)); 157 if (strpos($noNS, ':') === FALSE && 158 substr($id, 0, strlen($ns)) == $ns) { 159 $newAssignment = true; 160 $pageApprover = $approver; 161 } 162 } elseif($id == $ns) { 163 $newAssignment = true; 164 $pageApprover = $approver; 165 } 166 } 167 return $newAssignment; 168 } 169 170 /** 171 * @param string $approver 172 * @return bool 173 */ 174 public function isGroup($approver) { 175 if (!$approver) return false; 176 if (strncmp($approver, "@", 1) === 0) return true; 177 return false; 178 } 179 180 /** 181 * @param $userinfo 182 * @param string $group 183 * @return bool 184 */ 185 public function isInGroup($userinfo, $group) { 186 $groupname = substr($group, 1); 187 if (in_array($groupname, $userinfo['grps'])) return true; 188 return false; 189 } 190 191 /** 192 * @param $id 193 * @param string $pageApprover 194 * @return bool 195 */ 196 public function client_can_approve($id, $pageApprover) { 197 global $INFO; 198 //user not log in 199 if (!isset($INFO['userinfo'])) return false; 200 201 if ($pageApprover == $INFO['client']) { 202 return true; 203 } elseif ($this->isGroup($pageApprover) && $this->isInGroup($INFO['userinfo'], $pageApprover)) { 204 return true; 205 //no approver provided, check if approve plugin apply here 206 } elseif (auth_quickaclcheck($id) >= AUTH_DELETE && 207 (!$pageApprover || !$this->getConf('strict_approver'))) { 208 return true; 209 } 210 211 return false; 212 } 213 214 /** 215 * @param $id 216 * @return bool 217 */ 218 public function client_can_mark_ready_for_approval($id) { 219 return auth_quickaclcheck($id) >= AUTH_EDIT; 220 } 221 222 /** 223 * @param $id 224 * @return bool 225 */ 226 public function client_can_see_drafts($id, $pageApprover) { 227 if (!$this->getConf('hide_drafts_for_viewers')) return true; 228 229 if (auth_quickaclcheck($id) >= AUTH_EDIT) return true; 230 if ($this->client_can_approve($id, $pageApprover)) return true; 231 232 return false; 233 } 234 235 /** 236 * Get the array of all pages ids in wiki 237 * 238 * @return array 239 */ 240 public function getPages() { 241 global $conf; 242 243 $datadir = realpath($conf['datadir']); // path without ending "/" 244 $directory = new RecursiveDirectoryIterator($datadir, FilesystemIterator::SKIP_DOTS); 245 $iterator = new RecursiveIteratorIterator($directory); 246 247 $pages = []; 248 /** @var SplFileInfo $fileinfo */ 249 foreach ($iterator as $fileinfo) { 250 if (!$fileinfo->isFile()) continue; 251 252 $path = $fileinfo->getRealPath(); // it should return "/" both on windows and linux 253 //remove dir part 254 $path = substr($path, strlen($datadir)); 255 //make file a dokuwiki path 256 $id = $this->pathID($path); 257 $pages[] = $id; 258 } 259 260 return $pages; 261 } 262 263 /** 264 * translates a document path to an ID 265 * 266 * fixes dokuwiki pathID - support for Windows enviroment 267 * 268 * @param string $path 269 * @param bool $keeptxt 270 * 271 * @return mixed|string 272 */ 273 public function pathID($path,$keeptxt=false){ 274 $id = utf8_decodeFN($path); 275 $id = str_replace(DIRECTORY_SEPARATOR,':',$id); 276 if(!$keeptxt) $id = preg_replace('#\.txt$#','',$id); 277 $id = trim($id, ':'); 278 return $id; 279 } 280} 281