Implemented polls [From test API]

This commit is contained in:
Alex RootJunior 2019-04-11 00:32:46 +03:00
parent 2a6f36b19b
commit e2e2d9c9fe
10 changed files with 107 additions and 7 deletions

View file

@ -38,5 +38,5 @@ __all__ = [
'utils'
]
__version__ = '2.0.2.dev1'
__version__ = '2.1.dev1'
__api_version__ = '4.1'

View file

@ -229,6 +229,10 @@ class Methods(Helper):
SET_GAME_SCORE = Item() # setGameScore
GET_GAME_HIGH_SCORES = Item() # getGameHighScores
# Polls
SEND_POLL = Item()
STOP_POLL = Item()
@staticmethod
def api_url(token, method):
"""

View file

@ -2056,3 +2056,20 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
result = await self.request(api.Methods.GET_GAME_HIGH_SCORES, payload)
return [types.GameHighScore(**gamehighscore) for gamehighscore in result]
async def send_poll(self, chat_id: typing.Union[base.Integer, base.String],
question: base.String,
options: typing.List[base.String],
reply_to_message_id: typing.Union[base.Integer, None]):
options = prepare_arg(options)
payload = generate_payload(**locals())
result = await self.request(api.Methods.SEND_POLL, payload)
return types.Message(**result)
async def stop_poll(self, chat_id: typing.Union[base.String, base.Integer],
message_id: base.Integer) -> types.Poll:
payload = generate_payload(**locals())
result = await self.request(api.Methods.STOP_POLL, payload)
return types.Poll(**result)

View file

@ -64,6 +64,7 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
self.callback_query_handlers = Handler(self, middleware_key='callback_query')
self.shipping_query_handlers = Handler(self, middleware_key='shipping_query')
self.pre_checkout_query_handlers = Handler(self, middleware_key='pre_checkout_query')
self.poll_handlers = Handler(self, middleware_key='poll')
self.errors_handlers = Handler(self, once=False, middleware_key='error')
self.middleware = MiddlewareManager(self)
@ -80,7 +81,8 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
filters_factory = self.filters_factory
filters_factory.bind(StateFilter, exclude_event_handlers=[
self.errors_handlers
self.errors_handlers,
self.poll_handlers
])
filters_factory.bind(ContentTypeFilter, event_handlers=[
self.message_handlers, self.edited_message_handlers,
@ -92,7 +94,7 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
filters_factory.bind(Text, event_handlers=[
self.message_handlers, self.edited_message_handlers,
self.channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers
self.callback_query_handlers, self.poll_handlers
])
filters_factory.bind(HashTag, event_handlers=[
self.message_handlers, self.edited_message_handlers,
@ -101,7 +103,7 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
filters_factory.bind(Regexp, event_handlers=[
self.message_handlers, self.edited_message_handlers,
self.channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers
self.callback_query_handlers, self.poll_handlers
])
filters_factory.bind(RegexpCommandsFilter, event_handlers=[
self.message_handlers, self.edited_message_handlers
@ -185,6 +187,8 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
if update.pre_checkout_query:
types.User.set_current(update.pre_checkout_query.from_user)
return await self.pre_checkout_query_handlers.notify(update.pre_checkout_query)
if update.poll:
return await self.poll_handlers.notify(update.poll)
except Exception as e:
err = await self.errors_handlers.notify(update, e)
if err:
@ -796,6 +800,20 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
return decorator
def register_poll_handler(self, callback, *custom_filters, run_task=None, **kwargs):
filters_set = self.filters_factory.resolve(self.poll_handlers,
*custom_filters,
**kwargs)
self.poll_handlers.register(self._wrap_async_task(callback, run_task), filters_set)
def poll_handler(self, *custom_filters, run_task=None, **kwargs):
def decorator(callback):
self.register_poll_handler(callback, *custom_filters, run_task=run_task,
**kwargs)
return callback
return decorator
def register_errors_handler(self, callback, *custom_filters, exception=None, run_task=None, **kwargs):
"""
Register handler for errors

View file

@ -8,7 +8,7 @@ from babel.support import LazyProxy
from aiogram import types
from aiogram.dispatcher.filters.filters import BoundFilter, Filter
from aiogram.types import CallbackQuery, Message, InlineQuery
from aiogram.types import CallbackQuery, Message, InlineQuery, Poll
from aiogram.utils.deprecated import warn_deprecated
@ -164,10 +164,14 @@ class Text(Filter):
async def check(self, obj: Union[Message, CallbackQuery, InlineQuery]):
if isinstance(obj, Message):
text = obj.text or obj.caption or ''
if not text and obj.poll:
text = obj.poll.question
elif isinstance(obj, CallbackQuery):
text = obj.data
elif isinstance(obj, InlineQuery):
text = obj.query
elif isinstance(obj, Poll):
text = obj.question
else:
return False
@ -269,12 +273,16 @@ class Regexp(Filter):
async def check(self, obj: Union[Message, CallbackQuery]):
if isinstance(obj, Message):
match = self.regexp.search(obj.text or obj.caption or '')
content = obj.text or obj.caption or ''
if not content and obj.poll:
content = obj.poll.question
elif isinstance(obj, CallbackQuery) and obj.data:
match = self.regexp.search(obj.data)
content = obj.data
else:
return False
match = self.regexp.search(content)
if match:
return {'regexp': match}
return False

View file

@ -43,6 +43,7 @@ from .passport_element_error import PassportElementError, PassportElementErrorDa
PassportElementErrorSelfie
from .passport_file import PassportFile
from .photo_size import PhotoSize
from .poll import PollOptions, Poll
from .pre_checkout_query import PreCheckoutQuery
from .reply_keyboard import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
from .response_parameters import ResponseParameters
@ -142,6 +143,8 @@ __all__ = (
'PassportElementErrorSelfie',
'PassportFile',
'PhotoSize',
'Poll',
'PollOptions',
'PreCheckoutQuery',
'ReplyKeyboardMarkup',
'ReplyKeyboardRemove',

View file

@ -19,6 +19,7 @@ from .location import Location
from .message_entity import MessageEntity
from .passport_data import PassportData
from .photo_size import PhotoSize
from .poll import Poll
from .sticker import Sticker
from .successful_payment import SuccessfulPayment
from .user import User
@ -81,6 +82,7 @@ class Message(base.TelegramObject):
successful_payment: SuccessfulPayment = fields.Field(base=SuccessfulPayment)
connected_website: base.String = fields.Field()
passport_data: PassportData = fields.Field(base=PassportData)
poll: Poll = fields.Field(base=Poll)
@property
@functools.lru_cache()
@ -137,6 +139,8 @@ class Message(base.TelegramObject):
return ContentType.GROUP_CHAT_CREATED
elif self.passport_data:
return ContentType.PASSPORT_DATA
elif self.poll:
return ContentType.POLL
else:
return ContentType.UNKNOWN
@ -1539,6 +1543,7 @@ class ContentType(helper.Helper):
DELETE_CHAT_PHOTO = helper.Item() # delete_chat_photo
GROUP_CHAT_CREATED = helper.Item() # group_chat_created
PASSPORT_DATA = helper.Item() # passport_data
POLL = helper.Item()
UNKNOWN = helper.Item() # unknown
ANY = helper.Item() # any
@ -1600,6 +1605,7 @@ class ContentTypes(helper.Helper):
DELETE_CHAT_PHOTO = helper.ListItem() # delete_chat_photo
GROUP_CHAT_CREATED = helper.ListItem() # group_chat_created
PASSPORT_DATA = helper.ListItem() # passport_data
POLL = helper.ListItem()
UNKNOWN = helper.ListItem() # unknown
ANY = helper.ListItem() # any

16
aiogram/types/poll.py Normal file
View file

@ -0,0 +1,16 @@
import typing
from . import base
from . import fields
class PollOptions(base.TelegramObject):
text: base.String = fields.Field()
voter_count: base.Integer = fields.Field()
class Poll(base.TelegramObject):
id: base.String = fields.Field()
question: base.String = fields.Field()
options: typing.List[PollOptions] = fields.ListField(base=PollOptions)
is_closed: base.Boolean = fields.Field()

View file

@ -6,6 +6,7 @@ from .callback_query import CallbackQuery
from .chosen_inline_result import ChosenInlineResult
from .inline_query import InlineQuery
from .message import Message
from .poll import Poll
from .pre_checkout_query import PreCheckoutQuery
from .shipping_query import ShippingQuery
from ..utils import helper
@ -28,6 +29,7 @@ class Update(base.TelegramObject):
callback_query: CallbackQuery = fields.Field(base=CallbackQuery)
shipping_query: ShippingQuery = fields.Field(base=ShippingQuery)
pre_checkout_query: PreCheckoutQuery = fields.Field(base=PreCheckoutQuery)
poll: Poll = fields.Field(base=Poll)
def __hash__(self):
return self.update_id

View file

@ -7,12 +7,16 @@ TelegramAPIError
MessageNotModified
MessageToForwardNotFound
MessageToDeleteNotFound
MessageWithPollNotFound
MessageIsNotAPoll
MessageIdentifierNotSpecified
MessageTextIsEmpty
MessageCantBeEdited
MessageCantBeDeleted
MessageToEditNotFound
ToMuchMessages
PollCantBeStopped
PollHasAlreadyClosed
ObjectExpectedAsReplyMarkup
InlineKeyboardExpected
ChatNotFound
@ -164,6 +168,20 @@ class MessageToDeleteNotFound(MessageError):
match = 'message to delete not found'
class MessageWithPollNotFound(MessageError):
"""
Will be raised when you try to stop poll with message without poll
"""
match = 'message with poll to stop not found'
class MessageIsNotAPoll(MessageError):
"""
Will be raised when you try to stop poll with message without poll
"""
match = 'message is not a poll'
class MessageIdentifierNotSpecified(MessageError):
match = 'message identifier is not specified'
@ -203,6 +221,14 @@ class InlineKeyboardExpected(BadRequest):
match = 'inline keyboard expected'
class PollCantBeStopped(BadRequest):
match = "poll can't be stopped"
class PollHasAlreadyBeenClosed(BadRequest):
match = 'poll has already been closed'
class ChatNotFound(BadRequest):
match = 'chat not found'