GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

SendtochannelCommand::executeNoDb()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 11
nc 3
nop 0
dl 0
loc 18
ccs 0
cts 12
cp 0
crap 12
rs 9.9
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot\Commands\AdminCommands;
13
14
use Longman\TelegramBot\Commands\AdminCommand;
15
use Longman\TelegramBot\Conversation;
16
use Longman\TelegramBot\Entities\Chat;
17
use Longman\TelegramBot\Entities\Entity;
18
use Longman\TelegramBot\Entities\Keyboard;
19
use Longman\TelegramBot\Entities\Message;
20
use Longman\TelegramBot\Entities\ServerResponse;
21
use Longman\TelegramBot\Exception\TelegramException;
22
use Longman\TelegramBot\Request;
23
24
class SendtochannelCommand extends AdminCommand
25
{
26
    /**
27
     * @var string
28
     */
29
    protected $name = 'sendtochannel';
30
31
    /**
32
     * @var string
33
     */
34
    protected $description = 'Send message to a channel';
35
36
    /**
37
     * @var string
38
     */
39
    protected $usage = '/sendtochannel <message to send>';
40
41
    /**
42
     * @var string
43
     */
44
    protected $version = '0.3.0';
45
46
    /**
47
     * @var bool
48
     */
49
    protected $need_mysql = true;
50
51
    /**
52
     * Conversation Object
53
     *
54
     * @var Conversation
55
     */
56
    protected $conversation;
57
58
    /**
59
     * Command execute method
60
     *
61
     * @return ServerResponse|mixed
62
     * @throws TelegramException
63
     */
64
    public function execute(): ServerResponse
65
    {
66
        $message = $this->getMessage();
67
        $chat_id = $message->getChat()->getId();
68
        $user_id = $message->getFrom()->getId();
69
70
        $type = $message->getType();
71
        // 'Cast' the command type to message to protect the machine state
72
        // if the command is recalled when the conversation is already started
73
        in_array($type, ['command', 'text'], true) && $type = 'message';
74
75
        $text           = trim($message->getText(true));
76
        $text_yes_or_no = ($text === 'Yes' || $text === 'No');
77
78
        $data = [
79
            'chat_id' => $chat_id,
80
        ];
81
82
        // Conversation
83
        $this->conversation = new Conversation($user_id, $chat_id, $this->getName());
84
85
        $notes = &$this->conversation->notes;
86
        !is_array($notes) && $notes = [];
87
88
        $channels = (array) $this->getConfig('your_channel');
89
        if (isset($notes['state'])) {
90
            $state = $notes['state'];
91
        } else {
92
            $state                    = (count($channels) === 0) ? -1 : 0;
93
            $notes['last_message_id'] = $message->getMessageId();
94
        }
95
96
        $yes_no_keyboard = new Keyboard(
97
            [
98
                'keyboard'          => [['Yes', 'No']],
99
                'resize_keyboard'   => true,
100
                'one_time_keyboard' => true,
101
                'selective'         => true,
102
            ]
103
        );
104
105
        switch ($state) {
106
            case -1:
107
                // getConfig has not been configured asking for channel to administer
108
                if ($type !== 'message' || $text === '') {
109
                    $notes['state'] = -1;
110
                    $this->conversation->update();
111
112
                    $result = $this->replyToChat(
113
                        'Insert the channel name or ID (_@yourchannel_ or _-12345_)',
114
                        [
115
                            'parse_mode'   => 'markdown',
116
                            'reply_markup' => Keyboard::remove(['selective' => true]),
117
                        ]
118
                    );
119
120
                    break;
121
                }
122
                $notes['channel']         = $text;
123
                $notes['last_message_id'] = $message->getMessageId();
124
                // Jump to state 1
125
                goto insert;
126
127
            // no break
128
            default:
129
            case 0:
130
                // getConfig has been configured choose channel
131
                if ($type !== 'message' || $text === '') {
132
                    $notes['state'] = 0;
133
                    $this->conversation->update();
134
135
                    $keyboard = array_map(function ($channel) {
136
                        return [$channel];
137
                    }, $channels);
138
139
                    $result = $this->replyToChat(
140
                        'Choose a channel from the keyboard' . PHP_EOL .
141
                        '_or_ insert the channel name or ID (_@yourchannel_ or _-12345_)',
142
                        [
143
                            'parse_mode'   => 'markdown',
144
                            'reply_markup' => new Keyboard(
145
                                [
146
                                    'keyboard'          => $keyboard,
147
                                    'resize_keyboard'   => true,
148
                                    'one_time_keyboard' => true,
149
                                    'selective'         => true,
150
                                ]
151
                            ),
152
                        ]
153
                    );
154
                    break;
155
                }
156
                $notes['channel']         = $text;
157
                $notes['last_message_id'] = $message->getMessageId();
158
159
            // no break
160
            case 1:
161
                insert:
162
                if (($type === 'message' && $text === '') || $notes['last_message_id'] === $message->getMessageId()) {
163
                    $notes['state'] = 1;
164
                    $this->conversation->update();
165
166
                    $result = $this->replyToChat(
167
                        'Insert the content you want to share: text, photo, audio...',
168
                        ['reply_markup' => Keyboard::remove(['selective' => true])]
169
                    );
170
                    break;
171
                }
172
                $notes['last_message_id'] = $message->getMessageId();
173
                $notes['message']         = $message->getRawData();
174
                $notes['message_type']    = $type;
175
            // no break
176
            case 2:
177
                if (!$text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
178
                    $notes['state'] = 2;
179
                    $this->conversation->update();
180
181
                    // Grab any existing caption.
182
                    if ($caption = $message->getCaption()) {
183
                        $notes['caption'] = $caption;
184
                        $text             = 'No';
185
                    } elseif (in_array($notes['message_type'], ['video', 'photo'], true)) {
186
                        $text = 'Would you like to insert a caption?';
187
                        if (!$text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
188
                            $text .= PHP_EOL . 'Type Yes or No';
189
                        }
190
191
                        $result = $this->replyToChat(
192
                            $text,
193
                            ['reply_markup' => $yes_no_keyboard]
194
                        );
195
                        break;
196
                    }
197
                }
198
                $notes['set_caption']     = ($text === 'Yes');
199
                $notes['last_message_id'] = $message->getMessageId();
200
            // no break
201
            case 3:
202
                if ($notes['set_caption'] && ($notes['last_message_id'] === $message->getMessageId() || $type !== 'message')) {
203
                    $notes['state'] = 3;
204
                    $this->conversation->update();
205
206
                    $result = $this->replyToChat(
207
                        'Insert caption:',
208
                        ['reply_markup' => Keyboard::remove(['selective' => true])]
209
                    );
210
                    break;
211
                }
212
                $notes['last_message_id'] = $message->getMessageId();
213
                if (isset($notes['caption'])) {
214
                    // If caption has already been send with the file, no need to ask for it.
215
                    $notes['set_caption'] = true;
216
                } else {
217
                    $notes['caption'] = $text;
218
                }
219
            // no break
220
            case 4:
221
                if (!$text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
222
                    $notes['state'] = 4;
223
                    $this->conversation->update();
224
225
                    $result = $this->replyToChat('Message will look like this:');
226
227
                    if ($notes['message_type'] !== 'command') {
228
                        if ($notes['set_caption']) {
229
                            $data['caption'] = $notes['caption'];
230
                        }
231
                        $this->sendBack(new Message($notes['message'], $this->telegram->getBotUsername()), $data);
232
233
                        $data['reply_markup'] = $yes_no_keyboard;
234
235
                        $data['text'] = 'Would you like to post it?';
236
                        if (!$text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
237
                            $data['text'] .= PHP_EOL . 'Type Yes or No';
238
                        }
239
                        $result = Request::sendMessage($data);
240
                    }
241
                    break;
242
                }
243
244
                $notes['post_message']    = ($text === 'Yes');
245
                $notes['last_message_id'] = $message->getMessageId();
246
            // no break
247
            case 5:
248
                $data['reply_markup'] = Keyboard::remove(['selective' => true]);
249
250
                if ($notes['post_message']) {
251
                    $data['parse_mode'] = 'markdown';
252
                    $data['text']       = $this->publish(
253
                        new Message($notes['message'], $this->telegram->getBotUsername()),
254
                        $notes['channel'],
255
                        $notes['caption']
256
                    );
257
                } else {
258
                    $data['text'] = 'Aborted by user, message not sent..';
259
                }
260
261
                $this->conversation->stop();
262
                $result = Request::sendMessage($data);
263
        }
264
265
        return $result;
266
    }
267
268
    /**
269
     * SendBack
270
     *
271
     * Received a message, the bot can send a copy of it to another chat/channel.
272
     * You don't have to care about the type of the message, the function detect it and use the proper
273
     * REQUEST:: function to send it.
274
     * $data include all the var that you need to send the message to the proper chat
275
     *
276
     * @todo This method will be moved to a higher level maybe in AdminCommand or Command
277
     * @todo Looking for a more significant name
278
     *
279
     * @param Message $message
280
     * @param array   $data
281
     *
282
     * @return ServerResponse
283
     * @throws TelegramException
284
     */
285
    protected function sendBack(Message $message, array $data): ServerResponse
286
    {
287
        $type = $message->getType();
288
        in_array($type, ['command', 'text'], true) && $type = 'message';
289
290
        if ($type === 'message') {
291
            $data['text'] = $message->getText(true);
292
        } elseif ($type === 'audio') {
293
            $data['audio']     = $message->getAudio()->getFileId();
294
            $data['duration']  = $message->getAudio()->getDuration();
295
            $data['performer'] = $message->getAudio()->getPerformer();
296
            $data['title']     = $message->getAudio()->getTitle();
297
        } elseif ($type === 'document') {
298
            $data['document'] = $message->getDocument()->getFileId();
299
        } elseif ($type === 'photo') {
300
            $data['photo'] = $message->getPhoto()[0]->getFileId();
301
        } elseif ($type === 'sticker') {
302
            $data['sticker'] = $message->getSticker()->getFileId();
303
        } elseif ($type === 'video') {
304
            $data['video'] = $message->getVideo()->getFileId();
305
        } elseif ($type === 'voice') {
306
            $data['voice'] = $message->getVoice()->getFileId();
307
        } elseif ($type === 'location') {
308
            $data['latitude']  = $message->getLocation()->getLatitude();
309
            $data['longitude'] = $message->getLocation()->getLongitude();
310
        }
311
312
        return Request::send('send' . ucfirst($type), $data);
313
    }
314
315
    /**
316
     * Publish a message to a channel and return success or failure message in markdown format
317
     *
318
     * @param Message     $message
319
     * @param string|int  $channel_id
320
     * @param string|null $caption
321
     *
322
     * @return string
323
     * @throws TelegramException
324
     */
325
    protected function publish(Message $message, $channel_id, $caption = null): string
326
    {
327
        $res = $this->sendBack($message, [
328
            'chat_id' => $channel_id,
329
            'caption' => $caption,
330
        ]);
331
332
        if ($res->isOk()) {
333
            /** @var Chat $channel */
334
            $channel          = $res->getResult()->getChat();
335
            $escaped_username = $channel->getUsername() ? Entity::escapeMarkdown($channel->getUsername()) : '';
336
337
            $response = sprintf(
338
                'Message successfully sent to *%s*%s',
339
                filter_var($channel->getTitle(), FILTER_SANITIZE_SPECIAL_CHARS),
340
                $escaped_username ? " (@{$escaped_username})" : ''
341
            );
342
        } else {
343
            $escaped_username = Entity::escapeMarkdown($channel_id);
344
            $response         = "Message not sent to *{$escaped_username}*" . PHP_EOL .
345
                                '- Does the channel exist?' . PHP_EOL .
346
                                '- Is the bot an admin of the channel?';
347
        }
348
349
        return $response;
350
    }
351
352
    /**
353
     * Execute without db
354
     *
355
     * @todo Why send just to the first found channel?
356
     *
357
     * @return mixed
358
     * @throws TelegramException
359
     */
360
    public function executeNoDb(): ServerResponse
361
    {
362
        $message = $this->getMessage();
363
        $text    = trim($message->getText(true));
364
365
        if ($text === '') {
366
            return $this->replyToChat('Usage: ' . $this->getUsage());
367
        }
368
369
        $channels = array_filter((array) $this->getConfig('your_channel'));
370
        if (empty($channels)) {
371
            return $this->replyToChat('No channels defined in the command config!');
372
        }
373
374
        return $this->replyToChat($this->publish(
375
            new Message($message->getRawData(), $this->telegram->getBotUsername()),
376
            reset($channels)
377
        ), ['parse_mode' => 'markdown']);
378
    }
379
}
380