diff --git a/src/Laravel/MaxBotManager.php b/src/Laravel/MaxBotManager.php index 254bf7c..6464d98 100644 --- a/src/Laravel/MaxBotManager.php +++ b/src/Laravel/MaxBotManager.php @@ -359,6 +359,58 @@ readonly class MaxBotManager $this->dispatcher->onMessageChatCreated($this->resolveHandler($handler)); } + /** + * Register a comment created handler. + * + * @param callable|string $handler Can be a closure, callable, or Laravel container binding. + * + * @throws BindingResolutionException + * @codeCoverageIgnore + */ + public function onCommentCreated(callable|string $handler): void + { + $this->dispatcher->onCommentCreated($this->resolveHandler($handler)); + } + + /** + * Register a comment edited handler. + * + * @param callable|string $handler Can be a closure, callable, or Laravel container binding. + * + * @throws BindingResolutionException + * @codeCoverageIgnore + */ + public function onCommentEdited(callable|string $handler): void + { + $this->dispatcher->onCommentEdited($this->resolveHandler($handler)); + } + + /** + * Register a comment removed handler. + * + * @param callable|string $handler Can be a closure, callable, or Laravel container binding. + * + * @throws BindingResolutionException + * @codeCoverageIgnore + */ + public function onCommentRemoved(callable|string $handler): void + { + $this->dispatcher->onCommentRemoved($this->resolveHandler($handler)); + } + + /** + * Register a bot admin permissions changed handler. + * + * @param callable|string $handler Can be a closure, callable, or Laravel container binding. + * + * @throws BindingResolutionException + * @codeCoverageIgnore + */ + public function onBotAdminPermissionsChanged(callable|string $handler): void + { + $this->dispatcher->onBotAdminPermissionsChanged($this->resolveHandler($handler)); + } + /** * Get the API instance. * @codeCoverageIgnore diff --git a/src/ModelFactory.php b/src/ModelFactory.php index 7f6785a..412a4c1 100644 --- a/src/ModelFactory.php +++ b/src/ModelFactory.php @@ -57,8 +57,12 @@ use BushlanovDev\MaxMessengerBot\Models\Updates\AbstractUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\BotAddedToChatUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\BotRemovedFromChatUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\BotStartedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\BotAdminPermissionsChangedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\BotStoppedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\ChatTitleChangedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\CommentCreatedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\CommentEditedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\CommentRemovedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\DialogClearedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\DialogMutedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\DialogRemovedUpdate; @@ -409,6 +413,10 @@ readonly class ModelFactory UpdateType::BotStopped => BotStoppedUpdate::fromArray($data), UpdateType::ChatTitleChanged => ChatTitleChangedUpdate::fromArray($data), UpdateType::MessageChatCreated => MessageChatCreatedUpdate::fromArray($data), + UpdateType::CommentCreated => CommentCreatedUpdate::fromArray($data), + UpdateType::CommentEdited => CommentEditedUpdate::fromArray($data), + UpdateType::CommentRemoved => CommentRemovedUpdate::fromArray($data), + UpdateType::BotAdminPermissionChanged => BotAdminPermissionsChangedUpdate::fromArray($data), default => throw new LogicException( 'Unknown or unsupported update type received: ' . ($data['update_type'] ?? 'none') ), diff --git a/src/Models/Updates/BotAdminPermissionsChangedUpdate.php b/src/Models/Updates/BotAdminPermissionsChangedUpdate.php new file mode 100644 index 0000000..e0a614e --- /dev/null +++ b/src/Models/Updates/BotAdminPermissionsChangedUpdate.php @@ -0,0 +1,37 @@ +addHandler(UpdateType::MessageChatCreated, $handler); } + + /** + * A convenient alias for addHandler(UpdateType::CommentCreated, $handler). + * + * @param callable(Models\Updates\CommentCreatedUpdate, Api): void $handler + * + * @return $this + * @codeCoverageIgnore + */ + public function onCommentCreated(callable $handler): self + { + return $this->addHandler(UpdateType::CommentCreated, $handler); + } + + /** + * A convenient alias for addHandler(UpdateType::CommentEdited, $handler). + * + * @param callable(Models\Updates\CommentEditedUpdate, Api): void $handler + * + * @return $this + * @codeCoverageIgnore + */ + public function onCommentEdited(callable $handler): self + { + return $this->addHandler(UpdateType::CommentEdited, $handler); + } + + /** + * A convenient alias for addHandler(UpdateType::CommentRemoved, $handler). + * + * @param callable(Models\Updates\CommentRemovedUpdate, Api): void $handler + * + * @return $this + * @codeCoverageIgnore + */ + public function onCommentRemoved(callable $handler): self + { + return $this->addHandler(UpdateType::CommentRemoved, $handler); + } + + /** + * A convenient alias for addHandler(UpdateType::BotAdminPermissionChanged, $handler). + * + * @param callable(Models\Updates\BotAdminPermissionsChangedUpdate, Api): void $handler + * + * @return $this + * @codeCoverageIgnore + */ + public function onBotAdminPermissionsChanged(callable $handler): self + { + return $this->addHandler(UpdateType::BotAdminPermissionChanged, $handler); + } } diff --git a/tests/ModelFactoryTest.php b/tests/ModelFactoryTest.php index f9c315b..cd8cb6f 100644 --- a/tests/ModelFactoryTest.php +++ b/tests/ModelFactoryTest.php @@ -43,8 +43,12 @@ use BushlanovDev\MaxMessengerBot\Models\Recipient; use BushlanovDev\MaxMessengerBot\Models\Result; use BushlanovDev\MaxMessengerBot\Models\Subscription; use BushlanovDev\MaxMessengerBot\Models\UpdateList; +use BushlanovDev\MaxMessengerBot\Models\Updates\BotAdminPermissionsChangedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\BotStartedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\ChatTitleChangedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\CommentCreatedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\CommentEditedUpdate; +use BushlanovDev\MaxMessengerBot\Models\Updates\CommentRemovedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\MessageChatCreatedUpdate; use BushlanovDev\MaxMessengerBot\Models\Updates\MessageCreatedUpdate; use BushlanovDev\MaxMessengerBot\Models\UploadEndpoint; @@ -104,6 +108,10 @@ use Psr\Log\LoggerInterface; #[UsesClass(LocationAttachment::class)] #[UsesClass(InlineKeyboardAttachment::class)] #[UsesClass(KeyboardPayload::class)] +#[UsesClass(CommentCreatedUpdate::class)] +#[UsesClass(CommentEditedUpdate::class)] +#[UsesClass(CommentRemovedUpdate::class)] +#[UsesClass(BotAdminPermissionsChangedUpdate::class)] final class ModelFactoryTest extends TestCase { private ModelFactory $factory; @@ -348,6 +356,45 @@ final class ModelFactoryTest extends TestCase $this->assertInstanceOf(UserWithPhoto::class, $chat->dialogWithUser); } + #[Test] + public function createUpdateHandlesCommentAndBotPermissionUpdates(): void + { + $comment = [ + 'timestamp' => 1, + 'body' => ['mid' => 'mid.comment', 'seq' => 1, 'text' => 'Nice post'], + 'recipient' => ['chat_type' => 'channel', 'chat_id' => -100, 'post_id' => 'mid.post'], + ]; + + $created = $this->factory->createUpdate(['update_type' => 'comment_created', 'timestamp' => 1, 'message' => $comment]); + $edited = $this->factory->createUpdate(['update_type' => 'comment_edited', 'timestamp' => 2, 'message' => $comment]); + $removed = $this->factory->createUpdate([ + 'update_type' => 'comment_removed', + 'timestamp' => 3, + 'message_id' => 'mid.comment', + 'chat_id' => -100, + 'user_id' => 42, + 'post_id' => 'mid.post', + ]); + $permissions = $this->factory->createUpdate([ + 'update_type' => 'bot_admin_permissions_changed', + 'timestamp' => 4, + 'chat_id' => -100, + 'user_id' => 42, + 'bot_id' => 7, + 'is_channel' => true, + 'is_admin' => true, + 'permissions' => ['read_all_messages', 'write'], + ]); + + $this->assertInstanceOf(CommentCreatedUpdate::class, $created); + $this->assertSame('Nice post', $created->message->body?->text); + $this->assertInstanceOf(CommentEditedUpdate::class, $edited); + $this->assertInstanceOf(CommentRemovedUpdate::class, $removed); + $this->assertSame('mid.post', $removed->postId); + $this->assertInstanceOf(BotAdminPermissionsChangedUpdate::class, $permissions); + $this->assertSame([ChatAdminPermission::ReadAllMessages, ChatAdminPermission::Write], $permissions->permissions); + } + #[Test] public function createUpdateListHandlesDifferentUpdateTypes(): void { diff --git a/tests/Models/Updates/BotAdminPermissionsChangedUpdateTest.php b/tests/Models/Updates/BotAdminPermissionsChangedUpdateTest.php new file mode 100644 index 0000000..3e254ec --- /dev/null +++ b/tests/Models/Updates/BotAdminPermissionsChangedUpdateTest.php @@ -0,0 +1,59 @@ + UpdateType::BotAdminPermissionChanged->value, + 'timestamp' => 1678886400000, + 'chat_id' => -100, + 'user_id' => 42, + 'bot_id' => 7, + 'is_channel' => true, + 'is_admin' => true, + 'permissions' => ['read_all_messages', 'pin_message'], + ]); + + $this->assertSame(UpdateType::BotAdminPermissionChanged, $update->updateType); + $this->assertSame(-100, $update->chatId); + $this->assertSame(42, $update->userId); + $this->assertSame(7, $update->botId); + $this->assertTrue($update->isChannel); + $this->assertTrue($update->isAdmin); + $this->assertSame([ChatAdminPermission::ReadAllMessages, ChatAdminPermission::PinMessage], $update->permissions); + } + + #[Test] + public function permissionsAreNullWhenTheBotIsNoLongerAdmin(): void + { + $update = BotAdminPermissionsChangedUpdate::fromArray([ + 'update_type' => UpdateType::BotAdminPermissionChanged->value, + 'timestamp' => 1678886400000, + 'chat_id' => -100, + 'user_id' => 42, + 'bot_id' => 7, + 'is_channel' => false, + 'is_admin' => false, + ]); + + $this->assertFalse($update->isAdmin); + $this->assertNull($update->permissions); + } +} diff --git a/tests/Models/Updates/CommentCreatedUpdateTest.php b/tests/Models/Updates/CommentCreatedUpdateTest.php new file mode 100644 index 0000000..c21a5bd --- /dev/null +++ b/tests/Models/Updates/CommentCreatedUpdateTest.php @@ -0,0 +1,41 @@ + UpdateType::CommentCreated->value, + 'timestamp' => 1678886400000, + 'message' => [ + 'timestamp' => 1678886400000, + 'body' => ['mid' => 'mid.comment', 'seq' => 5, 'text' => 'Nice post'], + 'recipient' => ['chat_type' => 'channel', 'chat_id' => -100], + ], + ]); + + $this->assertSame(UpdateType::CommentCreated, $update->updateType); + $this->assertSame(1678886400000, $update->timestamp); + $this->assertSame('mid.comment', $update->message->body?->mid); + $this->assertSame('Nice post', $update->message->body?->text); + } +} diff --git a/tests/Models/Updates/CommentEditedUpdateTest.php b/tests/Models/Updates/CommentEditedUpdateTest.php new file mode 100644 index 0000000..85b2f86 --- /dev/null +++ b/tests/Models/Updates/CommentEditedUpdateTest.php @@ -0,0 +1,41 @@ + UpdateType::CommentEdited->value, + 'timestamp' => 1678886400000, + 'message' => [ + 'timestamp' => 1678886400000, + 'body' => ['mid' => 'mid.comment', 'seq' => 5, 'text' => 'Nice post'], + 'recipient' => ['chat_type' => 'channel', 'chat_id' => -100], + ], + ]); + + $this->assertSame(UpdateType::CommentEdited, $update->updateType); + $this->assertSame(1678886400000, $update->timestamp); + $this->assertSame('mid.comment', $update->message->body?->mid); + $this->assertSame('Nice post', $update->message->body?->text); + } +} diff --git a/tests/Models/Updates/CommentRemovedUpdateTest.php b/tests/Models/Updates/CommentRemovedUpdateTest.php new file mode 100644 index 0000000..f4774c4 --- /dev/null +++ b/tests/Models/Updates/CommentRemovedUpdateTest.php @@ -0,0 +1,34 @@ + UpdateType::CommentRemoved->value, + 'timestamp' => 1678886400000, + 'message_id' => 'mid.comment', + 'chat_id' => -100, + 'user_id' => 42, + 'post_id' => 'mid.post', + ]); + + $this->assertSame(UpdateType::CommentRemoved, $update->updateType); + $this->assertSame('mid.comment', $update->messageId); + $this->assertSame(-100, $update->chatId); + $this->assertSame(42, $update->userId); + $this->assertSame('mid.post', $update->postId); + } +}