Slackbot::handleUrlVerification()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0185
1
<?php
2
3
namespace Botonomous;
4
5
use Botonomous\listener\AbstractBaseListener;
6
use Botonomous\listener\EventListener;
7
use Botonomous\plugin\AbstractPlugin;
8
9
/**
10
 * Class Botonomous.
11
 */
12
class Slackbot extends AbstractBot
13
{
14
    private $commands;
15
    private $lastError;
16
    private $currentCommand;
17
18
    /**
19
     * Botonomous constructor.
20
     *
21
     * @param Config|null $config
22
     *
23
     * @throws \Exception
24
     */
25 43
    public function __construct(Config $config = null)
26
    {
27 43
        if ($config !== null) {
28 6
            $this->setConfig($config);
29
        }
30
31 43
        $this->setTimezone();
32 43
    }
33
34
    /**
35
     * Set the timezone.
36
     *
37
     * @throws \Exception
38
     */
39 43
    private function setTimezone()
40
    {
41
        // set timezone
42 43
        date_default_timezone_set($this->getConfig()->get('timezone'));
43 43
    }
44
45
    /**
46
     * @param null|string $key
47
     *
48
     * @throws \Exception
49
     *
50
     * @return mixed
51
     */
52 10
    public function getRequest($key = null)
53
    {
54 10
        return $this->getListener()->getRequest($key);
55
    }
56
57
    /**
58
     * @throws \Exception
59
     *
60
     * @return AbstractBaseSlack|null|void
61
     */
62 1
    private function handleMessageActions()
63
    {
64 1
        $post = $this->getRequestUtility()->getPost();
65
66
        // ignore if payload is not set
67 1
        if (!isset($post['payload'])) {
68
            /* @noinspection PhpInconsistentReturnPointsInspection */
69 1
            return;
70
        }
71
72
        // posted payload is in JSON
73 1
        $payload = json_decode($post['payload'], true);
74
75 1
        return (new MessageAction())->load($payload);
76
    }
77
78
    /**
79
     * @throws \Exception
80
     */
81 5
    private function handleSendResponse()
82
    {
83
        // 1. Start listening
84 5
        $this->getListener()->listen();
85
86
        // 2. verify the request
87
        try {
88 5
            $verificationResult = $this->getListener()->verifyRequest();
89
90 5
            if ($verificationResult[AbstractBaseListener::ORIGIN_VERIFICATION_SUCCESS_KEY] !== true) {
91 2
                throw new BotonomousException(
92 5
                    $verificationResult[AbstractBaseListener::ORIGIN_VERIFICATION_MESSAGE_KEY]
93
                );
94
            }
95 2
        } catch (\Exception $e) {
96 2
            throw $e;
97
        }
98
99
        // 3. pre process the request
100 3
        $this->preProcessRequest();
101
102
        // 4. check access control
103 3
        if ($this->checkAccessControl() !== true) {
104 2
            return;
105
        }
106
107
        // 5. set the current command
108 1
        $message = $this->getListener()->getMessage();
109 1
        $this->setCurrentCommand($this->getMessageUtility()->extractCommandName($message));
110
111
        // 6. log the message
112 1
        $this->getLoggerUtility()->logChat(__METHOD__, $message);
113
114
        // 7. send confirmation message if is enabled
115 1
        $this->getSender()->sendConfirmation();
116
117
        // 8. And send the response to the channel, only if the response is not empty
118 1
        $response = $this->respond($message);
119
120 1
        if (!empty($response)) {
121 1
            $this->getSender()->send($response);
122
        }
123 1
    }
124
125
    /**
126
     * @throws \Exception
127
     *
128
     * @return bool
129
     */
130 3
    private function checkAccessControl(): bool
131
    {
132
        // if accessControlEnabled is not set true ignore the check and return true
133 3
        if ($this->getConfig()->get('accessControlEnabled') !== true) {
134 1
            return true;
135
        }
136
137 2
        if ($this->getBlackList()->isBlackListed() !== false) {
138
            // found in blacklist
139 1
            $this->getSender()->send($this->getDictionary()->get('generic-messages')['blacklistedMessage']);
140
141 1
            return false;
142
        }
143
144 1
        if ($this->getWhiteList()->isWhiteListed() !== true) {
145
            // not found in whitelist
146 1
            $this->getSender()->send($this->getDictionary()->get('generic-messages')['whitelistedMessage']);
147
148 1
            return false;
149
        }
150
151
        return true;
152
    }
153
154
    /**
155
     * @throws \Exception
156
     */
157 8
    public function run()
158
    {
159 8
        switch ($this->getListener()->determineAction()) {
160 8
            case 'oauth':
161 1
                return $this->handleOAuth();
162 7
            case 'message_actions':
163 1
                return $this->handleMessageActions();
164 6
            case 'url_verification':
165 1
                return $this->handleUrlVerification();
166
            default:
167 5
                return $this->handleSendResponse();
168
        }
169
    }
170
171
    /**
172
     * handle OAuth.
173
     *
174
     * @throws \Exception
175
     */
176 1
    private function handleOAuth()
177
    {
178 1
        return $this->getOauth()->doOauth();
179
    }
180
181
    /**
182
     * @throws \Exception
183
     */
184 1
    private function handleUrlVerification()
185
    {
186 1
        $request = $this->getRequestUtility()->getPostedBody();
187
188 1
        if (empty($request['challenge'])) {
189
            throw new BotonomousException('Challenge is missing for URL verification');
190
        }
191
192 1
        echo $request['challenge'];
193 1
    }
194
195
    /**
196
     * Pre-process the request.
197
     *
198
     * @throws \Exception
199
     */
200 3
    private function preProcessRequest()
201
    {
202 3
        $request = $this->getListener()->getRequest();
203
204
        // remove the trigger_word from beginning of the message
205 3
        if (!empty($request['trigger_word'])) {
206 3
            $request['text'] = $this->getMessageUtility()->removeTriggerWord(
207 3
                $request['text'],
208 3
                $request['trigger_word']
209
            );
210
211 3
            $this->getListener()->setRequest($request);
212
        }
213 3
    }
214
215
    /**
216
     * @param null $message
217
     *
218
     * @throws \Exception
219
     *
220
     * @return mixed
221
     */
222 4
    public function respond($message = null)
223
    {
224
        try {
225
            // If message is not set, get it from the current request
226 4
            if ($message === null) {
227 3
                $message = $this->getListener()->getMessage();
228
            }
229
230 4
            $commandExtractor = $this->getCommandExtractor();
231 4
            $command = $commandExtractor->getCommandByMessage($message);
232
233 4
            if (!$command instanceof Command) {
234
                // something went wrong, error will tell us!
235 2
                return $commandExtractor->getError();
236
            }
237
238 3
            $pluginClass = $this->getPluginClassByCommand($command);
239
240
            // check action exists
241 3
            $action = $command->getAction();
242 3
            if (!method_exists($pluginClass, $action)) {
243 1
                $className = get_class($pluginClass);
244
245 1
                throw new BotonomousException("Action / function: '{$action}' does not exist in '{$className}'");
246
            }
247
248 2
            return $pluginClass->$action();
249 1
        } catch (\Exception $e) {
250 1
            throw $e;
251
        }
252
    }
253
254
    /**
255
     * Get plugin class by command.
256
     *
257
     * @param Command $command
258
     *
259
     * @throws \Exception
260
     *
261
     * @return AbstractPlugin
262
     */
263 3
    private function getPluginClassByCommand(Command $command)
264
    {
265
        // create the class
266 3
        $pluginClassFile = $command->getClass();
267 3
        $pluginClass = new $pluginClassFile($this);
268
269
        // check class is valid
270 3
        if (!$pluginClass instanceof AbstractPlugin) {
271
            $className = get_class($pluginClass);
272
273
            throw new BotonomousException("Couldn't create class: '{$className}'");
274
        }
275
276 3
        return $pluginClass;
277
    }
278
279
    /**
280
     * @throws \Exception
281
     *
282
     * @return array
283
     */
284 2
    public function getCommands(): array
285
    {
286 2
        if (!isset($this->commands)) {
287 1
            $this->setCommands($this->getCommandContainer()->getAllAsObject());
288
        }
289
290 2
        return $this->commands;
291
    }
292
293
    /**
294
     * @param array $commands
295
     */
296 2
    public function setCommands(array $commands)
297
    {
298 2
        $this->commands = $commands;
299 2
    }
300
301
    /**
302
     * @return string
303
     */
304 1
    public function getLastError(): string
305
    {
306 1
        return $this->lastError;
307
    }
308
309
    /**
310
     * @param string $lastError
311
     */
312 1
    public function setLastError(string $lastError)
313
    {
314 1
        $this->lastError = $lastError;
315 1
    }
316
317
    /**
318
     * Return the current command.
319
     *
320
     * @return string
321
     */
322 1
    public function getCurrentCommand(): string
323
    {
324 1
        return $this->currentCommand;
325
    }
326
327
    /**
328
     * @param string $currentCommand
329
     */
330 2
    public function setCurrentCommand(string $currentCommand)
331
    {
332 2
        $this->currentCommand = $currentCommand;
333 2
    }
334
335
    /**
336
     * Determine if bot user id is mentioned in the message.
337
     *
338
     * @throws \Exception
339
     *
340
     * @return bool
341
     */
342 1
    public function youTalkingToMe(): bool
343
    {
344 1
        $message = $this->getListener()->getMessage();
345
346 1
        if (empty($message)) {
347 1
            return false;
348
        }
349
350 1
        if ($this->getMessageUtility()->isBotMentioned($message) === true) {
351 1
            return true;
352
        }
353
354 1
        $listener = $this->getListener();
355
        // check direct messages
356 1
        return $listener instanceof EventListener && $listener->getEvent()->isDirectMessage() === true;
357
    }
358
}
359