# standard imports import logging from typing import Optional import json # third party imports from redis import Redis logg = logging.getLogger() class UssdSession: """ This class defines the USSD session object that is called whenever a user interacts with the system. :cvar redis_cache: The in-memory redis cache. :type redis_cache: Redis """ redis_cache: Redis = None def __init__(self, external_session_id: str, service_code: str, msisdn: str, user_input: str, state: str, session_data: Optional[dict] = None): """ This function is called whenever a USSD session object is created and saves the instance to a JSON DB. :param external_session_id: The Africa's Talking session ID. :type external_session_id: str. :param service_code: The USSD service code from which the user used to gain access to the system. :type service_code: str. :param msisdn: The user's phone number. :type msisdn: str. :param user_input: The data or choice the user has made while interacting with the system. :type user_input: str. :param state: The name of the USSD menu that the user was interacting with. :type state: str. :param session_data: Any additional data that was persisted during the user's interaction with the system. :type session_data: dict. """ self.external_session_id = external_session_id self.service_code = service_code self.msisdn = msisdn self.user_input = user_input self.state = state self.session_data = session_data session = self.redis_cache.get(external_session_id) if session: session = json.loads(session) self.version = session.get('version') + 1 else: self.version = 1 self.session = { 'external_session_id': self.external_session_id, 'service_code': self.service_code, 'msisdn': self.msisdn, 'user_input': self.user_input, 'state': self.state, 'session_data': self.session_data, 'version': self.version } self.redis_cache.set(self.external_session_id, json.dumps(self.session)) self.redis_cache.persist(self.external_session_id) def set_data(self, key: str, value: str) -> None: """ This function adds or updates data to the session data. :param key: The name used to identify the data. :type key: str. :param value: The actual data to be stored in the session data. :type value: str. """ if self.session_data is None: self.session_data = {} self.session_data[key] = value self.redis_cache.set(self.external_session_id, json.dumps(self.session)) def get_data(self, key: str) -> Optional[str]: """ This function attempts to fetch data from the session data using the identifier for the specific data. :param key: The name used as the identifier for the specific data. :type key: str. :return: This function returns the queried data if found, else it doesn't return any value. :rtype: str. """ if self.session_data is not None: return self.session_data.get(key) else: return None def to_json(self): """ This function serializes the in memory ussd session object to a JSON object :return: A JSON object of a ussd session in memory :rtype: dict """ return { "external_session_id": self.external_session_id, "service_code": self.service_code, "msisdn": self.msisdn, "user_input": self.user_input, "state": self.state, "session_data": self.session_data, "version": self.version }