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