From 4aa3a5b2d9028622db54e54487f5004a61327abe Mon Sep 17 00:00:00 2001 From: Antonio De Lucreziis Date: Wed, 26 Jul 2023 18:08:51 +0200 Subject: [PATCH] chore: alcuni fix e riorganizzazione con yield e generatori --- .env.example | 2 +- bot.py | 292 ++++++++++++++++++++++++++++----------------------- 2 files changed, 160 insertions(+), 134 deletions(-) diff --git a/.env.example b/.env.example index ff3ba3f..c72acd0 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ BOT_TOKEN= -ADMIN_TELEGRAM_ID= +TELEGRAM_ADMIN_ID= diff --git a/bot.py b/bot.py index b6f911e..02a6b27 100644 --- a/bot.py +++ b/bot.py @@ -52,7 +52,6 @@ cursor.execute( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expiration_datetime TIMESTAMP DEFAULT NULL, FOREIGN KEY (owner_id) REFERENCES utenti (telegram_id) - ON DELETE CASCADE )""" ) conn.commit() @@ -63,14 +62,23 @@ cursor.execute( owner_id TEXT NOT NULL, proposta_id TEXT NOT NULL, content TEXT NOT NULL, - FOREIGN KEY (owner_id) REFERENCES utenti (telegram_id) - ON DELETE CASCADE, + FOREIGN KEY (owner_id) REFERENCES utenti (telegram_id), FOREIGN KEY (proposta_id) REFERENCES proposte (id) - ON DELETE CASCADE )""" ) conn.commit() +cursor.execute( + """ + CREATE TRIGGER IF NOT EXISTS cleanup_ordinazioni + AFTER DELETE ON proposte + BEGIN + DELETE FROM ordinazioni WHERE proposta_id = old.id; + END + """ +) +conn.commit() + cursor.execute( """CREATE TABLE IF NOT EXISTS utenti ( telegram_id TEXT PRIMARY KEY, @@ -130,10 +138,13 @@ def handle_status(message): nl = "\n" - bot.send_message(message.chat.id, f"*Ordinazioni alle tue proposte:*") - for o in ordinazioni_per_tue_proposte: - (proposta_id, _, name, description, _, _, _, _, _, ordinazione, _, username, _) = o - bot.send_message(message.chat.id, f"- _{name}_ per @{username} {nl}{ordinazione}") + bot.send_message(message.chat.id, f"*Ordinazioni alle tue proposte*") + if len(ordinazioni_per_tue_proposte) == 0: + bot.send_message(message.chat.id, f"Nessuno ha ancora ordinato qualcosa") + else: + for o in ordinazioni_per_tue_proposte: + (proposta_id, _, name, description, _, _, _, _, _, ordinazione, _, username, _) = o + bot.send_message(message.chat.id, f"- Ordine di @{username} per _{name}_{nl}{ordinazione}") tue_ordinazione = list( cursor.execute( @@ -146,26 +157,95 @@ def handle_status(message): nl = "\n" - bot.send_message(message.chat.id, f"*Le tue ordinazioni:*") - for o in tue_ordinazione: - (_, _, _, ordinazione, _, _, name, description, _, _, _, username, _) = o - bot.send_message(message.chat.id, f"- _{name}_ creata da @{username}{nl}{ordinazione}") + bot.send_message(message.chat.id, f"*Le tue ordinazioni*") + if len(tue_ordinazione) == 0: + bot.send_message(message.chat.id, f"Non ha ancora ordinato nulla") + else: + for o in tue_ordinazione: + (_, _, _, ordinazione, _, _, name, description, _, _, _, username, _) = o + bot.send_message(message.chat.id, f"- Ordine per _{name}_ di @{username}{nl}{ordinazione}") + + +def conversazione(func): + """ + Questa annotazione va applicata ad una conversazione a più step e permette di usare + message = yield -conversazioni_nuova_ordinazione = dict() -conversazioni_proposte = dict() + per mettere in pausa il codice e riprendere quando l'utente invia un messaggio di risposta. + """ + + def inner(message): + conv = func(message) + registro_conversazioni[message.chat.id] = conv + next(conv) + + return inner + + +@bot.message_handler(commands=["stop"]) +def handle_stop(message): + del registro_conversazioni[message.chat.id] @bot.message_handler(commands=["nuova_proposta"]) +@conversazione def handle_nuova_proposta(message): + """ + Chiede all'utente nome e descrizione della proposta e poi la aggiunge al database + """ + bot.send_message( message.chat.id, "Inserisci nome e descrizione dell'ordine (sulla prima riga il nome ed il resto dopo un accapo sarà la descrizione, invia /stop per uscire)", ) - print(f"Inizio conversazione con @{message.chat.username} per aggiungere una proposta") + message = yield - conversazioni_proposte[message.chat.id] = True + parts = message.text.split("\n", 1) + + proposta_id = str(uuid.uuid4()) + owner_id = str(message.from_user.id) + name = parts[0] + description = parts[1] if len(parts) > 1 else "" + + testo = "" + testo += f"*Proposta aggiunta con successo*" + "\n" + testo += f"Nome: {name}" + "\n" + testo += f"Descrizione: {description}" + "\n" + + bot.send_message(message.chat.id, testo) + + cursor.execute( + """ + INSERT INTO proposte(id, owner_id, name, description) VALUES (?, ?, ?, ?) + """, + (proposta_id, owner_id, name, description), + ) + conn.commit() + + # Notifichiamo della proposta gli utenti che hanno le notifiche attivate + + users_to_notify = list( + cursor.execute( + """ + SELECT * FROM utenti WHERE notification = TRUE + """, + ) + ) + + for utente in users_to_notify: + (user_id, _, _) = utente + + if user_id == owner_id: + continue + + testo = "" + testo += f"*Nuova proposta* da @{message.from_user.username}" + "\n" + testo += f"Nome: {name}" + "\n" + testo += f"Descrizione: {description}" + "\n" + + bot.send_message(user_id, testo) @bot.message_handler(commands=["proposte"]) @@ -197,10 +277,8 @@ def handle_proposte(message): bot.send_message(message.chat.id, testo) -conversazioni_nuova_ordinazione = dict() - - @bot.message_handler(commands=["nuova_ordinazione"]) +@conversazione def handle_nuova_ordinazione(message): owner_id = str(message.from_user.id) @@ -212,35 +290,68 @@ def handle_nuova_ordinazione(message): ) ) - testo = "Lista delle proposte:\n" + indicizzazione = {} + testo_proposte = "Lista delle proposte:\n" for i, p in enumerate(proposte): - (uuid, _, name, description, _, expiration_time) = p - - testo += textwrap.dedent( - f""" - {i + 1}. *{name}*: - {description} - """ - ) + (proposta_id, _, name, description, _, expiration_time) = p - indicizzazione = {str(i + 1): p[0] for i, p in enumerate(proposte)} - print(indicizzazione) + indicizzazione[str(i + 1)] = proposta_id - conversazioni_nuova_ordinazione[message.chat.id] = { - "indicizzazione": indicizzazione, - "proposta_id": None, - } + testo_proposte += f"{i + 1}. *{name}*:" + "\n" + testo_proposte += f"{description}" + "\n" - bot.send_message(message.chat.id, testo) + bot.send_message(message.chat.id, testo_proposte) bot.send_message(message.chat.id, "Invia il numero della proposta a cui vuoi aggiungere un'ordinazione") + while True: + message = yield + indice = message.text.strip() + if indice in indicizzazione: + break + indici = ", ".join(str(k) for k in indicizzazione.keys()) + bot.send_message(message.chat.id, f"Numero non valido, inviane uno tra {indici}") + + proposta_id = indicizzazione[indice] + + bot.send_message(message.chat.id, f"Ok, ora dì cosa vuoi ordinare") + message = yield + + ordinazione_id = str(uuid.uuid4()) + content = message.text.strip() + + cursor.execute( + """ + INSERT INTO ordinazioni(id, owner_id, proposta_id, content) VALUES (?, ?, ?, ?) + """, + (ordinazione_id, str(message.from_user.id), proposta_id, content), + ) + conn.commit() + + # Notifica il creatore dell'ordine ed il corrispondente creatore della proposta del nuovo ordine + + bot.send_message(message.chat.id, f"Ok, ordinazione aggiunta") + + (proposta_owner_id, proposta_name) = cursor.execute( + """ + SELECT owner_id, name from proposte WHERE id = ? + """, + (proposta_id,), + ).fetchone() + + testo_proposte = "" + testo_proposte = f"@{message.from_user.username} ha aggiunto un'ordinazione a _{proposta_name}_" + "\n" + + bot.send_message(proposta_owner_id, testo_proposte) + + return + @bot.message_handler(commands=["attiva_notifiche"]) def handle_attiva_notifiche(message): owner_id = str(message.from_user.id) cursor.execute( - f""" + """ UPDATE utenti SET notification = TRUE WHERE telegram_id = ? """, (owner_id,), @@ -255,7 +366,7 @@ def handle_disattiva_notifiche(message): owner_id = str(message.from_user.id) cursor.execute( - f""" + """ UPDATE utenti SET notification = FALSE WHERE telegram_id = ? """, (owner_id,), @@ -265,108 +376,23 @@ def handle_disattiva_notifiche(message): bot.send_message(message.chat.id, "Notifiche disattivate") +# Dizionario da chat a generatore per quella conversazione +registro_conversazioni = dict() + + @bot.message_handler() def handle_conversazione(message): print(f"handle_conversazione: {message.text}") - if message.chat.id in conversazioni_proposte: - print(f"Continuo conversazione con @{message.from_user.username} per aggiungere una proposta") - - parts = message.text.split("\n", 1) - - proposta_id = str(uuid.uuid4()) - owner_id = str(message.from_user.id) - name = parts[0] - description = parts[1] if len(parts) > 1 else "" - - testo = "" - testo += f"*Proposta aggiunta con successo*" + "\n" - testo += f"Nome: {name}" + "\n" - testo += f"Descrizione: {description}" + "\n" - - bot.send_message(message.chat.id, testo) - - cursor.execute( - """ - INSERT INTO proposte(id, owner_id, name, description) VALUES (?, ?, ?, ?) - """, - (proposta_id, owner_id, name, description), - ) - conn.commit() - - del conversazioni_proposte[message.chat.id] - - users_to_notify = list( - cursor.execute( - """ - SELECT * FROM utenti WHERE notification = TRUE - """, - ) - ) - - for utente in users_to_notify: - (user_id, _, _) = utente - - print(repr(user_id), repr(owner_id)) - if user_id == owner_id: - continue - - testo = "" - testo += f"*Nuova proposta* da @{message.from_user.username}" + "\n" - testo += f"Nome: {name}" + "\n" - testo += f"Descrizione: {description}" + "\n" - - bot.send_message(user_id, testo) + if message.chat.id in registro_conversazioni: + conv = registro_conversazioni[message.chat.id] + try: + result = conv.send(message) + print("Generator:", result) + except StopIteration: + del registro_conversazioni[message.chat.id] return - if message.chat.id in conversazioni_nuova_ordinazione: - conv = conversazioni_nuova_ordinazione[message.chat.id] - if conv["proposta_id"] is None: - indice = message.text.strip() - if indice not in conv["indicizzazione"]: - indici = ", ".join(str(k) for k in conv["indicizzazione"].keys()) - bot.send_message(message.chat.id, f"Numero non valido, inviane uno tra {indici}") - return - - proposta_uuid = conv["indicizzazione"][indice] - - conv["proposta_id"] = proposta_uuid - - bot.send_message(message.chat.id, f"Ok, ora dì cosa vuoi ordinare") - - print(conv) - return - else: - ordinazione_id = str(uuid.uuid4()) - ordinazione = message.text.strip() - - cursor.execute( - f""" - INSERT INTO ordinazioni(id, owner_id, proposta_id, content) VALUES (?, ?, ?, ?) - """, - (ordinazione_id, str(message.from_user.id), conv["proposta_id"], ordinazione), - ) - conn.commit() - - del conversazioni_nuova_ordinazione[message.chat.id] - - # Notifica al creatore della proposta del nuovo ordine - - bot.send_message(message.chat.id, f"Ok, ordinazione aggiunta") - - (proposta_owner_id, proposta_name) = cursor.execute( - f""" - SELECT owner_id, name from proposte WHERE id = ? - """, - (conv["proposta_id"],), - ).fetchone() - - testo = "" - testo = f"@{message.from_user.username} ha aggiunto un'ordinazione a _{proposta_name}_" + "\n" - - bot.send_message(proposta_owner_id, testo) - - return bot.send_message(message.chat.id, "Non hai cominciato una conversazione! Usa uno dei comandi")