xref: /plugin/recommend/action.php (revision c6f9d3d590f898165ce791277f4554ff3ef97548)
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