1<?php 2 3use dokuwiki\Extension\ActionPlugin; 4use dokuwiki\Extension\EventHandler; 5use dokuwiki\Extension\Event; 6use dokuwiki\plugin\recommend\MenuItem; 7use dokuwiki\Form\Form; 8use dokuwiki\Utf8\PhpString; 9 10class action_plugin_recommend extends ActionPlugin 11{ 12 public function register(EventHandler $controller) 13 { 14 foreach (['ACTION_ACT_PREPROCESS', 'AJAX_CALL_UNKNOWN', 'TPL_ACT_UNKNOWN'] as $event) { 15 $controller->register_hook($event, 'BEFORE', $this, 'handle'); 16 } 17 $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'handleMenu'); 18 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'autocomplete'); 19 } 20 21 /** 22 * Main processing 23 * 24 * @param Event $event 25 * @return void 26 */ 27 public function handle(Event $event) 28 { 29 if ($event->data !== 'recommend') { 30 return; 31 } 32 33 $event->preventDefault(); 34 35 if ($event->name === 'ACTION_ACT_PREPROCESS') { 36 return; 37 } 38 39 $event->stopPropagation(); 40 41 global $INPUT; 42 43 // early output to trigger display msgs even via AJAX. 44 echo ' '; 45 tpl_flush(); 46 if ($INPUT->server->str('REQUEST_METHOD') === 'POST') { 47 try { 48 $this->handlePost(); 49 if ($event->name === 'AJAX_CALL_UNKNOWN') { 50 $this->ajaxSuccess(); // To signal success to AJAX. 51 } else { 52 msg($this->getLang('thanks'), 1); 53 } 54 return; // we're done here 55 } catch (\Exception $e) { 56 msg($e->getMessage(), -1); 57 } 58 } 59 60 echo $this->getForm(); 61 } 62 63 /** 64 * Page menu item 65 * 66 * @param Event $event 67 * @return void 68 */ 69 public function handleMenu(Event $event) 70 { 71 if ($event->data['view'] !== 'page') return; 72 // menu item is only for logged in users 73 if (empty($_SERVER['REMOTE_USER'])) return; 74 75 array_splice($event->data['items'], -1, 0, [new MenuItem()]); 76 } 77 78 /** 79 * Autocomplete 80 * @param Event $event 81 * @throws Exception 82 * @author Andreas Gohr 83 */ 84 public function autocomplete(Event $event) 85 { 86 87 if ($event->data !== 'plugin_recommend_ac') { 88 return; 89 } 90 91 $event->preventDefault(); 92 $event->stopPropagation(); 93 94 /** @var \DokuWiki_Auth_Plugin $auth */ 95 global $auth; 96 global $INPUT; 97 98 if (!$auth->canDo('getUsers')) { 99 throw new Exception('The user backend can not search for users'); 100 } 101 102 header('Content-Type: application/json'); 103 104 // check minimum length 105 $lookup = trim($INPUT->str('search')); 106 if (PhpString::strlen($lookup) < 3) { 107 echo json_encode([]); 108 return; 109 } 110 111 // find users by login and name 112 $logins = $auth->retrieveUsers(0, 10, ['user' => $lookup]); 113 if (count($logins) < 10) { 114 $logins = array_merge($logins, $auth->retrieveUsers(0, 10, ['name' => $lookup])); 115 } 116 117 // reformat result for jQuery UI Autocomplete 118 $users = []; 119 foreach ($logins as $login => $info) { 120 $users[] = [ 121 'label' => $info['name'] . ' [' . $login . ']', 122 'value' => $login 123 ]; 124 } 125 126 echo json_encode($users); 127 } 128 129 /** 130 * Returns rendered form 131 * 132 * @return string 133 */ 134 protected function getForm() 135 { 136 global $INPUT; 137 138 $id = getID(); // we may run in AJAX context 139 if ($id === '') throw new \RuntimeException('No ID given'); 140 141 $form = new Form([ 142 'action' => wl($id, ['do' => 'recommend'], false, '&'), 143 'id' => 'plugin__recommend', 144 ]); 145 $form->setHiddenField('id', $id); // we need it for the ajax call 146 147 /** @var helper_plugin_recommend_assignment $helper */ 148 $helper = plugin_load('helper', 'recommend_assignment'); 149 $template = $helper->loadMatchingTemplate(); 150 151 if ($INPUT->server->has('REMOTE_USER')) { 152 global $USERINFO; 153 $form->setHiddenField('s_name', $USERINFO['name']); 154 $form->setHiddenField('s_email', $USERINFO['mail']); 155 } else { 156 $form->addTextInput('s_name', $this->getLang('yourname'))->addClass('edit'); 157 $form->addTextInput('s_email', $this->getLang('youremailaddress'))->addClass('edit'); 158 } 159 160 $form->addTextInput('r_email', $this->getLang('recipients')) 161 ->addClass('edit') 162 ->val($template['user'] ?? ''); 163 $form->addTextInput('subject', $this->getLang('subject')) 164 ->addClass('edit') 165 ->val($template['subject'] ?? ''); 166 $form->addTextarea('comment', $this->getLang('message')) 167 ->attr('rows', '8') 168 ->attr('cols', '40') 169 ->addClass('edit') 170 ->val($template['message'] ?? ''); 171 172 /** @var helper_plugin_captcha $captcha */ 173 $captcha = plugin_load('helper', 'captcha'); 174 if ($captcha) $form->addHTML($captcha->getHTML()); 175 176 $form->addTagOpen('div')->addClass('buttons'); 177 $form->addButton('submit', $this->getLang('send'))->attr('type', 'submit'); 178 $form->addTagClose('div'); 179 180 return $form->toHTML(); 181 } 182 183 /** 184 * Handles form submission 185 * 186 * @throws Exception 187 */ 188 protected function handlePost() 189 { 190 global $INPUT; 191 192 if (!checkSecurityToken()) { 193 throw new \Exception('Security token did not match'); 194 } 195 196 /** @var helper_plugin_recommend_mail $mailHelper */ 197 $mailHelper = plugin_load('helper', 'recommend_mail'); 198 199 // Captcha plugin 200 $captcha = null; 201 if (@is_dir(DOKU_PLUGIN . 'captcha')) $captcha = plugin_load('helper', 'captcha'); 202 if (!is_null($captcha) && $captcha->isEnabled() && !$captcha->check()) { 203 throw new \Exception($this->getLang('err_captcha')); 204 } 205 206 /* Validate input */ 207 $recipients = $INPUT->str('r_email'); 208 209 if (empty($recipients)) { 210 throw new \Exception($this->getLang('err_recipient')); 211 } 212 213 $recipients = $mailHelper->resolveRecipients($recipients); 214 $recipients = implode(',', $recipients); 215 216 if (!isset($_POST['s_email']) || !mail_isvalid($_POST['s_email'])) { 217 throw new \Exception($this->getLang('err_sendermail')); 218 } 219 if (!isset($_POST['s_name']) || trim($_POST['s_name']) === '') { 220 throw new \Exception($this->getLang('err_sendername')); 221 } 222 $s_name = $_POST['s_name']; 223 $sender = $s_name . ' <' . $_POST['s_email'] . '>'; 224 225 $id = $INPUT->filter('cleanID')->str('id'); 226 if ($id === '' || !page_exists($id)) throw new \Exception($this->getLang('err_page')); 227 228 $comment = $INPUT->str('comment'); 229 230 global $conf; 231 $replacements = [ 232 'PAGE' => $id, 233 'SITE' => $conf['title'], 234 'URL' => wl($id, '', true), 235 'COMMENT' => $comment, 236 'AUTHOR' => $s_name 237 ]; 238 239 $mailHelper->sendMail($recipients, $sender, $replacements); 240 241 /** @var helper_plugin_recommend_log $log */ 242 $log = new helper_plugin_recommend_log(date('Y-m')); 243 $log->writeEntry($id, $sender, $recipients, $comment); 244 } 245 246 /** 247 * show success message in ajax mode 248 */ 249 protected function ajaxSuccess() 250 { 251 echo '<form id="plugin__recommend" accept-charset="utf-8" method="post" action="?do=recommend">'; 252 echo '<div class="no">'; 253 echo '<span class="ui-icon ui-icon-circle-check" style="float: left; margin: 0 7px 50px 0;"></span>'; 254 echo '<p>' . $this->getLang('done') . '</p>'; 255 echo '<button type="reset" class="button">' . $this->getLang('close') . '</button>'; 256 echo '</div>'; 257 echo '</form>'; 258 } 259} 260