added settings menu

This commit is contained in:
Louis Heredero 2024-09-14 13:52:02 +02:00
parent 41d7dd066b
commit b7bf0e7fa2
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7

View File

@ -11,8 +11,8 @@ from typing import Optional
import requests import requests
import telegram.constants import telegram.constants
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from telegram import Update from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, CallbackQueryHandler
log_dir = os.getenv("BEEBOT_LOGS") log_dir = os.getenv("BEEBOT_LOGS")
if not log_dir: if not log_dir:
@ -35,6 +35,12 @@ logging.basicConfig(
logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def flag(code):
offset = 127462 - ord('A')
code = code.upper()
return chr(ord(code[0]) + offset) + chr(ord(code[1]) + offset)
class BeeBot: class BeeBot:
MENU_URL = "https://www.epfl.ch/campus/restaurants-shops-hotels/fr/industrie21-epfl-valais-wallis/?date={date}" MENU_URL = "https://www.epfl.ch/campus/restaurants-shops-hotels/fr/industrie21-epfl-valais-wallis/?date={date}"
RESTO_ID = 545 RESTO_ID = 545
@ -43,6 +49,34 @@ class BeeBot:
DB_PATH = os.path.join(BASE_DIR, "database.db") DB_PATH = os.path.join(BASE_DIR, "database.db")
TEMPLATE_PATH = os.path.join(BASE_DIR, "menu.typ") TEMPLATE_PATH = os.path.join(BASE_DIR, "menu.typ")
IMG_DIR = "/tmp/menu_images" IMG_DIR = "/tmp/menu_images"
LANGUAGES = {
"en": {
"emoji": flag("gb"),
"name": "English"
},
"fr": {
"emoji": flag("fr"),
"name": "Français"
},
"de": {
"emoji": flag("de"),
"name": "Deutsch"
}
}
CATEGORIES = {
"E": {
"name": "Étudiant"
},
"D": {
"name": "Doctorant"
},
"C": {
"name": "Campus"
},
"V": {
"name": "Visiteur"
}
}
def __init__(self, token: str): def __init__(self, token: str):
self.tg_token: str = token self.tg_token: str = token
@ -63,6 +97,8 @@ class BeeBot:
app = ApplicationBuilder().token(self.tg_token).build() app = ApplicationBuilder().token(self.tg_token).build()
app.add_handler(CommandHandler("week", self.cmd_week)) app.add_handler(CommandHandler("week", self.cmd_week))
app.add_handler(CommandHandler("today", self.cmd_today)) app.add_handler(CommandHandler("today", self.cmd_today))
app.add_handler(CommandHandler("settings", self.cmd_settings))
app.add_handler(CallbackQueryHandler(self.cb_handler))
logger.info("Starting bot") logger.info("Starting bot")
app.run_polling() app.run_polling()
@ -75,6 +111,74 @@ class BeeBot:
logger.debug("Received /today") logger.debug("Received /today")
await self.request_menu(update, context, True) await self.request_menu(update, context, True)
async def cmd_settings(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.debug("Received /settings")
menu = self.get_settings_menu(update)
reply_markup = InlineKeyboardMarkup(menu)
await update.effective_chat.send_message(text="Your preferences", reply_markup=reply_markup)
async def cb_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
query = update.callback_query
if query.data == "change_language":
await self.cb_change_language(update, context)
elif query.data.startswith("set_language"):
await self.cb_set_language(update, context)
elif query.data == "change_categories":
await self.cb_change_categories(update, context)
elif query.data.startswith("toggle_category"):
await self.cb_toggle_category(update, context)
elif query.data == "back_to_settings":
menu = self.get_settings_menu(update)
reply_markup = InlineKeyboardMarkup(menu)
await update.effective_message.edit_text(text="Your preferences", reply_markup=reply_markup)
async def cb_change_language(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.debug("Clicked 'Change language'")
menu = self.get_language_menu(update)
reply_markup = InlineKeyboardMarkup(menu)
await update.effective_message.edit_text(text="Choose a language", reply_markup=reply_markup)
async def cb_set_language(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
lang = update.callback_query.data.split(":")[1]
logger.debug(f"Clicked 'Set language to {lang}'")
cur = self.db_con.cursor()
cur.execute(
"UPDATE user SET lang=? WHERE telegram_id=?",
(lang, update.effective_user.id)
)
self.db_con.commit()
cur.close()
menu = self.get_language_menu(update)
reply_markup = InlineKeyboardMarkup(menu)
await update.effective_message.edit_text(text="Choose a language", reply_markup=reply_markup)
async def cb_change_categories(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.debug("Clicked 'Change categories'")
menu = self.get_categories_menu(update)
reply_markup = InlineKeyboardMarkup(menu)
await update.effective_message.edit_text(text="Choose the price categories to display", reply_markup=reply_markup)
async def cb_toggle_category(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
category = update.callback_query.data.split(":")[1]
logger.debug(f"Clicked 'Toggle category {category}'")
categories: set[str] = self.get_user_pref(update)["categories"]
if category in categories:
categories.remove(category)
else:
categories.add(category)
cur = self.db_con.cursor()
cur.execute(
"UPDATE user SET categories=? WHERE telegram_id=?",
(",".join(categories), update.effective_user.id)
)
self.db_con.commit()
cur.close()
menu = self.get_categories_menu(update)
reply_markup = InlineKeyboardMarkup(menu)
await update.effective_message.edit_text(text="Choose the price categories to display", reply_markup=reply_markup)
async def request_menu(self, update: Update, context: ContextTypes.DEFAULT_TYPE, today_only: bool) -> None: async def request_menu(self, update: Update, context: ContextTypes.DEFAULT_TYPE, today_only: bool) -> None:
chat_id = update.effective_chat.id chat_id = update.effective_chat.id
await context.bot.send_chat_action(chat_id=chat_id, action=telegram.constants.ChatAction.TYPING) await context.bot.send_chat_action(chat_id=chat_id, action=telegram.constants.ChatAction.TYPING)
@ -113,6 +217,7 @@ class BeeBot:
"id" INTEGER, "id" INTEGER,
"telegram_id" INTEGER NOT NULL UNIQUE, "telegram_id" INTEGER NOT NULL UNIQUE,
"categories" TEXT, "categories" TEXT,
"lang" TEXT NOT NULL DEFAULT 'fr',
"created_at" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, "created_at" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY("id" AUTOINCREMENT) PRIMARY KEY("id" AUTOINCREMENT)
); );
@ -123,27 +228,29 @@ class BeeBot:
def get_user_pref(self, update: Update) -> dict: def get_user_pref(self, update: Update) -> dict:
user_id = update.effective_user.id user_id = update.effective_user.id
cur = self.db_con.cursor() cur = self.db_con.cursor()
res = cur.execute("SELECT categories FROM user WHERE telegram_id=?", (user_id,)) res = cur.execute("SELECT categories, lang FROM user WHERE telegram_id=?", (user_id,))
user = res.fetchone() user = res.fetchone()
cur.close() cur.close()
if user is None: if user is None:
self.create_user(user_id) self.create_user(user_id)
return { return {
"categories": {"E", "D", "C", "V"} "categories": {"E", "D", "C", "V"},
"lang": "fr"
} }
categories = set(user[0].split(",")) categories = set(user[0].split(","))
return { return {
"categories": categories "categories": categories,
"lang": user[1]
} }
def create_user(self, telegram_id: int) -> None: def create_user(self, telegram_id: int) -> None:
logger.debug(f"New user with id {telegram_id}") logger.debug(f"New user with id {telegram_id}")
cur = self.db_con.cursor() cur = self.db_con.cursor()
cur.execute( cur.execute(
"INSERT INTO user (telegram_id, categories) VALUES (?, ?)", "INSERT INTO user (telegram_id, categories, lang) VALUES (?, ?, ?)",
(telegram_id, "E,D,C,V") (telegram_id, "E,D,C,V", "fr")
) )
self.db_con.commit() self.db_con.commit()
cur.close() cur.close()
@ -270,6 +377,52 @@ class BeeBot:
return menus return menus
def get_settings_menu(self, update: Update) -> list[list[InlineKeyboardButton]]:
prefs = self.get_user_pref(update)
menu = [
[
InlineKeyboardButton(f"Language: {prefs['lang']}", callback_data="change_language")
],
[
InlineKeyboardButton(f"Categories: {' / '.join(prefs['categories'])}", callback_data="change_categories")
]
]
return menu
def get_language_menu(self, update: Update) -> list[list[InlineKeyboardButton]]:
prefs = self.get_user_pref(update)
buttons = []
for lang, data in self.LANGUAGES.items():
extra = "" if prefs["lang"] == lang else ""
buttons.append(
InlineKeyboardButton(
data["emoji"] + extra,
callback_data=f"set_language:{lang}"
)
)
menu = [buttons[i:i+2] for i in range(0, len(buttons), 2)]
menu.append([
InlineKeyboardButton("Back to settings", callback_data="back_to_settings")
])
return menu
def get_categories_menu(self, update: Update) -> list[list[InlineKeyboardButton]]:
prefs = self.get_user_pref(update)
buttons = []
for categ, data in self.CATEGORIES.items():
extra = "" if categ in prefs["categories"] else ""
buttons.append(
InlineKeyboardButton(
data["name"] + extra,
callback_data=f"toggle_category:{categ}"
)
)
menu = [buttons[i:i+2] for i in range(0, len(buttons), 2)]
menu.append([
InlineKeyboardButton("Back to settings", callback_data="back_to_settings")
])
return menu
if __name__ == '__main__': if __name__ == '__main__':
logger.info("Welcome to BeeBot !") logger.info("Welcome to BeeBot !")
bot = BeeBot(os.getenv("TELEGRAM_TOKEN")) bot = BeeBot(os.getenv("TELEGRAM_TOKEN"))