SendtochannelCommand.php 13.4 KB
Newer Older
MBoretto's avatar
MBoretto committed
1
<?php
MBoretto's avatar
MBoretto committed
2
/**
MBoretto's avatar
MBoretto committed
3 4 5 6 7 8
 * This file is part of the TelegramBot package.
 *
 * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
9
 */
MBoretto's avatar
MBoretto committed
10

11
namespace Longman\TelegramBot\Commands\AdminCommands;
MBoretto's avatar
MBoretto committed
12

13
use Longman\TelegramBot\Entities\Keyboard;
14
use Longman\TelegramBot\Request;
15
use Longman\TelegramBot\Conversation;
MBoretto's avatar
MBoretto committed
16
use Longman\TelegramBot\Commands\AdminCommand;
17
use Longman\TelegramBot\Entities\Message;
MBoretto's avatar
MBoretto committed
18
use Longman\TelegramBot\Exception\TelegramException;
MBoretto's avatar
MBoretto committed
19

20
class SendtochannelCommand extends AdminCommand
MBoretto's avatar
MBoretto committed
21
{
22 23
    /**
     * @var string
24
     */
MBoretto's avatar
MBoretto committed
25
    protected $name = 'sendtochannel';
26 27 28 29

    /**
     * @var string
     */
MBoretto's avatar
MBoretto committed
30
    protected $description = 'Send message to a channel';
31 32 33 34

    /**
     * @var string
     */
35
    protected $usage = '/sendtochannel <message to send>';
36 37 38 39

    /**
     * @var string
     */
40
    protected $version = '0.2.0';
41 42 43 44

    /**
     * @var bool
     */
45
    protected $need_mysql = true;
MBoretto's avatar
MBoretto committed
46

47 48 49
    /**
     * Conversation Object
     *
MBoretto's avatar
MBoretto committed
50
     * @var \Longman\TelegramBot\Conversation
51 52 53
     */
    protected $conversation;

54
    /**
55 56 57
     * Command execute method
     *
     * @return \Longman\TelegramBot\Entities\ServerResponse|mixed
58
     * @throws \Longman\TelegramBot\Exception\TelegramException
59
     */
MBoretto's avatar
MBoretto committed
60 61 62
    public function execute()
    {
        $message = $this->getMessage();
MBoretto's avatar
MBoretto committed
63 64
        $chat_id = $message->getChat()->getId();
        $user_id = $message->getFrom()->getId();
65

66 67 68
        $type = $message->getType();
        // 'Cast' the command type into message to protect the machine state
        // if the commmad is recalled when the conversation is already started
69
        in_array($type, ['command', 'text'], true) && $type = 'message';
70 71 72 73 74 75 76

        $text           = trim($message->getText(true));
        $text_yes_or_no = ($text === 'Yes' || $text === 'No');

        $data = [
            'chat_id' => $chat_id,
        ];
77

78
        // Conversation
79
        $this->conversation = new Conversation($user_id, $chat_id, $this->getName());
80 81 82

        $notes = &$this->conversation->notes;
        !is_array($notes) && $notes = [];
83

84
        $channels = (array)$this->getConfig('your_channel');
85 86
        if (isset($notes['state'])) {
            $state = $notes['state'];
MBoretto's avatar
MBoretto committed
87
        } else {
88 89
            $state                    = (count($channels) === 0) ? -1 : 0;
            $notes['last_message_id'] = $message->getMessageId();
MBoretto's avatar
MBoretto committed
90
        }
91

92 93 94
        switch ($state) {
            case -1:
                // getConfig has not been configured asking for channel to administer
95
                if ($type !== 'message' || $text === '') {
96
                    $notes['state'] = -1;
MBoretto's avatar
MBoretto committed
97
                    $this->conversation->update();
98

99
                    $data['text']         = 'Insert the channel name: (@yourchannel)';
100
                    $data['reply_markup'] = Keyboard::remove(['selective' => true]);
101
                    $result               = Request::sendMessage($data);
102 103 104

                    break;
                }
105 106
                $notes['channel']         = $text;
                $notes['last_message_id'] = $message->getMessageId();
107 108 109
                // Jump to state 1
                goto insert;

110
            // no break
111 112
            default:
            case 0:
113
                // getConfig has been configured choose channel
114
                if ($type !== 'message' || !in_array($text, $channels, true)) {
115
                    $notes['state'] = 0;
MBoretto's avatar
MBoretto committed
116
                    $this->conversation->update();
117

118 119 120 121
                    $keyboard = [];
                    foreach ($channels as $channel) {
                        $keyboard[] = [$channel];
                    }
122
                    $data['reply_markup'] = new Keyboard(
123
                        [
124 125
                            'keyboard'          => $keyboard,
                            'resize_keyboard'   => true,
126
                            'one_time_keyboard' => true,
127
                            'selective'         => true,
128 129
                        ]
                    );
130 131 132

                    $data['text'] = 'Select a channel from the keyboard:';
                    $result       = Request::sendMessage($data);
133 134
                    break;
                }
135 136
                $notes['channel']         = $text;
                $notes['last_message_id'] = $message->getMessageId();
137

138
            // no break
139
            case 1:
140
                insert:
141
                if (($type === 'message' && $text === '') || $notes['last_message_id'] === $message->getMessageId()) {
142
                    $notes['state'] = 1;
MBoretto's avatar
MBoretto committed
143
                    $this->conversation->update();
144

145
                    $data['reply_markup'] = Keyboard::remove(['selective' => true]);
146 147
                    $data['text']         = 'Insert the content you want to share: text, photo, audio...';
                    $result               = Request::sendMessage($data);
148 149
                    break;
                }
150
                $notes['last_message_id'] = $message->getMessageId();
151
                $notes['message']         = $message->getRawData();
152
                $notes['message_type']    = $type;
153
            // no break
154
            case 2:
155 156
                if (!$text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
                    $notes['state'] = 2;
MBoretto's avatar
MBoretto committed
157
                    $this->conversation->update();
158

159
                    // Execute this just with object that allow caption
160 161
                    if (in_array($notes['message_type'], ['video', 'photo'], true)) {
                        $data['reply_markup'] = new Keyboard(
162
                            [
163
                                'keyboard'          => [['Yes', 'No']],
164
                                'resize_keyboard'   => true,
165
                                'one_time_keyboard' => true,
166
                                'selective'         => true,
167 168 169
                            ]
                        );

170 171 172
                        $data['text'] = 'Would you like to insert a caption?';
                        if (!$text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
                            $data['text'] .= PHP_EOL . 'Type Yes or No';
173 174 175 176 177
                        }
                        $result = Request::sendMessage($data);
                        break;
                    }
                }
178 179
                $notes['set_caption']     = ($text === 'Yes');
                $notes['last_message_id'] = $message->getMessageId();
180
            // no break
181
            case 3:
182
                if ($notes['set_caption'] && ($notes['last_message_id'] === $message->getMessageId() || $type !== 'message')) {
183
                    $notes['state'] = 3;
MBoretto's avatar
MBoretto committed
184
                    $this->conversation->update();
185

186
                    $data['text']         = 'Insert caption:';
187
                    $data['reply_markup'] = Keyboard::remove(['selective' => true]);
188
                    $result               = Request::sendMessage($data);
189 190
                    break;
                }
191 192
                $notes['last_message_id'] = $message->getMessageId();
                $notes['caption']         = $text;
193
            // no break
194
            case 4:
195 196
                if (!$text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
                    $notes['state'] = 4;
MBoretto's avatar
MBoretto committed
197
                    $this->conversation->update();
198 199

                    $data['text'] = 'Message will look like this:';
200
                    $result       = Request::sendMessage($data);
201

202 203 204
                    if ($notes['message_type'] !== 'command') {
                        if ($notes['set_caption']) {
                            $data['caption'] = $notes['caption'];
205
                        }
206
                        $this->sendBack(new Message($notes['message'], $this->telegram->getBotName()), $data);
207

208
                        $data['reply_markup'] = new Keyboard(
209
                            [
210
                                'keyboard'          => [['Yes', 'No']],
211
                                'resize_keyboard'   => true,
212
                                'one_time_keyboard' => true,
213
                                'selective'         => true,
214 215
                            ]
                        );
216 217 218 219 220 221

                        $data['text'] = 'Would you like to post it?';
                        if (!$text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
                            $data['text'] .= PHP_EOL . 'Type Yes or No';
                        }
                        $result = Request::sendMessage($data);
222 223 224 225
                    }
                    break;
                }

226 227
                $notes['post_message']    = ($text === 'Yes');
                $notes['last_message_id'] = $message->getMessageId();
228
            // no break
229
            case 5:
230
                $data['reply_markup'] = Keyboard::remove(['selective' => true]);
231

232
                if ($notes['post_message']) {
233
                    $data['text'] = $this->publish(
234 235 236
                        new Message($notes['message'], $this->telegram->getBotName()),
                        $notes['channel'],
                        $notes['caption']
237 238 239
                    );
                } else {
                    $data['text'] = 'Abort by user, message not sent..';
240
                }
241

242
                $this->conversation->stop();
243 244
                $result = Request::sendMessage($data);
        }
245

246
        return $result;
247 248
    }

249
    /**
250 251 252
     * SendBack
     *
     * Received a message, the bot can send a copy of it to another chat/channel.
MBoretto's avatar
MBoretto committed
253
     * You don't have to care about the type of the message, the function detect it and use the proper
254
     * REQUEST:: function to send it.
MBoretto's avatar
MBoretto committed
255
     * $data include all the var that you need to send the message to the proper chat
256
     *
257 258
     * @todo This method will be moved to a higher level maybe in AdminCommand or Command
     * @todo Looking for a more significant name
259
     *
MBoretto's avatar
MBoretto committed
260
     * @param \Longman\TelegramBot\Entities\Message $message
261
     * @param array                                 $data
262
     *
MBoretto's avatar
MBoretto committed
263
     * @return \Longman\TelegramBot\Entities\ServerResponse
264
     * @throws \Longman\TelegramBot\Exception\TelegramException
265
     */
266
    protected function sendBack(Message $message, array $data)
267 268
    {
        $type = $message->getType();
269 270 271
        in_array($type, ['command', 'text'], true) && $type = 'message';

        if ($type === 'message') {
272
            $data['text'] = $message->getText(true);
273
        } elseif ($type === 'audio') {
274 275
            $data['audio']     = $message->getAudio()->getFileId();
            $data['duration']  = $message->getAudio()->getDuration();
276
            $data['performer'] = $message->getAudio()->getPerformer();
277
            $data['title']     = $message->getAudio()->getTitle();
278
        } elseif ($type === 'document') {
279
            $data['document'] = $message->getDocument()->getFileId();
280
        } elseif ($type === 'photo') {
281
            $data['photo'] = $message->getPhoto()[0]->getFileId();
282
        } elseif ($type === 'sticker') {
283
            $data['sticker'] = $message->getSticker()->getFileId();
284
        } elseif ($type === 'video') {
285
            $data['video'] = $message->getVideo()->getFileId();
286
        } elseif ($type === 'voice') {
287
            $data['voice'] = $message->getVoice()->getFileId();
288
        } elseif ($type === 'location') {
289
            $data['latitude']  = $message->getLocation()->getLatitude();
290 291
            $data['longitude'] = $message->getLocation()->getLongitude();
        }
292

293
        $callback_path     = 'Longman\TelegramBot\Request';
294
        $callback_function = 'send' . ucfirst($type);
295
        if (!method_exists($callback_path, $callback_function)) {
296
            throw new TelegramException('Methods: ' . $callback_function . ' not found in class Request.');
297
        }
MBoretto's avatar
MBoretto committed
298

299
        return $callback_path::$callback_function($data);
MBoretto's avatar
MBoretto committed
300
    }
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345

    /**
     * Publish a message to a channel and return success or failure message
     *
     * @param \Longman\TelegramBot\Entities\Message $message
     * @param int                                   $channel
     * @param string|null                           $caption
     *
     * @return string
     * @throws \Longman\TelegramBot\Exception\TelegramException
     */
    protected function publish(Message $message, $channel, $caption = null)
    {
        $data = [
            'chat_id' => $channel,
            'caption' => $caption,
        ];

        if ($this->sendBack($message, $data)->isOk()) {
            $response = 'Message sent successfully to: ' . $channel;
        } else {
            $response = 'Message not sent to: ' . $channel . PHP_EOL .
                        '- Does the channel exist?' . PHP_EOL .
                        '- Is the bot an admin of the channel?';
        }

        return $response;
    }

    /**
     * Execute without db
     *
     * @todo Why send just to the first found channel?
     *
     * @return mixed
     * @throws \Longman\TelegramBot\Exception\TelegramException
     */
    public function executeNoDb()
    {
        $message = $this->getMessage();
        $chat_id = $message->getChat()->getId();
        $text    = trim($message->getText(true));

        $data = [
            'chat_id' => $chat_id,
346
            'text'    => 'Usage: ' . $this->getUsage(),
347 348 349 350 351
        ];

        if ($text !== '') {
            $channels      = (array)$this->getConfig('your_channel');
            $first_channel = $channels[0];
Armando Lüscher's avatar
Armando Lüscher committed
352
            $data['text']  = $this->publish(
353
                new Message($message->getRawData(), $this->telegram->getBotName()),
Armando Lüscher's avatar
Armando Lüscher committed
354 355
                $first_channel
            );
356 357 358 359
        }

        return Request::sendMessage($data);
    }
MBoretto's avatar
MBoretto committed
360
}