From b7bdae4678402e35aecc1c0c465f0fb7d28564b3 Mon Sep 17 00:00:00 2001
From: Stefano Pigozzi <ste.pigozzi@gmail.com>
Date: Mon, 29 Jan 2018 13:26:49 +0100
Subject: [PATCH] Started work on the admin menu

---
 strings.py | 42 +++++++++++++++++++++++--
 worker.py  | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 127 insertions(+), 5 deletions(-)

diff --git a/strings.py b/strings.py
index aca8261..b6e8100 100644
--- a/strings.py
+++ b/strings.py
@@ -16,14 +16,21 @@ conversation_after_start = "Ciao!\n" \
                            "Benvenuto su greed!"
 
 # Conversation: to send an inline keyboard you need to send a message with it
-conversation_open_user_menu = "Allora, {username}, cosa vorresti fare?"
+conversation_open_user_menu = "Cosa vorresti fare?"
 
 # Conversation: the same message as above but when the first has already been sent
 conversation_open_user_menu_multiple = "Hai bisogno di qualcos'altro?"
 
+# Conversation: like above, but for administrators
+conversation_open_admin_menu = "Sei un amministratore di greed!\n" \
+                               "Cosa vorresti fare?"
+
 # Conversation: select a payment method
 conversation_payment_method = "Come vuoi aggiungere fondi al tuo portafoglio?"
 
+# Conversation: select a product to edit
+conversation_admin_select_product = "Che prodotto vuoi modificare?"
+
 # 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."
@@ -46,9 +53,30 @@ menu_cash = "💵 In contanti"
 # User menu: credit card
 menu_credit_card = "💳 Con una carta di credito"
 
-# User menu: cancel
+# Admin menu: products
+menu_products = "📝️ Prodotti"
+
+# Admin menu: orders
+menu_orders = "📦 Ordini"
+
+# Admin menu: go to user mode
+menu_user_mode = "👤 Passa alla modalità utente"
+
+# Admin menu: add product
+menu_add_product = "✨ Nuovo prodotto"
+
+# Menu: cancel
 menu_cancel = "🔙 Annulla"
 
+# Add product: name?
+ask_product_name = "Come si deve chiamare il prodotto?"
+
+# Add product: description?
+ask_product_description = "Quale deve essere la descrizione del prodotto?"
+
+# Add product: price?
+ask_product_price = "Quanto deve costare il prodotto?"
+
 # Payment: cash payment info
 payment_cash = "Puoi pagare in contanti alla sede fisica del negozio.\n" \
                "Il gestore provvederà ad aggiungere credito al tuo account appena gli avrai consegnato i soldi."
@@ -74,6 +102,9 @@ bot_info = 'Questo bot utilizza <a href="https://github.com/Steffo99/greed">gree
            ' <a href="https://github.com/Steffo99/greed/blob/master/LICENSE">Affero General Public License 3.0</a>.\n' \
            'Il codice sorgente di questa versione è disponibile <i>qui</i>.\n'
 
+# Success: product has been added to the database
+success_product_added = "✅ Il prodotto è stato aggiunto con successo!"
+
 # Error: message received not in a private chat
 error_nonprivate_chat = "⚠️ Questo bot funziona solo in chat private."
 
@@ -88,4 +119,9 @@ error_payment_amount_over_max = "⚠️ Il massimo di fondi che possono essere a
 error_payment_amount_under_min = "⚠️ Il minimo di fondi che possono essere aggiunti in una singola transazione è {min_amount}."
 
 # Error: the invoice has expired and can't be paid
-error_invoice_expired = "⚠️ Questo pagamento è scaduto ed è stato annullato. Se vuoi ancora aggiungere fondi, usa l'opzione Aggiungi fondi del menu."
\ No newline at end of file
+error_invoice_expired = "⚠️ Questo pagamento è scaduto ed è stato annullato. Se vuoi ancora aggiungere fondi, usa l'opzione Aggiungi fondi del menu."
+
+# Error: a product with that name already exists
+error_duplicate_name = "️⚠ Esiste già un prodotto con questo nome."
+
+
diff --git a/worker.py b/worker.py
index 804954b..a565742 100644
--- a/worker.py
+++ b/worker.py
@@ -155,7 +155,7 @@ class ChatWorker(threading.Thread):
                         [telegram.KeyboardButton(strings.menu_add_credit)],
                         [telegram.KeyboardButton(strings.menu_bot_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)),
+            self.bot.send_message(self.chat.id, strings.conversation_open_user_menu,
                                   reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True))
             # Wait for a reply from the user
             selection = self.__wait_for_specific_message([strings.menu_order, strings.menu_order_status,
@@ -219,7 +219,7 @@ class ChatWorker(threading.Thread):
         self.bot.send_message(self.chat.id, strings.payment_cash)
 
     def __add_credit_cc(self):
-        """Ask the user how much money he wants to add to his wallet."""
+        """Add money to the wallet through a credit card payment."""
         # Create a keyboard to be sent later
         keyboard = [[telegram.KeyboardButton(strings.currency_format_string.format(symbol=strings.currency_symbol, value="10"))],
                     [telegram.KeyboardButton(strings.currency_format_string.format(symbol=strings.currency_symbol, value="25"))],
@@ -296,6 +296,92 @@ class ChatWorker(threading.Thread):
     def __admin_menu(self):
         """Function called from the run method when the user is an administrator.
         Administrative bot actions should be placed here."""
+        # Loop used to return to the menu after executing a command
+        while True:
+            # Create a keyboard with the admin main menu
+            keyboard = [[telegram.KeyboardButton(strings.menu_products)],
+                        [telegram.KeyboardButton(strings.menu_orders)],
+                        [telegram.KeyboardButton(strings.menu_user_mode)]]
+            # 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_admin_menu,
+                                  reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True))
+            # Wait for a reply from the user
+            selection = self.__wait_for_specific_message([strings.menu_products, strings.menu_orders,
+                                                          strings.menu_user_mode])
+            # If the user has selected the Products option...
+            if selection == strings.menu_products:
+                # Open the products menu
+                self.__products_menu()
+            # If the user has selected the Orders option...
+            elif selection == strings.menu_orders:
+                # Open the orders menu
+                self.__orders_menu()
+            # If the user has selected the User mode option...
+            elif selection == strings.menu_user_mode:
+                # Start the bot in user mode
+                self.__user_menu()
+
+    def __products_menu(self):
+        """Display the admin menu to select a product to edit."""
+        # Get the products list from the db
+        products = self.session.query(db.Product).all()
+        # Create a list of product names
+        product_names = [product.name for product in products]
+        # Insert at the start of the list the add product option
+        product_names.insert(0, strings.menu_add_product)
+        # Create a keyboard using the product names
+        keyboard = [[telegram.KeyboardButton(product_name)] for product_name in product_names]
+        # 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_admin_select_product,
+                              reply_markup=telegram.ReplyKeyboardMarkup(keyboard, one_time_keyboard=True))
+        # Wait for a reply from the user
+        selection = self.__wait_for_specific_message(product_names)
+        # If the user has selected the Add Product option...
+        if selection == strings.menu_add_product:
+            # Open the add product menu
+            self.__add_product_menu()
+        # If the user has selected a product
+        else:
+            # Open the edit menu for that specific product
+            self.__edit_product_menu(selection)
+
+    def __add_product_menu(self):
+        """Add a product to the database."""
+        # Ask for the product name until a valid product name is specified
+        while True:
+            # Ask the question to the user
+            self.bot.send_message(self.chat.id, strings.ask_product_name)
+            # Wait for an answer
+            name = self.__wait_for_regex(r"(.*)")
+            # Ensure a product with that name doesn't already exist
+            if self.session.query(db.Product).filter_by(name=name).one_or_none() is None:
+                # Exit the loop
+                break
+            self.bot.send_message(self.chat.id, strings.error_duplicate_name)
+        # Ask for the product description
+        self.bot.send_message(self.chat.id, strings.ask_product_description)
+        # Wait for an answer
+        description = self.__wait_for_regex(r"(.*)")
+        # Ask for the product price
+        self.bot.send_message(self.chat.id, strings.ask_product_price)
+        # Wait for an answer
+        price = int(self.__wait_for_regex(r"([0-9]{1,3}(?:[.,][0-9]{1,2})?)").replace(".", "").replace(",", "")) * (
+                    10 ** int(configloader.config["Payments"]["currency_exp"]))
+        # TODO: ask for product image
+        # Create the db record for the product
+        product = db.Product(name=name,
+                             description=description,
+                             price=price)
+        # Add the record to the session, then commit
+        self.session.add(product)
+        self.session.commit()
+        # Notify the user
+        self.bot.send_message(self.chat.id, strings.success_product_added)
+
+    def __edit_product_menu(self, name: str):
+        raise NotImplementedError()
+
+    def __orders_menu(self):
         raise NotImplementedError()
 
     def __graceful_stop(self):