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