xref: /plugin/acknowledge/action/ajax.php (revision c2e33bcede677b26c01ce484dd9ed10c198ffb08)
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