register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_diff_accept'); $controller->register_hook('HTML_SHOWREV_OUTPUT', 'BEFORE', $this, 'handle_showrev'); $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_approve'); $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_mark_ready_for_approval'); $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_viewer'); $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, 'handle_display_banner'); $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handle_pagesave_after'); } /** * @param Doku_Event $event */ public function handle_diff_accept(Doku_Event $event) { global $INFO; try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); if (!$helper->use_approve_here($sqlite, $INFO['id'])) return; if ($event->data == 'diff' && isset($_GET['approve'])) { $href = wl($INFO['id'], ['approve' => 'approve']); ptln(''.$this->getLang('approve').''); } if ($this->getConf('ready_for_approval') && $event->data == 'diff' && isset($_GET['ready_for_approval'])) { $href = wl($INFO['id'], ['ready_for_approval' => 'ready_for_approval']); ptln(''.$this->getLang('approve_ready').''); } } /** * @param Doku_Event $event */ public function handle_showrev(Doku_Event $event) { global $INFO; try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); if (!$helper->use_approve_here($sqlite, $INFO['id'])) return; $last_approved_rev = $helper->find_last_approved($sqlite, $INFO['id']); if ($last_approved_rev == $INFO['rev']) { $event->preventDefault(); } } /** * @param Doku_Event $event */ public function handle_approve(Doku_Event $event) { global $INFO; try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); if ($event->data != 'show') return; if (!isset($_GET['approve'])) return; if (!$helper->use_approve_here($sqlite, $INFO['id'], $approver)) return; if (!$helper->client_can_approve($INFO['id'], $approver)) return; $res = $sqlite->query('SELECT MAX(version)+1 FROM revision WHERE page=?', $INFO['id']); $next_version = $sqlite->res2single($res); if (!$next_version) { $next_version = 1; } //approved IS NULL prevents from overriding already approved page $sqlite->query('UPDATE revision SET approved=?, approved_by=?, version=? WHERE page=? AND current=1 AND approved IS NULL', date('c'), $INFO['client'], $next_version, $INFO['id']); header('Location: ' . wl($INFO['id'])); } /** * @param Doku_Event $event */ public function handle_mark_ready_for_approval(Doku_Event $event) { global $INFO; try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); if ($event->data != 'show') return; if (!isset($_GET['ready_for_approval'])) return; if (!$helper->use_approve_here($sqlite, $INFO['id'])) return; if (!$helper->client_can_mark_ready_for_approval($INFO['id'])) return; $sqlite->query('UPDATE revision SET ready_for_approval=?, ready_for_approval_by=? WHERE page=? AND current=1 AND ready_for_approval IS NULL', date('c'), $INFO['client'], $INFO['id']); header('Location: ' . wl($INFO['id'])); } /** * Redirect to newest approved page for user that don't have EDIT permission. * * @param Doku_Event $event */ public function handle_viewer(Doku_Event $event) { global $INFO; try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); if ($event->data != 'show') return; //apply only to current page if ($INFO['rev'] != 0) return; if (!$helper->use_approve_here($sqlite, $INFO['id'], $approver)) return; if ($helper->client_can_see_drafts($INFO['id'], $approver)) return; $last_approved_rev = $helper->find_last_approved($sqlite, $INFO['id']); //no page is approved if (!$last_approved_rev) return; $last_change_date = @filemtime(wikiFN($INFO['id'])); //current page is approved if ($last_approved_rev == $last_change_date) return; header("Location: " . wl($INFO['id'], ['rev' => $last_approved_rev], false, '&')); } /** * @param Doku_Event $event */ public function handle_display_banner(Doku_Event $event) { global $INFO, $ID; /* Return true if banner should not be displayed for users with or below read only permission. */ if (auth_quickaclcheck($ID) <= AUTH_READ && !$this->getConf('display_banner_for_readonly')) { return true; } /* Not returned - rendering the banner */ try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); if ($event->data != 'show') return; if (!$INFO['exists']) return; if (!$helper->use_approve_here($sqlite, $INFO['id'], $approver)) return; // $last_change_date = p_get_metadata($INFO['id'], 'last_change date'); $last_change_date = @filemtime(wikiFN($INFO['id'])); $rev = !$INFO['rev'] ? $last_change_date : $INFO['rev']; $res = $sqlite->query('SELECT ready_for_approval, ready_for_approval_by, approved, approved_by, version FROM revision WHERE page=? AND rev=?', $INFO['id'], $rev); $approve = $sqlite->res_fetch_assoc($res); $last_approved_rev = $helper->find_last_approved($sqlite, $INFO['id']); $classes = []; if ($this->getConf('prettyprint')) { $classes[] = 'plugin__approve_noprint'; } if ($approve['approved'] && $rev == $last_approved_rev) { $classes[] = 'plugin__approve_approved'; } elseif ($approve['approved']) { $classes[] = 'plugin__approve_old_approved'; } elseif ($this->getConf('ready_for_approval') && $approve['ready_for_approval']) { $classes[] = 'plugin__approve_ready'; } else { $classes[] = 'plugin__approve_draft'; } ptln('
'); // tpl_pageinfo(); // ptln(' | '); if ($approve['approved']) { ptln(''.$this->getLang('approved').''); ptln(' ' . dformat(strtotime($approve['approved']))); if($this->getConf('banner_long')) { ptln(' ' . $this->getLang('by') . ' ' . userlink($approve['approved_by'], true)); ptln(' (' . $this->getLang('version') . ': ' . $approve['version'] . ')'); } //not the newest page if ($rev != $last_change_date) { $res = $sqlite->query('SELECT rev, current FROM revision WHERE page=? AND approved IS NOT NULL ORDER BY rev DESC LIMIT 1', $INFO['id']); $last_approve = $sqlite->res_fetch_assoc($res); //we can see drafts if ($helper->client_can_see_drafts($INFO['id'], $approver)) { ptln(''); ptln($this->getLang($last_approve['current'] ? 'newest_approved' : 'newest_draft')); ptln(''); //we cannot see link to draft but there is some newer approved version } elseif ($last_approve['rev'] != $rev) { $urlParameters = []; if (!$last_approve['current']) { $urlParameters['rev'] = $last_approve['rev']; } ptln(''); ptln($this->getLang('newest_approved')); ptln(''); } } } else { if ($this->getConf('ready_for_approval') && $approve['ready_for_approval']) { ptln(''.$this->getLang('marked_approve_ready').''); ptln(' ' . dformat(strtotime($approve['ready_for_approval']))); ptln(' ' . $this->getLang('by') . ' ' . userlink($approve['ready_for_approval_by'], true)); } else { ptln(''.$this->getLang('draft').''); } $res = $sqlite->query('SELECT rev, current FROM revision WHERE page=? AND approved IS NOT NULL ORDER BY rev DESC LIMIT 1', $INFO['id']); $last_approve = $sqlite->res_fetch_assoc($res); //not exists approve for current page if (!$last_approve) { //not the newest page if ($rev != $last_change_date) { ptln(''); ptln($this->getLang('newest_draft')); ptln(''); } } else { $urlParameters = []; if (!$last_approve['current']) { $urlParameters['rev'] = $last_approve['rev']; } ptln(''); ptln($this->getLang('newest_approved')); ptln(''); } //we are in current page if ($rev == $last_change_date) { //compare with the last approved page or 0 if there is no approved versions $last_approved_rev = 0; if (isset($last_approve['rev'])) { $last_approved_rev = $last_approve['rev']; } if ($this->getConf('ready_for_approval') && $helper->client_can_mark_ready_for_approval($INFO['id']) && !$approve['ready_for_approval']) { $urlParameters = [ 'rev' => $last_approved_rev, 'do' => 'diff', 'ready_for_approval' => 'ready_for_approval' ]; ptln(' | '); ptln($this->getLang('approve_ready')); ptln(''); } if ($helper->client_can_approve($INFO['id'], $approver)) { $urlParameters = [ 'rev' => $last_approved_rev, 'do' => 'diff', 'approve' => 'approve' ]; ptln(' | '); ptln($this->getLang('approve')); ptln(''); } } } if ($approver && $this->getConf('banner_long')) { ptln(' | ' . $this->getLang('approver') . ': ' . userlink($approver, true)); } ptln('
'); } /** * @return bool|string|void */ protected function lastRevisionHasntApprovalData($id) { try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } $res = $sqlite->query('SELECT rev FROM revision WHERE page=? AND current=1 AND approved IS NULL AND ready_for_approval IS NULL', $id); return $sqlite->res2single($res); } /** * * @param Doku_Event $event event object by reference * @return void */ public function handle_pagesave_after(Doku_Event $event) { try { /** @var \helper_plugin_approve_db $db_helper */ $db_helper = plugin_load('helper', 'approve_db'); $sqlite = $db_helper->getDB(); } catch (Exception $e) { msg($e->getMessage(), -1); return; } /** @var helper_plugin_approve $helper */ $helper = plugin_load('helper', 'approve'); //no content was changed if (!$event->data['contentChanged']) return; $changeType = $event->data['changeType']; if ($changeType == DOKU_CHANGE_TYPE_REVERT) { if ($event->data['oldContent'] == '') { $changeType = DOKU_CHANGE_TYPE_CREATE; } else { $changeType = DOKU_CHANGE_TYPE_EDIT; } } $id = $event->data['id']; switch ($changeType) { case DOKU_CHANGE_TYPE_EDIT: case DOKU_CHANGE_TYPE_REVERT: case DOKU_CHANGE_TYPE_MINOR_EDIT: $last_change_date = $event->data['newRevision']; //if the current page has approved or ready_for_approval -- keep it $rev = $this->lastRevisionHasntApprovalData($id); if ($rev) { $sqlite->query('UPDATE revision SET rev=? WHERE page=? AND rev=?', $last_change_date, $id, $rev); } else { //keep previous record $sqlite->query('UPDATE revision SET current=0 WHERE page=? AND current=1', $id); $sqlite->storeEntry('revision', [ 'page' => $id, 'rev' => $last_change_date, 'current' => 1 ]); } break; case DOKU_CHANGE_TYPE_DELETE: //delete information about availability of a page but keep the history $sqlite->query('DELETE FROM page WHERE page=?', $id); //delete revision if no information about approvals $rev = $this->lastRevisionHasntApprovalData($id); if ($rev) { $sqlite->query('DELETE FROM revision WHERE page=? AND rev=?', $id, $rev); } else { $sqlite->query('UPDATE revision SET current=0 WHERE page=? AND current=1', $id); } break; case DOKU_CHANGE_TYPE_CREATE: if ($helper->isPageAssigned($sqlite, $id, $newApprover)) { $data = [ 'page' => $id, 'hidden' => $helper->in_hidden_namespace($sqlite, $id) ? '1' : '0' ]; if (!blank($newApprover)) { $data['approver'] = $newApprover; } $sqlite->storeEntry('page', $data); } //store revision $last_change_date = $event->data['newRevision']; $sqlite->storeEntry('revision', [ 'page' => $id, 'rev' => $last_change_date, 'current' => 1 ]); break; } } }