# standard imports import json import logging from datetime import timedelta # third-party imports import celery # local imports from cic_ussd.db.models.base import SessionBase from cic_ussd.db.models.user import User from cic_ussd.error import ActionDataNotFoundError from cic_ussd.redis import InMemoryStore from cic_ussd.transactions import IncomingTransactionProcessor logg = logging.getLogger(__file__) celery_app = celery.current_app @celery_app.task(bind=True) def process_account_creation_callback(self, result: str, url: str, status_code: int): """This function defines a task that creates a user and :param result: The blockchain address for the created account :type result: str :param url: URL provided to callback task in cic-eth should http be used for callback. :type url: str :param status_code: The status of the task to create an account :type status_code: int """ session = SessionBase.create_session() cache = InMemoryStore.cache task_id = self.request.root_id # get account creation status account_creation_data = cache.get(task_id) # check status if account_creation_data: account_creation_data = json.loads(account_creation_data) if status_code == 0: # update redis data account_creation_data['status'] = 'CREATED' cache.set(name=task_id, value=json.dumps(account_creation_data)) cache.persist(task_id) phone_number = account_creation_data.get('phone_number') # create user user = User(blockchain_address=result, phone_number=phone_number) session.add(user) session.commit() # expire cache cache.expire(task_id, timedelta(seconds=30)) session.close() else: cache.expire(task_id, timedelta(seconds=30)) session.close() else: session.close() raise ActionDataNotFoundError(f'Account creation task: {task_id}, returned unexpected response: {status_code}') @celery_app.task def process_incoming_transfer_callback(result: dict, param: str, status_code: int): logg.debug(f'PARAM: {param}, RESULT: {result}, STATUS_CODE: {status_code}') session = SessionBase.create_session() if result and status_code == 0: # collect result data recipient_blockchain_address = result.get('recipient') sender_blockchain_address = result.get('sender') token_symbol = result.get('token_symbol') value = result.get('destination_value') # try to find users in system recipient_user = session.query(User).filter_by(blockchain_address=recipient_blockchain_address).first() sender_user = session.query(User).filter_by(blockchain_address=sender_blockchain_address).first() # check whether recipient is in the system if not recipient_user: session.close() raise ValueError( f'Tx for recipient: {recipient_blockchain_address} was received but has no matching user in the system.' ) # process incoming transactions incoming_tx_processor = IncomingTransactionProcessor(phone_number=recipient_user.phone_number, preferred_language=recipient_user.preferred_language, token_symbol=token_symbol, value=value) if param == 'tokengift': logg.debug('Name information would require integration with cic meta.') incoming_tx_processor.process_token_gift_incoming_transactions(first_name="") elif param == 'transfer': logg.debug('Name information would require integration with cic meta.') if sender_user: sender_information = f'{sender_user.phone_number}, {""}, {""}' incoming_tx_processor.process_transfer_incoming_transaction(sender_information=sender_information) else: logg.warning( f'Tx with sender: {sender_blockchain_address} was received but has no matching user in the system.' ) incoming_tx_processor.process_transfer_incoming_transaction( sender_information=sender_blockchain_address) else: session.close() raise ValueError(f'Unexpected transaction param: {param}.') else: session.close() raise ValueError(f'Unexpected status code: {status_code}.')