mirror of
https://github.com/BushlanovDev/max-bot-api-client-php.git
synced 2026-08-30 12:07:05 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fa63fa10b | |||
| eb5f6c7bbe |
@@ -14,60 +14,115 @@
|
|||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
|
|
||||||
> Если вы новичок, то можете прочитать [официальную документацию](https://dev.max.ru/), написанную разработчиками Max
|
> Если вы новичок, то можете прочитать [официальную документацию](https://dev.max.ru/), написанную разработчиками Max.
|
||||||
|
|
||||||
### Получение токена
|
### Получение токена
|
||||||
|
|
||||||
Откройте диалог с [MasterBot](https://max.ru/MasterBot), следуйте инструкциям и создайте нового бота. После создания
|
Откройте диалог с [MasterBot](https://max.ru/MasterBot), следуйте инструкциям и создайте нового бота. После создания
|
||||||
бота MasterBot отправит вам токен.
|
бота MasterBot отправит вам токен.
|
||||||
|
|
||||||
|
### Установка библиотеки
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require bushlanov-dev/max-bot-api-client-php
|
||||||
|
```
|
||||||
|
|
||||||
|
### Использование
|
||||||
|
|
||||||
|
Отправка сообщения с клавиатурой
|
||||||
|
|
||||||
|
```php
|
||||||
|
$api = new \BushlanovDev\MaxMessengerBot\Api('YOUR_BOT_API_TOKEN');
|
||||||
|
|
||||||
|
$api->sendMessage(
|
||||||
|
userId: 123, // ID пользователя получателя сообщения
|
||||||
|
chatId: 321, // Или ID чата, в который нужно отправить сообщение
|
||||||
|
text: 'Привет!', // Текст сообщения, вы можете использовать HTML или Markdown
|
||||||
|
attachments: [
|
||||||
|
new InlineKeyboardAttachmentRequest([
|
||||||
|
[new CallbackButton('Нажми меня!', 'payload_button1')],
|
||||||
|
[new LinkButton('Нажми меня!', 'https://example.com')],
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
format: MessageFormat::Markdown, // Формат сообщения (Markdown или HTML)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Подписка на вэб хуки
|
||||||
|
|
||||||
|
```php
|
||||||
|
$api->subscribe(
|
||||||
|
new \BushlanovDev\MaxMessengerBot\Models\SubscriptionRequest(
|
||||||
|
'https://example.com/webhook', // URL на который будут приходить хуки
|
||||||
|
'super_secret', // Секретная фраза для проверки хуков
|
||||||
|
[
|
||||||
|
// Типы хуков которые вы хотите получать (либо ничего не указывать, чтобы получать все)
|
||||||
|
\BushlanovDev\MaxMessengerBot\Enums\UpdateType::MessageCreated,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Обработка хуков
|
||||||
|
|
||||||
|
```php
|
||||||
|
$webhookHandler = $api->createWebhookHandler();
|
||||||
|
|
||||||
|
$webhookHandler->addHandler(UpdateType::BotStarted, function (BotStartedUpdate $update, Api $api) {
|
||||||
|
$api->sendMessage(
|
||||||
|
chatId: $update->chatId,
|
||||||
|
text: 'Я запущен!',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Реализованные методы
|
## Реализованные методы
|
||||||
|
|
||||||
#### Bots
|
#### Bots
|
||||||
|
|
||||||
- [x] `GET /me` (`getBotInfo`) — *Получение информации о боте.*
|
- [x] `GET /me` (`getBotInfo`) - *Получение информации о боте.*
|
||||||
- [ ] `PATCH /me` (`editBotInfo`) — *Редактирование информации о боте.*
|
- [ ] `PATCH /me` (`editBotInfo`) - *Редактирование информации о боте.*
|
||||||
|
|
||||||
#### Chats
|
#### Chats
|
||||||
|
|
||||||
- [x] `GET /chats` (`getChats`) — *Получение списка всех чатов бота.*
|
- [x] `GET /chats` (`getChats`) - *Получение списка всех чатов бота.*
|
||||||
- [x] `GET /chats/{chatLink}` (`getChatByLink`) — *Получение информации о чате по ссылке.*
|
- [x] `GET /chats/{chatLink}` (`getChatByLink`) - *Получение информации о чате по ссылке.*
|
||||||
- [x] `GET /chats/{chatId}` (`getChat`) — *Получение информации о чате по ID.*
|
- [x] `GET /chats/{chatId}` (`getChat`) - *Получение информации о чате по ID.*
|
||||||
- [ ] `PATCH /chats/{chatId}` (`editChat`) — *Редактирование информации о чате.*
|
- [ ] `PATCH /chats/{chatId}` (`editChat`) - *Редактирование информации о чате.*
|
||||||
- [x] `DELETE /chats/{chatId}` (`deleteChat`) — *Удаление чата.*
|
- [x] `DELETE /chats/{chatId}` (`deleteChat`) - *Удаление чата.*
|
||||||
- [x] `POST /chats/{chatId}/actions` (`sendAction`) — *Отправка действия в чат (например, "печатает...").*
|
- [x] `POST /chats/{chatId}/actions` (`sendAction`) - *Отправка действия в чат (например, "печатает...").*
|
||||||
- [x] `GET /chats/{chatId}/pin` (`getPinnedMessage`) — *Получение закрепленного сообщения.*
|
- [x] `GET /chats/{chatId}/pin` (`getPinnedMessage`) - *Получение закрепленного сообщения.*
|
||||||
- [x] `PUT /chats/{chatId}/pin` (`pinMessage`) — *Закрепление сообщения.*
|
- [x] `PUT /chats/{chatId}/pin` (`pinMessage`) - *Закрепление сообщения.*
|
||||||
- [x] `DELETE /chats/{chatId}/pin` (`unpinMessage`) — *Открепление сообщения.*
|
- [x] `DELETE /chats/{chatId}/pin` (`unpinMessage`) - *Открепление сообщения.*
|
||||||
- [x] `GET /chats/{chatId}/members/me` (`getMembership`) — *Получение информации о членстве бота в чате.*
|
- [x] `GET /chats/{chatId}/members/me` (`getMembership`) - *Получение информации о членстве бота в чате.*
|
||||||
- [x] `DELETE /chats/{chatId}/members/me` (`leaveChat`) — *Выход бота из чата.*
|
- [x] `DELETE /chats/{chatId}/members/me` (`leaveChat`) - *Выход бота из чата.*
|
||||||
- [x] `GET /chats/{chatId}/members/admins` (`getAdmins`) — *Получение администраторов чата.*
|
- [x] `GET /chats/{chatId}/members/admins` (`getAdmins`) - *Получение администраторов чата.*
|
||||||
- [ ] `POST /chats/{chatId}/members/admins` (`postAdmins`) — *Назначение администраторов чата.*
|
- [x] `POST /chats/{chatId}/members/admins` (`addAdmins`) - *Назначение администраторов чата.*
|
||||||
- [x] `DELETE /chats/{chatId}/members/admins/{userId}` (`deleteAdmins`) — *Снятие прав администратора.*
|
- [x] `DELETE /chats/{chatId}/members/admins/{userId}` (`deleteAdmins`) - *Снятие прав администратора.*
|
||||||
- [x] `GET /chats/{chatId}/members` (`getMembers`) — *Получение участников чата.*
|
- [x] `GET /chats/{chatId}/members` (`getMembers`) - *Получение участников чата.*
|
||||||
- [ ] `POST /chats/{chatId}/members` (`addMembers`) — *Добавление участников в чат.*
|
- [x] `POST /chats/{chatId}/members` (`addMembers`) - *Добавление участников в чат.*
|
||||||
- [x] `DELETE /chats/{chatId}/members` (`removeMember`) — *Удаление участника из чата.*
|
- [x] `DELETE /chats/{chatId}/members` (`deleteMember`) - *Удаление участника из чата.*
|
||||||
|
|
||||||
#### Subscriptions
|
#### Subscriptions
|
||||||
|
|
||||||
- [x] `GET /subscriptions` (`getSubscriptions`) — *Получение списка Webhook-подписок.*
|
- [x] `GET /subscriptions` (`getSubscriptions`) - *Получение списка Webhook-подписок.*
|
||||||
- [x] `POST /subscriptions` (`subscribe`) — *Создание Webhook-подписки.*
|
- [x] `POST /subscriptions` (`subscribe`) - *Создание Webhook-подписки.*
|
||||||
- [x] `DELETE /subscriptions` (`unsubscribe`) — *Удаление Webhook-подписки.*
|
- [x] `DELETE /subscriptions` (`unsubscribe`) - *Удаление Webhook-подписки.*
|
||||||
- [x] `GET /updates` (`getUpdates`) — *Получение обновлений через Long-Polling.*
|
- [x] `GET /updates` (`getUpdates`) - *Получение обновлений через Long-Polling.*
|
||||||
|
|
||||||
#### Upload
|
#### Upload
|
||||||
|
|
||||||
- [x] `POST /uploads` (`getUploadUrl`) — *Получение URL для загрузки файла.*
|
- [x] `POST /uploads` (`getUploadUrl`) - *Получение URL для загрузки файла.*
|
||||||
|
|
||||||
#### Messages
|
#### Messages
|
||||||
|
|
||||||
- [x] `GET /messages` (`getMessages`) — *Получение списка сообщений из чата.*
|
- [x] `GET /messages` (`getMessages`) - *Получение списка сообщений из чата.*
|
||||||
- [x] `POST /messages` (`sendMessage`) — *Отправка сообщения.*
|
- [x] `POST /messages` (`sendMessage`) - *Отправка сообщения.*
|
||||||
- [ ] `PUT /messages` (`editMessage`) — *Редактирование сообщения.*
|
- [x] `PUT /messages` (`editMessage`) - *Редактирование сообщения.*
|
||||||
- [x] `DELETE /messages` (`deleteMessage`) — *Удаление сообщения.*
|
- [x] `DELETE /messages` (`deleteMessage`) - *Удаление сообщения.*
|
||||||
- [x] `GET /messages/{messageId}` (`getMessageById`) — *Получение сообщения по ID.*
|
- [x] `GET /messages/{messageId}` (`getMessageById`) - *Получение сообщения по ID.*
|
||||||
- [ ] `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) — *Получение детальной информации о видео.*
|
- [ ] `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) - *Получение детальной информации о видео.*
|
||||||
- [ ] `POST /answers` (`answerOnCallback`) — *Ответ на нажатие callback-кнопки.*
|
- [x] `POST /answers` (`answerOnCallback`) - *Ответ на нажатие callback-кнопки.*
|
||||||
|
|
||||||
## Лицензия
|
## Лицензия
|
||||||
|
|
||||||
|
|||||||
+225
-15
@@ -20,6 +20,7 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\PhotoAttachmentRequ
|
|||||||
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\VideoAttachmentRequest;
|
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\VideoAttachmentRequest;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||||
|
use BushlanovDev\MaxMessengerBot\Models\ChatAdmin;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
||||||
@@ -65,6 +66,7 @@ class Api
|
|||||||
private const string ACTION_CHATS_MEMBERS_ADMINS_ID = '/chats/%d/members/admins/%d';
|
private const string ACTION_CHATS_MEMBERS_ADMINS_ID = '/chats/%d/members/admins/%d';
|
||||||
private const string ACTION_CHATS_MEMBERS = '/chats/%d/members';
|
private const string ACTION_CHATS_MEMBERS = '/chats/%d/members';
|
||||||
private const string ACTION_UPDATES = '/updates';
|
private const string ACTION_UPDATES = '/updates';
|
||||||
|
private const string ACTION_ANSWERS = '/answers';
|
||||||
|
|
||||||
private readonly ClientApiInterface $client;
|
private readonly ClientApiInterface $client;
|
||||||
|
|
||||||
@@ -348,7 +350,7 @@ class Api
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to a chat.
|
* Sends a message to a chat or user.
|
||||||
*
|
*
|
||||||
* @param int|null $userId Fill this parameter if you want to send message to user.
|
* @param int|null $userId Fill this parameter if you want to send message to user.
|
||||||
* @param int|null $chatId Fill this if you send message to chat.
|
* @param int|null $chatId Fill this if you send message to chat.
|
||||||
@@ -381,27 +383,76 @@ class Api
|
|||||||
'disable_link_preview' => $disableLinkPreview,
|
'disable_link_preview' => $disableLinkPreview,
|
||||||
];
|
];
|
||||||
|
|
||||||
$body = [
|
|
||||||
'text' => $text,
|
|
||||||
'format' => $format?->value,
|
|
||||||
'notify' => $notify,
|
|
||||||
'link' => $link,
|
|
||||||
'attachments' => $attachments !== null ? array_map(
|
|
||||||
fn(AbstractModel $attachment) => $attachment->toArray(),
|
|
||||||
$attachments,
|
|
||||||
) : null,
|
|
||||||
];
|
|
||||||
|
|
||||||
$response = $this->client->request(
|
$response = $this->client->request(
|
||||||
self::METHOD_POST,
|
self::METHOD_POST,
|
||||||
self::ACTION_MESSAGES,
|
self::ACTION_MESSAGES,
|
||||||
array_filter($query, fn($item) => null !== $item),
|
array_filter($query, fn($item) => null !== $item),
|
||||||
array_filter($body, fn($item) => null !== $item),
|
$this->buildNewMessageBody($text, $attachments, $format, $link, $notify),
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->modelFactory->createMessage($response['message']);
|
return $this->modelFactory->createMessage($response['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to a user.
|
||||||
|
*
|
||||||
|
* @param int|null $userId Fill this parameter if you want to send message to user.
|
||||||
|
* @param string|null $text Message text.
|
||||||
|
* @param AbstractAttachmentRequest[]|null $attachments Message attachments.
|
||||||
|
* @param MessageFormat|null $format Message format.
|
||||||
|
* @param MessageLink|null $link Link to message.
|
||||||
|
* @param bool $notify If false, chat participants would not be notified.
|
||||||
|
* @param bool $disableLinkPreview If false, server will not generate media preview for links in text.
|
||||||
|
*
|
||||||
|
* @return Message
|
||||||
|
* @throws ClientApiException
|
||||||
|
* @throws NetworkException
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws SerializationException
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
public function sendUserMessage(
|
||||||
|
?int $userId = null,
|
||||||
|
?string $text = null,
|
||||||
|
?array $attachments = null,
|
||||||
|
?MessageFormat $format = null,
|
||||||
|
?MessageLink $link = null,
|
||||||
|
bool $notify = true,
|
||||||
|
bool $disableLinkPreview = false,
|
||||||
|
): Message {
|
||||||
|
return $this->sendMessage($userId, null, $text, $attachments, $format, $link, $notify, $disableLinkPreview);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to a chat.
|
||||||
|
*
|
||||||
|
* @param int|null $chatId Fill this if you send message to chat.
|
||||||
|
* @param string|null $text Message text.
|
||||||
|
* @param AbstractAttachmentRequest[]|null $attachments Message attachments.
|
||||||
|
* @param MessageFormat|null $format Message format.
|
||||||
|
* @param MessageLink|null $link Link to message.
|
||||||
|
* @param bool $notify If false, chat participants would not be notified.
|
||||||
|
* @param bool $disableLinkPreview If false, server will not generate media preview for links in text.
|
||||||
|
*
|
||||||
|
* @return Message
|
||||||
|
* @throws ClientApiException
|
||||||
|
* @throws NetworkException
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws SerializationException
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
public function sendChatMessage(
|
||||||
|
?int $chatId = null,
|
||||||
|
?string $text = null,
|
||||||
|
?array $attachments = null,
|
||||||
|
?MessageFormat $format = null,
|
||||||
|
?MessageLink $link = null,
|
||||||
|
bool $notify = true,
|
||||||
|
bool $disableLinkPreview = false,
|
||||||
|
): Message {
|
||||||
|
return $this->sendMessage(null, $chatId, $text, $attachments, $format, $link, $notify, $disableLinkPreview);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the URL for the subsequent file upload.
|
* Returns the URL for the subsequent file upload.
|
||||||
*
|
*
|
||||||
@@ -779,7 +830,7 @@ class Api
|
|||||||
[
|
[
|
||||||
'message_id' => $messageId,
|
'message_id' => $messageId,
|
||||||
'notify' => $notify,
|
'notify' => $notify,
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -877,7 +928,7 @@ class Api
|
|||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
* @throws SerializationException
|
* @throws SerializationException
|
||||||
*/
|
*/
|
||||||
public function removeMember(int $chatId, int $userId, bool $block = false): Result
|
public function deleteMember(int $chatId, int $userId, bool $block = false): Result
|
||||||
{
|
{
|
||||||
return $this->modelFactory->createResult(
|
return $this->modelFactory->createResult(
|
||||||
$this->client->request(
|
$this->client->request(
|
||||||
@@ -890,4 +941,163 @@ class Api
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the administrators for a chat.
|
||||||
|
*
|
||||||
|
* @param int $chatId The identifier of the chat.
|
||||||
|
* @param ChatAdmin[] $admins An array of ChatAdmin objects representing the users and their permissions.
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws ClientApiException
|
||||||
|
* @throws NetworkException
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws SerializationException
|
||||||
|
*/
|
||||||
|
public function addAdmins(int $chatId, array $admins): Result
|
||||||
|
{
|
||||||
|
return $this->modelFactory->createResult(
|
||||||
|
$this->client->request(
|
||||||
|
self::METHOD_POST,
|
||||||
|
sprintf(self::ACTION_CHATS_MEMBERS_ADMINS, $chatId),
|
||||||
|
[],
|
||||||
|
['admins' => array_map(fn(ChatAdmin $admin) => $admin->toArray(), $admins)],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds members to a chat. The bot may require additional permissions.
|
||||||
|
*
|
||||||
|
* @param int $chatId The identifier of the chat.
|
||||||
|
* @param int[] $userIds An array of user identifiers to add to the chat.
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws ClientApiException
|
||||||
|
* @throws NetworkException
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws SerializationException
|
||||||
|
*/
|
||||||
|
public function addMembers(int $chatId, array $userIds): Result
|
||||||
|
{
|
||||||
|
return $this->modelFactory->createResult(
|
||||||
|
$this->client->request(
|
||||||
|
self::METHOD_POST,
|
||||||
|
sprintf(self::ACTION_CHATS_MEMBERS, $chatId),
|
||||||
|
[],
|
||||||
|
['user_ids' => $userIds],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an answer to a callback query. This should be called after a user clicks an inline button.
|
||||||
|
*
|
||||||
|
* @param string $callbackId The identifier of the callback query.
|
||||||
|
* @param string|null $notification A short text notification to show to the user.
|
||||||
|
* @param string|null $text If provided, the original message will be edited with this text.
|
||||||
|
* @param AbstractAttachmentRequest[]|null $attachments New attachments for the edited message.
|
||||||
|
* @param MessageLink|null $link New link for the edited message.
|
||||||
|
* @param MessageFormat|null $format Formatting for the new message text.
|
||||||
|
* @param bool $notify Notification setting for the edited message.
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws ClientApiException
|
||||||
|
* @throws NetworkException
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws SerializationException
|
||||||
|
*/
|
||||||
|
public function answerOnCallback(
|
||||||
|
string $callbackId,
|
||||||
|
?string $notification = null,
|
||||||
|
?string $text = null,
|
||||||
|
?array $attachments = null,
|
||||||
|
?MessageLink $link = null,
|
||||||
|
?MessageFormat $format = null,
|
||||||
|
bool $notify = true,
|
||||||
|
): Result {
|
||||||
|
$answerBody = ['notification' => $notification];
|
||||||
|
if ($text !== null || $attachments !== null || $link !== null) {
|
||||||
|
$answerBody['message'] = $this->buildNewMessageBody($text, $attachments, $format, $link, $notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->modelFactory->createResult(
|
||||||
|
$this->client->request(
|
||||||
|
self::METHOD_POST,
|
||||||
|
self::ACTION_ANSWERS,
|
||||||
|
['callback_id' => $callbackId],
|
||||||
|
array_filter($answerBody, fn($value) => $value !== null)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits a message that was previously sent by the bot.
|
||||||
|
* Note on attachments:
|
||||||
|
* - To leave attachments unchanged, pass `null` (default).
|
||||||
|
* - To remove all attachments, pass an empty array `[]`.
|
||||||
|
*
|
||||||
|
* @param string $messageId The identifier of the message to edit.
|
||||||
|
* @param string|null $text New message text.
|
||||||
|
* @param AbstractAttachmentRequest[]|null $attachments New message attachments.
|
||||||
|
* @param MessageFormat|null $format Formatting for the new message text.
|
||||||
|
* @param MessageLink|null $link New link for the edited message.
|
||||||
|
* @param bool $notify Notification setting for the edited message.
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws ClientApiException
|
||||||
|
* @throws NetworkException
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws SerializationException
|
||||||
|
*/
|
||||||
|
public function editMessage(
|
||||||
|
string $messageId,
|
||||||
|
?string $text = null,
|
||||||
|
?array $attachments = null,
|
||||||
|
?MessageFormat $format = null,
|
||||||
|
?MessageLink $link = null,
|
||||||
|
bool $notify = true,
|
||||||
|
): Result {
|
||||||
|
return $this->modelFactory->createResult(
|
||||||
|
$this->client->request(
|
||||||
|
self::METHOD_PUT,
|
||||||
|
self::ACTION_MESSAGES,
|
||||||
|
['message_id' => $messageId],
|
||||||
|
$this->buildNewMessageBody($text, $attachments, $format, $link, $notify),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper to build the 'NewMessageBody' array structure consistently.
|
||||||
|
*
|
||||||
|
* @param string|null $text
|
||||||
|
* @param AbstractAttachmentRequest[]|null $attachments
|
||||||
|
* @param MessageFormat|null $format
|
||||||
|
* @param MessageLink|null $link
|
||||||
|
* @param bool $notify
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
* @throws ReflectionException
|
||||||
|
*/
|
||||||
|
private function buildNewMessageBody(
|
||||||
|
?string $text,
|
||||||
|
?array $attachments,
|
||||||
|
?MessageFormat $format,
|
||||||
|
?MessageLink $link,
|
||||||
|
bool $notify,
|
||||||
|
): array {
|
||||||
|
$body = [
|
||||||
|
'text' => $text,
|
||||||
|
'format' => $format?->value,
|
||||||
|
'notify' => $notify,
|
||||||
|
'link' => $link,
|
||||||
|
'attachments' => $attachments !== null ? array_map(
|
||||||
|
fn(AbstractModel $attachment) => $attachment->toArray(),
|
||||||
|
$attachments,
|
||||||
|
) : null,
|
||||||
|
];
|
||||||
|
|
||||||
|
return array_filter($body, fn($item) => $item !== null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace BushlanovDev\MaxMessengerBot\Exceptions;
|
namespace BushlanovDev\MaxMessengerBot\Exceptions;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
class NetworkException extends RuntimeException
|
class NetworkException extends RuntimeException
|
||||||
{
|
{
|
||||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace BushlanovDev\MaxMessengerBot\Exceptions;
|
namespace BushlanovDev\MaxMessengerBot\Exceptions;
|
||||||
|
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
class SerializationException extends LogicException
|
class SerializationException extends LogicException
|
||||||
{
|
{
|
||||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BushlanovDev\MaxMessengerBot\Models;
|
||||||
|
|
||||||
|
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||||
|
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an administrator to be set in a chat, linking a user ID with their permissions.
|
||||||
|
*/
|
||||||
|
final readonly class ChatAdmin extends AbstractModel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param int $userId The identifier of the user to be made an admin.
|
||||||
|
* @param ChatAdminPermission[] $permissions The list of permissions to grant to the user.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public int $userId,
|
||||||
|
#[ArrayOf(ChatAdminPermission::class)]
|
||||||
|
public array $permissions,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+226
-3
@@ -10,6 +10,7 @@ use BushlanovDev\MaxMessengerBot\Client;
|
|||||||
use BushlanovDev\MaxMessengerBot\ClientApiInterface;
|
use BushlanovDev\MaxMessengerBot\ClientApiInterface;
|
||||||
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
|
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
|
||||||
use BushlanovDev\MaxMessengerBot\Enums\ButtonType;
|
use BushlanovDev\MaxMessengerBot\Enums\ButtonType;
|
||||||
|
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||||
use BushlanovDev\MaxMessengerBot\Enums\MessageFormat;
|
use BushlanovDev\MaxMessengerBot\Enums\MessageFormat;
|
||||||
use BushlanovDev\MaxMessengerBot\Enums\SenderAction;
|
use BushlanovDev\MaxMessengerBot\Enums\SenderAction;
|
||||||
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
||||||
@@ -36,6 +37,7 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\StickerAttachmentRe
|
|||||||
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\VideoAttachmentRequest;
|
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\VideoAttachmentRequest;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||||
|
use BushlanovDev\MaxMessengerBot\Models\ChatAdmin;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||||
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
||||||
@@ -107,6 +109,7 @@ use RuntimeException;
|
|||||||
#[UsesClass(ChatMember::class)]
|
#[UsesClass(ChatMember::class)]
|
||||||
#[UsesClass(ArrayOf::class)]
|
#[UsesClass(ArrayOf::class)]
|
||||||
#[UsesClass(ChatMembersList::class)]
|
#[UsesClass(ChatMembersList::class)]
|
||||||
|
#[UsesClass(ChatAdmin::class)]
|
||||||
final class ApiTest extends TestCase
|
final class ApiTest extends TestCase
|
||||||
{
|
{
|
||||||
use PHPMock;
|
use PHPMock;
|
||||||
@@ -1827,7 +1830,7 @@ final class ApiTest extends TestCase
|
|||||||
$chatId = 12345;
|
$chatId = 12345;
|
||||||
$userId = 678;
|
$userId = 678;
|
||||||
$uri = sprintf('/chats/%d/members', $chatId);
|
$uri = sprintf('/chats/%d/members', $chatId);
|
||||||
$expectedQuery = ['user_id' => $userId];
|
$expectedQuery = ['user_id' => $userId, 'block' => false];
|
||||||
|
|
||||||
$rawResponse = ['success' => true];
|
$rawResponse = ['success' => true];
|
||||||
$expectedResult = new Result(true, null);
|
$expectedResult = new Result(true, null);
|
||||||
@@ -1844,7 +1847,7 @@ final class ApiTest extends TestCase
|
|||||||
->with($rawResponse)
|
->with($rawResponse)
|
||||||
->willReturn($expectedResult);
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
$result = $this->api->removeMember($chatId, $userId);
|
$result = $this->api->deleteMember($chatId, $userId);
|
||||||
|
|
||||||
$this->assertSame($expectedResult, $result);
|
$this->assertSame($expectedResult, $result);
|
||||||
}
|
}
|
||||||
@@ -1872,8 +1875,228 @@ final class ApiTest extends TestCase
|
|||||||
->with($rawResponse)
|
->with($rawResponse)
|
||||||
->willReturn($expectedResult);
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
$result = $this->api->removeMember($chatId, $userId, true);
|
$result = $this->api->deleteMember($chatId, $userId, true);
|
||||||
|
|
||||||
$this->assertSame($expectedResult, $result);
|
$this->assertSame($expectedResult, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function postAdminsCallsClientWithCorrectBody(): void
|
||||||
|
{
|
||||||
|
$chatId = 12345;
|
||||||
|
$uri = sprintf('/chats/%d/members/admins', $chatId);
|
||||||
|
$admins = [
|
||||||
|
new ChatAdmin(101, [ChatAdminPermission::Write]),
|
||||||
|
new ChatAdmin(202, [ChatAdminPermission::PinMessage]),
|
||||||
|
];
|
||||||
|
|
||||||
|
$expectedBody = [
|
||||||
|
'admins' => [
|
||||||
|
['user_id' => 101, 'permissions' => ['write']],
|
||||||
|
['user_id' => 202, 'permissions' => ['pin_message']],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('POST', $uri, [], $expectedBody)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->addAdmins($chatId, $admins);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function addMembersCallsClientWithCorrectBody(): void
|
||||||
|
{
|
||||||
|
$chatId = 12345;
|
||||||
|
$userIds = [101, 202, 303];
|
||||||
|
$uri = sprintf('/chats/%d/members', $chatId);
|
||||||
|
$expectedBody = ['user_ids' => $userIds];
|
||||||
|
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with(
|
||||||
|
self::equalTo('POST'),
|
||||||
|
self::equalTo($uri),
|
||||||
|
self::equalTo([]),
|
||||||
|
self::equalTo($expectedBody),
|
||||||
|
)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->addMembers($chatId, $userIds);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function answerOnCallbackWithNotificationOnly(): void
|
||||||
|
{
|
||||||
|
$callbackId = 'cb.123.abc';
|
||||||
|
$notification = 'Action confirmed!';
|
||||||
|
$expectedQuery = ['callback_id' => $callbackId];
|
||||||
|
$expectedBody = ['notification' => $notification];
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('POST', '/answers', $expectedQuery, $expectedBody)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->answerOnCallback($callbackId, $notification);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function answerOnCallbackWithMessageEdit(): void
|
||||||
|
{
|
||||||
|
$callbackId = 'cb.456.def';
|
||||||
|
$newText = 'Message updated!';
|
||||||
|
$expectedQuery = ['callback_id' => $callbackId];
|
||||||
|
$expectedBody = [
|
||||||
|
'message' => [
|
||||||
|
'text' => $newText,
|
||||||
|
'notify' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('POST', '/answers', $expectedQuery, $expectedBody)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->answerOnCallback(callbackId: $callbackId, text: $newText);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function answerOnCallbackWithBothMessageAndNotification(): void
|
||||||
|
{
|
||||||
|
$callbackId = 'cb.789.ghi';
|
||||||
|
$notification = 'Done!';
|
||||||
|
$newText = 'Updated!';
|
||||||
|
$expectedQuery = ['callback_id' => $callbackId];
|
||||||
|
$expectedBody = [
|
||||||
|
'notification' => $notification,
|
||||||
|
'message' => [
|
||||||
|
'text' => $newText,
|
||||||
|
'notify' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('POST', '/answers', $expectedQuery, $expectedBody)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->answerOnCallback(
|
||||||
|
callbackId: $callbackId,
|
||||||
|
notification: $notification,
|
||||||
|
text: $newText
|
||||||
|
);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function editMessageCallsClientWithCorrectParameters(): void
|
||||||
|
{
|
||||||
|
$messageId = 'mid.123.abc';
|
||||||
|
$newText = 'This is the edited text.';
|
||||||
|
$expectedQuery = ['message_id' => $messageId];
|
||||||
|
$expectedBody = [
|
||||||
|
'text' => $newText,
|
||||||
|
'notify' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('PUT', '/messages', $expectedQuery, $expectedBody)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->editMessage($messageId, $newText);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function editMessageCanClearAttachmentsWithEmptyArray(): void
|
||||||
|
{
|
||||||
|
$messageId = 'mid.456.def';
|
||||||
|
$expectedQuery = ['message_id' => $messageId];
|
||||||
|
$expectedBody = [
|
||||||
|
'attachments' => [],
|
||||||
|
'notify' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
$rawResponse = ['success' => true];
|
||||||
|
$expectedResult = new Result(true, null);
|
||||||
|
|
||||||
|
$this->clientMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('PUT', '/messages', $expectedQuery, $expectedBody)
|
||||||
|
->willReturn($rawResponse);
|
||||||
|
|
||||||
|
$this->modelFactoryMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('createResult')
|
||||||
|
->with($rawResponse)
|
||||||
|
->willReturn($expectedResult);
|
||||||
|
|
||||||
|
$result = $this->api->editMessage($messageId, attachments: []);
|
||||||
|
$this->assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BushlanovDev\MaxMessengerBot\Tests\Models;
|
||||||
|
|
||||||
|
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||||
|
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||||
|
use BushlanovDev\MaxMessengerBot\Models\ChatAdmin;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\Attributes\UsesClass;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
#[CoversClass(ChatAdmin::class)]
|
||||||
|
#[UsesClass(ArrayOf::class)]
|
||||||
|
final class ChatAdminTest extends TestCase
|
||||||
|
{
|
||||||
|
#[Test]
|
||||||
|
public function toArraySerializesCorrectly(): void
|
||||||
|
{
|
||||||
|
$admin = new ChatAdmin(123, [ChatAdminPermission::Write, ChatAdminPermission::PinMessage]);
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'user_id' => 123,
|
||||||
|
'permissions' => ['write', 'pin_message'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $admin->toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user