mirror of
https://github.com/BushlanovDev/max-bot-api-client-php.git
synced 2026-08-21 00:14:22 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3dd4d9a29 | |||
| 67ce2958a6 |
@@ -30,17 +30,17 @@
|
||||
|
||||
#### Chats
|
||||
|
||||
- [ ] `GET /chats` (`getChats`) — *Получение списка всех чатов бота.*
|
||||
- [ ] `GET /chats/{chatLink}` (`getChatByLink`) — *Получение информации о чате по ссылке.*
|
||||
- [x] `GET /chats` (`getChats`) — *Получение списка всех чатов бота.*
|
||||
- [x] `GET /chats/{chatLink}` (`getChatByLink`) — *Получение информации о чате по ссылке.*
|
||||
- [x] `GET /chats/{chatId}` (`getChat`) — *Получение информации о чате по ID.*
|
||||
- [ ] `PATCH /chats/{chatId}` (`editChat`) — *Редактирование информации о чате.*
|
||||
- [ ] `DELETE /chats/{chatId}` (`deleteChat`) — *Удаление чата.*
|
||||
- [ ] `POST /chats/{chatId}/actions` (`sendAction`) — *Отправка действия в чат (например, "печатает...").*
|
||||
- [ ] `GET /chats/{chatId}/pin` (`getPinnedMessage`) — *Получение закрепленного сообщения.*
|
||||
- [x] `DELETE /chats/{chatId}` (`deleteChat`) — *Удаление чата.*
|
||||
- [x] `POST /chats/{chatId}/actions` (`sendAction`) — *Отправка действия в чат (например, "печатает...").*
|
||||
- [x] `GET /chats/{chatId}/pin` (`getPinnedMessage`) — *Получение закрепленного сообщения.*
|
||||
- [ ] `PUT /chats/{chatId}/pin` (`pinMessage`) — *Закрепление сообщения.*
|
||||
- [ ] `DELETE /chats/{chatId}/pin` (`unpinMessage`) — *Открепление сообщения.*
|
||||
- [ ] `GET /chats/{chatId}/members/me` (`getMembership`) — *Получение информации о членстве бота в чате.*
|
||||
- [ ] `DELETE /chats/{chatId}/members/me` (`leaveChat`) — *Выход бота из чата.*
|
||||
- [x] `DELETE /chats/{chatId}/pin` (`unpinMessage`) — *Открепление сообщения.*
|
||||
- [x] `GET /chats/{chatId}/members/me` (`getMembership`) — *Получение информации о членстве бота в чате.*
|
||||
- [x] `DELETE /chats/{chatId}/members/me` (`leaveChat`) — *Выход бота из чата.*
|
||||
- [ ] `GET /chats/{chatId}/members/admins` (`getAdmins`) — *Получение администраторов чата.*
|
||||
- [ ] `POST /chats/{chatId}/members/admins` (`postAdmins`) — *Назначение администраторов чата.*
|
||||
- [ ] `DELETE /chats/{chatId}/members/admins/{userId}` (`deleteAdmins`) — *Снятие прав администратора.*
|
||||
@@ -68,3 +68,7 @@
|
||||
- [ ] `GET /messages/{messageId}` (`getMessageById`) — *Получение сообщения по ID.*
|
||||
- [ ] `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) — *Получение детальной информации о видео.*
|
||||
- [ ] `POST /answers` (`answerOnCallback`) — *Ответ на нажатие callback-кнопки.*
|
||||
|
||||
## Лицензия
|
||||
|
||||
Данная библиотека распространяется по лицензии MIT - подробности см. в файле [LICENSE](LICENSE).
|
||||
|
||||
+191
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace BushlanovDev\MaxMessengerBot;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Enums\MessageFormat;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\SenderAction;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UploadType;
|
||||
use BushlanovDev\MaxMessengerBot\Exceptions\ClientApiException;
|
||||
@@ -19,6 +20,8 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\PhotoAttachmentRequ
|
||||
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\VideoAttachmentRequest;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Message;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageLink;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Result;
|
||||
@@ -46,12 +49,16 @@ class Api
|
||||
private const string METHOD_GET = 'GET';
|
||||
private const string METHOD_POST = 'POST';
|
||||
private const string METHOD_DELETE = 'DELETE';
|
||||
// private const string METHOD_PATCH = 'PATCH';
|
||||
|
||||
private const string ACTION_ME = '/me';
|
||||
private const string ACTION_SUBSCRIPTIONS = '/subscriptions';
|
||||
private const string ACTION_MESSAGES = '/messages';
|
||||
private const string ACTION_UPLOADS = '/uploads';
|
||||
private const string ACTION_CHATS = '/chats';
|
||||
private const string ACTION_CHATS_ACTIONS = '/chats/%d/actions';
|
||||
private const string ACTION_CHATS_PIN = '/chats/%d/pin';
|
||||
private const string ACTION_CHATS_MEMBERS_ME = '/chats/%d/members/me';
|
||||
private const string ACTION_UPDATES = '/updates';
|
||||
|
||||
private readonly ClientApiInterface $client;
|
||||
@@ -477,4 +484,188 @@ class Api
|
||||
$this->client->request(self::METHOD_GET, self::ACTION_CHATS . '/' . $chatId)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns chat/channel information by its public link or a dialog with a user by their username.
|
||||
* The link should be prefixed with '@' or can be passed without it.
|
||||
*
|
||||
* @param string $chatLink Public chat link (e.g., '@mychannel') or username (e.g., '@john_doe').
|
||||
*
|
||||
* @return Chat
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function getChatByLink(string $chatLink): Chat
|
||||
{
|
||||
return $this->modelFactory->createChat(
|
||||
$this->client->request(
|
||||
self::METHOD_GET,
|
||||
self::ACTION_CHATS . '/' . $chatLink,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about chats that the bot participated in. The result is a paginated list.
|
||||
*
|
||||
* @param int|null $count Number of chats requested (1-100, default 50).
|
||||
* @param int|null $marker Points to the next data page. Use null for the first page.
|
||||
*
|
||||
* @return ChatList
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function getChats(?int $count = null, ?int $marker = null): ChatList
|
||||
{
|
||||
$query = [
|
||||
'count' => $count,
|
||||
'marker' => $marker,
|
||||
];
|
||||
|
||||
return $this->modelFactory->createChatList(
|
||||
$this->client->request(
|
||||
self::METHOD_GET,
|
||||
self::ACTION_CHATS,
|
||||
array_filter($query, fn($value) => $value !== null),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a chat for all participants. The bot must have appropriate permissions.
|
||||
*
|
||||
* @param int $chatId Chat identifier to delete.
|
||||
*
|
||||
* @return Result
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function deleteChat(int $chatId): Result
|
||||
{
|
||||
return $this->modelFactory->createResult(
|
||||
$this->client->request(
|
||||
self::METHOD_DELETE,
|
||||
self::ACTION_CHATS . '/' . $chatId,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a specific action to a chat, such as 'typing...'. This is used to show bot activity to the user.
|
||||
*
|
||||
* @param int $chatId The identifier of the target chat.
|
||||
* @param SenderAction $action The action to be sent.
|
||||
*
|
||||
* @return Result
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function sendAction(int $chatId, SenderAction $action): Result
|
||||
{
|
||||
return $this->modelFactory->createResult(
|
||||
$this->client->request(
|
||||
self::METHOD_POST,
|
||||
sprintf(self::ACTION_CHATS_ACTIONS, $chatId),
|
||||
[],
|
||||
['action' => $action->value],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pinned message in a chat or channel.
|
||||
*
|
||||
* @param int $chatId Identifier of the chat to get its pinned message from.
|
||||
*
|
||||
* @return Message|null
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function getPinnedMessage(int $chatId): ?Message
|
||||
{
|
||||
$response = $this->client->request(
|
||||
self::METHOD_GET,
|
||||
sprintf(self::ACTION_CHATS_PIN, $chatId),
|
||||
);
|
||||
|
||||
if (!isset($response['message']) || empty($response['message'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return $this->modelFactory->createMessage($response['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins a message in a chat or channel.
|
||||
*
|
||||
* @param int $chatId Chat identifier to remove the pinned message from.
|
||||
*
|
||||
* @return Result
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function unpinMessage(int $chatId): Result
|
||||
{
|
||||
return $this->modelFactory->createResult(
|
||||
$this->client->request(
|
||||
self::METHOD_DELETE,
|
||||
sprintf(self::ACTION_CHATS_PIN, $chatId),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns chat membership info for the current bot.
|
||||
*
|
||||
* @param int $chatId Chat identifier.
|
||||
*
|
||||
* @return ChatMember
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function getMembership(int $chatId): ChatMember
|
||||
{
|
||||
return $this->modelFactory->createChatMember(
|
||||
$this->client->request(
|
||||
self::METHOD_GET,
|
||||
sprintf(self::ACTION_CHATS_MEMBERS_ME, $chatId),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the bot from a chat's members.
|
||||
*
|
||||
* @param int $chatId Chat identifier to leave from.
|
||||
*
|
||||
* @return Result A simple success/fail result.
|
||||
* @throws ClientApiException
|
||||
* @throws NetworkException
|
||||
* @throws ReflectionException
|
||||
* @throws SerializationException
|
||||
*/
|
||||
public function leaveChat(int $chatId): Result
|
||||
{
|
||||
return $this->modelFactory->createResult(
|
||||
$this->client->request(
|
||||
self::METHOD_DELETE,
|
||||
sprintf(self::ACTION_CHATS_MEMBERS_ME, $chatId),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Enums;
|
||||
|
||||
/**
|
||||
* Defines the permissions an administrator can have in a chat.
|
||||
*/
|
||||
enum ChatAdminPermission: string
|
||||
{
|
||||
case ReadAllMessages = 'read_all_messages';
|
||||
case AddRemoveMembers = 'add_remove_members';
|
||||
case AddAdmins = 'add_admins';
|
||||
case ChangeChatInfo = 'change_chat_info';
|
||||
case PinMessage = 'pin_message';
|
||||
case Write = 'write';
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Enums;
|
||||
|
||||
/**
|
||||
* Represents the different actions a bot can send to a chat to indicate its status.
|
||||
*/
|
||||
enum SenderAction: string
|
||||
{
|
||||
case TypingOn = 'typing_on';
|
||||
case SendingPhoto = 'sending_photo';
|
||||
case SendingVideo = 'sending_video';
|
||||
case SendingAudio = 'sending_audio';
|
||||
case SendingFile = 'sending_file';
|
||||
case MarkSeen = 'mark_seen';
|
||||
}
|
||||
@@ -7,6 +7,8 @@ namespace BushlanovDev\MaxMessengerBot;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Message;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Result;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Subscription;
|
||||
@@ -178,4 +180,30 @@ class ModelFactory
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about chat list.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return ChatList
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function createChatList(array $data): ChatList
|
||||
{
|
||||
return ChatList::fromArray($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ChatMember object from raw API data.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return ChatMember
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function createChatMember(array $data): ChatMember
|
||||
{
|
||||
return ChatMember::fromArray($data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||
|
||||
/**
|
||||
* Represents a paginated list of chats.
|
||||
*/
|
||||
final readonly class ChatList extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @param Chat[] $chats List of requested chats.
|
||||
* @param int|null $marker Reference to the next page of requested chats. Can be null if it's the last page.
|
||||
*/
|
||||
public function __construct(
|
||||
#[ArrayOf(Chat::class)]
|
||||
public array $chats,
|
||||
public ?int $marker,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||
|
||||
/**
|
||||
* Represents a member of a chat, including their user information and chat-specific status.
|
||||
*/
|
||||
final readonly class ChatMember extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @param int $userId User's identifier.
|
||||
* @param string $firstName User's first name.
|
||||
* @param string|null $lastName User's last name.
|
||||
* @param string|null $username User's public username.
|
||||
* @param bool $isBot True if the user is a bot.
|
||||
* @param int $lastActivityTime Time of the user's last activity in Max.
|
||||
* @param string|null $description User's profile description.
|
||||
* @param string|null $avatarUrl URL of the user's avatar.
|
||||
* @param string|null $fullAvatarUrl URL of the user's full-sized avatar.
|
||||
* @param int $lastAccessTime The time the user last accessed the chat.
|
||||
* @param bool $isOwner True if this member is the owner of the chat.
|
||||
* @param bool $isAdmin True if this member is an administrator of the chat.
|
||||
* @param int $joinTime The time the user joined the chat.
|
||||
* @param ChatAdminPermission[]|null $permissions A list of permissions if the member is an admin, otherwise null.
|
||||
*/
|
||||
public function __construct(
|
||||
public int $userId,
|
||||
public string $firstName,
|
||||
public ?string $lastName,
|
||||
public ?string $username,
|
||||
public bool $isBot,
|
||||
public int $lastActivityTime,
|
||||
public ?string $description,
|
||||
public ?string $avatarUrl,
|
||||
public ?string $fullAvatarUrl,
|
||||
public int $lastAccessTime,
|
||||
public bool $isOwner,
|
||||
public bool $isAdmin,
|
||||
public int $joinTime,
|
||||
#[ArrayOf(ChatAdminPermission::class)]
|
||||
public ?array $permissions,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,13 @@ declare(strict_types=1);
|
||||
namespace BushlanovDev\MaxMessengerBot\Tests;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Api;
|
||||
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||
use BushlanovDev\MaxMessengerBot\Client;
|
||||
use BushlanovDev\MaxMessengerBot\ClientApiInterface;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\AttachmentType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\ButtonType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\MessageFormat;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\SenderAction;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UploadType;
|
||||
use BushlanovDev\MaxMessengerBot\Exceptions\SerializationException;
|
||||
@@ -34,6 +36,8 @@ use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\StickerAttachmentRe
|
||||
use BushlanovDev\MaxMessengerBot\Models\Attachments\Requests\VideoAttachmentRequest;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Message;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageBody;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Recipient;
|
||||
@@ -98,6 +102,9 @@ use RuntimeException;
|
||||
#[UsesClass(LocationAttachmentRequestPayload::class)]
|
||||
#[UsesClass(ShareAttachmentRequest::class)]
|
||||
#[UsesClass(ShareAttachmentRequestPayload::class)]
|
||||
#[UsesClass(ChatList::class)]
|
||||
#[UsesClass(ChatMember::class)]
|
||||
#[UsesClass(ArrayOf::class)]
|
||||
final class ApiTest extends TestCase
|
||||
{
|
||||
use PHPMock;
|
||||
@@ -1197,4 +1204,300 @@ final class ApiTest extends TestCase
|
||||
|
||||
$this->assertSame($expectedMessageObject, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getChatsPassesAllParametersToClient(): void
|
||||
{
|
||||
$count = 30;
|
||||
$marker = 12345;
|
||||
$expectedQuery = ['count' => $count, 'marker' => $marker];
|
||||
|
||||
$rawResponse = ['chats' => [], 'marker' => 54321];
|
||||
$expectedChatList = new ChatList([], 54321);
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', '/chats', $expectedQuery)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createChatList')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedChatList);
|
||||
|
||||
$result = $this->api->getChats($count, $marker);
|
||||
|
||||
$this->assertSame($expectedChatList, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getChatsHandlesNullParametersCorrectly(): void
|
||||
{
|
||||
$expectedQuery = [];
|
||||
$rawResponse = ['chats' => [], 'marker' => null];
|
||||
$expectedChatList = new ChatList([], null);
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', '/chats', $expectedQuery)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createChatList')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedChatList);
|
||||
|
||||
$result = $this->api->getChats(null, null);
|
||||
|
||||
$this->assertSame($expectedChatList, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getChatByLinkCallsClientAndFactoryCorrectly(): void
|
||||
{
|
||||
$chatLink = '@test_channel';
|
||||
$rawResponseData = [
|
||||
'chat_id' => 987,
|
||||
'type' => 'channel',
|
||||
'status' => 'active',
|
||||
'last_event_time' => 1,
|
||||
'participants_count' => 100,
|
||||
'is_public' => true,
|
||||
'title' => 'Test Channel',
|
||||
];
|
||||
|
||||
$expectedChatObject = Chat::fromArray($rawResponseData);
|
||||
|
||||
$this->clientMock
|
||||
->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', '/chats/' . $chatLink)
|
||||
->willReturn($rawResponseData);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createChat')
|
||||
->with($rawResponseData)
|
||||
->willReturn($expectedChatObject);
|
||||
|
||||
$result = $this->api->getChatByLink($chatLink);
|
||||
|
||||
$this->assertSame($expectedChatObject, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getChatByLinkHandlesLinkWithoutAtSymbol(): void
|
||||
{
|
||||
$chatLink = 'test_channel_no_at';
|
||||
$rawResponseData = [
|
||||
'chat_id' => 987,
|
||||
'type' => 'channel',
|
||||
'status' => 'active',
|
||||
'last_event_time' => 1,
|
||||
'participants_count' => 100,
|
||||
'is_public' => true,
|
||||
'title' => 'Test Channel',
|
||||
];
|
||||
$expectedChatObject = Chat::fromArray($rawResponseData);
|
||||
|
||||
$this->clientMock->method('request')->willReturn($rawResponseData);
|
||||
$this->modelFactoryMock->method('createChat')->willReturn($expectedChatObject);
|
||||
|
||||
$this->api->getChatByLink($chatLink);
|
||||
|
||||
$this->expectNotToPerformAssertions();
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function deleteChatCallsClientAndFactoryCorrectly(): void
|
||||
{
|
||||
$chatId = 123456789;
|
||||
$rawResponseData = ['success' => true, 'message' => null];
|
||||
$expectedResultObject = new Result(true, null);
|
||||
|
||||
$this->clientMock
|
||||
->expects($this->once())
|
||||
->method('request')
|
||||
->with(self::equalTo('DELETE'), self::equalTo('/chats/' . $chatId))
|
||||
->willReturn($rawResponseData);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createResult')
|
||||
->with($rawResponseData)
|
||||
->willReturn($expectedResultObject);
|
||||
|
||||
$result = $this->api->deleteChat($chatId);
|
||||
|
||||
$this->assertSame($expectedResultObject, $result);
|
||||
$this->assertTrue($result->success);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function sendActionCallsClientCorrectly(): void
|
||||
{
|
||||
$chatId = 12345;
|
||||
$action = SenderAction::TypingOn;
|
||||
$uri = '/chats/' . $chatId . '/actions';
|
||||
$expectedBody = ['action' => 'typing_on'];
|
||||
$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->sendAction($chatId, $action);
|
||||
$this->assertSame($expectedResult, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getPinnedMessageReturnsMessageOnSuccess(): void
|
||||
{
|
||||
$chatId = 12345;
|
||||
$uri = '/chats/' . $chatId . '/pin';
|
||||
|
||||
$messageData = [
|
||||
'timestamp' => 1,
|
||||
'body' => ['mid' => 'pinned.msg', 'seq' => 1],
|
||||
'recipient' => ['chat_type' => 'chat', 'chat_id' => $chatId],
|
||||
];
|
||||
$rawResponse = ['message' => $messageData];
|
||||
|
||||
$expectedMessage = Message::fromArray($messageData);
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', $uri)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock->expects($this->once())
|
||||
->method('createMessage')
|
||||
->with($messageData)
|
||||
->willReturn($expectedMessage);
|
||||
|
||||
$actualMessage = $this->api->getPinnedMessage($chatId);
|
||||
|
||||
$this->assertSame($expectedMessage, $actualMessage);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getPinnedMessageReturnsNullWhenNoMessageIsPinned(): void
|
||||
{
|
||||
$chatId = 54321;
|
||||
$uri = '/chats/' . $chatId . '/pin';
|
||||
$rawResponse = ['message' => null];
|
||||
|
||||
$this->clientMock->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', $uri)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock->expects($this->never())
|
||||
->method('createMessage');
|
||||
|
||||
$result = $this->api->getPinnedMessage($chatId);
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function unpinMessageCallsClientCorrectly(): void
|
||||
{
|
||||
$chatId = 98765;
|
||||
$uri = '/chats/' . $chatId . '/pin';
|
||||
$rawResponse = ['success' => true, 'message' => null];
|
||||
$expectedResult = new Result(true, null);
|
||||
|
||||
$this->clientMock
|
||||
->expects($this->once())
|
||||
->method('request')
|
||||
->with(self::equalTo('DELETE'), self::equalTo($uri))
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createResult')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedResult);
|
||||
|
||||
$result = $this->api->unpinMessage($chatId);
|
||||
|
||||
$this->assertSame($expectedResult, $result);
|
||||
$this->assertTrue($result->success);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getMembershipReturnsCorrectChatMember(): void
|
||||
{
|
||||
$chatId = 12345;
|
||||
$uri = sprintf('/chats/%d/members/me', $chatId);
|
||||
|
||||
$rawResponse = [
|
||||
'user_id' => 1,
|
||||
'first_name' => 'MyBot',
|
||||
'is_bot' => true,
|
||||
'last_activity_time' => 1,
|
||||
'last_name' => null,
|
||||
'username' => 'my_bot',
|
||||
'description' => null,
|
||||
'avatar_url' => null,
|
||||
'full_avatar_url' => null,
|
||||
'last_access_time' => 2,
|
||||
'is_owner' => false,
|
||||
'is_admin' => true,
|
||||
'join_time' => 0,
|
||||
'permissions' => ['write'],
|
||||
];
|
||||
$expectedMember = ChatMember::fromArray($rawResponse);
|
||||
|
||||
$this->clientMock
|
||||
->expects($this->once())
|
||||
->method('request')
|
||||
->with('GET', $uri)
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createChatMember')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedMember);
|
||||
|
||||
$result = $this->api->getMembership($chatId);
|
||||
|
||||
$this->assertSame($expectedMember, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function leaveChatCallsClientCorrectly(): void
|
||||
{
|
||||
$chatId = 54321;
|
||||
$uri = sprintf('/chats/%d/members/me', $chatId);
|
||||
$rawResponse = ['success' => true];
|
||||
$expectedResult = new Result(true, null);
|
||||
|
||||
$this->clientMock
|
||||
->expects($this->once())
|
||||
->method('request')
|
||||
->with(self::equalTo('DELETE'), self::equalTo($uri))
|
||||
->willReturn($rawResponse);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createResult')
|
||||
->with($rawResponse)
|
||||
->willReturn($expectedResult);
|
||||
|
||||
$result = $this->api->leaveChat($chatId);
|
||||
|
||||
$this->assertSame($expectedResult, $result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ declare(strict_types=1);
|
||||
namespace BushlanovDev\MaxMessengerBot\Tests;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\UpdateType;
|
||||
use BushlanovDev\MaxMessengerBot\ModelFactory;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotCommand;
|
||||
use BushlanovDev\MaxMessengerBot\Models\BotInfo;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Image;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Message;
|
||||
use BushlanovDev\MaxMessengerBot\Models\MessageBody;
|
||||
@@ -48,6 +51,8 @@ use PHPUnit\Framework\TestCase;
|
||||
#[UsesClass(Image::class)]
|
||||
#[UsesClass(ChatTitleChangedUpdate::class)]
|
||||
#[UsesClass(MessageChatCreatedUpdate::class)]
|
||||
#[UsesClass(ChatList::class)]
|
||||
#[UsesClass(ChatMember::class)]
|
||||
final class ModelFactoryTest extends TestCase
|
||||
{
|
||||
private ModelFactory $factory;
|
||||
@@ -314,4 +319,71 @@ final class ModelFactoryTest extends TestCase
|
||||
$this->assertInstanceOf(ChatTitleChangedUpdate::class, $updateList->updates[2]);
|
||||
$this->assertInstanceOf(MessageChatCreatedUpdate::class, $updateList->updates[3]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function createChatListDelegatesCreationToChatListModel(): void
|
||||
{
|
||||
$rawData = [
|
||||
'chats' => [
|
||||
[
|
||||
'chat_id' => 101,
|
||||
'type' => 'chat',
|
||||
'status' => 'active',
|
||||
'last_event_time' => 1,
|
||||
'participants_count' => 5,
|
||||
'is_public' => false,
|
||||
],
|
||||
[
|
||||
'chat_id' => 102,
|
||||
'type' => 'dialog',
|
||||
'status' => 'suspended',
|
||||
'last_event_time' => 2,
|
||||
'participants_count' => 2,
|
||||
'is_public' => false,
|
||||
],
|
||||
],
|
||||
'marker' => 98765,
|
||||
];
|
||||
|
||||
$chatList = $this->factory->createChatList($rawData);
|
||||
|
||||
$this->assertInstanceOf(ChatList::class, $chatList);
|
||||
|
||||
$this->assertSame(98765, $chatList->marker);
|
||||
$this->assertCount(2, $chatList->chats);
|
||||
$this->assertInstanceOf(Chat::class, $chatList->chats[0]);
|
||||
$this->assertSame(101, $chatList->chats[0]->chatId);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function createChatMember()
|
||||
{
|
||||
$rawData = [
|
||||
'user_id' => 101,
|
||||
'first_name' => 'AdminBot',
|
||||
'last_name' => null,
|
||||
'username' => 'admin_bot',
|
||||
'is_bot' => true,
|
||||
'last_activity_time' => 1678886400,
|
||||
'description' => 'I am a bot.',
|
||||
'avatar_url' => null,
|
||||
'full_avatar_url' => null,
|
||||
'last_access_time' => 1679000000,
|
||||
'is_owner' => false,
|
||||
'is_admin' => true,
|
||||
'join_time' => 1678000000,
|
||||
'permissions' => ['pin_message', 'write'],
|
||||
];
|
||||
|
||||
$chatMember = $this->factory->createChatMember($rawData);
|
||||
|
||||
$this->assertInstanceOf(ChatMember::class, $chatMember);
|
||||
$this->assertTrue($chatMember->isAdmin);
|
||||
$this->assertFalse($chatMember->isOwner);
|
||||
$this->assertIsArray($chatMember->permissions);
|
||||
$this->assertCount(2, $chatMember->permissions);
|
||||
$this->assertSame(ChatAdminPermission::PinMessage, $chatMember->permissions[0]);
|
||||
$this->assertSame(ChatAdminPermission::Write, $chatMember->permissions[1]);
|
||||
$this->assertEquals($rawData, $chatMember->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Tests\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||
use BushlanovDev\MaxMessengerBot\Models\Chat;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatList;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\Attributes\UsesClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
#[CoversClass(ChatList::class)]
|
||||
#[UsesClass(Chat::class)]
|
||||
#[UsesClass(ArrayOf::class)]
|
||||
final class ChatListTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function canBeCreatedFromArray(): void
|
||||
{
|
||||
$rawData = [
|
||||
'chats' => [
|
||||
[
|
||||
'chat_id' => 123,
|
||||
'type' => 'chat',
|
||||
'status' => 'active',
|
||||
'last_event_time' => 1,
|
||||
'participants_count' => 10,
|
||||
'is_public' => false,
|
||||
],
|
||||
[
|
||||
'chat_id' => 456,
|
||||
'type' => 'dialog',
|
||||
'status' => 'active',
|
||||
'last_event_time' => 2,
|
||||
'participants_count' => 2,
|
||||
'is_public' => false,
|
||||
],
|
||||
],
|
||||
'marker' => 98765,
|
||||
];
|
||||
|
||||
$chatList = ChatList::fromArray($rawData);
|
||||
|
||||
$this->assertInstanceOf(ChatList::class, $chatList);
|
||||
$this->assertCount(2, $chatList->chats);
|
||||
$this->assertInstanceOf(Chat::class, $chatList->chats[0]);
|
||||
$this->assertSame(123, $chatList->chats[0]->chatId);
|
||||
$this->assertSame(98765, $chatList->marker);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function canBeCreatedWithEmptyChatsAndNullMarker(): void
|
||||
{
|
||||
$rawData = ['chats' => [], 'marker' => null];
|
||||
$chatList = ChatList::fromArray($rawData);
|
||||
|
||||
$this->assertEmpty($chatList->chats);
|
||||
$this->assertNull($chatList->marker);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BushlanovDev\MaxMessengerBot\Tests\Models;
|
||||
|
||||
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
|
||||
use BushlanovDev\MaxMessengerBot\Enums\ChatAdminPermission;
|
||||
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\Attributes\UsesClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
#[CoversClass(ChatMember::class)]
|
||||
#[UsesClass(ArrayOf::class)]
|
||||
final class ChatMemberTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function canBeCreatedForAdmin(): void
|
||||
{
|
||||
$data = [
|
||||
'user_id' => 101,
|
||||
'first_name' => 'AdminBot',
|
||||
'last_name' => null,
|
||||
'username' => 'admin_bot',
|
||||
'is_bot' => true,
|
||||
'last_activity_time' => 1678886400,
|
||||
'description' => 'I am a bot.',
|
||||
'avatar_url' => null,
|
||||
'full_avatar_url' => null,
|
||||
'last_access_time' => 1679000000,
|
||||
'is_owner' => false,
|
||||
'is_admin' => true,
|
||||
'join_time' => 1678000000,
|
||||
'permissions' => ['pin_message', 'write'],
|
||||
];
|
||||
|
||||
$member = ChatMember::fromArray($data);
|
||||
|
||||
$this->assertInstanceOf(ChatMember::class, $member);
|
||||
$this->assertTrue($member->isAdmin);
|
||||
$this->assertFalse($member->isOwner);
|
||||
$this->assertIsArray($member->permissions);
|
||||
$this->assertCount(2, $member->permissions);
|
||||
$this->assertSame(ChatAdminPermission::PinMessage, $member->permissions[0]);
|
||||
$this->assertSame(ChatAdminPermission::Write, $member->permissions[1]);
|
||||
$this->assertEquals($data, $member->toArray());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function canBeCreatedForRegularMember(): void
|
||||
{
|
||||
$data = [
|
||||
'user_id' => 102,
|
||||
'first_name' => 'RegularUser',
|
||||
'last_name' => 'Smith',
|
||||
'username' => 'regular_user',
|
||||
'is_bot' => false,
|
||||
'last_activity_time' => 1678886401,
|
||||
'description' => null,
|
||||
'avatar_url' => 'http://example.com/avatar.png',
|
||||
'full_avatar_url' => 'http://example.com/avatar_full.png',
|
||||
'last_access_time' => 1679000001,
|
||||
'is_owner' => false,
|
||||
'is_admin' => false,
|
||||
'join_time' => 1678000001,
|
||||
'permissions' => null,
|
||||
];
|
||||
|
||||
$member = ChatMember::fromArray($data);
|
||||
|
||||
$this->assertFalse($member->isAdmin);
|
||||
$this->assertNull($member->permissions);
|
||||
$this->assertEquals($data, $member->toArray());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user