From 07d03769b4ab9737c872c3c2683820db3ddb6b30 Mon Sep 17 00:00:00 2001 From: Mahdi Date: Sun, 17 Nov 2024 22:01:27 +0330 Subject: [PATCH 1/4] Add full support for star payments! - Add 2 service message for getting stars or getting gift stars - Add fromString method for some case to PareMode class - Add TextWithEntities class for support styled text when user send star gifts - Add Payment class shows pending payment --- .../Message/Entities/TextWithEntities.php | 47 ++++++++++ .../Message/Service/DialogGiftStars.php | 45 ++++++++++ .../Message/Service/DialogStarGift.php | 49 +++++++++++ src/EventHandler/Payments/Payment.php | 87 +++++++++++++++++++ .../Payments/PaymentRequestedInfo.php | 31 +++++++ src/EventHandler/Payments/StarGift.php | 62 +++++++++++++ src/MTProtoTools/UpdateHandler.php | 38 ++++++++ src/ParseMode.php | 9 ++ 8 files changed, 368 insertions(+) create mode 100644 src/EventHandler/Message/Entities/TextWithEntities.php create mode 100644 src/EventHandler/Message/Service/DialogGiftStars.php create mode 100644 src/EventHandler/Message/Service/DialogStarGift.php create mode 100644 src/EventHandler/Payments/Payment.php create mode 100644 src/EventHandler/Payments/PaymentRequestedInfo.php create mode 100644 src/EventHandler/Payments/StarGift.php diff --git a/src/EventHandler/Message/Entities/TextWithEntities.php b/src/EventHandler/Message/Entities/TextWithEntities.php new file mode 100644 index 000000000..8516eb3ba --- /dev/null +++ b/src/EventHandler/Message/Entities/TextWithEntities.php @@ -0,0 +1,47 @@ +. + * + * @author Mahdi + * @copyright 2016-2023 Mahdi + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +namespace danog\MadelineProto\EventHandler\Message\Entities; + +use danog\MadelineProto\ParseMode; +use JsonSerializable; + +final class TextWithEntities implements JsonSerializable +{ + public function __construct( + /** Text */ + public readonly string $text, + /** Message entities for styled text */ + public readonly array $entities, + /** Whether to parse HTML or Markdown markup in the message */ + public readonly ?ParseMode $parseMode, + ) + { + + } + + + /** @internal */ + public function jsonSerialize(): mixed + { + $res = ['_' => static::class]; + $refl = new ReflectionClass($this); + foreach ($refl->getProperties(ReflectionProperty::IS_PUBLIC) as $prop) { + $res[$prop->getName()] = $prop->getValue($this); + } + return $res; + } +} \ No newline at end of file diff --git a/src/EventHandler/Message/Service/DialogGiftStars.php b/src/EventHandler/Message/Service/DialogGiftStars.php new file mode 100644 index 000000000..fee9aa0bd --- /dev/null +++ b/src/EventHandler/Message/Service/DialogGiftStars.php @@ -0,0 +1,45 @@ +. + * + * @author Mahdi + * @copyright 2016-2023 Mahdi + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +use danog\MadelineProto\EventHandler\Message\ServiceMessage; +use danog\MadelineProto\MTProto; + +/** + * Info about a gifted Telegram Stars. + */ +class DialogGiftStars extends ServiceMessage +{ + /** @internal */ + public function __construct( + MTProto $API, + array $rawMessage, + array $info, + /** Three-letter ISO 4217 currency code */ + public string $currency, + /** Price of the gift in the smallest units of the currency (integer, not float/double). */ + public int $amount, + /** Amount of gifted stars */ + public int $stars, + /** If the gift was bought using a cryptocurrency, the cryptocurrency name. */ + public ?string $cryptoCurrency, + /** If the gift was bought using a cryptocurrency, price of the gift in the smallest units of a cryptocurrency. */ + public ?int $cryptoAmount, + /** Identifier of the transaction, only visible to the receiver of the gift. */ + public string $transactionId, + ) { + parent::__construct($API, $rawMessage, $info); + } +} diff --git a/src/EventHandler/Message/Service/DialogStarGift.php b/src/EventHandler/Message/Service/DialogStarGift.php new file mode 100644 index 000000000..42f08947a --- /dev/null +++ b/src/EventHandler/Message/Service/DialogStarGift.php @@ -0,0 +1,49 @@ +. + * + * @author Mahdi + * @copyright 2016-2023 Mahdi + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +namespace danog\MadelineProto\EventHandler\Message\Service; + +use danog\MadelineProto\EventHandler\Message\Entities\TextWithEntities; +use danog\MadelineProto\EventHandler\Message\ServiceMessage; +use danog\MadelineProto\EventHandler\Payments\StarGift; +use danog\MadelineProto\MTProto; + +/** + * Info about a Star gifted. + */ +class DialogStarGift extends ServiceMessage +{ + /** @internal */ + public function __construct( + MTProto $API, + array $rawMessage, + array $info, + /** Show the name of sender hide or no */ + public readonly ?bool $hide, + /** Show the gift is saved on profile or no */ + public readonly ?bool $saved, + /** Show the gift is converted to stars or no */ + public readonly ?bool $converted, + /** The gift */ + public readonly StarGift $gift, + /** Styled text that sender of gift provided */ + public readonly ?TextWithEntities $message, + /** Amount of stars after the gift converted */ + public readonly ?int $convertStars + ) { + parent::__construct($API, $rawMessage, $info); + } +} diff --git a/src/EventHandler/Payments/Payment.php b/src/EventHandler/Payments/Payment.php new file mode 100644 index 000000000..27075e113 --- /dev/null +++ b/src/EventHandler/Payments/Payment.php @@ -0,0 +1,87 @@ +. + * + * @author Mahdi + * @copyright 2016-2023 Mahdi + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +namespace danog\MadelineProto\EventHandler\Payments; + +use danog\MadelineProto\EventHandler\Update; +use danog\MadelineProto\MTProto; + +/** This object contains information about an incoming pre-checkout query. */ +class Payment extends Update +{ + /** Unique query identifier */ + public readonly int $queryId; + /** User who sent the query */ + public readonly int $userId; + /** Bot specified invoice payload */ + public readonly string $payload; + /** Order info provided by the user */ + public readonly ?PaymentRequestedInfo $info; + /** Identifier of the shipping option chosen by the user */ + public readonly ?string $shippingOptionId; + /** Three-letter ISO 4217 currency code */ + public readonly string $currency; + /**Total amount in the smallest units of the currency (integer, not float/double). */ + public readonly int $totalAmount; + /** @internal */ + public function __construct(MTProto $API,array $rawRequestedPayment) + { + parent::__construct($API); + $this->queryId = $rawRequestedPayment['query_id']; + $this->userId = $rawRequestedPayment['user_id']; + $this->payload = $rawRequestedPayment['payload']; + $this->info = isset($rawRequestedPayment['payload']) ? new PaymentRequestedInfo( + $rawRequestedPayment['name'], + $rawRequestedPayment['phone'], + $rawRequestedPayment['email'], + ) : null; + $this->shippingOptionId = $rawRequestedPayment['shipping_option_id'] ?? null; + $this->currency = $rawRequestedPayment['$currency']; + $this->totalAmount = $rawRequestedPayment['total_amount']; + + } + + /** + * Accept pending payment. + * note that you must call this function or reject function up to 10 seconds after user accept payment!!. + */ + public function accept(): true + { + return $this->getClient()->methodCallAsyncRead( + 'messages.setBotPrecheckoutResults', + [ + 'success' => true, + 'query_id' => $this->queryId, + ] + ); + } + + /** + * Reject pending payment. + * note that you must call this function or accept function up to 10 seconds after user accept payment!!. + */ + public function reject(string $errorMessage): false + { + return $this->getClient()->methodCallAsyncRead( + 'messages.setBotPrecheckoutResults', + [ + 'success' => false, + 'query_id' => $this->queryId, + 'error' => $errorMessage, + ] + ); + } +} \ No newline at end of file diff --git a/src/EventHandler/Payments/PaymentRequestedInfo.php b/src/EventHandler/Payments/PaymentRequestedInfo.php new file mode 100644 index 000000000..bff998d10 --- /dev/null +++ b/src/EventHandler/Payments/PaymentRequestedInfo.php @@ -0,0 +1,31 @@ + static::class]; + $refl = new ReflectionClass($this); + foreach ($refl->getProperties(ReflectionProperty::IS_PUBLIC) as $prop) { + $res[$prop->getName()] = $prop->getValue($this); + } + return $res; + } +} \ No newline at end of file diff --git a/src/EventHandler/Payments/StarGift.php b/src/EventHandler/Payments/StarGift.php new file mode 100644 index 000000000..044c36fc8 --- /dev/null +++ b/src/EventHandler/Payments/StarGift.php @@ -0,0 +1,62 @@ +limited = $rawStarGift['limited'] ?? null; + $this->soldOut = $rawStarGift['sold_out'] ?? null; + $this->id = $rawStarGift['id']; + $this->sticker = isset($rawStarGift['sticker']) ? + new StaticSticker( + $API, + $rawStarGift['sticker'], + $rawStarGift['sticker']['attributes'], + $rawStarGift['sticker']['attributes'], + false + ) : null; + $this->stars = $rawStarGift['stars']; + $this->availabilityRemains = $rawStarGift['availability_remains'] ?? null; + $this->availabilityTotal = $rawStarGift['availability_total'] ?? null; + $this->convertStars = $rawStarGift['convert_stars']; + $this->startSell = $rawStarGift['first_sale_date'] ?? null; + $this->endSell = $rawStarGift['last_sale_date'] ?? null; + parent::__construct($API); + } + + /** @internal */ + public function jsonSerialize(): mixed + { + $v = get_object_vars($this); + unset($v['API'], $v['session']); + return $v; + } +} diff --git a/src/MTProtoTools/UpdateHandler.php b/src/MTProtoTools/UpdateHandler.php index de8141202..7273b4551 100644 --- a/src/MTProtoTools/UpdateHandler.php +++ b/src/MTProtoTools/UpdateHandler.php @@ -50,6 +50,8 @@ use danog\MadelineProto\EventHandler\InlineQuery; use danog\MadelineProto\EventHandler\Message; use danog\MadelineProto\EventHandler\Message\ChannelMessage; use danog\MadelineProto\EventHandler\Message\CommentReply; +use danog\MadelineProto\EventHandler\Message\Entities\MessageEntity; +use danog\MadelineProto\EventHandler\Message\Entities\TextWithEntities; use danog\MadelineProto\EventHandler\Message\GroupMessage; use danog\MadelineProto\EventHandler\Message\PrivateMessage; use danog\MadelineProto\EventHandler\Message\SecretMessage; @@ -80,11 +82,14 @@ use danog\MadelineProto\EventHandler\Message\Service\DialogScreenshotTaken; use danog\MadelineProto\EventHandler\Message\Service\DialogSetChatTheme; use danog\MadelineProto\EventHandler\Message\Service\DialogSetChatWallPaper; use danog\MadelineProto\EventHandler\Message\Service\DialogSetTTL; +use danog\MadelineProto\EventHandler\Message\Service\DialogStarGift; use danog\MadelineProto\EventHandler\Message\Service\DialogSuggestProfilePhoto; use danog\MadelineProto\EventHandler\Message\Service\DialogTitleChanged; use danog\MadelineProto\EventHandler\Message\Service\DialogTopicCreated; use danog\MadelineProto\EventHandler\Message\Service\DialogTopicEdited; use danog\MadelineProto\EventHandler\Message\Service\DialogWebView; +use danog\MadelineProto\EventHandler\Payments\Payment; +use danog\MadelineProto\EventHandler\Payments\StarGift; use danog\MadelineProto\EventHandler\Pinned; use danog\MadelineProto\EventHandler\Pinned\PinnedChannelMessages; use danog\MadelineProto\EventHandler\Pinned\PinnedGroupMessages; @@ -128,6 +133,7 @@ use danog\MadelineProto\TL\Types\Button; use danog\MadelineProto\UpdateHandlerType; use danog\MadelineProto\VoIP\DiscardReason; use danog\MadelineProto\VoIPController; +use DialogGiftStars; use Revolt\EventLoop; use SplQueue; use Throwable; @@ -490,6 +496,7 @@ trait UpdateHandler 'updatePendingJoinRequests' => new PendingJoinRequests($this, $update), 'updateBotChatInviteRequester' => new BotChatInviteRequest($this, $update), 'updateBotCommands' => new BotCommands($this, $update), + 'updateBotPrecheckoutQuery' => new Payment($this,$update), default => null }; } catch (\Throwable $e) { @@ -684,6 +691,37 @@ trait UpdateHandler $message['action']['text'], null ), + 'messageActionGiftStars' => new DialogGiftStars( + $this, + $message, + $info, + $message['action']['currency'], + $message['action']['amount'], + $message['action']['stars'], + $message['action']['crypto_currency'] ?? null, + $message['action']['crypto_amount'] ?? null, + $message['action']['transaction_id'], + ), + 'messageActionStarGift' => new DialogStarGift( + $this, + $message, + $info, + $message['action']['name_hidden'] ?? null, + $message['action']['saved'] ?? null, + $message['action']['converted'] ?? null, + new StarGift( + $this, + $message['action']['gift'] + ), + isset($message['action']['message']) ? new TextWithEntities( + $message['action']['message']['text'], + MessageEntity::fromRawEntities($message['action']['message']['entities']), + isset($message['action']['message']['parse_mode']) ? + ParseMode::fromString($message['action']['message']['parse_mode']) + : null + ) : null, + $message['action']['convert_stars'], + ), 'messageActionGiftPremium' => new DialogGiftPremium( $this, $message, diff --git a/src/ParseMode.php b/src/ParseMode.php index 1a1cee3d5..d7cb2185a 100644 --- a/src/ParseMode.php +++ b/src/ParseMode.php @@ -24,4 +24,13 @@ enum ParseMode: string case HTML = 'HTML'; case MARKDOWN = 'Markdown'; case TEXT = 'text'; + /** @internal */ + public static function fromString(string $mode): ?string{ + foreach (self::cases() as $case){ + if(strtoupper($mode) === $case->name){ + return $case->value; + } + } + return null; + } } From 587cee53e795c654ee88a778dbe554a4216541ac Mon Sep 17 00:00:00 2001 From: Mahdi Date: Sun, 17 Nov 2024 22:09:41 +0330 Subject: [PATCH 2/4] cs-fix --- src/EventHandler/Message/Entities/TextWithEntities.php | 6 ++---- src/EventHandler/Payments/Payment.php | 6 ++++-- src/EventHandler/Payments/PaymentRequestedInfo.php | 7 +++---- src/EventHandler/Payments/StarGift.php | 3 +-- src/MTProtoTools/UpdateHandler.php | 2 +- src/ParseMode.php | 7 ++++--- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/EventHandler/Message/Entities/TextWithEntities.php b/src/EventHandler/Message/Entities/TextWithEntities.php index 8516eb3ba..a5f6634f2 100644 --- a/src/EventHandler/Message/Entities/TextWithEntities.php +++ b/src/EventHandler/Message/Entities/TextWithEntities.php @@ -28,12 +28,10 @@ final class TextWithEntities implements JsonSerializable public readonly array $entities, /** Whether to parse HTML or Markdown markup in the message */ public readonly ?ParseMode $parseMode, - ) - { + ) { } - /** @internal */ public function jsonSerialize(): mixed { @@ -44,4 +42,4 @@ final class TextWithEntities implements JsonSerializable } return $res; } -} \ No newline at end of file +} diff --git a/src/EventHandler/Payments/Payment.php b/src/EventHandler/Payments/Payment.php index 27075e113..6739cc1a2 100644 --- a/src/EventHandler/Payments/Payment.php +++ b/src/EventHandler/Payments/Payment.php @@ -37,7 +37,7 @@ class Payment extends Update /**Total amount in the smallest units of the currency (integer, not float/double). */ public readonly int $totalAmount; /** @internal */ - public function __construct(MTProto $API,array $rawRequestedPayment) + public function __construct(MTProto $API, array $rawRequestedPayment) { parent::__construct($API); $this->queryId = $rawRequestedPayment['query_id']; @@ -72,6 +72,8 @@ class Payment extends Update /** * Reject pending payment. * note that you must call this function or accept function up to 10 seconds after user accept payment!!. + * @param string $errorMessage if the success isn’t set. Error message in human-readable form that explains the reason for failure to proceed with the checkout + * */ public function reject(string $errorMessage): false { @@ -84,4 +86,4 @@ class Payment extends Update ] ); } -} \ No newline at end of file +} diff --git a/src/EventHandler/Payments/PaymentRequestedInfo.php b/src/EventHandler/Payments/PaymentRequestedInfo.php index bff998d10..160a015f3 100644 --- a/src/EventHandler/Payments/PaymentRequestedInfo.php +++ b/src/EventHandler/Payments/PaymentRequestedInfo.php @@ -1,4 +1,4 @@ -limited = $rawStarGift['limited'] ?? null; diff --git a/src/MTProtoTools/UpdateHandler.php b/src/MTProtoTools/UpdateHandler.php index 7273b4551..3bc47fa3f 100644 --- a/src/MTProtoTools/UpdateHandler.php +++ b/src/MTProtoTools/UpdateHandler.php @@ -496,7 +496,7 @@ trait UpdateHandler 'updatePendingJoinRequests' => new PendingJoinRequests($this, $update), 'updateBotChatInviteRequester' => new BotChatInviteRequest($this, $update), 'updateBotCommands' => new BotCommands($this, $update), - 'updateBotPrecheckoutQuery' => new Payment($this,$update), + 'updateBotPrecheckoutQuery' => new Payment($this, $update), default => null }; } catch (\Throwable $e) { diff --git a/src/ParseMode.php b/src/ParseMode.php index d7cb2185a..1391abf18 100644 --- a/src/ParseMode.php +++ b/src/ParseMode.php @@ -25,9 +25,10 @@ enum ParseMode: string case MARKDOWN = 'Markdown'; case TEXT = 'text'; /** @internal */ - public static function fromString(string $mode): ?string{ - foreach (self::cases() as $case){ - if(strtoupper($mode) === $case->name){ + public static function fromString(string $mode): ?string + { + foreach (self::cases() as $case) { + if(strtoupper($mode) === $case->name) { return $case->value; } } From 3cfbee5864a5915bd775287967416490cbbfebda Mon Sep 17 00:00:00 2001 From: Mahdi Date: Sun, 17 Nov 2024 22:12:32 +0330 Subject: [PATCH 3/4] more refactor --- src/EventHandler/Payments/Payment.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/EventHandler/Payments/Payment.php b/src/EventHandler/Payments/Payment.php index 6739cc1a2..eae28ee10 100644 --- a/src/EventHandler/Payments/Payment.php +++ b/src/EventHandler/Payments/Payment.php @@ -19,7 +19,9 @@ namespace danog\MadelineProto\EventHandler\Payments; use danog\MadelineProto\EventHandler\Update; use danog\MadelineProto\MTProto; -/** This object contains information about an incoming pre-checkout query. */ +/** + * This object contains information about an incoming pre-checkout query. + */ class Payment extends Update { /** Unique query identifier */ @@ -73,7 +75,6 @@ class Payment extends Update * Reject pending payment. * note that you must call this function or accept function up to 10 seconds after user accept payment!!. * @param string $errorMessage if the success isn’t set. Error message in human-readable form that explains the reason for failure to proceed with the checkout - * */ public function reject(string $errorMessage): false { From 83c36563f45495c2d32c3db58e365d29b41610fa Mon Sep 17 00:00:00 2001 From: Mahdi Date: Tue, 19 Nov 2024 14:12:29 +0330 Subject: [PATCH 4/4] fix little bug --- src/EventHandler/Payments/Payment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EventHandler/Payments/Payment.php b/src/EventHandler/Payments/Payment.php index eae28ee10..fa06be852 100644 --- a/src/EventHandler/Payments/Payment.php +++ b/src/EventHandler/Payments/Payment.php @@ -51,7 +51,7 @@ class Payment extends Update $rawRequestedPayment['email'], ) : null; $this->shippingOptionId = $rawRequestedPayment['shipping_option_id'] ?? null; - $this->currency = $rawRequestedPayment['$currency']; + $this->currency = $rawRequestedPayment['currency']; $this->totalAmount = $rawRequestedPayment['total_amount']; }