query('SELECT value FROM config WHERE key=?', $key); $no_apr_namespaces_db = $sqlite->res2single($res); $no_apr_namespaces_conf = $this->getConf($key); //update internal config if ($no_apr_namespaces_db != $no_apr_namespaces_conf) { $sqlite->query('UPDATE config SET value=? WHERE key=?', $no_apr_namespaces_conf, $key); $res = $sqlite->query('SELECT page, hidden FROM page'); $pages = $sqlite->res2arr($res); foreach ($pages as $page) { $id = $page['page']; $hidden = $page['hidden']; $in_hidden_namespace = $this->in_hidden_namespace($sqlite, $id, $no_apr_namespaces_conf); $new_hidden = $in_hidden_namespace ? '1' : '0'; if ($hidden != $new_hidden) { $sqlite->query('UPDATE page SET hidden=? WHERE page=?', $new_hidden, $id); } } } return $no_apr_namespaces_conf; } /** * @param helper_plugin_sqlite $sqlite * @param $id * @param null $approver * @return bool */ public function use_approve_here(helper_plugin_sqlite $sqlite, $id, &$approver=null) { //check if we should update no_apr_namespace $this->no_apr_namespace($sqlite); $res = $sqlite->query('SELECT page, approver FROM page WHERE page=? AND hidden=0', $id); $row = $sqlite->res2row($res); if ($row) { $approver = $row['approver']; return true; } return false; } /** * @param helper_plugin_sqlite $sqlite * @param $id * @return bool|string */ public function find_last_approved(helper_plugin_sqlite $sqlite, $id) { $res = $sqlite->query('SELECT rev FROM revision WHERE page=? AND approved IS NOT NULL ORDER BY rev DESC LIMIT 1', $id); return $sqlite->res2single($res); } /** * @param helper_plugin_sqlite $sqlite * @param null $no_apr_namespaces * @return array|array[]|false|string[] */ public function get_hidden_namespaces_list(helper_plugin_sqlite $sqlite, $no_apr_namespaces=null) { if (!$no_apr_namespaces) { $no_apr_namespaces = $this->no_apr_namespace($sqlite); } $no_apr_namespaces_list = preg_split('/\s+/', $no_apr_namespaces,-1, PREG_SPLIT_NO_EMPTY); $no_apr_namespaces_list = array_map(function ($namespace) { return ltrim($namespace, ':'); }, $no_apr_namespaces_list); return $no_apr_namespaces_list; } /** * @param helper_plugin_sqlite $sqlite * @param $id * @param null $no_apr_namespaces * @return bool|string */ public function in_hidden_namespace(helper_plugin_sqlite $sqlite, $id, $no_apr_namespaces=null) { $no_apr_namespaces_list = $this->get_hidden_namespaces_list($sqlite, $no_apr_namespaces); $id = ltrim($id, ':'); foreach ($no_apr_namespaces_list as $namespace) { if (substr($id, 0, strlen($namespace)) == $namespace) { return true; } } return false; } /** * @param helper_plugin_sqlite $sqlite * @return array */ public function weighted_assignments(helper_plugin_sqlite $sqlite) { $res = $sqlite->query('SELECT id,namespace,approver FROM maintainer'); $assignments = $sqlite->res2arr($res); $weighted_assignments = []; foreach ($assignments as $assignment) { $ns = $assignment['namespace']; //more general namespaces are overridden by more specific ones. if (substr($ns, -1) == '*') { $weight = substr_count($ns, ':'); } else { $weight = PHP_INT_MAX; } $assignment['weight'] = $weight; $weighted_assignments[] = $assignment; } array_multisort(array_column($weighted_assignments, 'weight'), $weighted_assignments); return $weighted_assignments; } /** * @param helper_plugin_sqlite $sqlite * @param $id * @param null $pageApprover * @param null $weighted_assignments * @return bool */ public function isPageAssigned(helper_plugin_sqlite $sqlite, $id, &$pageApprover=null, $weighted_assignments=null) { if (!$weighted_assignments) { $weighted_assignments = $this->weighted_assignments($sqlite); } foreach ($weighted_assignments as $assignment) { $ns = ltrim($assignment['namespace'], ':'); $approver = $assignment['approver']; if (substr($ns, -2) == '**') { //remove '**' $ns = substr($ns, 0, -2); if (substr($id, 0, strlen($ns)) == $ns) { $newAssignment = true; $pageApprover = $approver; } } elseif (substr($ns, -1) == '*') { //remove '*' $ns = substr($ns, 0, -1); $noNS = substr($id, strlen($ns)); if (strpos($noNS, ':') === FALSE && substr($id, 0, strlen($ns)) == $ns) { $newAssignment = true; $pageApprover = $approver; } } elseif($id == $ns) { $newAssignment = true; $pageApprover = $approver; } } return $newAssignment; } /** * @param helper_plugin_sqlite $sqlite */ public function updatePagesAssignments(helper_plugin_sqlite $sqlite) { //clean current settings $sqlite->query('DELETE FROM page'); $wikiPages = $this->getPages(); $no_apr_namespace = $this->no_apr_namespace($sqlite); $weighted_assignments = $this->weighted_assignments($sqlite); foreach ($wikiPages as $id) { if ($this->isPageAssigned($sqlite, $id, $approver, $weighted_assignments)) { $data = [ 'page' => $id, 'hidden' => $this->in_hidden_namespace($sqlite, $id, $no_apr_namespace) ? '1' : '0' ]; if (!blank($approver)) { $data['approver'] = $approver; } $sqlite->storeEntry('page', $data); } } } /** * @param string $approver * @return bool */ public function isGroup($approver) { if (!$approver) return false; if (strncmp($approver, "@", 1) === 0) return true; return false; } /** * @param $userinfo * @param string $group * @return bool */ public function isInGroup($userinfo, $group) { $groupname = substr($group, 1); if (in_array($groupname, $userinfo['grps'])) return true; return false; } /** * @param $id * @param string $pageApprover * @return bool */ public function client_can_approve($id, $pageApprover) { global $INFO; //user not log in if (!isset($INFO['userinfo'])) return false; if ($pageApprover == $INFO['client']) { return true; } elseif ($this->isGroup($pageApprover) && $this->isInGroup($INFO['userinfo'], $pageApprover)) { return true; //no approver provided, check if approve plugin apply here } elseif (auth_quickaclcheck($id) >= AUTH_DELETE && (!$pageApprover || !$this->getConf('strict_approver'))) { return true; } return false; } /** * @param $id * @return bool */ public function client_can_mark_ready_for_approval($id) { global $INFO; $ready_for_approval_acl = preg_split('/\s+/', $this->getConf('ready_for_approval_acl'), -1, PREG_SPLIT_NO_EMPTY); if (count($ready_for_approval_acl) == 0) return auth_quickaclcheck($id) >= AUTH_EDIT; // empty foreach ($ready_for_approval_acl as $user_or_group) { if ($user_or_group[0] == '@' && $this->isInGroup($INFO['userinfo'], $user_or_group)) { return true; } elseif ($user_or_group == $INFO['client']) { return true; } } return false; } /** * @param $id * @return bool */ public function client_can_see_drafts($id, $pageApprover) { // in view mode no one can see drafts if ($this->getConf('viewmode') && get_doku_pref('approve_viewmode', false)) return false; if (!$this->getConf('hide_drafts_for_viewers')) return true; if (auth_quickaclcheck($id) >= AUTH_EDIT) return true; if ($this->client_can_approve($id, $pageApprover)) return true; return false; } /** * Get the array of all pages ids in wiki * * @return array */ public function getPages() { global $conf; $datadir = realpath($conf['datadir']); // path without ending "/" $directory = new RecursiveDirectoryIterator($datadir, FilesystemIterator::SKIP_DOTS); $iterator = new RecursiveIteratorIterator($directory); $pages = []; /** @var SplFileInfo $fileinfo */ foreach ($iterator as $fileinfo) { if (!$fileinfo->isFile()) continue; $path = $fileinfo->getRealPath(); // it should return "/" both on windows and linux //remove dir part $path = substr($path, strlen($datadir)); //make file a dokuwiki path $id = $this->pathID($path); $pages[] = $id; } return $pages; } /** * translates a document path to an ID * * fixes dokuwiki pathID - support for Windows enviroment * * @param string $path * @param bool $keeptxt * * @return mixed|string */ public function pathID($path,$keeptxt=false){ $id = utf8_decodeFN($path); $id = str_replace(DIRECTORY_SEPARATOR,':',$id); if(!$keeptxt) $id = preg_replace('#\.txt$#','',$id); $id = trim($id, ':'); return $id; } }