1<?php 2 3/** 4 * DokuWiki Plugin acknowledge (Action Component) 5 * 6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7 * @author Andreas Gohr, Anna Dabrowska <dokuwiki@cosmocode.de> 8 */ 9 10use dokuwiki\Extension\ActionPlugin; 11use dokuwiki\Extension\EventHandler; 12use dokuwiki\Extension\Event; 13use dokuwiki\Form\Form; 14 15class action_plugin_acknowledge extends ActionPlugin 16{ 17 /** @inheritDoc */ 18 public function register(EventHandler $controller) 19 { 20 $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handlePageSave'); 21 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxAcknowledge'); 22 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxAutocomplete'); 23 $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'AFTER', $this, 'handleUpgrade'); 24 } 25 26 /** 27 * Manage page meta data 28 * 29 * Store page last modified date 30 * Handle page deletions 31 * Handle page creations 32 * 33 * @param Event $event 34 * @param $param 35 */ 36 public function handlePageSave(Event $event, $param) 37 { 38 /** @var helper_plugin_acknowledge $helper */ 39 $helper = plugin_load('helper', 'acknowledge'); 40 41 if ($event->data['changeType'] === DOKU_CHANGE_TYPE_DELETE) { 42 $helper->removePage($event->data['id']); // this cascades to assignments 43 } elseif ($event->data['changeType'] !== DOKU_CHANGE_TYPE_MINOR_EDIT) { 44 $helper->storePageDate($event->data['id'], $event->data['newRevision'], $event->data['newContent']); 45 } 46 47 // Remove page assignees here because the syntax might have been removed 48 // they are readded on metadata rendering if still there 49 $helper->clearPageAssignments($event->data['id']); 50 51 if ($event->data['changeType'] === DOKU_CHANGE_TYPE_CREATE) { 52 // new pages need to have their auto assignments updated based on the existing patterns 53 $helper->setAutoAssignees($event->data['id']); 54 } 55 } 56 57 /** 58 * @param Event $event 59 * @param $param 60 */ 61 public function handleAjaxAcknowledge(Event $event, $param) 62 { 63 if ($event->data === 'plugin_acknowledge_acknowledge') { 64 $event->stopPropagation(); 65 $event->preventDefault(); 66 67 global $INPUT; 68 $id = $INPUT->str('id'); 69 70 if (page_exists($id)) { 71 echo $this->html(); 72 } 73 } 74 } 75 76 /** 77 * @param Event $event 78 * @return void 79 */ 80 public function handleAjaxAutocomplete(Event $event) 81 { 82 if ($event->data === 'plugin_acknowledge_autocomplete') { 83 if (!checkSecurityToken()) return; 84 85 global $INPUT; 86 87 $event->stopPropagation(); 88 $event->preventDefault(); 89 90 /** @var helper_plugin_acknowledge $hlp */ 91 $hlp = $this->loadHelper('acknowledge'); 92 93 $found = []; 94 95 if ($INPUT->has('user')) { 96 $search = $INPUT->str('user'); 97 $knownUsers = $hlp->getUsers(); 98 $found = array_filter($knownUsers, function ($user) use ($search) { 99 return (strstr(strtolower($user['label']), strtolower($search))) !== false ? $user : null; 100 }); 101 } 102 103 if ($INPUT->has('pg')) { 104 $search = $INPUT->str('pg'); 105 $pages = ft_pageLookup($search, true); 106 $found = array_map(function ($id, $title) { 107 return ['value' => $id, 'label' => $title ?? $id]; 108 }, array_keys($pages), array_values($pages)); 109 } 110 111 header('Content-Type: application/json'); 112 113 echo json_encode($found); 114 } 115 } 116 117 /** 118 * Handle Migration events 119 * 120 * @param Event $event 121 * @param $param 122 * @return void 123 */ 124 public function handleUpgrade(Event $event, $param) 125 { 126 if ($event->data['sqlite']->getAdapter()->getDbname() !== 'acknowledgement') { 127 return; 128 } 129 $to = $event->data['to']; 130 if ($to !== 3) return; // only handle upgrade to version 3 131 132 /** @var helper_plugin_acknowledge $helper */ 133 $helper = plugin_load('helper', 'acknowledge'); 134 $helper->updatePageIndex(); 135 } 136 137 /** 138 * Returns the acknowledgment form/confirmation 139 * 140 * @return string The HTML to display 141 */ 142 protected function html() 143 { 144 global $INPUT; 145 global $USERINFO; 146 $id = $INPUT->str('id'); 147 $ackSubmitted = $INPUT->bool('ack'); 148 $user = $INPUT->server->str('REMOTE_USER'); 149 if ($id === '' || $user === '') return ''; 150 151 /** @var helper_plugin_acknowledge $helper */ 152 $helper = plugin_load('helper', 'acknowledge'); 153 154 // only display for users assigned to the page 155 if (!$helper->isUserAssigned($id, $user, $USERINFO['grps'])) { 156 return ''; 157 } 158 159 if ($ackSubmitted) { 160 $helper->saveAcknowledgement($id, $user); 161 } 162 163 $ack = $helper->hasUserAcknowledged($id, $user); 164 165 $html = '<div class="' . ($ack ? 'ack' : 'noack') . '">'; 166 $html .= inlineSVG(__DIR__ . '/admin.svg'); 167 $html .= '</div>'; 168 169 if ($ack) { 170 $html .= '<div>'; 171 $html .= '<h4>'; 172 $html .= $this->getLang('ackOk'); 173 $html .= '</h4>'; 174 $html .= sprintf($this->getLang('ackGranted'), dformat($ack)); 175 $html .= '</div>'; 176 } else { 177 $html .= '<div>'; 178 $html .= '<h4>' . $this->getLang('ackRequired') . '</h4>'; 179 $latest = $helper->getLatestUserAcknowledgement($id, $user); 180 if ($latest) { 181 $html .= '<a href="' 182 . wl($id, ['do' => 'diff', 'at' => $latest], false, '&') . '">' 183 . sprintf($this->getLang('ackDiff'), dformat($latest)) 184 . '</a><br>'; 185 } 186 187 $form = new Form(['id' => 'ackForm']); 188 $form->addCheckbox('ack', $this->getLang('ackText'))->attr('required', 'required'); 189 $form->addHTML( 190 '<br><button type="submit" name="acksubmit" id="ack-submit">' 191 . $this->getLang('ackButton') 192 . '</button>' 193 ); 194 195 $html .= $form->toHTML(); 196 $html .= '</div>'; 197 } 198 199 return $html; 200 } 201} 202