2021-02-06 16:13:47 +01:00
|
|
|
# standard imports
|
2021-03-04 17:47:13 +01:00
|
|
|
import json
|
2021-02-06 16:13:47 +01:00
|
|
|
import logging
|
|
|
|
from typing import Tuple
|
|
|
|
|
2021-03-04 17:47:13 +01:00
|
|
|
# third-party imports
|
|
|
|
import celery
|
2021-06-29 12:49:25 +02:00
|
|
|
from cic_types.models.person import generate_metadata_pointer
|
2021-03-04 17:47:13 +01:00
|
|
|
from cic_types.models.person import generate_vcard_from_contact_data, manage_identity_data
|
2021-06-29 12:49:25 +02:00
|
|
|
from sqlalchemy.orm.session import Session
|
2021-03-04 17:47:13 +01:00
|
|
|
|
2021-02-06 16:13:47 +01:00
|
|
|
# local imports
|
2021-03-04 17:47:13 +01:00
|
|
|
from cic_ussd.chain import Chain
|
2021-04-19 10:44:40 +02:00
|
|
|
from cic_ussd.db.models.account import Account
|
2021-06-29 12:49:25 +02:00
|
|
|
from cic_ussd.db.models.base import SessionBase
|
2021-04-09 15:00:15 +02:00
|
|
|
from cic_ussd.error import MetadataNotFoundError
|
2021-03-04 17:47:13 +01:00
|
|
|
from cic_ussd.metadata import blockchain_address_to_metadata_pointer
|
2021-02-06 16:13:47 +01:00
|
|
|
from cic_ussd.operations import save_to_in_memory_ussd_session_data
|
2021-03-04 17:47:13 +01:00
|
|
|
from cic_ussd.redis import get_cached_data
|
2021-02-06 16:13:47 +01:00
|
|
|
|
|
|
|
logg = logging.getLogger(__file__)
|
|
|
|
|
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def change_preferred_language_to_en(state_machine_data: Tuple[str, dict, Account, Session]):
|
2021-02-06 16:13:47 +01:00
|
|
|
"""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
|
|
|
|
"""
|
2021-06-29 12:49:25 +02:00
|
|
|
user_input, ussd_session, user, session = state_machine_data
|
|
|
|
session = SessionBase.bind_session(session=session)
|
2021-02-06 16:13:47 +01:00
|
|
|
user.preferred_language = 'en'
|
2021-06-29 12:49:25 +02:00
|
|
|
session.add(user)
|
|
|
|
session.flush()
|
|
|
|
SessionBase.release_session(session=session)
|
2021-02-06 16:13:47 +01:00
|
|
|
|
2021-06-23 10:54:34 +02:00
|
|
|
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')
|
|
|
|
|
2021-02-06 16:13:47 +01:00
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def change_preferred_language_to_sw(state_machine_data: Tuple[str, dict, Account, Session]):
|
2021-02-06 16:13:47 +01:00
|
|
|
"""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
|
|
|
|
"""
|
2021-06-29 12:49:25 +02:00
|
|
|
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)
|
2021-02-06 16:13:47 +01:00
|
|
|
|
2021-06-23 10:54:34 +02:00
|
|
|
preferences_data = {
|
|
|
|
'preferred_language': 'sw'
|
|
|
|
}
|
|
|
|
|
|
|
|
s = celery.signature(
|
|
|
|
'cic_ussd.tasks.metadata.add_preferences_metadata',
|
2021-06-29 12:49:25 +02:00
|
|
|
[account.blockchain_address, preferences_data]
|
2021-06-23 10:54:34 +02:00
|
|
|
)
|
|
|
|
s.apply_async(queue='cic-ussd')
|
|
|
|
|
2021-02-06 16:13:47 +01:00
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def update_account_status_to_active(state_machine_data: Tuple[str, dict, Account, Session]):
|
2021-02-06 16:13:47 +01:00
|
|
|
"""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
|
|
|
|
"""
|
2021-06-29 12:49:25 +02:00
|
|
|
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)
|
2021-02-06 16:13:47 +01:00
|
|
|
|
|
|
|
|
2021-04-19 10:44:40 +02:00
|
|
|
def process_gender_user_input(user: Account, user_input: str):
|
2021-03-04 17:47:13 +01:00
|
|
|
"""
|
|
|
|
:param user:
|
|
|
|
:type user:
|
|
|
|
:param user_input:
|
|
|
|
:type user_input:
|
|
|
|
:return:
|
|
|
|
:rtype:
|
|
|
|
"""
|
2021-06-29 12:49:25 +02:00
|
|
|
gender = ""
|
2021-03-04 17:47:13 +01:00
|
|
|
if user.preferred_language == 'en':
|
|
|
|
if user_input == '1':
|
|
|
|
gender = 'Male'
|
2021-06-03 15:40:51 +02:00
|
|
|
elif user_input == '2':
|
2021-03-04 17:47:13 +01:00
|
|
|
gender = 'Female'
|
2021-06-03 15:40:51 +02:00
|
|
|
elif user_input == '3':
|
|
|
|
gender = 'Other'
|
2021-03-04 17:47:13 +01:00
|
|
|
else:
|
|
|
|
if user_input == '1':
|
|
|
|
gender = 'Mwanaume'
|
2021-06-03 15:40:51 +02:00
|
|
|
elif user_input == '2':
|
2021-03-04 17:47:13 +01:00
|
|
|
gender = 'Mwanamke'
|
2021-06-03 15:40:51 +02:00
|
|
|
elif user_input == '3':
|
|
|
|
gender = 'Nyingine'
|
2021-03-04 17:47:13 +01:00
|
|
|
return gender
|
|
|
|
|
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def save_metadata_attribute_to_session_data(state_machine_data: Tuple[str, dict, Account, Session]):
|
2021-02-06 16:13:47 +01:00
|
|
|
"""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
|
|
|
|
"""
|
2021-06-29 12:49:25 +02:00
|
|
|
user_input, ussd_session, user, session = state_machine_data
|
|
|
|
session = SessionBase.bind_session(session=session)
|
2021-02-06 16:13:47 +01:00
|
|
|
# get current menu
|
|
|
|
current_state = ussd_session.get('state')
|
|
|
|
|
|
|
|
# define session data key from current state
|
|
|
|
key = ''
|
2021-03-04 17:47:13 +01:00
|
|
|
if 'given_name' in current_state:
|
|
|
|
key = 'given_name'
|
2021-06-03 15:40:51 +02:00
|
|
|
|
2021-06-23 15:25:09 +02:00
|
|
|
if 'date_of_birth' in current_state:
|
|
|
|
key = 'date_of_birth'
|
|
|
|
|
2021-06-03 15:40:51 +02:00
|
|
|
if 'family_name' in current_state:
|
2021-03-04 17:47:13 +01:00
|
|
|
key = 'family_name'
|
2021-06-03 15:40:51 +02:00
|
|
|
|
|
|
|
if 'gender' in current_state:
|
2021-02-06 16:13:47 +01:00
|
|
|
key = 'gender'
|
2021-03-04 17:47:13 +01:00
|
|
|
user_input = process_gender_user_input(user=user, user_input=user_input)
|
2021-06-03 15:40:51 +02:00
|
|
|
|
|
|
|
if 'location' in current_state:
|
2021-02-06 16:13:47 +01:00
|
|
|
key = 'location'
|
2021-06-03 15:40:51 +02:00
|
|
|
|
|
|
|
if 'products' in current_state:
|
2021-03-04 17:47:13 +01:00
|
|
|
key = 'products'
|
2021-02-06 16:13:47 +01:00
|
|
|
|
|
|
|
# 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
|
|
|
|
}
|
2021-06-29 12:49:25 +02:00
|
|
|
save_to_in_memory_ussd_session_data(
|
|
|
|
queue='cic-ussd',
|
|
|
|
session=session,
|
|
|
|
session_data=session_data,
|
|
|
|
ussd_session=ussd_session)
|
2021-02-06 16:13:47 +01:00
|
|
|
|
|
|
|
|
2021-04-19 10:44:40 +02:00
|
|
|
def format_user_metadata(metadata: dict, user: Account):
|
2021-03-04 17:47:13 +01:00
|
|
|
"""
|
|
|
|
: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')
|
2021-06-03 15:40:51 +02:00
|
|
|
|
2021-06-23 15:25:09 +02:00
|
|
|
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])
|
|
|
|
}
|
|
|
|
|
2021-06-03 15:40:51 +02:00
|
|
|
# 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:
|
2021-03-04 17:47:13 +01:00
|
|
|
products = metadata.get('products').split(',')
|
2021-06-03 15:40:51 +02:00
|
|
|
|
2021-03-04 17:47:13 +01:00
|
|
|
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,
|
2021-06-23 15:25:09 +02:00
|
|
|
"date_of_birth": date_of_birth,
|
2021-03-04 17:47:13 +01:00
|
|
|
"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
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def save_complete_user_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
2021-03-04 17:47:13 +01:00
|
|
|
"""This function persists elements of the user metadata stored in session data
|
2021-02-06 16:13:47 +01:00
|
|
|
:param state_machine_data: A tuple containing user input, a ussd session and user object.
|
|
|
|
:type state_machine_data: tuple
|
|
|
|
"""
|
2021-06-29 12:49:25 +02:00
|
|
|
user_input, ussd_session, user, session = state_machine_data
|
2021-02-06 16:13:47 +01:00
|
|
|
|
|
|
|
# get session data
|
2021-03-04 17:47:13 +01:00
|
|
|
metadata = ussd_session.get('session_data')
|
|
|
|
|
|
|
|
# format metadata appropriately
|
|
|
|
user_metadata = format_user_metadata(metadata=metadata, user=user)
|
|
|
|
|
|
|
|
blockchain_address = user.blockchain_address
|
2021-04-14 11:00:10 +02:00
|
|
|
s_create_person_metadata = celery.signature(
|
|
|
|
'cic_ussd.tasks.metadata.create_person_metadata',
|
2021-03-04 17:47:13 +01:00
|
|
|
[blockchain_address, user_metadata]
|
|
|
|
)
|
2021-04-14 11:00:10 +02:00
|
|
|
s_create_person_metadata.apply_async(queue='cic-ussd')
|
2021-02-06 16:13:47 +01:00
|
|
|
|
2021-03-04 17:47:13 +01:00
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, Account, Session]):
|
|
|
|
user_input, ussd_session, user, session = state_machine_data
|
2021-03-04 17:47:13 +01:00
|
|
|
blockchain_address = user.blockchain_address
|
|
|
|
key = generate_metadata_pointer(
|
|
|
|
identifier=blockchain_address_to_metadata_pointer(blockchain_address=user.blockchain_address),
|
2021-05-01 16:52:54 +02:00
|
|
|
cic_type=':cic.person'
|
2021-03-04 17:47:13 +01:00
|
|
|
)
|
|
|
|
user_metadata = get_cached_data(key=key)
|
|
|
|
|
|
|
|
if not user_metadata:
|
2021-04-09 15:00:15 +02:00
|
|
|
raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}')
|
2021-03-04 17:47:13 +01:00
|
|
|
|
|
|
|
given_name = ussd_session.get('session_data').get('given_name')
|
|
|
|
family_name = ussd_session.get('session_data').get('family_name')
|
2021-06-23 15:25:09 +02:00
|
|
|
date_of_birth = ussd_session.get('session_data').get('date_of_birth')
|
2021-03-04 17:47:13 +01:00
|
|
|
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:
|
2021-06-03 15:40:51 +02:00
|
|
|
user_metadata['given_name'] = given_name
|
|
|
|
if family_name:
|
|
|
|
user_metadata['family_name'] = family_name
|
2021-06-23 15:25:09 +02:00
|
|
|
if date_of_birth and len(date_of_birth) == 4:
|
|
|
|
year = int(date_of_birth[:4])
|
|
|
|
user_metadata['date_of_birth'] = {
|
|
|
|
'year': year
|
|
|
|
}
|
2021-06-03 15:40:51 +02:00
|
|
|
if gender:
|
|
|
|
user_metadata['gender'] = gender
|
|
|
|
if location:
|
2021-03-04 17:47:13 +01:00
|
|
|
# get existing location metadata:
|
|
|
|
location_data = user_metadata.get('location')
|
|
|
|
location_data['area_name'] = location
|
2021-06-03 15:40:51 +02:00
|
|
|
user_metadata['location'] = location_data
|
|
|
|
if products:
|
|
|
|
user_metadata['products'] = products
|
2021-03-04 17:47:13 +01:00
|
|
|
|
2021-06-03 15:40:51 +02:00
|
|
|
user_metadata = format_user_metadata(metadata=user_metadata, user=user)
|
2021-03-04 17:47:13 +01:00
|
|
|
|
2021-04-14 11:00:10 +02:00
|
|
|
s_edit_person_metadata = celery.signature(
|
2021-06-03 15:40:51 +02:00
|
|
|
'cic_ussd.tasks.metadata.create_person_metadata',
|
|
|
|
[blockchain_address, user_metadata]
|
2021-03-04 17:47:13 +01:00
|
|
|
)
|
2021-04-14 11:00:10 +02:00
|
|
|
s_edit_person_metadata.apply_async(queue='cic-ussd')
|
2021-03-04 17:47:13 +01:00
|
|
|
|
|
|
|
|
2021-06-29 12:49:25 +02:00
|
|
|
def get_user_metadata(state_machine_data: Tuple[str, dict, Account, Session]):
|
|
|
|
user_input, ussd_session, user, session = state_machine_data
|
2021-03-04 17:47:13 +01:00
|
|
|
blockchain_address = user.blockchain_address
|
|
|
|
s_get_user_metadata = celery.signature(
|
2021-04-14 11:00:10 +02:00
|
|
|
'cic_ussd.tasks.metadata.query_person_metadata',
|
2021-03-04 17:47:13 +01:00
|
|
|
[blockchain_address]
|
|
|
|
)
|
|
|
|
s_get_user_metadata.apply_async(queue='cic-ussd')
|