Skip to content

Commit

Permalink
Start working on the code for the bot
Browse files Browse the repository at this point in the history
  • Loading branch information
Steffo99 committed Dec 21, 2017
1 parent d4febea commit 5f04a1f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 15 deletions.
2 changes: 1 addition & 1 deletion core.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def main():
# Skip the update
continue
# 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
old_worker = chat_workers.get(update.message.chat.id)
# If it exists, gracefully stop the worker
Expand Down
10 changes: 5 additions & 5 deletions database.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ class User(TableDeclarativeBase):
# Extra table parameters
__tablename__ = "users"

def __init__(self, telegram_user: telegram.User, **kwargs):
def __init__(self, telegram_chat: telegram.Chat, **kwargs):
# Initialize the super
super().__init__(**kwargs)
# Get the data from telegram
self.id = telegram_user.id
self.first_name = telegram_user.first_name
self.last_name = telegram_user.last_name
self.username = telegram_user.username
self.user_id = telegram_chat.id
self.first_name = telegram_chat.first_name
self.last_name = telegram_chat.last_name
self.username = telegram_chat.username
# The starting wallet value is 0
self.credit = decimal.Decimal("0")

Expand Down
16 changes: 16 additions & 0 deletions strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,26 @@
conversation_after_start = "Ciao!\n" \
"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
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."

# 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_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private."

Expand Down
86 changes: 77 additions & 9 deletions worker.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import threading
import typing
import telegram
import strings
import configloader
import sys
import queue as queuem
import database as db

class StopSignal:
"""A data class that should be sent to the worker when the conversation has to be stopped abnormally."""
Expand All @@ -21,6 +23,11 @@ def __init__(self, bot: telegram.Bot, chat: telegram.Chat, *args, **kwargs):
# Store the bot and chat info inside the class
self.bot = bot
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
self.queue = queuem.Queue()

Expand All @@ -29,11 +36,20 @@ def run(self):
# TODO: catch all the possible exceptions
# Welcome the user to the bot
self.bot.send_message(self.chat.id, strings.conversation_after_start)
# TODO: Send a command list or something
while True:
# For now, echo the sent message
update = self._receive_next_update()
self.bot.send_message(self.chat.id, f"{threading.current_thread().name} {update.message.text}")
# If the user isn't registered, create a new record and add it to the db
if self.user is None:
# Create the new record
self.user = db.User(self.chat)
# 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=""):
"""Gracefully stop the worker process"""
Expand All @@ -42,7 +58,7 @@ def stop(self, reason: str=""):
# Wait for the thread to stop
self.join()

def _receive_next_update(self) -> telegram.Update:
def __receive_next_update(self) -> telegram.Update:
"""Get the next update from the queue.
If no update is found, block the process until one is received.
If a stop signal is sent, try to gracefully stop the thread."""
Expand All @@ -51,17 +67,69 @@ def _receive_next_update(self) -> telegram.Update:
data = self.queue.get(timeout=int(configloader.config["Telegram"]["conversation_timeout"]))
except queuem.Empty:
# If the conversation times out, gracefully stop the thread
self._graceful_stop()
self.__graceful_stop()
# Check if the data is a stop signal instance
if isinstance(data, StopSignal):
# Gracefully stop the process
self._graceful_stop()
self.__graceful_stop()
# Return the received update
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."""
# Notify the user that the session has expired
self.bot.send_message(self.chat.id, strings.conversation_expired)
# Close the database session
# End the process
sys.exit(0)

0 comments on commit 5f04a1f

Please sign in to comment.