Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions botogram/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from . import shared
from . import tasks
from . import messages
from . import callbacks


class Bot(frozenbot.FrozenBot):
Expand Down Expand Up @@ -75,6 +76,8 @@ def __init__(self, api_connection):
messages.process_channel_post)
self.register_update_processor("edited_channel_post",
messages.process_channel_post_edited)
self.register_update_processor("callback_query",
callbacks.process_callback)

self._bot_id = str(uuid.uuid4())

Expand Down Expand Up @@ -166,6 +169,11 @@ def __(func):
return func
return __

def callback(self, func):
"""Add a callback query hook"""
self._main_component.add_callback_query_hook(func)
return func

def timer(self, interval):
"""Register a new timer"""
def __(func):
Expand Down
22 changes: 22 additions & 0 deletions botogram/callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
botogram.messages
Logic for callbacks sent to your bot

Copyright (c) 2016 Pietro Albini <pietro@pietroalbini.io>
Released under the MIT license
"""


def process_callback(bot, chains, update):
for hook in chains["callback_query"]:
bot.logger.debug("Processing callback query in update #%s with the "
"hook %s..." % (update.update_id, hook.name))

result = hook.call(bot, update)
if result is True:
bot.logger.debug("Update %s was just processed by the %s hook." %
(update.update_id, hook.name))
return

bot.logger.debug("No hook actually processed the #%s update." %
update.update_id)
14 changes: 12 additions & 2 deletions botogram/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __new__(cls, *args, **kwargs):
self.__messages_edited_hooks = []
self.__channel_post_hooks = []
self.__channel_post_edited_hooks = []
self.__callback_query_hooks = []

self._component_id = str(uuid.uuid4())

Expand Down Expand Up @@ -171,11 +172,19 @@ def add_channel_post_hook(self, func):
def add_channel_post_edited_hook(self, func):
"""Add an edited channel post hook"""
if not callable(func):
raise ValueError("A edited channel post hook must be callable")
raise ValueError("An edited channel post hook must be callable")

hook = hooks.EditedChannelPostHook(func, self)
self.__channel_post_edited_hooks.append(hook)

def add_callback_query_hook(self, func):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename this to add_callback_hook to be consistent with @bot.callback?

"""Add a callback query hook"""
if not callable(func):
return ValueError("A callback query hook must be callable")

hook = hooks.CallbackQueryHook(func, self)
self.__callback_query_hooks.append(hook)

def _add_no_commands_hook(self, func):
"""Register an hook which will be executed when no commands matches"""
if not callable(func):
Expand All @@ -200,7 +209,8 @@ def _get_chains(self):
"chat_unavalable_hooks": [self.__chat_unavailable_hooks],
"messages_edited": [self.__messages_edited_hooks],
"channel_post": [self.__channel_post_hooks],
"channel_post_edited": [self.__channel_post_edited_hooks]
"channel_post_edited": [self.__channel_post_edited_hooks],
"callback_query": [self.__callback_query_hooks],
}

def _get_commands(self):
Expand Down
9 changes: 9 additions & 0 deletions botogram/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@ def _call(self, bot, update):
message=message)


class CallbackQueryHook(Hook):
"""Underlying hook for @bot.callback"""

def _call(self, bot, update):
query = update.callback_query
return bot._call(self.func, self.component_id, message=query.message,
user=query.sender, callback=query)


class TimerHook(Hook):
"""Underlying hook for a timer"""

Expand Down
37 changes: 37 additions & 0 deletions botogram/objects/callback_query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
botogram.objects.callback_query
Representation of the callback query-related upstream API objects

Copyright (c) 2015 Pietro Albini <pietro@pietroalbini.io>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be you, not me, and we're not in 2015.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it's your work 🥇

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did nothing on that file: the copyright notice should be of the single file, not of the whole project, and you're the author of that file :)

Released under the MIT license
"""

from .base import BaseObject

from .messages import User, Message
from . import mixins


class CallbackQuery(BaseObject, mixins.CallbackMixin):
"""Telegram API representation of a callback query

https://core.telegram.org/bots/api#callbackquery
"""

required = {
"id": str,
"from": User,
"message": Message,
"chat_instance": str,
}
optional = {
"inline_message_id": str,
"data": str,
"game_short_name": str,
}
replace_keys = {
"from": "sender",
}

def __init__(self, data, api=None):
super().__init__(data, api)
12 changes: 12 additions & 0 deletions botogram/objects/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,15 @@ def save(self, path):
downloaded = self._api.file_content(response["result"]["file_path"])
with open(path, 'wb') as f:
f.write(downloaded)


class CallbackMixin:
"""Add some methods for callbacks"""

@_require_api
def notify(self, text, alert=False, cache_time=0):
self._api.call("answerCallbackQuery",
{"callback_query_id": self.id,
"text": text,
"show_alert": alert,
"cache_time": cache_time})
4 changes: 3 additions & 1 deletion botogram/objects/updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .base import BaseObject, multiple

from .messages import Message
from .callback_query import CallbackQuery


class Update(BaseObject):
Expand All @@ -24,7 +25,8 @@ class Update(BaseObject):
"message": Message,
"edited_message": Message,
"channel_post": Message,
"edited_channel_post": Message
"edited_channel_post": Message,
"callback_query": CallbackQuery,
}
_check_equality_ = "update_id"

Expand Down
42 changes: 42 additions & 0 deletions docs/api/telegram.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ about its business.
* :py:class:`~botogram.ReplyKeyboardMarkup`
* :py:class:`~botogram.ReplyKeyboardHide`
* :py:class:`~botogram.ForceReply`
* :py:class:`~botogram.CallbackQuery`


.. py:class:: botogram.User
Expand Down Expand Up @@ -2077,6 +2078,47 @@ about its business.
*This attribute can be None if it's not provided by Telegram.*


.. py:class:: botogram.CallbackQuery

This class represents a callback query received by the bot.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You forgot the version this is added to.

.. py:attribute:: id

The id of the callback.

.. py:attribute:: sender

The :py:class:`~botogram.User` that sent the callback query.

.. py:attribute:: message

The :py:class:`~botogram.Message` that was attached to the button that originated the query.

*This attribute can be None if it's not provided by Telegram.*

.. py:attribute:: inline_message_id

The id of the message sent via the bot in inline mode that was attached to the button that originated the query.

*This attribute can be None if it's not provided by Telegram.*

.. py:attribute:: chat_instance

The chat to which the message with the callback button was sent.

.. py:attribute:: data

Data associated with the callback button.

*This attribute can be None if it's not provided by Telegram.*

.. py:attribute:: game_short_name

Short name of a Game to be returned, serves as the unique identifier for the game.

*This attribute can be None if it's not provided by Telegram.*


.. _Telegram's Bot API: https://core.telegram.org/bots/api
.. _API methods: https://core.telegram.org/bots/api#available-methods
.. _API types: https://core.telegram.org/bots/api#available-types