Compare commits

..
10 Commits
Author SHA1 Message Date
Davte 53802728a1 Compliance with bot API 7.9
Implemented a system to get administration privileges if running the bot in absence of administrators (the token is provided through the command line).

(cherry picked from commit db240ce199)
2024-08-17 21:12:47 +02:00
Davte 2cdb4e743f Get package version from metadata when package has no __version__ attribute 2024-08-04 18:49:16 +02:00
Davte 98fbbf0127 Compliance with bot API 7.8 2024-08-04 18:30:21 +02:00
Davte 856d53de1c Compliance with bot API 7.7
(cherry picked from commit fd4374f328)
2024-07-07 14:37:21 +02:00
Davte 5e8a2b65f5 Compliance with bot API 7.2
- Included python version in `/version` command
- Added the parameter `business_connection_id` to the methods sendMessage, sendPhoto, sendVideo, sendAnimation, sendAudio, sendDocument, sendSticker, sendVideoNote, sendVoice, sendLocation, sendVenue, sendContact, sendPoll, sendDice, sendGame, and sendMediaGroup, sendChatAction.
- Moved the parameter `format` to Sticker instead of StickerSet (and related methods)

(cherry picked from commit 6b489363de)
2024-04-13 11:17:11 +02:00
Davte 3b0bfb4880 Compliance with bot API 7.1
- Added the class ReplyParameters and replaced parameters reply_to_message_id and allow_sending_without_reply in the methods copyMessage, sendMessage, sendPhoto, sendVideo, sendAnimation, sendAudio, sendDocument, sendSticker, sendVideoNote, sendVoice, sendLocation, sendVenue, sendContact, sendPoll, sendDice, sendInvoice, sendGame, and sendMediaGroup with the field reply_parameters of type ReplyParameters.
- Added the class LinkPreviewOptions and replaced the parameter disable_web_page_preview with link_preview_options in the methods sendMessage and editMessageText.

(cherry picked from commit a343e095e8)
2024-04-13 11:17:07 +02:00
Davte a49e727e31 Allow to overwrite file when using bot.download_file method
(cherry picked from commit a3b28bc1d6)
2024-04-13 11:17:04 +02:00
Davte c78522d46b download_file behaves differently if a local bot API server is used. Wrong default API url was being used
(cherry picked from commit 3969794075)
2024-04-13 11:17:00 +02:00
Davte c4964105b4 Support Local Bot API Server (with custom api_url).
(cherry picked from commit 748ba624a4)
2024-02-17 14:47:28 +01:00
Davte 3396bc6f18 download_file method updated to handle exceptions and return information about downloaded file
(cherry picked from commit 41507067be)
2024-02-14 19:31:20 +01:00
5 changed files with 848 additions and 235 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ __author__ = "Davide Testa"
__email__ = "davide@davte.it"
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
__license__ = "GNU General Public License v3.0"
__version__ = "2.9.8"
__version__ = "2.10.6"
__maintainer__ = "Davide Testa"
__contact__ = "t.me/davte"
+141 -79
View File
@@ -13,10 +13,12 @@ import asyncio
import datetime
import json
import logging
import platform
import re
import types
from collections import OrderedDict
from importlib.metadata import version as get_package_version_from_metadata
from typing import Union, List, Tuple
# Third party modules
@@ -27,8 +29,8 @@ from davtelepot.messages import default_admin_messages, default_talk_messages
from davtelepot.bot import Bot
from davtelepot.utilities import (
async_wrapper, CachedPage, Confirmator, extract, get_cleaned_text,
get_user, clean_html_string, line_drawing_unordered_list, make_button,
make_inline_keyboard, remove_html_tags, send_part_of_text_file,
get_secure_key, get_user, clean_html_string, line_drawing_unordered_list,
make_button, make_inline_keyboard, remove_html_tags, send_part_of_text_file,
send_csv_file, make_lines_of_buttons, join_path
)
@@ -43,6 +45,13 @@ variable_regex = re.compile(r"(?P<name>[a-zA-Z]\w*)\s*=\s*"
r"\"[^\"]*\")")
def get_package_version(package: types.ModuleType):
"""Get version of given package."""
if hasattr(package, '__version__'):
return package.__version__
return get_package_version_from_metadata(package.__name__)
async def _forward_to(update,
bot: Bot,
sender,
@@ -223,9 +232,9 @@ def get_talk_panel(bot: Bot,
return text, reply_markup
async def _talk_command(bot: Bot,
update,
user_record):
async def talk_command(bot: Bot,
update,
user_record):
text = get_cleaned_text(
update,
bot,
@@ -343,17 +352,17 @@ async def end_session(bot: Bot,
return
async def _talk_button(bot: Bot,
update,
user_record,
data):
async def talk_button(bot: Bot,
update,
user_record,
data):
telegram_id = user_record['telegram_id']
command, *arguments = data
result, text, reply_markup = '', '', None
if command == 'search':
bot.set_individual_text_message_handler(
await async_wrapper(
_talk_command,
talk_command,
),
update
)
@@ -426,7 +435,7 @@ async def _talk_button(bot: Bot,
return result
async def _restart_command(bot: Bot,
async def restart_command(bot: Bot,
update,
user_record):
with bot.db as db:
@@ -453,7 +462,7 @@ async def _restart_command(bot: Bot,
return
async def _stop_command(bot: Bot,
async def stop_command(bot: Bot,
update,
user_record):
text = bot.get_message(
@@ -495,10 +504,10 @@ async def stop_bots(bot: Bot):
return
async def _stop_button(bot: Bot,
update,
user_record,
data: List[Union[int, str]]):
async def stop_button(bot: Bot,
update,
user_record,
data: List[Union[int, str]]):
result, text, reply_markup = '', '', None
telegram_id = user_record['telegram_id']
command = data[0] if len(data) > 0 else 'None'
@@ -535,7 +544,7 @@ async def _stop_button(bot: Bot,
return result
async def _send_bot_database(bot: Bot, user_record: OrderedDict, language: str):
async def send_bot_database(bot: Bot, user_record: OrderedDict, language: str):
if not all(
[
bot.db_url.endswith('.db'),
@@ -562,7 +571,7 @@ async def _send_bot_database(bot: Bot, user_record: OrderedDict, language: str):
)
async def _query_command(bot, update, user_record):
async def query_command(bot, update, user_record):
query = get_cleaned_text(
update,
bot,
@@ -640,7 +649,7 @@ async def _query_command(bot, update, user_record):
)
async def _query_button(bot, update, user_record, data):
async def query_button(bot, update, user_record, data):
result, text, reply_markup = '', '', None
command = data[0] if len(data) else 'default'
error_message = bot.get_message(
@@ -677,7 +686,7 @@ async def _query_button(bot, update, user_record, data):
return result
async def _log_command(bot, update, user_record):
async def log_command(bot, update, user_record):
if bot.log_file_path is None:
return bot.get_message(
'admin', 'log_command', 'no_log',
@@ -730,7 +739,7 @@ async def _log_command(bot, update, user_record):
return
async def _errors_command(bot, update, user_record):
async def errors_command(bot, update, user_record):
# Always send errors log file in private chat
chat_id = update['from']['id']
if bot.errors_file_path is None:
@@ -774,7 +783,7 @@ async def _errors_command(bot, update, user_record):
return
async def _maintenance_command(bot, update, user_record):
async def maintenance_command(bot, update, user_record):
maintenance_message = get_cleaned_text(update, bot, ['maintenance'])
if maintenance_message.startswith('{'):
maintenance_message = json.loads(maintenance_message)
@@ -864,7 +873,12 @@ async def get_new_versions(bot: Bot,
"skipping...")
continue
new_version = web_page['info']['version']
current_version = package.__version__
try:
current_version = get_package_version(package)
except TypeError:
current_version = "NA"
logging.error("Could not get current version of "
"package %s", package.__name__)
notification_record = bot.db['updates_notifications'].find_one(
package=package.__name__,
order_by=['-id'],
@@ -883,17 +897,18 @@ async def get_new_versions(bot: Bot,
return news
async def _version_command(bot: Bot, update: dict,
user_record: OrderedDict, language: str):
async def version_command(bot: Bot, update: dict,
user_record: OrderedDict, language: str):
last_commit = await get_last_commit()
text = bot.get_message(
'admin', 'version_command', 'header',
last_commit=last_commit,
update=update, user_record=user_record
) + '\n\n'
text += f'<b>Python: </b> <code>{platform.python_version()}</code>\n'
text += '\n'.join(
f"<b>{package.__name__}</b>: "
f"<code>{package.__version__}</code>"
f"<code>{get_package_version(package)}</code>"
for package in bot.packages
)
temporary_message = await bot.send_message(
@@ -937,7 +952,7 @@ async def notify_new_version(bot: Bot):
order_by=['-id']
)
current_versions = {
f"{package.__name__}_version": package.__version__
f"{package.__name__}_version": get_package_version(package)
for package in bot.packages
}
current_versions['last_commit'] = last_commit
@@ -1032,7 +1047,7 @@ async def get_package_updates(bot: Bot,
await asyncio.sleep(monitoring_interval)
async def _send_start_messages(bot: Bot):
async def send_start_messages(bot: Bot):
"""Send restart messages at restart."""
for restart_message in bot.db['restart_messages'].find(sent=None):
asyncio.ensure_future(
@@ -1060,7 +1075,7 @@ async def _send_start_messages(bot: Bot):
return
async def _load_talking_sessions(bot: Bot):
async def load_talking_sessions(bot: Bot):
sessions = []
for session in bot.db.query(
"""SELECT *
@@ -1139,7 +1154,7 @@ def get_custom_commands(bot: Bot, language: str = None) -> List[dict]:
)
async def _father_command(bot, language):
async def father_command(bot, language):
modes = [
{
key: (
@@ -1443,12 +1458,12 @@ async def edit_bot_father_settings_via_message(bot: Bot,
return result, text, reply_markup
async def _father_button(bot: Bot, user_record: OrderedDict,
async def father_button(bot: Bot, user_record: OrderedDict,
language: str, data: list):
"""Handle BotFather button.
Operational modes
- main: back to main page (see _father_command)
- main: back to main page (see `father_command`)
- get: show commands stored by @BotFather
- set: edit commands stored by @BotFather
"""
@@ -1542,7 +1557,7 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
elif command == 'main':
return dict(
text='',
edit=(await _father_command(bot=bot, language=language))
edit=(await father_command(bot=bot, language=language))
)
elif command == 'set':
stored_commands = await bot.getMyCommands()
@@ -1810,8 +1825,8 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
return result
async def _config_command(bot: Bot, update: dict,
user_record: dict, language: str):
async def config_command(bot: Bot, update: dict,
user_record: dict, language: str):
text = get_cleaned_text(
update,
bot,
@@ -1844,6 +1859,50 @@ async def _config_command(bot: Bot, update: dict,
language=language)
async def become_administrator(bot: Bot, update: dict,
user_record: dict, language: str):
"""When the bot has no administrator, become one providing a token.
The token will be printed to the stdout on the machine running the bot.
"""
if len(bot.administrators) > 0:
return
def _get_message(*args):
return bot.get_message('admin', 'become_admin', *args,
update=update, user_record=user_record,
language=language)
token = get_cleaned_text(update=update, bot=bot,
replace=['become_administrator',
'00become_administrator'],
strip='/ @_')
if token != bot.administration_token:
return _get_message('wrong_token')
with bot.db as db:
db['users'].update({**user_record, 'privileges': 1},
['id'])
return _get_message('success')
async def create_promotion_command(bot: Bot):
"""If bot has no administrators, users can elevate themselves.
To do so, they need to provide a token, that will be printed to the stdout
of the machine running the bot.
"""
await bot.get_me()
bot.administration_token = get_secure_key(length=10)
print(f"To become administrator click "
f"https://t.me/{bot.name}?start="
f"00become_administrator_{bot.administration_token}")
@bot.command(command='become_administrator',
authorization_level='everybody',
aliases=['00become_administrator'])
async def _become_administrator(bot, update, user_record, language):
return await become_administrator(bot=bot, update=update,
user_record=user_record,
language=language)
def init(telegram_bot: Bot,
talk_messages: dict = None,
admin_messages: dict = None,
@@ -1907,16 +1966,16 @@ def init(telegram_bot: Bot,
# Tasks to complete before starting bot
@telegram_bot.additional_task(when='BEFORE')
async def load_talking_sessions():
return await _load_talking_sessions(bot=telegram_bot)
async def _load_talking_sessions():
return await load_talking_sessions(bot=telegram_bot)
@telegram_bot.additional_task(when='BEFORE', bot=telegram_bot)
async def notify_version(bot):
return await notify_new_version(bot=bot)
@telegram_bot.additional_task('BEFORE')
async def send_restart_messages():
return await _send_start_messages(bot=telegram_bot)
async def _send_start_messages():
return await send_start_messages(bot=telegram_bot)
# Administration commands
@telegram_bot.command(command='/db',
@@ -1925,10 +1984,10 @@ def init(telegram_bot: Bot,
description=admin_messages[
'db_command']['description'],
authorization_level='admin')
async def send_bot_database(bot, user_record, language):
return await _send_bot_database(bot=bot,
user_record=user_record,
language=language)
async def _send_bot_database(bot, user_record, language):
return await send_bot_database(bot=bot,
user_record=user_record,
language=language)
@telegram_bot.command(command='/errors',
aliases=[],
@@ -1936,8 +1995,8 @@ def init(telegram_bot: Bot,
description=admin_messages[
'errors_command']['description'],
authorization_level='admin')
async def errors_command(bot, update, user_record):
return await _errors_command(bot, update, user_record)
async def _errors_command(bot, update, user_record):
return await errors_command(bot, update, user_record)
@telegram_bot.command(command='/father',
aliases=[],
@@ -1948,14 +2007,14 @@ def init(telegram_bot: Bot,
if key in ('description', )
},
authorization_level='admin')
async def father_command(bot, language):
return await _father_command(bot=bot, language=language)
async def _father_command(bot, language):
return await father_command(bot=bot, language=language)
@telegram_bot.button(prefix='father:///',
separator='|',
authorization_level='admin')
async def query_button(bot, user_record, language, data):
return await _father_button(bot=bot,
async def _father_button(bot, user_record, language, data):
return await father_button(bot=bot,
user_record=user_record,
language=language,
data=data)
@@ -1966,16 +2025,16 @@ def init(telegram_bot: Bot,
description=admin_messages[
'log_command']['description'],
authorization_level='admin')
async def log_command(bot, update, user_record):
return await _log_command(bot, update, user_record)
async def _log_command(bot, update, user_record):
return await log_command(bot, update, user_record)
@telegram_bot.command(command='/maintenance', aliases=[],
show_in_keyboard=False,
description=admin_messages[
'maintenance_command']['description'],
authorization_level='admin')
async def maintenance_command(bot, update, user_record):
return await _maintenance_command(bot, update, user_record)
async def _maintenance_command(bot, update, user_record):
return await maintenance_command(bot, update, user_record)
@telegram_bot.command(command='/query',
aliases=[],
@@ -1983,16 +2042,16 @@ def init(telegram_bot: Bot,
description=admin_messages[
'query_command']['description'],
authorization_level='admin')
async def query_command(bot, update, user_record):
return await _query_command(bot, update, user_record)
async def _query_command(bot, update, user_record):
return await query_command(bot, update, user_record)
@telegram_bot.button(prefix='db_query:///',
separator='|',
description=admin_messages[
'query_command']['description'],
authorization_level='admin')
async def query_button(bot, update, user_record, data):
return await _query_button(bot, update, user_record, data)
async def _query_button(bot, update, user_record, data):
return await query_button(bot, update, user_record, data)
@telegram_bot.command(command='/restart',
aliases=[],
@@ -2000,8 +2059,8 @@ def init(telegram_bot: Bot,
description=admin_messages[
'restart_command']['description'],
authorization_level='admin')
async def restart_command(bot, update, user_record):
return await _restart_command(bot, update, user_record)
async def _restart_command(bot, update, user_record):
return await restart_command(bot, update, user_record)
@telegram_bot.command(command='/select',
aliases=[],
@@ -2009,8 +2068,8 @@ def init(telegram_bot: Bot,
description=admin_messages[
'select_command']['description'],
authorization_level='admin')
async def select_command(bot, update, user_record):
return await _query_command(bot, update, user_record)
async def _select_command(bot, update, user_record):
return await query_command(bot, update, user_record)
@telegram_bot.command(command='/stop',
aliases=[],
@@ -2018,16 +2077,16 @@ def init(telegram_bot: Bot,
description=admin_messages[
'stop_command']['description'],
authorization_level='admin')
async def stop_command(bot, update, user_record):
return await _stop_command(bot, update, user_record)
async def _stop_command(bot, update, user_record):
return await stop_command(bot, update, user_record)
@telegram_bot.button(prefix='stop:///',
separator='|',
description=admin_messages[
'stop_command']['description'],
authorization_level='admin')
async def stop_button(bot, update, user_record, data):
return await _stop_button(bot, update, user_record, data)
async def _stop_button(bot, update, user_record, data):
return await stop_button(bot, update, user_record, data)
@telegram_bot.command(command='/talk',
aliases=[],
@@ -2035,14 +2094,14 @@ def init(telegram_bot: Bot,
description=admin_messages[
'talk_command']['description'],
authorization_level='admin')
async def talk_command(bot, update, user_record):
return await _talk_command(bot, update, user_record)
async def _talk_command(bot, update, user_record):
return await talk_command(bot, update, user_record)
@telegram_bot.button(prefix='talk:///',
separator='|',
authorization_level='admin')
async def talk_button(bot, update, user_record, data):
return await _talk_button(bot, update, user_record, data)
async def _talk_button(bot, update, user_record, data):
return await talk_button(bot, update, user_record, data)
@telegram_bot.command(command='/version',
aliases=[],
@@ -2053,11 +2112,11 @@ def init(telegram_bot: Bot,
},
show_in_keyboard=False,
authorization_level='admin')
async def version_command(bot, update, user_record, language):
return await _version_command(bot=bot,
update=update,
user_record=user_record,
language=language)
async def _version_command(bot, update, user_record, language):
return await version_command(bot=bot,
update=update,
user_record=user_record,
language=language)
@telegram_bot.command(command='/config',
aliases=[],
@@ -2068,8 +2127,11 @@ def init(telegram_bot: Bot,
},
show_in_keyboard=False,
authorization_level='admin')
async def config_command(bot, update, user_record, language):
return await _config_command(bot=bot,
update=update,
user_record=user_record,
language=language)
async def _config_command(bot, update, user_record, language):
return await config_command(bot=bot,
update=update,
user_record=user_record,
language=language)
if len(telegram_bot.administrators) == 0:
asyncio.ensure_future(create_promotion_command(bot=telegram_bot))
+582 -80
View File
File diff suppressed because it is too large Load Diff
+114 -75
View File
@@ -2,34 +2,6 @@
camelCase methods mirror API directly, while snake_case ones act as middleware
someway.
Usage
```
import sys
from davtelepot.bot import Bot
from data.passwords import my_token, my_other_token
long_polling_bot = Bot(token=my_token, database_url='my_db')
webhook_bot = Bot(token=my_other_token, hostname='example.com',
certificate='path/to/certificate.pem',
database_url='my_other_db')
@long_polling_bot.command('/foo')
async def foo_command(bot, update, user_record, language):
return "Bar!"
@webhook_bot.command('/bar')
async def bar_command(bot, update, user_record, language):
return "Foo!"
exit_state = Bot.run(
local_host='127.0.0.5',
port=8552
)
sys.exit(exit_state)
```
"""
# Standard library modules
@@ -49,7 +21,9 @@ from typing import Callable, List, Union, Dict
import aiohttp.web
# Project modules
from davtelepot.api import TelegramBot, TelegramError
from davtelepot.api import (
LinkPreviewOptions, ReplyParameters, TelegramBot, TelegramError
)
from davtelepot.database import ObjectWithDatabase
from davtelepot.languages import MultiLanguageObject
from davtelepot.messages import davtelepot_messages
@@ -104,10 +78,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
_errors_file_path = None
_documents_max_dimension = 50 * 1000 * 1000 # 50 MB
def __init__(
self, token, hostname='', certificate=None, max_connections=40,
allowed_updates=None, database_url='bot.db'
):
def __init__(self,
token, hostname='', certificate=None,
max_connections=40, allowed_updates=None,
database_url='bot.db', api_url: str = None):
"""Init a bot instance.
token : str
@@ -125,7 +99,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
# Append `self` to class list of instances
self.__class__.bots.append(self)
# Call superclasses constructors with proper arguments
TelegramBot.__init__(self, token)
TelegramBot.__init__(self, token, api_url=api_url)
ObjectWithDatabase.__init__(self, database_url=database_url)
MultiLanguageObject.__init__(self)
self.messages['davtelepot'] = davtelepot_messages
@@ -1319,19 +1293,21 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
async def send_message(self, chat_id: Union[int, str] = None,
text: str = None,
message_thread_id: int = None,
entities: List[dict] = None,
parse_mode: str = 'HTML',
message_thread_id: int = None,
link_preview_options: LinkPreviewOptions = None,
disable_notification: bool = None,
protect_content: bool = None,
disable_web_page_preview: bool = None,
disable_notification: bool = None,
reply_to_message_id: int = None,
allow_sending_without_reply: bool = None,
reply_markup=None,
update: dict = None,
reply_to_update: bool = False,
send_default_keyboard: bool = True,
user_record: OrderedDict = None):
user_record: OrderedDict = None,
reply_parameters: ReplyParameters = None,
reply_markup=None):
"""Send text via message(s).
This method wraps lower-level `TelegramBot.sendMessage` method.
@@ -1352,6 +1328,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
user_record = self.db['users'].find_one(telegram_id=chat_id)
if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id']
if disable_web_page_preview:
if link_preview_options is None:
link_preview_options = LinkPreviewOptions()
link_preview_options['is_disabled'] = True
if (
send_default_keyboard
and reply_markup is None
@@ -1395,19 +1375,27 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
limit=self.__class__.TELEGRAM_MESSAGES_MAX_LEN - 100,
parse_mode=parse_mode
)
if reply_to_message_id:
if reply_parameters is None:
reply_parameters = ReplyParameters(message_id=reply_to_message_id)
reply_parameters['message_id'] = reply_to_message_id
if allow_sending_without_reply:
reply_parameters['allow_sending_without_reply'] = allow_sending_without_reply
if reply_to_update and 'chat' in update and 'id' in update['chat']:
if update['chat']['id'] != chat_id:
reply_parameters['chat_id'] = update['chat']['id']
for text_chunk, is_last in text_chunks:
_reply_markup = (reply_markup if is_last else None)
sent_message_update = await self.sendMessage(
chat_id=chat_id,
text=text_chunk,
message_thread_id=message_thread_id,
parse_mode=parse_mode,
entities=entities,
message_thread_id=message_thread_id,
protect_content=protect_content,
disable_web_page_preview=disable_web_page_preview,
link_preview_options=link_preview_options,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
reply_parameters=reply_parameters,
reply_markup=_reply_markup
)
return sent_message_update
@@ -1431,6 +1419,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
parse_mode: str = 'HTML',
entities: List[dict] = None,
disable_web_page_preview: bool = None,
link_preview_options: LinkPreviewOptions = None,
allow_sending_without_reply: bool = None,
reply_markup=None,
update: dict = None):
@@ -1463,6 +1452,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
)
):
if i == 0:
if disable_web_page_preview:
if link_preview_options is None:
link_preview_options = LinkPreviewOptions()
link_preview_options['is_disabled'] = True
edited_message = await self.editMessageText(
text=text_chunk,
chat_id=chat_id,
@@ -1470,7 +1463,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
inline_message_id=inline_message_id,
parse_mode=parse_mode,
entities=entities,
disable_web_page_preview=disable_web_page_preview,
link_preview_options=link_preview_options,
reply_markup=(reply_markup if is_last else None)
)
if chat_id is None:
@@ -1576,6 +1569,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
reply_markup=None,
update: dict = None,
reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True,
use_stored_file_id: bool = True):
"""Send photos.
@@ -1599,6 +1593,15 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
chat_id = self.get_chat_id(update)
if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id']
if reply_to_message_id:
if reply_parameters is None:
reply_parameters = ReplyParameters(message_id=reply_to_message_id)
reply_parameters['message_id'] = reply_to_message_id
if allow_sending_without_reply:
reply_parameters['allow_sending_without_reply'] = allow_sending_without_reply
if reply_to_update and 'chat' in update and 'id' in update['chat']:
if update['chat']['id'] != chat_id:
reply_parameters['chat_id'] = update['chat']['id']
if (
send_default_keyboard
and reply_markup is None
@@ -1652,8 +1655,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
parse_mode=parse_mode,
caption_entities=caption_entities,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_parameters=reply_parameters,
reply_markup=reply_markup
)
if isinstance(sent_update, Exception):
@@ -1701,6 +1703,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
reply_markup=None,
update: dict = None,
reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True,
use_stored_file_id: bool = True):
"""Send audio files.
@@ -1724,6 +1727,15 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
chat_id = self.get_chat_id(update)
if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id']
if reply_to_message_id:
if reply_parameters is None:
reply_parameters = ReplyParameters(message_id=reply_to_message_id)
reply_parameters['message_id'] = reply_to_message_id
if allow_sending_without_reply:
reply_parameters['allow_sending_without_reply'] = allow_sending_without_reply
if reply_to_update and 'chat' in update and 'id' in update['chat']:
if update['chat']['id'] != chat_id:
reply_parameters['chat_id'] = update['chat']['id']
if (
send_default_keyboard
and reply_markup is None
@@ -1781,8 +1793,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
title=title,
thumbnail=thumbnail,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_parameters=reply_parameters,
reply_markup=reply_markup
)
if isinstance(sent_update, Exception):
@@ -1826,6 +1837,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
reply_markup=None,
update: dict = None,
reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True,
use_stored_file_id: bool = True):
"""Send voice messages.
@@ -1849,6 +1861,15 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
chat_id = self.get_chat_id(update)
if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id']
if reply_to_message_id:
if reply_parameters is None:
reply_parameters = ReplyParameters(message_id=reply_to_message_id)
reply_parameters['message_id'] = reply_to_message_id
if allow_sending_without_reply:
reply_parameters['allow_sending_without_reply'] = allow_sending_without_reply
if reply_to_update and 'chat' in update and 'id' in update['chat']:
if update['chat']['id'] != chat_id:
reply_parameters['chat_id'] = update['chat']['id']
if (
send_default_keyboard
and reply_markup is None
@@ -1903,8 +1924,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
caption_entities=caption_entities,
duration=duration,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_parameters=reply_parameters,
reply_markup=reply_markup
)
if isinstance(sent_update, Exception):
@@ -1951,6 +1971,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
document_name: str = None,
update: dict = None,
reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True,
use_stored_file_id: bool = False):
"""Send a document.
@@ -1983,6 +2004,15 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
return
if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id']
if reply_to_message_id:
if reply_parameters is None:
reply_parameters = ReplyParameters(message_id=reply_to_message_id)
reply_parameters['message_id'] = reply_to_message_id
if allow_sending_without_reply:
reply_parameters['allow_sending_without_reply'] = allow_sending_without_reply
if reply_to_update and 'chat' in update and 'id' in update['chat']:
if update['chat']['id'] != chat_id:
reply_parameters['chat_id'] = update['chat']['id']
if chat_id > 0:
user_record = self.db['users'].find_one(telegram_id=chat_id)
language = self.get_language(update=update, user_record=user_record)
@@ -2061,7 +2091,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
caption=caption,
parse_mode=parse_mode,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
reply_parameters=reply_parameters,
reply_markup=reply_markup,
update=update,
reply_to_update=reply_to_update,
@@ -2092,8 +2122,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
caption_entities=caption_entities,
disable_content_type_detection=disable_content_type_detection,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_parameters=reply_parameters,
reply_markup=reply_markup
)
if isinstance(sent_update, Exception):
@@ -2127,7 +2156,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
return sent_update
async def download_file(self, file_id,
file_name=None, path=None):
file_name=None, path=None,
prevent_overwriting: bool = False):
"""Given a telegram `file_id`, download the related file.
Telegram may not preserve the original file name and MIME type: the
@@ -2137,26 +2167,35 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
file = await self.getFile(file_id=file_id)
if file is None or isinstance(file, Exception):
logging.error(f"{file}")
return
file_bytes = await async_get(
url=(
f"https://api.telegram.org/file/"
f"bot{self.token}/"
f"{file['file_path']}"
),
mode='raw'
)
path = path or self.path
while file_name is None:
file_name = get_secure_key(length=10)
if os.path.exists(f"{path}/{file_name}"):
file_name = None
try:
with open(f"{path}/{file_name}", 'wb') as local_file:
local_file.write(file_bytes)
except Exception as e:
logging.error(f"File download failed due to {e}")
return
return file
if self.api_url == 'https://api.telegram.org':
file_bytes = await async_get(
url=(
f"{self.api_url}/file/"
f"bot{self.token}/"
f"{file['file_path']}"
),
mode='raw'
)
path = path or self.path
if file_name is None:
file_name = get_secure_key(length=10)
file_complete_path = os.path.join(path, file_name)
if prevent_overwriting:
while os.path.exists(file_complete_path):
file_complete_path = file_complete_path + '1'
try:
with open(file_complete_path, 'wb') as local_file:
local_file.write(file_bytes)
except Exception as e:
logging.error(f"File download failed due to {e}")
return e
else:
file_complete_path = file['file_path']
return dict(file_id=file_id,
file_name=file_name,
path=path,
file_complete_path=file_complete_path)
def translate_inline_query_answer_result(self, record,
update=None, user_record=None):
@@ -3495,7 +3534,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
Each bot will receive updates via long polling or webhook according to
its initialization parameters.
A single aiohttp.web.Application instance will be run (cls.app) on
local_host:port and it may serve custom-defined routes as well.
local_host:port, and it may serve custom-defined routes as well.
"""
if local_host is not None:
cls.local_host = local_host
+10
View File
@@ -22,6 +22,16 @@ davtelepot_messages = {
}
default_admin_messages = {
'become_admin': {
'success': {
'en': "🎉 You are now administrator! 👑",
'it': "🎉 Ora hai diritti di amministrazione! 👑",
},
'wrong_token': {
'en': "❌ Wrong token 🚷",
'it': "❌ Password errata 🚷",
},
},
'cancel': {
'button': {
'en': "↩️ Cancel",