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
|
|
|
|
from cic_types.models.person import Person, generate_metadata_pointer
|
|
|
|
from cic_types.models.person import generate_vcard_from_contact_data, manage_identity_data
|
|
|
|
|
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-02-06 16:13:47 +01:00
|
|
|
from cic_ussd.db.models.user import User
|
2021-04-07 08:21: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__)
|
|
|
|
|
|
|
|
|
|
|
|
def change_preferred_language_to_en(state_machine_data: Tuple[str, dict, User]):
|
|
|
|
"""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 = state_machine_data
|
|
|
|
user.preferred_language = 'en'
|
|
|
|
User.session.add(user)
|
|
|
|
User.session.commit()
|
|
|
|
|
|
|
|
|
|
|
|
def change_preferred_language_to_sw(state_machine_data: Tuple[str, dict, User]):
|
|
|
|
"""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, user = state_machine_data
|
|
|
|
user.preferred_language = 'sw'
|
|
|
|
User.session.add(user)
|
|
|
|
User.session.commit()
|
|
|
|
|
|
|
|
|
|
|
|
def update_account_status_to_active(state_machine_data: Tuple[str, dict, User]):
|
|
|
|
"""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, user = state_machine_data
|
|
|
|
user.activate_account()
|
|
|
|
User.session.add(user)
|
|
|
|
User.session.commit()
|
|
|
|
|
|
|
|
|
2021-03-04 17:47:13 +01:00
|
|
|
def process_gender_user_input(user: User, user_input: str):
|
|
|
|
"""
|
|
|
|
:param user:
|
|
|
|
:type user:
|
|
|
|
:param user_input:
|
|
|
|
:type user_input:
|
|
|
|
:return:
|
|
|
|
:rtype:
|
|
|
|
"""
|
|
|
|
if user.preferred_language == 'en':
|
|
|
|
if user_input == '1':
|
|
|
|
gender = 'Male'
|
|
|
|
else:
|
|
|
|
gender = 'Female'
|
|
|
|
else:
|
|
|
|
if user_input == '1':
|
|
|
|
gender = 'Mwanaume'
|
|
|
|
else:
|
|
|
|
gender = 'Mwanamke'
|
|
|
|
return gender
|
|
|
|
|
|
|
|
|
|
|
|
def save_metadata_attribute_to_session_data(state_machine_data: Tuple[str, dict, User]):
|
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
|
|
|
|
"""
|
|
|
|
user_input, ussd_session, user = state_machine_data
|
|
|
|
|
|
|
|
# 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'
|
|
|
|
elif 'family_name' in current_state:
|
|
|
|
key = 'family_name'
|
2021-02-06 16:13:47 +01:00
|
|
|
elif 'gender' in current_state:
|
|
|
|
key = 'gender'
|
2021-03-04 17:47:13 +01:00
|
|
|
user_input = process_gender_user_input(user=user, user_input=user_input)
|
2021-02-06 16:13:47 +01:00
|
|
|
elif 'location' in current_state:
|
|
|
|
key = 'location'
|
2021-03-04 17:47:13 +01:00
|
|
|
elif 'products' in current_state:
|
|
|
|
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
|
|
|
|
}
|
|
|
|
save_to_in_memory_ussd_session_data(queue='cic-ussd', session_data=session_data, ussd_session=ussd_session)
|
|
|
|
|
|
|
|
|
2021-03-04 17:47:13 +01:00
|
|
|
def format_user_metadata(metadata: dict, user: User):
|
|
|
|
"""
|
|
|
|
: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')
|
|
|
|
location = {
|
|
|
|
"area_name": metadata.get('location')
|
|
|
|
}
|
|
|
|
products = []
|
|
|
|
if metadata.get('products'):
|
|
|
|
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,
|
|
|
|
"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, User]):
|
|
|
|
"""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
|
|
|
|
"""
|
|
|
|
user_input, ussd_session, user = state_machine_data
|
|
|
|
|
|
|
|
# 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
|
|
|
|
s_create_user_metadata = celery.signature(
|
|
|
|
'cic_ussd.tasks.metadata.create_user_metadata',
|
|
|
|
[blockchain_address, user_metadata]
|
|
|
|
)
|
|
|
|
s_create_user_metadata.apply_async(queue='cic-ussd')
|
2021-02-06 16:13:47 +01:00
|
|
|
|
2021-03-04 17:47:13 +01:00
|
|
|
|
|
|
|
def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, User]):
|
|
|
|
user_input, ussd_session, user = 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:
|
2021-04-07 08:21: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')
|
|
|
|
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
|
|
|
|
person = Person()
|
|
|
|
user_metadata = json.loads(user_metadata)
|
2021-04-06 19:53:38 +02:00
|
|
|
deserialized_person = person.deserialize(person_data=user_metadata)
|
2021-03-04 17:47:13 +01:00
|
|
|
|
|
|
|
# edit specific metadata attribute
|
|
|
|
if given_name:
|
|
|
|
deserialized_person.given_name = given_name
|
|
|
|
elif family_name:
|
|
|
|
deserialized_person.family_name = family_name
|
|
|
|
elif gender:
|
|
|
|
deserialized_person.gender = gender
|
|
|
|
elif location:
|
|
|
|
# get existing location metadata:
|
|
|
|
location_data = user_metadata.get('location')
|
|
|
|
location_data['area_name'] = location
|
|
|
|
deserialized_person.location = location_data
|
|
|
|
elif products:
|
|
|
|
deserialized_person.products = products
|
|
|
|
|
|
|
|
edited_metadata = deserialized_person.serialize()
|
|
|
|
|
|
|
|
s_edit_user_metadata = celery.signature(
|
|
|
|
'cic_ussd.tasks.metadata.edit_user_metadata',
|
|
|
|
[blockchain_address, edited_metadata, 'pgp']
|
|
|
|
)
|
|
|
|
s_edit_user_metadata.apply_async(queue='cic-ussd')
|
|
|
|
|
|
|
|
|
|
|
|
def get_user_metadata(state_machine_data: Tuple[str, dict, User]):
|
|
|
|
user_input, ussd_session, user = state_machine_data
|
|
|
|
blockchain_address = user.blockchain_address
|
|
|
|
s_get_user_metadata = celery.signature(
|
|
|
|
'cic_ussd.tasks.metadata.query_user_metadata',
|
|
|
|
[blockchain_address]
|
|
|
|
)
|
|
|
|
s_get_user_metadata.apply_async(queue='cic-ussd')
|