mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Merge branch 'dev-2.x' into dev-2.x
This commit is contained in:
commit
23ceb1445e
47 changed files with 952 additions and 848 deletions
|
|
@ -1,4 +1,3 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import random
|
||||
import uuid
|
||||
|
|
@ -21,12 +20,12 @@ dp.middleware.setup(LoggingMiddleware())
|
|||
|
||||
POSTS = {
|
||||
str(uuid.uuid4()): {
|
||||
'title': f"Post {index}",
|
||||
'title': f'Post {index}',
|
||||
'body': 'Lorem ipsum dolor sit amet, '
|
||||
'consectetur adipiscing elit, '
|
||||
'sed do eiusmod tempor incididunt ut '
|
||||
'labore et dolore magna aliqua',
|
||||
'votes': random.randint(-2, 5)
|
||||
'votes': random.randint(-2, 5),
|
||||
} for index in range(1, 6)
|
||||
}
|
||||
|
||||
|
|
@ -42,21 +41,24 @@ def get_keyboard() -> types.InlineKeyboardMarkup:
|
|||
markup.add(
|
||||
types.InlineKeyboardButton(
|
||||
post['title'],
|
||||
callback_data=posts_cb.new(id=post_id, action='view'))
|
||||
callback_data=posts_cb.new(id=post_id, action='view')),
|
||||
)
|
||||
return markup
|
||||
|
||||
|
||||
def format_post(post_id: str, post: dict) -> (str, types.InlineKeyboardMarkup):
|
||||
text = f"{md.hbold(post['title'])}\n" \
|
||||
f"{md.quote_html(post['body'])}\n" \
|
||||
f"\n" \
|
||||
f"Votes: {post['votes']}"
|
||||
text = md.text(
|
||||
md.hbold(post['title']),
|
||||
md.quote_html(post['body']),
|
||||
'', # just new empty line
|
||||
f"Votes: {post['votes']}",
|
||||
sep = '\n',
|
||||
)
|
||||
|
||||
markup = types.InlineKeyboardMarkup()
|
||||
markup.row(
|
||||
types.InlineKeyboardButton('👍', callback_data=posts_cb.new(id=post_id, action='like')),
|
||||
types.InlineKeyboardButton('👎', callback_data=posts_cb.new(id=post_id, action='unlike')),
|
||||
types.InlineKeyboardButton('👎', callback_data=posts_cb.new(id=post_id, action='dislike')),
|
||||
)
|
||||
markup.add(types.InlineKeyboardButton('<< Back', callback_data=posts_cb.new(id='-', action='list')))
|
||||
return text, markup
|
||||
|
|
@ -84,7 +86,7 @@ async def query_view(query: types.CallbackQuery, callback_data: dict):
|
|||
await query.message.edit_text(text, reply_markup=markup)
|
||||
|
||||
|
||||
@dp.callback_query_handler(posts_cb.filter(action=['like', 'unlike']))
|
||||
@dp.callback_query_handler(posts_cb.filter(action=['like', 'dislike']))
|
||||
async def query_post_vote(query: types.CallbackQuery, callback_data: dict):
|
||||
try:
|
||||
await dp.throttle('vote', rate=1)
|
||||
|
|
@ -100,10 +102,10 @@ async def query_post_vote(query: types.CallbackQuery, callback_data: dict):
|
|||
|
||||
if action == 'like':
|
||||
post['votes'] += 1
|
||||
elif action == 'unlike':
|
||||
elif action == 'dislike':
|
||||
post['votes'] -= 1
|
||||
|
||||
await query.answer('Voted.')
|
||||
await query.answer('Vote accepted')
|
||||
text, markup = format_post(post_id, post)
|
||||
await query.message.edit_text(text, reply_markup=markup)
|
||||
|
||||
|
|
@ -114,4 +116,4 @@ async def message_not_modified_handler(update, error):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
executor.start_polling(dp, loop=loop, skip_updates=True)
|
||||
executor.start_polling(dp, skip_updates=True)
|
||||
|
|
|
|||
|
|
@ -27,42 +27,40 @@ likes = {} # user_id: amount_of_likes
|
|||
def get_keyboard():
|
||||
return types.InlineKeyboardMarkup().row(
|
||||
types.InlineKeyboardButton('👍', callback_data=vote_cb.new(action='up')),
|
||||
types.InlineKeyboardButton('👎', callback_data=vote_cb.new(action='down')))
|
||||
types.InlineKeyboardButton('👎', callback_data=vote_cb.new(action='down')),
|
||||
)
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
async def cmd_start(message: types.Message):
|
||||
amount_of_likes = likes.get(message.from_user.id, 0) # get value if key exists else set to 0
|
||||
await message.reply(f'Vote! Now you have {amount_of_likes} votes.', reply_markup=get_keyboard())
|
||||
await message.reply(f'Vote! You have {amount_of_likes} votes now.', reply_markup=get_keyboard())
|
||||
|
||||
|
||||
@dp.callback_query_handler(vote_cb.filter(action='up'))
|
||||
async def vote_up_cb_handler(query: types.CallbackQuery, callback_data: dict):
|
||||
logging.info(callback_data) # callback_data contains all info from callback data
|
||||
likes[query.from_user.id] = likes.get(query.from_user.id, 0) + 1 # update amount of likes in storage
|
||||
amount_of_likes = likes[query.from_user.id]
|
||||
@dp.callback_query_handler(vote_cb.filter(action=['up', 'down']))
|
||||
async def callback_vote_action(query: types.CallbackQuery, callback_data: dict):
|
||||
logging.info('Got this callback data: %r', callback_data) # callback_data contains all info from callback data
|
||||
await query.answer() # don't forget to answer callback query as soon as possible
|
||||
callback_data_action = callback_data['action']
|
||||
likes_count = likes.get(query.from_user.id, 0)
|
||||
|
||||
await bot.edit_message_text(f'You voted up! Now you have {amount_of_likes} votes.',
|
||||
query.from_user.id,
|
||||
query.message.message_id,
|
||||
reply_markup=get_keyboard())
|
||||
if callback_data_action == 'up':
|
||||
likes_count += 1
|
||||
else:
|
||||
likes_count -= 1
|
||||
|
||||
likes[query.from_user.id] = likes_count # update amount of likes in storage
|
||||
|
||||
@dp.callback_query_handler(vote_cb.filter(action='down'))
|
||||
async def vote_down_cb_handler(query: types.CallbackQuery, callback_data: dict):
|
||||
logging.info(callback_data) # callback_data contains all info from callback data
|
||||
likes[query.from_user.id] = likes.get(query.from_user.id, 0) - 1 # update amount of likes in storage
|
||||
amount_of_likes = likes[query.from_user.id]
|
||||
|
||||
await bot.edit_message_text(f'You voted down! Now you have {amount_of_likes} votes.',
|
||||
query.from_user.id,
|
||||
query.message.message_id,
|
||||
reply_markup=get_keyboard())
|
||||
await bot.edit_message_text(
|
||||
f'You voted {callback_data_action}! Now you have {likes_count} vote[s].',
|
||||
query.from_user.id,
|
||||
query.message.message_id,
|
||||
reply_markup=get_keyboard(),
|
||||
)
|
||||
|
||||
|
||||
@dp.errors_handler(exception=MessageNotModified) # handle the cases when this exception raises
|
||||
async def message_not_modified_handler(update, error):
|
||||
# pass
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
Babel is required.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiogram import Bot, Dispatcher, executor, md, types
|
||||
|
|
@ -22,12 +21,13 @@ async def check_language(message: types.Message):
|
|||
|
||||
await message.reply(md.text(
|
||||
md.bold('Info about your language:'),
|
||||
md.text(' 🔸', md.bold('Code:'), md.italic(locale.locale)),
|
||||
md.text(' 🔸', md.bold('Territory:'), md.italic(locale.territory or 'Unknown')),
|
||||
md.text(' 🔸', md.bold('Language name:'), md.italic(locale.language_name)),
|
||||
md.text(' 🔸', md.bold('English language name:'), md.italic(locale.english_name)),
|
||||
sep='\n'))
|
||||
md.text('🔸', md.bold('Code:'), md.code(locale.language)),
|
||||
md.text('🔸', md.bold('Territory:'), md.code(locale.territory or 'Unknown')),
|
||||
md.text('🔸', md.bold('Language name:'), md.code(locale.language_name)),
|
||||
md.text('🔸', md.bold('English language name:'), md.code(locale.english_name)),
|
||||
sep='\n',
|
||||
))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
executor.start_polling(dp, loop=loop, skip_updates=True)
|
||||
executor.start_polling(dp, skip_updates=True)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ dp = Dispatcher(bot)
|
|||
@dp.message_handler(commands=['start', 'help'])
|
||||
async def send_welcome(message: types.Message):
|
||||
"""
|
||||
This handler will be called when client send `/start` or `/help` commands.
|
||||
This handler will be called when user sends `/start` or `/help` command
|
||||
"""
|
||||
await message.reply("Hi!\nI'm EchoBot!\nPowered by aiogram.")
|
||||
|
||||
|
|
@ -28,13 +28,25 @@ async def send_welcome(message: types.Message):
|
|||
@dp.message_handler(regexp='(^cat[s]?$|puss)')
|
||||
async def cats(message: types.Message):
|
||||
with open('data/cats.jpg', 'rb') as photo:
|
||||
await bot.send_photo(message.chat.id, photo, caption='Cats is here 😺',
|
||||
reply_to_message_id=message.message_id)
|
||||
'''
|
||||
# Old fashioned way:
|
||||
await bot.send_photo(
|
||||
message.chat.id,
|
||||
photo,
|
||||
caption='Cats are here 😺',
|
||||
reply_to_message_id=message.message_id,
|
||||
)
|
||||
'''
|
||||
|
||||
await message.reply_photo(photo, caption='Cats are here 😺')
|
||||
|
||||
|
||||
@dp.message_handler()
|
||||
async def echo(message: types.Message):
|
||||
await bot.send_message(message.chat.id, message.text)
|
||||
# old style:
|
||||
# await bot.send_message(message.chat.id, message.text)
|
||||
|
||||
await message.reply(message.text, reply=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
import asyncio
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
import aiogram.utils.markdown as md
|
||||
from aiogram import Bot, Dispatcher, types
|
||||
from aiogram.contrib.fsm_storage.memory import MemoryStorage
|
||||
from aiogram.dispatcher import FSMContext
|
||||
from aiogram.dispatcher.filters import Text
|
||||
from aiogram.dispatcher.filters.state import State, StatesGroup
|
||||
from aiogram.types import ParseMode
|
||||
from aiogram.utils import executor
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
|
||||
# For example use simple MemoryStorage for Dispatcher.
|
||||
|
|
@ -25,7 +28,7 @@ class Form(StatesGroup):
|
|||
gender = State() # Will be represented in storage as 'Form:gender'
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
@dp.message_handler(commands='start')
|
||||
async def cmd_start(message: types.Message):
|
||||
"""
|
||||
Conversation's entry point
|
||||
|
|
@ -37,19 +40,21 @@ async def cmd_start(message: types.Message):
|
|||
|
||||
|
||||
# You can use state '*' if you need to handle all states
|
||||
@dp.message_handler(state='*', commands=['cancel'])
|
||||
@dp.message_handler(lambda message: message.text.lower() == 'cancel', state='*')
|
||||
async def cancel_handler(message: types.Message, state: FSMContext, raw_state: Optional[str] = None):
|
||||
@dp.message_handler(state='*', commands='cancel')
|
||||
@dp.message_handler(Text(equals='cancel', ignore_case=True), state='*')
|
||||
async def cancel_handler(message: types.Message, state: FSMContext):
|
||||
"""
|
||||
Allow user to cancel any action
|
||||
"""
|
||||
if raw_state is None:
|
||||
current_state = await state.get_state()
|
||||
if current_state is None:
|
||||
return
|
||||
|
||||
logging.info('Cancelling state %r', current_state)
|
||||
# Cancel state and inform user about it
|
||||
await state.finish()
|
||||
# And remove keyboard (just in case)
|
||||
await message.reply('Canceled.', reply_markup=types.ReplyKeyboardRemove())
|
||||
await message.reply('Cancelled.', reply_markup=types.ReplyKeyboardRemove())
|
||||
|
||||
|
||||
@dp.message_handler(state=Form.name)
|
||||
|
|
@ -66,7 +71,7 @@ async def process_name(message: types.Message, state: FSMContext):
|
|||
|
||||
# Check age. Age gotta be digit
|
||||
@dp.message_handler(lambda message: not message.text.isdigit(), state=Form.age)
|
||||
async def failed_process_age(message: types.Message):
|
||||
async def process_age_invalid(message: types.Message):
|
||||
"""
|
||||
If age is invalid
|
||||
"""
|
||||
|
|
@ -88,11 +93,11 @@ async def process_age(message: types.Message, state: FSMContext):
|
|||
|
||||
|
||||
@dp.message_handler(lambda message: message.text not in ["Male", "Female", "Other"], state=Form.gender)
|
||||
async def failed_process_gender(message: types.Message):
|
||||
async def process_gender_invalid(message: types.Message):
|
||||
"""
|
||||
In this example gender has to be one of: Male, Female, Other.
|
||||
"""
|
||||
return await message.reply("Bad gender name. Choose you gender from keyboard.")
|
||||
return await message.reply("Bad gender name. Choose your gender from the keyboard.")
|
||||
|
||||
|
||||
@dp.message_handler(state=Form.gender)
|
||||
|
|
@ -104,11 +109,17 @@ async def process_gender(message: types.Message, state: FSMContext):
|
|||
markup = types.ReplyKeyboardRemove()
|
||||
|
||||
# And send message
|
||||
await bot.send_message(message.chat.id, md.text(
|
||||
md.text('Hi! Nice to meet you,', md.bold(data['name'])),
|
||||
md.text('Age:', data['age']),
|
||||
md.text('Gender:', data['gender']),
|
||||
sep='\n'), reply_markup=markup, parse_mode=ParseMode.MARKDOWN)
|
||||
await bot.send_message(
|
||||
message.chat.id,
|
||||
md.text(
|
||||
md.text('Hi! Nice to meet you,', md.bold(data['name'])),
|
||||
md.text('Age:', md.code(data['age'])),
|
||||
md.text('Gender:', data['gender']),
|
||||
sep='\n',
|
||||
),
|
||||
reply_markup=markup,
|
||||
parse_mode=ParseMode.MARKDOWN,
|
||||
)
|
||||
|
||||
# Finish conversation
|
||||
await state.finish()
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from pathlib import Path
|
|||
from aiogram import Bot, Dispatcher, executor, types
|
||||
from aiogram.contrib.middlewares.i18n import I18nMiddleware
|
||||
|
||||
TOKEN = 'BOT TOKEN HERE'
|
||||
TOKEN = 'BOT_TOKEN_HERE'
|
||||
I18N_DOMAIN = 'mybot'
|
||||
|
||||
BASE_DIR = Path(__file__).parent
|
||||
|
|
@ -54,14 +54,16 @@ dp.middleware.setup(i18n)
|
|||
_ = i18n.gettext
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
@dp.message_handler(commands='start')
|
||||
async def cmd_start(message: types.Message):
|
||||
# Simply use `_('message')` instead of `'message'` and never use f-strings for translatable texts.
|
||||
await message.reply(_('Hello, <b>{user}</b>!').format(user=message.from_user.full_name))
|
||||
|
||||
|
||||
@dp.message_handler(commands=['lang'])
|
||||
@dp.message_handler(commands='lang')
|
||||
async def cmd_lang(message: types.Message, locale):
|
||||
# For setting custom lang you have to modify i18n middleware, like this:
|
||||
# https://github.com/aiogram/EventsTrackerBot/blob/master/modules/base/middlewares.py
|
||||
await message.reply(_('Your current language: <i>{language}</i>').format(language=locale))
|
||||
|
||||
# If you care about pluralization, here's small handler
|
||||
|
|
@ -70,15 +72,27 @@ async def cmd_lang(message: types.Message, locale):
|
|||
# Alias for gettext method, parser will understand double underscore as plural (aka ngettext)
|
||||
__ = i18n.gettext
|
||||
|
||||
# Some pseudo numeric value
|
||||
TOTAL_LIKES = 0
|
||||
|
||||
@dp.message_handler(commands=['like'])
|
||||
# some likes manager
|
||||
LIKES_STORAGE = {'count': 0}
|
||||
|
||||
|
||||
def get_likes() -> int:
|
||||
return LIKES_STORAGE['count']
|
||||
|
||||
|
||||
def increase_likes() -> int:
|
||||
LIKES_STORAGE['count'] += 1
|
||||
return get_likes()
|
||||
#
|
||||
|
||||
|
||||
@dp.message_handler(commands='like')
|
||||
async def cmd_like(message: types.Message, locale):
|
||||
TOTAL_LIKES += 1
|
||||
likes = increase_likes()
|
||||
|
||||
# NOTE: This is comment for a translator
|
||||
await message.reply(__('Aiogram has {number} like!', 'Aiogram has {number} likes!', TOTAL_LIKES).format(number=TOTAL_LIKES))
|
||||
await message.reply(__('Aiogram has {number} like!', 'Aiogram has {number} likes!', likes).format(number=likes))
|
||||
|
||||
if __name__ == '__main__':
|
||||
executor.start_polling(dp, skip_updates=True)
|
||||
|
|
|
|||
|
|
@ -1,37 +1,35 @@
|
|||
from aiogram import Bot, Dispatcher, executor, types
|
||||
from aiogram.dispatcher.handler import SkipHandler
|
||||
|
||||
API_TOKEN = 'API_TOKE_HERE'
|
||||
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
bot = Bot(token=API_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
user_id_to_test = None # todo: Set id here
|
||||
chat_id_to_test = user_id_to_test
|
||||
user_id_required = None # TODO: Set id here
|
||||
chat_id_required = user_id_required # Change for use in groups (user_id == chat_id in pm)
|
||||
|
||||
|
||||
@dp.message_handler(user_id=user_id_to_test)
|
||||
@dp.message_handler(user_id=user_id_required)
|
||||
async def handler1(msg: types.Message):
|
||||
await bot.send_message(msg.chat.id,
|
||||
"Hello, checking with user_id=")
|
||||
raise SkipHandler
|
||||
await bot.send_message(msg.chat.id, "Hello, checking with user_id=")
|
||||
raise SkipHandler # just for demo
|
||||
|
||||
|
||||
@dp.message_handler(chat_id=chat_id_to_test)
|
||||
@dp.message_handler(chat_id=chat_id_required)
|
||||
async def handler2(msg: types.Message):
|
||||
await bot.send_message(msg.chat.id,
|
||||
"Hello, checking with chat_id=")
|
||||
raise SkipHandler
|
||||
await bot.send_message(msg.chat.id, "Hello, checking with chat_id=")
|
||||
raise SkipHandler # just for demo
|
||||
|
||||
|
||||
@dp.message_handler(user_id=user_id_to_test, chat_id=chat_id_to_test)
|
||||
@dp.message_handler(user_id=user_id_required, chat_id=chat_id_required)
|
||||
async def handler3(msg: types.Message):
|
||||
await bot.send_message(msg.chat.id,
|
||||
"Hello from user= & chat_id=")
|
||||
await msg.reply("Hello from user= & chat_id=", reply=False)
|
||||
|
||||
|
||||
@dp.message_handler(user_id=[user_id_to_test, 123]) # todo: add second id here
|
||||
@dp.message_handler(user_id=[user_id_required, 42]) # TODO: You can add any number of ids here
|
||||
async def handler4(msg: types.Message):
|
||||
print("Checked user_id with list!")
|
||||
await msg.reply("Checked user_id with list!", reply=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import asyncio
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from aiogram import Bot, types, Dispatcher, executor
|
||||
from aiogram import Bot, Dispatcher, executor
|
||||
from aiogram.types import InlineQuery, \
|
||||
InputTextMessageContent, InlineQueryResultArticle
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
|
@ -12,10 +14,22 @@ dp = Dispatcher(bot)
|
|||
|
||||
|
||||
@dp.inline_handler()
|
||||
async def inline_echo(inline_query: types.InlineQuery):
|
||||
input_content = types.InputTextMessageContent(inline_query.query or 'echo')
|
||||
item = types.InlineQueryResultArticle(id='1', title='echo',
|
||||
input_message_content=input_content)
|
||||
async def inline_echo(inline_query: InlineQuery):
|
||||
# id affects both preview and content,
|
||||
# so it has to be unique for each result
|
||||
# (Unique identifier for this result, 1-64 Bytes)
|
||||
# you can set your unique id's
|
||||
# but for example i'll generate it based on text because I know, that
|
||||
# only text will be passed in this example
|
||||
text = inline_query.query or 'echo'
|
||||
input_content = InputTextMessageContent(text)
|
||||
result_id: str = hashlib.md5(text.encode()).hexdigest()
|
||||
item = InlineQueryResultArticle(
|
||||
id=result_id,
|
||||
title=f'Result {text!r}',
|
||||
input_message_content=input_content,
|
||||
)
|
||||
# don't forget to set cache_time=1 for testing (default is 300s or 5m)
|
||||
await bot.answer_inline_query(inline_query.id, results=[item], cache_time=1)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,50 +6,56 @@ import logging
|
|||
|
||||
from aiogram import Bot, Dispatcher, executor, types
|
||||
|
||||
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Initialize bot and dispatcher
|
||||
bot = Bot(token=API_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
@dp.message_handler(commands='start')
|
||||
async def start_cmd_handler(message: types.Message):
|
||||
keyboard_markup = types.InlineKeyboardMarkup(row_width=3)
|
||||
# default row_width is 3, so here we can omit it actually
|
||||
# kept for clearness
|
||||
|
||||
keyboard_markup.row(types.InlineKeyboardButton("Yes!", callback_data='yes'),
|
||||
# in real life for the callback_data the callback data factory should be used
|
||||
# here the raw string is used for the simplicity
|
||||
types.InlineKeyboardButton("No!", callback_data='no'))
|
||||
text_and_data = (
|
||||
('Yes!', 'yes'),
|
||||
('No!', 'no'),
|
||||
)
|
||||
# in real life for the callback_data the callback data factory should be used
|
||||
# here the raw string is used for the simplicity
|
||||
row_btns = (types.InlineKeyboardButton(text, callback_data=data) for text, data in text_and_data)
|
||||
|
||||
keyboard_markup.add(types.InlineKeyboardButton("aiogram link",
|
||||
url='https://github.com/aiogram/aiogram'))
|
||||
# url buttons has no callback data
|
||||
keyboard_markup.row(*row_btns)
|
||||
keyboard_markup.add(
|
||||
# url buttons have no callback data
|
||||
types.InlineKeyboardButton('aiogram source', url='https://github.com/aiogram/aiogram'),
|
||||
)
|
||||
|
||||
await message.reply("Hi!\nDo you love aiogram?", reply_markup=keyboard_markup)
|
||||
|
||||
|
||||
@dp.callback_query_handler(lambda cb: cb.data in ['yes', 'no']) # if cb.data is either 'yes' or 'no'
|
||||
# @dp.callback_query_handler(text='yes') # if cb.data == 'yes'
|
||||
# Use multiple registrators. Handler will execute when one of the filters is OK
|
||||
@dp.callback_query_handler(text='no') # if cb.data == 'no'
|
||||
@dp.callback_query_handler(text='yes') # if cb.data == 'yes'
|
||||
async def inline_kb_answer_callback_handler(query: types.CallbackQuery):
|
||||
await query.answer() # send answer to close the rounding circle
|
||||
|
||||
answer_data = query.data
|
||||
logger.debug(f"answer_data={answer_data}")
|
||||
# here we can work with query.data
|
||||
# always answer callback queries, even if you have nothing to say
|
||||
await query.answer(f'You answered with {answer_data!r}')
|
||||
|
||||
if answer_data == 'yes':
|
||||
await bot.send_message(query.from_user.id, "That's great!")
|
||||
text = 'Great, me too!'
|
||||
elif answer_data == 'no':
|
||||
await bot.send_message(query.from_user.id, "Oh no...Why so?")
|
||||
text = 'Oh no...Why so?'
|
||||
else:
|
||||
await bot.send_message(query.from_user.id, "Invalid callback data!")
|
||||
text = f'Unexpected callback data {answer_data!r}!'
|
||||
|
||||
await bot.send_message(query.from_user.id, text)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -1,31 +1,26 @@
|
|||
# Translations template for PROJECT.
|
||||
# Copyright (C) 2018 ORGANIZATION
|
||||
# Copyright (C) 2019 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2018-06-30 03:50+0300\n"
|
||||
"POT-Creation-Date: 2019-08-10 17:51+0300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.6.0\n"
|
||||
"Generated-By: Babel 2.7.0\n"
|
||||
|
||||
#: i18n_example.py:48
|
||||
#: i18n_example.py:60
|
||||
msgid "Hello, <b>{user}</b>!"
|
||||
msgstr ""
|
||||
|
||||
#: i18n_example.py:53
|
||||
#: i18n_example.py:67
|
||||
msgid "Your current language: <i>{language}</i>"
|
||||
msgstr ""
|
||||
|
||||
msgid "Aiogram has {number} like!"
|
||||
msgid_plural "Aiogram has {number} likes!"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
# Russian translations for PROJECT.
|
||||
# Copyright (C) 2018 ORGANIZATION
|
||||
# Copyright (C) 2019 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2018-06-30 03:50+0300\n"
|
||||
"PO-Revision-Date: 2018-06-30 03:43+0300\n"
|
||||
"POT-Creation-Date: 2019-08-10 17:51+0300\n"
|
||||
"PO-Revision-Date: 2019-08-10 17:52+0300\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: ru\n"
|
||||
"Language-Team: ru <LL@li.org>\n"
|
||||
|
|
@ -17,18 +17,19 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.6.0\n"
|
||||
"Generated-By: Babel 2.7.0\n"
|
||||
|
||||
#: i18n_example.py:48
|
||||
#: i18n_example.py:60
|
||||
msgid "Hello, <b>{user}</b>!"
|
||||
msgstr "Привет, <b>{user}</b>!"
|
||||
|
||||
#: i18n_example.py:53
|
||||
#: i18n_example.py:67
|
||||
msgid "Your current language: <i>{language}</i>"
|
||||
msgstr "Твой язык: <i>{language}</i>"
|
||||
|
||||
#: i18n_example.py:95
|
||||
msgid "Aiogram has {number} like!"
|
||||
msgid_plural "Aiogram has {number} likes!"
|
||||
msgstr[0] "Aiogram имеет {number} лайк!"
|
||||
msgstr[1] "Aiogram имеет {number} лайка!"
|
||||
msgstr[2] "Aiogram имеет {number} лайков!"
|
||||
msgstr[2] "Aiogram имеет {number} лайков!"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import asyncio
|
|||
|
||||
from aiogram import Bot, Dispatcher, executor, filters, types
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
|
|
@ -13,10 +14,10 @@ async def send_welcome(message: types.Message):
|
|||
# So... At first I want to send something like this:
|
||||
await message.reply("Do you want to see many pussies? Are you ready?")
|
||||
|
||||
# And wait few seconds...
|
||||
# Wait a little...
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# Good bots should send chat actions. Or not.
|
||||
# Good bots should send chat actions...
|
||||
await types.ChatActions.upload_photo()
|
||||
|
||||
# Create media group
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from aiogram.dispatcher.handler import CancelHandler, current_handler
|
|||
from aiogram.dispatcher.middlewares import BaseMiddleware
|
||||
from aiogram.utils.exceptions import Throttled
|
||||
|
||||
TOKEN = 'BOT TOKEN HERE'
|
||||
TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
# In this example Redis storage is used
|
||||
storage = RedisStorage2(db=5)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import asyncio
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram import types
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.types.message import ContentTypes
|
||||
from aiogram.utils import executor
|
||||
|
||||
BOT_TOKEN = 'BOT TOKEN HERE'
|
||||
PAYMENTS_PROVIDER_TOKEN = '123456789:TEST:1234567890abcdef1234567890abcdef'
|
||||
|
||||
BOT_TOKEN = 'BOT_TOKEN_HERE'
|
||||
PAYMENTS_PROVIDER_TOKEN = '123456789:TEST:1422'
|
||||
|
||||
bot = Bot(BOT_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
|
|
@ -15,13 +14,13 @@ dp = Dispatcher(bot)
|
|||
# Setup prices
|
||||
prices = [
|
||||
types.LabeledPrice(label='Working Time Machine', amount=5750),
|
||||
types.LabeledPrice(label='Gift wrapping', amount=500)
|
||||
types.LabeledPrice(label='Gift wrapping', amount=500),
|
||||
]
|
||||
|
||||
# Setup shipping options
|
||||
shipping_options = [
|
||||
types.ShippingOption(id='instant', title='WorldWide Teleporter').add(types.LabeledPrice('Teleporter', 1000)),
|
||||
types.ShippingOption(id='pickup', title='Local pickup').add(types.LabeledPrice('Pickup', 300))
|
||||
types.ShippingOption(id='pickup', title='Local pickup').add(types.LabeledPrice('Pickup', 300)),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -59,7 +58,7 @@ async def cmd_buy(message: types.Message):
|
|||
' Order our Working Time Machine today!',
|
||||
provider_token=PAYMENTS_PROVIDER_TOKEN,
|
||||
currency='usd',
|
||||
photo_url='https://images.fineartamerica.com/images-medium-large/2-the-time-machine-dmitriy-khristenko.jpg',
|
||||
photo_url='https://telegra.ph/file/d08ff863531f10bf2ea4b.jpg',
|
||||
photo_height=512, # !=0/None or picture won't be shown
|
||||
photo_width=512,
|
||||
photo_size=512,
|
||||
|
|
@ -69,14 +68,14 @@ async def cmd_buy(message: types.Message):
|
|||
payload='HAPPY FRIDAYS COUPON')
|
||||
|
||||
|
||||
@dp.shipping_query_handler(func=lambda query: True)
|
||||
@dp.shipping_query_handler(lambda query: True)
|
||||
async def shipping(shipping_query: types.ShippingQuery):
|
||||
await bot.answer_shipping_query(shipping_query.id, ok=True, shipping_options=shipping_options,
|
||||
error_message='Oh, seems like our Dog couriers are having a lunch right now.'
|
||||
' Try again later!')
|
||||
|
||||
|
||||
@dp.pre_checkout_query_handler(func=lambda query: True)
|
||||
@dp.pre_checkout_query_handler(lambda query: True)
|
||||
async def checkout(pre_checkout_query: types.PreCheckoutQuery):
|
||||
await bot.answer_pre_checkout_query(pre_checkout_query.id, ok=True,
|
||||
error_message="Aliens tried to steal your card's CVV,"
|
||||
|
|
@ -95,4 +94,4 @@ async def got_payment(message: types.Message):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
executor.start_polling(dp)
|
||||
executor.start_polling(dp, skip_updates=True)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
|
|
@ -11,13 +10,13 @@ from aiogram.utils.executor import start_polling
|
|||
from aiogram.utils.markdown import bold, code, italic, text
|
||||
|
||||
# Configure bot here
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
PROXY_URL = 'http://PROXY_URL' # Or 'socks5://...'
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
PROXY_URL = 'http://PROXY_URL' # Or 'socks5://host:port'
|
||||
|
||||
# If authentication is required in your proxy then uncomment next line and change login/password for it
|
||||
# NOTE: If authentication is required in your proxy then uncomment next line and change login/password for it
|
||||
# PROXY_AUTH = aiohttp.BasicAuth(login='login', password='password')
|
||||
# And add `proxy_auth=PROXY_AUTH` argument in line 25, like this:
|
||||
# >>> bot = Bot(token=API_TOKEN, loop=loop, proxy=PROXY_URL, proxy_auth=PROXY_AUTH)
|
||||
# And add `proxy_auth=PROXY_AUTH` argument in line 30, like this:
|
||||
# >>> bot = Bot(token=API_TOKEN, proxy=PROXY_URL, proxy_auth=PROXY_AUTH)
|
||||
# Also you can use Socks5 proxy but you need manually install aiohttp_socks package.
|
||||
|
||||
# Get my ip URL
|
||||
|
|
@ -26,26 +25,32 @@ GET_IP_URL = 'http://bot.whatismyipaddress.com/'
|
|||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
bot = Bot(token=API_TOKEN, proxy=PROXY_URL)
|
||||
|
||||
# If auth is required:
|
||||
# bot = Bot(token=API_TOKEN, proxy=PROXY_URL, proxy_auth=PROXY_AUTH)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
async def fetch(url, proxy=None, proxy_auth=None):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, proxy=proxy, proxy_auth=proxy_auth) as response:
|
||||
return await response.text()
|
||||
async def fetch(url, session):
|
||||
async with session.get(url) as response:
|
||||
return await response.text()
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
async def cmd_start(message: types.Message):
|
||||
# fetching urls will take some time, so notify user that everything is OK
|
||||
await types.ChatActions.typing()
|
||||
|
||||
content = []
|
||||
|
||||
# Make request (without proxy)
|
||||
ip = await fetch(GET_IP_URL)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
ip = await fetch(GET_IP_URL, session)
|
||||
content.append(text(':globe_showing_Americas:', bold('IP:'), code(ip)))
|
||||
# This line is formatted to '🌎 *IP:* `YOUR IP`'
|
||||
|
||||
# Make request through proxy
|
||||
ip = await fetch(GET_IP_URL, bot.proxy, bot.proxy_auth)
|
||||
# Make request through bot's proxy
|
||||
ip = await fetch(GET_IP_URL, bot.session)
|
||||
content.append(text(':locked_with_key:', bold('IP:'), code(ip), italic('via proxy')))
|
||||
# This line is formatted to '🔐 *IP:* `YOUR IP` _via proxy_'
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,28 @@ from aiogram import Bot, types
|
|||
from aiogram.dispatcher import Dispatcher, filters
|
||||
from aiogram.utils import executor
|
||||
|
||||
bot = Bot(token='TOKEN')
|
||||
|
||||
bot = Bot(token='BOT_TOKEN_HERE', parse_mode=types.ParseMode.HTML)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler(filters.RegexpCommandsFilter(regexp_commands=['item_([0-9]*)']))
|
||||
async def send_welcome(message: types.Message, regexp_command):
|
||||
await message.reply("You have requested an item with number: {}".format(regexp_command.group(1)))
|
||||
await message.reply(f"You have requested an item with id <code>{regexp_command.group(1)}</code>")
|
||||
|
||||
|
||||
@dp.message_handler(commands='start')
|
||||
async def create_deeplink(message: types.Message):
|
||||
bot_user = await bot.me
|
||||
bot_username = bot_user.username
|
||||
deeplink = f'https://t.me/{bot_username}?start=item_12345'
|
||||
text = (
|
||||
f'Either send a command /item_1234 or follow this link {deeplink} and then click start\n'
|
||||
'It also can be hidden in a inline button\n\n'
|
||||
'Or just send <code>/start item_123</code>'
|
||||
)
|
||||
await message.reply(text, disable_web_page_preview=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
executor.start_polling(dp)
|
||||
executor.start_polling(dp, skip_updates=True)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import logging
|
|||
|
||||
from aiogram import Bot, Dispatcher, executor, types
|
||||
|
||||
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
# Configure logging
|
||||
|
|
@ -18,24 +19,27 @@ bot = Bot(token=API_TOKEN)
|
|||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
@dp.message_handler(commands='start')
|
||||
async def start_cmd_handler(message: types.Message):
|
||||
keyboard_markup = types.ReplyKeyboardMarkup(row_width=3)
|
||||
# default row_width is 3, so here we can omit it actually
|
||||
# kept for clearness
|
||||
|
||||
keyboard_markup.row(types.KeyboardButton("Yes!"),
|
||||
types.KeyboardButton("No!"))
|
||||
btns_text = ('Yes!', 'No!')
|
||||
keyboard_markup.row(*(types.KeyboardButton(text) for text in btns_text))
|
||||
# adds buttons as a new row to the existing keyboard
|
||||
# the behaviour doesn't depend on row_width attribute
|
||||
|
||||
keyboard_markup.add(types.KeyboardButton("I don't know"),
|
||||
types.KeyboardButton("Who am i?"),
|
||||
types.KeyboardButton("Where am i?"),
|
||||
types.KeyboardButton("Who is there?"))
|
||||
# adds buttons. New rows is formed according to row_width parameter
|
||||
more_btns_text = (
|
||||
"I don't know",
|
||||
"Who am i?",
|
||||
"Where am i?",
|
||||
"Who is there?",
|
||||
)
|
||||
keyboard_markup.add(*(types.KeyboardButton(text) for text in more_btns_text))
|
||||
# adds buttons. New rows are formed according to row_width parameter
|
||||
|
||||
await message.reply("Hi!\nDo you love aiogram?", reply_markup=keyboard_markup)
|
||||
await message.reply("Hi!\nDo you like aiogram?", reply_markup=keyboard_markup)
|
||||
|
||||
|
||||
@dp.message_handler()
|
||||
|
|
@ -45,15 +49,17 @@ async def all_msg_handler(message: types.Message):
|
|||
# in real bot, it's better to define message_handler(text="...") for each button
|
||||
# but here for the simplicity only one handler is defined
|
||||
|
||||
text_of_button = message.text
|
||||
logger.debug(text_of_button) # print the text we got
|
||||
button_text = message.text
|
||||
logger.debug('The answer is %r', button_text) # print the text we've got
|
||||
|
||||
if text_of_button == 'Yes!':
|
||||
await message.reply("That's great", reply_markup=types.ReplyKeyboardRemove())
|
||||
elif text_of_button == 'No!':
|
||||
await message.reply("Oh no! Why?", reply_markup=types.ReplyKeyboardRemove())
|
||||
if button_text == 'Yes!':
|
||||
reply_text = "That's great"
|
||||
elif button_text == 'No!':
|
||||
reply_text = "Oh no! Why?"
|
||||
else:
|
||||
await message.reply("Keep calm...Everything is fine", reply_markup=types.ReplyKeyboardRemove())
|
||||
reply_text = "Keep calm...Everything is fine"
|
||||
|
||||
await message.reply(reply_text, reply_markup=types.ReplyKeyboardRemove())
|
||||
# with message, we send types.ReplyKeyboardRemove() to hide the keyboard
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import logging
|
|||
|
||||
from aiogram import Bot, Dispatcher, executor, types
|
||||
|
||||
API_TOKEN = 'API_TOKEN_HERE'
|
||||
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
|
@ -16,10 +17,12 @@ logging.basicConfig(level=logging.INFO)
|
|||
bot = Bot(token=API_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
# if the text from user in the list
|
||||
@dp.message_handler(text=['text1', 'text2'])
|
||||
async def text_in_handler(message: types.Message):
|
||||
await message.answer("The message text is in the list!")
|
||||
await message.answer("The message text equals to one of in the list!")
|
||||
|
||||
|
||||
# if the text contains any string
|
||||
@dp.message_handler(text_contains='example1')
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ Example for throttling manager.
|
|||
You can use that for flood controlling.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiogram import Bot, types
|
||||
|
|
@ -13,14 +12,15 @@ from aiogram.dispatcher import Dispatcher
|
|||
from aiogram.utils.exceptions import Throttled
|
||||
from aiogram.utils.executor import start_polling
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
|
||||
# Throttling manager does not work without Leaky Bucket.
|
||||
# Then need to use storages. For example use simple in-memory storage.
|
||||
# You need to use a storage. For example use simple in-memory storage.
|
||||
storage = MemoryStorage()
|
||||
dp = Dispatcher(bot, storage=storage)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,176 +1,66 @@
|
|||
"""
|
||||
Example outdated
|
||||
"""
|
||||
import logging
|
||||
|
||||
import asyncio
|
||||
import ssl
|
||||
import sys
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
import aiogram
|
||||
from aiogram import Bot, types
|
||||
from aiogram.contrib.fsm_storage.memory import MemoryStorage
|
||||
from aiogram.contrib.middlewares.logging import LoggingMiddleware
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.dispatcher.webhook import get_new_configured_app, SendMessage
|
||||
from aiogram.types import ChatType, ParseMode, ContentTypes
|
||||
from aiogram.utils.markdown import hbold, bold, text, link
|
||||
from aiogram.dispatcher.webhook import SendMessage
|
||||
from aiogram.utils.executor import start_webhook
|
||||
|
||||
TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
WEBHOOK_HOST = 'example.com' # Domain name or IP addres which your bot is located.
|
||||
WEBHOOK_PORT = 443 # Telegram Bot API allows only for usage next ports: 443, 80, 88 or 8443
|
||||
WEBHOOK_URL_PATH = '/webhook' # Part of URL
|
||||
API_TOKEN = 'BOT_TOKEN_HERE'
|
||||
|
||||
# This options needed if you use self-signed SSL certificate
|
||||
# Instructions: https://core.telegram.org/bots/self-signed
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
# webhook settings
|
||||
WEBHOOK_HOST = 'https://your.domain'
|
||||
WEBHOOK_PATH = '/path/to/api'
|
||||
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"
|
||||
|
||||
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}{WEBHOOK_URL_PATH}"
|
||||
|
||||
# Web app settings:
|
||||
# Use LAN address to listen webhooks
|
||||
# User any available port in range from 1024 to 49151 if you're using proxy, or WEBHOOK_PORT if you're using direct webhook handling
|
||||
WEBAPP_HOST = 'localhost'
|
||||
# webserver settings
|
||||
WEBAPP_HOST = 'localhost' # or ip
|
||||
WEBAPP_PORT = 3001
|
||||
|
||||
BAD_CONTENT = ContentTypes.PHOTO & ContentTypes.DOCUMENT & ContentTypes.STICKER & ContentTypes.AUDIO
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
bot = Bot(TOKEN)
|
||||
storage = MemoryStorage()
|
||||
dp = Dispatcher(bot, storage=storage)
|
||||
bot = Bot(token=API_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
dp.middleware.setup(LoggingMiddleware())
|
||||
|
||||
|
||||
async def cmd_start(message: types.Message):
|
||||
# Yep. aiogram allows to respond into webhook.
|
||||
# https://core.telegram.org/bots/api#making-requests-when-getting-updates
|
||||
return SendMessage(chat_id=message.chat.id, text='Hi from webhook!',
|
||||
reply_to_message_id=message.message_id)
|
||||
@dp.message_handler()
|
||||
async def echo(message: types.Message):
|
||||
# Regular request
|
||||
# await bot.send_message(message.chat.id, message.text)
|
||||
|
||||
# or reply INTO webhook
|
||||
return SendMessage(message.chat.id, message.text)
|
||||
|
||||
|
||||
async def cmd_about(message: types.Message):
|
||||
# In this function markdown utils are userd for formatting message text
|
||||
return SendMessage(message.chat.id, text(
|
||||
bold('Hi! I\'m just a simple telegram bot.'),
|
||||
'',
|
||||
text('I\'m powered by', bold('Python', Version(*sys.version_info[:]))),
|
||||
text('With', link(text('aiogram', aiogram.VERSION), 'https://github.com/aiogram/aiogram')),
|
||||
sep='\n'
|
||||
), parse_mode=ParseMode.MARKDOWN)
|
||||
async def on_startup(dp):
|
||||
await bot.set_webhook(WEBHOOK_URL)
|
||||
# insert code here to run it after start
|
||||
|
||||
|
||||
async def cancel(message: types.Message):
|
||||
# Get current state context
|
||||
state = dp.current_state(chat=message.chat.id, user=message.from_user.id)
|
||||
async def on_shutdown(dp):
|
||||
logging.warning('Shutting down..')
|
||||
|
||||
# If current user in any state - cancel it.
|
||||
if await state.get_state() is not None:
|
||||
await state.set_state(state=None)
|
||||
return SendMessage(message.chat.id, 'Current action is canceled.')
|
||||
# Otherwise do nothing
|
||||
# insert code here to run it before shutdown
|
||||
|
||||
|
||||
async def unknown(message: types.Message):
|
||||
"""
|
||||
Handler for unknown messages.
|
||||
"""
|
||||
return SendMessage(message.chat.id,
|
||||
f"I don\'t know what to do with content type `{message.content_type()}`. Sorry :c")
|
||||
|
||||
|
||||
async def cmd_id(message: types.Message):
|
||||
"""
|
||||
Return info about user.
|
||||
"""
|
||||
if message.reply_to_message:
|
||||
target = message.reply_to_message.from_user
|
||||
chat = message.chat
|
||||
elif message.forward_from and message.chat.type == ChatType.PRIVATE:
|
||||
target = message.forward_from
|
||||
chat = message.forward_from or message.chat
|
||||
else:
|
||||
target = message.from_user
|
||||
chat = message.chat
|
||||
|
||||
result_msg = [hbold('Info about user:'),
|
||||
f"First name: {target.first_name}"]
|
||||
if target.last_name:
|
||||
result_msg.append(f"Last name: {target.last_name}")
|
||||
if target.username:
|
||||
result_msg.append(f"Username: {target.mention}")
|
||||
result_msg.append(f"User ID: {target.id}")
|
||||
|
||||
result_msg.extend([hbold('Chat:'),
|
||||
f"Type: {chat.type}",
|
||||
f"Chat ID: {chat.id}"])
|
||||
if chat.type != ChatType.PRIVATE:
|
||||
result_msg.append(f"Title: {chat.title}")
|
||||
else:
|
||||
result_msg.append(f"Title: {chat.full_name}")
|
||||
return SendMessage(message.chat.id, '\n'.join(result_msg), reply_to_message_id=message.message_id,
|
||||
parse_mode=ParseMode.HTML)
|
||||
|
||||
|
||||
async def on_startup(app):
|
||||
# Demonstrate one of the available methods for registering handlers
|
||||
# This command available only in main state (state=None)
|
||||
dp.register_message_handler(cmd_start, commands=['start'])
|
||||
|
||||
# This handler is available in all states at any time.
|
||||
dp.register_message_handler(cmd_about, commands=['help', 'about'], state='*')
|
||||
dp.register_message_handler(unknown, content_types=BAD_CONTENT,
|
||||
func=lambda message: message.chat.type == ChatType.PRIVATE)
|
||||
|
||||
# You are able to register one function handler for multiple conditions
|
||||
dp.register_message_handler(cancel, commands=['cancel'], state='*')
|
||||
dp.register_message_handler(cancel, func=lambda message: message.text.lower().strip() in ['cancel'], state='*')
|
||||
|
||||
dp.register_message_handler(cmd_id, commands=['id'], state='*')
|
||||
dp.register_message_handler(cmd_id, func=lambda message: message.forward_from or
|
||||
message.reply_to_message and
|
||||
message.chat.type == ChatType.PRIVATE, state='*')
|
||||
|
||||
# Get current webhook status
|
||||
webhook = await bot.get_webhook_info()
|
||||
|
||||
# If URL is bad
|
||||
if webhook.url != WEBHOOK_URL:
|
||||
# If URL doesnt match current - remove webhook
|
||||
if not webhook.url:
|
||||
await bot.delete_webhook()
|
||||
|
||||
# Set new URL for webhook
|
||||
await bot.set_webhook(WEBHOOK_URL, certificate=open(WEBHOOK_SSL_CERT, 'rb'))
|
||||
# If you want to use free certificate signed by LetsEncrypt you need to set only URL without sending certificate.
|
||||
|
||||
|
||||
async def on_shutdown(app):
|
||||
"""
|
||||
Graceful shutdown. This method is recommended by aiohttp docs.
|
||||
"""
|
||||
# Remove webhook.
|
||||
# Remove webhook (not acceptable in some cases)
|
||||
await bot.delete_webhook()
|
||||
|
||||
# Close Redis connection.
|
||||
# Close DB connection (if used)
|
||||
await dp.storage.close()
|
||||
await dp.storage.wait_closed()
|
||||
|
||||
logging.warning('Bye!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Get instance of :class:`aiohttp.web.Application` with configured router.
|
||||
app = get_new_configured_app(dispatcher=dp, path=WEBHOOK_URL_PATH)
|
||||
|
||||
# Setup event handlers.
|
||||
app.on_startup.append(on_startup)
|
||||
app.on_shutdown.append(on_shutdown)
|
||||
|
||||
# Generate SSL context
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
|
||||
|
||||
# Start web-application.
|
||||
web.run_app(app, host=WEBAPP_HOST, port=WEBAPP_PORT, ssl_context=context)
|
||||
# Note:
|
||||
# If you start your bot using nginx or Apache web server, SSL context is not required.
|
||||
# Otherwise you need to set `ssl_context` parameter.
|
||||
start_webhook(
|
||||
dispatcher=dp,
|
||||
webhook_path=WEBHOOK_PATH,
|
||||
on_startup=on_startup,
|
||||
on_shutdown=on_shutdown,
|
||||
skip_updates=True,
|
||||
host=WEBAPP_HOST,
|
||||
port=WEBAPP_PORT,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiogram import Bot, types
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.utils.executor import start_webhook
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
# webhook settings
|
||||
WEBHOOK_HOST = 'https://your.domain'
|
||||
WEBHOOK_PATH = '/path/to/api'
|
||||
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"
|
||||
|
||||
# webserver settings
|
||||
WEBAPP_HOST = 'localhost' # or ip
|
||||
WEBAPP_PORT = 3001
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler()
|
||||
async def echo(message: types.Message):
|
||||
await bot.send_message(message.chat.id, message.text)
|
||||
|
||||
|
||||
async def on_startup(dp):
|
||||
await bot.set_webhook(WEBHOOK_URL)
|
||||
# insert code here to run it after start
|
||||
|
||||
|
||||
async def on_shutdown(dp):
|
||||
# insert code here to run it before shutdown
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start_webhook(dispatcher=dp, webhook_path=WEBHOOK_PATH, on_startup=on_startup, on_shutdown=on_shutdown,
|
||||
skip_updates=True, host=WEBAPP_HOST, port=WEBAPP_PORT)
|
||||
176
examples/webhook_example_old.py
Normal file
176
examples/webhook_example_old.py
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
"""
|
||||
Example outdated
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import ssl
|
||||
import sys
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
import aiogram
|
||||
from aiogram import Bot, types
|
||||
from aiogram.contrib.fsm_storage.memory import MemoryStorage
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.dispatcher.webhook import get_new_configured_app, SendMessage
|
||||
from aiogram.types import ChatType, ParseMode, ContentTypes
|
||||
from aiogram.utils.markdown import hbold, bold, text, link
|
||||
|
||||
TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
WEBHOOK_HOST = 'example.com' # Domain name or IP addres which your bot is located.
|
||||
WEBHOOK_PORT = 443 # Telegram Bot API allows only for usage next ports: 443, 80, 88 or 8443
|
||||
WEBHOOK_URL_PATH = '/webhook' # Part of URL
|
||||
|
||||
# This options needed if you use self-signed SSL certificate
|
||||
# Instructions: https://core.telegram.org/bots/self-signed
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
|
||||
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}{WEBHOOK_URL_PATH}"
|
||||
|
||||
# Web app settings:
|
||||
# Use LAN address to listen webhooks
|
||||
# User any available port in range from 1024 to 49151 if you're using proxy, or WEBHOOK_PORT if you're using direct webhook handling
|
||||
WEBAPP_HOST = 'localhost'
|
||||
WEBAPP_PORT = 3001
|
||||
|
||||
BAD_CONTENT = ContentTypes.PHOTO & ContentTypes.DOCUMENT & ContentTypes.STICKER & ContentTypes.AUDIO
|
||||
|
||||
bot = Bot(TOKEN)
|
||||
storage = MemoryStorage()
|
||||
dp = Dispatcher(bot, storage=storage)
|
||||
|
||||
|
||||
async def cmd_start(message: types.Message):
|
||||
# Yep. aiogram allows to respond into webhook.
|
||||
# https://core.telegram.org/bots/api#making-requests-when-getting-updates
|
||||
return SendMessage(chat_id=message.chat.id, text='Hi from webhook!',
|
||||
reply_to_message_id=message.message_id)
|
||||
|
||||
|
||||
async def cmd_about(message: types.Message):
|
||||
# In this function markdown utils are userd for formatting message text
|
||||
return SendMessage(message.chat.id, text(
|
||||
bold('Hi! I\'m just a simple telegram bot.'),
|
||||
'',
|
||||
text('I\'m powered by', bold('Python', Version(*sys.version_info[:]))),
|
||||
text('With', link(text('aiogram', aiogram.VERSION), 'https://github.com/aiogram/aiogram')),
|
||||
sep='\n'
|
||||
), parse_mode=ParseMode.MARKDOWN)
|
||||
|
||||
|
||||
async def cancel(message: types.Message):
|
||||
# Get current state context
|
||||
state = dp.current_state(chat=message.chat.id, user=message.from_user.id)
|
||||
|
||||
# If current user in any state - cancel it.
|
||||
if await state.get_state() is not None:
|
||||
await state.set_state(state=None)
|
||||
return SendMessage(message.chat.id, 'Current action is canceled.')
|
||||
# Otherwise do nothing
|
||||
|
||||
|
||||
async def unknown(message: types.Message):
|
||||
"""
|
||||
Handler for unknown messages.
|
||||
"""
|
||||
return SendMessage(message.chat.id,
|
||||
f"I don\'t know what to do with content type `{message.content_type()}`. Sorry :c")
|
||||
|
||||
|
||||
async def cmd_id(message: types.Message):
|
||||
"""
|
||||
Return info about user.
|
||||
"""
|
||||
if message.reply_to_message:
|
||||
target = message.reply_to_message.from_user
|
||||
chat = message.chat
|
||||
elif message.forward_from and message.chat.type == ChatType.PRIVATE:
|
||||
target = message.forward_from
|
||||
chat = message.forward_from or message.chat
|
||||
else:
|
||||
target = message.from_user
|
||||
chat = message.chat
|
||||
|
||||
result_msg = [hbold('Info about user:'),
|
||||
f"First name: {target.first_name}"]
|
||||
if target.last_name:
|
||||
result_msg.append(f"Last name: {target.last_name}")
|
||||
if target.username:
|
||||
result_msg.append(f"Username: {target.mention}")
|
||||
result_msg.append(f"User ID: {target.id}")
|
||||
|
||||
result_msg.extend([hbold('Chat:'),
|
||||
f"Type: {chat.type}",
|
||||
f"Chat ID: {chat.id}"])
|
||||
if chat.type != ChatType.PRIVATE:
|
||||
result_msg.append(f"Title: {chat.title}")
|
||||
else:
|
||||
result_msg.append(f"Title: {chat.full_name}")
|
||||
return SendMessage(message.chat.id, '\n'.join(result_msg), reply_to_message_id=message.message_id,
|
||||
parse_mode=ParseMode.HTML)
|
||||
|
||||
|
||||
async def on_startup(app):
|
||||
# Demonstrate one of the available methods for registering handlers
|
||||
# This command available only in main state (state=None)
|
||||
dp.register_message_handler(cmd_start, commands=['start'])
|
||||
|
||||
# This handler is available in all states at any time.
|
||||
dp.register_message_handler(cmd_about, commands=['help', 'about'], state='*')
|
||||
dp.register_message_handler(unknown, content_types=BAD_CONTENT,
|
||||
func=lambda message: message.chat.type == ChatType.PRIVATE)
|
||||
|
||||
# You are able to register one function handler for multiple conditions
|
||||
dp.register_message_handler(cancel, commands=['cancel'], state='*')
|
||||
dp.register_message_handler(cancel, func=lambda message: message.text.lower().strip() in ['cancel'], state='*')
|
||||
|
||||
dp.register_message_handler(cmd_id, commands=['id'], state='*')
|
||||
dp.register_message_handler(cmd_id, func=lambda message: message.forward_from or
|
||||
message.reply_to_message and
|
||||
message.chat.type == ChatType.PRIVATE, state='*')
|
||||
|
||||
# Get current webhook status
|
||||
webhook = await bot.get_webhook_info()
|
||||
|
||||
# If URL is bad
|
||||
if webhook.url != WEBHOOK_URL:
|
||||
# If URL doesnt match current - remove webhook
|
||||
if not webhook.url:
|
||||
await bot.delete_webhook()
|
||||
|
||||
# Set new URL for webhook
|
||||
await bot.set_webhook(WEBHOOK_URL, certificate=open(WEBHOOK_SSL_CERT, 'rb'))
|
||||
# If you want to use free certificate signed by LetsEncrypt you need to set only URL without sending certificate.
|
||||
|
||||
|
||||
async def on_shutdown(app):
|
||||
"""
|
||||
Graceful shutdown. This method is recommended by aiohttp docs.
|
||||
"""
|
||||
# Remove webhook.
|
||||
await bot.delete_webhook()
|
||||
|
||||
# Close Redis connection.
|
||||
await dp.storage.close()
|
||||
await dp.storage.wait_closed()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Get instance of :class:`aiohttp.web.Application` with configured router.
|
||||
app = get_new_configured_app(dispatcher=dp, path=WEBHOOK_URL_PATH)
|
||||
|
||||
# Setup event handlers.
|
||||
app.on_startup.append(on_startup)
|
||||
app.on_shutdown.append(on_shutdown)
|
||||
|
||||
# Generate SSL context
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
|
||||
|
||||
# Start web-application.
|
||||
web.run_app(app, host=WEBAPP_HOST, port=WEBAPP_PORT, ssl_context=context)
|
||||
# Note:
|
||||
# If you start your bot using nginx or Apache web server, SSL context is not required.
|
||||
# Otherwise you need to set `ssl_context` parameter.
|
||||
Loading…
Add table
Add a link
Reference in a new issue