xref: /plugin/tagging/action/main.php (revision df43a7be9125b55733c41a4f1a13770bf4033169)
1<?php
2
3use dokuwiki\Extension\ActionPlugin;
4use dokuwiki\Extension\Event;
5use dokuwiki\Extension\EventHandler;
6
7/**
8 * Class action_plugin_tagging_main
9 */
10class action_plugin_tagging_main extends ActionPlugin
11{
12    /**
13     * Register handlers
14     *
15     * @param EventHandler $controller
16     */
17    public function register(EventHandler $controller)
18    {
19        $controller->register_hook(
20            'AJAX_CALL_UNKNOWN',
21            'BEFORE',
22            $this,
23            'handle_ajax_call_unknown'
24        );
25
26        $controller->register_hook(
27            'ACTION_ACT_PREPROCESS',
28            'BEFORE',
29            $this,
30            'handle_jump'
31        );
32
33        $controller->register_hook(
34            'DOKUWIKI_STARTED',
35            'AFTER',
36            $this,
37            'js_add_security_token'
38        );
39
40        $controller->register_hook(
41            'PLUGIN_MOVE_PAGE_RENAME',
42            'AFTER',
43            $this,
44            'update_moved_page'
45        );
46    }
47
48    /**
49     * Add sectok to JavaScript to secure ajax requests
50     *
51     * @param Event $event
52     * @param            $param
53     */
54    public function js_add_security_token(Event $event, $param)
55    {
56        global $JSINFO;
57        $JSINFO['sectok'] = getSecurityToken();
58    }
59
60    /**
61     * Handle our AJAX requests
62     *
63     * @param Event $event
64     * @param            $param
65     */
66    public function handle_ajax_call_unknown(Event $event, $param)
67    {
68        $handled = true;
69
70        if ($event->data == 'plugin_tagging_save') {
71            $this->save();
72        } elseif ($event->data == 'plugin_tagging_autocomplete') {
73            $this->autocomplete();
74        } elseif ($event->data === 'plugin_tagging_admin_change') {
75            $this->admin_change();
76        } elseif ($event->data === 'plugin_tagging_html_pages') {
77            $this->getPagesHtml();
78        } elseif ($event->data === 'plugin_tagging_delete') {
79            $this->deleteTag();
80        } elseif ($event->data === 'plugin_tagging_rename') {
81            $this->renameTag();
82        } else {
83            $handled = false;
84        }
85        if (!$handled) {
86            return;
87        }
88
89        $event->preventDefault();
90        $event->stopPropagation();
91    }
92
93    /**
94     * Jump to a tag
95     *
96     * @param Event $event
97     * @param            $param
98     */
99    public function handle_jump(Event &$event, $param)
100    {
101        if (act_clean($event->data) != 'tagjmp') {
102            return;
103        }
104
105        $event->preventDefault();
106        $event->stopPropagation();
107
108        $event->data = 'show';
109
110        global $INPUT;
111        $tags = $INPUT->arr('tag', (array)$INPUT->str('tag'));
112        $lang = $INPUT->str('lang');
113
114        /** @var helper_plugin_tagging $hlp */
115        $hlp = plugin_load('helper', 'tagging');
116
117        foreach ($tags as $tag) {
118            $filter = ['tag' => $tag];
119            if ($lang) {
120                $filter['lang'] = $lang;
121            }
122            $pages = $hlp->findItems($filter, 'pid', 1);
123            if (!count($pages)) {
124                continue;
125            }
126
127            $pages = array_keys($pages);
128            $id = array_pop($pages);
129            send_redirect(wl($id, '', true, '&'));
130        }
131
132        $tags = array_map('hsc', $tags);
133        msg(sprintf($this->getLang('tagjmp_error'), implode(', ', $tags)), -1);
134    }
135
136    /**
137     * Save new/changed tags
138     */
139    public function save()
140    {
141        global $INPUT;
142        global $INFO;
143
144        /** @var helper_plugin_tagging $hlp */
145        $hlp = plugin_load('helper', 'tagging');
146
147        $data = $INPUT->arr('tagging');
148        $id = $data['id'];
149        $INFO['writable'] = auth_quickaclcheck($id) >= AUTH_EDIT; // we also need this in findItems
150
151        if ($INFO['writable'] && $hlp->getUser()) {
152            $hlp->replaceTags(
153                $id,
154                $hlp->getUser(),
155                preg_split(
156                    '/(\s*,\s*)|(\s*,?\s*\n\s*)/',
157                    $data['tags'],
158                    -1,
159                    PREG_SPLIT_NO_EMPTY
160                )
161            );
162            $hlp->updateElasticState($id);
163        }
164
165        $tags = $hlp->findItems(['pid' => $id], 'tag');
166        $hlp->html_cloud($tags, 'tag', [$hlp, 'linkToSearch'], false);
167    }
168
169    /**
170     * Return autocompletion data
171     */
172    public function autocomplete()
173    {
174        global $INPUT;
175
176        /** @var helper_plugin_tagging $hlp */
177        $hlp = plugin_load('helper', 'tagging');
178
179        $search = $INPUT->str('term');
180        $tags = $hlp->findItems(['tag' => '*' . $hlp->getDB()->escape_string($search) . '*'], 'tag');
181        arsort($tags);
182        $tags = array_keys($tags);
183
184        header('Content-Type: application/json');
185
186        echo json_encode(array_combine($tags, $tags));
187    }
188
189    /**
190     * Allow admins to change all tags (not only their own)
191     * We change the tag for every user
192     */
193    public function admin_change()
194    {
195        global $INPUT;
196
197        /** @var helper_plugin_tagging $hlp */
198        $hlp = plugin_load('helper', 'tagging');
199
200        header('Content-Type: application/json');
201
202        if (!auth_isadmin()) {
203            echo json_encode(['status' => 'error', 'msg' => $this->getLang('no_admin')]);
204            return;
205        }
206
207        if (!checkSecurityToken()) {
208            echo json_encode(['status' => 'error', 'msg' => 'Security Token did not match. Possible CSRF attack.']);
209            return;
210        }
211
212        if (!$INPUT->has('id')) {
213            echo json_encode(['status' => 'error', 'msg' => 'No page id given.']);
214            return;
215        }
216        $pid = $INPUT->str('id');
217
218        if (!$INPUT->has('oldValue') || !$INPUT->has('newValue')) {
219            echo json_encode(['status' => 'error', 'msg' => 'No proper input. Give "oldValue" and "newValue"']);
220            return;
221        }
222
223
224        [$err, $msg] = $hlp->modifyPageTag($pid, $INPUT->str('oldValue'), $INPUT->str('newValue'));
225        if ($err) {
226            echo json_encode(['status' => 'error', 'msg' => $msg]);
227            return;
228        }
229
230        $tags = $hlp->findItems(['pid' => $pid], 'tag');
231        $userTags = $hlp->findItems(['pid' => $pid, 'tagger' => $hlp->getUser()], 'tag');
232        echo json_encode([
233            'status' => 'ok',
234            'tags_edit_value' => implode(', ', array_keys($userTags)),
235            'html_cloud' => $hlp->html_cloud($tags, 'tag', [$hlp, 'linkToSearch'], false, true)
236        ]);
237    }
238
239    /**
240     * Management: delete all occurrences of a tag
241     */
242    public function deleteTag()
243    {
244        global $INPUT;
245        $data = $INPUT->arr('tagging');
246
247        /** @var helper_plugin_tagging $hlp */
248        $hlp = plugin_load('helper', 'tagging');
249        $hlp->deleteTags($data['tid']);
250
251        // update elasticsearch state for all relevant pages
252        $pids = $hlp->findItems(['tag' => $data['tid'][0]], 'pid');
253        if (!empty($pids)) {
254            foreach (array_keys($pids) as $pid) {
255                $hlp->updateElasticState($pid);
256            }
257        }
258    }
259
260    /**
261     * Management: rename all occurrences of a tag
262     */
263    public function renameTag()
264    {
265        global $INPUT;
266        $data = $INPUT->arr('tagging');
267
268        /** @var helper_plugin_tagging $hlp */
269        $hlp = plugin_load('helper', 'tagging');
270        $hlp->renameTag($data['oldValue'], $data['newValue']);
271
272        // update elasticsearch state for all relevant pages
273        $pids = $hlp->findItems(['tag' => $data['newValue']], 'pid');
274        if (!empty($pids)) {
275            foreach (array_keys($pids) as $pid) {
276                $hlp->updateElasticState($pid);
277            }
278        }
279    }
280
281    /**
282     * Tag dialog HTML: print links to all pages with a given tag
283     */
284    public function getPagesHtml()
285    {
286        global $INPUT;
287        $data = $INPUT->arr('tagging');
288
289        /** @var helper_plugin_tagging $hlp */
290        $hlp = plugin_load('helper', 'tagging');
291        echo $hlp->getPagesHtml($data['tid']);
292    }
293
294    /**
295     * Updates tagging database after a page has been moved/renamed by the move plugin
296     *
297     * @param Event $event
298     * @param $param
299     */
300    public function update_moved_page(Event $event, $param)
301    {
302        $src = $event->data['src_id'];
303        $dst = $event->data['dst_id'];
304
305        /** @var helper_plugin_tagging $hlp */
306        $hlp = plugin_load('helper', 'tagging');
307        $hlp->renamePage($src, $dst);
308    }
309}
310