1c38b6ca8SAnna Dabrowska<?php 2c38b6ca8SAnna Dabrowska 3c38b6ca8SAnna Dabrowska/** 4c38b6ca8SAnna Dabrowska * DokuWiki Plugin acknowledge (AJAX Action Component) 5c38b6ca8SAnna Dabrowska * 6c38b6ca8SAnna Dabrowska * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7c38b6ca8SAnna Dabrowska * @author Andreas Gohr, Anna Dabrowska <dokuwiki@cosmocode.de> 8c38b6ca8SAnna Dabrowska */ 9c38b6ca8SAnna Dabrowska 10c38b6ca8SAnna Dabrowskause dokuwiki\Extension\ActionPlugin; 11c38b6ca8SAnna Dabrowskause dokuwiki\Extension\EventHandler; 12c38b6ca8SAnna Dabrowskause dokuwiki\Extension\Event; 13c38b6ca8SAnna Dabrowskause dokuwiki\Form\Form; 14c38b6ca8SAnna Dabrowska 15c38b6ca8SAnna Dabrowskaclass action_plugin_acknowledge_ajax extends ActionPlugin 16c38b6ca8SAnna Dabrowska{ 17c38b6ca8SAnna Dabrowska /** @inheritDoc */ 18c38b6ca8SAnna Dabrowska public function register(EventHandler $controller) 19c38b6ca8SAnna Dabrowska { 20c38b6ca8SAnna Dabrowska $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxAcknowledge'); 21c38b6ca8SAnna Dabrowska $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxAutocomplete'); 22*c2e33bceSAnna Dabrowska $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxUserList'); 23c38b6ca8SAnna Dabrowska } 24c38b6ca8SAnna Dabrowska 25c38b6ca8SAnna Dabrowska /** 26c38b6ca8SAnna Dabrowska * @param Event $event 27c38b6ca8SAnna Dabrowska * @param $param 28c38b6ca8SAnna Dabrowska */ 29c38b6ca8SAnna Dabrowska public function handleAjaxAcknowledge(Event $event, $param) 30c38b6ca8SAnna Dabrowska { 31c38b6ca8SAnna Dabrowska if ($event->data === 'plugin_acknowledge_acknowledge') { 32c38b6ca8SAnna Dabrowska $event->stopPropagation(); 33c38b6ca8SAnna Dabrowska $event->preventDefault(); 34c38b6ca8SAnna Dabrowska 35c38b6ca8SAnna Dabrowska global $INPUT; 36c38b6ca8SAnna Dabrowska $id = $INPUT->str('id'); 37c38b6ca8SAnna Dabrowska 38c38b6ca8SAnna Dabrowska if (page_exists($id)) { 39c38b6ca8SAnna Dabrowska echo $this->html(); 40c38b6ca8SAnna Dabrowska } 41c38b6ca8SAnna Dabrowska } 42c38b6ca8SAnna Dabrowska } 43c38b6ca8SAnna Dabrowska 44c38b6ca8SAnna Dabrowska /** 45c38b6ca8SAnna Dabrowska * @param Event $event 46c38b6ca8SAnna Dabrowska * @return void 47c38b6ca8SAnna Dabrowska */ 48c38b6ca8SAnna Dabrowska public function handleAjaxAutocomplete(Event $event) 49c38b6ca8SAnna Dabrowska { 50c38b6ca8SAnna Dabrowska if ($event->data === 'plugin_acknowledge_autocomplete') { 51c38b6ca8SAnna Dabrowska if (!checkSecurityToken()) return; 52c38b6ca8SAnna Dabrowska 53c38b6ca8SAnna Dabrowska global $INPUT; 54c38b6ca8SAnna Dabrowska 55c38b6ca8SAnna Dabrowska $event->stopPropagation(); 56c38b6ca8SAnna Dabrowska $event->preventDefault(); 57c38b6ca8SAnna Dabrowska 58c38b6ca8SAnna Dabrowska /** @var helper_plugin_acknowledge $hlp */ 59c38b6ca8SAnna Dabrowska $hlp = $this->loadHelper('acknowledge'); 60c38b6ca8SAnna Dabrowska 61c38b6ca8SAnna Dabrowska $found = []; 62c38b6ca8SAnna Dabrowska 63c38b6ca8SAnna Dabrowska if ($INPUT->has('user')) { 64c38b6ca8SAnna Dabrowska $search = $INPUT->str('user'); 65c38b6ca8SAnna Dabrowska $knownUsers = $hlp->getUsers(); 66c38b6ca8SAnna Dabrowska $found = array_filter($knownUsers, function ($user) use ($search) { 67c38b6ca8SAnna Dabrowska return (strstr(strtolower($user['label']), strtolower($search))) !== false ? $user : null; 68c38b6ca8SAnna Dabrowska }); 69c38b6ca8SAnna Dabrowska } 70c38b6ca8SAnna Dabrowska 71c38b6ca8SAnna Dabrowska if ($INPUT->has('pg')) { 72c38b6ca8SAnna Dabrowska $search = $INPUT->str('pg'); 73c38b6ca8SAnna Dabrowska $pages = ft_pageLookup($search, true); 74c38b6ca8SAnna Dabrowska $found = array_map(function ($id, $title) { 75c38b6ca8SAnna Dabrowska return ['value' => $id, 'label' => $title ?? $id]; 76c38b6ca8SAnna Dabrowska }, array_keys($pages), array_values($pages)); 77c38b6ca8SAnna Dabrowska } 78c38b6ca8SAnna Dabrowska 79c38b6ca8SAnna Dabrowska header('Content-Type: application/json'); 80c38b6ca8SAnna Dabrowska 81c38b6ca8SAnna Dabrowska echo json_encode($found); 82c38b6ca8SAnna Dabrowska } 83c38b6ca8SAnna Dabrowska } 84c38b6ca8SAnna Dabrowska 85c38b6ca8SAnna Dabrowska /** 86*c2e33bceSAnna Dabrowska * Returns the full user list for a report section (loaded on demand) 87*c2e33bceSAnna Dabrowska * 88*c2e33bceSAnna Dabrowska * @param Event $event 89*c2e33bceSAnna Dabrowska * @return void 90*c2e33bceSAnna Dabrowska */ 91*c2e33bceSAnna Dabrowska public function handleAjaxUserList(Event $event) 92*c2e33bceSAnna Dabrowska { 93*c2e33bceSAnna Dabrowska if ($event->data !== 'plugin_acknowledge_userlist') return; 94*c2e33bceSAnna Dabrowska 95*c2e33bceSAnna Dabrowska $event->stopPropagation(); 96*c2e33bceSAnna Dabrowska $event->preventDefault(); 97*c2e33bceSAnna Dabrowska 98*c2e33bceSAnna Dabrowska if (!auth_ismanager()) return; 99*c2e33bceSAnna Dabrowska 100*c2e33bceSAnna Dabrowska global $INPUT; 101*c2e33bceSAnna Dabrowska $id = $INPUT->str('id'); 102*c2e33bceSAnna Dabrowska $status = $INPUT->str('status'); 103*c2e33bceSAnna Dabrowska 104*c2e33bceSAnna Dabrowska if (!page_exists($id)) return; 105*c2e33bceSAnna Dabrowska if (!in_array($status, ['current', 'due'], true)) return; 106*c2e33bceSAnna Dabrowska 107*c2e33bceSAnna Dabrowska /** @var helper_plugin_acknowledge $helper */ 108*c2e33bceSAnna Dabrowska $helper = plugin_load('helper', 'acknowledge'); 109*c2e33bceSAnna Dabrowska 110*c2e33bceSAnna Dabrowska if (!$helper->getPageAssignees($id)) return; 111*c2e33bceSAnna Dabrowska 112*c2e33bceSAnna Dabrowska echo $this->userListHtml($helper->getPageAcknowledgements($id, '', $status)); 113*c2e33bceSAnna Dabrowska } 114*c2e33bceSAnna Dabrowska 115*c2e33bceSAnna Dabrowska /** 116b55c1d2dSAnna Dabrowska * Returns the acknowledgment form/confirmation and optionally management report 117c38b6ca8SAnna Dabrowska * 118c38b6ca8SAnna Dabrowska * @return string The HTML to display 119c38b6ca8SAnna Dabrowska */ 120c38b6ca8SAnna Dabrowska protected function html() 121c38b6ca8SAnna Dabrowska { 122c38b6ca8SAnna Dabrowska global $INPUT; 123c38b6ca8SAnna Dabrowska $id = $INPUT->str('id'); 124c38b6ca8SAnna Dabrowska $user = $INPUT->server->str('REMOTE_USER'); 125c38b6ca8SAnna Dabrowska if ($id === '' || $user === '') return ''; 126c38b6ca8SAnna Dabrowska 127c38b6ca8SAnna Dabrowska /** @var helper_plugin_acknowledge $helper */ 128c38b6ca8SAnna Dabrowska $helper = plugin_load('helper', 'acknowledge'); 129c38b6ca8SAnna Dabrowska 130b55c1d2dSAnna Dabrowska return $this->bannerHtml($id, $user, $helper) . $this->reportHtml($id, $helper); 131b55c1d2dSAnna Dabrowska } 132b55c1d2dSAnna Dabrowska 133b55c1d2dSAnna Dabrowska /** 134b55c1d2dSAnna Dabrowska * Returns the personal acknowledgement banner 135b55c1d2dSAnna Dabrowska * 136b55c1d2dSAnna Dabrowska * @param string $id 137b55c1d2dSAnna Dabrowska * @param string $user 138b55c1d2dSAnna Dabrowska * @param helper_plugin_acknowledge $helper 139b55c1d2dSAnna Dabrowska * @return string 140b55c1d2dSAnna Dabrowska */ 141b55c1d2dSAnna Dabrowska protected function bannerHtml($id, $user, helper_plugin_acknowledge $helper) 142b55c1d2dSAnna Dabrowska { 143b55c1d2dSAnna Dabrowska global $INPUT; 144b55c1d2dSAnna Dabrowska global $USERINFO; 145b55c1d2dSAnna Dabrowska 146c38b6ca8SAnna Dabrowska // only display for users assigned to the page 147c38b6ca8SAnna Dabrowska if (!$helper->isUserAssigned($id, $user, $USERINFO['grps'])) { 148c38b6ca8SAnna Dabrowska return ''; 149c38b6ca8SAnna Dabrowska } 150c38b6ca8SAnna Dabrowska 151a8303a15SAnna Dabrowska // if the approve plugin is active, only show if the page is approved 152a8303a15SAnna Dabrowska if ($helper->isBlockedByApprove($id)) { 153a8303a15SAnna Dabrowska return ''; 154a8303a15SAnna Dabrowska } 155a8303a15SAnna Dabrowska 156b55c1d2dSAnna Dabrowska if ($INPUT->bool('ack')) { 157c38b6ca8SAnna Dabrowska $helper->saveAcknowledgement($id, $user); 158c38b6ca8SAnna Dabrowska } 159c38b6ca8SAnna Dabrowska 160c38b6ca8SAnna Dabrowska $ack = $helper->hasUserAcknowledged($id, $user); 161c38b6ca8SAnna Dabrowska 162b55c1d2dSAnna Dabrowska $html = '<div class="plugin-acknowledge-box ack' . ($ack ? ' done' : '') . '">'; 163b55c1d2dSAnna Dabrowska $html .= '<div class="ack-icon">'; 164c38b6ca8SAnna Dabrowska $html .= inlineSVG(__DIR__ . '/../admin.svg'); 165c38b6ca8SAnna Dabrowska $html .= '</div>'; 166c38b6ca8SAnna Dabrowska 167b55c1d2dSAnna Dabrowska $html .= '<div class="content">'; 168c38b6ca8SAnna Dabrowska if ($ack) { 169c38b6ca8SAnna Dabrowska $html .= '<h4>'; 170c38b6ca8SAnna Dabrowska $html .= $this->getLang('ackOk'); 171c38b6ca8SAnna Dabrowska $html .= '</h4>'; 172c38b6ca8SAnna Dabrowska $html .= sprintf($this->getLang('ackGranted'), dformat($ack)); 173c38b6ca8SAnna Dabrowska } else { 174c38b6ca8SAnna Dabrowska $html .= '<h4>' . $this->getLang('ackRequired') . '</h4>'; 175c38b6ca8SAnna Dabrowska $latest = $helper->getLatestUserAcknowledgement($id, $user); 176c38b6ca8SAnna Dabrowska if ($latest) { 177c38b6ca8SAnna Dabrowska $html .= '<a href="' 178c38b6ca8SAnna Dabrowska . wl($id, ['do' => 'diff', 'at' => $latest], false, '&') . '">' 179c38b6ca8SAnna Dabrowska . sprintf($this->getLang('ackDiff'), dformat($latest)) 180c38b6ca8SAnna Dabrowska . '</a><br>'; 181c38b6ca8SAnna Dabrowska } 182c38b6ca8SAnna Dabrowska 183c38b6ca8SAnna Dabrowska $form = new Form(['id' => 'ackForm']); 184c38b6ca8SAnna Dabrowska $form->addCheckbox('ack', $this->getLang('ackText'))->attr('required', 'required'); 185c38b6ca8SAnna Dabrowska $form->addHTML( 186c38b6ca8SAnna Dabrowska '<br><button type="submit" name="acksubmit" id="ack-submit">' 187c38b6ca8SAnna Dabrowska . $this->getLang('ackButton') 188c38b6ca8SAnna Dabrowska . '</button>' 189c38b6ca8SAnna Dabrowska ); 190c38b6ca8SAnna Dabrowska 191c38b6ca8SAnna Dabrowska $html .= $form->toHTML(); 192c38b6ca8SAnna Dabrowska } 193b55c1d2dSAnna Dabrowska $html .= '</div>'; // content 194b55c1d2dSAnna Dabrowska $html .= '</div>'; // box 195b55c1d2dSAnna Dabrowska 196b55c1d2dSAnna Dabrowska return $html; 197b55c1d2dSAnna Dabrowska } 198b55c1d2dSAnna Dabrowska 199b55c1d2dSAnna Dabrowska /** 200b55c1d2dSAnna Dabrowska * Returns the manager/admin report box 201b55c1d2dSAnna Dabrowska * 202b55c1d2dSAnna Dabrowska * @param string $id 203b55c1d2dSAnna Dabrowska * @param helper_plugin_acknowledge $helper 204b55c1d2dSAnna Dabrowska * @return string 205b55c1d2dSAnna Dabrowska */ 206b55c1d2dSAnna Dabrowska protected function reportHtml($id, helper_plugin_acknowledge $helper) 207b55c1d2dSAnna Dabrowska { 208b55c1d2dSAnna Dabrowska $mode = $this->getConf('onpage_report'); 209b55c1d2dSAnna Dabrowska if ($mode === 'off') return ''; 210b55c1d2dSAnna Dabrowska 211b55c1d2dSAnna Dabrowska if (!auth_ismanager()) return ''; 212b55c1d2dSAnna Dabrowska 213b55c1d2dSAnna Dabrowska if (!$helper->getPageAssignees($id)) return ''; 214b55c1d2dSAnna Dabrowska 215b55c1d2dSAnna Dabrowska $html = '<div class="plugin-acknowledge-box report">'; 216b55c1d2dSAnna Dabrowska 217b55c1d2dSAnna Dabrowska $html .= '<div class="ack-icon">'; 218b55c1d2dSAnna Dabrowska $html .= inlineSVG(__DIR__ . '/../admin.svg'); 219b55c1d2dSAnna Dabrowska $html .= '</div>'; 220b55c1d2dSAnna Dabrowska 221b55c1d2dSAnna Dabrowska $html .= '<div class="content">'; 222b55c1d2dSAnna Dabrowska $html .= '<h3>' . $this->getLang('reportTitle') . '</h3>'; 223b55c1d2dSAnna Dabrowska 224*c2e33bceSAnna Dabrowska // resolve group membership once, derive both counts arithmetically 225*c2e33bceSAnna Dabrowska $counts = $helper->getPageAcknowledgementCounts($id); 226*c2e33bceSAnna Dabrowska 227b55c1d2dSAnna Dabrowska if ($mode === 'acknowledged' || $mode === 'both') { 228*c2e33bceSAnna Dabrowska $html .= '<p>' . $this->getLang('reportAcknowledgedTitle') . '</p>'; 229*c2e33bceSAnna Dabrowska $html .= $this->userCountHtml($id, 'current', $counts['current']); 230b55c1d2dSAnna Dabrowska } 231b55c1d2dSAnna Dabrowska 232b55c1d2dSAnna Dabrowska if ($mode === 'pending' || $mode === 'both') { 233*c2e33bceSAnna Dabrowska $html .= '<p>' . $this->getLang('reportPendingTitle') . '</p>'; 234*c2e33bceSAnna Dabrowska $html .= $this->userCountHtml($id, 'due', $counts['due']); 235b55c1d2dSAnna Dabrowska } 236b55c1d2dSAnna Dabrowska 237b55c1d2dSAnna Dabrowska $html .= '</div>'; // content 238b55c1d2dSAnna Dabrowska $html .= '</div>'; // box 239b55c1d2dSAnna Dabrowska 240b55c1d2dSAnna Dabrowska return $html; 241b55c1d2dSAnna Dabrowska } 242b55c1d2dSAnna Dabrowska 243b55c1d2dSAnna Dabrowska /** 244*c2e33bceSAnna Dabrowska * Renders a clickable user count that loads the full user list on demand 245*c2e33bceSAnna Dabrowska * 246*c2e33bceSAnna Dabrowska * @param string $id 247*c2e33bceSAnna Dabrowska * @param string $status acknowledgement status ('current' or 'due') 248*c2e33bceSAnna Dabrowska * @param int $count 249*c2e33bceSAnna Dabrowska * @return string 250*c2e33bceSAnna Dabrowska */ 251*c2e33bceSAnna Dabrowska protected function userCountHtml($id, $status, $count) 252*c2e33bceSAnna Dabrowska { 253*c2e33bceSAnna Dabrowska if (!$count) { 254*c2e33bceSAnna Dabrowska return '<p>' . $this->getLang('reportNobody') . '</p>'; 255*c2e33bceSAnna Dabrowska } 256*c2e33bceSAnna Dabrowska 257*c2e33bceSAnna Dabrowska return '<p><a href="#" class="plugin-acknowledge-loadusers"' 258*c2e33bceSAnna Dabrowska . ' data-id="' . hsc($id) . '" data-status="' . hsc($status) . '">' 259*c2e33bceSAnna Dabrowska . sprintf($this->getLang('reportUserCount'), $count) 260*c2e33bceSAnna Dabrowska . '</a></p>'; 261*c2e33bceSAnna Dabrowska } 262*c2e33bceSAnna Dabrowska 263*c2e33bceSAnna Dabrowska /** 264b55c1d2dSAnna Dabrowska * Renders a list of users from acknowledgement records. 265b55c1d2dSAnna Dabrowska * 266b55c1d2dSAnna Dabrowska * @param array $rows 267b55c1d2dSAnna Dabrowska * @return string 268b55c1d2dSAnna Dabrowska */ 269b55c1d2dSAnna Dabrowska protected function userListHtml($rows) 270b55c1d2dSAnna Dabrowska { 271b55c1d2dSAnna Dabrowska if (!$rows) { 272b55c1d2dSAnna Dabrowska return '<p>' . $this->getLang('reportNobody') . '</p>'; 273b55c1d2dSAnna Dabrowska } 274b55c1d2dSAnna Dabrowska 275b55c1d2dSAnna Dabrowska $html = '<ul>'; 276b55c1d2dSAnna Dabrowska foreach ($rows as $row) { 277b55c1d2dSAnna Dabrowska $html .= '<li>'; 278b55c1d2dSAnna Dabrowska $html .= userlink($row['user']); 279b55c1d2dSAnna Dabrowska 280b55c1d2dSAnna Dabrowska if (!empty($row['ack'])) { 281b55c1d2dSAnna Dabrowska $html .= ' ' . $this->getLang('reportAckedOn') . ' ' . hsc(dformat($row['ack'])); 282b55c1d2dSAnna Dabrowska } 283b55c1d2dSAnna Dabrowska $html .= '</li>'; 284b55c1d2dSAnna Dabrowska } 285b55c1d2dSAnna Dabrowska $html .= '</ul>'; 286c38b6ca8SAnna Dabrowska 287c38b6ca8SAnna Dabrowska return $html; 288c38b6ca8SAnna Dabrowska } 289c38b6ca8SAnna Dabrowska} 290