From 6ac7898b36de7c24be18a674fa32ed217ae7f05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Mon, 29 Jan 2024 01:54:00 +0100 Subject: [PATCH 01/19] Implement new reaction features --- src/DB.php | 126 +++++++++++++++--- src/Entities/Chat.php | 17 ++- src/Entities/MessageReactionCountUpdated.php | 24 ++++ src/Entities/MessageReactionUpdated.php | 33 +++++ src/Entities/ReactionCount.php | 24 ++++ src/Entities/ReactionType/Factory.php | 24 ++++ src/Entities/ReactionType/ReactionType.php | 15 +++ .../ReactionType/ReactionTypeCustomEmoji.php | 22 +++ .../ReactionType/ReactionTypeEmoji.php | 22 +++ .../ReactionTypeNotImplemented.php | 11 ++ src/Entities/Update.php | 92 +++++++------ src/Request.php | 3 + structure.sql | 35 +++++ utils/db-schema-update/0.82.0-unreleased.sql | 36 +++++ 14 files changed, 414 insertions(+), 70 deletions(-) create mode 100644 src/Entities/MessageReactionCountUpdated.php create mode 100644 src/Entities/MessageReactionUpdated.php create mode 100644 src/Entities/ReactionCount.php create mode 100644 src/Entities/ReactionType/Factory.php create mode 100644 src/Entities/ReactionType/ReactionType.php create mode 100644 src/Entities/ReactionType/ReactionTypeCustomEmoji.php create mode 100644 src/Entities/ReactionType/ReactionTypeEmoji.php create mode 100644 src/Entities/ReactionType/ReactionTypeNotImplemented.php create mode 100644 utils/db-schema-update/0.82.0-unreleased.sql diff --git a/src/DB.php b/src/DB.php index 6472d171..0ce49d88 100644 --- a/src/DB.php +++ b/src/DB.php @@ -19,6 +19,8 @@ use Longman\TelegramBot\Entities\ChosenInlineResult; use Longman\TelegramBot\Entities\InlineQuery; use Longman\TelegramBot\Entities\Message; +use Longman\TelegramBot\Entities\MessageReactionCountUpdated; +use Longman\TelegramBot\Entities\MessageReactionUpdated; use Longman\TelegramBot\Entities\Payments\PreCheckoutQuery; use Longman\TelegramBot\Entities\Payments\ShippingQuery; use Longman\TelegramBot\Entities\Poll; @@ -153,6 +155,8 @@ protected static function defineTables(): void 'edited_message', 'inline_query', 'message', + 'message_reaction', + 'message_reaction_count', 'poll', 'poll_answer', 'pre_checkout_query', @@ -316,23 +320,6 @@ public static function entitiesArrayToJson(array $entities, $default = null) /** * Insert entry to telegram_update table * - * @param int $update_id - * @param int|null $chat_id - * @param int|null $message_id - * @param int|null $edited_message_id - * @param int|null $channel_post_id - * @param int|null $edited_channel_post_id - * @param string|null $inline_query_id - * @param string|null $chosen_inline_result_id - * @param string|null $callback_query_id - * @param string|null $shipping_query_id - * @param string|null $pre_checkout_query_id - * @param string|null $poll_id - * @param string|null $poll_answer_poll_id - * @param string|null $my_chat_member_updated_id - * @param string|null $chat_member_updated_id - * - * @return bool If the insert was successful * @throws TelegramException */ protected static function insertTelegramUpdate( @@ -342,6 +329,8 @@ protected static function insertTelegramUpdate( ?int $edited_message_id = null, ?int $channel_post_id = null, ?int $edited_channel_post_id = null, + ?string $message_reaction_id = null, + ?string $message_reaction_count_id = null, ?string $inline_query_id = null, ?string $chosen_inline_result_id = null, ?string $callback_query_id = null, @@ -353,8 +342,8 @@ protected static function insertTelegramUpdate( ?string $chat_member_updated_id = null, ?string $chat_join_request_id = null ): ?bool { - if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null) { - throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id are all null'); + if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $message_reaction_id === null && $message_reaction_count_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null) { + throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, message_reaction_id, message_reaction_count_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id are all null'); } if (!self::isDbConnected()) { @@ -366,13 +355,15 @@ protected static function insertTelegramUpdate( INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '` ( `id`, `chat_id`, `message_id`, `edited_message_id`, - `channel_post_id`, `edited_channel_post_id`, `inline_query_id`, `chosen_inline_result_id`, + `channel_post_id`, `edited_channel_post_id`, `message_reaction_id`, `message_reaction_count_id`, + `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `shipping_query_id`, `pre_checkout_query_id`, `poll_id`, `poll_answer_poll_id`, `my_chat_member_updated_id`, `chat_member_updated_id`, `chat_join_request_id` ) VALUES ( :id, :chat_id, :message_id, :edited_message_id, - :channel_post_id, :edited_channel_post_id, :inline_query_id, :chosen_inline_result_id, + :channel_post_id, :edited_channel_post_id, :message_reaction_id, :message_reaction_count_id, + :inline_query_id, :chosen_inline_result_id, :callback_query_id, :shipping_query_id, :pre_checkout_query_id, :poll_id, :poll_answer_poll_id, :my_chat_member_updated_id, :chat_member_updated_id, :chat_join_request_id @@ -385,6 +376,8 @@ protected static function insertTelegramUpdate( $sth->bindValue(':edited_message_id', $edited_message_id); $sth->bindValue(':channel_post_id', $channel_post_id); $sth->bindValue(':edited_channel_post_id', $edited_channel_post_id); + $sth->bindValue(':message_reaction_id', $message_reaction_id); + $sth->bindValue(':message_reaction_count_id', $message_reaction_count_id); $sth->bindValue(':inline_query_id', $inline_query_id); $sth->bindValue(':chosen_inline_result_id', $chosen_inline_result_id); $sth->bindValue(':callback_query_id', $callback_query_id); @@ -556,6 +549,8 @@ public static function insertRequest(Update $update): bool $edited_message_id = null; $channel_post_id = null; $edited_channel_post_id = null; + $message_reaction_id = null; + $message_reaction_count_id = null; $inline_query_id = null; $chosen_inline_result_id = null; $callback_query_id = null; @@ -579,6 +574,14 @@ public static function insertRequest(Update $update): bool } elseif (($edited_channel_post = $update->getEditedChannelPost()) && self::insertEditedMessageRequest($edited_channel_post)) { $chat_id = $edited_channel_post->getChat()->getId(); $edited_channel_post_id = (int) self::$pdo->lastInsertId(); + } elseif (($message_reaction = $update->getMessageReaction()) && self::insertMessageReaction($message_reaction)) { + $chat_id = $message_reaction->getChat()->getId(); + $message_id = $message_reaction->getMessageId(); + $message_reaction_id = self::$pdo->lastInsertId(); + } elseif (($message_reaction_count = $update->getMessageReactionCount()) && self::insertMessageReactionCount($message_reaction_count)) { + $chat_id = $message_reaction_count->getChat()->getId(); + $message_id = $message_reaction_count->getMessageId(); + $message_reaction_count_id = self::$pdo->lastInsertId(); } elseif (($inline_query = $update->getInlineQuery()) && self::insertInlineQueryRequest($inline_query)) { $inline_query_id = $inline_query->getId(); } elseif (($chosen_inline_result = $update->getChosenInlineResult()) && self::insertChosenInlineResultRequest($chosen_inline_result)) { @@ -610,6 +613,8 @@ public static function insertRequest(Update $update): bool $edited_message_id, $channel_post_id, $edited_channel_post_id, + $message_reaction_id, + $message_reaction_count_id, $inline_query_id, $chosen_inline_result_id, $callback_query_id, @@ -623,6 +628,85 @@ public static function insertRequest(Update $update): bool ); } + public static function insertMessageReaction(MessageReactionUpdated $message_reaction): bool + { + if (!self::isDbConnected()) { + return false; + } + + try { + $sth = self::$pdo->prepare(' + INSERT IGNORE INTO `' . TB_MESSAGE_REACTION . '` + (`chat_id`, `message_id`, `user_id`, `actor_chat_id`, `old_reaction`, `new_reaction`, `created_at`) + VALUES + (:chat_id, :message_id, :user_id, :actor_chat_id, :old_reaction, :new_reaction, :created_at) + '); + + $date = self::getTimestamp($message_reaction->getDate()); + $chat_id = null; + $user_id = null; + $actor_chat_id = null; + + if ($chat = $message_reaction->getChat()) { + $chat_id = $chat->getId(); + self::insertChat($chat, $date); + } + if ($user = $message_reaction->getUser()) { + $user_id = $user->getId(); + self::insertUser($user, $date); + } + if ($actor_chat = $message_reaction->getActorChat()) { + $actor_chat_id = $actor_chat->getId(); + self::insertChat($actor_chat, $date); + } + + $sth->bindValue(':chat_id', $chat_id); + $sth->bindValue(':message_id', $message_reaction->getMessageId()); + $sth->bindValue(':user_id', $user_id); + $sth->bindValue(':actor_chat_id', $actor_chat_id); + $sth->bindValue(':old_reaction', self::entitiesArrayToJson($message_reaction->getOldReaction() ?: [])); + $sth->bindValue(':new_reaction', self::entitiesArrayToJson($message_reaction->getNewReaction() ?: [])); + $sth->bindValue(':created_at', $date); + + return $sth->execute(); + } catch (PDOException $e) { + throw new TelegramException($e->getMessage()); + } + } + + public static function insertMessageReactionCount(MessageReactionCountUpdated $message_reaction_count): bool + { + if (!self::isDbConnected()) { + return false; + } + + try { + $sth = self::$pdo->prepare(' + INSERT IGNORE INTO `' . TB_MESSAGE_REACTION_COUNT . '` + (`chat_id`, `message_id`, `reactions`, `created_at`) + VALUES + (:chat_id, :message_id, :reactions, :created_at) + '); + + $date = self::getTimestamp($message_reaction_count->getDate()); + $chat_id = null; + + if ($chat = $message_reaction->getChat()) { + $chat_id = $chat->getId(); + self::insertChat($chat, $date); + } + + $sth->bindValue(':chat_id', $chat_id); + $sth->bindValue(':message_id', $message_reaction_count->getMessageId()); + $sth->bindValue(':reactions', $message_reaction_count->getReactions()); + $sth->bindValue(':created_at', $date); + + return $sth->execute(); + } catch (PDOException $e) { + throw new TelegramException($e->getMessage()); + } + } + /** * Insert inline query request into database * diff --git a/src/Entities/Chat.php b/src/Entities/Chat.php index 97798243..4cc89bc0 100644 --- a/src/Entities/Chat.php +++ b/src/Entities/Chat.php @@ -11,8 +11,11 @@ namespace Longman\TelegramBot\Entities; +use Longman\TelegramBot\Entities\ReactionType\Factory as ReactionTypeFactory; +use Longman\TelegramBot\Entities\ReactionType\ReactionType; + /** - * Class Chat + * This object represents a chat. * * @link https://core.telegram.org/bots/api#chat * @@ -27,6 +30,7 @@ * @method bool getIsForum() Optional. True, if the supergroup chat is a forum (has topics enabled) * @method ChatPhoto getPhoto() Optional. Chat photo. Returned only in getChat. * @method string[] getActiveUsernames() Optional. If non-empty, the list of all active chat usernames; for private chats, supergroups and channels. Returned only in getChat. + * @method ReactionType[] getAvailableReactions() Optional. List of available reactions allowed in the chat. If omitted, then all emoji reactions are allowed. Returned only in getChat. * @method string getEmojiStatusCustomEmojiId() Optional. Custom emoji identifier of emoji status of the other party in a private chat. Returned only in getChat. * @method int getEmojiStatusExpirationDate() Optional. Expiration date of the emoji status of the other party in a private chat in Unix time, if any. Returned only in getChat. * @method string getBio() Optional. Bio of the other party in a private chat. Returned only in getChat. @@ -56,14 +60,15 @@ class Chat extends Entity protected function subEntities(): array { return [ - 'photo' => ChatPhoto::class, - 'pinned_message' => Message::class, - 'permissions' => ChatPermissions::class, - 'location' => ChatLocation::class, + 'photo' => ChatPhoto::class, + 'available_reactions' => [ReactionTypeFactory::class], + 'pinned_message' => Message::class, + 'permissions' => ChatPermissions::class, + 'location' => ChatLocation::class, ]; } - public function __construct($data) + public function __construct(array $data) { parent::__construct($data); diff --git a/src/Entities/MessageReactionCountUpdated.php b/src/Entities/MessageReactionCountUpdated.php new file mode 100644 index 00000000..21dc848b --- /dev/null +++ b/src/Entities/MessageReactionCountUpdated.php @@ -0,0 +1,24 @@ + Chat::class, + 'reactions' => [ReactionCount::class], + ]; + } +} diff --git a/src/Entities/MessageReactionUpdated.php b/src/Entities/MessageReactionUpdated.php new file mode 100644 index 00000000..c5b60214 --- /dev/null +++ b/src/Entities/MessageReactionUpdated.php @@ -0,0 +1,33 @@ + Chat::class, + 'user' => User::class, + 'actor_chat' => Chat::class, + 'old_reaction' => [ReactionTypeFactory::class], + 'new_reaction' => [ReactionTypeFactory::class], + ]; + } +} diff --git a/src/Entities/ReactionCount.php b/src/Entities/ReactionCount.php new file mode 100644 index 00000000..c99e67d3 --- /dev/null +++ b/src/Entities/ReactionCount.php @@ -0,0 +1,24 @@ + ReactionTypeFactory::class, + ]; + } +} diff --git a/src/Entities/ReactionType/Factory.php b/src/Entities/ReactionType/Factory.php new file mode 100644 index 00000000..d7cb8cab --- /dev/null +++ b/src/Entities/ReactionType/Factory.php @@ -0,0 +1,24 @@ + ReactionTypeEmoji::class, + 'custom_emoji' => ReactionTypeCustomEmoji::class, + ]; + + if (!isset($type[$data['type'] ?? ''])) { + return new ReactionTypeNotImplemented($data, $bot_username); + } + + $class = $type[$data['type']]; + return new $class($data, $bot_username); + } +} diff --git a/src/Entities/ReactionType/ReactionType.php b/src/Entities/ReactionType/ReactionType.php new file mode 100644 index 00000000..901f951d --- /dev/null +++ b/src/Entities/ReactionType/ReactionType.php @@ -0,0 +1,15 @@ + Message::class, - self::TYPE_EDITED_MESSAGE => EditedMessage::class, - self::TYPE_CHANNEL_POST => ChannelPost::class, - self::TYPE_EDITED_CHANNEL_POST => EditedChannelPost::class, - self::TYPE_INLINE_QUERY => InlineQuery::class, - self::TYPE_CHOSEN_INLINE_RESULT => ChosenInlineResult::class, - self::TYPE_CALLBACK_QUERY => CallbackQuery::class, - self::TYPE_SHIPPING_QUERY => ShippingQuery::class, - self::TYPE_PRE_CHECKOUT_QUERY => PreCheckoutQuery::class, - self::TYPE_POLL => Poll::class, - self::TYPE_POLL_ANSWER => PollAnswer::class, - self::TYPE_MY_CHAT_MEMBER => ChatMemberUpdated::class, - self::TYPE_CHAT_MEMBER => ChatMemberUpdated::class, - self::TYPE_CHAT_JOIN_REQUEST => ChatJoinRequest::class, + self::TYPE_MESSAGE => Message::class, + self::TYPE_EDITED_MESSAGE => EditedMessage::class, + self::TYPE_CHANNEL_POST => ChannelPost::class, + self::TYPE_EDITED_CHANNEL_POST => EditedChannelPost::class, + self::TYPE_MESSAGE_REACTION => MessageReactionUpdated::class, + self::TYPE_MESSAGE_REACTION_COUNT => MessageReactionCountUpdated::class, + self::TYPE_INLINE_QUERY => InlineQuery::class, + self::TYPE_CHOSEN_INLINE_RESULT => ChosenInlineResult::class, + self::TYPE_CALLBACK_QUERY => CallbackQuery::class, + self::TYPE_SHIPPING_QUERY => ShippingQuery::class, + self::TYPE_PRE_CHECKOUT_QUERY => PreCheckoutQuery::class, + self::TYPE_POLL => Poll::class, + self::TYPE_POLL_ANSWER => PollAnswer::class, + self::TYPE_MY_CHAT_MEMBER => ChatMemberUpdated::class, + self::TYPE_CHAT_MEMBER => ChatMemberUpdated::class, + self::TYPE_CHAT_JOIN_REQUEST => ChatJoinRequest::class, ]; } diff --git a/src/Request.php b/src/Request.php index 04134f7c..e6e12bff 100644 --- a/src/Request.php +++ b/src/Request.php @@ -52,6 +52,7 @@ * @method static ServerResponse sendPoll(array $data) Use this method to send a native poll. A native poll can't be sent to a private chat. On success, the sent Message is returned. * @method static ServerResponse sendDice(array $data) Use this method to send a dice, which will have a random value from 1 to 6. On success, the sent Message is returned. * @method static ServerResponse sendChatAction(array $data) Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success. + * @method static ServerResponse setMessageReaction(array $data) Use this method to change the chosen reactions on a message. Service messages can't be reacted to. Automatically forwarded messages from a channel to its discussion group have the same available reactions as messages in the channel. Returns True on success. * @method static ServerResponse getUserProfilePhotos(array $data) Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos object. * @method static ServerResponse getFile(array $data) Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link https://api.telegram.org/file/bot/, where is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling getFile again. * @method static ServerResponse banChatMember(array $data) Use this method to kick a user from a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success. @@ -228,6 +229,7 @@ class Request 'sendPoll', 'sendDice', 'sendChatAction', + 'setMessageReaction', 'getUserProfilePhotos', 'getFile', 'banChatMember', @@ -950,6 +952,7 @@ private static function limitTelegramRequests(string $action, array $data = []): 'sendContact', 'sendPoll', 'sendDice', + 'setMessageReaction', 'sendInvoice', 'sendGame', 'setGameScore', diff --git a/structure.sql b/structure.sql index 205dadec..5b344307 100644 --- a/structure.sql +++ b/structure.sql @@ -41,6 +41,39 @@ CREATE TABLE IF NOT EXISTS `user_chat` ( FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +CREATE TABLE IF NOT EXISTS `message_reaction` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'The chat containing the message the user reacted to', + `message_id` bigint COMMENT 'Unique identifier of the message inside the chat', + `user_id` bigint NULL COMMENT 'Optional. The user that changed the reaction, if the user isn''t anonymous', + `actor_chat_id` bigint NULL COMMENT 'Optional. The chat on behalf of which the reaction was changed, if the user is anonymous', + `old_reaction` TEXT NOT NULL COMMENT 'Previous list of reaction types that were set by the user', + `new_reaction` TEXT NOT NULL COMMENT 'New list of reaction types that have been set by the user', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + KEY `user_id` (`user_id`), + KEY `actor_chat_id` (`actor_chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`), + FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), + FOREIGN KEY (`actor_chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +CREATE TABLE IF NOT EXISTS `message_reaction_count` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'The chat containing the message', + `message_id` bigint COMMENT 'Unique message identifier inside the chat', + `reactions` TEXT NOT NULL COMMENT 'List of reactions that are present on the message', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + CREATE TABLE IF NOT EXISTS `inline_query` ( `id` bigint UNSIGNED COMMENT 'Unique identifier for this query', `user_id` bigint NULL COMMENT 'Unique user identifier', @@ -301,6 +334,8 @@ CREATE TABLE IF NOT EXISTS `telegram_update` ( `edited_message_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New version of a message that is known to the bot and was edited', `channel_post_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming channel post of any kind - text, photo, sticker, etc.', `edited_channel_post_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New version of a channel post that is known to the bot and was edited', + `message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user', + `message_reaction_count_id` bigint UNSIGNED DEFAULT NULL COMMENT 'Reactions to a message with anonymous reactions were changed', `inline_query_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming inline query', `chosen_inline_result_id` bigint UNSIGNED DEFAULT NULL COMMENT 'The result of an inline query that was chosen by a user and sent to their chat partner', `callback_query_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming callback query', diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql new file mode 100644 index 00000000..e93ffbb4 --- /dev/null +++ b/utils/db-schema-update/0.82.0-unreleased.sql @@ -0,0 +1,36 @@ +CREATE TABLE IF NOT EXISTS `message_reaction` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'The chat containing the message the user reacted to', + `message_id` bigint COMMENT 'Unique identifier of the message inside the chat', + `user_id` bigint NULL COMMENT 'Optional. The user that changed the reaction, if the user isn''t anonymous', + `actor_chat_id` bigint NULL COMMENT 'Optional. The chat on behalf of which the reaction was changed, if the user is anonymous', + `old_reaction` TEXT NOT NULL COMMENT 'Previous list of reaction types that were set by the user', + `new_reaction` TEXT NOT NULL COMMENT 'New list of reaction types that have been set by the user', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + KEY `user_id` (`user_id`), + KEY `actor_chat_id` (`actor_chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`), + FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), + FOREIGN KEY (`actor_chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +CREATE TABLE IF NOT EXISTS `message_reaction_count` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'The chat containing the message', + `message_id` bigint COMMENT 'Unique message identifier inside the chat', + `reactions` TEXT NOT NULL COMMENT 'List of reactions that are present on the message', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +ALTER TABLE `telegram_update` + ADD COLUMN `message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user' AFTER `edited_channel_post_id`, + ADD COLUMN `message_reaction_count_id` bigint UNSIGNED DEFAULT NULL COMMENT 'Reactions to a message with anonymous reactions were changed' AFTER `message_reaction_id`; From e49bf3bc1e323f8cbb6971b5547b67d9da1dceaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sat, 23 Mar 2024 21:04:15 +0100 Subject: [PATCH 02/19] Bot API 7.0 - Replies 2.0 --- src/DB.php | 5 +- src/Entities/ExternalReplyInfo.php | 74 ++++++++++++++++++++ src/Entities/Message.php | 4 ++ src/Entities/ReplyParameters.php | 38 ++++++++++ src/Entities/TextQuote.php | 35 +++++++++ structure.sql | 1 + utils/db-schema-update/0.82.0-unreleased.sql | 3 + 7 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 src/Entities/ExternalReplyInfo.php create mode 100644 src/Entities/ReplyParameters.php create mode 100644 src/Entities/TextQuote.php diff --git a/src/DB.php b/src/DB.php index 0ce49d88..badadc3a 100644 --- a/src/DB.php +++ b/src/DB.php @@ -1219,7 +1219,7 @@ public static function insertMessageRequest(Message $message): bool ( `id`, `user_id`, `chat_id`, `message_thread_id`, `sender_chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`, `forward_signature`, `forward_sender_name`, `forward_date`, `is_topic_message`, - `reply_to_chat`, `reply_to_message`, `via_bot`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`, + `reply_to_chat`, `reply_to_message`, `external_reply`, `via_bot`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`, `audio`, `document`, `animation`, `game`, `photo`, `sticker`, `story`, `video`, `voice`, `video_note`, `caption`, `has_media_spoiler`, `contact`, `location`, `venue`, `poll`, `dice`, `new_chat_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, @@ -1230,7 +1230,7 @@ public static function insertMessageRequest(Message $message): bool ) VALUES ( :message_id, :user_id, :chat_id, :message_thread_id, :sender_chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id, :forward_signature, :forward_sender_name, :forward_date, :is_topic_message, - :reply_to_chat, :reply_to_message, :via_bot, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities, + :reply_to_chat, :reply_to_message, :external_reply, :via_bot, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities, :audio, :document, :animation, :game, :photo, :sticker, :story, :video, :voice, :video_note, :caption, :has_media_spoiler, :contact, :location, :venue, :poll, :dice, :new_chat_members, :left_chat_member, :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created, @@ -1272,6 +1272,7 @@ public static function insertMessageRequest(Message $message): bool } $sth->bindValue(':reply_to_chat', $reply_to_chat_id); $sth->bindValue(':reply_to_message', $reply_to_message_id); + $sth->bindValue(':external_reply', $message->getExternalReply()); $sth->bindValue(':via_bot', $via_bot_id); $sth->bindValue(':edit_date', self::getTimestamp($message->getEditDate())); diff --git a/src/Entities/ExternalReplyInfo.php b/src/Entities/ExternalReplyInfo.php new file mode 100644 index 00000000..e879973d --- /dev/null +++ b/src/Entities/ExternalReplyInfo.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +/** + * This object contains information about a message that is being replied to, which may come from another chat or forum topic. + * + * @link https://core.telegram.org/bots/api#externalreplyinfo + * + * @method MessageOrigin getOrigin() Origin of the message replied to by the given message + * @method Chat getChat() Optional. Chat the original message belongs to. Available only if the chat is a supergroup or a channel. + * @method int getMessageId() Optional. Unique message identifier inside the original chat. Available only if the original chat is a supergroup or a channel. + * @method LinkPreviewOptions getLinkPreviewOptions() Optional. Options used for link preview generation for the original message, if it is a text message + * @method Animation getAnimation() Optional. Message is an animation, information about the animation + * @method Audio getAudio() Optional. Message is an audio file, information about the file + * @method Document getDocument() Optional. Message is a general file, information about the file + * @method PhotoSize[] getPhoto() Optional. Message is a photo, available sizes of the photo + * @method Sticker getSticker() Optional. Message is a sticker, information about the sticker + * @method Story getStory() Optional. Message is a forwarded story + * @method Video getVideo() Optional. Message is a video, information about the video + * @method VideoNote getVideoNote() Optional. Message is a video note, information about the video message + * @method Voice getVoice() Optional. Message is a voice message, information about the file + * @method bool getHasMediaSpoiler() Optional. True, if the message media is covered by a spoiler animation + * @method Contact getContact() Optional. Message is a shared contact, information about the contact + * @method Dice getDice() Optional. Message is a dice with random value + * @method Game getGame() Optional. Message is a game, information about the game. More about games » + * @method Giveaway getGiveaway() Optional. Message is a scheduled giveaway, information about the giveaway + * @method GiveawayWinners getGiveawayWinners() Optional. A giveaway with public winners was completed + * @method Invoice getInvoice() Optional. Message is an invoice for a payment, information about the invoice. More about payments » + * @method Location getLocation() Optional. Message is a shared location, information about the location + * @method Poll getPoll() Optional. Message is a native poll, information about the poll + * @method Venue getVenue() Optional. Message is a venue, information about the venue + */ +class ExternalReplyInfo extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'origin' => MessageOrigin::class, + 'chat' => Chat::class, + 'link_preview_options' => LinkPreviewOptions::class, + 'animation' => Animation::class, + 'audio' => Audio::class, + 'document' => Document::class, + 'photo' => [PhotoSize::class], + 'sticker' => Sticker::class, + 'story' => Story::class, + 'video' => Video::class, + 'video_note' => VideoNote::class, + 'voice' => Voice::class, + 'contact' => Contact::class, + 'dice' => Dice::class, + 'game' => Game::class, + 'giveaway' => Giveaway::class, + 'giveaway_winners' => GiveawayWinners::class, + 'invoice' => Invoice::class, + 'location' => Location::class, + 'poll' => Poll::class, + 'venue' => Venue::class, + ]; + } +} diff --git a/src/Entities/Message.php b/src/Entities/Message.php index 58f36b43..bdf0f98e 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -44,6 +44,8 @@ * @method bool getIsTopicMessage() Optional. True, if the message is sent to a forum topic * @method bool getIsAutomaticForward() Optional. True, if the message is a channel post that was automatically forwarded to the connected discussion group * @method ReplyToMessage getReplyToMessage() Optional. For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply. + * @method ExternalReplyInfo getExternalReply() Optional. Information about the message that is being replied to, which may come from another chat or forum topic + * @method TextQuote getQuote() Optional. For replies that quote part of the original message, the quoted part of the message * @method User getViaBot() Optional. Bot through which the message was sent * @method int getEditDate() Optional. Date the message was last edited in Unix time * @method bool getHasProtectedContent() Optional. True, if the message can't be forwarded @@ -115,6 +117,8 @@ protected function subEntities(): array 'forward_from' => User::class, 'forward_from_chat' => Chat::class, 'reply_to_message' => ReplyToMessage::class, + 'external_reply' => ExternalReplyInfo::class, + 'quote' => TextQuote::class, 'via_bot' => User::class, 'entities' => [MessageEntity::class], 'animation' => Animation::class, diff --git a/src/Entities/ReplyParameters.php b/src/Entities/ReplyParameters.php new file mode 100644 index 00000000..176650d9 --- /dev/null +++ b/src/Entities/ReplyParameters.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +/** + * Describes reply parameters for the message that is being sent. + * + * @link https://core.telegram.org/bots/api#replyparameters + * + * @method int getMessageId() Identifier of the message that will be replied to in the current chat, or in the chat chat_id if it is specified + * @method int|string getChatId() Optional. If the message to be replied to is from a different chat, unique identifier for the chat or username of the channel (in the format @channelusername) + * @method bool getAllowSendingWithoutReply() Optional. Pass True if the message should be sent even if the specified message to be replied to is not found; can be used only for replies in the same chat and forum topic. + * @method string getQuote() Optional. Quoted part of the message to be replied to; 0-1024 characters after entities parsing. The quote must be an exact substring of the message to be replied to, including bold, italic, underline, strikethrough, spoiler, and custom_emoji entities. The message will fail to send if the quote isn't found in the original message. + * @method string getQuoteParseMode() Optional. Mode for parsing entities in the quote. See formatting options for more details. + * @method MessageEntity[] getQuoteEntities() Optional. A JSON-serialized list of special entities that appear in the quote. It can be specified instead of quote_parse_mode. + * @method int getQuotePosition() Optional. Position of the quote in the original message in UTF-16 code units + */ +class ReplyParameters extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'quote_entities' => [MessageEntity::class], + ]; + } +} diff --git a/src/Entities/TextQuote.php b/src/Entities/TextQuote.php new file mode 100644 index 00000000..9e237d79 --- /dev/null +++ b/src/Entities/TextQuote.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +/** + * This object contains information about the quoted part of a message that is replied to by the given message. + * + * @link https://core.telegram.org/bots/api#textquote + * + * @method string getText() Text of the quoted part of a message that is replied to by the given message + * @method MessageEntity[] getEntities() Optional. Special entities that appear in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and custom_emoji entities are kept in quotes. + * @method int getPosition() Approximate quote position in the original message in UTF-16 code units as specified by the sender + * @method bool getIsManual() Optional. True, if the quote was chosen manually by the message sender. Otherwise, the quote was added automatically by the server. + */ +class TextQuote extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'entities' => [MessageEntity::class], + ]; + } +} diff --git a/structure.sql b/structure.sql index 5b344307..dcc5821a 100644 --- a/structure.sql +++ b/structure.sql @@ -121,6 +121,7 @@ CREATE TABLE IF NOT EXISTS `message` ( `is_automatic_forward` tinyint(1) DEFAULT 0 COMMENT 'True, if the message is a channel post that was automatically forwarded to the connected discussion group', `reply_to_chat` bigint NULL DEFAULT NULL COMMENT 'Unique chat identifier', `reply_to_message` bigint UNSIGNED DEFAULT NULL COMMENT 'Message that this message is reply to', + `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic', `via_bot` bigint NULL DEFAULT NULL COMMENT 'Optional. Bot through which the message was sent', `edit_date` timestamp NULL DEFAULT NULL COMMENT 'Date the message was last edited in Unix time', `has_protected_content` tinyint(1) DEFAULT 0 COMMENT 'True, if the message can''t be forwarded', diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql index e93ffbb4..adb79343 100644 --- a/utils/db-schema-update/0.82.0-unreleased.sql +++ b/utils/db-schema-update/0.82.0-unreleased.sql @@ -31,6 +31,9 @@ CREATE TABLE IF NOT EXISTS `message_reaction_count` ( FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +ALTER TABLE `message` + ADD COLUMN `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic' AFTER `reply_to_message`; + ALTER TABLE `telegram_update` ADD COLUMN `message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user' AFTER `edited_channel_post_id`, ADD COLUMN `message_reaction_count_id` bigint UNSIGNED DEFAULT NULL COMMENT 'Reactions to a message with anonymous reactions were changed' AFTER `message_reaction_id`; From 5677512592b5c8c7237a716c2548ca95acd166d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sat, 23 Mar 2024 21:22:36 +0100 Subject: [PATCH 03/19] Bot API 7.0 - Link Preview Customization --- src/DB.php | 5 ++-- .../InputTextMessageContent.php | 26 ++++++----------- src/Entities/LinkPreviewOptions.php | 28 +++++++++++++++++++ src/Entities/Message.php | 2 ++ structure.sql | 1 + utils/db-schema-update/0.82.0-unreleased.sql | 3 +- 6 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 src/Entities/LinkPreviewOptions.php diff --git a/src/DB.php b/src/DB.php index badadc3a..8aeefdce 100644 --- a/src/DB.php +++ b/src/DB.php @@ -1219,7 +1219,7 @@ public static function insertMessageRequest(Message $message): bool ( `id`, `user_id`, `chat_id`, `message_thread_id`, `sender_chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`, `forward_signature`, `forward_sender_name`, `forward_date`, `is_topic_message`, - `reply_to_chat`, `reply_to_message`, `external_reply`, `via_bot`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`, + `reply_to_chat`, `reply_to_message`, `external_reply`, `via_bot`, `link_preview_options`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`, `audio`, `document`, `animation`, `game`, `photo`, `sticker`, `story`, `video`, `voice`, `video_note`, `caption`, `has_media_spoiler`, `contact`, `location`, `venue`, `poll`, `dice`, `new_chat_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, @@ -1230,7 +1230,7 @@ public static function insertMessageRequest(Message $message): bool ) VALUES ( :message_id, :user_id, :chat_id, :message_thread_id, :sender_chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id, :forward_signature, :forward_sender_name, :forward_date, :is_topic_message, - :reply_to_chat, :reply_to_message, :external_reply, :via_bot, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities, + :reply_to_chat, :reply_to_message, :external_reply, :via_bot, :link_preview_options, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities, :audio, :document, :animation, :game, :photo, :sticker, :story, :video, :voice, :video_note, :caption, :has_media_spoiler, :contact, :location, :venue, :poll, :dice, :new_chat_members, :left_chat_member, :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created, @@ -1275,6 +1275,7 @@ public static function insertMessageRequest(Message $message): bool $sth->bindValue(':external_reply', $message->getExternalReply()); $sth->bindValue(':via_bot', $via_bot_id); + $sth->bindValue(':link_preview_options', $message->getLinkPreviewOptions()); $sth->bindValue(':edit_date', self::getTimestamp($message->getEditDate())); $sth->bindValue(':media_group_id', $message->getMediaGroupId()); $sth->bindValue(':author_signature', $message->getAuthorSignature()); diff --git a/src/Entities/InputMessageContent/InputTextMessageContent.php b/src/Entities/InputMessageContent/InputTextMessageContent.php index ebb47545..574f93af 100644 --- a/src/Entities/InputMessageContent/InputTextMessageContent.php +++ b/src/Entities/InputMessageContent/InputTextMessageContent.php @@ -14,27 +14,19 @@ use Longman\TelegramBot\Entities\InlineQuery\InlineEntity; /** - * Class InputTextMessageContent + * Represents the content of a text message to be sent as the result of an inline query. * * @link https://core.telegram.org/bots/api#inputtextmessagecontent * - * - * $data = [ - * 'message_text' => '', - * 'parse_mode' => '', - * 'disable_web_page_preview' => true, - * ]; - * + * @method string getMessageText() Text of the message to be sent, 1-4096 characters. + * @method string getParseMode() Optional. Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. + * @method MessageEntity[] getEntities() Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode + * @method LinkPreviewOptions getLinkPreviewOptions() Optional. Link preview generation options for the message * - * @method string getMessageText() Text of the message to be sent, 1-4096 characters. - * @method string getParseMode() Optional. Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. - * @method MessageEntity[] getEntities() Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode - * @method bool getDisableWebPagePreview() Optional. Disables link previews for links in the sent message - * - * @method $this setMessageText(string $message_text) Text of the message to be sent, 1-4096 characters. - * @method $this setParseMode(string $parse_mode) Optional. Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. - * @method $this setEntities(array $entities) Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode - * @method $this setDisableWebPagePreview(bool $disable_web_page_preview) Optional. Disables link previews for links in the sent message + * @method $this setMessageText(string $message_text) Text of the message to be sent, 1-4096 characters. + * @method $this setParseMode(string $parse_mode) Optional. Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. + * @method $this setEntities(array $entities) Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode + * @method $this setLinkPreviewOptions(LinkPreviewOptions $link_preview_options) Optional. Link preview generation options for the message */ class InputTextMessageContent extends InlineEntity implements InputMessageContent { diff --git a/src/Entities/LinkPreviewOptions.php b/src/Entities/LinkPreviewOptions.php new file mode 100644 index 00000000..7838e86b --- /dev/null +++ b/src/Entities/LinkPreviewOptions.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +/** + * Describes the options used for link preview generation. + * + * @link https://core.telegram.org/bots/api#linkpreviewoptions + * + * @method bool getIsDisabled() Optional. True, if the link preview is disabled + * @method string getUrl() Optional. URL to use for the link preview. If empty, then the first URL found in the message text will be used + * @method bool getPreferSmallMedia() Optional. True, if the media in the link preview is supposed to be shrunk; ignored if the URL isn't explicitly specified or media size change isn't supported for the preview + * @method bool getPreferLargeMedia() Optional. True, if the media in the link preview is supposed to be enlarged; ignored if the URL isn't explicitly specified or media size change isn't supported for the preview + * @method bool getShowAboveText() Optional. True, if the link preview must be shown above the message text; otherwise, the link preview will be shown below the message text * + */ +class LinkPreviewOptions extends Entity +{ + +} diff --git a/src/Entities/Message.php b/src/Entities/Message.php index bdf0f98e..2922ec1b 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -51,6 +51,7 @@ * @method bool getHasProtectedContent() Optional. True, if the message can't be forwarded * @method string getMediaGroupId() Optional. The unique identifier of a media message group this message belongs to * @method string getAuthorSignature() Optional. Signature of the post author for messages in channels + * @method LinkPreviewOptions getLinkPreviewOptions() Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed * @method MessageEntity[] getEntities() Optional. For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text * @method MessageEntity[] getCaptionEntities() Optional. For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear in the caption * @method Audio getAudio() Optional. Message is an audio file, information about the file @@ -120,6 +121,7 @@ protected function subEntities(): array 'external_reply' => ExternalReplyInfo::class, 'quote' => TextQuote::class, 'via_bot' => User::class, + 'link_preview_options' => LinkPreviewOptions::class, 'entities' => [MessageEntity::class], 'animation' => Animation::class, 'audio' => Audio::class, diff --git a/structure.sql b/structure.sql index dcc5821a..022cf74d 100644 --- a/structure.sql +++ b/structure.sql @@ -123,6 +123,7 @@ CREATE TABLE IF NOT EXISTS `message` ( `reply_to_message` bigint UNSIGNED DEFAULT NULL COMMENT 'Message that this message is reply to', `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic', `via_bot` bigint NULL DEFAULT NULL COMMENT 'Optional. Bot through which the message was sent', + `link_preview_options` TEXT NULL DEFAULT NULL COMMENT 'Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed', `edit_date` timestamp NULL DEFAULT NULL COMMENT 'Date the message was last edited in Unix time', `has_protected_content` tinyint(1) DEFAULT 0 COMMENT 'True, if the message can''t be forwarded', `media_group_id` TEXT COMMENT 'The unique identifier of a media message group this message belongs to', diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql index adb79343..1882b963 100644 --- a/utils/db-schema-update/0.82.0-unreleased.sql +++ b/utils/db-schema-update/0.82.0-unreleased.sql @@ -32,7 +32,8 @@ CREATE TABLE IF NOT EXISTS `message_reaction_count` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; ALTER TABLE `message` - ADD COLUMN `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic' AFTER `reply_to_message`; + ADD COLUMN `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic' AFTER `reply_to_message`, + ADD COLUMN `link_preview_options` TEXT NULL DEFAULT NULL COMMENT 'Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed' AFTER `via_bot`; ALTER TABLE `telegram_update` ADD COLUMN `message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user' AFTER `edited_channel_post_id`, From d70ff9841e0ddf41356ae7f629b677bc8f5826f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 24 Mar 2024 15:06:39 +0100 Subject: [PATCH 04/19] Bot API 7.0 - Multiple Message Actions --- src/Request.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Request.php b/src/Request.php index e6e12bff..bf0bd27e 100644 --- a/src/Request.php +++ b/src/Request.php @@ -34,7 +34,9 @@ * @method static ServerResponse logOut() Use this method to log out from the cloud Bot API server before launching the bot locally. Requires no parameters. Returns True on success. * @method static ServerResponse close() Use this method to close the bot instance before moving it from one local server to another. Requires no parameters. Returns True on success. * @method static ServerResponse forwardMessage(array $data) Use this method to forward messages of any kind. On success, the sent Message is returned. + * @method static ServerResponse forwardMessages(array $data) Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an array of MessageId of the sent messages is returned. * @method static ServerResponse copyMessage(array $data) Use this method to copy messages of any kind. The method is analogous to the method forwardMessages, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success. + * @method static ServerResponse copyMessages(array $data) Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array of MessageId of the sent messages is returned. * @method static ServerResponse sendPhoto(array $data) Use this method to send photos. On success, the sent Message is returned. * @method static ServerResponse sendAudio(array $data) Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .mp3 format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future. * @method static ServerResponse sendDocument(array $data) Use this method to send general files. On success, the sent Message is returned. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future. @@ -117,6 +119,7 @@ * @method static ServerResponse editMessageReplyMarkup(array $data) Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. * @method static ServerResponse stopPoll(array $data) Use this method to stop a poll which was sent by the bot. On success, the stopped Poll with the final results is returned. * @method static ServerResponse deleteMessage(array $data) Use this method to delete a message, including service messages, with certain limitations. Returns True on success. + * @method static ServerResponse deleteMessages(array $data) Use this method to delete multiple messages simultaneously. If some of the specified messages can't be found, they are skipped. Returns True on success. * @method static ServerResponse getStickerSet(array $data) Use this method to get a sticker set. On success, a StickerSet object is returned. * @method static ServerResponse getCustomEmojiStickers(array $data) Use this method to get information about custom emoji stickers by their identifiers. Returns an Array of Sticker objects. * @method static ServerResponse uploadStickerFile(array $data) Use this method to upload a .png file with a sticker for later use in createNewStickerSet and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success. @@ -211,7 +214,9 @@ class Request 'close', 'sendMessage', 'forwardMessage', + 'forwardMessages', 'copyMessage', + 'copyMessages', 'sendPhoto', 'sendAudio', 'sendDocument', @@ -294,6 +299,7 @@ class Request 'editMessageReplyMarkup', 'stopPoll', 'deleteMessage', + 'deleteMessages', 'getStickerSet', 'getCustomEmojiStickers', 'uploadStickerFile', @@ -935,7 +941,9 @@ private static function limitTelegramRequests(string $action, array $data = []): $limited_methods = [ 'sendMessage', 'forwardMessage', + 'forwardMessages', 'copyMessage', + 'copyMessages', 'sendPhoto', 'sendAudio', 'sendDocument', @@ -963,6 +971,8 @@ private static function limitTelegramRequests(string $action, array $data = []): 'editMessageMedia', 'editMessageReplyMarkup', 'stopPoll', + 'deleteMessage', + 'deleteMessages', 'setChatTitle', 'setChatDescription', 'setChatStickerSet', From 4ba3ee961f18bf2d84e95d33b89866dd4b786c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 24 Mar 2024 15:35:27 +0100 Subject: [PATCH 05/19] Bot API 7.0 - Request for multiple users --- src/Entities/KeyboardButton.php | 54 +++++++++---------- ...ser.php => KeyboardButtonRequestUsers.php} | 10 ++-- src/Entities/Message.php | 6 +-- src/Entities/UserShared.php | 18 ------- src/Entities/UsersShared.php | 16 ++++++ structure.sql | 2 +- utils/db-schema-update/0.82.0-unreleased.sql | 3 +- 7 files changed, 53 insertions(+), 56 deletions(-) rename src/Entities/{KeyboardButtonRequestUser.php => KeyboardButtonRequestUsers.php} (72%) delete mode 100644 src/Entities/UserShared.php create mode 100644 src/Entities/UsersShared.php diff --git a/src/Entities/KeyboardButton.php b/src/Entities/KeyboardButton.php index d735a32d..25cc7f04 100644 --- a/src/Entities/KeyboardButton.php +++ b/src/Entities/KeyboardButton.php @@ -11,8 +11,6 @@ namespace Longman\TelegramBot\Entities; -use Longman\TelegramBot\Exception\TelegramException; - /** * Class KeyboardButton * @@ -20,28 +18,28 @@ * * @link https://core.telegram.org/bots/api#keyboardbutton * - * @property KeyboardButtonRequestUser $request_user - * @property KeyboardButtonRequestChat $request_chat - * @property bool $request_contact - * @property bool $request_location - * @property KeyboardButtonPollType $request_poll - * @property WebAppInfo $web_app + * @property KeyboardButtonRequestUsers $request_users + * @property KeyboardButtonRequestChat $request_chat + * @property bool $request_contact + * @property bool $request_location + * @property KeyboardButtonPollType $request_poll + * @property WebAppInfo $web_app * - * @method string getText() Text of the button. If none of the optional fields are used, it will be sent to the bot as a message when the button is pressed - * @method KeyboardButtonRequestUser getRequestUser() Optional. If specified, pressing the button will open a list of suitable users. Tapping on any user will send their identifier to the bot in a “user_shared” service message. Available in private chats only. - * @method KeyboardButtonRequestChat getRequestChat() Optional. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will send its identifier to the bot in a “chat_shared” service message. Available in private chats only. - * @method bool getRequestContact() Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only - * @method bool getRequestLocation() Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only - * @method KeyboardButtonPollType getRequestPoll() Optional. If specified, the user will be asked to create a poll and send it to the bot when the button is pressed. Available in private chats only - * @method WebAppInfo getWebApp() Optional. If specified, the described Web App will be launched when the button is pressed. The Web App will be able to send a “web_app_data” service message. Available in private chats only. + * @method string getText() Text of the button. If none of the optional fields are used, it will be sent to the bot as a message when the button is pressed + * @method KeyboardButtonRequestUsers getRequestUsers() Optional. If specified, pressing the button will open a list of suitable users. Identifiers of selected users will be sent to the bot in a “users_shared” service message. Available in private chats only. + * @method KeyboardButtonRequestChat getRequestChat() Optional. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will send its identifier to the bot in a “chat_shared” service message. Available in private chats only. + * @method bool getRequestContact() Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only + * @method bool getRequestLocation() Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only + * @method KeyboardButtonPollType getRequestPoll() Optional. If specified, the user will be asked to create a poll and send it to the bot when the button is pressed. Available in private chats only + * @method WebAppInfo getWebApp() Optional. If specified, the described Web App will be launched when the button is pressed. The Web App will be able to send a “web_app_data” service message. Available in private chats only. * - * @method $this setText(string $text) Text of the button. If none of the optional fields are used, it will be sent to the bot as a message when the button is pressed - * @method $this setRequestUser(KeyboardButtonRequestUser $request_user) Optional. If specified, pressing the button will open a list of suitable users. Tapping on any user will send their identifier to the bot in a “user_shared” service message. Available in private chats only. - * @method $this setRequestChat(KeyboardButtonRequestChat $request_chat) Optional. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will send its identifier to the bot in a “chat_shared” service message. Available in private chats only. - * @method $this setRequestContact(bool $request_contact) Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only - * @method $this setRequestLocation(bool $request_location) Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only - * @method $this setRequestPoll(KeyboardButtonPollType $request_poll) Optional. If specified, the user will be asked to create a poll and send it to the bot when the button is pressed. Available in private chats only - * @method $this setWebApp(WebAppInfo $web_app) Optional. If specified, the described Web App will be launched when the button is pressed. The Web App will be able to send a “web_app_data” service message. Available in private chats only. + * @method $this setText(string $text) Text of the button. If none of the optional fields are used, it will be sent to the bot as a message when the button is pressed + * @method $this setRequestUsers(KeyboardButtonRequestUsers $request_users) Optional. If specified, pressing the button will open a list of suitable users. Identifiers of selected users will be sent to the bot in a “users_shared” service message. Available in private chats only. + * @method $this setRequestChat(KeyboardButtonRequestChat $request_chat) Optional. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will send its identifier to the bot in a “chat_shared” service message. Available in private chats only. + * @method $this setRequestContact(bool $request_contact) Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only + * @method $this setRequestLocation(bool $request_location) Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only + * @method $this setRequestPoll(KeyboardButtonPollType $request_poll) Optional. If specified, the user will be asked to create a poll and send it to the bot when the button is pressed. Available in private chats only + * @method $this setWebApp(WebAppInfo $web_app) Optional. If specified, the described Web App will be launched when the button is pressed. The Web App will be able to send a “web_app_data” service message. Available in private chats only. */ class KeyboardButton extends Entity { @@ -59,10 +57,10 @@ public function __construct($data) protected function subEntities(): array { return [ - 'request_user' => KeyboardButtonRequestUser::class, - 'request_chat' => KeyboardButtonRequestChat::class, - 'request_poll' => KeyboardButtonPollType::class, - 'web_app' => WebAppInfo::class, + 'request_users' => KeyboardButtonRequestUsers::class, + 'request_chat' => KeyboardButtonRequestChat::class, + 'request_poll' => KeyboardButtonPollType::class, + 'web_app' => WebAppInfo::class, ]; } @@ -84,8 +82,8 @@ public static function couldBe(array $data): bool public function __call($method, $args) { // Only 1 of these can be set, so clear the others when setting a new one. - if (in_array($method, ['setRequestUser', 'setRequestChat', 'setRequestContact', 'setRequestLocation', 'setRequestPoll', 'setWebApp'], true)) { - unset($this->reqest_user, $this->request_chat, $this->request_contact, $this->request_location, $this->request_poll, $this->web_app); + if (in_array($method, ['setRequestUsers', 'setRequestChat', 'setRequestContact', 'setRequestLocation', 'setRequestPoll', 'setWebApp'], true)) { + unset($this->request_users, $this->request_chat, $this->request_contact, $this->request_location, $this->request_poll, $this->web_app); } return parent::__call($method, $args); diff --git a/src/Entities/KeyboardButtonRequestUser.php b/src/Entities/KeyboardButtonRequestUsers.php similarity index 72% rename from src/Entities/KeyboardButtonRequestUser.php rename to src/Entities/KeyboardButtonRequestUsers.php index 6ba69f62..945bafa9 100644 --- a/src/Entities/KeyboardButtonRequestUser.php +++ b/src/Entities/KeyboardButtonRequestUsers.php @@ -3,21 +3,21 @@ namespace Longman\TelegramBot\Entities; /** - * Class KeyboardButtonRequestUser + * This object defines the criteria used to request suitable users. The identifiers of the selected users will be shared with the bot when the corresponding button is pressed. * - * This entity defines the criteria used to request a suitable user. The identifier of the selected user will be shared with the bot when the corresponding button is pressed. - * - * @link https://core.telegram.org/bots/api#keyboardbuttonrequestuser + * @link https://core.telegram.org/bots/api#keyboardbuttonrequestusers * * @method int getRequestId() Signed 32-bit identifier of the request, which will be received back in the UserShared object. Must be unique within the message * @method bool getUserIsBot() Optional. Pass True to request a bot, pass False to request a regular user. If not specified, no additional restrictions are applied. * @method bool getUserIsPremium() Optional. Pass True to request a premium user, pass False to request a non-premium user. If not specified, no additional restrictions are applied. + * @method int getMaxQuantity() Optional. The maximum number of users to be selected; 1-10. Defaults to 1. * * @method $this setRequestId(int $request_id) Signed 32-bit identifier of the request, which will be received back in the UserShared object. Must be unique within the message * @method $this setUserIsBot(bool $user_is_bot) Optional. Pass True to request a bot, pass False to request a regular user. If not specified, no additional restrictions are applied. * @method $this setUserIsPremium(bool $user_is_premium) Optional. Pass True to request a premium user, pass False to request a non-premium user. If not specified, no additional restrictions are applied. + * @method int setMaxQuantity(int $set_max_quantity) Optional. The maximum number of users to be selected; 1-10. Defaults to 1. */ -class KeyboardButtonRequestUser extends Entity +class KeyboardButtonRequestUsers extends Entity { } diff --git a/src/Entities/Message.php b/src/Entities/Message.php index 2922ec1b..c0795078 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -85,7 +85,7 @@ * @method Message getPinnedMessage() Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply. * @method Invoice getInvoice() Optional. Message is an invoice for a payment, information about the invoice. * @method SuccessfulPayment getSuccessfulPayment() Optional. Message is a service message about a successful payment, information about the payment. - * @method UserShared getUserShared() Optional. Service message: a user was shared with the bot + * @method UsersShared getUsersShared() Optional. Service message: users were shared with the bot * @method ChatShared getChatShared() Optional. Service message: a chat was shared with the bot * @method string getConnectedWebsite() Optional. The domain name of the website on which the user has logged in. * @method WriteAccessAllowed getWriteAccessAllowed() Optional. Service message: the user allowed the bot added to the attachment menu to write messages @@ -146,7 +146,7 @@ protected function subEntities(): array 'pinned_message' => __CLASS__, 'invoice' => Invoice::class, 'successful_payment' => SuccessfulPayment::class, - 'user_shared' => UserShared::class, + 'users_shared' => UsersShared::class, 'chat_shared' => ChatShared::class, 'write_access_allowed' => WriteAccessAllowed::class, 'passport_data' => PassportData::class, @@ -292,7 +292,7 @@ public function getType(): string 'pinned_message', 'invoice', 'successful_payment', - 'user_shared', + 'users_shared', 'chat_shared', 'write_access_allowed', 'passport_data', diff --git a/src/Entities/UserShared.php b/src/Entities/UserShared.php deleted file mode 100644 index aac35d2c..00000000 --- a/src/Entities/UserShared.php +++ /dev/null @@ -1,18 +0,0 @@ - Date: Sun, 24 Mar 2024 17:48:06 +0100 Subject: [PATCH 06/19] Bot API 7.0 - Chat Boost --- src/DB.php | 110 +++++++++++++++++- src/Entities/ChatBoost.php | 37 ++++++ src/Entities/ChatBoostRemoved.php | 38 ++++++ .../ChatBoostSource/ChatBoostSource.php | 16 +++ .../ChatBoostSourceGiftCode.php | 27 +++++ .../ChatBoostSourceGiveaway.php | 29 +++++ .../ChatBoostSourceNotImplemented.php | 15 +++ .../ChatBoostSourcePremium.php | 27 +++++ src/Entities/ChatBoostSource/Factory.php | 24 ++++ src/Entities/ChatBoostUpdated.php | 34 ++++++ src/Entities/UserChatBoosts.php | 32 +++++ src/Request.php | 2 + structure.sql | 26 +++++ utils/db-schema-update/0.82.0-unreleased.sql | 26 +++++ 14 files changed, 437 insertions(+), 6 deletions(-) create mode 100644 src/Entities/ChatBoost.php create mode 100644 src/Entities/ChatBoostRemoved.php create mode 100644 src/Entities/ChatBoostSource/ChatBoostSource.php create mode 100644 src/Entities/ChatBoostSource/ChatBoostSourceGiftCode.php create mode 100644 src/Entities/ChatBoostSource/ChatBoostSourceGiveaway.php create mode 100644 src/Entities/ChatBoostSource/ChatBoostSourceNotImplemented.php create mode 100644 src/Entities/ChatBoostSource/ChatBoostSourcePremium.php create mode 100644 src/Entities/ChatBoostSource/Factory.php create mode 100644 src/Entities/ChatBoostUpdated.php create mode 100644 src/Entities/UserChatBoosts.php diff --git a/src/DB.php b/src/DB.php index 8aeefdce..25e5713a 100644 --- a/src/DB.php +++ b/src/DB.php @@ -14,6 +14,8 @@ use Longman\TelegramBot\Entities\CallbackQuery; use Longman\TelegramBot\Entities\Chat; +use Longman\TelegramBot\Entities\ChatBoostRemoved; +use Longman\TelegramBot\Entities\ChatBoostUpdated; use Longman\TelegramBot\Entities\ChatJoinRequest; use Longman\TelegramBot\Entities\ChatMemberUpdated; use Longman\TelegramBot\Entities\ChosenInlineResult; @@ -149,6 +151,8 @@ protected static function defineTables(): void $tables = [ 'callback_query', 'chat', + 'chat_boost_updated', + 'chat_boost_removed', 'chat_join_request', 'chat_member_updated', 'chosen_inline_result', @@ -340,10 +344,12 @@ protected static function insertTelegramUpdate( ?string $poll_answer_poll_id = null, ?string $my_chat_member_updated_id = null, ?string $chat_member_updated_id = null, - ?string $chat_join_request_id = null + ?string $chat_join_request_id = null, + ?string $chat_boost_updated_id = null, + ?string $chat_boost_removed_id = null ): ?bool { - if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $message_reaction_id === null && $message_reaction_count_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null) { - throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, message_reaction_id, message_reaction_count_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id are all null'); + if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $message_reaction_id === null && $message_reaction_count_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null && $chat_boost_updated_id === null && $chat_boost_removed_id === null) { + throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, message_reaction_id, message_reaction_count_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id, chat_join_request_id, chat_boost_updated_id, chat_boost_removed_id are all null'); } if (!self::isDbConnected()) { @@ -359,14 +365,14 @@ protected static function insertTelegramUpdate( `inline_query_id`, `chosen_inline_result_id`, `callback_query_id`, `shipping_query_id`, `pre_checkout_query_id`, `poll_id`, `poll_answer_poll_id`, `my_chat_member_updated_id`, `chat_member_updated_id`, - `chat_join_request_id` + `chat_join_request_id`, `chat_boost_updated_id`, `chat_boost_removed_id` ) VALUES ( :id, :chat_id, :message_id, :edited_message_id, :channel_post_id, :edited_channel_post_id, :message_reaction_id, :message_reaction_count_id, :inline_query_id, :chosen_inline_result_id, :callback_query_id, :shipping_query_id, :pre_checkout_query_id, :poll_id, :poll_answer_poll_id, :my_chat_member_updated_id, :chat_member_updated_id, - :chat_join_request_id + :chat_join_request_id, :chat_boost_updated_id, :chat_boost_removed_id ) '); @@ -388,6 +394,8 @@ protected static function insertTelegramUpdate( $sth->bindValue(':my_chat_member_updated_id', $my_chat_member_updated_id); $sth->bindValue(':chat_member_updated_id', $chat_member_updated_id); $sth->bindValue(':chat_join_request_id', $chat_join_request_id); + $sth->bindValue(':chat_boost_updated_id', $chat_boost_updated_id); + $sth->bindValue(':chat_boost_removed_id', $chat_boost_removed_id); return $sth->execute(); } catch (PDOException $e) { @@ -561,6 +569,8 @@ public static function insertRequest(Update $update): bool $my_chat_member_updated_id = null; $chat_member_updated_id = null; $chat_join_request_id = null; + $chat_boost_updated_id = null; + $chat_boost_removed_id = null; if (($message = $update->getMessage()) && self::insertMessageRequest($message)) { $chat_id = $message->getChat()->getId(); @@ -602,6 +612,10 @@ public static function insertRequest(Update $update): bool $chat_member_updated_id = self::$pdo->lastInsertId(); } elseif (($chat_join_request = $update->getChatJoinRequest()) && self::insertChatJoinRequestRequest($chat_join_request)) { $chat_join_request_id = self::$pdo->lastInsertId(); + } elseif (($chat_boost_updated = $update->getChatBoost()) && self::insertChatBoostUpdatedRequest($chat_boost_updated)) { + $chat_boost_updated_id = self::$pdo->lastInsertId(); + } elseif (($chat_boost_removed = $update->getRemovedChatBoost()) && self::insertChatBoostRemovedRequest($chat_boost_removed)) { + $chat_boost_removed_id = self::$pdo->lastInsertId(); } else { return false; } @@ -624,7 +638,9 @@ public static function insertRequest(Update $update): bool $poll_answer_poll_id, $my_chat_member_updated_id, $chat_member_updated_id, - $chat_join_request_id + $chat_join_request_id, + $chat_boost_updated_id, + $chat_boost_removed_id ); } @@ -1143,6 +1159,88 @@ public static function insertChatJoinRequestRequest(ChatJoinRequest $chat_join_r } } + /** + * Insert chat boost updated into database + * + * @param ChatBoostUpdated $chat_boost_updated + * + * @return bool If the insert was successful + * @throws TelegramException + */ + public static function insertChatBoostUpdatedRequest(ChatBoostUpdated $chat_boost_updated): bool + { + if (!self::isDbConnected()) { + return false; + } + + try { + $sth = self::$pdo->prepare(' + INSERT INTO `' . TB_CHAT_BOOST_UPDATED . '` + (`chat_id`, `boost`, `created_at`) + VALUES + (:chat_id, :boost, :created_at) + '); + + $date = self::getTimestamp(); + $chat_id = null; + + if ($chat = $chat_boost_updated->getChat()) { + $chat_id = $chat->getId(); + self::insertChat($chat, $date); + } + + $sth->bindValue(':chat_id', $chat_id); + $sth->bindValue(':boost', $chat_boost_updated->getBoost()); + $sth->bindValue(':created_at', $date); + + return $sth->execute(); + } catch (PDOException $e) { + throw new TelegramException($e->getMessage()); + } + } + + /** + * Insert chat boost removed into database + * + * @param ChatBoostRemoved $chat_boost_removed + * + * @return bool If the insert was successful + * @throws TelegramException + */ + public static function insertChatBoostRemovedRequest(ChatBoostRemoved $chat_boost_removed): bool + { + if (!self::isDbConnected()) { + return false; + } + + try { + $sth = self::$pdo->prepare(' + INSERT INTO `' . TB_CHAT_BOOST_REMOVED . '` + (`chat_id`, `boost_id`, `remove_date`, `source`, `created_at`) + VALUES + (:chat_id, :boost_id, :remove_date, :source, :created_at) + '); + + $date = self::getTimestamp(); + $chat_id = null; + + if ($chat = $chat_boost_removed->getChat()) { + $chat_id = $chat->getId(); + self::insertChat($chat, $date); + } + + $sth->bindValue(':chat_id', $chat_id); + $sth->bindValue(':boost_id', $chat_boost_removed->getBoostId()); + $sth->bindValue(':remove_date', self::getTimestamp($chat_boost_removed->getRemoveDate())); + $sth->bindValue(':source', $chat_boost_removed->getSource()); + $sth->bindValue(':created_at', $date); + + return $sth->execute(); + } catch (PDOException $e) { + throw new TelegramException($e->getMessage()); + } + } + /** * Insert Message request in db * diff --git a/src/Entities/ChatBoost.php b/src/Entities/ChatBoost.php new file mode 100644 index 00000000..adfbddb0 --- /dev/null +++ b/src/Entities/ChatBoost.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +use Longman\TelegramBot\Entities\ChatBoostSource\Factory as ChatBoostSourceFactory; + +/** + * This object contains information about a chat boost. + * + * @link https://core.telegram.org/bots/api#chatboost + * + * @method string getBoostId() Unique identifier of the boost + * @method int getAddDate() Point in time (Unix timestamp) when the chat was boosted + * @method int getExpirationDate() Point in time (Unix timestamp) when the boost will automatically expire, unless the booster's Telegram Premium subscription is prolonged + * @method ChatBoostSource getSource() Source of the added boost + */ +class ChatBoost extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'source' => ChatBoostSourceFactory::class, + ]; + } +} diff --git a/src/Entities/ChatBoostRemoved.php b/src/Entities/ChatBoostRemoved.php new file mode 100644 index 00000000..2b893cca --- /dev/null +++ b/src/Entities/ChatBoostRemoved.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +use Longman\TelegramBot\Entities\ChatBoostSource\Factory as ChatBoostSourceFactory; + +/** + * This object represents a boost removed from a chat. + * + * @link https://core.telegram.org/bots/api#chatboostremoved + * + * @method Chat getChat() Chat which was boosted + * @method string getBoostId() Unique identifier of the boost + * @method int getRemoveDate() Point in time (Unix timestamp) when the boost was removed + * @method ChatBoostSource getSource() Source of the removed boost + */ +class ChatBoostRemoved extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'chat' => Chat::class, + 'source' => ChatBoostSourceFactory::class, + ]; + } +} diff --git a/src/Entities/ChatBoostSource/ChatBoostSource.php b/src/Entities/ChatBoostSource/ChatBoostSource.php new file mode 100644 index 00000000..dae048a9 --- /dev/null +++ b/src/Entities/ChatBoostSource/ChatBoostSource.php @@ -0,0 +1,16 @@ + User::class, + ]; + } +} diff --git a/src/Entities/ChatBoostSource/ChatBoostSourceGiveaway.php b/src/Entities/ChatBoostSource/ChatBoostSourceGiveaway.php new file mode 100644 index 00000000..7e405480 --- /dev/null +++ b/src/Entities/ChatBoostSource/ChatBoostSourceGiveaway.php @@ -0,0 +1,29 @@ + User::class, + ]; + } +} diff --git a/src/Entities/ChatBoostSource/ChatBoostSourceNotImplemented.php b/src/Entities/ChatBoostSource/ChatBoostSourceNotImplemented.php new file mode 100644 index 00000000..e045fcc0 --- /dev/null +++ b/src/Entities/ChatBoostSource/ChatBoostSourceNotImplemented.php @@ -0,0 +1,15 @@ + User::class, + ]; + } +} diff --git a/src/Entities/ChatBoostSource/Factory.php b/src/Entities/ChatBoostSource/Factory.php new file mode 100644 index 00000000..11e5af78 --- /dev/null +++ b/src/Entities/ChatBoostSource/Factory.php @@ -0,0 +1,24 @@ + ChatBoostSourcePremium::class, + 'gift_code' => ChatBoostSourceGiftCode::class, + 'giveaway' => ChatBoostSourceGiveaway::class, + ]; + + if (!isset($type[$data['source'] ?? ''])) { + return new ChatBoostSourceNotImplemented($data, $bot_username); + } + + $class = $type[$data['source']]; + return new $class($data, $bot_username); + } +} diff --git a/src/Entities/ChatBoostUpdated.php b/src/Entities/ChatBoostUpdated.php new file mode 100644 index 00000000..5228b957 --- /dev/null +++ b/src/Entities/ChatBoostUpdated.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +/** + * This object represents a boost added to a chat or changed. + * + * @link https://core.telegram.org/bots/api#chatboostupdated + * + * @method Chat getChat() Chat which was boosted + * @method ChatBoost getBoost() Information about the chat boost + */ +class ChatBoostUpdated extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'chat' => Chat::class, + 'chat_boost' => ChatBoost::class, + ]; + } +} diff --git a/src/Entities/UserChatBoosts.php b/src/Entities/UserChatBoosts.php new file mode 100644 index 00000000..de45ddb1 --- /dev/null +++ b/src/Entities/UserChatBoosts.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Longman\TelegramBot\Entities; + +/** + * This object represents a list of boosts added to a chat by a user. + * + * @link https://core.telegram.org/bots/api#userchatboosts + * + * @method ChatBoost[] getBoosts() The list of boosts added to the chat by the user + */ +class UserChatBoosts extends Entity +{ + /** + * {@inheritdoc} + */ + protected function subEntities(): array + { + return [ + 'boosts' => [ChatBoost::class], + ]; + } +} diff --git a/src/Request.php b/src/Request.php index bf0bd27e..4cad3ddc 100644 --- a/src/Request.php +++ b/src/Request.php @@ -100,6 +100,7 @@ * @method static ServerResponse unpinAllGeneralForumTopicMessages(array $data) Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success. * @method static ServerResponse answerCallbackQuery(array $data) Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned. * @method static ServerResponse answerInlineQuery(array $data) Use this method to send answers to an inline query. On success, True is returned. + * @method static ServerResponse getUserChatBoosts(array $data) Use this method to get the list of boosts added to a chat by a user. Requires administrator rights in the chat. Returns a UserChatBoosts object. * @method static ServerResponse setMyCommands(array $data) Use this method to change the list of the bot's commands. Returns True on success. * @method static ServerResponse deleteMyCommands(array $data) Use this method to delete the list of the bot's commands for the given scope and user language. After deletion, higher level commands will be shown to affected users. Returns True on success. * @method static ServerResponse getMyCommands(array $data) Use this method to get the current list of the bot's commands. Requires no parameters. Returns Array of BotCommand on success. @@ -280,6 +281,7 @@ class Request 'unpinAllGeneralForumTopicMessages', 'answerCallbackQuery', 'answerInlineQuery', + 'getUserChatBoosts', 'setMyCommands', 'deleteMyCommands', 'getMyCommands', diff --git a/structure.sql b/structure.sql index b3f49767..ae766984 100644 --- a/structure.sql +++ b/structure.sql @@ -329,6 +329,32 @@ CREATE TABLE IF NOT EXISTS `chat_join_request` ( FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +CREATE TABLE IF NOT EXISTS `chat_boost_updated` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'Chat which was boosted', + `boost` TEXT NOT NULL COMMENT 'Information about the chat boost', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +CREATE TABLE IF NOT EXISTS `chat_boost_removed` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'Chat which was boosted', + `boost_id` varchar NOT NULL COMMENT 'Unique identifier of the boost', + `remove_date` timestamp NOT NULL COMMENT 'Point in time (Unix timestamp) when the boost was removed', + `source` TEXT NOT NULL COMMENT 'Source of the removed boost', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + CREATE TABLE IF NOT EXISTS `telegram_update` ( `id` bigint UNSIGNED COMMENT 'Update''s unique identifier', `chat_id` bigint NULL DEFAULT NULL COMMENT 'Unique chat identifier', diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql index 81dde119..e58df278 100644 --- a/utils/db-schema-update/0.82.0-unreleased.sql +++ b/utils/db-schema-update/0.82.0-unreleased.sql @@ -31,6 +31,32 @@ CREATE TABLE IF NOT EXISTS `message_reaction_count` ( FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; +CREATE TABLE IF NOT EXISTS `chat_boost_updated` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'Chat which was boosted', + `boost` TEXT NOT NULL COMMENT 'Information about the chat boost', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +CREATE TABLE IF NOT EXISTS `chat_boost_removed` ( + `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', + `chat_id` bigint COMMENT 'Chat which was boosted', + `boost_id` varchar NOT NULL COMMENT 'Unique identifier of the boost', + `remove_date` timestamp NOT NULL COMMENT 'Point in time (Unix timestamp) when the boost was removed', + `source` TEXT NOT NULL COMMENT 'Source of the removed boost', + `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', + + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + + FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + ALTER TABLE `message` ADD COLUMN `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic' AFTER `reply_to_message`, ADD COLUMN `link_preview_options` TEXT NULL DEFAULT NULL COMMENT 'Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed' AFTER `via_bot`, From 72578a264bcae43ddb00191ff16d737dc5c43ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sat, 4 May 2024 22:14:38 +0200 Subject: [PATCH 07/19] wip --- CHANGELOG.md | 5 +++++ composer.json | 4 ++-- src/Entities/Update.php | 8 +++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2608bb47..f36c1a11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ Exclamation symbols (:exclamation:) note something of importance e.g. breaking c - [:ledger: View file changes][Unreleased] ### Added ### Changed +BC + Renamed the class KeyboardButtonRequestUser to KeyboardButtonRequestUsers. + Renamed the field request_user to request_users in KeyboardButton. + Renamed DB field message.user_shared to message.users_shared. + ### Deprecated ### Removed ### Fixed diff --git a/composer.json b/composer.json index e94888dd..da478ad1 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^8.1", "ext-pdo": "*", "ext-curl": "*", "ext-json": "*", @@ -75,7 +75,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.81.x-dev" + "dev-develop": "0.83.x-dev" } } } diff --git a/src/Entities/Update.php b/src/Entities/Update.php index 931074f9..716b1830 100644 --- a/src/Entities/Update.php +++ b/src/Entities/Update.php @@ -36,6 +36,8 @@ * @method ChatMemberUpdated getMyChatMember() Optional. The bot's chat member status was updated in a chat. For private chats, this update is received only when the bot is blocked or unblocked by the user. * @method ChatMemberUpdated getChatMember() Optional. A chat member's status was updated in a chat. The bot must be an administrator in the chat and must explicitly specify “chat_member” in the list of allowed_updates to receive these updates. * @method ChatJoinRequest getChatJoinRequest() Optional. A request to join the chat has been sent. The bot must have the can_invite_users administrator right in the chat to receive these updates. + * @method ChatBoostUpdated getChatBoost() Optional. A chat boost was added or changed. The bot must be an administrator in the chat to receive these updates. + * @method ChatBoostRemoved getRemovedChatBoost() Optional. A boost was removed from a chat. The bot must be an administrator in the chat to receive these updates. */ class Update extends Entity { @@ -55,6 +57,8 @@ class Update extends Entity public const TYPE_MY_CHAT_MEMBER = 'my_chat_member'; public const TYPE_CHAT_MEMBER = 'chat_member'; public const TYPE_CHAT_JOIN_REQUEST = 'chat_join_request'; + public const TYPE_CHAT_BOOST = 'chat_boost'; + public const TYPE_REMOVED_CHAT_BOOST = 'removed_chat_boost'; /** * {@inheritdoc} @@ -78,6 +82,8 @@ protected function subEntities(): array self::TYPE_MY_CHAT_MEMBER => ChatMemberUpdated::class, self::TYPE_CHAT_MEMBER => ChatMemberUpdated::class, self::TYPE_CHAT_JOIN_REQUEST => ChatJoinRequest::class, + self::TYPE_CHAT_BOOST => ChatBoostUpdated::class, + self::TYPE_REMOVED_CHAT_BOOST => ChatBoostRemoved::class, ]; } @@ -110,7 +116,7 @@ public function getUpdateType(): ?string /** * Get update content * - * @return CallbackQuery|ChatMemberUpdated|ChosenInlineResult|InlineQuery|Message|PollAnswer|Poll|PreCheckoutQuery|ShippingQuery + * @return Message|EditedMessage|ChannelPost|EditedChannelPost|MessageReactionUpdated|MessageReactionCountUpdated|InlineQuery|ChosenInlineResult|CallbackQuery|ShippingQuery|PreCheckoutQuery|Poll|PollAnswer|ChatMemberUpdated|ChatJoinRequest|ChatBoostUpdated|ChatBoostRemoved */ public function getUpdateContent() { From 1d9286f0cbed5fe2e9bf347098c246b9cb3a3476 Mon Sep 17 00:00:00 2001 From: Tii Date: Mon, 13 May 2024 18:45:42 +0200 Subject: [PATCH 08/19] Other Changes pt. 1 --- src/Entities/Chat.php | 5 ++++ src/Entities/Message.php | 8 ++---- src/Entities/MessageOrigin/MessageOrigin.php | 16 +++++++++++ .../MessageOrigin/MessageOriginChannel.php | 28 +++++++++++++++++++ .../MessageOrigin/MessageOriginChat.php | 27 ++++++++++++++++++ .../MessageOrigin/MessageOriginHiddenUser.php | 20 +++++++++++++ .../MessageOrigin/MessageOriginUser.php | 26 +++++++++++++++++ 7 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 src/Entities/MessageOrigin/MessageOrigin.php create mode 100644 src/Entities/MessageOrigin/MessageOriginChannel.php create mode 100644 src/Entities/MessageOrigin/MessageOriginChat.php create mode 100644 src/Entities/MessageOrigin/MessageOriginHiddenUser.php create mode 100644 src/Entities/MessageOrigin/MessageOriginUser.php diff --git a/src/Entities/Chat.php b/src/Entities/Chat.php index 4cc89bc0..8a46c519 100644 --- a/src/Entities/Chat.php +++ b/src/Entities/Chat.php @@ -28,9 +28,13 @@ * @method string getFirstName() Optional. First name of the other party in a private chat * @method string getLastName() Optional. Last name of the other party in a private chat * @method bool getIsForum() Optional. True, if the supergroup chat is a forum (has topics enabled) + * @method int getAccentColorId() Identifier of the accent color for the chat name and backgrounds of the chat photo, reply header, and link preview. See accent colors for more details. * @method ChatPhoto getPhoto() Optional. Chat photo. Returned only in getChat. * @method string[] getActiveUsernames() Optional. If non-empty, the list of all active chat usernames; for private chats, supergroups and channels. Returned only in getChat. * @method ReactionType[] getAvailableReactions() Optional. List of available reactions allowed in the chat. If omitted, then all emoji reactions are allowed. Returned only in getChat. + * @method string getBackgroundCustomEmojiId() Optional. Custom emoji identifier of the emoji chosen by the chat for the reply header and link preview background + * @method int getProfileAccentColorId() Optional. Identifier of the accent color for the chat's profile background. See profile accent colors for more details. + * @method string getProfileBackgroundCustomEmojiId() Optional. Custom emoji identifier of the emoji chosen by the chat for its profile background * @method string getEmojiStatusCustomEmojiId() Optional. Custom emoji identifier of emoji status of the other party in a private chat. Returned only in getChat. * @method int getEmojiStatusExpirationDate() Optional. Expiration date of the emoji status of the other party in a private chat in Unix time, if any. Returned only in getChat. * @method string getBio() Optional. Bio of the other party in a private chat. Returned only in getChat. @@ -47,6 +51,7 @@ * @method bool getHasAggressiveAntiSpamEnabled() Optional. True, if aggressive anti-spam checks are enabled in the supergroup. The field is only available to chat administrators. Returned only in getChat. * @method bool getHasHiddenMembers() Optional. True, if non-administrators can only get the list of bots and administrators in the chat. Returned only in getChat. * @method bool getHasProtectedContent() Optional. True, if messages from the chat can't be forwarded to other chats. Returned only in getChat. + * @method bool getHasVisibleHistory() Optional. True, if new chat members will have access to old messages; available only to chat administrators * @method string getStickerSetName() Optional. For supergroups, name of group sticker set. Returned only in getChat. * @method bool getCanSetStickerSet() Optional. True, if the bot can change the group sticker set. Returned only in getChat. * @method int getLinkedChatId() Optional. Unique identifier for the linked chat. Returned only in getChat. diff --git a/src/Entities/Message.php b/src/Entities/Message.php index c0795078..217fed7b 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -12,6 +12,7 @@ namespace Longman\TelegramBot\Entities; use Longman\TelegramBot\Entities\Games\Game; +use Longman\TelegramBot\Entities\MessageOrigin\MessageOrigin; use Longman\TelegramBot\Entities\Payments\Invoice; use Longman\TelegramBot\Entities\Payments\SuccessfulPayment; use Longman\TelegramBot\Entities\TelegramPassport\PassportData; @@ -35,12 +36,7 @@ * @method Chat getSenderChat() Optional. Sender of the message, sent on behalf of a chat. The channel itself for channel messages. The supergroup itself for messages from anonymous group administrators. The linked channel for messages automatically forwarded to the discussion group * @method int getDate() Date the message was sent in Unix time * @method Chat getChat() Conversation the message belongs to - * @method User getForwardFrom() Optional. For forwarded messages, sender of the original message - * @method Chat getForwardFromChat() Optional. For messages forwarded from a channel, information about the original channel - * @method int getForwardFromMessageId() Optional. For forwarded channel posts, identifier of the original message in the channel - * @method string getForwardSignature() Optional. For messages forwarded from channels, signature of the post author if present - * @method string getForwardSenderName() Optional. Sender's name for messages forwarded from users who disallow adding a link to their account in forwarded messages - * @method int getForwardDate() Optional. For forwarded messages, date the original message was sent in Unix time + * @method MessageOrigin getForwardOrigin() Optional. Information about the original message for forwarded messages * @method bool getIsTopicMessage() Optional. True, if the message is sent to a forum topic * @method bool getIsAutomaticForward() Optional. True, if the message is a channel post that was automatically forwarded to the connected discussion group * @method ReplyToMessage getReplyToMessage() Optional. For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply. diff --git a/src/Entities/MessageOrigin/MessageOrigin.php b/src/Entities/MessageOrigin/MessageOrigin.php new file mode 100644 index 00000000..db0cd5c7 --- /dev/null +++ b/src/Entities/MessageOrigin/MessageOrigin.php @@ -0,0 +1,16 @@ + Chat::class, + ]; + } + +} diff --git a/src/Entities/MessageOrigin/MessageOriginChat.php b/src/Entities/MessageOrigin/MessageOriginChat.php new file mode 100644 index 00000000..47ff472b --- /dev/null +++ b/src/Entities/MessageOrigin/MessageOriginChat.php @@ -0,0 +1,27 @@ + Chat::class, + ]; + } + +} diff --git a/src/Entities/MessageOrigin/MessageOriginHiddenUser.php b/src/Entities/MessageOrigin/MessageOriginHiddenUser.php new file mode 100644 index 00000000..72ec6450 --- /dev/null +++ b/src/Entities/MessageOrigin/MessageOriginHiddenUser.php @@ -0,0 +1,20 @@ + User::class, + ]; + } + +} From 5de19357219aaa4ea6b69510370481fc0270202a Mon Sep 17 00:00:00 2001 From: Tii Date: Mon, 13 May 2024 19:13:00 +0200 Subject: [PATCH 09/19] Other Changes pt. 2: Added Factory and NotImplemented class --- src/Entities/Message.php | 4 +-- src/Entities/MessageOrigin/Factory.php | 26 +++++++++++++++++++ src/Entities/MessageOrigin/MessageOrigin.php | 2 -- .../MessageOriginNotImplemented.php | 14 ++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/Entities/MessageOrigin/Factory.php create mode 100644 src/Entities/MessageOrigin/MessageOriginNotImplemented.php diff --git a/src/Entities/Message.php b/src/Entities/Message.php index 217fed7b..3c9af262 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -12,6 +12,7 @@ namespace Longman\TelegramBot\Entities; use Longman\TelegramBot\Entities\Games\Game; +use Longman\TelegramBot\Entities\MessageOrigin\Factory as MessageOriginFactory; use Longman\TelegramBot\Entities\MessageOrigin\MessageOrigin; use Longman\TelegramBot\Entities\Payments\Invoice; use Longman\TelegramBot\Entities\Payments\SuccessfulPayment; @@ -111,8 +112,7 @@ protected function subEntities(): array 'from' => User::class, 'sender_chat' => Chat::class, 'chat' => Chat::class, - 'forward_from' => User::class, - 'forward_from_chat' => Chat::class, + 'forward_origin' => MessageOriginFactory::class, 'reply_to_message' => ReplyToMessage::class, 'external_reply' => ExternalReplyInfo::class, 'quote' => TextQuote::class, diff --git a/src/Entities/MessageOrigin/Factory.php b/src/Entities/MessageOrigin/Factory.php new file mode 100644 index 00000000..54f7409d --- /dev/null +++ b/src/Entities/MessageOrigin/Factory.php @@ -0,0 +1,26 @@ + MessageOriginUser::class, + 'hidden_user' => MessageOriginHiddenUser::class, + 'chat' => MessageOriginChat::class, + 'channel' => MessageOriginChannel::class, + ]; + + if (!isset($type[$data['type'] ?? ''])) { + return new MessageOriginNotImplemented($data, $bot_username); + } + + $class = $type[$data['type']]; + return new $class($data, $bot_username); + } + +} diff --git a/src/Entities/MessageOrigin/MessageOrigin.php b/src/Entities/MessageOrigin/MessageOrigin.php index db0cd5c7..a8a468c0 100644 --- a/src/Entities/MessageOrigin/MessageOrigin.php +++ b/src/Entities/MessageOrigin/MessageOrigin.php @@ -2,8 +2,6 @@ namespace Longman\TelegramBot\Entities\MessageOrigin; -use Longman\TelegramBot\Entities\Entity; - /** * This object describes the origin of a message. * diff --git a/src/Entities/MessageOrigin/MessageOriginNotImplemented.php b/src/Entities/MessageOrigin/MessageOriginNotImplemented.php new file mode 100644 index 00000000..7e9793e9 --- /dev/null +++ b/src/Entities/MessageOrigin/MessageOriginNotImplemented.php @@ -0,0 +1,14 @@ + Date: Mon, 13 May 2024 19:32:10 +0200 Subject: [PATCH 10/19] Other Changes pt. 3: Added MaybeInaccessibleMessage --- src/Entities/CallbackQuery.php | 18 ++++++++------- src/Entities/Message.php | 8 ++++--- src/Entities/Message/Factory.php | 21 ++++++++++++++++++ src/Entities/Message/InaccessibleMessage.php | 22 +++++++++++++++++++ .../Message/MaybeInaccessibleMessage.php | 15 +++++++++++++ 5 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 src/Entities/Message/Factory.php create mode 100644 src/Entities/Message/InaccessibleMessage.php create mode 100644 src/Entities/Message/MaybeInaccessibleMessage.php diff --git a/src/Entities/CallbackQuery.php b/src/Entities/CallbackQuery.php index e65f6bf2..d5fd51d7 100644 --- a/src/Entities/CallbackQuery.php +++ b/src/Entities/CallbackQuery.php @@ -11,6 +11,8 @@ namespace Longman\TelegramBot\Entities; +use Longman\TelegramBot\Entities\Message\Factory as MaybeInaccessibleMessageFactory; +use Longman\TelegramBot\Entities\Message\MaybeInaccessibleMessage; use Longman\TelegramBot\Request; /** @@ -18,13 +20,13 @@ * * @link https://core.telegram.org/bots/api#callbackquery * - * @method string getId() Unique identifier for this query - * @method User getFrom() Sender - * @method Message getMessage() Optional. Message with the callback button that originated the query. Note that message content and message date will not be available if the message is too old - * @method string getInlineMessageId() Optional. Identifier of the message sent via the bot in inline mode, that originated the query - * @method string getChatInstance() Global identifier, uniquely corresponding to the chat to which the message with the callback button was sent. Useful for high scores in games. - * @method string getData() Data associated with the callback button. Be aware that a bad client can send arbitrary data in this field - * @method string getGameShortName() Optional. Short name of a Game to be returned, serves as the unique identifier for the game + * @method string getId() Unique identifier for this query + * @method User getFrom() Sender + * @method MaybeInaccessibleMessage getMessage() Optional. Message with the callback button that originated the query. Note that message content and message date will not be available if the message is too old + * @method string getInlineMessageId() Optional. Identifier of the message sent via the bot in inline mode, that originated the query + * @method string getChatInstance() Global identifier, uniquely corresponding to the chat to which the message with the callback button was sent. Useful for high scores in games. + * @method string getData() Data associated with the callback button. Be aware that a bad client can send arbitrary data in this field + * @method string getGameShortName() Optional. Short name of a Game to be returned, serves as the unique identifier for the game */ class CallbackQuery extends Entity { @@ -35,7 +37,7 @@ protected function subEntities(): array { return [ 'from' => User::class, - 'message' => Message::class, + 'message' => MaybeInaccessibleMessageFactory::class, ]; } diff --git a/src/Entities/Message.php b/src/Entities/Message.php index 3c9af262..9d640319 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -12,6 +12,8 @@ namespace Longman\TelegramBot\Entities; use Longman\TelegramBot\Entities\Games\Game; +use Longman\TelegramBot\Entities\Message\Factory as MaybeInaccessibleMessageFactory; +use Longman\TelegramBot\Entities\Message\MaybeInaccessibleMessage; use Longman\TelegramBot\Entities\MessageOrigin\Factory as MessageOriginFactory; use Longman\TelegramBot\Entities\MessageOrigin\MessageOrigin; use Longman\TelegramBot\Entities\Payments\Invoice; @@ -79,7 +81,7 @@ * @method bool getChannelChatCreated() Optional. Service message: the channel has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel. * @method int getMigrateToChatId() Optional. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier. * @method int getMigrateFromChatId() Optional. The supergroup has been migrated from a group with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier. - * @method Message getPinnedMessage() Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply. + * @method MaybeInaccessibleMessage getPinnedMessage() Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply. * @method Invoice getInvoice() Optional. Message is an invoice for a payment, information about the invoice. * @method SuccessfulPayment getSuccessfulPayment() Optional. Message is a service message about a successful payment, information about the payment. * @method UsersShared getUsersShared() Optional. Service message: users were shared with the bot @@ -101,7 +103,7 @@ * @method WebAppData getWebAppData() Optional. Service message: data sent by a Web App * @method InlineKeyboard getReplyMarkup() Optional. Inline keyboard attached to the message. login_url buttons are represented as ordinary url buttons. */ -class Message extends Entity +class Message extends Entity implements MaybeInaccessibleMessage { /** * {@inheritdoc} @@ -139,7 +141,7 @@ protected function subEntities(): array 'left_chat_member' => User::class, 'new_chat_photo' => [PhotoSize::class], 'message_auto_delete_timer_changed' => MessageAutoDeleteTimerChanged::class, - 'pinned_message' => __CLASS__, + 'pinned_message' => MaybeInaccessibleMessageFactory::class, 'invoice' => Invoice::class, 'successful_payment' => SuccessfulPayment::class, 'users_shared' => UsersShared::class, diff --git a/src/Entities/Message/Factory.php b/src/Entities/Message/Factory.php new file mode 100644 index 00000000..63ce362e --- /dev/null +++ b/src/Entities/Message/Factory.php @@ -0,0 +1,21 @@ + Chat::class, + ]; + } + +} diff --git a/src/Entities/Message/MaybeInaccessibleMessage.php b/src/Entities/Message/MaybeInaccessibleMessage.php new file mode 100644 index 00000000..8e9d1b85 --- /dev/null +++ b/src/Entities/Message/MaybeInaccessibleMessage.php @@ -0,0 +1,15 @@ + Date: Mon, 13 May 2024 20:05:03 +0200 Subject: [PATCH 11/19] Bot API 7.0 - Giveaway --- src/Entities/Giveaway/Giveaway.php | 34 +++++++++++++++++++ src/Entities/Giveaway/GiveawayCompleted.php | 26 +++++++++++++++ src/Entities/Giveaway/GiveawayCreated.php | 10 ++++++ src/Entities/Giveaway/GiveawayWinners.php | 36 +++++++++++++++++++++ src/Entities/Message.php | 12 +++++++ 5 files changed, 118 insertions(+) create mode 100644 src/Entities/Giveaway/Giveaway.php create mode 100644 src/Entities/Giveaway/GiveawayCompleted.php create mode 100644 src/Entities/Giveaway/GiveawayCreated.php create mode 100644 src/Entities/Giveaway/GiveawayWinners.php diff --git a/src/Entities/Giveaway/Giveaway.php b/src/Entities/Giveaway/Giveaway.php new file mode 100644 index 00000000..af6d307c --- /dev/null +++ b/src/Entities/Giveaway/Giveaway.php @@ -0,0 +1,34 @@ + getChats() The list of chats which the user must join to participate in the giveaway + * @method int getWinnersSelectionDate() Point in time (Unix timestamp) when winners of the giveaway will be selected + * @method int getWinnerCount() The number of users which are supposed to be selected as winners of the giveaway + * @method bool getOnlyNewMembers() Optional. True, if only users who join the chats after the giveaway started should be eligible to win + * @method bool getHasPublicWinners() Optional. True, if the list of giveaway winners will be visible to everyone + * @method string getPrizeDescription() Optional. Description of additional giveaway prize + * @method array getCountryCodes() Optional. A list of two-letter ISO 3166-1 alpha-2 country codes indicating the countries from which eligible users for the giveaway must come. If empty, then all users can participate in the giveaway. Users with a phone number that was bought on Fragment can always participate in giveaways. + * @method int getPremiumSubscriptionMonthCount() Optional. The number of months the Telegram Premium subscription won from the giveaway will be active for + + * + */ +class Giveaway extends Entity +{ + + protected function subEntities(): array + { + return [ + 'chats' => [Chat::class], + ]; + } + +} diff --git a/src/Entities/Giveaway/GiveawayCompleted.php b/src/Entities/Giveaway/GiveawayCompleted.php new file mode 100644 index 00000000..8f97fae3 --- /dev/null +++ b/src/Entities/Giveaway/GiveawayCompleted.php @@ -0,0 +1,26 @@ + Message::class, + ]; + } +} diff --git a/src/Entities/Giveaway/GiveawayCreated.php b/src/Entities/Giveaway/GiveawayCreated.php new file mode 100644 index 00000000..cb546215 --- /dev/null +++ b/src/Entities/Giveaway/GiveawayCreated.php @@ -0,0 +1,10 @@ + getWinners() List of up to 100 winners of the giveaway + * @method int getAdditionalChatCount() Optional. The number of other chats the user had to join in order to be eligible for the giveaway + * @method int getPremiumSubscriptionMonthCount() Optional. The number of months the Telegram Premium subscription won from the giveaway will be active for + * @method int getUnclaimedPrizeCount() Optional. Number of undistributed prizes + * @method bool getOnlyNewMembers() Optional. True, if only users who had joined the chats after the giveaway started were eligible to win + * @method bool getWasRefunded() Optional. True, if the giveaway was canceled because the payment for it was refunded + * @method string getPrizeDescription() Optional. Description of additional giveaway prize + */ +class GiveawayWinners extends Entity +{ + + protected function subEntities(): array + { + return [ + 'chat' => Chat::class, + 'winners' => [User::class], + ]; + } +} diff --git a/src/Entities/Message.php b/src/Entities/Message.php index 9d640319..8f771a30 100644 --- a/src/Entities/Message.php +++ b/src/Entities/Message.php @@ -12,6 +12,10 @@ namespace Longman\TelegramBot\Entities; use Longman\TelegramBot\Entities\Games\Game; +use Longman\TelegramBot\Entities\Giveaway\Giveaway; +use Longman\TelegramBot\Entities\Giveaway\GiveawayCompleted; +use Longman\TelegramBot\Entities\Giveaway\GiveawayCreated; +use Longman\TelegramBot\Entities\Giveaway\GiveawayWinners; use Longman\TelegramBot\Entities\Message\Factory as MaybeInaccessibleMessageFactory; use Longman\TelegramBot\Entities\Message\MaybeInaccessibleMessage; use Longman\TelegramBot\Entities\MessageOrigin\Factory as MessageOriginFactory; @@ -96,6 +100,10 @@ * @method ForumTopicReopened getForumTopicReopened() Optional. Service message: forum topic reopened * @method GeneralForumTopicHidden getGeneralForumTopicHidden() Optional. Service message: the 'General' forum topic hidden * @method GeneralForumTopicUnhidden getGeneralForumTopicUnhidden() Optional. Service message: the 'General' forum topic unhidden + * @method GiveawayCreated getGiveawayCreated() Optional. Service message: a scheduled giveaway was created + * @method Giveaway getGiveaway() Optional. The message is a scheduled giveaway message + * @method GiveawayWinners getGiveawayWinners() Optional. A giveaway with public winners was completed + * @method GiveawayCompleted getGiveawayCompleted() Optional. Service message: a giveaway without public winners was completed * @method VideoChatScheduled getVideoChatScheduled() Optional. Service message: voice chat scheduled * @method VideoChatStarted getVideoChatStarted() Optional. Service message: voice chat started * @method VideoChatEnded getVideoChatEnded() Optional. Service message: voice chat ended @@ -155,6 +163,10 @@ protected function subEntities(): array 'forum_topic_reopened' => ForumTopicReopened::class, 'general_forum_topic_hidden' => GeneralForumTopicHidden::class, 'general_forum_topic_unhidden' => GeneralForumTopicUnhidden::class, + 'giveaway_created' => GiveawayCreated::class, + 'giveaway' => Giveaway::class, + 'giveaway_winners' => GiveawayWinners::class, + 'giveaway_completed' => GiveawayCompleted::class, 'video_chat_scheduled' => VideoChatScheduled::class, 'video_chat_started' => VideoChatStarted::class, 'video_chat_ended' => VideoChatEnded::class, From 6c3eeaf4786dfce47cb45f10fbac608fadfb6e10 Mon Sep 17 00:00:00 2001 From: Tii Date: Tue, 14 May 2024 15:36:48 +0200 Subject: [PATCH 12/19] Fixed varchar bug --- structure.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structure.sql b/structure.sql index ae766984..cf806153 100644 --- a/structure.sql +++ b/structure.sql @@ -344,7 +344,7 @@ CREATE TABLE IF NOT EXISTS `chat_boost_updated` ( CREATE TABLE IF NOT EXISTS `chat_boost_removed` ( `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', `chat_id` bigint COMMENT 'Chat which was boosted', - `boost_id` varchar NOT NULL COMMENT 'Unique identifier of the boost', + `boost_id` varchar(200) NOT NULL COMMENT 'Unique identifier of the boost', `remove_date` timestamp NOT NULL COMMENT 'Point in time (Unix timestamp) when the boost was removed', `source` TEXT NOT NULL COMMENT 'Source of the removed boost', `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', From c63bbbd462dadd5b127ca77228d94fdfc24da10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 22:11:30 +0200 Subject: [PATCH 13/19] Update changelog for Bot API 7.0 --- CHANGELOG.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f36c1a11..c7bc9263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,12 @@ Exclamation symbols (:exclamation:) note something of importance e.g. breaking c ## [Unreleased] ### Notes -- [:ledger: View file changes][Unreleased] +- [:ledger: View file changes][Unreleased] ∙ [:page_with_curl: DB migration script][unreleased-sql-migration] +- [:exclamation:][unreleased-bc-minimum-php-81] PHP 8.1+ required! ### Added +- Bot API 7.0 (@noplanman, @TiiFuchs) (#1459) ### Changed -BC - Renamed the class KeyboardButtonRequestUser to KeyboardButtonRequestUsers. - Renamed the field request_user to request_users in KeyboardButton. - Renamed DB field message.user_shared to message.users_shared. - +- [:exclamation:][unreleased-bc-user-to-users] Various fields have been pluralised from "user" to "users". ### Deprecated ### Removed ### Fixed @@ -639,6 +637,9 @@ BC ### Deprecated - Move `hideKeyboard` to `removeKeyboard`. +[unreleased-sql-migration]: https://github.com/php-telegram-bot/core/tree/develop/utils/db-schema-update/0.82.0-unreleased.sql +[unreleased-bc-unreleased-bc-minimum-php-81]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#minimum-php-81 +[unreleased-bc-unreleased-bc-user-to-users]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#user-to-users [0.82.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.81.0-0.82.0.sql [0.81.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.80.0-0.81.0.sql [0.80.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.79.0-0.80.0.sql From 7410c365fadebb6336d9512d9909baadbe7847fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 22:14:48 +0200 Subject: [PATCH 14/19] Fix varchar in SQL migration script --- utils/db-schema-update/0.82.0-unreleased.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql index e58df278..ca6aafde 100644 --- a/utils/db-schema-update/0.82.0-unreleased.sql +++ b/utils/db-schema-update/0.82.0-unreleased.sql @@ -46,7 +46,7 @@ CREATE TABLE IF NOT EXISTS `chat_boost_updated` ( CREATE TABLE IF NOT EXISTS `chat_boost_removed` ( `id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry', `chat_id` bigint COMMENT 'Chat which was boosted', - `boost_id` varchar NOT NULL COMMENT 'Unique identifier of the boost', + `boost_id` varchar(200) NOT NULL COMMENT 'Unique identifier of the boost', `remove_date` timestamp NOT NULL COMMENT 'Point in time (Unix timestamp) when the boost was removed', `source` TEXT NOT NULL COMMENT 'Source of the removed boost', `created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation', From 4fd666383674460bcfd266a92853d34835d65db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 22:19:45 +0200 Subject: [PATCH 15/19] Fix tests for PHP 8.1+ --- .github/workflows/tests.yaml | 6 +++--- .scrutinizer.yml | 2 +- README.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index a334bee5..4d73c14e 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - php: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php: ['8.1', '8.2', '8.3'] services: mariadb: @@ -70,11 +70,11 @@ jobs: run: composer check-code - name: Run test suite - if: ${{ matrix.php != '7.3'}} + if: ${{ matrix.php != '8.1'}} run: composer test-cov - name: Run test suite (with coverage) - if: ${{ matrix.php == '7.3'}} + if: ${{ matrix.php == '8.1'}} run: | composer test-cov composer test-cov-upload diff --git a/.scrutinizer.yml b/.scrutinizer.yml index d3e57889..d788c467 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,6 +1,6 @@ build: environment: - php: 7.3.0 + php: 8.1.0 nodes: analysis: tests: diff --git a/README.md b/README.md index 85c13e61..51654d8b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A Telegram Bot based on the official [Telegram Bot API] [![Dependencies](https://tidelift.com/badges/github/php-telegram-bot/core?style=flat)][Tidelift] [![Total Downloads](https://img.shields.io/packagist/dt/longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot) [![Downloads Month](https://img.shields.io/packagist/dm/longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot) -[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D7.3-8892BF.svg)](https://php.net/) +[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D8.1-8892BF.svg)](https://php.net/) [![License](https://img.shields.io/packagist/l/longman/telegram-bot.svg)](https://github.com/php-telegram-bot/core/LICENSE) ## Table of Contents @@ -176,7 +176,7 @@ Create *composer.json* file "name": "yourproject/yourproject", "type": "project", "require": { - "php": ">=7.3", + "php": "^8.1", "longman/telegram-bot": "*" } } From 14c77ebc1ce3b6f1c9426f31a59355756e63c38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 22:26:06 +0200 Subject: [PATCH 16/19] Use pre MariaDB 10.5 way of renaming column, for backwards compatibility --- utils/db-schema-update/0.82.0-unreleased.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql index ca6aafde..3fb04f37 100644 --- a/utils/db-schema-update/0.82.0-unreleased.sql +++ b/utils/db-schema-update/0.82.0-unreleased.sql @@ -60,7 +60,7 @@ CREATE TABLE IF NOT EXISTS `chat_boost_removed` ( ALTER TABLE `message` ADD COLUMN `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic' AFTER `reply_to_message`, ADD COLUMN `link_preview_options` TEXT NULL DEFAULT NULL COMMENT 'Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed' AFTER `via_bot`, - RENAME COLUMN `user_shared` TO `users_shared`; + CHANGE COLUMN `user_shared` `users_shared` TEXT; ALTER TABLE `telegram_update` ADD COLUMN `message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user' AFTER `edited_channel_post_id`, From 99c49ad787001e983710f131a18bcb1e911a6058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 22:34:19 +0200 Subject: [PATCH 17/19] PHPCS is our friend, let's make it happy --- src/Entities/Giveaway/Giveaway.php | 4 ---- src/Entities/Giveaway/GiveawayCompleted.php | 1 - src/Entities/Giveaway/GiveawayCreated.php | 2 +- src/Entities/Giveaway/GiveawayWinners.php | 3 +-- src/Entities/Message/InaccessibleMessage.php | 1 - src/Entities/MessageOrigin/Factory.php | 1 - src/Entities/MessageOrigin/MessageOriginChannel.php | 1 - src/Entities/MessageOrigin/MessageOriginChat.php | 1 - src/Entities/MessageOrigin/MessageOriginHiddenUser.php | 1 - src/Entities/MessageOrigin/MessageOriginUser.php | 1 - 10 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Entities/Giveaway/Giveaway.php b/src/Entities/Giveaway/Giveaway.php index af6d307c..bd7fe931 100644 --- a/src/Entities/Giveaway/Giveaway.php +++ b/src/Entities/Giveaway/Giveaway.php @@ -18,17 +18,13 @@ * @method string getPrizeDescription() Optional. Description of additional giveaway prize * @method array getCountryCodes() Optional. A list of two-letter ISO 3166-1 alpha-2 country codes indicating the countries from which eligible users for the giveaway must come. If empty, then all users can participate in the giveaway. Users with a phone number that was bought on Fragment can always participate in giveaways. * @method int getPremiumSubscriptionMonthCount() Optional. The number of months the Telegram Premium subscription won from the giveaway will be active for - - * */ class Giveaway extends Entity { - protected function subEntities(): array { return [ 'chats' => [Chat::class], ]; } - } diff --git a/src/Entities/Giveaway/GiveawayCompleted.php b/src/Entities/Giveaway/GiveawayCompleted.php index 8f97fae3..29450072 100644 --- a/src/Entities/Giveaway/GiveawayCompleted.php +++ b/src/Entities/Giveaway/GiveawayCompleted.php @@ -16,7 +16,6 @@ */ class GiveawayCompleted extends Entity { - protected function subEntities(): array { return [ diff --git a/src/Entities/Giveaway/GiveawayCreated.php b/src/Entities/Giveaway/GiveawayCreated.php index cb546215..c4ec8dee 100644 --- a/src/Entities/Giveaway/GiveawayCreated.php +++ b/src/Entities/Giveaway/GiveawayCreated.php @@ -4,7 +4,7 @@ use Longman\TelegramBot\Entities\Entity; -class GiveawayCreated extends Entity +class GiveawayCreated extends Entity { } diff --git a/src/Entities/Giveaway/GiveawayWinners.php b/src/Entities/Giveaway/GiveawayWinners.php index 28d729e9..9874fbe1 100644 --- a/src/Entities/Giveaway/GiveawayWinners.php +++ b/src/Entities/Giveaway/GiveawayWinners.php @@ -25,11 +25,10 @@ */ class GiveawayWinners extends Entity { - protected function subEntities(): array { return [ - 'chat' => Chat::class, + 'chat' => Chat::class, 'winners' => [User::class], ]; } diff --git a/src/Entities/Message/InaccessibleMessage.php b/src/Entities/Message/InaccessibleMessage.php index fa67021f..9b5f2748 100644 --- a/src/Entities/Message/InaccessibleMessage.php +++ b/src/Entities/Message/InaccessibleMessage.php @@ -18,5 +18,4 @@ protected function subEntities(): array 'chat' => Chat::class, ]; } - } diff --git a/src/Entities/MessageOrigin/Factory.php b/src/Entities/MessageOrigin/Factory.php index 54f7409d..d3220506 100644 --- a/src/Entities/MessageOrigin/Factory.php +++ b/src/Entities/MessageOrigin/Factory.php @@ -22,5 +22,4 @@ public static function make(array $data, string $bot_username): Entity $class = $type[$data['type']]; return new $class($data, $bot_username); } - } diff --git a/src/Entities/MessageOrigin/MessageOriginChannel.php b/src/Entities/MessageOrigin/MessageOriginChannel.php index 674ebe33..acb9807f 100644 --- a/src/Entities/MessageOrigin/MessageOriginChannel.php +++ b/src/Entities/MessageOrigin/MessageOriginChannel.php @@ -24,5 +24,4 @@ protected function subEntities(): array 'chat' => Chat::class, ]; } - } diff --git a/src/Entities/MessageOrigin/MessageOriginChat.php b/src/Entities/MessageOrigin/MessageOriginChat.php index 47ff472b..a0c2b398 100644 --- a/src/Entities/MessageOrigin/MessageOriginChat.php +++ b/src/Entities/MessageOrigin/MessageOriginChat.php @@ -23,5 +23,4 @@ protected function subEntities(): array 'sender_chat' => Chat::class, ]; } - } diff --git a/src/Entities/MessageOrigin/MessageOriginHiddenUser.php b/src/Entities/MessageOrigin/MessageOriginHiddenUser.php index 72ec6450..baff892f 100644 --- a/src/Entities/MessageOrigin/MessageOriginHiddenUser.php +++ b/src/Entities/MessageOrigin/MessageOriginHiddenUser.php @@ -3,7 +3,6 @@ namespace Longman\TelegramBot\Entities\MessageOrigin; use Longman\TelegramBot\Entities\Entity; -use Longman\TelegramBot\Entities\MessageOrigin\MessageOrigin; /** * The message was originally sent by an unknown user. diff --git a/src/Entities/MessageOrigin/MessageOriginUser.php b/src/Entities/MessageOrigin/MessageOriginUser.php index 17fb4247..9aa000ac 100644 --- a/src/Entities/MessageOrigin/MessageOriginUser.php +++ b/src/Entities/MessageOrigin/MessageOriginUser.php @@ -22,5 +22,4 @@ protected function subEntities(): array 'sender_user' => User::class, ]; } - } From 231ab481aca892c7192161cd2213bb09565a2e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 22:41:19 +0200 Subject: [PATCH 18/19] Fix some missing "user" to "users" changes --- src/DB.php | 22 +++++++++++----------- tests/Unit/Entities/KeyboardButtonTest.php | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/DB.php b/src/DB.php index 25e5713a..cae89be1 100644 --- a/src/DB.php +++ b/src/DB.php @@ -78,7 +78,7 @@ public static function initialize( array $credentials, Telegram $telegram, $table_prefix = '', - $encoding = 'utf8mb4' + $encoding = 'utf8mb4', ): PDO { if (empty($credentials)) { throw new TelegramException('MySQL credentials not provided!'); @@ -127,7 +127,7 @@ public static function initialize( public static function externalInitialize( PDO $external_pdo_connection, Telegram $telegram, - string $table_prefix = '' + string $table_prefix = '', ): PDO { if ($external_pdo_connection === null) { throw new TelegramException('MySQL external connection not provided!'); @@ -300,12 +300,12 @@ protected static function getTimestamp(?int $unixtime = null): string /** * Convert array of Entity items to a JSON array * - * @todo Find a better way, as json_* functions are very heavy - * * @param array $entities * @param mixed $default * * @return mixed + * @todo Find a better way, as json_* functions are very heavy + * */ public static function entitiesArrayToJson(array $entities, $default = null) { @@ -346,7 +346,7 @@ protected static function insertTelegramUpdate( ?string $chat_member_updated_id = null, ?string $chat_join_request_id = null, ?string $chat_boost_updated_id = null, - ?string $chat_boost_removed_id = null + ?string $chat_boost_removed_id = null, ): ?bool { if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $message_reaction_id === null && $message_reaction_count_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null && $chat_boost_updated_id === null && $chat_boost_removed_id === null) { throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, message_reaction_id, message_reaction_count_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id, chat_join_request_id, chat_boost_updated_id, chat_boost_removed_id are all null'); @@ -539,12 +539,12 @@ public static function insertChat(Chat $chat, ?string $date = null, ?int $migrat /** * Insert request into database * - * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails? - * * @param Update $update * * @return bool * @throws TelegramException + * @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails? + * */ public static function insertRequest(Update $update): bool { @@ -640,7 +640,7 @@ public static function insertRequest(Update $update): bool $chat_member_updated_id, $chat_join_request_id, $chat_boost_updated_id, - $chat_boost_removed_id + $chat_boost_removed_id, ); } @@ -1322,7 +1322,7 @@ public static function insertMessageRequest(Message $message): bool `location`, `venue`, `poll`, `dice`, `new_chat_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `message_auto_delete_timer_changed`, `migrate_to_chat_id`, `migrate_from_chat_id`, - `pinned_message`, `invoice`, `successful_payment`, `user_shared`, `chat_shared`, `connected_website`, `write_access_allowed`, `passport_data`, `proximity_alert_triggered`, + `pinned_message`, `invoice`, `successful_payment`, `users_shared`, `chat_shared`, `connected_website`, `write_access_allowed`, `passport_data`, `proximity_alert_triggered`, `forum_topic_created`, `forum_topic_edited`, `forum_topic_closed`, `forum_topic_reopened`, `general_forum_topic_hidden`, `general_forum_topic_unhidden`, `video_chat_scheduled`, `video_chat_started`, `video_chat_ended`, `video_chat_participants_invited`, `web_app_data`, `reply_markup` ) VALUES ( @@ -1333,7 +1333,7 @@ public static function insertMessageRequest(Message $message): bool :location, :venue, :poll, :dice, :new_chat_members, :left_chat_member, :new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created, :supergroup_chat_created, :channel_chat_created, :message_auto_delete_timer_changed, :migrate_to_chat_id, :migrate_from_chat_id, - :pinned_message, :invoice, :successful_payment, :user_shared, :chat_shared, :connected_website, :write_access_allowed, :passport_data, :proximity_alert_triggered, + :pinned_message, :invoice, :successful_payment, :users_shared, :chat_shared, :connected_website, :write_access_allowed, :passport_data, :proximity_alert_triggered, :forum_topic_created, :forum_topic_edited, :forum_topic_closed, :forum_topic_reopened, :general_forum_topic_hidden, :general_forum_topic_unhidden, :video_chat_scheduled, :video_chat_started, :video_chat_ended, :video_chat_participants_invited, :web_app_data, :reply_markup ) @@ -1411,7 +1411,7 @@ public static function insertMessageRequest(Message $message): bool $sth->bindValue(':pinned_message', $message->getPinnedMessage()); $sth->bindValue(':invoice', $message->getInvoice()); $sth->bindValue(':successful_payment', $message->getSuccessfulPayment()); - $sth->bindValue(':user_shared', $message->getUserShared()); + $sth->bindValue(':users_shared', $message->getUsersShared()); $sth->bindValue(':chat_shared', $message->getChatShared()); $sth->bindValue(':connected_website', $message->getConnectedWebsite()); $sth->bindValue(':write_access_allowed', $message->getWriteAccessAllowed()); diff --git a/tests/Unit/Entities/KeyboardButtonTest.php b/tests/Unit/Entities/KeyboardButtonTest.php index d8fc7840..e7cd907b 100644 --- a/tests/Unit/Entities/KeyboardButtonTest.php +++ b/tests/Unit/Entities/KeyboardButtonTest.php @@ -14,7 +14,7 @@ use Longman\TelegramBot\Entities\KeyboardButton; use Longman\TelegramBot\Entities\KeyboardButtonPollType; use Longman\TelegramBot\Entities\KeyboardButtonRequestChat; -use Longman\TelegramBot\Entities\KeyboardButtonRequestUser; +use Longman\TelegramBot\Entities\KeyboardButtonRequestUsers; use Longman\TelegramBot\Entities\WebAppInfo; use Longman\TelegramBot\Exception\TelegramException; use Longman\TelegramBot\Tests\Unit\TestCase; @@ -31,7 +31,7 @@ class KeyboardButtonTest extends TestCase public function testKeyboardButtonSuccess(): void { new KeyboardButton(['text' => 'message']); - new KeyboardButton(['text' => 'message', 'request_user' => new KeyboardButtonRequestUser([])]); + new KeyboardButton(['text' => 'message', 'request_users' => new KeyboardButtonRequestUsers([])]); new KeyboardButton(['text' => 'message', 'request_chat' => new KeyboardButtonRequestChat([])]); new KeyboardButton(['text' => 'message', 'request_contact' => true]); new KeyboardButton(['text' => 'message', 'request_location' => true]); @@ -49,8 +49,8 @@ public function testInlineKeyboardButtonCouldBe(): void public function testReturnsSubentitiesOnArray() { $button = new KeyboardButton('message'); - $button->request_user = []; - $this->assertInstanceOf(KeyboardButtonRequestUser::class, $button->getRequestUser()); + $button->request_users = []; + $this->assertInstanceOf(KeyboardButtonRequestUsers::class, $button->getRequestUsers()); $button = new KeyboardButton('message'); $button->request_chat = []; From 6071bb957c815282c1cb452eac08f787c4aa2fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 24 May 2024 23:13:21 +0200 Subject: [PATCH 19/19] Mini fix on namespace, skip coverage for now due to some weird error --- .github/workflows/tests.yaml | 18 +++++++++++------- composer.json | 2 +- src/Entities/ReactionType/Factory.php | 1 - .../ReactionTypeNotImplemented.php | 3 +-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4d73c14e..87764e11 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -70,11 +70,15 @@ jobs: run: composer check-code - name: Run test suite - if: ${{ matrix.php != '8.1'}} - run: composer test-cov + run: composer test - - name: Run test suite (with coverage) - if: ${{ matrix.php == '8.1'}} - run: | - composer test-cov - composer test-cov-upload +# - name: Run test suite +# if: ${{ matrix.php != '8.1'}} +# run: composer test-cov + +# - name: Run test suite (with coverage) +# if: ${{ matrix.php == '8.1'}} +# run: | +# wget https://scrutinizer-ci.com/ocular.phar +# composer test-cov +# composer test-cov-upload diff --git a/composer.json b/composer.json index da478ad1..1c421ec9 100644 --- a/composer.json +++ b/composer.json @@ -64,7 +64,7 @@ "XDEBUG_MODE=coverage \"vendor/bin/phpunit\" --coverage-clover clover.xml" ], "test-cov-upload": [ - "wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover clover.xml" + "@php ocular.phar code-coverage:upload --format=php-clover clover.xml" ] }, "config": { diff --git a/src/Entities/ReactionType/Factory.php b/src/Entities/ReactionType/Factory.php index d7cb8cab..f61cf368 100644 --- a/src/Entities/ReactionType/Factory.php +++ b/src/Entities/ReactionType/Factory.php @@ -2,7 +2,6 @@ namespace Longman\TelegramBot\Entities\ReactionType; -use Longman\TelegramBot\Entities\ChatMember\ReactionTypeNotImplemented; use Longman\TelegramBot\Entities\Entity; class Factory extends \Longman\TelegramBot\Entities\Factory diff --git a/src/Entities/ReactionType/ReactionTypeNotImplemented.php b/src/Entities/ReactionType/ReactionTypeNotImplemented.php index 8b5e4abc..26fab61e 100644 --- a/src/Entities/ReactionType/ReactionTypeNotImplemented.php +++ b/src/Entities/ReactionType/ReactionTypeNotImplemented.php @@ -1,9 +1,8 @@