Add phone metadata generator

This commit is contained in:
nolash 2021-04-07 08:21:15 +02:00
parent 5c6375c9ec
commit aed58e62df
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
9 changed files with 97 additions and 11 deletions

View File

@ -18,7 +18,7 @@ class ActionDataNotFoundError(OSError):
pass pass
class UserMetadataNotFoundError(OSError): class MetadataNotFoundError(OSError):
"""Raised when metadata is expected but not available in cache.""" """Raised when metadata is expected but not available in cache."""
pass pass
@ -31,3 +31,10 @@ class UnsupportedMethodError(OSError):
class CachedDataNotFoundError(OSError): class CachedDataNotFoundError(OSError):
"""Raised when the method passed to the make request function is unsupported.""" """Raised when the method passed to the make request function is unsupported."""
pass pass
class MetadataStoreError(Exception):
"""Raised when metadata storage fails"""
pass

View File

@ -3,7 +3,10 @@
# third-party imports # third-party imports
import requests import requests
from chainlib.eth.address import to_checksum from chainlib.eth.address import to_checksum
from hexathon import add_0x from hexathon import (
add_0x,
strip_0x,
)
# local imports # local imports
from cic_ussd.error import UnsupportedMethodError from cic_ussd.error import UnsupportedMethodError
@ -40,4 +43,4 @@ def blockchain_address_to_metadata_pointer(blockchain_address: str):
:return: :return:
:rtype: :rtype:
""" """
return bytes.fromhex(blockchain_address[2:]) return bytes.fromhex(strip_0x(blockchain_address))

View File

@ -0,0 +1,47 @@
# standard imports
import logging
import os
# external imports
from cic_types.models.person import generate_metadata_pointer
from cic_ussd.metadata import make_request
from cic_ussd.metadata.signer import Signer
# local imports
from cic_ussd.error import MetadataStoreError
logg = logging.getLogger().getChild(__name__)
class PhonePointerMetadata:
base_url = None
def __init__(self, identifier: bytes, engine: str):
"""
:param identifier:
:type identifier:
"""
self.headers = {
'X-CIC-AUTOMERGE': 'server',
'Content-Type': 'application/json'
}
self.identifier = identifier
self.metadata_pointer = generate_metadata_pointer(
identifier=self.identifier,
cic_type='cic.phone'
)
if self.base_url:
self.url = os.path.join(self.base_url, self.metadata_pointer)
self.engine = engine
def create(self, data: str):
try:
result = make_request(method='POST', url=self.url, data=data, headers=self.headers)
metadata = result.content
self.edit(data=metadata, engine=self.engine)
result.raise_for_status()
except requests.exceptions.HTTPError as error:
raise MetadataStoreError(error)

View File

@ -12,6 +12,7 @@ from cic_ussd.chain import Chain
from cic_ussd.metadata import make_request from cic_ussd.metadata import make_request
from cic_ussd.metadata.signer import Signer from cic_ussd.metadata.signer import Signer
from cic_ussd.redis import cache_data from cic_ussd.redis import cache_data
from cic_ussd.error import MetadataStoreError
logg = logging.getLogger() logg = logging.getLogger()
@ -28,7 +29,7 @@ class UserMetadata:
:param identifier: :param identifier:
:type identifier: :type identifier:
""" """
self. headers = { self.headers = {
'X-CIC-AUTOMERGE': 'server', 'X-CIC-AUTOMERGE': 'server',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
@ -49,7 +50,7 @@ class UserMetadata:
logg.info(f'Get sign material response status: {result.status_code}') logg.info(f'Get sign material response status: {result.status_code}')
result.raise_for_status() result.raise_for_status()
except requests.exceptions.HTTPError as error: except requests.exceptions.HTTPError as error:
raise RuntimeError(error) raise MetadataStoreError(error)
def edit(self, data: bytes, engine: str): def edit(self, data: bytes, engine: str):
""" """
@ -79,7 +80,7 @@ class UserMetadata:
logg.info(f'Signed content submission status: {result.status_code}.') logg.info(f'Signed content submission status: {result.status_code}.')
result.raise_for_status() result.raise_for_status()
except requests.exceptions.HTTPError as error: except requests.exceptions.HTTPError as error:
raise RuntimeError(error) raise MetadataStoreError(error)
def query(self): def query(self):
result = make_request(method='GET', url=self.url) result = make_request(method='GET', url=self.url)
@ -99,4 +100,4 @@ class UserMetadata:
logg.info('The data is not available and might need to be added.') logg.info('The data is not available and might need to be added.')
result.raise_for_status() result.raise_for_status()
except requests.exceptions.HTTPError as error: except requests.exceptions.HTTPError as error:
raise RuntimeError(error) raise MetadataNotFoundError(error)

View File

@ -15,7 +15,7 @@ from cic_ussd.balance import BalanceManager, compute_operational_balance, get_ca
from cic_ussd.chain import Chain from cic_ussd.chain import Chain
from cic_ussd.db.models.user import AccountStatus, User from cic_ussd.db.models.user import AccountStatus, User
from cic_ussd.db.models.ussd_session import UssdSession from cic_ussd.db.models.ussd_session import UssdSession
from cic_ussd.error import UserMetadataNotFoundError from cic_ussd.error import MetadataNotFoundError
from cic_ussd.menu.ussd_menu import UssdMenu from cic_ussd.menu.ussd_menu import UssdMenu
from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.metadata import blockchain_address_to_metadata_pointer
from cic_ussd.phone_number import get_user_by_phone_number from cic_ussd.phone_number import get_user_by_phone_number
@ -235,7 +235,7 @@ def process_display_user_metadata(user: User, display_key: str):
products=products products=products
) )
else: else:
raise UserMetadataNotFoundError(f'Expected user metadata but found none in cache for key: {user.blockchain_address}') raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {user.blockchain_address}')
def process_account_statement(user: User, display_key: str, ussd_session: dict): def process_account_statement(user: User, display_key: str, ussd_session: dict):

View File

@ -11,7 +11,7 @@ from cic_types.models.person import generate_vcard_from_contact_data, manage_ide
# local imports # local imports
from cic_ussd.chain import Chain from cic_ussd.chain import Chain
from cic_ussd.db.models.user import User from cic_ussd.db.models.user import User
from cic_ussd.error import UserMetadataNotFoundError from cic_ussd.error import MetadataNotFoundError
from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.metadata import blockchain_address_to_metadata_pointer
from cic_ussd.operations import save_to_in_memory_ussd_session_data from cic_ussd.operations import save_to_in_memory_ussd_session_data
from cic_ussd.redis import get_cached_data from cic_ussd.redis import get_cached_data
@ -181,7 +181,7 @@ def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, User]):
user_metadata = get_cached_data(key=key) user_metadata = get_cached_data(key=key)
if not user_metadata: if not user_metadata:
raise UserMetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}') raise MetadataNotFoundError(f'Expected user metadata but found none in cache for key: {blockchain_address}')
given_name = ussd_session.get('session_data').get('given_name') given_name = ussd_session.get('session_data').get('given_name')
family_name = ussd_session.get('session_data').get('family_name') family_name = ussd_session.get('session_data').get('family_name')

View File

@ -5,6 +5,7 @@ import celery
import sqlalchemy import sqlalchemy
# local imports # local imports
from cic_ussd.error import MetadataStoreError
class CriticalTask(celery.Task): class CriticalTask(celery.Task):
@ -18,3 +19,9 @@ class CriticalSQLAlchemyTask(CriticalTask):
sqlalchemy.exc.DatabaseError, sqlalchemy.exc.DatabaseError,
sqlalchemy.exc.TimeoutError, sqlalchemy.exc.TimeoutError,
) )
class CriticalMetadataTask(CriticalTask):
autoretry_for = (
MetadataStoreError,
)

View File

@ -54,6 +54,18 @@ def process_account_creation_callback(self, result: str, url: str, status_code:
session.commit() session.commit()
session.close() session.close()
queue = self.request.delivery_info.get('routing_key')
s = celery.signature(
'cic_ussd.tasks.metadata.add_phone_pointer',
[
result,
phone_number,
'pgp',
]
queue=queue,
)
s.apply_async()
# expire cache # expire cache
cache.expire(task_id, timedelta(seconds=180)) cache.expire(task_id, timedelta(seconds=180))

View File

@ -8,6 +8,8 @@ import celery
# local imports # local imports
from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.metadata import blockchain_address_to_metadata_pointer
from cic_ussd.metadata.user import UserMetadata from cic_ussd.metadata.user import UserMetadata
from cic_ussd.metadata.phone import PhonePointerMetadata
from cic_ussd.tasks.base import CriticalMetadataTask
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
@ -46,3 +48,10 @@ def edit_user_metadata(blockchain_address: str, data: bytes, engine: str):
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address) identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
user_metadata_client = UserMetadata(identifier=identifier) user_metadata_client = UserMetadata(identifier=identifier)
user_metadata_client.edit(data=data, engine=engine) user_metadata_client.edit(data=data, engine=engine)
@celery_app.task(bind=True, base=CriticalMetadataTask)
def add_phone_pointer(blockchain_address: str, phone: str, engine: str):
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
phone_metadata_client = PhonePointerMetadata(identifier=identifier, engine=engine)
phone_metadata_client.create(data=phone)