2021-08-06 18:29:01 +02:00
|
|
|
# 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
|
2021-09-18 11:07:05 +02:00
|
|
|
chain_str = Chain.spec.__str__()
|
2021-08-06 18:29:01 +02:00
|
|
|
|
|
|
|
if isinstance(metadata.get('identities'), dict):
|
|
|
|
identities = metadata.get('identities')
|
|
|
|
else:
|
|
|
|
identities = manage_identity_data(
|
|
|
|
blockchain_address=blockchain_address,
|
2021-09-18 11:07:05 +02:00
|
|
|
chain_str=chain_str
|
2021-08-06 18:29:01 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
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')
|