Finished working on /father command

This commit is contained in:
Davte
2020-05-07 15:07:45 +02:00
parent 9072c3abe5
commit ca6dca3cb7
2 changed files with 518 additions and 56 deletions

View File

@@ -13,6 +13,7 @@ import asyncio
import datetime
import json
import logging
import re
import types
from collections import OrderedDict
@@ -34,6 +35,8 @@ from .utilities import (
# Use this parameter in SQL `LIMIT x OFFSET y` clauses
rows_number_limit = 10
command_description_parser = re.compile(r'(?P<command>\w+)(\s?-\s?(?P<description>.*))?')
async def _forward_to(update,
bot: Bot,
@@ -1059,7 +1062,7 @@ def get_custom_commands(bot: Bot, language: str = None) -> List[dict]:
hidden=False
)
]
hidden_commands = [
hidden_commands_names = [
record['command']
for record in bot.db['bot_father_commands'].find(
cancelled=None,
@@ -1069,9 +1072,10 @@ def get_custom_commands(bot: Bot, language: str = None) -> List[dict]:
return sorted(
[
command
for command in get_current_commands(bot=bot, language=language)
if command['command'] not in hidden_commands
] + additional_commands,
for command in (get_current_commands(bot=bot, language=language)
+ additional_commands)
if command['command'] not in hidden_commands_names
],
key=(lambda c: c['command'])
)
@@ -1144,7 +1148,11 @@ def browse_bot_father_settings_records(bot: Bot,
language=language,
record_interval=((page * rows_number_limit + 1) if records else 0,
min((page + 1) * rows_number_limit, len(records)),
records_count)
records_count),
commands_list='\n'.join(
f"{'' if record['hidden'] else ''} {record['command']}"
for record in records[:rows_number_limit]
)
)
buttons = make_lines_of_buttons(
[
@@ -1154,7 +1162,7 @@ def browse_bot_father_settings_records(bot: Bot,
delimiter='|',
data=['settings', 'edit', 'select', record['id']]
)
for record in records
for record in records[:rows_number_limit]
],
3
)
@@ -1198,10 +1206,144 @@ def browse_bot_father_settings_records(bot: Bot,
return result, text, reply_markup
def get_bot_father_settings_editor(mode: str,
record: OrderedDict = None):
"""Get a coroutine to edit or create a record in bot father settings table.
Modes:
- add
- hide
"""
async def bot_father_settings_editor(bot: Bot, update: dict,
language: str):
"""Edit or create a record in bot father settings table."""
nonlocal record
if record is not None:
record_id = record['id']
else:
record_id = None
# Cancel if user used /cancel command, or remove trailing forward_slash
input_text = update['text']
if input_text.startswith('/'):
if language not in bot.messages['admin']['cancel']['lower']:
language = bot.default_language
if input_text.lower().endswith(bot.messages['admin']['cancel']['lower'][language]):
return bot.get_message(
'admin', 'cancel', 'done',
language=language
)
else:
input_text = input_text[1:]
if record is None:
# Use regex compiled pattern to search for command and description
re_search = command_description_parser.search(input_text)
if re_search is None:
return bot.get_message(
'admin', 'error', 'text',
language=language
)
re_search = re_search.groupdict()
command = re_search['command'].lower()
description = re_search['description']
else:
command = record['command']
description = input_text
error = None
# A description (str 3-256) is required
if mode in ('add', 'edit'):
if description is None or len(description) < 3:
error = 'missing_description'
elif type(description) is str and len(description) > 255:
error = 'description_too_long'
elif mode == 'add':
duplicate = bot.db['bot_father_commands'].find_one(
command=command,
cancelled=None
)
if duplicate:
error = 'duplicate_record'
if error:
text = bot.get_message(
'admin', 'father_command', 'settings', 'modes',
'add', 'error', error,
language=language
)
reply_markup = make_inline_keyboard(
[
make_button(
text=bot.get_message(
'admin', 'father_command', 'back',
language=language
),
prefix='father:///',
delimiter='|',
data=['settings']
)
]
)
else:
table = bot.db['bot_father_commands']
new_record = dict(
command=command,
description=description,
hidden=(mode == 'hide'),
cancelled=None
)
if record_id is None:
record_id = table.insert(
new_record
)
else:
new_record['id'] = record_id
table.upsert(
new_record,
['id']
)
text = bot.get_message(
'admin', 'father_command', 'settings', 'modes',
mode, ('edit' if 'id' in new_record else 'add'), 'done',
command=command,
description=(description if description else '-'),
language=language
)
reply_markup = make_inline_keyboard(
[
make_button(
text=bot.get_message(
'admin', 'father_command', 'settings', 'modes',
'edit', 'button',
language=language
),
prefix='father:///',
delimiter='|',
data=['settings', 'edit', 'select', record_id]
), make_button(
text=bot.get_message(
'admin', 'father_command', 'back',
language=language
),
prefix='father:///',
delimiter='|',
data=['settings']
)
],
2
)
asyncio.ensure_future(
bot.delete_message(update=update)
)
return dict(
text=text,
reply_markup=reply_markup
)
return bot_father_settings_editor
async def edit_bot_father_settings_via_message(bot: Bot,
user_record: OrderedDict,
language: str,
mode: str):
mode: str,
record: OrderedDict = None):
result, text, reply_markup = '', '', None
modes = bot.messages['admin']['father_command']['settings']['modes']
if mode not in modes:
@@ -1210,13 +1352,35 @@ async def edit_bot_father_settings_via_message(bot: Bot,
language=language
)
else:
result = "🚧 Not implemented yet!"
# TODO: write messages, set individual text message parser to create records
# result = bot.get_message(
# messages=modes[mode],
# language=language
# )
# bot.set_individual_text_message_handler()
result = bot.get_message(
('add' if record is None else 'edit'), 'popup',
messages=modes[mode],
language=language,
command=(record['command'] if record is not None else None)
)
text = bot.get_message(
('add' if record is None else 'edit'), 'text',
messages=modes[mode],
language=language,
command=(record['command'] if record is not None else None)
)
reply_markup = make_inline_keyboard(
[
make_button(
text=bot.get_message(
'admin', 'cancel', 'button',
language=language,
),
prefix='father:///',
delimiter='|',
data=['cancel']
)
]
)
bot.set_individual_text_message_handler(
get_bot_father_settings_editor(mode=mode, record=record),
user_id=user_record['telegram_id'],
)
return result, text, reply_markup
@@ -1231,7 +1395,24 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
"""
result, text, reply_markup = '', '', None
command, *data = data
if command == 'get':
if command == 'cancel':
bot.remove_individual_text_message_handler(user_id=user_record['telegram_id'])
result = text = bot.get_message(
'admin', 'cancel', 'done',
language=language
)
reply_markup = make_inline_keyboard(
[
make_button(
text=bot.get_message('admin', 'father_command', 'back',
language=language),
prefix='father:///',
delimiter='|',
data=['main']
)
]
)
elif command == 'get':
commands = await bot.getMyCommands()
text = '<code>' + '\n'.join(
"{c[command]} - {c[description]}".format(c=command)
@@ -1255,13 +1436,13 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
)
elif command == 'set':
stored_commands = await bot.getMyCommands()
current_commands = get_current_commands(bot=bot, language=language)
current_commands = get_custom_commands(bot=bot, language=language)
if len(data) > 0 and data[0] == 'confirm':
if not Confirmator.get('set_bot_father_commands',
confirm_timedelta=3
).confirm(user_record['id']):
return bot.get_message(
'admin', 'father_command', 'confirm',
'admin', 'confirm',
language=language
)
if stored_commands == current_commands:
@@ -1270,13 +1451,19 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
language=language
)
else:
await bot.setMyCommands(
current_commands
)
text = bot.get_message(
'admin', 'father_command', 'set', 'done',
language=language
)
if isinstance(
await bot.setMyCommands(current_commands),
Exception
):
text = bot.get_message(
'admin', 'father_command', 'set', 'error',
language=language
)
else:
text = bot.get_message(
'admin', 'father_command', 'set', 'done',
language=language
)
reply_markup = make_inline_keyboard(
[
make_button(
@@ -1289,17 +1476,24 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
]
)
else:
stored_commands_names = [c['command'] for c in stored_commands]
current_commands_names = [c['command'] for c in current_commands]
# Show preview of new, edited and removed commands
# See 'legend' in bot.messages['admin']['father_command']['set']
text = bot.get_message(
'admin', 'father_command', 'set', 'header',
language=language
) + '\n\n' + '\n\n'.join([
'\n'.join(
('' if c in stored_commands else '☑️ ') + c['command']
('' if c in stored_commands
else '☑️ ' if c['command'] not in stored_commands_names
else '✏️') + c['command']
for c in current_commands
),
'\n'.join(
f'{c["command"]}'
for c in stored_commands if c not in current_commands
f'{command}'
for command in stored_commands_names
if command not in current_commands_names
),
bot.get_message(
'admin', 'father_command', 'set', 'legend',
@@ -1387,7 +1581,108 @@ async def _father_button(bot: Bot, user_record: OrderedDict,
elif data[0] == 'edit':
if len(data) > 2 and data[1] == 'select':
selected_record = bot.db['bot_father_commands'].find_one(id=data[2])
# TODO: show selected record and actions on it
if selected_record is None:
return bot.get_message(
'admin', 'error',
language=language
)
if len(data) == 3:
text = bot.get_message(
'admin', 'father_command', 'settings',
'modes', 'edit', 'panel', 'text',
language=language,
command=selected_record['command'],
description=selected_record['description'],
)
reply_markup = make_inline_keyboard(
[
make_button(
text=bot.get_message(
'admin', 'father_command', 'settings',
'modes', 'edit', 'panel',
'edit_description', 'button',
language=language,
),
prefix='father:///',
delimiter='|',
data=['settings', 'edit', 'select',
selected_record['id'], 'edit_descr']
),
make_button(
text=bot.get_message(
'admin', 'father_command', 'settings',
'modes', 'edit', 'panel',
'delete', 'button',
language=language,
),
prefix='father:///',
delimiter='|',
data=['settings', 'edit', 'select',
selected_record['id'], 'del']
),
make_button(
text=bot.get_message(
'admin', 'father_command', 'back',
language=language,
),
prefix='father:///',
delimiter='|',
data=['settings', 'edit']
)
],
2
)
elif len(data) > 3 and data[3] == 'edit_descr':
result, text, reply_markup = await edit_bot_father_settings_via_message(
bot=bot,
user_record=user_record,
language=language,
mode=data[0],
record=selected_record
)
elif len(data) > 3 and data[3] == 'del':
if not Confirmator.get('set_bot_father_commands',
confirm_timedelta=3
).confirm(user_record['id']):
result = bot.get_message(
'admin', 'confirm',
language=language
)
else:
bot.db['bot_father_commands'].update(
dict(
id=selected_record['id'],
cancelled=True
),
['id']
)
result = bot.get_message(
'admin', 'father_command', 'settings',
'modes', 'edit', 'panel', 'delete',
'done', 'popup',
language=language
)
text = bot.get_message(
'admin', 'father_command', 'settings',
'modes', 'edit', 'panel', 'delete',
'done', 'text',
language=language
)
reply_markup = make_inline_keyboard(
[
make_button(
text=bot.get_message(
'admin', 'father_command',
'back',
language=language
),
prefix='father:///',
delimiter='|',
data=['settings']
)
],
1
)
elif len(data) == 1 or data[1] == 'go':
result, text, reply_markup = browse_bot_father_settings_records(
bot=bot,

View File

@@ -1,6 +1,24 @@
"""Default messages for bot functions."""
default_admin_messages = {
'cancel': {
'button': {
'en': "↩️ Cancel",
'it': "↩️ Annulla"
},
'done': {
'en': "↩️ Operation cancelled",
'it': "↩️ Operazione annullata",
},
'lower': {
'en': "cancel",
'it': "annulla",
},
},
'confirm': {
'en': "🔄 Click again to confirm",
'it': "🔄 Clicka di nuovo per confermare",
},
'db_command': {
'description': {
'en': "Ask for bot database via Telegram",
@@ -23,6 +41,12 @@ default_admin_messages = {
'it': "Database inviato."
}
},
'error': {
'text': {
'en': "❌️ Error!",
'it': "❌️ Errore!"
},
},
'errors_command': {
'description': {
'en': "Receive bot error log file, if set",
@@ -71,10 +95,6 @@ default_admin_messages = {
'en': "↩️ Back",
'it': "↩️ Indietro",
},
'confirm': {
'en': "🔄 Click again to confirm",
'it': "🔄 Clicka di nuovo per confermare",
},
'description': {
'en': "Edit the @BotFather commands",
'it': "Modifica i comandi con @BotFather",
@@ -130,6 +150,10 @@ default_admin_messages = {
'en': "✅ Done!",
'it': "✅ Fatto!",
},
'error': {
'en': "Something went wrong 😕",
'it': "Qualcosa è andato storto 😕",
},
'header': {
'en': "✏️ <b>Change commands stored by @BotFather 🤖</b>",
'it': "✏️ <b>Modifica i comandi salvati su @BotFather 🤖</b>",
@@ -137,12 +161,14 @@ default_admin_messages = {
'legend': {
'en': "<b>Legend</b>\n"
"✅ <i>Already stored</i>\n"
"✏️ <i>New description</i>\n"
"☑ <i>New command</i>\n"
"❌ <i>Will be removed</i>",
'it': "<b>Legenda</b>\n"
"✅ <i>Già presente</i>\n"
"✏️ <i>Nuova descrizione</i>\n"
"☑ <i>Nuovo comando</i>\n"
"❌ <i>Comando eliminato</i>",
"❌ <i>Comando da eliminare</i>",
},
'no_change': {
'en': "❌ No change detected",
@@ -152,53 +178,194 @@ default_admin_messages = {
'settings': {
'browse_records': {
'en': "✏️ <b>Edit BotFather settings</b> ⚙️\n\n"
"Select a record to edit.\n"
"Showing records from {record_interval[0]} to "
"{record_interval[1]} of {record_interval[2]}\n\n"
"Select a record to edit.\n\n"
"{commands_list}\n\n"
"<i>Legend</i>\n"
" Added commands\n"
" Hidden commands\n",
" Hidden commands\n\n"
"Showing records from {record_interval[0]} to "
"{record_interval[1]} of {record_interval[2]}",
'it': "✏️ <b>Modifica impostazioni di BotFather</b> ⚙\n\n"
"Seleziona un'impostazione da modificare.\n"
"Record da {record_interval[0]} a "
"{record_interval[1]} di {record_interval[2]}\n\n"
"Seleziona un'impostazione da modificare.\n\n"
"{commands_list}\n\n"
"<i>Legenda</i>\n"
" Comandi aggiunti\n"
" Comandi nascosti\n",
" Comandi nascosti\n\n"
"Record da {record_interval[0]} a "
"{record_interval[1]} di {record_interval[2]}",
},
'modes': {
'add': {
'symbol': "",
'name': {
'en': "Add",
'it': "Aggiungi"
'add': {
'done': {
'en': " <b>Added additional command</b>\n\n"
"Command: {command}\n"
"Description: {description}",
'it': " <b>Inserito comando aggiuntivo</b>\n\n"
"Comando: {command}\n"
"Descrizione: {description}",
},
'popup': {
'en': "Write the command to add",
'it': "Scrivimi il comando da aggiungere",
},
'text': {
'en': "Write the command to add or /cancel this operation",
'it': "Scrivimi il comando da aggiungere o /annulla",
},
},
'description': {
'en': "Add command to default list",
'it': "Aggiungi un comando dalla lista autogenerata"
}
},
'edit': {
'done': {
'en': "✏️ <b>Edited additional command</b>\n\n"
"Command: {command}\n"
"Description: {description}",
'it': "✏️ <b>Comando da nascondere modificato</b>\n\n"
"Comando: {command}\n"
"Descrizione: {description}",
},
},
'error': {
'description_too_long': {
'en': "<b>Description is too long</b>\n\n"
"Description length must be 3-256 chars.",
'it': "<b>Descrizione troppo lunga</b>\n\n"
"La descrizione deve essere di 3-256 caratteri.",
},
'duplicate_record': {
'en': "<b>Duplicate record</b>\n\n"
"Command is already being added to default "
"output. Edit that record if you need to.",
'it': "<b>Record già presente</b>\n\n"
"Questo comando è già aggiunto a quelli di "
"default. Modifica il record già presente se "
"necessario.",
},
'missing_description': {
'en': "<b>Missing description</b>\n\n"
"Additional commands must have a description "
"(3-256 chars).",
'it': "<b>Descrizione mancante</b>\n\n"
"I comandi aggiuntivi devono avere una "
"descrizione di 3-256 caratteri.",
},
'unhandled_exception': {
'en': "❌ <b>Unhandled exception </b> ⚠️",
'it': "❌ <b>Errore imprevisto </b> ⚠️",
},
},
'name': {
'en': "Add",
'it': "Aggiungi"
},
'symbol': "",
},
'hide': {
'symbol': "",
'name': {
'en': "Hide",
'it': "Nascondi"
'add': {
'done': {
'en': " <b>Added hidden command</b>\n\n"
"Command: {command}\n",
'it': " <b>Comando da nascondere aggiunto</b>"
"Comando: {command}\n",
},
'popup': {
'en': "Write the command to hide",
'it': "Scrivimi il comando da nascondere",
},
'text': {
'en': "Write the command to hide or /cancel this operation",
'it': "Scrivimi il comando da nascondere o /annulla",
}
},
'description': {
'en': "Hide command from default list",
'it': "Nascondi un comando dalla lista autogenerata"
}
},
'edit': {
'done': {
'en': "✏️ <b>Edited hidden command</b>\n\n"
"Command: {command}\n"
"Description: {description}",
'it': "✏️ <b>Comando da nascondere modificato</b>\n\n"
"Comando: {command}\n"
"Descrizione: {description}",
},
},
'name': {
'en': "Hide",
'it': "Nascondi"
},
'symbol': "",
},
'edit': {
'symbol': "✏️",
'name': {
'en': "Edit",
'it': "Modifica"
'button': {
'en': "✏️ Edit record",
'it': "✏️ Modifica record"
},
'description': {
'en': "Edit added or hidden commands",
'it': "Modifica i comandi aggiunti o nascosti"
}
},
'edit': {
'popup': {
'en': "Write the new description",
'it': "Scrivimi la nuova descrizione",
},
'text': {
'en': "Write the new description for command "
"{command} or /cancel",
'it': "Scrivimi la nuova descrizione per il "
"comando {command} o /annulla",
},
'done': {
'en': "✏️ Edit succeeded ✅\n\n"
"Command: {command}\n"""
"Description: {description}",
'it': "✏️ Modifica completata ✅\n\n"
"Comando: {command}\n"""
"Descrizione: {description}",
}
},
'name': {
'en': "Edit",
'it': "Modifica"
},
'panel': {
'delete': {
'button': {
'en': "❌ Delete record",
'it': "❌ Elimina record",
},
'done': {
'popup': {
'en': "Record deleted ✅",
'it': "Record eliminato ✅",
},
'text': {
'en': "Record deleted ✅",
'it': "Record eliminato ✅",
},
},
},
'edit_description': {
'button': {
'en': "✏️ Edit description",
'it': "✏️ Modifica descrizione",
},
},
'text': {
'en': "✏️ Edit record ✅\n\n"
"Command: {command}\n"""
"Description: {description}",
'it': "✏️ Modifica record\n\n"
"Comando: {command}\n"""
"Descrizione: {description}",
},
},
'symbol': "✏️",
},
},
'panel': {