Philip/multi token v1

This commit is contained in:
2021-11-29 15:04:50 +00:00
parent b368b022c1
commit e426f7b451
32 changed files with 1037 additions and 119 deletions

View File

@@ -93,6 +93,30 @@ def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account, Sessio
return user_input == '00'
def menu_eleven_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
"""
This function checks that user input matches a string with value '11'
: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 '99'
:rtype: bool
"""
user_input, ussd_session, account, session = state_machine_data
return user_input == '11'
def menu_twenty_two_selected(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
"""
This function checks that user input matches a string with value '22'
: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 '99'
:rtype: bool
"""
user_input, ussd_session, account, session = state_machine_data
return user_input == '22'
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'

View File

@@ -3,7 +3,6 @@ user's pin.
"""
# standard imports
import json
import logging
import re
from typing import Tuple
@@ -16,6 +15,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.processor.util import wait_for_session_data
from cic_ussd.session.ussd_session import create_or_update_session, persist_ussd_session
@@ -31,11 +31,8 @@ def is_valid_pin(state_machine_data: Tuple[str, dict, Account, Session]) -> bool
:rtype: bool
"""
user_input, ussd_session, account, session = state_machine_data
pin_is_valid = False
matcher = r'^\d{4}$'
if re.match(matcher, user_input):
pin_is_valid = True
return pin_is_valid
return bool(re.match(matcher, user_input))
def is_authorized_pin(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
@@ -68,7 +65,7 @@ def save_initial_pin_to_session_data(state_machine_data: Tuple[str, dict, Accoun
: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
user_input, ussd_session, account, session = state_machine_data
initial_pin = create_password_hash(user_input)
if ussd_session.get('data'):
data = ussd_session.get('data')
@@ -97,7 +94,8 @@ def pins_match(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
:return: A match between two pin values.
:rtype: bool
"""
user_input, ussd_session, user, session = state_machine_data
user_input, ussd_session, account, session = state_machine_data
wait_for_session_data('Initial pin', session_data_key='initial_pin', ussd_session=ussd_session)
initial_pin = ussd_session.get('data').get('initial_pin')
return check_password_hash(user_input, initial_pin)
@@ -107,11 +105,12 @@ def complete_pin_change(state_machine_data: Tuple[str, dict, Account, Session]):
: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
user_input, ussd_session, account, session = state_machine_data
session = SessionBase.bind_session(session=session)
wait_for_session_data('Initial pin', session_data_key='initial_pin', ussd_session=ussd_session)
password_hash = ussd_session.get('data').get('initial_pin')
user.password_hash = password_hash
session.add(user)
account.password_hash = password_hash
session.add(account)
session.flush()
SessionBase.release_session(session=session)
@@ -134,6 +133,6 @@ def is_valid_new_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
is_old_pin = user.verify_password(password=user_input)
user_input, ussd_session, account, session = state_machine_data
is_old_pin = account.verify_password(password=user_input)
return is_valid_pin(state_machine_data=state_machine_data) and not is_old_pin

View File

@@ -6,7 +6,7 @@ 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.account.tokens import get_active_token_symbol
from cic_ussd.db.models.account import Account
from cic_ussd.notifications import Notifier
from cic_ussd.phone_number import Support
@@ -18,7 +18,7 @@ def upsell_unregistered_recipient(state_machine_data: Tuple[str, dict, Account,
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()
token_symbol = get_active_token_symbol(account.blockchain_address)
tx_sender_information = account.standard_metadata_id()
notifier.send_sms_notification('sms.upsell_unregistered_recipient',
phone_number,

View File

@@ -0,0 +1,69 @@
# standard imports
from typing import Tuple
# external imports
from sqlalchemy.orm.session import Session
# local imports
from cic_ussd.account.tokens import set_active_token
from cic_ussd.db.models.account import Account
from cic_ussd.processor.util import wait_for_session_data
from cic_ussd.session.ussd_session import save_session_data
def is_valid_token_selection(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
session_data = ussd_session.get('data')
account_tokens_list = session_data.get('account_tokens_list')
if not account_tokens_list:
wait_for_session_data('Account token list', session_data_key='account_tokens_list', ussd_session=ussd_session)
if user_input not in ['00', '22']:
try:
user_input = int(user_input)
return user_input <= len(account_tokens_list)
except ValueError:
user_input = user_input.upper()
return any(token_data['symbol'] == user_input for token_data in account_tokens_list)
def process_token_selection(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
account_tokens_list = ussd_session.get('data').get('account_tokens_list')
try:
user_input = int(user_input)
selected_token = account_tokens_list[user_input-1]
except ValueError:
user_input = user_input.upper()
selected_token = next(token_data for token_data in account_tokens_list if token_data['symbol'] == user_input)
data = {
'selected_token': selected_token
}
save_session_data(queue='cic-ussd', session=session, data=data, ussd_session=ussd_session)
def set_selected_active_token(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
wait_for_session_data(resource_name='Selected token', session_data_key='selected_token', ussd_session=ussd_session)
selected_token = ussd_session.get('data').get('selected_token')
token_symbol = selected_token.get('symbol')
set_active_token(blockchain_address=account.blockchain_address, token_symbol=token_symbol)

View File

@@ -5,18 +5,17 @@ from typing import Tuple
# third party imports
import celery
from phonenumbers.phonenumberutil import NumberParseException
from sqlalchemy.orm.session import Session
# local imports
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.tokens import get_active_token_symbol, get_cached_token_data
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.phone_number import process_phone_number, E164Format
from cic_ussd.session.ussd_session import save_session_data
from sqlalchemy.orm.session import Session
logg = logging.getLogger(__file__)
@@ -63,7 +62,11 @@ def has_sufficient_balance(state_machine_data: Tuple[str, dict, Account, Session
:rtype: bool
"""
user_input, ussd_session, account, session = state_machine_data
return int(user_input) <= get_cached_available_balance(account.blockchain_address)
identifier = bytes.fromhex(account.blockchain_address)
token_symbol = get_active_token_symbol(account.blockchain_address)
token_data = get_cached_token_data(account.blockchain_address, token_symbol)
decimals = token_data.get('decimals')
return int(user_input) <= get_cached_available_balance(decimals, [identifier, token_symbol.encode('utf-8')])
def save_recipient_phone_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
@@ -122,9 +125,10 @@ def process_transaction_request(state_machine_data: Tuple[str, dict, Account, Se
to_address = recipient.blockchain_address
from_address = account.blockchain_address
amount = int(ussd_session.get('data').get('transaction_amount'))
token_symbol = get_default_token_symbol()
token_symbol = get_active_token_symbol(account.blockchain_address)
token_data = get_cached_token_data(account.blockchain_address, token_symbol)
decimals = token_data.get('decimals')
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)
outgoing_tx_processor.transfer(amount=amount, decimals=decimals, token_symbol=token_symbol)