mirror of
https://github.com/TeamPGM/pyrogram.git
synced 2024-11-16 04:35:24 +00:00
Add support for clicking web app and user profile buttons
Co-authored-by: Shrimadhav U K <SpEcHiDe@users.noreply.github.com>
This commit is contained in:
parent
5e543d3afc
commit
60334bebeb
@ -199,6 +199,10 @@ class Client(Methods):
|
|||||||
Pass an instance of your own implementation of session storage engine.
|
Pass an instance of your own implementation of session storage engine.
|
||||||
Useful when you want to store your session in databases like Mongo, Redis, etc.
|
Useful when you want to store your session in databases like Mongo, Redis, etc.
|
||||||
|
|
||||||
|
client_platform (:obj:`~pyrogram.enums.ClientPlatform`, *optional*):
|
||||||
|
The platform where this client is running.
|
||||||
|
Defaults to 'other'
|
||||||
|
|
||||||
init_connection_params (:obj:`~pyrogram.raw.base.JSONValue`, *optional*):
|
init_connection_params (:obj:`~pyrogram.raw.base.JSONValue`, *optional*):
|
||||||
Additional initConnection parameters.
|
Additional initConnection parameters.
|
||||||
For now, only the tz_offset field is supported, for specifying timezone offset in seconds.
|
For now, only the tz_offset field is supported, for specifying timezone offset in seconds.
|
||||||
@ -230,36 +234,37 @@ class Client(Methods):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
api_id: Union[int, str] = None,
|
api_id: Optional[Union[int, str]] = None,
|
||||||
api_hash: str = None,
|
api_hash: Optional[str] = None,
|
||||||
app_version: str = APP_VERSION,
|
app_version: str = APP_VERSION,
|
||||||
device_model: str = DEVICE_MODEL,
|
device_model: str = DEVICE_MODEL,
|
||||||
system_version: str = SYSTEM_VERSION,
|
system_version: str = SYSTEM_VERSION,
|
||||||
lang_pack: str = LANG_PACK,
|
lang_pack: str = LANG_PACK,
|
||||||
lang_code: str = LANG_CODE,
|
lang_code: str = LANG_CODE,
|
||||||
system_lang_code: str = SYSTEM_LANG_CODE,
|
system_lang_code: str = SYSTEM_LANG_CODE,
|
||||||
ipv6: bool = False,
|
ipv6: Optional[bool] = False,
|
||||||
proxy: dict = None,
|
proxy: Optional[dict] = None,
|
||||||
test_mode: bool = False,
|
test_mode: Optional[bool] = False,
|
||||||
bot_token: str = None,
|
bot_token: Optional[str] = None,
|
||||||
session_string: str = None,
|
session_string: Optional[str] = None,
|
||||||
in_memory: bool = None,
|
in_memory: Optional[bool] = None,
|
||||||
phone_number: str = None,
|
phone_number: Optional[str] = None,
|
||||||
phone_code: str = None,
|
phone_code: Optional[str] = None,
|
||||||
password: str = None,
|
password: Optional[str] = None,
|
||||||
workers: int = WORKERS,
|
workers: int = WORKERS,
|
||||||
workdir: str = WORKDIR,
|
workdir: Union[str, Path] = WORKDIR,
|
||||||
plugins: dict = None,
|
plugins: Optional[dict] = None,
|
||||||
parse_mode: "enums.ParseMode" = enums.ParseMode.DEFAULT,
|
parse_mode: "enums.ParseMode" = enums.ParseMode.DEFAULT,
|
||||||
no_updates: bool = None,
|
no_updates: Optional[bool] = None,
|
||||||
skip_updates: bool = True,
|
skip_updates: Optional[bool] = True,
|
||||||
takeout: bool = None,
|
takeout: Optional[bool] = None,
|
||||||
sleep_threshold: int = Session.SLEEP_THRESHOLD,
|
sleep_threshold: int = Session.SLEEP_THRESHOLD,
|
||||||
hide_password: bool = False,
|
hide_password: Optional[bool] = False,
|
||||||
max_concurrent_transmissions: int = MAX_CONCURRENT_TRANSMISSIONS,
|
max_concurrent_transmissions: int = MAX_CONCURRENT_TRANSMISSIONS,
|
||||||
max_message_cache_size: int = MAX_MESSAGE_CACHE_SIZE,
|
max_message_cache_size: int = MAX_MESSAGE_CACHE_SIZE,
|
||||||
storage_engine: Storage = None,
|
storage_engine: Optional[Storage] = None,
|
||||||
init_connection_params: "raw.base.JSONValue" = None
|
client_platform: "enums.ClientPlatform" = enums.ClientPlatform.OTHER,
|
||||||
|
init_connection_params: Optional["raw.base.JSONValue"] = None
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@ -292,6 +297,7 @@ class Client(Methods):
|
|||||||
self.hide_password = hide_password
|
self.hide_password = hide_password
|
||||||
self.max_concurrent_transmissions = max_concurrent_transmissions
|
self.max_concurrent_transmissions = max_concurrent_transmissions
|
||||||
self.max_message_cache_size = max_message_cache_size
|
self.max_message_cache_size = max_message_cache_size
|
||||||
|
self.client_platform = client_platform
|
||||||
self.init_connection_params = init_connection_params
|
self.init_connection_params = init_connection_params
|
||||||
|
|
||||||
self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler")
|
self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler")
|
||||||
|
@ -22,6 +22,7 @@ from .chat_event_action import ChatEventAction
|
|||||||
from .chat_member_status import ChatMemberStatus
|
from .chat_member_status import ChatMemberStatus
|
||||||
from .chat_members_filter import ChatMembersFilter
|
from .chat_members_filter import ChatMembersFilter
|
||||||
from .chat_type import ChatType
|
from .chat_type import ChatType
|
||||||
|
from .client_platform import ClientPlatform
|
||||||
from .folder_color import FolderColor
|
from .folder_color import FolderColor
|
||||||
from .message_entity_type import MessageEntityType
|
from .message_entity_type import MessageEntityType
|
||||||
from .message_media_type import MessageMediaType
|
from .message_media_type import MessageMediaType
|
||||||
@ -43,6 +44,7 @@ __all__ = [
|
|||||||
'ChatMemberStatus',
|
'ChatMemberStatus',
|
||||||
'ChatMembersFilter',
|
'ChatMembersFilter',
|
||||||
'ChatType',
|
'ChatType',
|
||||||
|
'ClientPlatform',
|
||||||
'FolderColor',
|
'FolderColor',
|
||||||
'MessageEntityType',
|
'MessageEntityType',
|
||||||
'MessageMediaType',
|
'MessageMediaType',
|
||||||
|
49
pyrogram/enums/client_platform.py
Normal file
49
pyrogram/enums/client_platform.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
from .auto_name import AutoName
|
||||||
|
|
||||||
|
|
||||||
|
class ClientPlatform(AutoName):
|
||||||
|
"""Valid platforms for a :obj:`~pyrogram.Client`."""
|
||||||
|
|
||||||
|
ANDROID = auto()
|
||||||
|
"Android"
|
||||||
|
|
||||||
|
IOS = auto()
|
||||||
|
"iOS"
|
||||||
|
|
||||||
|
WP = auto()
|
||||||
|
"Windows Phone"
|
||||||
|
|
||||||
|
BB = auto()
|
||||||
|
"Blackberry"
|
||||||
|
|
||||||
|
DESKTOP = auto()
|
||||||
|
"Desktop"
|
||||||
|
|
||||||
|
WEB = auto()
|
||||||
|
"Web"
|
||||||
|
|
||||||
|
UBP = auto()
|
||||||
|
"Ubuntu Phone"
|
||||||
|
|
||||||
|
OTHER = auto()
|
||||||
|
"Other"
|
@ -16,10 +16,10 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union, Optional
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw, utils
|
||||||
|
|
||||||
|
|
||||||
class RequestCallbackAnswer:
|
class RequestCallbackAnswer:
|
||||||
@ -28,6 +28,7 @@ class RequestCallbackAnswer:
|
|||||||
chat_id: Union[int, str],
|
chat_id: Union[int, str],
|
||||||
message_id: int,
|
message_id: int,
|
||||||
callback_data: Union[str, bytes],
|
callback_data: Union[str, bytes],
|
||||||
|
password: Optional[str] = None,
|
||||||
timeout: int = 10
|
timeout: int = 10
|
||||||
):
|
):
|
||||||
"""Request a callback answer from bots.
|
"""Request a callback answer from bots.
|
||||||
@ -47,6 +48,10 @@ class RequestCallbackAnswer:
|
|||||||
callback_data (``str`` | ``bytes``):
|
callback_data (``str`` | ``bytes``):
|
||||||
Callback data associated with the inline button you want to get the answer from.
|
Callback data associated with the inline button you want to get the answer from.
|
||||||
|
|
||||||
|
password (``str``, *optional*):
|
||||||
|
When clicking certain buttons (such as BotFather's confirmation button to transfer ownership), if your account has 2FA enabled, you need to provide your account's password.
|
||||||
|
The 2-step verification password for the current user. Only applicable, if the :obj:`~pyrogram.types.InlineKeyboardButton` contains ``callback_data_with_password``.
|
||||||
|
|
||||||
timeout (``int``, *optional*):
|
timeout (``int``, *optional*):
|
||||||
Timeout in seconds.
|
Timeout in seconds.
|
||||||
|
|
||||||
@ -56,6 +61,8 @@ class RequestCallbackAnswer:
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
TimeoutError: In case the bot fails to answer within 10 seconds.
|
TimeoutError: In case the bot fails to answer within 10 seconds.
|
||||||
|
ValueError: In case of invalid arguments.
|
||||||
|
RPCError: In case of Telegram RPC error.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@ -66,11 +73,18 @@ class RequestCallbackAnswer:
|
|||||||
# Telegram only wants bytes, but we are allowed to pass strings too.
|
# Telegram only wants bytes, but we are allowed to pass strings too.
|
||||||
data = bytes(callback_data, "utf-8") if isinstance(callback_data, str) else callback_data
|
data = bytes(callback_data, "utf-8") if isinstance(callback_data, str) else callback_data
|
||||||
|
|
||||||
|
if password:
|
||||||
|
r = await self.invoke(
|
||||||
|
raw.functions.account.GetPassword()
|
||||||
|
)
|
||||||
|
password = utils.compute_password_check(r, password)
|
||||||
|
|
||||||
return await self.invoke(
|
return await self.invoke(
|
||||||
raw.functions.messages.GetBotCallbackAnswer(
|
raw.functions.messages.GetBotCallbackAnswer(
|
||||||
peer=await self.resolve_peer(chat_id),
|
peer=await self.resolve_peer(chat_id),
|
||||||
msg_id=message_id,
|
msg_id=message_id,
|
||||||
data=data
|
data=data,
|
||||||
|
password=password
|
||||||
),
|
),
|
||||||
retries=0,
|
retries=0,
|
||||||
timeout=timeout
|
timeout=timeout
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union, Optional
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
@ -69,19 +69,23 @@ class InlineKeyboardButton(Object):
|
|||||||
callback_game (:obj:`~pyrogram.types.CallbackGame`, *optional*):
|
callback_game (:obj:`~pyrogram.types.CallbackGame`, *optional*):
|
||||||
Description of the game that will be launched when the user presses the button.
|
Description of the game that will be launched when the user presses the button.
|
||||||
**NOTE**: This type of button **must** always be the first button in the first row.
|
**NOTE**: This type of button **must** always be the first button in the first row.
|
||||||
|
|
||||||
|
callback_data_with_password (``bytes``, *optional*):
|
||||||
|
A button that asks for the 2-step verification password of the current user and then sends a callback query to a bot Data to be sent to the bot via a callback query.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text: str,
|
text: str,
|
||||||
callback_data: Union[str, bytes] = None,
|
callback_data: Optional[Union[str, bytes]] = None,
|
||||||
url: str = None,
|
url: Optional[str] = None,
|
||||||
web_app: "types.WebAppInfo" = None,
|
web_app: Optional["types.WebAppInfo"] = None,
|
||||||
login_url: "types.LoginUrl" = None,
|
login_url: Optional["types.LoginUrl"] = None,
|
||||||
user_id: int = None,
|
user_id: Optional[int] = None,
|
||||||
switch_inline_query: str = None,
|
switch_inline_query: Optional[str] = None,
|
||||||
switch_inline_query_current_chat: str = None,
|
switch_inline_query_current_chat: Optional[str] = None,
|
||||||
callback_game: "types.CallbackGame" = None
|
callback_game: Optional["types.CallbackGame"] = None,
|
||||||
|
requires_password: Optional[bool] = None
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@ -94,6 +98,7 @@ class InlineKeyboardButton(Object):
|
|||||||
self.switch_inline_query = switch_inline_query
|
self.switch_inline_query = switch_inline_query
|
||||||
self.switch_inline_query_current_chat = switch_inline_query_current_chat
|
self.switch_inline_query_current_chat = switch_inline_query_current_chat
|
||||||
self.callback_game = callback_game
|
self.callback_game = callback_game
|
||||||
|
self.requires_password = requires_password
|
||||||
# self.pay = pay
|
# self.pay = pay
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -108,7 +113,8 @@ class InlineKeyboardButton(Object):
|
|||||||
|
|
||||||
return InlineKeyboardButton(
|
return InlineKeyboardButton(
|
||||||
text=b.text,
|
text=b.text,
|
||||||
callback_data=data
|
callback_data=data,
|
||||||
|
requires_password=getattr(b, "requires_password", None)
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(b, raw.types.KeyboardButtonUrl):
|
if isinstance(b, raw.types.KeyboardButtonUrl):
|
||||||
@ -162,7 +168,8 @@ class InlineKeyboardButton(Object):
|
|||||||
|
|
||||||
return raw.types.KeyboardButtonCallback(
|
return raw.types.KeyboardButtonCallback(
|
||||||
text=self.text,
|
text=self.text,
|
||||||
data=data
|
data=data,
|
||||||
|
requires_password=self.requires_password
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.url is not None:
|
if self.url is not None:
|
||||||
|
@ -4294,7 +4294,15 @@ class Message(Object, Update):
|
|||||||
revoke=revoke
|
revoke=revoke
|
||||||
)
|
)
|
||||||
|
|
||||||
async def click(self, x: Union[int, str] = 0, y: int = None, quote: bool = None, timeout: int = 10):
|
async def click(
|
||||||
|
self,
|
||||||
|
x: Union[int, str] = 0,
|
||||||
|
y: int = None,
|
||||||
|
quote: bool = None,
|
||||||
|
timeout: int = 10,
|
||||||
|
request_write_access: bool = True,
|
||||||
|
password: str = None
|
||||||
|
):
|
||||||
"""Bound method *click* of :obj:`~pyrogram.types.Message`.
|
"""Bound method *click* of :obj:`~pyrogram.types.Message`.
|
||||||
|
|
||||||
Use as a shortcut for clicking a button attached to the message instead of:
|
Use as a shortcut for clicking a button attached to the message instead of:
|
||||||
@ -4346,11 +4354,22 @@ class Message(Object, Update):
|
|||||||
timeout (``int``, *optional*):
|
timeout (``int``, *optional*):
|
||||||
Timeout in seconds.
|
Timeout in seconds.
|
||||||
|
|
||||||
|
request_write_access (``bool``, *optional*):
|
||||||
|
Only used in case of :obj:`~pyrogram.types.LoginUrl` button.
|
||||||
|
True, if the bot can send messages to the user.
|
||||||
|
Defaults to ``True``.
|
||||||
|
|
||||||
|
password (``str``, *optional*):
|
||||||
|
When clicking certain buttons (such as BotFather's confirmation button to transfer ownership), if your account has 2FA enabled, you need to provide your account's password.
|
||||||
|
The 2-step verification password for the current user. Only applicable, if the :obj:`~pyrogram.types.InlineKeyboardButton` contains ``requires_password``.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- The result of :meth:`~pyrogram.Client.request_callback_answer` in case of inline callback button clicks.
|
- The result of :meth:`~pyrogram.Client.request_callback_answer` in case of inline callback button clicks.
|
||||||
- The result of :meth:`~Message.reply()` in case of normal button clicks.
|
- The result of :meth:`~Message.reply()` in case of normal button clicks.
|
||||||
- A string in case the inline button is a URL, a *switch_inline_query* or a
|
- A string in case the inline button is a URL, a *switch_inline_query* or a
|
||||||
*switch_inline_query_current_chat* button.
|
*switch_inline_query_current_chat* button.
|
||||||
|
- A string URL with the user details, in case of a WebApp button.
|
||||||
|
- A :obj:`~pyrogram.types.Chat` object in case of a ``KeyboardButtonUserProfile`` button.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
RPCError: In case of a Telegram RPC error.
|
RPCError: In case of a Telegram RPC error.
|
||||||
@ -4404,8 +4423,53 @@ class Message(Object, Update):
|
|||||||
callback_data=button.callback_data,
|
callback_data=button.callback_data,
|
||||||
timeout=timeout
|
timeout=timeout
|
||||||
)
|
)
|
||||||
|
elif button.requires_password:
|
||||||
|
if password is None:
|
||||||
|
raise ValueError(
|
||||||
|
"This button requires a password"
|
||||||
|
)
|
||||||
|
|
||||||
|
return await self._client.request_callback_answer(
|
||||||
|
chat_id=self.chat.id,
|
||||||
|
message_id=self.id,
|
||||||
|
callback_data=button.callback_data,
|
||||||
|
password=password,
|
||||||
|
timeout=timeout
|
||||||
|
)
|
||||||
elif button.url:
|
elif button.url:
|
||||||
return button.url
|
return button.url
|
||||||
|
elif button.web_app:
|
||||||
|
web_app = button.web_app
|
||||||
|
|
||||||
|
bot_peer_id = (
|
||||||
|
self.via_bot and
|
||||||
|
self.via_bot.id
|
||||||
|
) or (
|
||||||
|
self.from_user and
|
||||||
|
self.from_user.is_bot and
|
||||||
|
self.from_user.id
|
||||||
|
) or None
|
||||||
|
|
||||||
|
if not bot_peer_id:
|
||||||
|
raise ValueError(
|
||||||
|
"This button requires a bot as the sender"
|
||||||
|
)
|
||||||
|
|
||||||
|
r = await self._client.invoke(
|
||||||
|
raw.functions.messages.RequestWebView(
|
||||||
|
peer=await self._client.resolve_peer(self.chat.id),
|
||||||
|
bot=await self._client.resolve_peer(bot_peer_id),
|
||||||
|
url=web_app.url,
|
||||||
|
platform=self._client.client_platform.value,
|
||||||
|
# TODO
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return r.url
|
||||||
|
elif button.user_id:
|
||||||
|
return await self._client.get_chat(
|
||||||
|
button.user_id,
|
||||||
|
force_full=False
|
||||||
|
)
|
||||||
elif button.switch_inline_query:
|
elif button.switch_inline_query:
|
||||||
return button.switch_inline_query
|
return button.switch_inline_query
|
||||||
elif button.switch_inline_query_current_chat:
|
elif button.switch_inline_query_current_chat:
|
||||||
@ -4413,7 +4477,7 @@ class Message(Object, Update):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("This button is not supported yet")
|
raise ValueError("This button is not supported yet")
|
||||||
else:
|
else:
|
||||||
await self.reply(button, quote=quote)
|
await self.reply(text=button, quote=quote)
|
||||||
|
|
||||||
async def react(self, emoji: Union[int, str, List[Union[int, str]]] = None, big: bool = False) -> bool:
|
async def react(self, emoji: Union[int, str, List[Union[int, str]]] = None, big: bool = False) -> bool:
|
||||||
"""Bound method *react* of :obj:`~pyrogram.types.Message`.
|
"""Bound method *react* of :obj:`~pyrogram.types.Message`.
|
||||||
|
Loading…
Reference in New Issue
Block a user