Compare commits

..
117 Commits
Author SHA1 Message Date
Davte c1f4abc541 Specify encoding in send_part_of_text_file function
(cherry picked from commit ec747bef1d)
2024-02-14 19:31:17 +01:00
Davte c4a822e45d Compliance with bot API 6.8 and 6.9
Added the method `unpinAllGeneralForumTopicMessages` (6.8).

Added the new administrator privileges `can_post_stories`, `can_edit_stories` and `can_delete_stories` to the class `ChatAdministratorRights` and to the method `promoteChatMember` (6.9).
2023-11-12 11:55:03 +01:00
Davte 6b4a95be36 Method to add table columns if missing 2023-08-23 18:23:32 +02:00
Davte beaf3f8516 Allow non-null standard output and/or error pipe to be passed to aio_subprocess_shell function 2023-08-23 17:17:55 +02:00
Davte fc1f087d4a When answering inline queries, prevent invalid InlineQueryResultsButton instantiation
(cherry picked from commit eab81b065d)
2023-08-07 20:19:50 +02:00
Davte aeac4aea52 Better variable regex: accept only one decimal separator in float numbers
(cherry picked from commit 51a77c695b)
2023-07-25 18:58:45 +02:00
Davte 5ab22909cf Whitespace 2023-07-25 16:42:26 +02:00
Davte 9094955812 Config command implemented, allowing administrators to add variables to configuration files 2023-07-25 16:25:56 +02:00
Davte 173783e154 Moved join_path function to utilities module 2023-07-25 16:24:18 +02:00
Davte 92a986d090 Catch up with branch main (v 2.9.1) 2023-07-25 16:23:21 +02:00
Davte 3e6e364336 Compliance with Telegram Bot API 6.5 2023-02-03 21:40:09 +01:00
Davte f0a4c914e4 Compliance with Telegram Bot API 6.4 2023-01-06 10:30:25 +01:00
Davte 80a1440e75 Make the regex dot match any character at all, including a newline, when cleaning HTML strings (so multiline tag bodies are allowed, as they are in Telegram HTML markdown). 2022-12-26 14:12:23 +01:00
Davte b978022658 HTML parse_mode check upgraded.
All supported tags permitted, malformed tags replaced with escaped characters
2022-12-12 22:45:08 +01:00
Davte 50f561e7f9 Method to add a table and its columns to and ObjectWithDatabase 2022-12-10 18:46:29 +01:00
Davte a9b785f49d Compliance with Telegram Bot API 6.3 2022-12-08 16:19:45 +01:00
Davte b7d08ab2ba When admin A requests profile picture of user B, send B's picture and not A's. 2022-12-06 22:18:35 +01:00
Davte d362ec496b Browse users via /auth command 2022-12-05 22:04:59 +01:00
Davte 0bfc1e157b Working on users browsing via /auth command 2022-12-04 22:13:48 +01:00
Davte bc40957b27 Syntax-breaking typo 2022-10-12 14:19:46 +02:00
Davte 45117610f9 Bug fix: use a unique loop 2022-10-12 14:01:10 +02:00
Davte f91661927e Bug fix: use a unique loop 2022-10-12 13:34:01 +02:00
Davte 12f3a2cc73 Bug fix: asyncio.run cannot take asyncio.gather as coroutine 2022-10-12 13:31:23 +02:00
Davte 25abb80343 Bug fix: no running loop, need to create a new one. 2022-10-12 13:26:03 +02:00
Davte 76ea65a660 asyncio get_event_loop method is being deprecated; use new_event_loop / get_running_loop and asyncio.run instead
Major version change because it may not be backward-compatible
2022-10-12 13:24:40 +02:00
Davte e254dbf42a send_document method should not require a chat_id since it can be passed an update object 2020-12-20 20:30:49 +01:00
Davte b7b91a65ea send_photo method should not require a chat_id since it can be passed an update object 2020-12-11 08:21:57 +01:00
Davte abebff43d9 Avoid relative import statements 2020-11-19 15:18:50 +01:00
Davte a460f71b69 Items in __all__ must be str, not module 2020-11-19 14:37:33 +01:00
Davte 6ad5ec2865 Document can be None if document_path is provided 2020-11-19 12:32:50 +01:00
Davte cfae729270 Do not log chardet INFO and DEBUG levels 2020-11-16 23:05:24 +01:00
Davte dc9c2a7b14 Compliance with Telegram Bot API 5.0 and improved type hinting for API methods. 2020-11-16 22:54:25 +01:00
Davte a3cc676432 Identify edited methods (new or deprecated parameters) in addition to new methods. 2020-11-16 20:51:27 +01:00
Davte 15a7a58537 Version number 2020-11-15 21:35:45 +01:00
Davte ea30fd39cf Import statements refactored 2020-11-15 21:34:26 +01:00
Davte a5cabdd102 web should not be imported from aiohttp; use aiohttp.web instead 2020-11-15 20:55:22 +01:00
Davte 89fa73d1a5 Store user profile pictures in bot database and show them in authorization panel 2020-10-07 16:22:51 +02:00
Davte 4b22658bf5 MySQL compatibility: specify VARCHAR length
`db.types.string` becomes now `db.types.string(n)`
`db.types.text` is the wrong type to use (text blobs)
2020-10-07 16:19:03 +02:00
Davte bce8cff3cf Pass all information to command handler when using /start 2020-09-26 19:28:03 +02:00
Davte ea07aa47cf Make general_handler handle photo updates 2020-09-05 10:35:52 +02:00
Davte d49bab54ca Updated examples 2020-08-23 14:21:37 +02:00
Davte 83d01e4da9 Remove argument parameter from parser decorator 2020-08-23 14:07:51 +02:00
Davte 59dde0d25e In text message handler, make available both lowered and original text and inspect condition parameters 2020-08-23 14:03:42 +02:00
Davte 713f4ffd0e Accept language directly 2020-08-20 15:50:53 +02:00
Davte 51bc95332f General handler implemented and applied to contact updates 2020-08-17 23:52:16 +02:00
Davte 92758d923c Document handlers implemented 2020-08-16 15:17:09 +02:00
Davte 946e2a881f Declare packenv variable 2020-07-19 16:17:39 +02:00
Davte 0f4d31892f Prevent globbing and word splitting 2020-07-19 16:11:00 +02:00
Davte c4eaa0b9db Update default help messages with given ones, instead of replacing them 2020-07-17 09:48:52 +02:00
Davte 21214feb0a In default keyboard, show only buttons for commands the user is authorized to call 2020-07-16 10:05:28 +02:00
Davte f7ee5b71a1 Prevent decoding None objects 2020-07-15 13:16:21 +02:00
Davte fb58c0239d Async function to run shell commands 2020-07-15 13:11:04 +02:00
Davte c848bfc228 Script to merge split files 2020-06-22 22:53:25 +02:00
Davte f823057cbe Split outgoing documents bigger than 50 MB and send chunks 2020-06-22 20:30:03 +02:00
Davte d7a1acd23b Typos 2020-06-20 15:44:26 +02:00
Davte 70053c9279 Send error message if database could not be sent - new version 2020-06-20 15:34:39 +02:00
Davte 1c76c7d797 Send error message if database could not be sent 2020-06-20 15:31:42 +02:00
Davte dfffbff7c6 Merge 2020-06-20 15:20:22 +02:00
Davte a4b1ed09a2 longest_cooldown_timedelta property defined 2020-06-20 15:18:13 +02:00
Davte a1bd681cbf Merge 2020-06-20 15:16:46 +02:00
Davte 9c57677320 Accept both updates and raw_updates in maintenance exception criteria 2020-05-21 15:32:04 +02:00
Davte 956e982157 Pass to handlers the parameters they take and preserve update_id 2020-05-21 14:55:32 +02:00
Davte 4bd10894a8 Merge branch 'master' into develop 2020-05-19 15:21:02 +02:00
Davte 89a9863510 Send long text messages as files 2020-05-19 15:12:38 +02:00
Davte ed36e53a28 Consider _ as a digit when prettifying expressions 2020-05-19 15:11:58 +02:00
Davte 8977e0fbc3 Shorten buffer time for calculation sessions 2020-05-19 14:04:02 +02:00
Davte cf7e0c740b Redundant escape 2020-05-19 13:59:15 +02:00
Davte 12b18cff58 Prettify expressions removing whitespace around newlines and adjusting whitespace around parentheses 2020-05-19 12:53:20 +02:00
Davte 3160723aa7 TypeError bug fixed 2020-05-18 22:25:30 +02:00
Davte 8e2feb5ac2 Prevent message is not modified exceptions 2020-05-18 22:08:10 +02:00
Davte cbc7424a97 Prettify expressions 2020-05-18 19:31:26 +02:00
Davte 1e7c384b6d Multilanguage message in version command
(cherry picked from commit a7fd054106)
2020-05-18 18:58:23 +02:00
Davte 7cc2e02f47 Remove whitespace at the end of the expression after del button is pressed 2020-05-18 18:50:21 +02:00
Davte 6315c0dcc2 Track input via message of algebraic expressions as well as input via buttons. 2020-05-18 18:33:40 +02:00
Davte f06c525f5b Merged branch master 2020-05-18 15:09:05 +02:00
Davte ea5c63c1f8 Finished working on calc command 2020-05-18 15:04:18 +02:00
Davte ea549b63c8 Working on calc command 2020-05-18 13:04:19 +02:00
Davte e63b0f9265 Working on calc command 2020-05-18 12:42:04 +02:00
Davte cb9310437f Working on calc button 2020-05-17 19:45:39 +02:00
Davte 5bc58dd7d5 Working on calc button 2020-05-16 15:51:49 +02:00
Davte 5d35579e10 Working on /calc command 2020-05-15 19:48:04 +02:00
Davte b0132e0b30 /when command implemented 2020-05-14 22:18:21 +02:00
Davte 49ecee63d0 /info command implemented 2020-05-14 21:58:38 +02:00
Davte 273eda2b67 /ping command implemented
/length command returns characters in text message even, not only in reply
2020-05-14 20:25:29 +02:00
Davte b12f653096 Useful tools module added 2020-05-14 18:50:05 +02:00
Davte 05878f3fbd Language-labelled commands are accepted only for selected language. /father uses selected language for commands 2020-05-14 18:49:40 +02:00
Davte c583c3c3b0 Allow language-labelled commands 2020-05-14 15:32:06 +02:00
Davte 2d40903069 Finished working on /version command 2020-05-13 19:44:04 +02:00
Davte 217a445a65 Working on /version command 2020-05-13 15:54:38 +02:00
Davte b68dbe7a07 /ban command implemented 2020-05-13 15:31:59 +02:00
Davte 258ca9f6ef /ban command implemented 2020-05-13 15:31:20 +02:00
Davte 3648a36636 Version 2020-05-13 15:22:37 +02:00
Davte ef99493c7f Finished working on /ban 2020-05-13 15:22:14 +02:00
Davte 841f7f0c8d Working on /ban 2020-05-13 12:47:37 +02:00
Davte 23882e5b3b Implemented button to delete all commands stored by BotFather 2020-05-07 22:52:42 +02:00
Davte 6ba21f0115 Version 2020-05-07 15:29:10 +02:00
Davte ca6dca3cb7 Finished working on /father command 2020-05-07 15:07:45 +02:00
Davte 9072c3abe5 Working on /father command 2020-05-06 23:18:27 +02:00
Davte e74e38c6ae Comment 2020-05-06 15:39:45 +02:00
Davte 7a23045479 New parameters of sendPoll method 2020-05-06 15:33:23 +02:00
Davte 5ef449a542 Temp 2020-05-06 00:44:21 +02:00
Davte a2c83f8d9c Pass language to update handlers 2020-05-06 00:39:23 +02:00
Davte dddaf20ea2 Temp 2020-05-05 23:44:58 +02:00
Davte a828bb5d3c Move functions outside init 2020-05-05 12:29:55 +02:00
Davte 25f5514dff Type hinting
(cherry picked from commit 3896776f0e)
2020-04-28 12:08:01 +02:00
Davte 34f802732b Do not notify package updates too often
(cherry picked from commit ab6a0bc0ad)
2020-04-28 09:48:53 +02:00
Davte f6466b0540 Merge branch 'develop' of ssh://gogs.davte.it:8445/Davte/davtelepot into develop
# Conflicts:
#	davtelepot/__init__.py
2020-04-28 09:48:42 +02:00
Davte 7565df17ba New version
(cherry picked from commit e61d757c1a)
2020-04-28 00:36:28 +02:00
Davte 4be33370b9 Text made more clear
(cherry picked from commit e7274dce07)
2020-04-28 00:27:36 +02:00
Davte cf3f7a88fb Deprecated admin_tools submodule 2020-04-28 00:26:38 +02:00
Davte a4d464da58 Text made more clear 2020-04-27 19:07:10 +02:00
Davte 83c0a91919 Missing whitespace
(cherry picked from commit b107cc105d)
2020-04-27 18:03:24 +02:00
Davte 85a5ce3882 Merge branch 'develop' of ssh://gogs.davte.it:8445/Davte/davtelepot into develop 2020-04-27 17:30:05 +02:00
Davte 77405d2dd3 Merge branch 'master' into develop
# Conflicts:
#	davtelepot/__init__.py
#	davtelepot/administration_tools.py
2020-04-27 14:03:58 +02:00
Davte 1e2316e748 Package update notifier completed 2020-04-27 13:45:25 +02:00
Davte 16014c5a42 Working on package update notifier 2020-04-26 23:30:44 +02:00
Davte f0be5b5ff2 Working on package update notifier 2020-04-26 23:14:10 +02:00
8 changed files with 266 additions and 1730 deletions
-1
View File
@@ -41,7 +41,6 @@ __pycache__/
# Distribution / packaging # Distribution / packaging
.Python .Python
env/ env/
.venv/
build/ build/
develop-eggs/ develop-eggs/
dist/ dist/
+1 -1
View File
@@ -11,7 +11,7 @@ __author__ = "Davide Testa"
__email__ = "davide@davte.it" __email__ = "davide@davte.it"
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"] __credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
__license__ = "GNU General Public License v3.0" __license__ = "GNU General Public License v3.0"
__version__ = "2.10.11" __version__ = "2.9.8"
__maintainer__ = "Davide Testa" __maintainer__ = "Davide Testa"
__contact__ = "t.me/davte" __contact__ = "t.me/davte"
+92 -171
View File
@@ -13,12 +13,10 @@ import asyncio
import datetime import datetime
import json import json
import logging import logging
import platform
import re import re
import types import types
from collections import OrderedDict from collections import OrderedDict
from importlib.metadata import version as get_package_version_from_metadata
from typing import Union, List, Tuple from typing import Union, List, Tuple
# Third party modules # Third party modules
@@ -29,8 +27,8 @@ from davtelepot.messages import default_admin_messages, default_talk_messages
from davtelepot.bot import Bot from davtelepot.bot import Bot
from davtelepot.utilities import ( from davtelepot.utilities import (
async_wrapper, CachedPage, Confirmator, extract, get_cleaned_text, async_wrapper, CachedPage, Confirmator, extract, get_cleaned_text,
get_secure_key, get_user, clean_html_string, line_drawing_unordered_list, get_user, clean_html_string, line_drawing_unordered_list, make_button,
make_button, make_inline_keyboard, remove_html_tags, send_part_of_text_file, make_inline_keyboard, remove_html_tags, send_part_of_text_file,
send_csv_file, make_lines_of_buttons, join_path send_csv_file, make_lines_of_buttons, join_path
) )
@@ -45,13 +43,6 @@ variable_regex = re.compile(r"(?P<name>[a-zA-Z]\w*)\s*=\s*"
r"\"[^\"]*\")") 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, async def _forward_to(update,
bot: Bot, bot: Bot,
sender, sender,
@@ -232,9 +223,9 @@ def get_talk_panel(bot: Bot,
return text, reply_markup return text, reply_markup
async def talk_command(bot: Bot, async def _talk_command(bot: Bot,
update, update,
user_record): user_record):
text = get_cleaned_text( text = get_cleaned_text(
update, update,
bot, bot,
@@ -352,17 +343,17 @@ async def end_session(bot: Bot,
return return
async def talk_button(bot: Bot, async def _talk_button(bot: Bot,
update, update,
user_record, user_record,
data): data):
telegram_id = user_record['telegram_id'] telegram_id = user_record['telegram_id']
command, *arguments = data command, *arguments = data
result, text, reply_markup = '', '', None result, text, reply_markup = '', '', None
if command == 'search': if command == 'search':
bot.set_individual_text_message_handler( bot.set_individual_text_message_handler(
await async_wrapper( await async_wrapper(
talk_command, _talk_command,
), ),
update update
) )
@@ -435,7 +426,7 @@ async def talk_button(bot: Bot,
return result return result
async def restart_command(bot: Bot, async def _restart_command(bot: Bot,
update, update,
user_record): user_record):
with bot.db as db: with bot.db as db:
@@ -462,7 +453,7 @@ async def restart_command(bot: Bot,
return return
async def stop_command(bot: Bot, async def _stop_command(bot: Bot,
update, update,
user_record): user_record):
text = bot.get_message( text = bot.get_message(
@@ -504,10 +495,10 @@ async def stop_bots(bot: Bot):
return return
async def stop_button(bot: Bot, async def _stop_button(bot: Bot,
update, update,
user_record, user_record,
data: List[Union[int, str]]): data: List[Union[int, str]]):
result, text, reply_markup = '', '', None result, text, reply_markup = '', '', None
telegram_id = user_record['telegram_id'] telegram_id = user_record['telegram_id']
command = data[0] if len(data) > 0 else 'None' command = data[0] if len(data) > 0 else 'None'
@@ -544,7 +535,7 @@ async def stop_button(bot: Bot,
return result 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( if not all(
[ [
bot.db_url.endswith('.db'), bot.db_url.endswith('.db'),
@@ -571,7 +562,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( query = get_cleaned_text(
update, update,
bot, bot,
@@ -649,7 +640,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 result, text, reply_markup = '', '', None
command = data[0] if len(data) else 'default' command = data[0] if len(data) else 'default'
error_message = bot.get_message( error_message = bot.get_message(
@@ -686,7 +677,7 @@ async def query_button(bot, update, user_record, data):
return result 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: if bot.log_file_path is None:
return bot.get_message( return bot.get_message(
'admin', 'log_command', 'no_log', 'admin', 'log_command', 'no_log',
@@ -739,7 +730,7 @@ async def log_command(bot, update, user_record):
return 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 # Always send errors log file in private chat
chat_id = update['from']['id'] chat_id = update['from']['id']
if bot.errors_file_path is None: if bot.errors_file_path is None:
@@ -783,7 +774,7 @@ async def errors_command(bot, update, user_record):
return 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']) maintenance_message = get_cleaned_text(update, bot, ['maintenance'])
if maintenance_message.startswith('{'): if maintenance_message.startswith('{'):
maintenance_message = json.loads(maintenance_message) maintenance_message = json.loads(maintenance_message)
@@ -836,8 +827,7 @@ def get_maintenance_exception_criterion(bot, allowed_command):
async def get_last_commit(): async def get_last_commit():
"""Get last commit hash and message.""" """Get last commit hash and davtelepot version."""
last_commit_message = None
try: try:
_subprocess = await asyncio.create_subprocess_exec( _subprocess = await asyncio.create_subprocess_exec(
'git', 'rev-parse', 'HEAD', 'git', 'rev-parse', 'HEAD',
@@ -845,22 +835,12 @@ async def get_last_commit():
stderr=asyncio.subprocess.STDOUT stderr=asyncio.subprocess.STDOUT
) )
stdout, _ = await _subprocess.communicate() stdout, _ = await _subprocess.communicate()
last_commit_hash = stdout.decode().strip() last_commit = stdout.decode().strip()
except Exception as e: except Exception as e:
last_commit_hash = f"{e}" last_commit = f"{e}"
try: if last_commit.startswith("fatal: not a git repository"):
_subprocess = await asyncio.create_subprocess_exec( last_commit = "-"
'git', 'log', '--pretty=%B', "-n", "1", last_commit_hash, return last_commit
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT
)
stdout, _ = await _subprocess.communicate()
last_commit_message = stdout.decode().strip()
except Exception:
pass
if last_commit_hash.startswith("fatal: not a git repository"):
last_commit_hash = "-"
return last_commit_hash, last_commit_message
async def get_new_versions(bot: Bot, async def get_new_versions(bot: Bot,
@@ -884,12 +864,7 @@ async def get_new_versions(bot: Bot,
"skipping...") "skipping...")
continue continue
new_version = web_page['info']['version'] new_version = web_page['info']['version']
try: current_version = package.__version__
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( notification_record = bot.db['updates_notifications'].find_one(
package=package.__name__, package=package.__name__,
order_by=['-id'], order_by=['-id'],
@@ -908,21 +883,17 @@ async def get_new_versions(bot: Bot,
return news return news
async def version_command(bot: Bot, update: dict, async def _version_command(bot: Bot, update: dict,
user_record: OrderedDict, language: str): user_record: OrderedDict, language: str):
last_commit_hash, last_commit_message = await get_last_commit() last_commit = await get_last_commit()
text = bot.get_message( text = bot.get_message(
'admin', 'version_command', 'header', 'admin', 'version_command', 'header',
last_commit=last_commit_hash, last_commit=last_commit,
update=update, user_record=user_record update=update, user_record=user_record
) ) + '\n\n'
if last_commit_message:
text += "\n<i>" + last_commit_message + "</i>"
text += "\n\n"
text += f'<b>Python: </b> <code>{platform.python_version()}</code>\n'
text += '\n'.join( text += '\n'.join(
f"<b>{package.__name__}</b>: " f"<b>{package.__name__}</b>: "
f"<code>{get_package_version(package)}</code>" f"<code>{package.__version__}</code>"
for package in bot.packages for package in bot.packages
) )
temporary_message = await bot.send_message( temporary_message = await bot.send_message(
@@ -961,15 +932,15 @@ async def notify_new_version(bot: Bot):
Notify admins when last commit and/or davtelepot version change. Notify admins when last commit and/or davtelepot version change.
""" """
last_commit_hash, last_commit_message = await get_last_commit() last_commit = await get_last_commit()
old_record = bot.db['version_history'].find_one( old_record = bot.db['version_history'].find_one(
order_by=['-id'] order_by=['-id']
) )
current_versions = { current_versions = {
f"{package.__name__}_version": get_package_version(package) f"{package.__name__}_version": package.__version__
for package in bot.packages for package in bot.packages
} }
current_versions['last_commit'] = last_commit_hash current_versions['last_commit'] = last_commit
if old_record is None: if old_record is None:
old_record = dict( old_record = dict(
updated_at=datetime.datetime.min, updated_at=datetime.datetime.min,
@@ -992,16 +963,13 @@ async def notify_new_version(bot: Bot):
'admin', 'new_version', 'title', 'admin', 'new_version', 'title',
user_record=admin user_record=admin
) + '\n\n' ) + '\n\n'
if last_commit_hash != old_record['last_commit']: if last_commit != old_record['last_commit']:
text += bot.get_message( text += bot.get_message(
'admin', 'new_version', 'last_commit', 'admin', 'new_version', 'last_commit',
old_record=old_record, old_record=old_record,
new_record=current_versions, new_record=current_versions,
user_record=admin user_record=admin
) ) + '\n\n'
if last_commit_message:
text += f"\n<i>{last_commit_message}</i>"
text += "\n\n"
text += '\n'.join( text += '\n'.join(
f"<b>{name[:-len('_version')]}</b>: " f"<b>{name[:-len('_version')]}</b>: "
f"<code>{old_record[name]}</code> —> " f"<code>{old_record[name]}</code> —> "
@@ -1064,7 +1032,7 @@ async def get_package_updates(bot: Bot,
await asyncio.sleep(monitoring_interval) await asyncio.sleep(monitoring_interval)
async def send_start_messages(bot: Bot): async def _send_start_messages(bot: Bot):
"""Send restart messages at restart.""" """Send restart messages at restart."""
for restart_message in bot.db['restart_messages'].find(sent=None): for restart_message in bot.db['restart_messages'].find(sent=None):
asyncio.ensure_future( asyncio.ensure_future(
@@ -1092,7 +1060,7 @@ async def send_start_messages(bot: Bot):
return return
async def load_talking_sessions(bot: Bot): async def _load_talking_sessions(bot: Bot):
sessions = [] sessions = []
for session in bot.db.query( for session in bot.db.query(
"""SELECT * """SELECT *
@@ -1171,7 +1139,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 = [ modes = [
{ {
key: ( key: (
@@ -1475,12 +1443,12 @@ async def edit_bot_father_settings_via_message(bot: Bot,
return result, text, reply_markup 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): language: str, data: list):
"""Handle BotFather button. """Handle BotFather button.
Operational modes Operational modes
- main: back to main page (see `father_command`) - main: back to main page (see _father_command)
- get: show commands stored by @BotFather - get: show commands stored by @BotFather
- set: edit commands stored by @BotFather - set: edit commands stored by @BotFather
""" """
@@ -1574,7 +1542,7 @@ async def father_button(bot: Bot, user_record: OrderedDict,
elif command == 'main': elif command == 'main':
return dict( return dict(
text='', text='',
edit=(await father_command(bot=bot, language=language)) edit=(await _father_command(bot=bot, language=language))
) )
elif command == 'set': elif command == 'set':
stored_commands = await bot.getMyCommands() stored_commands = await bot.getMyCommands()
@@ -1842,8 +1810,8 @@ async def father_button(bot: Bot, user_record: OrderedDict,
return result return result
async def config_command(bot: Bot, update: dict, async def _config_command(bot: Bot, update: dict,
user_record: dict, language: str): user_record: dict, language: str):
text = get_cleaned_text( text = get_cleaned_text(
update, update,
bot, bot,
@@ -1876,52 +1844,6 @@ async def config_command(bot: Bot, update: dict,
language=language) 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()
if len(bot.administrators) > 0:
return
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, def init(telegram_bot: Bot,
talk_messages: dict = None, talk_messages: dict = None,
admin_messages: dict = None, admin_messages: dict = None,
@@ -1985,16 +1907,16 @@ def init(telegram_bot: Bot,
# Tasks to complete before starting bot # Tasks to complete before starting bot
@telegram_bot.additional_task(when='BEFORE') @telegram_bot.additional_task(when='BEFORE')
async def _load_talking_sessions(): async def load_talking_sessions():
return await load_talking_sessions(bot=telegram_bot) return await _load_talking_sessions(bot=telegram_bot)
@telegram_bot.additional_task(when='BEFORE', bot=telegram_bot) @telegram_bot.additional_task(when='BEFORE', bot=telegram_bot)
async def notify_version(bot): async def notify_version(bot):
return await notify_new_version(bot=bot) return await notify_new_version(bot=bot)
@telegram_bot.additional_task('BEFORE') @telegram_bot.additional_task('BEFORE')
async def _send_start_messages(): async def send_restart_messages():
return await send_start_messages(bot=telegram_bot) return await _send_start_messages(bot=telegram_bot)
# Administration commands # Administration commands
@telegram_bot.command(command='/db', @telegram_bot.command(command='/db',
@@ -2003,10 +1925,10 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'db_command']['description'], 'db_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _send_bot_database(bot, user_record, language): async def send_bot_database(bot, user_record, language):
return await send_bot_database(bot=bot, return await _send_bot_database(bot=bot,
user_record=user_record, user_record=user_record,
language=language) language=language)
@telegram_bot.command(command='/errors', @telegram_bot.command(command='/errors',
aliases=[], aliases=[],
@@ -2014,8 +1936,8 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'errors_command']['description'], 'errors_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _errors_command(bot, update, user_record): async def errors_command(bot, update, user_record):
return await errors_command(bot, update, user_record) return await _errors_command(bot, update, user_record)
@telegram_bot.command(command='/father', @telegram_bot.command(command='/father',
aliases=[], aliases=[],
@@ -2026,14 +1948,14 @@ def init(telegram_bot: Bot,
if key in ('description', ) if key in ('description', )
}, },
authorization_level='admin') authorization_level='admin')
async def _father_command(bot, language): async def father_command(bot, language):
return await father_command(bot=bot, language=language) return await _father_command(bot=bot, language=language)
@telegram_bot.button(prefix='father:///', @telegram_bot.button(prefix='father:///',
separator='|', separator='|',
authorization_level='admin') authorization_level='admin')
async def _father_button(bot, user_record, language, data): async def query_button(bot, user_record, language, data):
return await father_button(bot=bot, return await _father_button(bot=bot,
user_record=user_record, user_record=user_record,
language=language, language=language,
data=data) data=data)
@@ -2044,16 +1966,16 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'log_command']['description'], 'log_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _log_command(bot, update, user_record): async def log_command(bot, update, user_record):
return await log_command(bot, update, user_record) return await _log_command(bot, update, user_record)
@telegram_bot.command(command='/maintenance', aliases=[], @telegram_bot.command(command='/maintenance', aliases=[],
show_in_keyboard=False, show_in_keyboard=False,
description=admin_messages[ description=admin_messages[
'maintenance_command']['description'], 'maintenance_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _maintenance_command(bot, update, user_record): async def maintenance_command(bot, update, user_record):
return await maintenance_command(bot, update, user_record) return await _maintenance_command(bot, update, user_record)
@telegram_bot.command(command='/query', @telegram_bot.command(command='/query',
aliases=[], aliases=[],
@@ -2061,16 +1983,16 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'query_command']['description'], 'query_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _query_command(bot, update, user_record): async def query_command(bot, update, user_record):
return await query_command(bot, update, user_record) return await _query_command(bot, update, user_record)
@telegram_bot.button(prefix='db_query:///', @telegram_bot.button(prefix='db_query:///',
separator='|', separator='|',
description=admin_messages[ description=admin_messages[
'query_command']['description'], 'query_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _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) return await _query_button(bot, update, user_record, data)
@telegram_bot.command(command='/restart', @telegram_bot.command(command='/restart',
aliases=[], aliases=[],
@@ -2078,8 +2000,8 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'restart_command']['description'], 'restart_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _restart_command(bot, update, user_record): async def restart_command(bot, update, user_record):
return await restart_command(bot, update, user_record) return await _restart_command(bot, update, user_record)
@telegram_bot.command(command='/select', @telegram_bot.command(command='/select',
aliases=[], aliases=[],
@@ -2087,8 +2009,8 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'select_command']['description'], 'select_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _select_command(bot, update, user_record): async def select_command(bot, update, user_record):
return await query_command(bot, update, user_record) return await _query_command(bot, update, user_record)
@telegram_bot.command(command='/stop', @telegram_bot.command(command='/stop',
aliases=[], aliases=[],
@@ -2096,16 +2018,16 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'stop_command']['description'], 'stop_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _stop_command(bot, update, user_record): async def stop_command(bot, update, user_record):
return await stop_command(bot, update, user_record) return await _stop_command(bot, update, user_record)
@telegram_bot.button(prefix='stop:///', @telegram_bot.button(prefix='stop:///',
separator='|', separator='|',
description=admin_messages[ description=admin_messages[
'stop_command']['description'], 'stop_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _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) return await _stop_button(bot, update, user_record, data)
@telegram_bot.command(command='/talk', @telegram_bot.command(command='/talk',
aliases=[], aliases=[],
@@ -2113,14 +2035,14 @@ def init(telegram_bot: Bot,
description=admin_messages[ description=admin_messages[
'talk_command']['description'], 'talk_command']['description'],
authorization_level='admin') authorization_level='admin')
async def _talk_command(bot, update, user_record): async def talk_command(bot, update, user_record):
return await talk_command(bot, update, user_record) return await _talk_command(bot, update, user_record)
@telegram_bot.button(prefix='talk:///', @telegram_bot.button(prefix='talk:///',
separator='|', separator='|',
authorization_level='admin') authorization_level='admin')
async def _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) return await _talk_button(bot, update, user_record, data)
@telegram_bot.command(command='/version', @telegram_bot.command(command='/version',
aliases=[], aliases=[],
@@ -2131,11 +2053,11 @@ def init(telegram_bot: Bot,
}, },
show_in_keyboard=False, show_in_keyboard=False,
authorization_level='admin') authorization_level='admin')
async def _version_command(bot, update, user_record, language): async def version_command(bot, update, user_record, language):
return await version_command(bot=bot, return await _version_command(bot=bot,
update=update, update=update,
user_record=user_record, user_record=user_record,
language=language) language=language)
@telegram_bot.command(command='/config', @telegram_bot.command(command='/config',
aliases=[], aliases=[],
@@ -2146,9 +2068,8 @@ def init(telegram_bot: Bot,
}, },
show_in_keyboard=False, show_in_keyboard=False,
authorization_level='admin') authorization_level='admin')
async def _config_command(bot, update, user_record, language): async def config_command(bot, update, user_record, language):
return await config_command(bot=bot, return await _config_command(bot=bot,
update=update, update=update,
user_record=user_record, user_record=user_record,
language=language) language=language)
asyncio.ensure_future(create_promotion_command(bot=telegram_bot))
+85 -1354
View File
File diff suppressed because it is too large Load Diff
+3 -5
View File
@@ -25,7 +25,6 @@ class TelegramApiMethod(object):
'Boolean': "bool", 'Boolean': "bool",
'Integer': "int", 'Integer': "int",
'Integer or String': "Union[int, str]", 'Integer or String': "Union[int, str]",
'Array of Integer': "List[str]",
'String': "str", 'String': "str",
} }
"""Telegram bot API method.""" """Telegram bot API method."""
@@ -56,15 +55,14 @@ class TelegramApiMethod(object):
for n, paragraph in enumerate(self.description.replace('.', '.\n').split('\n')): for n, paragraph in enumerate(self.description.replace('.', '.\n').split('\n')):
additional_indentation = 0 additional_indentation = 0
if n == 0 and paragraph.startswith(redundant_string): if n == 0 and paragraph.startswith(redundant_string):
paragraph = (paragraph[len(redundant_string)].upper() paragraph = paragraph[len(redundant_string)].upper() + paragraph[len(redundant_string)+1:]
+ paragraph[len(redundant_string)+1:])
for word in paragraph.split(' '): for word in paragraph.split(' '):
if len(current_line) + len(word) > 80 - indentation - additional_indentation: if len(current_line) + len(word) > 80 - indentation - additional_indentation:
additional_indentation = max(additional_indentation, 4) additional_indentation = max(additional_indentation, 4)
result += f"{current_line.strip()}\n{' ' * additional_indentation}" result += f"{current_line.strip()}\n{' ' * additional_indentation}"
current_line = "" current_line = ""
current_line += f"{word} " current_line += f"{word} "
if len(current_line) > 0: if len(current_line):
result += f"{current_line.strip()}\n" result += f"{current_line.strip()}\n"
current_line = "" current_line = ""
if n == 0: if n == 0:
@@ -205,7 +203,7 @@ async def print_api_methods(filename=None,
) )
) )
if output_file: if output_file:
with open(output_file, 'w', encoding="utf-8") as file: with open(output_file, 'w') as file:
if new_methods: if new_methods:
file.write( file.write(
"from typing import List, Union\n" "from typing import List, Union\n"
+84 -187
View File
@@ -2,6 +2,34 @@
camelCase methods mirror API directly, while snake_case ones act as middleware camelCase methods mirror API directly, while snake_case ones act as middleware
someway. 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 # Standard library modules
@@ -21,9 +49,7 @@ from typing import Callable, List, Union, Dict
import aiohttp.web import aiohttp.web
# Project modules # Project modules
from davtelepot.api import ( from davtelepot.api import TelegramBot, TelegramError
LinkPreviewOptions, ReplyParameters, TelegramBot, TelegramError
)
from davtelepot.database import ObjectWithDatabase from davtelepot.database import ObjectWithDatabase
from davtelepot.languages import MultiLanguageObject from davtelepot.languages import MultiLanguageObject
from davtelepot.messages import davtelepot_messages from davtelepot.messages import davtelepot_messages
@@ -78,10 +104,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
_errors_file_path = None _errors_file_path = None
_documents_max_dimension = 50 * 1000 * 1000 # 50 MB _documents_max_dimension = 50 * 1000 * 1000 # 50 MB
def __init__(self, def __init__(
token, hostname='', certificate=None, self, token, hostname='', certificate=None, max_connections=40,
max_connections=40, allowed_updates=None, allowed_updates=None, database_url='bot.db'
database_url='bot.db', api_url: str = None): ):
"""Init a bot instance. """Init a bot instance.
token : str token : str
@@ -99,7 +125,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
# Append `self` to class list of instances # Append `self` to class list of instances
self.__class__.bots.append(self) self.__class__.bots.append(self)
# Call superclasses constructors with proper arguments # Call superclasses constructors with proper arguments
TelegramBot.__init__(self, token, api_url=api_url) TelegramBot.__init__(self, token)
ObjectWithDatabase.__init__(self, database_url=database_url) ObjectWithDatabase.__init__(self, database_url=database_url)
MultiLanguageObject.__init__(self) MultiLanguageObject.__init__(self)
self.messages['davtelepot'] = davtelepot_messages self.messages['davtelepot'] = davtelepot_messages
@@ -122,47 +148,12 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
'edited_message': self.edited_message_handler, 'edited_message': self.edited_message_handler,
'channel_post': self.channel_post_handler, 'channel_post': self.channel_post_handler,
'edited_channel_post': self.edited_channel_post_handler, 'edited_channel_post': self.edited_channel_post_handler,
'business_connection': self.get_update_handler(
update_type='business_connection'
),
'business_message': self.get_update_handler(
update_type='business_message'
),
'edited_business_message': self.get_update_handler(
update_type='edited_business_message'
),
'deleted_business_messages': self.get_update_handler(
update_type='deleted_business_messages'
),
'message_reaction': self.get_update_handler(
update_type='message_reaction'
),
'message_reaction_count': self.get_update_handler(
update_type='message_reaction_count'
),
'inline_query': self.inline_query_handler, 'inline_query': self.inline_query_handler,
'chosen_inline_result': self.chosen_inline_result_handler, 'chosen_inline_result': self.chosen_inline_result_handler,
'callback_query': self.callback_query_handler, 'callback_query': self.callback_query_handler,
'shipping_query': self.shipping_query_handler, 'shipping_query': self.shipping_query_handler,
'pre_checkout_query': self.pre_checkout_query_handler, 'pre_checkout_query': self.pre_checkout_query_handler,
'purchased_paid_media': self.get_update_handler(
update_type='purchased_paid_media'
),
'poll': self.poll_handler, 'poll': self.poll_handler,
'poll_answer': self.get_update_handler(
update_type='poll_answer'
),
'my_chat_member': self.get_update_handler(
update_type='my_chat_member'
),
'chat_member': self.get_update_handler( update_type='chat_member' ),
'chat_join_request': self.get_update_handler(
update_type='chat_join_request'
),
'chat_boost': self.get_update_handler( update_type='chat_boost' ),
'removed_chat_boost': self.get_update_handler(
update_type='removed_chat_boost'
),
} }
# Different message update types need different handlers # Different message update types need different handlers
self.message_handlers = { self.message_handlers = {
@@ -256,8 +247,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
self.Role = None self.Role = None
self.packages = [sys.modules['davtelepot']] self.packages = [sys.modules['davtelepot']]
self._documents_max_dimension = None self._documents_max_dimension = None
self._getting_me = False
self._got_me = False
# Add `users` table with its fields if missing # Add `users` table with its fields if missing
if 'users' not in self.db.tables: if 'users' not in self.db.tables:
table = self.db.create_table( table = self.db.create_table(
@@ -717,18 +706,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
) )
return return
def get_update_handler(self, update_type: str):
"""Get update handler for `update_type`."""
bot = self
async def handler(update, user_record, language=None):
"""Handle update message of type `update_type`"""
logging.info(
"The following update was received: %s\n"
"However, this `%s` handler does nothing yet.",
update, update_type
)
return handler
async def edited_channel_post_handler(self, update, user_record, language=None): async def edited_channel_post_handler(self, update, user_record, language=None):
"""Handle Telegram `edited_channel_post` update.""" """Handle Telegram `edited_channel_post` update."""
logging.info( logging.info(
@@ -1342,21 +1319,19 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
async def send_message(self, chat_id: Union[int, str] = None, async def send_message(self, chat_id: Union[int, str] = None,
text: str = None, text: str = None,
message_thread_id: int = None,
entities: List[dict] = None, entities: List[dict] = None,
parse_mode: str = 'HTML', parse_mode: str = 'HTML',
link_preview_options: LinkPreviewOptions = None, message_thread_id: int = None,
disable_notification: bool = None,
protect_content: bool = None, protect_content: bool = None,
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
allow_sending_without_reply: bool = None, allow_sending_without_reply: bool = None,
reply_markup=None,
update: dict = None, update: dict = None,
reply_to_update: bool = False, reply_to_update: bool = False,
send_default_keyboard: bool = True, 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). """Send text via message(s).
This method wraps lower-level `TelegramBot.sendMessage` method. This method wraps lower-level `TelegramBot.sendMessage` method.
@@ -1377,10 +1352,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
user_record = self.db['users'].find_one(telegram_id=chat_id) user_record = self.db['users'].find_one(telegram_id=chat_id)
if reply_to_update and 'message_id' in update: if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id'] 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 ( if (
send_default_keyboard send_default_keyboard
and reply_markup is None and reply_markup is None
@@ -1424,27 +1395,19 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
limit=self.__class__.TELEGRAM_MESSAGES_MAX_LEN - 100, limit=self.__class__.TELEGRAM_MESSAGES_MAX_LEN - 100,
parse_mode=parse_mode 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: for text_chunk, is_last in text_chunks:
_reply_markup = (reply_markup if is_last else None) _reply_markup = (reply_markup if is_last else None)
sent_message_update = await self.sendMessage( sent_message_update = await self.sendMessage(
chat_id=chat_id, chat_id=chat_id,
text=text_chunk, text=text_chunk,
message_thread_id=message_thread_id,
parse_mode=parse_mode, parse_mode=parse_mode,
entities=entities, entities=entities,
link_preview_options=link_preview_options, message_thread_id=message_thread_id,
disable_notification=disable_notification,
protect_content=protect_content, protect_content=protect_content,
reply_parameters=reply_parameters, disable_web_page_preview=disable_web_page_preview,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_markup=_reply_markup reply_markup=_reply_markup
) )
return sent_message_update return sent_message_update
@@ -1468,7 +1431,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
parse_mode: str = 'HTML', parse_mode: str = 'HTML',
entities: List[dict] = None, entities: List[dict] = None,
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
link_preview_options: LinkPreviewOptions = None,
allow_sending_without_reply: bool = None, allow_sending_without_reply: bool = None,
reply_markup=None, reply_markup=None,
update: dict = None): update: dict = None):
@@ -1501,10 +1463,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
) )
): ):
if i == 0: 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( edited_message = await self.editMessageText(
text=text_chunk, text=text_chunk,
chat_id=chat_id, chat_id=chat_id,
@@ -1512,7 +1470,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
inline_message_id=inline_message_id, inline_message_id=inline_message_id,
parse_mode=parse_mode, parse_mode=parse_mode,
entities=entities, entities=entities,
link_preview_options=link_preview_options, disable_web_page_preview=disable_web_page_preview,
reply_markup=(reply_markup if is_last else None) reply_markup=(reply_markup if is_last else None)
) )
if chat_id is None: if chat_id is None:
@@ -1618,7 +1576,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
reply_markup=None, reply_markup=None,
update: dict = None, update: dict = None,
reply_to_update: bool = False, reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True, send_default_keyboard: bool = True,
use_stored_file_id: bool = True): use_stored_file_id: bool = True):
"""Send photos. """Send photos.
@@ -1642,15 +1599,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
chat_id = self.get_chat_id(update) chat_id = self.get_chat_id(update)
if reply_to_update and 'message_id' in update: if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id'] 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 ( if (
send_default_keyboard send_default_keyboard
and reply_markup is None and reply_markup is None
@@ -1704,7 +1652,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
parse_mode=parse_mode, parse_mode=parse_mode,
caption_entities=caption_entities, caption_entities=caption_entities,
disable_notification=disable_notification, disable_notification=disable_notification,
reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_markup=reply_markup reply_markup=reply_markup
) )
if isinstance(sent_update, Exception): if isinstance(sent_update, Exception):
@@ -1752,7 +1701,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
reply_markup=None, reply_markup=None,
update: dict = None, update: dict = None,
reply_to_update: bool = False, reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True, send_default_keyboard: bool = True,
use_stored_file_id: bool = True): use_stored_file_id: bool = True):
"""Send audio files. """Send audio files.
@@ -1776,15 +1724,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
chat_id = self.get_chat_id(update) chat_id = self.get_chat_id(update)
if reply_to_update and 'message_id' in update: if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id'] 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 ( if (
send_default_keyboard send_default_keyboard
and reply_markup is None and reply_markup is None
@@ -1842,7 +1781,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
title=title, title=title,
thumbnail=thumbnail, thumbnail=thumbnail,
disable_notification=disable_notification, disable_notification=disable_notification,
reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_markup=reply_markup reply_markup=reply_markup
) )
if isinstance(sent_update, Exception): if isinstance(sent_update, Exception):
@@ -1886,7 +1826,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
reply_markup=None, reply_markup=None,
update: dict = None, update: dict = None,
reply_to_update: bool = False, reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True, send_default_keyboard: bool = True,
use_stored_file_id: bool = True): use_stored_file_id: bool = True):
"""Send voice messages. """Send voice messages.
@@ -1910,15 +1849,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
chat_id = self.get_chat_id(update) chat_id = self.get_chat_id(update)
if reply_to_update and 'message_id' in update: if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id'] 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 ( if (
send_default_keyboard send_default_keyboard
and reply_markup is None and reply_markup is None
@@ -1973,7 +1903,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
caption_entities=caption_entities, caption_entities=caption_entities,
duration=duration, duration=duration,
disable_notification=disable_notification, disable_notification=disable_notification,
reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_markup=reply_markup reply_markup=reply_markup
) )
if isinstance(sent_update, Exception): if isinstance(sent_update, Exception):
@@ -2020,7 +1951,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
document_name: str = None, document_name: str = None,
update: dict = None, update: dict = None,
reply_to_update: bool = False, reply_to_update: bool = False,
reply_parameters: ReplyParameters = None,
send_default_keyboard: bool = True, send_default_keyboard: bool = True,
use_stored_file_id: bool = False): use_stored_file_id: bool = False):
"""Send a document. """Send a document.
@@ -2053,15 +1983,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
return return
if reply_to_update and 'message_id' in update: if reply_to_update and 'message_id' in update:
reply_to_message_id = update['message_id'] 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: if chat_id > 0:
user_record = self.db['users'].find_one(telegram_id=chat_id) user_record = self.db['users'].find_one(telegram_id=chat_id)
language = self.get_language(update=update, user_record=user_record) language = self.get_language(update=update, user_record=user_record)
@@ -2140,7 +2061,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
disable_notification=disable_notification, disable_notification=disable_notification,
reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup, reply_markup=reply_markup,
update=update, update=update,
reply_to_update=reply_to_update, reply_to_update=reply_to_update,
@@ -2171,7 +2092,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
caption_entities=caption_entities, caption_entities=caption_entities,
disable_content_type_detection=disable_content_type_detection, disable_content_type_detection=disable_content_type_detection,
disable_notification=disable_notification, disable_notification=disable_notification,
reply_parameters=reply_parameters, reply_to_message_id=reply_to_message_id,
allow_sending_without_reply=allow_sending_without_reply,
reply_markup=reply_markup reply_markup=reply_markup
) )
if isinstance(sent_update, Exception): if isinstance(sent_update, Exception):
@@ -2205,8 +2127,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
return sent_update return sent_update
async def download_file(self, file_id, 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. """Given a telegram `file_id`, download the related file.
Telegram may not preserve the original file name and MIME type: the Telegram may not preserve the original file name and MIME type: the
@@ -2216,35 +2137,26 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
file = await self.getFile(file_id=file_id) file = await self.getFile(file_id=file_id)
if file is None or isinstance(file, Exception): if file is None or isinstance(file, Exception):
logging.error(f"{file}") logging.error(f"{file}")
return file return
if self.api_url == 'https://api.telegram.org': file_bytes = await async_get(
file_bytes = await async_get( url=(
url=( f"https://api.telegram.org/file/"
f"{self.api_url}/file/" f"bot{self.token}/"
f"bot{self.token}/" f"{file['file_path']}"
f"{file['file_path']}" ),
), mode='raw'
mode='raw' )
) path = path or self.path
path = path or self.path while file_name is None:
if file_name is None: file_name = get_secure_key(length=10)
file_name = get_secure_key(length=10) if os.path.exists(f"{path}/{file_name}"):
file_complete_path = os.path.join(path, file_name) file_name = None
if prevent_overwriting: try:
while os.path.exists(file_complete_path): with open(f"{path}/{file_name}", 'wb') as local_file:
file_complete_path = file_complete_path + '1' local_file.write(file_bytes)
try: except Exception as e:
with open(file_complete_path, 'wb') as local_file: logging.error(f"File download failed due to {e}")
local_file.write(file_bytes) return
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, def translate_inline_query_answer_result(self, record,
update=None, user_record=None): update=None, user_record=None):
@@ -2853,7 +2765,9 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
""" """
if not callable(condition): if not callable(condition):
raise TypeError( raise TypeError(
f'Condition {condition.__name__} is not a callable' 'Condition {c} is not a callable'.format(
c=condition.__name__
)
) )
def query_decorator(handler): def query_decorator(handler):
@@ -3194,41 +3108,26 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
Restart bots if bot can't be got. Restart bots if bot can't be got.
""" """
for _ in range(60):
if not self._getting_me:
break
await asyncio.sleep(0.5)
else:
raise TimeoutError("Getting bot information was in progress but "
"did not make it in 30 seconds...")
if self._got_me:
return
self._getting_me = True
try: try:
me = await self.getMe() me = await self.getMe()
if isinstance(me, Exception): if isinstance(me, Exception):
raise me raise me
if me is None: elif me is None:
raise TypeError('getMe returned None') raise Exception('getMe returned None')
self._name = me["username"] self._name = me["username"]
self._telegram_id = me['id'] self._telegram_id = me['id']
except Exception as e: except Exception as e:
logging.error( logging.error(
"API getMe method failed, information about this bot could " f"API getMe method failed, information about this bot could "
"not be retrieved. Restarting in 5 minutes...\n\n" f"not be retrieved. Restarting in 5 minutes...\n\n"
"Error information:\n%s", e f"Error information:\n{e}"
) )
self._getting_me = False
await asyncio.sleep(5*60) await asyncio.sleep(5*60)
if self._got_me:
return
self.__class__.stop( self.__class__.stop(
message="Information about this bot could not be retrieved.\n" message="Information about this bot could not be retrieved.\n"
"Restarting...", "Restarting...",
final_state=65 final_state=65
) )
self._getting_me = False
self._got_me = True
def setup(self): def setup(self):
"""Make bot ask for updates and handle responses.""" """Make bot ask for updates and handle responses."""
@@ -3243,11 +3142,9 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
async def close_sessions(self): async def close_sessions(self):
"""Close open sessions.""" """Close open sessions."""
for session_name in list(self.sessions.keys()): for session_name, session in self.sessions.items():
session = self.sessions[session_name]
if not session.closed: if not session.closed:
await session.close() await session.close()
del self.sessions[session_name]
async def send_one_message(self, *args, **kwargs): async def send_one_message(self, *args, **kwargs):
sent_message = await self.send_message(*args, **kwargs) sent_message = await self.send_message(*args, **kwargs)
@@ -3598,7 +3495,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
Each bot will receive updates via long polling or webhook according to Each bot will receive updates via long polling or webhook according to
its initialization parameters. its initialization parameters.
A single aiohttp.web.Application instance will be run (cls.app) on 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: if local_host is not None:
cls.local_host = local_host cls.local_host = local_host
-10
View File
@@ -22,16 +22,6 @@ davtelepot_messages = {
} }
default_admin_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': { 'cancel': {
'button': { 'button': {
'en': "↩️ Cancel", 'en': "↩️ Cancel",
+1 -1
View File
@@ -51,7 +51,7 @@ setuptools.setup(
license=find_information("license", "davtelepot", "__init__.py"), license=find_information("license", "davtelepot", "__init__.py"),
long_description=long_description, long_description=long_description,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
url="https://gitea.davte.it/davte/davtelepot", url="https://gogs.davte.it/davte/davtelepot",
packages=setuptools.find_packages(), packages=setuptools.find_packages(),
platforms=['any'], platforms=['any'],
install_requires=[ install_requires=[