The great bump
This commit is contained in:
248
apps/cic-ussd/cic_ussd/state_machine/logic/account.py
Normal file
248
apps/cic-ussd/cic_ussd/state_machine/logic/account.py
Normal file
@@ -0,0 +1,248 @@
|
||||
# standard imports
|
||||
import json
|
||||
import logging
|
||||
from typing import Tuple
|
||||
|
||||
# third-party imports
|
||||
import celery
|
||||
import i18n
|
||||
from chainlib.hash import strip_0x
|
||||
from cic_types.models.person import get_contact_data_from_vcard, generate_vcard_from_contact_data, manage_identity_data
|
||||
|
||||
# local imports
|
||||
from cic_ussd.account.chain import Chain
|
||||
from cic_ussd.account.maps import gender, language
|
||||
from cic_ussd.account.metadata import get_cached_preferred_language
|
||||
from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.error import MetadataNotFoundError
|
||||
from cic_ussd.metadata import PersonMetadata
|
||||
from cic_ussd.session.ussd_session import save_session_data
|
||||
from cic_ussd.translation import translation_for
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
logg = logging.getLogger(__file__)
|
||||
|
||||
|
||||
def change_preferred_language(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""
|
||||
:param state_machine_data:
|
||||
:type state_machine_data:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
r_user_input = language().get(user_input)
|
||||
session = SessionBase.bind_session(session)
|
||||
account.preferred_language = r_user_input
|
||||
session.add(account)
|
||||
session.flush()
|
||||
SessionBase.release_session(session)
|
||||
|
||||
preferences_data = {
|
||||
'preferred_language': r_user_input
|
||||
}
|
||||
|
||||
s = celery.signature(
|
||||
'cic_ussd.tasks.metadata.add_preferences_metadata',
|
||||
[account.blockchain_address, preferences_data],
|
||||
queue='cic-ussd'
|
||||
)
|
||||
return s.apply_async()
|
||||
|
||||
|
||||
def update_account_status_to_active(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function sets user's account to active.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
account.activate_account()
|
||||
session.add(account)
|
||||
session.flush()
|
||||
SessionBase.release_session(session=session)
|
||||
|
||||
|
||||
def parse_gender(account: Account, user_input: str):
|
||||
"""
|
||||
:param account:
|
||||
:type account:
|
||||
:param user_input:
|
||||
:type user_input:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
preferred_language = get_cached_preferred_language(account.blockchain_address)
|
||||
if not preferred_language:
|
||||
preferred_language = i18n.config.get('fallback')
|
||||
r_user_input = gender().get(user_input)
|
||||
return translation_for(f'helpers.{r_user_input}', preferred_language)
|
||||
|
||||
|
||||
def save_metadata_attribute_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function saves first name data to the ussd session in the redis cache.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
current_state = ussd_session.get('state')
|
||||
|
||||
key = ''
|
||||
if 'given_name' in current_state:
|
||||
key = 'given_name'
|
||||
|
||||
if 'date_of_birth' in current_state:
|
||||
key = 'date_of_birth'
|
||||
|
||||
if 'family_name' in current_state:
|
||||
key = 'family_name'
|
||||
|
||||
if 'gender' in current_state:
|
||||
key = 'gender'
|
||||
user_input = parse_gender(account, user_input)
|
||||
|
||||
if 'location' in current_state:
|
||||
key = 'location'
|
||||
|
||||
if 'products' in current_state:
|
||||
key = 'products'
|
||||
|
||||
if ussd_session.get('data'):
|
||||
data = ussd_session.get('data')
|
||||
data[key] = user_input
|
||||
else:
|
||||
data = {
|
||||
key: user_input
|
||||
}
|
||||
save_session_data('cic-ussd', session, data, ussd_session)
|
||||
SessionBase.release_session(session)
|
||||
|
||||
|
||||
def parse_person_metadata(account: Account, metadata: dict):
|
||||
"""
|
||||
:param account:
|
||||
:type account:
|
||||
:param metadata:
|
||||
:type metadata:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
set_gender = metadata.get('gender')
|
||||
given_name = metadata.get('given_name')
|
||||
family_name = metadata.get('family_name')
|
||||
email = metadata.get('email')
|
||||
|
||||
if isinstance(metadata.get('date_of_birth'), dict):
|
||||
date_of_birth = metadata.get('date_of_birth')
|
||||
else:
|
||||
date_of_birth = {
|
||||
"year": int(metadata.get('date_of_birth')[:4])
|
||||
}
|
||||
if isinstance(metadata.get('location'), dict):
|
||||
location = metadata.get('location')
|
||||
else:
|
||||
location = {
|
||||
"area_name": metadata.get('location')
|
||||
}
|
||||
if isinstance(metadata.get('products'), list):
|
||||
products = metadata.get('products')
|
||||
else:
|
||||
products = metadata.get('products').split(',')
|
||||
|
||||
phone_number = account.phone_number
|
||||
date_registered = int(account.created.replace().timestamp())
|
||||
blockchain_address = account.blockchain_address
|
||||
chain_spec = f'{Chain.spec.common_name()}:{Chain.spec.engine()}: {Chain.spec.chain_id()}'
|
||||
|
||||
if isinstance(metadata.get('identities'), dict):
|
||||
identities = metadata.get('identities')
|
||||
else:
|
||||
identities = manage_identity_data(
|
||||
blockchain_address=blockchain_address,
|
||||
blockchain_type=Chain.spec.engine(),
|
||||
chain_spec=chain_spec
|
||||
)
|
||||
|
||||
return {
|
||||
"date_registered": date_registered,
|
||||
"date_of_birth": date_of_birth,
|
||||
"gender": set_gender,
|
||||
"identities": identities,
|
||||
"location": location,
|
||||
"products": products,
|
||||
"vcard": generate_vcard_from_contact_data(
|
||||
email=email,
|
||||
family_name=family_name,
|
||||
given_name=given_name,
|
||||
tel=phone_number
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def save_complete_person_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function persists elements of the user metadata stored in session data
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
metadata = ussd_session.get('data')
|
||||
person_metadata = parse_person_metadata(account, metadata)
|
||||
blockchain_address = account.blockchain_address
|
||||
s_create_person_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.create_person_metadata', [blockchain_address, person_metadata], queue='cic-ussd')
|
||||
s_create_person_metadata.apply_async()
|
||||
|
||||
|
||||
def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""
|
||||
:param state_machine_data:
|
||||
:type state_machine_data:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
blockchain_address = account.blockchain_address
|
||||
identifier = bytes.fromhex(strip_0x(blockchain_address))
|
||||
person_metadata = PersonMetadata(identifier)
|
||||
cached_person_metadata = person_metadata.get_cached_metadata()
|
||||
|
||||
if not cached_person_metadata:
|
||||
raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}')
|
||||
|
||||
person_metadata = json.loads(cached_person_metadata)
|
||||
data = ussd_session.get('data')
|
||||
contact_data = {}
|
||||
vcard = person_metadata.get('vcard')
|
||||
if vcard:
|
||||
contact_data = get_contact_data_from_vcard(vcard)
|
||||
person_metadata.pop('vcard')
|
||||
given_name = data.get('given_name') or contact_data.get('given')
|
||||
family_name = data.get('family_name') or contact_data.get('family')
|
||||
date_of_birth = data.get('date_of_birth') or person_metadata.get('date_of_birth')
|
||||
set_gender = data.get('gender') or person_metadata.get('gender')
|
||||
location = data.get('location') or person_metadata.get('location')
|
||||
products = data.get('products') or person_metadata.get('products')
|
||||
if isinstance(date_of_birth, str):
|
||||
year = int(date_of_birth)
|
||||
person_metadata['date_of_birth'] = {'year': year}
|
||||
person_metadata['gender'] = set_gender
|
||||
person_metadata['given_name'] = given_name
|
||||
person_metadata['family_name'] = family_name
|
||||
if isinstance(location, str):
|
||||
location_data = person_metadata.get('location')
|
||||
location_data['area_name'] = location
|
||||
person_metadata['location'] = location_data
|
||||
person_metadata['products'] = products
|
||||
if contact_data:
|
||||
contact_data.pop('given')
|
||||
contact_data.pop('family')
|
||||
contact_data.pop('tel')
|
||||
person_metadata = {**person_metadata, **contact_data}
|
||||
parsed_person_metadata = parse_person_metadata(account, person_metadata)
|
||||
s_edit_person_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.create_person_metadata',
|
||||
[blockchain_address, parsed_person_metadata]
|
||||
)
|
||||
s_edit_person_metadata.apply_async(queue='cic-ussd')
|
||||
@@ -1,21 +0,0 @@
|
||||
# standard imports
|
||||
import logging
|
||||
from typing import Tuple
|
||||
|
||||
# third-party imports
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
# local imports
|
||||
from cic_ussd.db.models.account import Account
|
||||
|
||||
logg = logging.getLogger(__file__)
|
||||
|
||||
|
||||
def process_mini_statement_request(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function compiles a brief statement of a user's last three inbound and outbound transactions and send the
|
||||
same as a message on their selected avenue for notification.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
logg.debug('This section requires integration with cic-eth. (The last 6 transactions would be sent as an sms.)')
|
||||
@@ -5,44 +5,47 @@ ussd menu facilitating the return of appropriate menu responses based on said us
|
||||
# standard imports
|
||||
from typing import Tuple
|
||||
|
||||
# external imports
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
# local imports
|
||||
from cic_ussd.db.models.account import Account
|
||||
|
||||
|
||||
def menu_one_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_one_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""This function checks that user input matches a string with value '1'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
:return: A user input's match with '1'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '1'
|
||||
|
||||
|
||||
def menu_two_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_two_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""This function checks that user input matches a string with value '2'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
:return: A user input's match with '2'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '2'
|
||||
|
||||
|
||||
def menu_three_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_three_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""This function checks that user input matches a string with value '3'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
:return: A user input's match with '3'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '3'
|
||||
|
||||
|
||||
def menu_four_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_four_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""
|
||||
This function checks that user input matches a string with value '4'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
@@ -50,11 +53,11 @@ def menu_four_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
:return: A user input's match with '4'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '4'
|
||||
|
||||
|
||||
def menu_five_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_five_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""
|
||||
This function checks that user input matches a string with value '5'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
@@ -62,11 +65,11 @@ def menu_five_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
:return: A user input's match with '5'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '5'
|
||||
|
||||
|
||||
def menu_six_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_six_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""
|
||||
This function checks that user input matches a string with value '6'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
@@ -74,11 +77,11 @@ def menu_six_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
:return: A user input's match with '6'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '6'
|
||||
|
||||
|
||||
def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""
|
||||
This function checks that user input matches a string with value '00'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
@@ -86,11 +89,11 @@ def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account]) -> bo
|
||||
:return: A user input's match with '00'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '00'
|
||||
|
||||
|
||||
def menu_ninety_nine_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
|
||||
def menu_ninety_nine_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
"""
|
||||
This function checks that user input matches a string with value '99'
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
@@ -98,5 +101,5 @@ def menu_ninety_nine_selected(state_machine_data: Tuple[str, dict, Account]) ->
|
||||
:return: A user input's match with '99'
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return user_input == '99'
|
||||
|
||||
@@ -16,8 +16,7 @@ from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.db.enum import AccountStatus
|
||||
from cic_ussd.encoder import create_password_hash, check_password_hash
|
||||
from cic_ussd.operations import persist_session_to_db_task, create_or_update_session
|
||||
from cic_ussd.redis import InMemoryStore
|
||||
from cic_ussd.session.ussd_session import create_or_update_session, persist_ussd_session
|
||||
|
||||
|
||||
logg = logging.getLogger(__file__)
|
||||
@@ -31,7 +30,7 @@ def is_valid_pin(state_machine_data: Tuple[str, dict, Account, Session]) -> bool
|
||||
:return: A pin's validity
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
pin_is_valid = False
|
||||
matcher = r'^\d{4}$'
|
||||
if re.match(matcher, user_input):
|
||||
@@ -46,8 +45,11 @@ def is_authorized_pin(state_machine_data: Tuple[str, dict, Account, Session]) ->
|
||||
:return: A match between two pin values.
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
return user.verify_password(password=user_input)
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
is_verified_password = account.verify_password(password=user_input)
|
||||
if not is_verified_password:
|
||||
account.failed_pin_attempts += 1
|
||||
return is_verified_password
|
||||
|
||||
|
||||
def is_locked_account(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
@@ -57,8 +59,8 @@ def is_locked_account(state_machine_data: Tuple[str, dict, Account, Session]) ->
|
||||
:return: A match between two pin values.
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
return user.get_account_status() == AccountStatus.LOCKED.name
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return account.get_status(session) == AccountStatus.LOCKED.name
|
||||
|
||||
|
||||
def save_initial_pin_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
@@ -67,38 +69,25 @@ def save_initial_pin_to_session_data(state_machine_data: Tuple[str, dict, Accoun
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
|
||||
# define redis cache entry point
|
||||
cache = InMemoryStore.cache
|
||||
|
||||
# get external session id
|
||||
external_session_id = ussd_session.get('external_session_id')
|
||||
|
||||
# get corresponding session record
|
||||
in_redis_ussd_session = cache.get(external_session_id)
|
||||
in_redis_ussd_session = json.loads(in_redis_ussd_session)
|
||||
|
||||
# set initial pin data
|
||||
initial_pin = create_password_hash(user_input)
|
||||
if ussd_session.get('session_data'):
|
||||
session_data = ussd_session.get('session_data')
|
||||
session_data['initial_pin'] = initial_pin
|
||||
if ussd_session.get('data'):
|
||||
data = ussd_session.get('data')
|
||||
data['initial_pin'] = initial_pin
|
||||
else:
|
||||
session_data = {
|
||||
data = {
|
||||
'initial_pin': initial_pin
|
||||
}
|
||||
|
||||
# create new in memory ussd session with current ussd session data
|
||||
external_session_id = ussd_session.get('external_session_id')
|
||||
create_or_update_session(
|
||||
external_session_id=external_session_id,
|
||||
phone=in_redis_ussd_session.get('msisdn'),
|
||||
service_code=in_redis_ussd_session.get('service_code'),
|
||||
msisdn=ussd_session.get('msisdn'),
|
||||
service_code=ussd_session.get('service_code'),
|
||||
user_input=user_input,
|
||||
current_menu=in_redis_ussd_session.get('state'),
|
||||
state=ussd_session.get('state'),
|
||||
session=session,
|
||||
session_data=session_data
|
||||
data=data
|
||||
)
|
||||
persist_session_to_db_task(external_session_id=external_session_id, queue='cic-ussd')
|
||||
persist_ussd_session(external_session_id, 'cic-ussd')
|
||||
|
||||
|
||||
def pins_match(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
@@ -109,7 +98,7 @@ def pins_match(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
initial_pin = ussd_session.get('session_data').get('initial_pin')
|
||||
initial_pin = ussd_session.get('data').get('initial_pin')
|
||||
return check_password_hash(user_input, initial_pin)
|
||||
|
||||
|
||||
@@ -120,7 +109,7 @@ def complete_pin_change(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
password_hash = ussd_session.get('session_data').get('initial_pin')
|
||||
password_hash = ussd_session.get('data').get('initial_pin')
|
||||
user.password_hash = password_hash
|
||||
session.add(user)
|
||||
session.flush()
|
||||
@@ -134,8 +123,8 @@ def is_blocked_pin(state_machine_data: Tuple[str, dict, Account, Session]) -> bo
|
||||
:return: A match between two pin values.
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
return user.get_account_status() == AccountStatus.LOCKED.name
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return account.get_status(session) == AccountStatus.LOCKED.name
|
||||
|
||||
|
||||
def is_valid_new_pin(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
# standard imports
|
||||
import logging
|
||||
from typing import Tuple
|
||||
|
||||
# external imports
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
# local imports
|
||||
from cic_ussd.account.metadata import get_cached_preferred_language
|
||||
from cic_ussd.account.tokens import get_default_token_symbol
|
||||
from cic_ussd.db.models.account import Account
|
||||
|
||||
logg = logging.getLogger()
|
||||
from cic_ussd.notifications import Notifier
|
||||
from cic_ussd.phone_number import Support
|
||||
|
||||
|
||||
def send_terms_to_user_if_required(state_machine_data: Tuple[str, dict, Account]):
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
logg.debug('Requires integration to cic-notify.')
|
||||
|
||||
|
||||
def process_mini_statement_request(state_machine_data: Tuple[str, dict, Account]):
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
logg.debug('Requires integration to cic-notify.')
|
||||
|
||||
|
||||
def upsell_unregistered_recipient(state_machine_data: Tuple[str, dict, Account]):
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
logg.debug('Requires integration to cic-notify.')
|
||||
def upsell_unregistered_recipient(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
""""""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
notifier = Notifier()
|
||||
phone_number = ussd_session.get('data')['recipient_phone_number']
|
||||
preferred_language = get_cached_preferred_language(account.blockchain_address)
|
||||
token_symbol = get_default_token_symbol()
|
||||
tx_sender_information = account.standard_metadata_id()
|
||||
notifier.send_sms_notification('sms.upsell_unregistered_recipient',
|
||||
phone_number,
|
||||
preferred_language,
|
||||
tx_sender_information=tx_sender_information,
|
||||
token_symbol=token_symbol,
|
||||
support_phone=Support.phone_number)
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
# standard imports
|
||||
import json
|
||||
import logging
|
||||
from typing import Tuple
|
||||
|
||||
# third party imports
|
||||
import celery
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
# local imports
|
||||
from cic_ussd.balance import compute_operational_balance
|
||||
from cic_ussd.chain import Chain
|
||||
from cic_ussd.account.balance import get_cached_available_balance
|
||||
from cic_ussd.account.chain import Chain
|
||||
from cic_ussd.account.tokens import get_default_token_symbol
|
||||
from cic_ussd.account.transaction import OutgoingTransaction
|
||||
from cic_ussd.db.enum import AccountStatus
|
||||
from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.db.enum import AccountStatus
|
||||
from cic_ussd.operations import save_to_in_memory_ussd_session_data
|
||||
from cic_ussd.phone_number import process_phone_number, E164Format
|
||||
from cic_ussd.processor import retrieve_token_symbol
|
||||
from cic_ussd.redis import create_cached_data_key, get_cached_data
|
||||
from cic_ussd.transactions import OutgoingTransactionProcessor
|
||||
|
||||
from cic_ussd.session.ussd_session import save_session_data
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
logg = logging.getLogger(__file__)
|
||||
|
||||
@@ -31,13 +28,15 @@ def is_valid_recipient(state_machine_data: Tuple[str, dict, Account, Session]) -
|
||||
:return: A user's validity
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
phone_number = process_phone_number(user_input, E164Format.region)
|
||||
session = SessionBase.bind_session(session=session)
|
||||
recipient = Account.get_by_phone_number(phone_number=phone_number, session=session)
|
||||
SessionBase.release_session(session=session)
|
||||
is_not_initiator = phone_number != user.phone_number
|
||||
has_active_account_status = user.get_account_status() == AccountStatus.ACTIVE.name
|
||||
is_not_initiator = phone_number != account.phone_number
|
||||
has_active_account_status = False
|
||||
if recipient:
|
||||
has_active_account_status = recipient.get_status(session) == AccountStatus.ACTIVE.name
|
||||
return is_not_initiator and has_active_account_status and recipient is not None
|
||||
|
||||
|
||||
@@ -49,7 +48,7 @@ def is_valid_transaction_amount(state_machine_data: Tuple[str, dict, Account, Se
|
||||
:return: A transaction amount's validity
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
try:
|
||||
return int(user_input) > 0
|
||||
except ValueError:
|
||||
@@ -64,16 +63,8 @@ def has_sufficient_balance(state_machine_data: Tuple[str, dict, Account, Session
|
||||
:return: An account balance's validity
|
||||
:rtype: bool
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
# get cached balance
|
||||
key = create_cached_data_key(
|
||||
identifier=bytes.fromhex(user.blockchain_address[2:]),
|
||||
salt=':cic.balances_data'
|
||||
)
|
||||
cached_balance = get_cached_data(key=key)
|
||||
operational_balance = compute_operational_balance(balances=json.loads(cached_balance))
|
||||
|
||||
return int(user_input) <= operational_balance
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
return int(user_input) <= get_cached_available_balance(account.blockchain_address)
|
||||
|
||||
|
||||
def save_recipient_phone_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
@@ -81,17 +72,13 @@ def save_recipient_phone_to_session_data(state_machine_data: Tuple[str, dict, Ac
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
|
||||
session_data = ussd_session.get('session_data') or {}
|
||||
session_data = ussd_session.get('data') or {}
|
||||
recipient_phone_number = process_phone_number(phone_number=user_input, region=E164Format.region)
|
||||
session_data['recipient_phone_number'] = recipient_phone_number
|
||||
|
||||
save_to_in_memory_ussd_session_data(
|
||||
queue='cic-ussd',
|
||||
session=session,
|
||||
session_data=session_data,
|
||||
ussd_session=ussd_session)
|
||||
save_session_data('cic-ussd', session, session_data, ussd_session)
|
||||
|
||||
|
||||
def retrieve_recipient_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
@@ -101,18 +88,13 @@ def retrieve_recipient_metadata(state_machine_data: Tuple[str, dict, Account, Se
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
|
||||
recipient_phone_number = process_phone_number(phone_number=user_input, region=E164Format.region)
|
||||
recipient = Account.get_by_phone_number(phone_number=recipient_phone_number, session=session)
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
recipient_phone_number = process_phone_number(user_input, E164Format.region)
|
||||
recipient = Account.get_by_phone_number(recipient_phone_number, session)
|
||||
blockchain_address = recipient.blockchain_address
|
||||
|
||||
# retrieve and cache account's metadata
|
||||
s_query_person_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.query_person_metadata',
|
||||
[blockchain_address]
|
||||
)
|
||||
s_query_person_metadata.apply_async(queue='cic-ussd')
|
||||
'cic_ussd.tasks.metadata.query_person_metadata', [blockchain_address], queue='cic-ussd')
|
||||
s_query_person_metadata.apply_async()
|
||||
|
||||
|
||||
def save_transaction_amount_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
@@ -120,16 +102,11 @@ def save_transaction_amount_to_session_data(state_machine_data: Tuple[str, dict,
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
|
||||
session_data = ussd_session.get('session_data') or {}
|
||||
session_data = ussd_session.get('data') or {}
|
||||
session_data['transaction_amount'] = user_input
|
||||
|
||||
save_to_in_memory_ussd_session_data(
|
||||
queue='cic-ussd',
|
||||
session=session,
|
||||
session_data=session_data,
|
||||
ussd_session=ussd_session)
|
||||
save_session_data('cic-ussd', session, session_data, ussd_session)
|
||||
|
||||
|
||||
def process_transaction_request(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
@@ -137,20 +114,18 @@ def process_transaction_request(state_machine_data: Tuple[str, dict, Account, Se
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
|
||||
# retrieve token symbol
|
||||
chain_str = Chain.spec.__str__()
|
||||
|
||||
# get user from phone number
|
||||
recipient_phone_number = ussd_session.get('session_data').get('recipient_phone_number')
|
||||
recipient_phone_number = ussd_session.get('data').get('recipient_phone_number')
|
||||
recipient = Account.get_by_phone_number(phone_number=recipient_phone_number, session=session)
|
||||
to_address = recipient.blockchain_address
|
||||
from_address = user.blockchain_address
|
||||
amount = int(ussd_session.get('session_data').get('transaction_amount'))
|
||||
token_symbol = retrieve_token_symbol(chain_str=chain_str)
|
||||
from_address = account.blockchain_address
|
||||
amount = int(ussd_session.get('data').get('transaction_amount'))
|
||||
token_symbol = get_default_token_symbol()
|
||||
|
||||
outgoing_tx_processor = OutgoingTransactionProcessor(chain_str=chain_str,
|
||||
from_address=from_address,
|
||||
to_address=to_address)
|
||||
outgoing_tx_processor.process_outgoing_transfer_transaction(amount=amount, token_symbol=token_symbol)
|
||||
outgoing_tx_processor = OutgoingTransaction(chain_str=chain_str,
|
||||
from_address=from_address,
|
||||
to_address=to_address)
|
||||
outgoing_tx_processor.transfer(amount=amount, token_symbol=token_symbol)
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
# standard imports
|
||||
import json
|
||||
import logging
|
||||
from typing import Tuple
|
||||
|
||||
# third-party imports
|
||||
import celery
|
||||
from cic_types.models.person import generate_metadata_pointer
|
||||
from cic_types.models.person import generate_vcard_from_contact_data, manage_identity_data
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
# local imports
|
||||
from cic_ussd.chain import Chain
|
||||
from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.error import MetadataNotFoundError
|
||||
from cic_ussd.metadata import blockchain_address_to_metadata_pointer
|
||||
from cic_ussd.operations import save_to_in_memory_ussd_session_data
|
||||
from cic_ussd.redis import get_cached_data
|
||||
|
||||
logg = logging.getLogger(__file__)
|
||||
|
||||
|
||||
def change_preferred_language_to_en(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function changes the user's preferred language to english.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
user.preferred_language = 'en'
|
||||
session.add(user)
|
||||
session.flush()
|
||||
SessionBase.release_session(session=session)
|
||||
|
||||
preferences_data = {
|
||||
'preferred_language': 'en'
|
||||
}
|
||||
|
||||
s = celery.signature(
|
||||
'cic_ussd.tasks.metadata.add_preferences_metadata',
|
||||
[user.blockchain_address, preferences_data]
|
||||
)
|
||||
s.apply_async(queue='cic-ussd')
|
||||
|
||||
|
||||
def change_preferred_language_to_sw(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function changes the user's preferred language to swahili.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
account.preferred_language = 'sw'
|
||||
session.add(account)
|
||||
session.flush()
|
||||
SessionBase.release_session(session=session)
|
||||
|
||||
preferences_data = {
|
||||
'preferred_language': 'sw'
|
||||
}
|
||||
|
||||
s = celery.signature(
|
||||
'cic_ussd.tasks.metadata.add_preferences_metadata',
|
||||
[account.blockchain_address, preferences_data]
|
||||
)
|
||||
s.apply_async(queue='cic-ussd')
|
||||
|
||||
|
||||
def update_account_status_to_active(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function sets user's account to active.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
account.activate_account()
|
||||
session.add(account)
|
||||
session.flush()
|
||||
SessionBase.release_session(session=session)
|
||||
|
||||
|
||||
def process_gender_user_input(user: Account, user_input: str):
|
||||
"""
|
||||
:param user:
|
||||
:type user:
|
||||
:param user_input:
|
||||
:type user_input:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
gender = ""
|
||||
if user.preferred_language == 'en':
|
||||
if user_input == '1':
|
||||
gender = 'Male'
|
||||
elif user_input == '2':
|
||||
gender = 'Female'
|
||||
elif user_input == '3':
|
||||
gender = 'Other'
|
||||
else:
|
||||
if user_input == '1':
|
||||
gender = 'Mwanaume'
|
||||
elif user_input == '2':
|
||||
gender = 'Mwanamke'
|
||||
elif user_input == '3':
|
||||
gender = 'Nyingine'
|
||||
return gender
|
||||
|
||||
|
||||
def save_metadata_attribute_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function saves first name data to the ussd session in the redis cache.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
session = SessionBase.bind_session(session=session)
|
||||
# get current menu
|
||||
current_state = ussd_session.get('state')
|
||||
|
||||
# define session data key from current state
|
||||
key = ''
|
||||
if 'given_name' in current_state:
|
||||
key = 'given_name'
|
||||
|
||||
if 'date_of_birth' in current_state:
|
||||
key = 'date_of_birth'
|
||||
|
||||
if 'family_name' in current_state:
|
||||
key = 'family_name'
|
||||
|
||||
if 'gender' in current_state:
|
||||
key = 'gender'
|
||||
user_input = process_gender_user_input(user=user, user_input=user_input)
|
||||
|
||||
if 'location' in current_state:
|
||||
key = 'location'
|
||||
|
||||
if 'products' in current_state:
|
||||
key = 'products'
|
||||
|
||||
# check if there is existing session data
|
||||
if ussd_session.get('session_data'):
|
||||
session_data = ussd_session.get('session_data')
|
||||
session_data[key] = user_input
|
||||
else:
|
||||
session_data = {
|
||||
key: user_input
|
||||
}
|
||||
save_to_in_memory_ussd_session_data(
|
||||
queue='cic-ussd',
|
||||
session=session,
|
||||
session_data=session_data,
|
||||
ussd_session=ussd_session)
|
||||
|
||||
|
||||
def format_user_metadata(metadata: dict, user: Account):
|
||||
"""
|
||||
:param metadata:
|
||||
:type metadata:
|
||||
:param user:
|
||||
:type user:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
gender = metadata.get('gender')
|
||||
given_name = metadata.get('given_name')
|
||||
family_name = metadata.get('family_name')
|
||||
|
||||
if isinstance(metadata.get('date_of_birth'), dict):
|
||||
date_of_birth = metadata.get('date_of_birth')
|
||||
else:
|
||||
date_of_birth = {
|
||||
"year": int(metadata.get('date_of_birth')[:4])
|
||||
}
|
||||
|
||||
# check whether there's existing location data
|
||||
if isinstance(metadata.get('location'), dict):
|
||||
location = metadata.get('location')
|
||||
else:
|
||||
location = {
|
||||
"area_name": metadata.get('location')
|
||||
}
|
||||
# check whether it is a list
|
||||
if isinstance(metadata.get('products'), list):
|
||||
products = metadata.get('products')
|
||||
else:
|
||||
products = metadata.get('products').split(',')
|
||||
|
||||
phone_number = user.phone_number
|
||||
date_registered = int(user.created.replace().timestamp())
|
||||
blockchain_address = user.blockchain_address
|
||||
chain_spec = f'{Chain.spec.common_name()}:{Chain.spec.network_id()}'
|
||||
identities = manage_identity_data(
|
||||
blockchain_address=blockchain_address,
|
||||
blockchain_type=Chain.spec.engine(),
|
||||
chain_spec=chain_spec
|
||||
)
|
||||
return {
|
||||
"date_registered": date_registered,
|
||||
"date_of_birth": date_of_birth,
|
||||
"gender": gender,
|
||||
"identities": identities,
|
||||
"location": location,
|
||||
"products": products,
|
||||
"vcard": generate_vcard_from_contact_data(
|
||||
family_name=family_name,
|
||||
given_name=given_name,
|
||||
tel=phone_number
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def save_complete_user_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function persists elements of the user metadata stored in session data
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: tuple
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
|
||||
# get session data
|
||||
metadata = ussd_session.get('session_data')
|
||||
|
||||
# format metadata appropriately
|
||||
user_metadata = format_user_metadata(metadata=metadata, user=user)
|
||||
|
||||
blockchain_address = user.blockchain_address
|
||||
s_create_person_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.create_person_metadata',
|
||||
[blockchain_address, user_metadata]
|
||||
)
|
||||
s_create_person_metadata.apply_async(queue='cic-ussd')
|
||||
|
||||
|
||||
def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
blockchain_address = user.blockchain_address
|
||||
key = generate_metadata_pointer(
|
||||
identifier=blockchain_address_to_metadata_pointer(blockchain_address=user.blockchain_address),
|
||||
cic_type=':cic.person'
|
||||
)
|
||||
user_metadata = get_cached_data(key=key)
|
||||
|
||||
if not user_metadata:
|
||||
raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}')
|
||||
|
||||
given_name = ussd_session.get('session_data').get('given_name')
|
||||
family_name = ussd_session.get('session_data').get('family_name')
|
||||
date_of_birth = ussd_session.get('session_data').get('date_of_birth')
|
||||
gender = ussd_session.get('session_data').get('gender')
|
||||
location = ussd_session.get('session_data').get('location')
|
||||
products = ussd_session.get('session_data').get('products')
|
||||
|
||||
# validate user metadata
|
||||
user_metadata = json.loads(user_metadata)
|
||||
|
||||
# edit specific metadata attribute
|
||||
if given_name:
|
||||
user_metadata['given_name'] = given_name
|
||||
if family_name:
|
||||
user_metadata['family_name'] = family_name
|
||||
if date_of_birth and len(date_of_birth) == 4:
|
||||
year = int(date_of_birth[:4])
|
||||
user_metadata['date_of_birth'] = {
|
||||
'year': year
|
||||
}
|
||||
if gender:
|
||||
user_metadata['gender'] = gender
|
||||
if location:
|
||||
# get existing location metadata:
|
||||
location_data = user_metadata.get('location')
|
||||
location_data['area_name'] = location
|
||||
user_metadata['location'] = location_data
|
||||
if products:
|
||||
user_metadata['products'] = products
|
||||
|
||||
user_metadata = format_user_metadata(metadata=user_metadata, user=user)
|
||||
|
||||
s_edit_person_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.create_person_metadata',
|
||||
[blockchain_address, user_metadata]
|
||||
)
|
||||
s_edit_person_metadata.apply_async(queue='cic-ussd')
|
||||
|
||||
|
||||
def get_user_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
blockchain_address = user.blockchain_address
|
||||
s_get_user_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.query_person_metadata',
|
||||
[blockchain_address]
|
||||
)
|
||||
s_get_user_metadata.apply_async(queue='cic-ussd')
|
||||
@@ -4,67 +4,58 @@ import re
|
||||
from typing import Tuple
|
||||
|
||||
# third-party imports
|
||||
from cic_types.models.person import generate_metadata_pointer
|
||||
from chainlib.hash import strip_0x
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
# local imports
|
||||
from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.metadata import blockchain_address_to_metadata_pointer
|
||||
from cic_ussd.redis import get_cached_data
|
||||
from cic_ussd.metadata import PersonMetadata
|
||||
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
def has_cached_user_metadata(state_machine_data: Tuple[str, dict, Account]):
|
||||
def has_cached_person_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function checks whether the attributes of the user's metadata constituting a profile are filled out.
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
# check for user metadata in cache
|
||||
key = generate_metadata_pointer(
|
||||
identifier=blockchain_address_to_metadata_pointer(blockchain_address=user.blockchain_address),
|
||||
cic_type=':cic.person'
|
||||
)
|
||||
user_metadata = get_cached_data(key=key)
|
||||
return user_metadata is not None
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
identifier = bytes.fromhex(strip_0x(account.blockchain_address))
|
||||
metadata_client = PersonMetadata(identifier)
|
||||
return metadata_client.get_cached_metadata() is not None
|
||||
|
||||
|
||||
def is_valid_name(state_machine_data: Tuple[str, dict, Account]):
|
||||
def is_valid_name(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""This function checks that a user provided name is valid
|
||||
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
||||
:type state_machine_data: str
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
name_matcher = "^[a-zA-Z]+$"
|
||||
valid_name = re.match(name_matcher, user_input)
|
||||
if valid_name:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return bool(valid_name)
|
||||
|
||||
|
||||
def is_valid_gender_selection(state_machine_data: Tuple[str, dict, Account]):
|
||||
def is_valid_gender_selection(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""
|
||||
:param state_machine_data:
|
||||
:type state_machine_data:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
selection_matcher = "^[1-2]$"
|
||||
if re.match(selection_matcher, user_input):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
selection_matcher = "^[1-3]$"
|
||||
return bool(re.match(selection_matcher, user_input))
|
||||
|
||||
|
||||
def is_valid_date(state_machine_data: Tuple[str, dict, Account]):
|
||||
def is_valid_date(state_machine_data: Tuple[str, dict, Account, Session]):
|
||||
"""
|
||||
:param state_machine_data:
|
||||
:type state_machine_data:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
user_input, ussd_session, user, session = state_machine_data
|
||||
user_input, ussd_session, account, session = state_machine_data
|
||||
# For MVP this value is defaulting to year
|
||||
return len(user_input) == 4 and int(user_input) >= 1900
|
||||
|
||||
Reference in New Issue
Block a user