Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline button for decryption of messages #7

Merged
merged 2 commits into from
Oct 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ pyvenv.cfg

app/config.py
log.txt
messages.db
21 changes: 17 additions & 4 deletions app/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import os
import string
import asyncio
import functools
from aiohttp import web
from aiotg import Bot, Chat, InlineQuery
from aiotg import Bot, Chat, InlineQuery, CallbackQuery

import msgdb
from config import *
from strconv import *
from queryutil import *
Expand Down Expand Up @@ -74,14 +76,25 @@ def inline_request_handler(request: InlineQuery) -> None:
if str_from_base64:
add_article("Дешифровка", str_from_base64)
elif request.query:
msg_id = msgdb.insert(request.query)
keyboard = InlineKeyboardBuilder()
keyboard.add_row().add("Расшифровать", callback_data=msg_id)
add_decryptable_article = functools.partial(add_article, reply_markup=keyboard.build())

add_article("Проблемы с раскладкой?", switch_keyboard_layout(request.query))
add_article("Говорить, как робот", str_to_bin(request.query))
add_article("Типа программист", str_to_hex(request.query))
add_article("Шифровка", str_to_base64(request.query))
add_decryptable_article("Говорить, как робот", str_to_bin(request.query))
add_decryptable_article("Типа программист", str_to_hex(request.query))
add_decryptable_article("Шифровка", str_to_base64(request.query))

request.answer(results.build_list())


@bot.callback
def decrypt(_, callback_query: CallbackQuery) -> None:
message = msgdb.select(callback_query.data) or "Расшифровка потерялась :("
callback_query.answer(text=message)


if __name__ == '__main__':
loop = asyncio.get_event_loop()
if DEBUG:
Expand Down
30 changes: 30 additions & 0 deletions app/msgdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Simple wrapper over an sqlite3 database to store textual messages."""

import sqlite3
import logging
from typing import *

__db = sqlite3.connect('messages.db')
__db.execute("CREATE TABLE IF NOT EXISTS Messages(message TEXT NOT NULL)")
_logger = logging.getLogger(__name__)


def insert(message: str) -> int:
cur = __db.execute("INSERT INTO Messages(message) VALUES (?)", [message])
__db.commit()
_logger.debug("Message '{}' was saved with id {:d}".format(message, cur.lastrowid))
return cur.lastrowid


def select(rowid: int) -> Optional[str]:
cur = __db.execute("SELECT message FROM Messages WHERE rowid=?", [rowid])
row = cur.fetchone()
return row[0] if row else None


def _mock_database(tempfile):
"""Open another file as the database. Used internally for testing purposes."""
global __db
__db.close()
__db = sqlite3.connect(tempfile)
__db.execute("CREATE TABLE Messages(message TEXT NOT NULL)")
53 changes: 50 additions & 3 deletions app/queryutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ def get_articles_generator_for(storage: InlineQueryResultsBuilder, max_descripti
"""Generate the function that simplifies the creation of articles which text and description must be the same.
:param storage: an instance of `InlineQueryResultsBuilder`
:param max_description: a maximum length of the description string
:return: a function `(title: str, text: str) -> None` which you should use to add new articles to the storage
:return: a function `(title: str, text: str, **kwargs) -> None` which you should use to add new articles to the
storage
"""
def add_article(title: str, text: str) -> None:
def add_article(title: str, text: str, **kwargs) -> None:
if len(text) > max_description:
description = text[:max_description-1].rstrip() + '…'
else:
Expand All @@ -44,6 +45,52 @@ def add_article(title: str, text: str) -> None:
description=description,
input_message_content={
'message_text': text
}
},
**kwargs
)
return add_article


class InlineKeyboardBuilder:
"""A builder to simplify creation of inline keyboards.

Usage:
>>> builder = InlineKeyboardBuilder()
>>> row1 = builder.add_row().add("Button 1").add("Button 2")
>>> row2 = builder.add_row().add("Button 3").add("Button 4")
>>> keyboard = builder.build()
"""

class RowBuilder:
"""An internal builder used to create a DSL for rows."""

def __init__(self):
self._cols = []

def add(self, text: str, **kwargs) -> "InlineKeyboardBuilder.RowBuilder":
"""Append a new button to the internal list. Can be used in chains of methods.
:param text: see https://core.telegram.org/bots/api#inlinekeyboardbutton
"""

obj = kwargs
obj['text'] = text
self._cols.append(obj)
return self

def build(self) -> list:
""":return: a copy of the internal list"""
return self._cols.copy()

def __init__(self):
self._rows = []

def add_row(self) -> "InlineKeyboardBuilder.RowBuilder":
""":return: a builder object for you to fill it."""
row_builder = InlineKeyboardBuilder.RowBuilder()
self._rows.append(row_builder)
return row_builder

def build(self) -> dict:
""":return: a dict prepared for the Bot API"""
keyboard = [row.build() for row in self._rows.copy()]
return {'inline_keyboard': keyboard}
8 changes: 8 additions & 0 deletions tests/test_msgdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from app import msgdb


def test_database(tmpdir):
msgdb._mock_database(str(tmpdir.join('messages.db')))
rowid = msgdb.insert("Hello World")
assert rowid == 1
assert msgdb.select(rowid) == "Hello World"