Skip to content

Feature/smartinterface #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 55 commits into from
Mar 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
566be6a
Tracking New Table Schema
MBoretto Feb 18, 2016
f533ecd
Merge branch 'new_command_structure_alpha' into feature/smartinterface
MBoretto Feb 19, 2016
57ed52b
Merge branch 'new_command_structure_alpha' into feature/smartinterface
MBoretto Feb 19, 2016
a8ea577
tracking works
MBoretto Feb 19, 2016
84267c3
resolve conflict
MBoretto Feb 23, 2016
8fbc160
new amazing /senttochannel command
MBoretto Feb 24, 2016
6a0d3d3
Merge remote-tracking branch 'upstream/develop' into feature/smartint…
MBoretto Feb 24, 2016
4a788a3
Renaming to Conversation, Readme
MBoretto Feb 24, 2016
1ca2887
bugfix conversation are not overwritten
MBoretto Feb 25, 2016
4df1b58
fix entities test
MBoretto Feb 25, 2016
672f622
Allow backwards compatibility when managing only one channel.
noplanman Feb 25, 2016
e02f104
Correct typos and minor code styling.
noplanman Feb 25, 2016
c51f8d5
Merge pull request #2 from noplanman/conversations_typos
MBoretto Feb 26, 2016
eda8c21
Merge pull request #1 from noplanman/feature/smartinterface
MBoretto Feb 26, 2016
8a15256
some fix
MBoretto Feb 26, 2016
5adfab2
fix bug retipe command
MBoretto Feb 26, 2016
a93bf5b
sent to channel works without configuration
MBoretto Feb 26, 2016
521fc15
introducing /cancel command
MBoretto Feb 26, 2016
f41e8a5
Added code block
MBoretto Feb 26, 2016
0a3ee2e
1-line sendtochannel without db
MBoretto Feb 26, 2016
75468f6
Merge remote-tracking branch 'upstream/develop' into feature/smartint…
MBoretto Feb 26, 2016
408085f
using new REQUEST emptyresponse
MBoretto Feb 26, 2016
02bdd0a
Let the user know which conversation has been cancelled.
noplanman Feb 26, 2016
93152b3
no Db is not shown
MBoretto Feb 27, 2016
b5e2203
Merge pull request #4 from MBoretto/cancel_command
MBoretto Feb 27, 2016
aff6c03
conversation as internal member
MBoretto Feb 27, 2016
00bcf78
Remove conversation group for now.
noplanman Feb 28, 2016
8667819
Fix generic message command to use new conversation methods.
noplanman Feb 28, 2016
61d732c
Update database schema.
noplanman Feb 28, 2016
6f7e361
Fix commands that use conversations to use corrected methods.
noplanman Feb 28, 2016
685db12
Modify ConversationDB to use new database schema and names.
noplanman Feb 28, 2016
5f7ec80
Merge remote-tracking branch 'mboretto/feature/smartinterface' into c…
noplanman Feb 28, 2016
e4483de
introducing conversation notes
MBoretto Feb 29, 2016
19258c1
renaming data in notes
MBoretto Feb 29, 2016
6dbab38
Merge pull request #6 from noplanman/conversations_code_review
MBoretto Feb 29, 2016
8c359b2
works without update
MBoretto Feb 29, 2016
7238e75
Merge branch 'noplan_conversation' into feature/smartinterface
MBoretto Feb 29, 2016
c917fa7
Merge branch 'structure' into feature/smartinterface
MBoretto Mar 4, 2016
cb4e9be
removing null from primary keys
MBoretto Mar 4, 2016
bdf46a2
Some typo corrections.
noplanman Mar 5, 2016
0567c8c
Merge pull request #7 from noplanman/fix_typos
MBoretto Mar 5, 2016
f302c73
introduce noplanman suggestion
MBoretto Mar 6, 2016
33dd4a8
reintroduced update()
MBoretto Mar 8, 2016
291b90f
Merge pull request #8 from MBoretto/repair
MBoretto Mar 8, 2016
8855585
Remove unused $command_is_provided variable.
noplanman Mar 10, 2016
92608fd
Add clear() method to reset internal conversation variables when canc…
noplanman Mar 10, 2016
7db0a91
Fix how the /sendtochannel command is ended.
noplanman Mar 11, 2016
b8e3b4b
Fix exception handling for ConversationDB.
noplanman Mar 11, 2016
ca9bff2
Add conversation tests and a few matching helpers.
noplanman Mar 11, 2016
60cf814
change delete in order to avoid integrity constraint
MBoretto Mar 13, 2016
97755aa
Merge pull request #2 from MBoretto/changedeleteorder
noplanman Mar 13, 2016
0ae4fd1
Merge branch 'develop' into feature/smartinterface
MBoretto Mar 13, 2016
8a5a5c5
Merge branch 'feature/smartinterface' of https://github.com/MBoretto/…
MBoretto Mar 13, 2016
2858ff5
Merge pull request #9 from noplanman/small_cleanup_fixes
MBoretto Mar 13, 2016
7d434dd
Merge pull request #10 from noplanman/add_conversation_tests
MBoretto Mar 13, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ You can also store inline query and chosen inline query in the database.
### Channels Support

All methods implemented can be used to manage channels.
With [admin commands](#admin-commands) you can manage your channel directly with your bot private chat.
With [admin commands](#admin-commands) you can manage your channels directly with your bot private chat.

### Commands

Expand Down Expand Up @@ -397,7 +397,7 @@ $telegram->setCommandConfig('date', ['google_api_key' => 'your_google_api_key_he
Enabling this feature, the admin bot can perform some super user commands like:
- Send message to all chats */sendtoall*
- List all the chats started with the bot */chats*
- Send a message to a channel */sendtochannel* (NEW! see below how to configure it)
- Send a message to your channels */sendtochannel* (NEW! see below how to configure it)
You can specify one or more admins with this option:

```php
Expand All @@ -414,7 +414,11 @@ To enable this feature follow these steps:
- Enable admin interface for your user as explained in the admin section above.
- Enter your channel name as a parameter for the */sendtochannel* command:
```php
$telegram->setCommandConfig('sendtochannel', ['your_channel' => '@type_here_your_channel']);
$telegram->setCommandConfig('sendtochannel', ['your_channel' => ['@type_here_your_channel']]);
```
- If you want to manage more channels:
```php
$telegram->setCommandConfig('sendtochannel', ['your_channel'=>['@type_here_your_channel', '@type_here_another_channel', '@and_so_on']]);
```
- Enjoy!

Expand Down
319 changes: 292 additions & 27 deletions src/Commands/AdminCommands/SendtochannelCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@

namespace Longman\TelegramBot\Commands\AdminCommands;

use Longman\TelegramBot\Commands\AdminCommand;
use Longman\TelegramBot\Request;
use Longman\TelegramBot\Conversation;
use Longman\TelegramBot\Commands\AdminCommand;
use Longman\TelegramBot\Entities\Message;
use Longman\TelegramBot\Entities\ReplyKeyboardHide;
use Longman\TelegramBot\Entities\ReplyKeyboardMarkup;
use Longman\TelegramBot\Exception\TelegramException;

/**
* Admin "/sendtochannel" command
*/
class SendtochannelCommand extends AdminCommand
{
/**#@+
Expand All @@ -24,46 +26,309 @@ class SendtochannelCommand extends AdminCommand
protected $name = 'sendtochannel';
protected $description = 'Send message to a channel';
protected $usage = '/sendtochannel <message to send>';
protected $version = '0.1.1';
protected $need_mysql = false;
protected $version = '0.1.4';
protected $need_mysql = true;
/**#@-*/

/**
* Execute command
* Conversation Object
*
* @todo Don't use empty, as a string of '0' is regarded to be empty
*
* @return boolean
* @var Longman\TelegramBot\Conversation
*/
protected $conversation;

/**
* {@inheritdoc}
*/
public function execute()
{
$message = $this->getMessage();
$chat_id = $message->getChat()->getId();
$user_id = $message->getFrom()->getId();
$type = $message->getType();
// 'Cast' the command type into message this protect the machine state
// if the commmad is recolled when the conversation is already started
$type = ($type == 'command') ? 'Message' : $type;
$text = trim($message->getText(true));

$data = [];
$data['chat_id'] = $chat_id;

// Conversation
$this->conversation = new Conversation($user_id, $chat_id, $this->getName());

$channels = (array) $this->getConfig('your_channel');
if (!isset($this->conversation->notes['state'])) {
$state = (count($channels) == 0) ? -1 : 0;
$this->conversation->notes['last_message_id'] = $message->getMessageId();
} else {
$state = $this->conversation->notes['state'];
}
switch ($state) {
case -1:
// getConfig has not been configured asking for channel to administer
if ($type != 'Message' || empty($text)) {
$this->conversation->notes['state'] = -1;
$this->conversation->update();

$data['text'] = 'Insert the channel name: (@yourchannel)';
$data['reply_markup'] = new ReplyKeyBoardHide(['selective' => true]);
$result = Request::sendMessage($data);

break;
}
$this->conversation->notes['channel'] = $text;
$this->conversation->notes['last_message_id'] = $message->getMessageId();
// Jump to state 1
goto insert;

// no break
default:
case 0:
// getConfig has been configured choose channel
if ($type != 'Message' || !in_array($text, $channels)) {
$this->conversation->notes['state'] = 0;
$this->conversation->update();

$keyboard = [];
foreach ($channels as $channel) {
$keyboard[] = [$channel];
}
$reply_keyboard_markup = new ReplyKeyboardMarkup(
[
'keyboard' => $keyboard ,
'resize_keyboard' => true,
'one_time_keyboard' => true,
'selective' => true
]
);
$data['reply_markup'] = $reply_keyboard_markup;
$data['text'] = 'Select a channel';
if ($type != 'Message' || !in_array($text, $channels)) {
$data['text'] = 'Select a channel from the keyboard:';
}
$result = Request::sendMessage($data);
break;
}
$this->conversation->notes['channel'] = $text;
$this->conversation->notes['last_message_id'] = $message->getMessageId();

// no break
case 1:
insert:
if ($this->conversation->notes['last_message_id'] == $message->getMessageId() || ($type == 'Message' && empty($text))) {
$this->conversation->notes['state'] = 1;
$this->conversation->update();

$data['reply_markup'] = new ReplyKeyBoardHide(['selective' => true]);
$data['text'] = 'Insert the content you want to share: text, photo, audio...';
$result = Request::sendMessage($data);
break;
}
$this->conversation->notes['last_message_id'] = $message->getMessageId();
$this->conversation->notes['message'] = $message->reflect();
$this->conversation->notes['message_type'] = $type;

// no break
case 2:
if ($this->conversation->notes['last_message_id'] == $message->getMessageId() || !($text == 'Yes' || $text == 'No')) {
$this->conversation->notes['state'] = 2;
$this->conversation->update();

// Execute this just with object that allow caption
if ($this->conversation->notes['message_type'] == 'Video' || $this->conversation->notes['message_type'] == 'Photo') {
$keyboard = [['Yes', 'No']];
$reply_keyboard_markup = new ReplyKeyboardMarkup(
[
'keyboard' => $keyboard ,
'resize_keyboard' => true,
'one_time_keyboard' => true,
'selective' => true
]
);
$data['reply_markup'] = $reply_keyboard_markup;

$data['text'] = 'Would you insert caption?';
if ($this->conversation->notes['last_message_id'] != $message->getMessageId() && !($text == 'Yes' || $text == 'No')) {
$data['text'] = 'Would you insert a caption?' . "\n" . 'Type Yes or No';
}
$result = Request::sendMessage($data);
break;
}
}
$this->conversation->notes['set_caption'] = false;
if ($text == 'Yes') {
$this->conversation->notes['set_caption'] = true;
}
$this->conversation->notes['last_message_id'] = $message->getMessageId();
// no break
case 3:
if (($this->conversation->notes['last_message_id'] == $message->getMessageId() || $type != 'Message' ) && $this->conversation->notes['set_caption']) {
$this->conversation->notes['state'] = 3;
$this->conversation->update();

$data['text'] = 'Insert caption:';
$data['reply_markup'] = new ReplyKeyBoardHide(['selective' => true]);
$result = Request::sendMessage($data);
break;
}
$this->conversation->notes['last_message_id'] = $message->getMessageId();
$this->conversation->notes['caption'] = $text;
// no break
case 4:
if ($this->conversation->notes['last_message_id'] == $message->getMessageId() || !($text == 'Yes' || $text == 'No')) {
$this->conversation->notes['state'] = 4;
$this->conversation->update();

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

if ($this->conversation->notes['message_type'] != 'command') {
if ($this->conversation->notes['set_caption']) {
$data['caption'] = $this->conversation->notes['caption'];
}
$result = $this->sendBack(new Message($this->conversation->notes['message'], 'thisbot'), $data);

$data['text'] = 'Would you post it?';
if ($this->conversation->notes['last_message_id'] != $message->getMessageId() && !($text == 'Yes' || $text == 'No')) {
$data['text'] = 'Would you post it?' . "\n" . 'Press Yes or No';
}
$keyboard = [['Yes', 'No']];
$reply_keyboard_markup = new ReplyKeyboardMarkup(
[
'keyboard' => $keyboard ,
'resize_keyboard' => true,
'one_time_keyboard' => true,
'selective' => true
]
);
$data['reply_markup'] = $reply_keyboard_markup;
$result = Request::sendMessage($data);
}
break;
}

$this->conversation->notes['post_message'] = false;
if ($text == 'Yes') {
$this->conversation->notes['post_message'] = true;
}
$this->conversation->notes['last_message_id'] = $message->getMessageId();
// no break
case 5:
$data['reply_markup'] = new ReplyKeyBoardHide(['selective' => true]);

if ($this->conversation->notes['post_message']) {
$data['text'] = $this->publish(
new Message($this->conversation->notes['message'], 'anystring'),
$this->conversation->notes['channel'],
$this->conversation->notes['caption']
);
} else {
$data['text'] = 'Abort by user, message not sent..';
}

$this->conversation->stop();
$result = Request::sendMessage($data);
}
return $result;
}

/**
* {@inheritdoc}
*/
public function executeNoDB()
{
$message = $this->getMessage();
$text = trim($message->getText(true));
$chat_id = $message->getChat()->getId();
$text = $message->getText(true);

$data = [];
$data['chat_id'] = $chat_id;

if (empty($text)) {
$text_back = 'Write the message to send: /sendtochannel <message>';
$data['text'] = 'Usage: /sendtochannel <text>';
} else {
$your_channel = $this->getConfig('your_channel');
//Send message to channel
$data = [
'chat_id' => $your_channel,
'text' => $text,
];

if (Request::sendMessage($data)->isOk()) {
$text_back = 'Message sent succesfully to: ' . $your_channel;
} else {
$text_back = 'Sorry message not sent to: ' . $your_channel;
}
$channels = (array) $this->getConfig('your_channel');
$first_channel = $channels[0];
$data['text'] = $this->publish(new Message($message->reflect(), 'anystring'), $first_channel);
}
return Request::sendMessage($data);
}

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

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

/**
* SendBack
*
* Received a message, the bot can send a copy of it to another chat/channel.
* You don't have to care about the type of the message, the function detect it and use the proper
* REQUEST:: function to send it.
* $data include all the var that you need to send the message to the proper chat
*
* @todo This method will be moved at an higher level maybe in AdminCommand or Command
* @todo Looking for a more significative name
*
* @param Entities\Message $message
* @param array $data
*
* @return Entities\ServerResponse
*/
protected function sendBack(Message $message, array $data)
{
$type = $message->getType();
$type = ($type == 'command') ? 'Message' : $type;
if ($type == 'Message') {
$data['text'] = $message->getText(true);
} elseif ($type == 'Audio') {
$data['audio'] = $message->getAudio()->getFileId();
$data['duration'] = $message->getAudio()->getDuration();
$data['performer'] = $message->getAudio()->getPerformer();
$data['title'] = $message->getAudio()->getTitle();
} elseif ($type == 'Document') {
$data['document'] = $message->getDocument()->getFileId();
} elseif ($type == 'Photo') {
$data['photo'] = $message->getPhoto()[0]->getFileId();
} elseif ($type == 'Sticker') {
$data['sticker'] = $message->getSticker()->getFileId();
} elseif ($type == 'Video') {
$data['video'] = $message->getVideo()->getFileId();
} elseif ($type == 'Voice') {
$data['voice'] = $message->getVoice()->getFileId();
} elseif ($type == 'Location') {
$data['latitude'] = $message->getLocation()->getLatitude();
$data['longitude'] = $message->getLocation()->getLongitude();
}
$callback_path = 'Longman\TelegramBot\Request';
$callback_function = 'send' . $type;
if (! method_exists($callback_path, $callback_function)) {
throw new TelegramException('Methods: ' . $callback_function . ' not found in class Request.');
}

return call_user_func_array($callback_path . '::' . $callback_function, [$data]);
}
}
1 change: 0 additions & 1 deletion src/Commands/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ public function executeNoDB()
return Request::sendMessage($data);
}


/**
* Get update object
*
Expand Down
Loading