Commands refactoring

This commit is contained in:
REDNBLACK 2017-08-19 18:19:21 +03:00
parent ad94b406bd
commit d4200c08b7
18 changed files with 100 additions and 99 deletions

View File

@ -20,3 +20,6 @@ class AbstractEntity(ABC):
"""Returns True if the message was edited. """Returns True if the message was edited.
""" """
return self.message.edit_date is not None return self.message.edit_date is not None
def __str__(self):
return str(self.__dict__)

View File

@ -1,3 +1,4 @@
import logging
from telegram import Update from telegram import Update
from telegram.ext import Handler from telegram.ext import Handler
from telegram.ext.dispatcher import run_async from telegram.ext.dispatcher import run_async
@ -28,11 +29,17 @@ class CommandHandler(Handler):
@run_async @run_async
def handle(self, bot, update): def handle(self, bot, update):
command = Command(update.message) data = Command(update.message)
logging.debug(f"Incoming command: {data}")
try: try:
self.commands[command.name](bot, command) command = self.commands[data.name]
except (IndexError, ValueError): if command.bot is None:
bot.send_message(chat_id=command.chat_id, command.bot = bot
reply_to_message_id=command.message.message_id, command.execute(data)
text='Invalid command! Type /help') except (KeyError, IndexError, ValueError):
bot.send_message(
chat_id=data.chat_id,
reply_to_message_id=data.message.message_id,
text='Invalid command! Type /help'
)

View File

@ -19,9 +19,9 @@ commands = {}
for clazz in Base.__subclasses__(): for clazz in Base.__subclasses__():
command_name = getattr(clazz, 'name') command_name = getattr(clazz, 'name')
command_aliases = getattr(clazz, 'aliases') command_aliases = getattr(clazz, 'aliases')
execute_method = getattr(clazz, 'execute') instance = clazz()
if command_name is not None: if command_name is not None:
commands[command_name] = execute_method commands[command_name] = instance
for command_alias in command_aliases: for command_alias in command_aliases:
commands[command_alias] = execute_method commands[command_alias] = instance

View File

@ -5,20 +5,20 @@ from abc import ABC, abstractmethod
class Base(ABC): class Base(ABC):
name = None name = None
aliases = [] aliases = []
bot = None
@staticmethod
@abstractmethod @abstractmethod
def execute(bot, command): def execute(self, command):
pass pass
@staticmethod def reply(self, command, text):
def reply(bot, command, message): logging.debug("Command %s: %s" % (str(command), text))
logging.debug("[Chat %s %s command] %s: %s" %
(command.chat_type,
command.chat_id,
command.name,
message))
bot.send_message(chat_id=command.chat_id, self.bot.send_message(
chat_id=command.chat_id,
reply_to_message_id=command.message.message_id, reply_to_message_id=command.message.message_id,
text=message) text=text
)
def send_photo(self, command, photo):
self.bot.send_photo(chat_id=command.chat_id, photo=photo)

View File

@ -1,16 +1,16 @@
from .base import Base from .base import Base
import json import json
from urllib.request import urlopen from urllib.request import urlopen
from src.config import encoding
class Boobs(Base): class Boobs(Base):
name = 'boobs' name = 'boobs'
aliases = ['80085', '(.)(.)'] aliases = ['80085', '(.)(.)']
@staticmethod def execute(self, command):
def execute(bot, command):
response = urlopen('http://api.oboobs.ru/noise/1') response = urlopen('http://api.oboobs.ru/noise/1')
data = json.loads(response.read().decode('utf-8')) data = json.loads(response.read().decode(encoding))
url = 'http://media.oboobs.ru/' + data[0]['preview'] url = 'http://media.oboobs.ru/' + data[0]['preview']
bot.send_photo(chat_id=command.chat_id, photo=url) self.send_photo(command, photo=url)

View File

@ -1,6 +1,7 @@
from .base import Base from .base import Base
import json import json
from src.utils import random_element from src.utils import random_element
from src.config import encoding
from urllib.request import urlopen from urllib.request import urlopen
@ -8,16 +9,15 @@ class Borscht(Base):
name = 'borscht' name = 'borscht'
images = None images = None
@staticmethod def __init__(self):
def execute(bot, command): super().__init__()
if Borscht.images is None: self.images = self.__preload()
Borscht.images = Borscht.__preload()
bot.send_photo(chat_id=command.chat_id, photo=random_element(Borscht.images)) def execute(self, command):
self.send_photo(command, photo=random_element(Borscht.images))
@staticmethod def __preload(self):
def __preload():
response = urlopen('https://api.cognitive.microsoft.com/bing/v5.0/images/search?q=%D0%B1%D0%BE%D1%80%D1%89&mkt=en-us&safe-search=strict&image-type=photo&subscription-key=dd95294bc02748a1ab5152d36fdbbdac') response = urlopen('https://api.cognitive.microsoft.com/bing/v5.0/images/search?q=%D0%B1%D0%BE%D1%80%D1%89&mkt=en-us&safe-search=strict&image-type=photo&subscription-key=dd95294bc02748a1ab5152d36fdbbdac')
data = json.loads(response.read().decode('utf-8')) data = json.loads(response.read().decode(encoding))
return list(map(lambda e: e['contentUrl'], data['value'])) return list(map(lambda e: e['contentUrl'], data['value']))

View File

@ -1,5 +1,6 @@
from .base import Base from .base import Base
import json import json
from src.config import encoding
from urllib.request import urlopen from urllib.request import urlopen
@ -7,10 +8,9 @@ class Butts(Base):
name = 'butts' name = 'butts'
aliases = ['(_._)', '(_*_)', '(Y)'] aliases = ['(_._)', '(_*_)', '(Y)']
@staticmethod def execute(self, command):
def execute(bot, command):
response = urlopen('http://api.obutts.ru/noise/1') response = urlopen('http://api.obutts.ru/noise/1')
data = json.loads(response.read().decode('utf-8')) data = json.loads(response.read().decode(encoding))
url = 'http://media.obutts.ru/' + data[0]['preview'] url = 'http://media.obutts.ru/' + data[0]['preview']
bot.send_photo(chat_id=command.chat_id, photo=url) self.send_photo(command, photo=url)

View File

@ -5,20 +5,18 @@ from src.config import chance_repository
class Chance(Base): class Chance(Base):
name = 'chance' name = 'chance'
@staticmethod def execute(self, command):
def execute(bot, command):
if command.is_private(): if command.is_private():
return Chance.reply(bot, command, 'Command disabled for private chats') return self.reply(command, 'Command disabled for private chats')
try: try:
new_chance = int(command.args[0]) new_chance = int(command.args[0])
if new_chance < 1 or new_chance > 50: if new_chance < 1 or new_chance > 50:
return Chance.reply(bot, command, 'Usage: /chance 1-50.') return self.reply(command, 'Usage: /chance 1-50.')
old_chance = chance_repository.set(chat_id=command.chat_id, new_chance=new_chance) old_chance = chance_repository.set(chat_id=command.chat_id, new_chance=new_chance)
Chance.reply(bot, command, 'Change chance from {} to {}'.format(old_chance, new_chance)) self.reply(command, 'Change chance from {} to {}'.format(old_chance, new_chance))
except (IndexError, ValueError): except (IndexError, ValueError):
Chance.reply(bot, command, 'Current chance: {}' self.reply(command, 'Current chance: {}'.format(chance_repository.get(command.chat_id)))
.format(chance_repository.get(command.chat_id)))

View File

@ -5,12 +5,13 @@ from urllib.request import urlopen, Request
class Facepalm(Base): class Facepalm(Base):
name = 'facepalm' name = 'facepalm'
aliases = ['o'] aliases = ['o']
path = 'storage/facepalm.jpg'
headers = {'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"}
@staticmethod def execute(self, command):
def execute(bot, command): req = Request("http://loremflickr.com/500/410/facepalm", headers=self.headers)
req = Request("http://loremflickr.com/500/410/facepalm", headers={'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"}) output = open(self.path, "wb")
output = open("storage/facepalm.jpg", "wb")
output.write(urlopen(req).read()) output.write(urlopen(req).read())
output.close() output.close()
bot.send_photo(chat_id=command.chat_id, photo=open('storage/facepalm.jpg', 'rb')) self.send_photo(command, photo=open(self.path, 'rb'))

View File

@ -5,7 +5,6 @@ from src.config import trigram_repository
class GetStats(Base): class GetStats(Base):
name = 'get_stats' name = 'get_stats'
@staticmethod def execute(self, command):
def execute(bot, command):
pairs_count = trigram_repository.count(command.chat_id) pairs_count = trigram_repository.count(command.chat_id)
GetStats.reply(bot, command, 'Pairs: {}'.format(pairs_count)) self.reply(command, 'Pairs: {}'.format(pairs_count))

View File

@ -6,6 +6,5 @@ class Help(Base):
name = 'help' name = 'help'
text = read_to_string('resources/info/help.txt') text = read_to_string('resources/info/help.txt')
@staticmethod def execute(self, command):
def execute(bot, command): self.reply(command, self.text)
Help.reply(bot, command, Help.text)

View File

@ -6,10 +6,8 @@ class Meow(Base):
name = 'meow' name = 'meow'
aliases = [':3', '=3'] aliases = [':3', '=3']
@staticmethod def execute(self, command):
def execute(bot, command):
opener = build_opener(HTTPRedirectHandler) opener = build_opener(HTTPRedirectHandler)
request = opener.open('http://thecatapi.com/api/images/get?format=src') req = opener.open('http://thecatapi.com/api/images/get?format=src')
url = request.url
bot.send_photo(chat_id=command.chat_id, photo=url) self.send_photo(command, photo=req.url)

View File

@ -4,13 +4,12 @@ from src.config import config, trigram_repository
class Moderate(Base): class Moderate(Base):
aliases = ['mod_f', 'mod_d'] aliases = ['mod_f', 'mod_d']
gods = [int(id) for id in config.getlist('bot', 'god_mode')] gods = config.getlist('bot', 'god_mode', type=int)
@staticmethod def execute(self, command):
def execute(bot, command):
try: try:
if not command.is_private() and not Moderate.is_admin(bot, command): if not command.is_private() and not self.__is_admin(command):
return Moderate.reply(bot, command, 'You don\'t have admin privileges!') return self.reply(command, 'You don\'t have admin privileges!')
if len(command.args) == 0: if len(command.args) == 0:
raise IndexError raise IndexError
@ -18,20 +17,20 @@ class Moderate(Base):
if command.name == 'mod_f': if command.name == 'mod_f':
words = trigram_repository.find_word(command.chat_id, command.args[0].strip()) words = trigram_repository.find_word(command.chat_id, command.args[0].strip())
reply = '\n'.join(words) reply = '\n'.join(words)
if reply == '': if reply.strip() == '':
reply = 'Nothing found' reply = 'Nothing found'
Moderate.reply(bot, command, reply) self.reply(command, reply)
elif command.name == 'mod_d': elif command.name == 'mod_d':
trigram_repository.remove_word(command.chat_id, command.args[0].strip()) trigram_repository.remove_word(command.chat_id, command.args[0].strip())
except (IndexError, ValueError): except (IndexError, ValueError):
Moderate.reply(bot, command, """Usage: self.reply(command, """Usage:
/mod_f <similar_word> for search /mod_f <similar_word> for search
/mod_d <exact_word> for deletion""") /mod_d <exact_word> for deletion""")
@staticmethod def __is_admin(self, entity):
def is_admin(bot, entity):
user_id = entity.message.from_user.id user_id = entity.message.from_user.id
admin_ids = list(map(lambda m: m.user.id, bot.get_chat_administrators(entity.chat_id))) admin_ids = list(map(lambda m: m.user.id, self.bot.get_chat_administrators(entity.chat_id)))
return user_id in admin_ids or user_id in Moderate.gods return user_id in admin_ids \
or user_id in self.gods

View File

@ -12,6 +12,5 @@ class Ping(Base):
'pingback' 'pingback'
] ]
@staticmethod def execute(self, command):
def execute(bot, command): self.reply(command, random_element(Ping.answers))
Ping.reply(bot, command, random_element(Ping.answers))

View File

@ -4,6 +4,5 @@ from .base import Base
class Start(Base): class Start(Base):
name = 'start' name = 'start'
@staticmethod def execute(self, command):
def execute(bot, command): self.reply(command, 'Hi! :3')
Start.reply(bot, command, 'Hi! :3')

View File

@ -4,16 +4,15 @@ from PIL import Image, ImageFont, ImageDraw
class Vzhuh(Base): class Vzhuh(Base):
name = 'vzhuh' name = 'vzhuh'
path = 'storage/vzhuh.png'
@staticmethod def execute(self, command):
def execute(bot, command): text = self.__format_text('вжух ' + ' '.join(command.args))
text = Vzhuh.format_text('вжух ' + ' '.join(command.args)) self.__generate_image(text)
Vzhuh.create_image(text)
bot.send_photo(chat_id=command.chat_id, photo=open('storage/vzhuh.png', 'rb')) self.send_photo(command, photo=open(self.path, 'rb'))
@staticmethod def __format_text(self, text):
def format_text(text):
result = [] result = []
current_part = '' current_part = ''
if len(text) > 8: if len(text) > 8:
@ -31,10 +30,9 @@ class Vzhuh(Base):
return '\n'.join(result) return '\n'.join(result)
@staticmethod def __generate_image(self, text):
def create_image(text):
img = Image.open("resources/vzhuh/sample.png") img = Image.open("resources/vzhuh/sample.png")
draw = ImageDraw.Draw(img) draw = ImageDraw.Draw(img)
font = ImageFont.truetype('resources/vzhuh/Impact.ttf', 44, index=0) font = ImageFont.truetype('resources/vzhuh/Impact.ttf', 44, index=0)
draw.text((222, 280), text, (0, 0, 0), font=font) draw.text((222, 280), text, (0, 0, 0), font=font)
img.save('storage/vzhuh.png') img.save(self.path)

View File

@ -4,12 +4,13 @@ from urllib.request import urlopen, Request
class Woof(Base): class Woof(Base):
name = 'woof' name = 'woof'
path = 'storage/woof.jpg'
headers = {'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"}
@staticmethod def execute(self, command):
def execute(bot, command): req = Request("http://loremflickr.com/500/410/dog", headers=self.headers)
req = Request("http://loremflickr.com/500/410/dog", headers={'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"}) output = open(self.path, "wb")
output = open("storage/woof.jpg", "wb")
output.write(urlopen(req).read()) output.write(urlopen(req).read())
output.close() output.close()
bot.send_photo(chat_id=command.chat_id, photo=open('storage/woof.jpg', 'rb')) self.send_photo(command, photo=open(self.path, 'rb'))

View File

@ -7,10 +7,10 @@ from urllib.request import urlopen
class XKCD(Base): class XKCD(Base):
name = 'xkcd' name = 'xkcd'
@staticmethod def execute(self, command):
def execute(bot, command):
last_id = json.loads(urlopen("http://xkcd.com/info.0.json").read().decode('utf-8'))['num'] last_id = json.loads(urlopen("http://xkcd.com/info.0.json").read().decode('utf-8'))['num']
id = random.randint(1, last_id) random_id = random.randint(1, last_id)
url = json.loads(urlopen('http://xkcd.com/' + str(id) + '/info.0.json').read().decode('utf-8'))['img'] req = urlopen('http://xkcd.com/%d/info.0.json' % random_id)
data = json.loads(req.read().decode('utf-8'))
bot.send_photo(chat_id=command.chat_id, photo=url) self.send_photo(command, photo=data['img'])