mirror of
https://github.com/BushlanovDev/max-bot-api-client-php.git
synced 2026-10-07 12:29:11 +00:00
Add comments API
Schema 0.0.33 adds comments to channel posts:
- GET /messages/{messageId}/comments getComments()
- GET /messages/{messageId}/comments/{commentId} getCommentById()
- POST /messages/{messageId}/comments sendComment()
- PUT /messages/{messageId}/comments editComment()
- DELETE /messages/{messageId}/comments deleteComment()
Comments get their own models (CommentMessage, CommentMessageBody,
CommentLinkedMessage): unlike Message they have no attachments and
no public URL. README coverage map and docs updated.
This commit is contained in:
@@ -225,6 +225,14 @@ $handler->handle();
|
||||
- [x] `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) - [*Получение детальной информации о видео.*](./docs/README.md#Получение-детальной-информации-о-видео)
|
||||
- [x] `POST /answers` (`answerOnCallback`) - [*Ответ на нажатие callback-кнопки.*](./docs/README.md#Ответ-на-нажатие-callback-кнопки)
|
||||
|
||||
#### Comments
|
||||
|
||||
- [x] `GET /messages/{messageId}/comments` (`getComments`) - [*Получение комментариев к посту.*](./docs/README.md#Получение-комментариев-к-посту)
|
||||
- [x] `GET /messages/{messageId}/comments/{commentId}` (`getCommentById`) - [*Получение комментария по ID.*](./docs/README.md#Получение-комментария-по-ID)
|
||||
- [x] `POST /messages/{messageId}/comments` (`sendComment`) - [*Отправка комментария.*](./docs/README.md#Отправка-комментария)
|
||||
- [x] `PUT /messages/{messageId}/comments` (`editComment`) - [*Редактирование комментария.*](./docs/README.md#Редактирование-комментария)
|
||||
- [x] `DELETE /messages/{messageId}/comments` (`deleteComment`) - [*Удаление комментария.*](./docs/README.md#Удаление-комментария)
|
||||
|
||||
## Лицензия
|
||||
|
||||
Данная библиотека распространяется под лицензией MIT - подробности см. в файле [LICENSE](LICENSE).
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
- `GET /messages/{messageId}` (`getMessageById`) - [*Получение сообщения по ID.*](#Получение-сообщения-по-ID)
|
||||
- `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) - [*Получение детальной информации о видео.*](#Получение-детальной-информации-о-видео)
|
||||
- `POST /answers` (`answerOnCallback`) - [*Ответ на нажатие callback-кнопки.*](#Ответ-на-нажатие-callback-кнопки)
|
||||
- [Комментарии](#Комментарии)
|
||||
- `GET /messages/{messageId}/comments` (`getComments`) - [*Получение комментариев к посту.*](#Получение-комментариев-к-посту)
|
||||
- `GET /messages/{messageId}/comments/{commentId}` (`getCommentById`) - [*Получение комментария по ID.*](#Получение-комментария-по-ID)
|
||||
- `POST /messages/{messageId}/comments` (`sendComment`) - [*Отправка комментария.*](#Отправка-комментария)
|
||||
- `PUT /messages/{messageId}/comments` (`editComment`) - [*Редактирование комментария.*](#Редактирование-комментария)
|
||||
- `DELETE /messages/{messageId}/comments` (`deleteComment`) - [*Удаление комментария.*](#Удаление-комментария)
|
||||
- [Laravel](#Laravel)
|
||||
- [Регистрация пакета](#Регистрация-пакета)
|
||||
- [Настройка](#Настройка)
|
||||
@@ -459,6 +465,60 @@ $api->answerOnCallback(
|
||||
);
|
||||
```
|
||||
|
||||
## Комментарии
|
||||
|
||||
Комментарии оставляют к постам в каналах. В отличие от сообщений, у комментария нет вложений и публичной ссылки.
|
||||
Для некоторых методов бот должен быть администратором канала с нужными правами. События `comment_created`,
|
||||
`comment_edited` и `comment_removed` приходят, только если у бота есть право `read_all_messages`.
|
||||
|
||||
### Получение комментариев к посту
|
||||
|
||||
Возвращает комментарии к посту, начиная с последнего.
|
||||
|
||||
```php
|
||||
$comments = $api->getComments(
|
||||
messageId: 'mid.post', // Идентификатор поста
|
||||
commentIds: ['mid.1', 'mid.2'], // Идентификаторы нужных комментариев (необязательно)
|
||||
before: 1678886400000, // Комментарии до этого времени (необязательно)
|
||||
after: 1678880000000, // Комментарии после этого времени (необязательно)
|
||||
count: 50, // Максимальное количество комментариев в ответе, 1-100 (необязательно)
|
||||
);
|
||||
```
|
||||
|
||||
### Получение комментария по ID
|
||||
|
||||
```php
|
||||
$comment = $api->getCommentById('mid.post', 'mid.comment');
|
||||
```
|
||||
|
||||
### Отправка комментария
|
||||
|
||||
```php
|
||||
$comment = $api->sendComment(
|
||||
messageId: 'mid.post', // Идентификатор поста
|
||||
text: 'Спасибо за пост!', // Текст комментария
|
||||
format: MessageFormat::Markdown, // Формат текста Markdown или HTML (необязательно)
|
||||
link: new MessageLink(MessageLinkType::Reply, 'mid.comment'), // Ответ на другой комментарий (необязательно)
|
||||
disableLinkPreview: false, // Не генерировать превью ссылок (необязательно)
|
||||
);
|
||||
```
|
||||
|
||||
### Редактирование комментария
|
||||
|
||||
```php
|
||||
$result = $api->editComment(
|
||||
messageId: 'mid.post',
|
||||
commentId: 'mid.comment',
|
||||
text: 'Исправленный текст',
|
||||
);
|
||||
```
|
||||
|
||||
### Удаление комментария
|
||||
|
||||
```php
|
||||
$result = $api->deleteComment('mid.post', 'mid.comment');
|
||||
```
|
||||
|
||||
## Laravel
|
||||
|
||||
### Регистрация пакета
|
||||
|
||||
+171
@@ -27,6 +27,7 @@ use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatPatch;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Message;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageLink;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Result;
|
||||
@@ -77,6 +78,8 @@ class Api
|
||||
private const string ACTION_UPDATES = '/updates';
|
||||
private const string ACTION_ANSWERS = '/answers';
|
||||
private const string ACTION_VIDEO_DETAILS = '/videos/%s';
|
||||
private const string ACTION_MESSAGE_COMMENTS = '/messages/%s/comments';
|
||||
private const string ACTION_MESSAGE_COMMENT = '/messages/%s/comments/%s';
|
||||
|
||||
private const int RESUMABLE_UPLOAD_THRESHOLD_BYTES = 10 * 1024 * 1024; // 10 MB
|
||||
|
||||
@@ -861,6 +864,153 @@ class Api
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns comments to a post in a channel. Comments are traversed in reverse order, the latest first.
|
||||
*
|
||||
* @param string $messageId Identifier (`mid`) of the commented post.
|
||||
* @param string[]|null $commentIds Identifiers of the comments to get.
|
||||
* @param int|null $before Comments before this Unix timestamp (ms).
|
||||
* @param int|null $after Comments after this Unix timestamp (ms).
|
||||
* @param int|null $count Maximum amount of comments in the response (1-100, default 50).
|
||||
*
|
||||
* @return CommentMessage[]
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function getComments(
|
||||
string $messageId,
|
||||
?array $commentIds = null,
|
||||
?int $before = null,
|
||||
?int $after = null,
|
||||
?int $count = null,
|
||||
): array {
|
||||
$query = [
|
||||
'comment_ids' => $commentIds !== null ? implode(',', $commentIds) : null,
|
||||
'before' => $before,
|
||||
'after' => $after,
|
||||
'count' => $count,
|
||||
];
|
||||
|
||||
$response = $this->client->request(
|
||||
self::METHOD_GET,
|
||||
sprintf(self::ACTION_MESSAGE_COMMENTS, $messageId),
|
||||
array_filter($query, fn($value) => $value !== null),
|
||||
);
|
||||
|
||||
return $this->modelFactory->createCommentMessages($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single comment to a post in a channel.
|
||||
*
|
||||
* @param string $messageId Identifier (`mid`) of the commented post.
|
||||
* @param string $commentId Identifier (`mid`) of the comment.
|
||||
*
|
||||
* @return CommentMessage
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function getCommentById(string $messageId, string $commentId): CommentMessage
|
||||
{
|
||||
return $this->modelFactory->createCommentMessage(
|
||||
$this->client->request(
|
||||
self::METHOD_GET,
|
||||
sprintf(self::ACTION_MESSAGE_COMMENT, $messageId, $commentId),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a comment to a post in a channel. Comments cannot have attachments.
|
||||
*
|
||||
* @param string $messageId Identifier (`mid`) of the commented post.
|
||||
* @param string|null $text Comment text.
|
||||
* @param MessageFormat|null $format Comment format.
|
||||
* @param MessageLink|null $link Link to a comment to reply to or forward.
|
||||
* @param bool $disableLinkPreview If false, server will not generate media preview for links in text.
|
||||
*
|
||||
* @return CommentMessage
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function sendComment(
|
||||
string $messageId,
|
||||
?string $text = null,
|
||||
?MessageFormat $format = null,
|
||||
?MessageLink $link = null,
|
||||
bool $disableLinkPreview = false,
|
||||
): CommentMessage {
|
||||
return $this->modelFactory->createCommentMessageFromSendResponse(
|
||||
$this->client->request(
|
||||
self::METHOD_POST,
|
||||
sprintf(self::ACTION_MESSAGE_COMMENTS, $messageId),
|
||||
['disable_link_preview' => $disableLinkPreview],
|
||||
$this->buildNewCommentBody($text, $format, $link),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits a comment to a post in a channel. Comments cannot have attachments.
|
||||
*
|
||||
* @param string $messageId Identifier (`mid`) of the commented post.
|
||||
* @param string $commentId Identifier (`mid`) of the comment to edit.
|
||||
* @param string|null $text New comment text.
|
||||
* @param MessageFormat|null $format Formatting for the new text.
|
||||
* @param MessageLink|null $link New link for the edited comment.
|
||||
*
|
||||
* @return Result
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function editComment(
|
||||
string $messageId,
|
||||
string $commentId,
|
||||
?string $text = null,
|
||||
?MessageFormat $format = null,
|
||||
?MessageLink $link = null,
|
||||
): Result {
|
||||
return $this->modelFactory->createResult(
|
||||
$this->client->request(
|
||||
self::METHOD_PUT,
|
||||
sprintf(self::ACTION_MESSAGE_COMMENTS, $messageId),
|
||||
['comment_id' => $commentId],
|
||||
$this->buildNewCommentBody($text, $format, $link),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a comment to a post in a channel if the bot has permission to delete messages.
|
||||
*
|
||||
* @param string $messageId Identifier (`mid`) of the commented post.
|
||||
* @param string $commentId Identifier (`mid`) of the comment to delete.
|
||||
*
|
||||
* @return Result
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function deleteComment(string $messageId, string $commentId): Result
|
||||
{
|
||||
return $this->modelFactory->createResult(
|
||||
$this->client->request(
|
||||
self::METHOD_DELETE,
|
||||
sprintf(self::ACTION_MESSAGE_COMMENTS, $messageId),
|
||||
['comment_id' => $commentId],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a message in a chat or channel.
|
||||
*
|
||||
@@ -1233,4 +1383,25 @@ class Api
|
||||
|
||||
return array_filter($body, fn($item) => $item !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to build the 'NewCommentBody' array structure: like 'NewMessageBody',
|
||||
* but without attachments and notify.
|
||||
*
|
||||
* @param string|null $text
|
||||
* @param MessageFormat|null $format
|
||||
* @param MessageLink|null $link
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildNewCommentBody(?string $text, ?MessageFormat $format, ?MessageLink $link): array
|
||||
{
|
||||
$body = [
|
||||
'text' => $text,
|
||||
'format' => $format?->value,
|
||||
'link' => $link,
|
||||
];
|
||||
|
||||
return array_filter($body, fn($item) => $item !== null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessageBody;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Markup\AbstractMarkup;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Markup\EmphasizedMarkup;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Markup\HeadingMarkup;
|
||||
@@ -224,6 +226,74 @@ readonly class ModelFactory
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment to a post in a channel.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return CommentMessage
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function createCommentMessage(array $data): CommentMessage
|
||||
{
|
||||
if (isset($data['body']) && is_array($data['body'])) {
|
||||
$data['body'] = $this->createCommentMessageBody($data['body']);
|
||||
}
|
||||
|
||||
if (isset($data['link']['message']) && is_array($data['link']['message'])) {
|
||||
$data['link']['message'] = $this->createCommentMessageBody($data['link']['message']);
|
||||
}
|
||||
|
||||
return CommentMessage::fromArray($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of comments.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return CommentMessage[]
|
||||
*/
|
||||
public function createCommentMessages(array $data): array
|
||||
{
|
||||
return isset($data['messages']) && is_array($data['messages'])
|
||||
? array_map([$this, 'createCommentMessage'], $data['messages'])
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CommentMessage from the response of the sendComment endpoint.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return CommentMessage
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function createCommentMessageFromSendResponse(array $data): CommentMessage
|
||||
{
|
||||
return $this->createCommentMessage($data['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CommentMessageBody from raw API data, handling polymorphic markup.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return CommentMessageBody
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function createCommentMessageBody(array $data): CommentMessageBody
|
||||
{
|
||||
if (isset($data['markup']) && is_array($data['markup'])) {
|
||||
$data['markup'] = array_map(
|
||||
[$this, 'createMarkupElement'],
|
||||
$data['markup'],
|
||||
);
|
||||
}
|
||||
|
||||
return CommentMessageBody::fromArray($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MessageBody object from raw API data, handling polymorphic attachments and markup.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Enums\MessageLinkType;
|
||||
|
||||
/**
|
||||
* A forwarded or replied comment linked to a comment.
|
||||
*/
|
||||
final readonly class CommentLinkedMessage extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @param MessageLinkType $type Type of linked message (forward or reply).
|
||||
* @param CommentMessageBody $message The body of the original comment.
|
||||
* @param UserWithPhoto|null $sender The sender of the original comment. Can be null if posted on behalf of a channel.
|
||||
* @param int|null $chatId The chat where the comment was originally posted.
|
||||
*/
|
||||
public function __construct(
|
||||
public MessageLinkType $type,
|
||||
public CommentMessageBody $message,
|
||||
public ?UserWithPhoto $sender,
|
||||
public ?int $chatId,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Models;
|
||||
|
||||
/**
|
||||
* A comment to a post in a channel. Unlike Message, it has no public URL and no attachments.
|
||||
*/
|
||||
final readonly class CommentMessage extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @param int $timestamp Unix-time when the comment was created.
|
||||
* @param Recipient $recipient Comment recipient, always a channel; carries the commented post in $postId.
|
||||
* @param CommentMessageBody $body Body of the comment.
|
||||
* @param UserWithPhoto|null $sender User who sent the comment. Can be null if posted on behalf of a channel.
|
||||
* @param CommentLinkedMessage|null $link Forwarded or replied comment.
|
||||
* @param MessageStat|null $stat Comment statistics.
|
||||
*/
|
||||
public function __construct(
|
||||
public int $timestamp,
|
||||
public Recipient $recipient,
|
||||
public CommentMessageBody $body,
|
||||
public ?UserWithPhoto $sender,
|
||||
public ?CommentLinkedMessage $link,
|
||||
public ?MessageStat $stat,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Models\Markup\AbstractMarkup;
|
||||
|
||||
/**
|
||||
* Body of a comment. Unlike MessageBody, comments have no attachments.
|
||||
*/
|
||||
final readonly class CommentMessageBody extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @param string $mid Unique identifier of the comment.
|
||||
* @param int $seq Sequence identifier of the comment in the chat.
|
||||
* @param string|null $text Comment text.
|
||||
* @param AbstractMarkup[]|null $markup Comment text markup.
|
||||
*/
|
||||
public function __construct(
|
||||
public string $mid,
|
||||
public int $seq,
|
||||
public ?string $text,
|
||||
public ?array $markup,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,9 @@ use BushlanovDev\MaxMessengerBot\ClientApiInterface;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\InlineButtonType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\ChatType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\MessageFormat;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\MessageLinkType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\SenderAction;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UploadType;
|
||||
@@ -47,6 +49,9 @@ use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatPatch;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Message;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageBody;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessageBody;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageLink;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Recipient;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Result;
|
||||
use BushlanovDev\MaxMessengerBot\Models\UserWithPhoto;
|
||||
@@ -86,6 +91,9 @@ use RuntimeException;
|
||||
#[UsesClass(Message::class)]
|
||||
#[UsesClass(MessageBody::class)]
|
||||
#[UsesClass(Recipient::class)]
|
||||
#[UsesClass(CommentMessage::class)]
|
||||
#[UsesClass(CommentMessageBody::class)]
|
||||
#[UsesClass(MessageLink::class)]
|
||||
#[UsesClass(UserWithPhoto::class)]
|
||||
#[UsesClass(CallbackButton::class)]
|
||||
#[UsesClass(InlineKeyboardAttachmentRequestPayload::class)]
|
||||
@@ -1332,6 +1340,153 @@ final class ApiTest extends TestCase
|
||||
$this->assertSame($expectedMessages, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getCommentsCallsClientWithAllParameters(): void
|
||||
{
|
||||
$expectedQuery = [
|
||||
'comment_ids' => 'mid.c1,mid.c2',
|
||||
'before' => 1678886400000,
|
||||
'after' => 1678880000000,
|
||||
'count' => 20,
|
||||
];
|
||||
$rawResponse = ['messages' => [$this->commentData()]];
|
||||
$expectedComments = [$this->comment()];
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', '/messages/mid.post/comments', $expectedQuery)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createCommentMessages')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedComments);
|
||||
|
||||
$result = $this->api->getComments('mid.post', ['mid.c1', 'mid.c2'], 1678886400000, 1678880000000, 20);
|
||||
|
||||
$this->assertSame($expectedComments, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getCommentsOmitsEmptyParameters(): void
|
||||
{
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', '/messages/mid.post/comments', [])
|
||||
->willReturn(['messages' => []]);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createCommentMessages')
|
||||
->willReturn([]);
|
||||
|
||||
$this->assertSame([], $this->api->getComments('mid.post'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getCommentByIdRequestsTheSingleComment(): void
|
||||
{
|
||||
$expectedComment = $this->comment();
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', '/messages/mid.post/comments/mid.comment')
|
||||
->willReturn($this->commentData());
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createCommentMessage')
|
||||
->with($this->commentData())
|
||||
->willReturn($expectedComment);
|
||||
|
||||
$this->assertSame($expectedComment, $this->api->getCommentById('mid.post', 'mid.comment'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function sendCommentPostsNewCommentBody(): void
|
||||
{
|
||||
$link = new MessageLink(MessageLinkType::Reply, 'mid.other');
|
||||
$rawResponse = ['message' => $this->commentData()];
|
||||
$expectedComment = $this->comment();
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with(
|
||||
'POST',
|
||||
'/messages/mid.post/comments',
|
||||
['disable_link_preview' => true],
|
||||
['text' => 'Nice post', 'format' => 'markdown', 'link' => $link],
|
||||
)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createCommentMessageFromSendResponse')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedComment);
|
||||
|
||||
$result = $this->api->sendComment('mid.post', 'Nice post', MessageFormat::Markdown, $link, true);
|
||||
|
||||
$this->assertSame($expectedComment, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function editCommentPutsNewTextForTheComment(): void
|
||||
{
|
||||
$expectedResult = new Result(true, null);
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('PUT', '/messages/mid.post/comments', ['comment_id' => 'mid.comment'], ['text' => 'Edited'])
|
||||
->willReturn(['success' => true]);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createResult')
|
||||
->with(['success' => true])
|
||||
->willReturn($expectedResult);
|
||||
|
||||
$this->assertSame($expectedResult, $this->api->editComment('mid.post', 'mid.comment', 'Edited'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function deleteCommentDeletesByCommentId(): void
|
||||
{
|
||||
$expectedResult = new Result(true, null);
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('DELETE', '/messages/mid.post/comments', ['comment_id' => 'mid.comment'])
|
||||
->willReturn(['success' => true]);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createResult')
|
||||
->with(['success' => true])
|
||||
->willReturn($expectedResult);
|
||||
|
||||
$this->assertSame($expectedResult, $this->api->deleteComment('mid.post', 'mid.comment'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function commentData(): array
|
||||
{
|
||||
return [
|
||||
'timestamp' => 1,
|
||||
'body' => ['mid' => 'mid.comment', 'seq' => 1, 'text' => 'Nice post'],
|
||||
'recipient' => ['chat_type' => 'channel', 'chat_id' => -100, 'post_id' => 'mid.post'],
|
||||
];
|
||||
}
|
||||
|
||||
private function comment(): CommentMessage
|
||||
{
|
||||
return new CommentMessage(
|
||||
1,
|
||||
new Recipient(ChatType::Channel, null, -100, 'mid.post'),
|
||||
new CommentMessageBody('mid.comment', 1, 'Nice post', null),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getMessagesReturnsEmptyArrayForEmptyResponse(): void
|
||||
{
|
||||
|
||||
@@ -29,6 +29,10 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\ShareAttachment;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotCommand;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotCommandsInfo;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Markup\QuoteMarkup;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentLinkedMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessageBody;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
@@ -67,6 +71,10 @@ use Psr\Log\LoggerInterface;
|
||||
#[UsesClass(BotInfo::class)]
|
||||
#[UsesClass(BotCommand::class)]
|
||||
#[UsesClass(BotCommandsInfo::class)]
|
||||
#[UsesClass(CommentMessage::class)]
|
||||
#[UsesClass(CommentMessageBody::class)]
|
||||
#[UsesClass(CommentLinkedMessage::class)]
|
||||
#[UsesClass(QuoteMarkup::class)]
|
||||
#[UsesClass(Result::class)]
|
||||
#[UsesClass(Subscription::class)]
|
||||
#[UsesClass(ArrayOf::class)]
|
||||
@@ -198,6 +206,58 @@ final class ModelFactoryTest extends TestCase
|
||||
$this->assertNull($botCommands->commands[1]->description);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function createCommentMessageHydratesBodyMarkupAndLink(): void
|
||||
{
|
||||
$comment = $this->factory->createCommentMessage([
|
||||
'timestamp' => 1,
|
||||
'recipient' => ['chat_type' => 'channel', 'chat_id' => -100, 'post_id' => 'mid.post'],
|
||||
'body' => [
|
||||
'mid' => 'mid.comment',
|
||||
'seq' => 3,
|
||||
'text' => 'Quoted reply',
|
||||
'markup' => [['type' => 'quote', 'from' => 0, 'length' => 6]],
|
||||
],
|
||||
'sender' => ['user_id' => 42, 'first_name' => 'Anna', 'is_bot' => false],
|
||||
'link' => [
|
||||
'type' => 'reply',
|
||||
'message' => [
|
||||
'mid' => 'mid.parent',
|
||||
'seq' => 2,
|
||||
'text' => 'Parent',
|
||||
'markup' => [['type' => 'strong', 'from' => 0, 'length' => 6]],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(CommentMessage::class, $comment);
|
||||
$this->assertSame('mid.post', $comment->recipient->postId);
|
||||
$this->assertSame('Quoted reply', $comment->body->text);
|
||||
$this->assertInstanceOf(QuoteMarkup::class, $comment->body->markup[0]);
|
||||
$this->assertSame(42, $comment->sender?->userId);
|
||||
$this->assertInstanceOf(CommentLinkedMessage::class, $comment->link);
|
||||
$this->assertInstanceOf(StrongMarkup::class, $comment->link->message->markup[0]);
|
||||
$this->assertNull($comment->stat);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function createCommentMessagesAndSendResponseUnwrapComments(): void
|
||||
{
|
||||
$data = [
|
||||
'timestamp' => 1,
|
||||
'recipient' => ['chat_type' => 'channel', 'chat_id' => -100],
|
||||
'body' => ['mid' => 'mid.comment', 'seq' => 1],
|
||||
];
|
||||
|
||||
$list = $this->factory->createCommentMessages(['messages' => [$data, $data]]);
|
||||
$sent = $this->factory->createCommentMessageFromSendResponse(['message' => $data]);
|
||||
|
||||
$this->assertCount(2, $list);
|
||||
$this->assertContainsOnlyInstancesOf(CommentMessage::class, $list);
|
||||
$this->assertSame([], $this->factory->createCommentMessages([]));
|
||||
$this->assertSame('mid.comment', $sent->body->mid);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function createBotInfoHandlesNullCommands(): void
|
||||
{
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Tests\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Enums\MessageLinkType;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentLinkedMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessage;
|
||||
use BushlanovDev\MaxMessengerBot\Models\CommentMessageBody;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageStat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Recipient;
|
||||
use BushlanovDev\MaxMessengerBot\Models\UserWithPhoto;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\Attributes\UsesClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
#[CoversClass(CommentMessage::class)]
|
||||
#[CoversClass(CommentMessageBody::class)]
|
||||
#[CoversClass(CommentLinkedMessage::class)]
|
||||
#[UsesClass(Recipient::class)]
|
||||
#[UsesClass(UserWithPhoto::class)]
|
||||
#[UsesClass(MessageStat::class)]
|
||||
final class CommentMessageTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function canBeCreatedFromArrayWithAllData(): void
|
||||
{
|
||||
$comment = CommentMessage::fromArray([
|
||||
'timestamp' => 1678886400000,
|
||||
'recipient' => ['chat_type' => 'channel', 'chat_id' => -100, 'post_id' => 'mid.post'],
|
||||
'body' => ['mid' => 'mid.comment', 'seq' => 7, 'text' => 'Agree', 'markup' => null],
|
||||
'sender' => ['user_id' => 42, 'first_name' => 'Anna', 'is_bot' => false],
|
||||
'link' => [
|
||||
'type' => 'forward',
|
||||
'message' => ['mid' => 'mid.original', 'seq' => 1, 'text' => 'Original', 'markup' => null],
|
||||
'sender' => null,
|
||||
'chat_id' => -200,
|
||||
],
|
||||
'stat' => ['views' => 10],
|
||||
]);
|
||||
|
||||
$this->assertSame(1678886400000, $comment->timestamp);
|
||||
$this->assertSame('mid.post', $comment->recipient->postId);
|
||||
$this->assertSame('mid.comment', $comment->body->mid);
|
||||
$this->assertSame(7, $comment->body->seq);
|
||||
$this->assertSame('Agree', $comment->body->text);
|
||||
$this->assertSame('Anna', $comment->sender?->firstName);
|
||||
$this->assertSame(MessageLinkType::Forward, $comment->link?->type);
|
||||
$this->assertSame('Original', $comment->link?->message->text);
|
||||
$this->assertSame(-200, $comment->link?->chatId);
|
||||
$this->assertSame(10, $comment->stat?->views);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function commentOnBehalfOfChannelHasNoSender(): void
|
||||
{
|
||||
$comment = CommentMessage::fromArray([
|
||||
'timestamp' => 1,
|
||||
'recipient' => ['chat_type' => 'channel', 'chat_id' => -100],
|
||||
'body' => ['mid' => 'mid.comment', 'seq' => 1],
|
||||
]);
|
||||
|
||||
$this->assertNull($comment->sender);
|
||||
$this->assertNull($comment->link);
|
||||
$this->assertNull($comment->body->text);
|
||||
$this->assertNull($comment->body->markup);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user