1
Fork 0
mirror of https://github.com/Steffo99/greed.git synced 2024-11-22 14:04:18 +00:00

Start working on the code for the bot

This commit is contained in:
Steffo 2017-12-21 10:42:23 +01:00
parent d4febea186
commit 5f04a1ffe9
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: C27544372FBB445D
4 changed files with 99 additions and 15 deletions

View file

@ -75,7 +75,7 @@ def main():
# Skip the update # Skip the update
continue continue
# If the message is a start command... # If the message is a start command...
if update.message.text == "/start": if update.message.text is not None and update.message.text == "/start":
# Check if a worker already exists for that chat # Check if a worker already exists for that chat
old_worker = chat_workers.get(update.message.chat.id) old_worker = chat_workers.get(update.message.chat.id)
# If it exists, gracefully stop the worker # If it exists, gracefully stop the worker

View file

@ -33,14 +33,14 @@ class User(TableDeclarativeBase):
# Extra table parameters # Extra table parameters
__tablename__ = "users" __tablename__ = "users"
def __init__(self, telegram_user: telegram.User, **kwargs): def __init__(self, telegram_chat: telegram.Chat, **kwargs):
# Initialize the super # Initialize the super
super().__init__(**kwargs) super().__init__(**kwargs)
# Get the data from telegram # Get the data from telegram
self.id = telegram_user.id self.user_id = telegram_chat.id
self.first_name = telegram_user.first_name self.first_name = telegram_chat.first_name
self.last_name = telegram_user.last_name self.last_name = telegram_chat.last_name
self.username = telegram_user.username self.username = telegram_chat.username
# The starting wallet value is 0 # The starting wallet value is 0
self.credit = decimal.Decimal("0") self.credit = decimal.Decimal("0")

View file

@ -15,10 +15,26 @@ in_stock_format_string = "{quantity} disponibili"
conversation_after_start = "Ciao!\n" \ conversation_after_start = "Ciao!\n" \
"Benvenuto su greed!" "Benvenuto su greed!"
# Answer: to send an inline keyboard you need to send a message with it
conversation_open_user_menu = "Allora, {username}, cosa vorresti fare?"
# Notification: the conversation has expired # Notification: the conversation has expired
conversation_expired = "🕐 Il bot non ha ricevuto messaggi per un po' di tempo, quindi ha chiuso la conversazione.\n" \ conversation_expired = "🕐 Il bot non ha ricevuto messaggi per un po' di tempo, quindi ha chiuso la conversazione.\n" \
"Per riavviarne una nuova, invia il comando /start." "Per riavviarne una nuova, invia il comando /start."
# User menu: order
menu_order = "🛍 Ordina"
# User menu: order status
menu_order_status = "❓ Stato ordini"
# User menu: add credit
menu_add_credit = "💵 Ricarica"
# User menu: bot info
menu_info = " Informazioni sul bot"
# Error: message received not in a private chat # Error: message received not in a private chat
error_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private." error_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private."

View file

@ -1,9 +1,11 @@
import threading import threading
import typing
import telegram import telegram
import strings import strings
import configloader import configloader
import sys import sys
import queue as queuem import queue as queuem
import database as db
class StopSignal: class StopSignal:
"""A data class that should be sent to the worker when the conversation has to be stopped abnormally.""" """A data class that should be sent to the worker when the conversation has to be stopped abnormally."""
@ -21,6 +23,11 @@ class ChatWorker(threading.Thread):
# Store the bot and chat info inside the class # Store the bot and chat info inside the class
self.bot = bot self.bot = bot
self.chat = chat self.chat = chat
# Open a new database session
self.session = db.Session()
# Get the user db data from the users and admin tables
self.user = self.session.query(db.User).filter(db.User.user_id == self.chat.id).one_or_none()
self.admin = self.session.query(db.Admin).filter(db.Admin.user_id == self.chat.id).one_or_none()
# The sending pipe is stored in the ChatWorker class, allowing the forwarding of messages to the chat process # The sending pipe is stored in the ChatWorker class, allowing the forwarding of messages to the chat process
self.queue = queuem.Queue() self.queue = queuem.Queue()
@ -29,11 +36,20 @@ class ChatWorker(threading.Thread):
# TODO: catch all the possible exceptions # TODO: catch all the possible exceptions
# Welcome the user to the bot # Welcome the user to the bot
self.bot.send_message(self.chat.id, strings.conversation_after_start) self.bot.send_message(self.chat.id, strings.conversation_after_start)
# TODO: Send a command list or something # If the user isn't registered, create a new record and add it to the db
while True: if self.user is None:
# For now, echo the sent message # Create the new record
update = self._receive_next_update() self.user = db.User(self.chat)
self.bot.send_message(self.chat.id, f"{threading.current_thread().name} {update.message.text}") # Add the new record to the db
self.session.add(self.user)
# Commit the transaction
self.session.commit()
# If the user is not an admin, send him to the user menu
if self.admin is None:
self.__user_menu()
# If the user is an admin, send him to the admin menu
else:
self.__admin_menu()
def stop(self, reason: str=""): def stop(self, reason: str=""):
"""Gracefully stop the worker process""" """Gracefully stop the worker process"""
@ -42,7 +58,7 @@ class ChatWorker(threading.Thread):
# Wait for the thread to stop # Wait for the thread to stop
self.join() self.join()
def _receive_next_update(self) -> telegram.Update: def __receive_next_update(self) -> telegram.Update:
"""Get the next update from the queue. """Get the next update from the queue.
If no update is found, block the process until one is received. If no update is found, block the process until one is received.
If a stop signal is sent, try to gracefully stop the thread.""" If a stop signal is sent, try to gracefully stop the thread."""
@ -51,17 +67,69 @@ class ChatWorker(threading.Thread):
data = self.queue.get(timeout=int(configloader.config["Telegram"]["conversation_timeout"])) data = self.queue.get(timeout=int(configloader.config["Telegram"]["conversation_timeout"]))
except queuem.Empty: except queuem.Empty:
# If the conversation times out, gracefully stop the thread # If the conversation times out, gracefully stop the thread
self._graceful_stop() self.__graceful_stop()
# Check if the data is a stop signal instance # Check if the data is a stop signal instance
if isinstance(data, StopSignal): if isinstance(data, StopSignal):
# Gracefully stop the process # Gracefully stop the process
self._graceful_stop() self.__graceful_stop()
# Return the received update # Return the received update
return data return data
def _graceful_stop(self): def __wait_for_specific_message(self, items:typing.List[str]) -> str:
"""Continue getting updates until until one of the strings contained in the list is received as a message."""
while True:
# Get the next update
update = self.__receive_next_update()
# Ensure the update contains a message
if update.message is None:
continue
# Ensure the message contains text
if update.message.text is None:
continue
# Check if the message is contained in the list
if update.message.text not in items:
continue
# Return the message text
return update.message.text
def __user_menu(self):
"""Function called from the run method when the user is not an administrator.
Normal bot actions should be placed here."""
# Create a keyboard with the user main menu
keyboard = [[telegram.KeyboardButton(strings.menu_order)],
[telegram.KeyboardButton(strings.menu_order_status)],
[telegram.KeyboardButton(strings.menu_add_credit)],
[telegram.KeyboardButton(strings.menu_info)]]
# Send the previously created keyboard to the user (ensuring it can be clicked only 1 time)
self.bot.send_message(self.chat.id, strings.conversation_open_user_menu.format(username=str(self.user)),
reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True))
# Wait for a reply from the user
# TODO: change this
selection = self.__wait_for_specific_message([strings.menu_order, strings.menu_order_status,
strings.menu_add_credit, strings.menu_info])
# If the user has selected the Order option...
if selection == strings.menu_order:
...
# If the user has selected the Order Status option...
elif selection == strings.menu_order_status:
...
# If the user has selected the Add Credit option...
elif selection == strings.menu_add_credit:
...
# If the user has selected the Bot Info option...
elif selection == strings.menu_info:
...
def __admin_menu(self):
"""Function called from the run method when the user is an administrator.
Administrative bot actions should be placed here."""
self.bot.send_message(self.chat.id, "Sei un Amministralol")
def __graceful_stop(self):
"""Handle the graceful stop of the thread.""" """Handle the graceful stop of the thread."""
# Notify the user that the session has expired # Notify the user that the session has expired
self.bot.send_message(self.chat.id, strings.conversation_expired) self.bot.send_message(self.chat.id, strings.conversation_expired)
# Close the database session
# End the process # End the process
sys.exit(0) sys.exit(0)