Censors sensitive config values.
This commit is contained in:
@@ -1,8 +1,4 @@
|
||||
# standard import
|
||||
import os
|
||||
import logging
|
||||
import urllib
|
||||
import json
|
||||
|
||||
# third-party imports
|
||||
# this must be included for the package to be recognized as a tasks package
|
||||
@@ -14,3 +10,5 @@ from .logger import *
|
||||
from .ussd_session import *
|
||||
from .callback_handler import *
|
||||
from .metadata import *
|
||||
from .notifications import *
|
||||
from .processor import *
|
||||
|
||||
@@ -7,14 +7,14 @@ from datetime import datetime, timedelta
|
||||
import celery
|
||||
|
||||
# local imports
|
||||
from cic_ussd.balance import compute_operational_balance, get_balances
|
||||
from cic_ussd.chain import Chain
|
||||
from cic_ussd.conversions import from_wei
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.account import define_account_tx_metadata
|
||||
from cic_ussd.error import ActionDataNotFoundError
|
||||
from cic_ussd.redis import InMemoryStore, cache_data, create_cached_data_key
|
||||
from cic_ussd.redis import InMemoryStore, cache_data, create_cached_data_key, get_cached_data
|
||||
from cic_ussd.tasks.base import CriticalSQLAlchemyTask
|
||||
from cic_ussd.transactions import IncomingTransactionProcessor
|
||||
|
||||
logg = logging.getLogger(__file__)
|
||||
celery_app = celery.current_app
|
||||
@@ -58,9 +58,9 @@ def process_account_creation_callback(self, result: str, url: str, status_code:
|
||||
|
||||
# add phone number metadata lookup
|
||||
s_phone_pointer = celery.signature(
|
||||
'cic_ussd.tasks.metadata.add_phone_pointer',
|
||||
[result, phone_number]
|
||||
)
|
||||
'cic_ussd.tasks.metadata.add_phone_pointer',
|
||||
[result, phone_number]
|
||||
)
|
||||
s_phone_pointer.apply_async(queue=queue)
|
||||
|
||||
# add custom metadata tags
|
||||
@@ -87,59 +87,106 @@ def process_account_creation_callback(self, result: str, url: str, status_code:
|
||||
session.close()
|
||||
|
||||
|
||||
@celery_app.task
|
||||
def process_incoming_transfer_callback(result: dict, param: str, status_code: int):
|
||||
session = SessionBase.create_session()
|
||||
@celery_app.task(bind=True)
|
||||
def process_transaction_callback(self, result: dict, param: str, status_code: int):
|
||||
if status_code == 0:
|
||||
chain_str = Chain.spec.__str__()
|
||||
|
||||
# collect result data
|
||||
# collect transaction metadata
|
||||
destination_token_symbol = result.get('destination_token_symbol')
|
||||
destination_token_value = result.get('destination_token_value')
|
||||
recipient_blockchain_address = result.get('recipient')
|
||||
sender_blockchain_address = result.get('sender')
|
||||
token_symbol = result.get('destination_token_symbol')
|
||||
value = result.get('destination_token_value')
|
||||
source_token_symbol = result.get('source_token_symbol')
|
||||
source_token_value = result.get('source_token_value')
|
||||
|
||||
# try to find users in system
|
||||
recipient_user = session.query(Account).filter_by(blockchain_address=recipient_blockchain_address).first()
|
||||
sender_user = session.query(Account).filter_by(blockchain_address=sender_blockchain_address).first()
|
||||
# build stakeholder callback params
|
||||
recipient_metadata = {
|
||||
"token_symbol": destination_token_symbol,
|
||||
"token_value": destination_token_value,
|
||||
"blockchain_address": recipient_blockchain_address,
|
||||
"tag": "recipient",
|
||||
"tx_param": param
|
||||
}
|
||||
|
||||
# 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.'
|
||||
)
|
||||
# retrieve account balances
|
||||
get_balances(
|
||||
address=recipient_blockchain_address,
|
||||
callback_param=recipient_metadata,
|
||||
chain_str=chain_str,
|
||||
callback_task='cic_ussd.tasks.callback_handler.process_transaction_balances_callback',
|
||||
token_symbol=destination_token_symbol,
|
||||
asynchronous=True)
|
||||
|
||||
# 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)
|
||||
# only retrieve sender if transaction is a transfer
|
||||
if param == 'transfer':
|
||||
sender_metadata = {
|
||||
"blockchain_address": sender_blockchain_address,
|
||||
"token_symbol": source_token_symbol,
|
||||
"token_value": source_token_value,
|
||||
"tag": "sender",
|
||||
"tx_param": param
|
||||
}
|
||||
|
||||
if param == 'tokengift':
|
||||
incoming_tx_processor.process_token_gift_incoming_transactions()
|
||||
elif param == 'transfer':
|
||||
if sender_user:
|
||||
sender_information = define_account_tx_metadata(user=sender_user)
|
||||
incoming_tx_processor.process_transfer_incoming_transaction(
|
||||
sender_information=sender_information,
|
||||
recipient_blockchain_address=recipient_blockchain_address
|
||||
)
|
||||
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='GRASSROOTS ECONOMICS',
|
||||
recipient_blockchain_address=recipient_blockchain_address
|
||||
)
|
||||
else:
|
||||
session.close()
|
||||
raise ValueError(f'Unexpected transaction param: {param}.')
|
||||
get_balances(
|
||||
address=sender_blockchain_address,
|
||||
callback_param=sender_metadata,
|
||||
chain_str=chain_str,
|
||||
callback_task='cic_ussd.tasks.callback_handler.process_transaction_balances_callback',
|
||||
token_symbol=source_token_symbol,
|
||||
asynchronous=True)
|
||||
else:
|
||||
raise ValueError(f'Unexpected status code: {status_code}.')
|
||||
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def process_transaction_balances_callback(self, result: list, param: dict, status_code: int):
|
||||
queue = self.request.delivery_info.get('routing_key')
|
||||
if status_code == 0:
|
||||
# retrieve balance data
|
||||
balances_data = result[0]
|
||||
operational_balance = compute_operational_balance(balances=balances_data)
|
||||
|
||||
# retrieve account's address
|
||||
blockchain_address = param.get('blockchain_address')
|
||||
|
||||
# append balance to transaction metadata
|
||||
transaction_metadata = param
|
||||
transaction_metadata['operational_balance'] = operational_balance
|
||||
|
||||
# retrieve account's preferences
|
||||
s_preferences_metadata = celery.signature(
|
||||
'cic_ussd.tasks.metadata.query_preferences_metadata',
|
||||
[blockchain_address],
|
||||
queue=queue
|
||||
)
|
||||
|
||||
# parse metadata and run validations
|
||||
s_process_account_metadata = celery.signature(
|
||||
'cic_ussd.tasks.processor.process_tx_metadata_for_notification',
|
||||
[transaction_metadata],
|
||||
queue=queue
|
||||
)
|
||||
|
||||
# issue notification of transaction
|
||||
s_notify_account = celery.signature(
|
||||
'cic_ussd.tasks.notifications.notify_account_of_transaction',
|
||||
queue=queue
|
||||
)
|
||||
|
||||
if param.get('tx_param') == 'transfer':
|
||||
celery.chain(s_preferences_metadata, s_process_account_metadata, s_notify_account).apply_async()
|
||||
|
||||
if param.get('tx_param') == 'tokengift':
|
||||
s_process_account_metadata = celery.signature(
|
||||
'cic_ussd.tasks.processor.process_tx_metadata_for_notification',
|
||||
[{}, transaction_metadata],
|
||||
queue=queue
|
||||
)
|
||||
celery.chain(s_process_account_metadata, s_notify_account).apply_async()
|
||||
else:
|
||||
session.close()
|
||||
raise ValueError(f'Unexpected status code: {status_code}.')
|
||||
|
||||
session.close()
|
||||
|
||||
@celery_app.task
|
||||
def process_balances_callback(result: list, param: str, status_code: int):
|
||||
@@ -151,6 +198,7 @@ def process_balances_callback(result: list, param: str, status_code: int):
|
||||
salt=':cic.balances_data'
|
||||
)
|
||||
cache_data(key=key, data=json.dumps(balances_data))
|
||||
logg.debug(f'caching: {balances_data} with key: {key}')
|
||||
else:
|
||||
raise ValueError(f'Unexpected status code: {status_code}.')
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ def query_person_metadata(blockchain_address: str):
|
||||
:rtype:
|
||||
"""
|
||||
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
|
||||
logg.debug(f'Retrieving person metadata for address: {blockchain_address}.')
|
||||
person_metadata_client = PersonMetadata(identifier=identifier)
|
||||
person_metadata_client.query()
|
||||
|
||||
@@ -72,3 +73,15 @@ def add_preferences_metadata(blockchain_address: str, data: dict):
|
||||
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
|
||||
custom_metadata_client = PreferencesMetadata(identifier=identifier)
|
||||
custom_metadata_client.create(data=data)
|
||||
|
||||
|
||||
@celery_app.task()
|
||||
def query_preferences_metadata(blockchain_address: str):
|
||||
"""This method retrieves preferences metadata based on an account's blockchain address.
|
||||
:param blockchain_address: Blockchain address of an account.
|
||||
:type blockchain_address: str | Ox-hex
|
||||
"""
|
||||
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
|
||||
logg.debug(f'Retrieving preferences metadata for address: {blockchain_address}.')
|
||||
person_metadata_client = PreferencesMetadata(identifier=identifier)
|
||||
return person_metadata_client.query()
|
||||
|
||||
70
apps/cic-ussd/cic_ussd/tasks/notifications.py
Normal file
70
apps/cic-ussd/cic_ussd/tasks/notifications.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# standard imports
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
# third-party imports
|
||||
import celery
|
||||
|
||||
# local imports
|
||||
from cic_ussd.notifications import Notifier
|
||||
from cic_ussd.phone_number import Support
|
||||
|
||||
celery_app = celery.current_app
|
||||
logg = logging.getLogger(__file__)
|
||||
notifier = Notifier()
|
||||
|
||||
|
||||
@celery_app.task
|
||||
def notify_account_of_transaction(notification_data: dict):
|
||||
"""
|
||||
:param notification_data:
|
||||
:type notification_data:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
|
||||
account_tx_role = notification_data.get('account_tx_role')
|
||||
amount = notification_data.get('amount')
|
||||
balance = notification_data.get('balance')
|
||||
phone_number = notification_data.get('phone_number')
|
||||
preferred_language = notification_data.get('preferred_language')
|
||||
token_symbol = notification_data.get('token_symbol')
|
||||
transaction_account_metadata = notification_data.get('transaction_account_metadata')
|
||||
transaction_type = notification_data.get('transaction_type')
|
||||
|
||||
timestamp = datetime.datetime.now().strftime('%d-%m-%y, %H:%M %p')
|
||||
|
||||
if transaction_type == 'tokengift':
|
||||
support_phone = Support.phone_number
|
||||
notifier.send_sms_notification(
|
||||
key='sms.account_successfully_created',
|
||||
phone_number=phone_number,
|
||||
preferred_language=preferred_language,
|
||||
balance=balance,
|
||||
support_phone=support_phone,
|
||||
token_symbol=token_symbol
|
||||
)
|
||||
|
||||
if transaction_type == 'transfer':
|
||||
if account_tx_role == 'recipient':
|
||||
notifier.send_sms_notification(
|
||||
key='sms.received_tokens',
|
||||
phone_number=phone_number,
|
||||
preferred_language=preferred_language,
|
||||
amount=amount,
|
||||
token_symbol=token_symbol,
|
||||
tx_sender_information=transaction_account_metadata,
|
||||
timestamp=timestamp,
|
||||
balance=balance
|
||||
)
|
||||
else:
|
||||
notifier.send_sms_notification(
|
||||
key='sms.sent_tokens',
|
||||
phone_number=phone_number,
|
||||
preferred_language=preferred_language,
|
||||
amount=amount,
|
||||
token_symbol=token_symbol,
|
||||
tx_recipient_information=transaction_account_metadata,
|
||||
timestamp=timestamp,
|
||||
balance=balance
|
||||
)
|
||||
88
apps/cic-ussd/cic_ussd/tasks/processor.py
Normal file
88
apps/cic-ussd/cic_ussd/tasks/processor.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# third-party imports
|
||||
import celery
|
||||
from i18n import config
|
||||
|
||||
# local imports
|
||||
from cic_ussd.account import define_account_tx_metadata
|
||||
from cic_ussd.db.models.account import Account
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.error import UnknownUssdRecipient
|
||||
from cic_ussd.transactions import from_wei
|
||||
|
||||
|
||||
celery_app = celery.current_app
|
||||
logg = logging.getLogger(__file__)
|
||||
|
||||
|
||||
@celery_app.task
|
||||
def process_tx_metadata_for_notification(result: celery.Task, transaction_metadata: dict):
|
||||
"""
|
||||
:param result:
|
||||
:type result:
|
||||
:param transaction_metadata:
|
||||
:type transaction_metadata:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
notification_data = {}
|
||||
|
||||
# get preferred language
|
||||
preferred_language = result.get('preferred_language')
|
||||
if not preferred_language:
|
||||
preferred_language = config.get('fallback')
|
||||
notification_data['preferred_language'] = preferred_language
|
||||
|
||||
# validate account information against present ussd storage data.
|
||||
session = SessionBase.create_session()
|
||||
blockchain_address = transaction_metadata.get('blockchain_address')
|
||||
tag = transaction_metadata.get('tag')
|
||||
account = session.query(Account).filter_by(blockchain_address=blockchain_address).first()
|
||||
if not account and tag == 'recipient':
|
||||
session.close()
|
||||
raise UnknownUssdRecipient(
|
||||
f'Tx for recipient: {blockchain_address} was received but has no matching user in the system.'
|
||||
)
|
||||
|
||||
# get phone number associated with account
|
||||
phone_number = account.phone_number
|
||||
notification_data['phone_number'] = phone_number
|
||||
|
||||
# get account's role in transaction i.e sender / recipient
|
||||
tx_param = transaction_metadata.get('tx_param')
|
||||
notification_data['transaction_type'] = tx_param
|
||||
|
||||
# get token amount and symbol
|
||||
if tag == 'recipient':
|
||||
account_tx_role = tag
|
||||
amount = transaction_metadata.get('token_value')
|
||||
amount = from_wei(value=amount)
|
||||
token_symbol = transaction_metadata.get('token_symbol')
|
||||
else:
|
||||
account_tx_role = tag
|
||||
amount = transaction_metadata.get('token_value')
|
||||
amount = from_wei(value=amount)
|
||||
token_symbol = transaction_metadata.get('token_symbol')
|
||||
notification_data['account_tx_role'] = account_tx_role
|
||||
notification_data['amount'] = amount
|
||||
notification_data['token_symbol'] = token_symbol
|
||||
|
||||
# get account's standard ussd identification pattern
|
||||
if tx_param == 'transfer':
|
||||
tx_account_metadata = define_account_tx_metadata(user=account)
|
||||
notification_data['transaction_account_metadata'] = tx_account_metadata
|
||||
|
||||
if tag == 'recipient':
|
||||
notification_data['notification_key'] = 'sms.received_tokens'
|
||||
else:
|
||||
notification_data['notification_key'] = 'sms.sent_tokens'
|
||||
|
||||
if tx_param == 'tokengift':
|
||||
notification_data['notification_key'] = 'sms.account_successfully_created'
|
||||
|
||||
# get account's balance
|
||||
notification_data['balance'] = transaction_metadata.get('operational_balance')
|
||||
|
||||
return notification_data
|
||||
Reference in New Issue
Block a user