105 lines
4.0 KiB
Python
105 lines
4.0 KiB
Python
# standard imports
|
|
import logging
|
|
from typing import Optional
|
|
|
|
# third party imports
|
|
from tinydb import Query
|
|
from tinydb.table import Document, Table
|
|
|
|
# define logger.
|
|
logg = logging.getLogger()
|
|
|
|
|
|
class UssdMenu:
|
|
"""
|
|
This class defines the USSD menu object that is called whenever a user makes transitions in the menu.
|
|
:cvar ussd_menu_db: The tinydb database object.
|
|
:type ussd_menu_db: Table
|
|
"""
|
|
ussd_menu_db = None
|
|
Menu = Query()
|
|
|
|
def __init__(self,
|
|
name: str,
|
|
description: str,
|
|
parent: Optional[str],
|
|
country: Optional[str] = 'Kenya',
|
|
gateway: Optional[str] = 'USSD'):
|
|
"""
|
|
This function is called whenever a USSD menu object is created and saves the instance to a JSON DB.
|
|
:param name: The name of the menu and is used as it's unique identifier.
|
|
:type name: str.
|
|
:param description: A brief explanation of what the menu does.
|
|
:type description: str.
|
|
:param parent: The menu from which the current menu is called. Transitions move from parent to child menus.
|
|
:type parent: str.
|
|
:param country: The country from which the menu is created for and being used. Defaults to Kenya.
|
|
:type country: str
|
|
:param gateway: The gateway through which the menu is used. Defaults to USSD.
|
|
:type gateway: str.
|
|
:raises ValueError: If menu already exists.
|
|
"""
|
|
self.name = name
|
|
self.description = description
|
|
self.parent = parent
|
|
self.display_key = f'{gateway.lower()}.{country.lower()}.{name}'
|
|
|
|
menu = self.ussd_menu_db.get(UssdMenu.Menu.name == name)
|
|
if menu:
|
|
raise ValueError('Menu already exists!')
|
|
self.ussd_menu_db.insert({
|
|
'name': self.name,
|
|
'description': self.description,
|
|
'parent': self.parent,
|
|
'display_key': self.display_key
|
|
})
|
|
|
|
@staticmethod
|
|
def find_by_name(name: str) -> Document:
|
|
"""
|
|
This function attempts to fetch a menu from the JSON DB using the unique name.
|
|
:param name: The name of the menu that is being searched for.
|
|
:type name: str.
|
|
:return: The function returns the queried menu in JSON format if found,
|
|
else it returns the menu item for invalid requests.
|
|
:rtype: Document.
|
|
"""
|
|
menu = UssdMenu.ussd_menu_db.get(UssdMenu.Menu.name == name)
|
|
if not menu:
|
|
logg.error("No USSD Menu with name {}".format(name))
|
|
return UssdMenu.ussd_menu_db.get(UssdMenu.Menu.name == 'exit_invalid_request')
|
|
else:
|
|
return menu
|
|
|
|
@staticmethod
|
|
def set_description(name: str, description: str):
|
|
"""
|
|
This function updates the description for a specific menu in the JSON DB.
|
|
:param name: The name of the menu whose description should be updated.
|
|
:type name: str.
|
|
:param description: The new menu description. On success it should overwrite the menu's previous description.
|
|
:type description: str.
|
|
"""
|
|
menu = UssdMenu.find_by_name(name=name)
|
|
UssdMenu.ussd_menu_db.update({'description': description}, UssdMenu.Menu.name == menu['name'])
|
|
|
|
@staticmethod
|
|
def parent_menu(menu_name: str) -> Document:
|
|
"""
|
|
This function fetches the parent menu of the menu instance it has been called on.
|
|
:param menu_name: The name of the menu whose parent is to be returned.
|
|
:type menu_name: str
|
|
:return: This function returns the menu's parent menu in JSON format.
|
|
:rtype: Document.
|
|
"""
|
|
ussd_menu = UssdMenu.find_by_name(name=menu_name)
|
|
return UssdMenu.find_by_name(ussd_menu.get('parent'))
|
|
|
|
def __repr__(self) -> str:
|
|
"""
|
|
This method return the object representation of the menu.
|
|
:return: This function returns a string containing the object representation of the menu.
|
|
:rtype: str.
|
|
"""
|
|
return f"<UssdMenu {self.name} - {self.description}>"
|