From 8c5fd117eafce988a782661b66ad7c1b64b72523 Mon Sep 17 00:00:00 2001 From: Stefano Vittorio Porta Date: Thu, 19 Oct 2023 00:01:50 +0200 Subject: [PATCH] feat: added feedback buttons for automated messages Also, automated messages save a copy of the original message. Improves #5 --- bot.py | 57 +++++++++++++++++++++++++++++++++++++++--------- data/question.py | 36 ++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 data/question.py diff --git a/bot.py b/bot.py index 1a95b28..cb6032b 100644 --- a/bot.py +++ b/bot.py @@ -12,10 +12,12 @@ from telegram import Update, MessageEntity, InlineKeyboardMarkup, InlineKeyboardButton, User as TelegramUser, \ ChatMemberAdministrator from telegram.constants import MessageEntityType, ParseMode, ChatType -from telegram.ext import ContextTypes, Application, ApplicationBuilder, CommandHandler +from telegram.ext import ContextTypes, Application, ApplicationBuilder, CommandHandler, MessageHandler, filters, \ + CallbackQueryHandler, CallbackContext from data.botchat import BotChat from data.botuser import BotUser +from data.question import Question def load_api_key(path: str) -> str: @@ -45,7 +47,7 @@ def __init__(self, shortcut: list[str] | None, name: str, url: str | list[str]): ResourceData(["anno2"], "Gruppo per gli Studenti del Secondo Anno", "https://t.me/joinchat/huoxYswWOLQ5Mjk0"), ResourceData(["anno3"], "Gruppo per gli Studenti del Terzo Anno", "https://t.me/joinchat/UmWgshpk8MXD_Y4KvLyU8A"), - ResourceData(["links"], "Lista dei link", "https://tsi-unito.eu/links"), + ResourceData(["link", "links"], "Lista dei link", "https://tsi-unito.eu/links"), ResourceData(["lavoratori"], "Gruppo Studenti Lavoratori", "https://t.me/joinchat/QC1UEhvITLJNL33noRtszQ"), ResourceData(["internazionali", "international"], "International Students Group", "https://t.me/international_students_CS_unito"), @@ -190,7 +192,7 @@ async def command_start(update: Update, context: ContextTypes.DEFAULT_TYPE): await message.reply_html( f"Ciao! Attualmente la funzionalità che hai richiesto non è disponibile.\n" f"Se credi che questo sia un errore, inoltra questo messaggio a @Stefa168.\n\n" - f"payload: {payload}") + f"payload: {payload}") await delete_message(message) @@ -253,12 +255,39 @@ def user_has_role(user: TelegramUser, accepted_roles: set[str], session: Session async def reply_repo_appunti(update: Update, context: ContextTypes.DEFAULT_TYPE): - await update.message.reply_html(f"Ciao {update.message.from_user.full_name}, puoi trovare molti appunti gratuiti " - f"sulla Guida degli Studenti\n\n" - f" » Appunti", - quote=True, - message_thread_id=update.message.message_thread_id) + message = update.message + + with Session(engine) as session: + question = Question(message.message_id, message.from_user.id, message.text) + + session.add(question) + # IT IS CRUCIAL TO FLUSH TO REGISTER THE DATA ON THE DB + # Otherwise, some fields won't be populated. + session.flush() + + feedback_kb = InlineKeyboardMarkup.from_row([ + InlineKeyboardButton(emojize("Utile :thumbsup:", language="alias"), + callback_data=f"upvote-{question.id}"), + InlineKeyboardButton(emojize("Non utile :thumbsdown:", language="alias"), + callback_data=f"downvote-{question.id}") + ]) + + # todo1 + # If the original message is edited, we should stop tracking for feedback. + # Also, we should check if the user is banned from giving feedback. + # No more than one feedback point (negative or positive) can be assigned by one user on a message. + await update.message.reply_html( + f"Ciao {update.message.from_user.full_name}, puoi trovare molti appunti gratuiti " + f"sulla Guida degli Studenti\n\n" + f" » Appunti\n\n" + f"(Messaggio automatico, lascia un feedback se ritieni che possa essere utile!)", + quote=True, + message_thread_id=update.message.message_thread_id, + disable_web_page_preview=True, + reply_markup=feedback_kb) + + session.commit() # noinspection DuplicatedCode @@ -348,6 +377,11 @@ def check(check_name: str, b: bool, prev: tuple[str, bool] = ("", True)): session.rollback() +async def handle_auto_feedback(update: Update, context: CallbackContext): + query = update.callback_query + print(query) + + def main(api_key: str) -> None: application: Application = ApplicationBuilder().token(api_key).build() @@ -359,7 +393,10 @@ def main(api_key: str) -> None: application.add_handler(CommandHandler(["start"], command_start)) application.add_handler(CommandHandler(["rappresentanti", "rapp"], command_rappresentanti)) application.add_handler(CommandHandler(["activate"], command_activate)) - application.add_handler(MessageHandler(filters.Regex("(vendo|cerco|compro|avete|qualcuno.*ha|Vendo|Cerco|Compro|Avete|Qualcuno.*ha).*appunti.*"),reply_repo_appunti)) #may be too generic + application.add_handler(MessageHandler( + filters.Regex("(vendo|cerco|compro|avete|qualcuno.*ha|Vendo|Cerco|Compro|Avete|Qualcuno.*ha).*appunti.*"), + reply_repo_appunti)) # may be too generic + application.add_handler(CallbackQueryHandler(handle_auto_feedback)) application.run_polling() diff --git a/data/question.py b/data/question.py new file mode 100644 index 0000000..753c1f5 --- /dev/null +++ b/data/question.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass +from datetime import datetime + +from sqlalchemy import Table, Column, Integer, BigInteger, String, DateTime, func +from sqlalchemy.orm import registry + +mapper_registry = registry() + + +@mapper_registry.mapped +@dataclass +class Question: + _tablename = "nlp_questions" + __table__ = Table( + _tablename, + mapper_registry.metadata, + Column("id", Integer(), primary_key=True, nullable=False), + Column("message_id", BigInteger(), index=True, unique=True, nullable=False), + Column("user_id", BigInteger(), index=True, unique=True, nullable=False), + Column("message", String(), nullable=False), + Column("date", DateTime(), server_default=func.now(), nullable=False) + ) + + id: int + message_id: int + user_id: int + message: str + date: datetime + + def __init__(self, message_id: int, user_id: int, message: str): + self.message_id = message_id + self.user_id = user_id + self.message = message + + def __repr__(self): + return f""