basic reworked bot

This commit is contained in:
Remy Moll
2021-01-29 21:45:16 +01:00
parent ec8983eb57
commit 39ae1ec038
18 changed files with 589 additions and 174 deletions

View File

@@ -1,5 +1,2 @@
# Placeholder
from . import clock
from . import help
from . import weather
from . import status
from . import clock, help, weather, status, zvv, lists, alias, plaintext

65
bot2/commands/alias.py Normal file
View File

@@ -0,0 +1,65 @@
from .template import *
FIRST = range(1)
class Alias(BotFunc):
"""create a new command for command-paths you often use"""
def __init__(self, dispatcher, prst):
super().__init__(prst)
self.dispatcher = dispatcher
# do not interact with him yet!
def create_handler(self):
conv_handler = ConversationHandler(
entry_points=[CommandHandler('alias', self.entry_point)],
states={
FIRST: [
CallbackQueryHandler(self.print_all, pattern="^all$"),
CallbackQueryHandler(self.create_alias, pattern="^new$"),
CallbackQueryHandler(self.delete_alias, pattern='^delete$'),
]
},
fallbacks=[CommandHandler('alias', self.entry_point)],
)
return conv_handler
def entry_point(self, update: Update, context: CallbackContext) -> None:
super().entry_point()
test = self.dispatcher
print(self.dispatcher.handlers[0])
keyboard = [
[InlineKeyboardButton("All aliases", callback_data="all")],
[InlineKeyboardButton("Create new alias", callback_data="new")],
[InlineKeyboardButton("Delete alias", callback_data="delete")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("What exactly do you want?", reply_markup=reply_markup)
return FIRST
def print_all(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
all_alias = ""
for k in self.persistence["bot"]["aliases"]:
all_alias += k + " - " + self.persistence["bot"]["aliases"] +"\n"
query.edit_message_text(text="List of all commands:\n" + all_alias)
return ConversationHandler.END
def create_alias(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
all_alias = ""
for k in self.persistence["bot"]["aliases"]:
all_alias += k + " - " + self.persistence["bot"]["aliases"] +"\n"
query.edit_message_text(text="List of all commands:\n" + all_alias)
return ConversationHandler.END
def delete_alias(self, update: Update, context: CallbackContext) -> None:
return ConversationHandler.END

View File

@@ -0,0 +1,23 @@
from .template import *
CHOOSE, ARGS = range(2)
class Clock(BotFunc):
"""pass on commands to clock-module"""
def __init__(self, prst, hw_commands):
super().__init__(prst)
self.hw_commands = hw_commands
def create_handler(self):
handler = ConversationHandler(
entry_points=[CommandHandler("clock", self.entry_point)],
states={
CHOOSE : [],
ARGS : []
},
fallbacks=[CommandHandler('clock', self.entry_point)],
)
return handler
def entry_point(self):
super().entry_point()

View File

@@ -1,19 +1,13 @@
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext
from telegram.ext import (
Updater,
CommandHandler,
CallbackQueryHandler,
ConversationHandler,
CallbackContext,
)
from .template import *
FIRST = 1
class Help():
class Help(BotFunc):
"""Shows the functions and their usage"""
def __init__(self):
def __init__(self, prst):
super().__init__(prst)
self.available_commands = {}
@@ -25,7 +19,7 @@ class Help():
CallbackQueryHandler(self.print_all, pattern="^all$"),
CallbackQueryHandler(self.choose_specific, pattern="^specific$"),
CallbackQueryHandler(self.print_one, pattern='func-'),
]
],
},
fallbacks=[CommandHandler('help', self.entry_point)],
)
@@ -34,9 +28,13 @@ class Help():
def add_commands(self, commands):
# commands is a dict {"name": class}
for k in commands:
self.available_commands[k] = commands[k].__doc__
if k != "plaintext":
self.available_commands[k] = commands[k].__doc__
def entry_point(self, update: Update, context: CallbackContext) -> None:
super().entry_point()
keyboard = [
[
InlineKeyboardButton("All commands", callback_data="all"),
@@ -51,12 +49,11 @@ class Help():
def print_all(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
all_cmd = ""
for k in self.available_commands:
all_cmd += k + " - " + self.available_commands[k] +"\n"
for h in self.available_commands:
all_cmd += h + " - `" + self.available_commands[h] + "`\n"
query.edit_message_text(text="List of all commands:\n" + all_cmd)
query.edit_message_text(text="List of all commands:\n" + all_cmd, parse_mode = ParseMode.MARKDOWN)
return ConversationHandler.END
@@ -66,8 +63,8 @@ class Help():
keyboard = [[InlineKeyboardButton(k, callback_data="func-" + k)] for k in self.available_commands]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text(
text="What command should be printed?", reply_markup=reply_markup
)
@@ -77,11 +74,12 @@ class Help():
def print_one(self, update: Update, context: CallbackContext) -> None:
"""Show new choice of buttons"""
query = update.callback_query
data = query.data.replace("func-", "")
name = query.data.replace("func-", "")
query.answer()
message = self.available_commands[data]
message = name + ": `" + self.available_commands[name] + "`"
query.edit_message_text(
text= message
text= message,
parse_mode = ParseMode.MARKDOWN_V2
)
return ConversationHandler.END

177
bot2/commands/lists.py Normal file
View File

@@ -0,0 +1,177 @@
from .template import *
import datetime
import requests
NAME, NEW, ACTION, ITEMADD, ITEMREMOVE = range(5)
class Lists(BotFunc):
"""Create and edit lists"""
def __init__(self, prst):
super().__init__(prst)
self.current_name = ""
def create_handler(self):
conv_handler = ConversationHandler(
entry_points=[CommandHandler('list', self.entry_point)],
states={
NAME: [
CallbackQueryHandler(self.choose_list, pattern="^list-"),
CallbackQueryHandler(self.new_list, pattern="^new$"),
],
NEW : [MessageHandler(Filters.text, callback=self.new_listname)],
ACTION: [
CallbackQueryHandler(self.list_add, pattern="^add$"),
CallbackQueryHandler(self.list_remove, pattern="^remove$"),
CallbackQueryHandler(self.list_clear, pattern="^clear$"),
CallbackQueryHandler(self.list_delete, pattern="^delete$"),
CallbackQueryHandler(self.list_print, pattern="^print$"),
CallbackQueryHandler(self.list_menu, pattern="^overview$"),
],
ITEMADD : [MessageHandler(Filters.text, callback=self.list_add_item)],
ITEMREMOVE : [CallbackQueryHandler(self.list_remove_index)]
},
fallbacks=[CommandHandler('list', self.entry_point)],
)
return conv_handler
def entry_point(self, update: Update, context: CallbackContext) -> None:
super().entry_point()
keyboard = [[InlineKeyboardButton(k, callback_data="list-"+k)] for k in self.persistence["global"]["lists"]] + [[InlineKeyboardButton("New list", callback_data="new")]]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text(text="Here are the existing lists. You can also create a new one:", reply_markup=reply_markup)
return NAME
def choose_list(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
data = query.data
name = data.replace("list-","")
query.answer()
self.current_name = name
keyboard = [
[InlineKeyboardButton("Add item", callback_data="add")],
[InlineKeyboardButton("Remove item", callback_data="remove")],
[InlineKeyboardButton("Clear list", callback_data="clear")],
[InlineKeyboardButton("Print list", callback_data="print")],
[InlineKeyboardButton("Delete list", callback_data="delete")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("Very well. For " + name + " the following actions are available:", reply_markup=reply_markup)
return ACTION
def list_menu(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
keyboard = [
[InlineKeyboardButton("Add item", callback_data="add")],
[InlineKeyboardButton("Remove item", callback_data="remove")],
[InlineKeyboardButton("Clear list", callback_data="clear")],
[InlineKeyboardButton("Print list", callback_data="print")],
[InlineKeyboardButton("Delete list", callback_data="delete")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("Very well. For " + self.current_name + " the following actions are available:", reply_markup=reply_markup)
return ACTION
def new_list(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
query.edit_message_text("What's the name of the new list?")
return NEW
def new_listname(self, update: Update, context: CallbackContext) -> None:
name = update.message.text
if name not in self.persistence["global"]["lists"]:
self.persistence["global"]["lists"][name] = []
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("To the menu!", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
self.current_name = name
update.message.reply_text("Thanks. List " + name + " was successfully created.", reply_markup=reply_markup)
return ACTION
else:
update.message.reply_text("Oh no! That list already exists")
return ConversationHandler.END
def list_add(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
query.edit_message_text("What would you like to add?")
return ITEMADD
def list_remove(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
keyboard = [[InlineKeyboardButton(k, callback_data=i)] for i,k in enumerate(self.persistence["global"]["lists"][self.current_name])]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("Which item would you like to remove?", reply_markup = reply_markup)
return ITEMREMOVE
def list_clear(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
self.persistence["global"]["lists"][self.current_name] = []
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("List " + self.current_name + " cleared", reply_markup=reply_markup)
return ACTION
def list_delete(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
self.persistence["global"]["lists"].pop(self.current_name, None)
query.edit_message_text("List " + self.current_name + " deleted")
return ConversationHandler.END
def list_print(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
content = "\n".join(self.persistence["global"]["lists"][self.current_name])
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("Content of " + self.current_name + ":\n" + content, reply_markup=reply_markup)
return ACTION
def list_add_item(self, update: Update, context: CallbackContext) -> None:
name = update.message.text
self.persistence["global"]["lists"][self.current_name] += [name]
keyboard = [[InlineKeyboardButton("Add some more", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("Added " + name, reply_markup=reply_markup)
return ACTION
def list_remove_index(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
ind = int(query.data)
query.answer()
old = self.persistence["global"]["lists"][self.current_name]
name = old.pop(ind)
self.persistence["global"]["lists"][self.current_name] = old
keyboard = [[InlineKeyboardButton("Remove another", callback_data="remove"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("Removed " + name, reply_markup=reply_markup)
return ACTION

View File

@@ -0,0 +1,15 @@
from .template import *
class Plain(BotFunc):
"""Not a command: just keeps logs and usage_data"""
def __init__(self, prst):
super().__init__(prst)
def create_handler(self):
h = MessageHandler(Filters.text, callback=self.add_to_log)
return h
def add_to_log(self, update: Update, context: CallbackContext) -> None:
super().entry_point()
super().increase_counter("receive_activity")

View File

@@ -1,35 +1,29 @@
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext
from telegram.ext import (
Updater,
CommandHandler,
CallbackQueryHandler,
ConversationHandler,
CallbackContext,
)
from .template import *
import datetime
import requests
import socket
import numpy as np
import os
FIRST = 1
class Status():
class Status(BotFunc):
"""Shows a short status of the program."""
def __init__(self, name, version, prst, logger):
def __init__(self, name, version, prst):
super().__init__(prst)
self.start_time = datetime.datetime.now()
self.name = name
self.version = version
self.persistence = prst
self.logger = logger
def create_handler(self):
conv_handler = ConversationHandler(
entry_points=[CommandHandler('status', self.entry_point)],
states={
FIRST: [
CallbackQueryHandler(self.print_status, pattern="^status-"),
CallbackQueryHandler(self.send_log, pattern="^full$"),
]
},
fallbacks=[CommandHandler('status', self.entry_point)],
@@ -38,22 +32,14 @@ class Status():
def entry_point(self, update: Update, context: CallbackContext) -> None:
super().entry_point()
user = update.message.from_user
keyboard = [
[
InlineKeyboardButton("Status", callback_data="status-simple"),
InlineKeyboardButton("With log", callback_data="status-full"),
InlineKeyboardButton("And the log?", callback_data="full"),
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("What exactly do you want?", reply_markup=reply_markup)
return FIRST
def print_status(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
wanted = query.data.replace("status-","")
query.answer()
delta = str(datetime.datetime.now() - self.start_time)
message = "BeebBop, this is " + self.name + " (V." + self.version + ")\n"
@@ -68,25 +54,30 @@ class Status():
ip = "not fetchable"
local_ips = "not fetchable"
message += "<pre>Status: Running 🟢\n"
message += "Uptime: " + delta[:delta.rfind(".")] + "\n"
message += "Reboots: " + str(self.persistence["global"]["reboots"]) + "\n"
message += "IP (public): " + ip + "\n"
message += "IP (private): " + str(local_ips) + "\n"
message += "Status: Running 🟢\n"
message += "Uptime: `" + delta[:delta.rfind(".")] + "`\n"
message += "Reboots: `" + str(self.persistence["global"]["reboots"]) + "`\n"
message += "IP (public): `" + ip + "`\n"
message += "IP (private): `" + str(local_ips) + "`\n"
tot_r = np.array(self.persistence["bot"]["receive_activity"]["count"]).sum()
message += "Total messages read: " + str(tot_r) + "\n"
message += "Total messages read: `" + str(tot_r) + "`\n"
tot_s = np.array(self.persistence["bot"]["send_activity"]["count"]).sum()
message += "Total messages sent: " + str(tot_s) + "\n"
message += "Total messages sent: `" + str(tot_s) + "`\n"
tot_e = np.array(self.persistence["bot"]["execute_activity"]["count"]).sum()
message += "Commands executed " + str(tot_e) + "</pre>\n"
message += "Commands executed `" + str(tot_e) + "`\n"
if wanted == "full":
message += str(dir(self.logger))
update.message.reply_text(message, reply_markup=reply_markup)
return FIRST
query.edit_message_text(
text= message
)
return ConversationHandler.END
def send_log(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query
wanted = query.data.replace("status-","")
query.answer()
with open("persistence/complete.log") as l:
query.message.reply_document(l)
return ConversationHandler.END

33
bot2/commands/template.py Normal file
View File

@@ -0,0 +1,33 @@
import logging
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ParseMode
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext, MessageHandler, Filters
from telegram.ext import (
Updater,
CommandHandler,
CallbackQueryHandler,
ConversationHandler,
CallbackContext,
)
import datetime
class BotFunc():
"""Base class for a specific bot-functionality"""
def __init__(self, prst):
self.logger = logging.getLogger(__name__)
self.persistence = prst
def entry_point(self):
self.increase_counter("execute_activity")
def increase_counter(self, counter_name):
current_hour = int(datetime.datetime.now().timestamp() // 3600)
if len(self.persistence["bot"][counter_name]["hour"]) == 0 or current_hour != self.persistence["bot"][counter_name]["hour"][-1]:
self.persistence["bot"][counter_name]["hour"].append(current_hour)
self.persistence["bot"][counter_name]["count"].append(1)
else:
self.persistence["bot"][counter_name]["count"][-1] += 1

View File

@@ -1,23 +1,18 @@
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext
from telegram.ext import (
Updater,
CommandHandler,
CallbackQueryHandler,
ConversationHandler,
CallbackContext,
)
from .template import *
import datetime
FIRST = 1
class Weather():
class Weather(BotFunc):
"""Shows a weatherforecast for a given location"""
def __init__(self, api):
def __init__(self, api, prst):
"""initialize api and persistence"""
super().__init__(prst)
self.api = api
self.city = ""
def create_handler(self):
"""returns the handlers with button-logic"""
conv_handler = ConversationHandler(
@@ -36,6 +31,7 @@ class Weather():
def entry_point(self, update: Update, context: CallbackContext) -> None:
"""Reacts the call of the command. Prints the first buttons"""
super().entry_point()
keyboard = [
[
InlineKeyboardButton("Zürich", callback_data="city-zurich"),
@@ -44,7 +40,10 @@ class Weather():
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("Which city?", reply_markup=reply_markup)
if update.message:
update.message.reply_text("Which city?", reply_markup=reply_markup)
else:
update.callback_query.edit_message_text("Which city", reply_markup=reply_markup)
return FIRST

86
bot2/commands/zvv.py Normal file
View File

@@ -0,0 +1,86 @@
from .template import *
import datetime
import requests
START, DEST = range(2)
class Zvv(BotFunc):
"""Connects to the swiss travel-api to get public transport routes"""
def __init__(self, prst):
super().__init__(prst)
self.start = ""
self.dest = ""
pass
def create_handler(self):
conv_handler = ConversationHandler(
entry_points=[CommandHandler('zvv', self.entry_point)],
states={
START: [MessageHandler(Filters.text, callback=self.get_start)],
DEST: [MessageHandler(Filters.text, callback=self.get_dest)]
},
fallbacks=[CommandHandler('zvv', self.entry_point)],
)
return conv_handler
def entry_point(self, update: Update, context: CallbackContext) -> None:
super().entry_point()
update.message.reply_text("What is the start point?")
return START
def get_start(self, update: Update, context: CallbackContext) -> None:
loc = update.message.text
self.start = loc
update.message.reply_text("Ok. Going from " + loc + ", what is the destination?")
return DEST
def get_dest(self, update: Update, context: CallbackContext) -> None:
loc = update.message.text
self.dest = loc
route = self.get_result()
update.message.reply_text("Her are the routes I've got:\n" + route)
return ConversationHandler.END
def get_result(self):
url = "http://transport.opendata.ch/v1/connections"
start = self.start
dest = self.dest
data = {"from" : start, "to" : dest, "limit" : 2}
try:
routes = requests.get(url, params=data).json()
result = routes["connections"]
text = result[0]["from"]["station"]["name"] + "" + result[0]["to"]["station"]["name"] + "\n\n"
for con in result:
text += "Start: " + datetime.datetime.fromtimestamp(int(con["from"]["departureTimestamp"])).strftime("%d/%m - %H:%M") + "\n"
text += "🏁 " + datetime.datetime.fromtimestamp(int(con["to"]["arrivalTimestamp"])).strftime("%d/%m - %H:%M") + "\n"
text += "" + con["duration"] + "\n"
text += "🗺️ Route:\n"
for step in con["sections"]:
if step["journey"] != None:
text += step["journey"]["passList"][0]["station"]["name"] + " (" + datetime.datetime.fromtimestamp(int(step["journey"]["passList"][0]["departureTimestamp"])).strftime("%H:%M") + ")\n"
text += "➡️ Linie " + self.number_to_emoji(step["journey"]["number"]) + "\n"
text += step["journey"]["passList"][-1]["station"]["name"] + " (" + datetime.datetime.fromtimestamp(int(step["journey"]["passList"][-1]["arrivalTimestamp"])).strftime("%H:%M") +")\n"
else:
text += "Walk."
text += "\n"
return text
except:
return "Invalid api call."
def number_to_emoji(self, number):
out = ""
numbers = ["0","1","2","3","4","5","6","7","8","9"]
for i in str(number):
out += numbers[int(i)]
return str(out)