diff --git a/src/EventHandler/Message/Entities/TextWithEntities.php b/src/EventHandler/Message/Entities/TextWithEntities.php new file mode 100644 index 000000000..a5f6634f2 --- /dev/null +++ b/src/EventHandler/Message/Entities/TextWithEntities.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 + */ + +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; + } +} 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..6739cc1a2 --- /dev/null +++ b/src/EventHandler/Payments/Payment.php @@ -0,0 +1,89 @@ +. + * + * @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!!. + * @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 + { + return $this->getClient()->methodCallAsyncRead( + 'messages.setBotPrecheckoutResults', + [ + 'success' => false, + 'query_id' => $this->queryId, + 'error' => $errorMessage, + ] + ); + } +} diff --git a/src/EventHandler/Payments/PaymentRequestedInfo.php b/src/EventHandler/Payments/PaymentRequestedInfo.php new file mode 100644 index 000000000..160a015f3 --- /dev/null +++ b/src/EventHandler/Payments/PaymentRequestedInfo.php @@ -0,0 +1,30 @@ + static::class]; + $refl = new ReflectionClass($this); + foreach ($refl->getProperties(ReflectionProperty::IS_PUBLIC) as $prop) { + $res[$prop->getName()] = $prop->getValue($this); + } + return $res; + } +} diff --git a/src/EventHandler/Payments/StarGift.php b/src/EventHandler/Payments/StarGift.php new file mode 100644 index 000000000..b00ce25db --- /dev/null +++ b/src/EventHandler/Payments/StarGift.php @@ -0,0 +1,61 @@ +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..3bc47fa3f 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..1391abf18 100644 --- a/src/ParseMode.php +++ b/src/ParseMode.php @@ -24,4 +24,14 @@ 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; + } }