Compare commits
5 Commits
master
...
lash/meta-
Author | SHA1 | Date | |
---|---|---|---|
8c453a9190 | |||
b101496402 | |||
|
80dc84eb3a | ||
|
fe07d28193 | ||
|
aed58e62df |
@ -6,6 +6,9 @@ MAX_BODY_LENGTH=1024
|
||||
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
|
||||
SERVICE_CODE=*483*46#
|
||||
|
||||
[phone_number]
|
||||
REGION=KE
|
||||
|
||||
[ussd]
|
||||
MENU_FILE=/usr/src/data/ussd_menu.json
|
||||
|
||||
|
@ -18,7 +18,7 @@ class ActionDataNotFoundError(OSError):
|
||||
pass
|
||||
|
||||
|
||||
class UserMetadataNotFoundError(OSError):
|
||||
class MetadataNotFoundError(OSError):
|
||||
"""Raised when metadata is expected but not available in cache."""
|
||||
pass
|
||||
|
||||
@ -31,3 +31,10 @@ class UnsupportedMethodError(OSError):
|
||||
class CachedDataNotFoundError(OSError):
|
||||
"""Raised when the method passed to the make request function is unsupported."""
|
||||
pass
|
||||
|
||||
|
||||
class MetadataStoreError(Exception):
|
||||
"""Raised when metadata storage fails"""
|
||||
pass
|
||||
|
||||
|
||||
|
@ -3,7 +3,10 @@
|
||||
# third-party imports
|
||||
import requests
|
||||
from chainlib.eth.address import to_checksum
|
||||
from hexathon import add_0x
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
|
||||
# local imports
|
||||
from cic_ussd.error import UnsupportedMethodError
|
||||
@ -40,4 +43,4 @@ def blockchain_address_to_metadata_pointer(blockchain_address: str):
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
return bytes.fromhex(blockchain_address[2:])
|
||||
return bytes.fromhex(strip_0x(blockchain_address))
|
||||
|
47
apps/cic-ussd/cic_ussd/metadata/phone.py
Normal file
47
apps/cic-ussd/cic_ussd/metadata/phone.py
Normal 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)
|
@ -12,6 +12,7 @@ from cic_ussd.chain import Chain
|
||||
from cic_ussd.metadata import make_request
|
||||
from cic_ussd.metadata.signer import Signer
|
||||
from cic_ussd.redis import cache_data
|
||||
from cic_ussd.error import MetadataStoreError
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
@ -28,7 +29,7 @@ class UserMetadata:
|
||||
:param identifier:
|
||||
:type identifier:
|
||||
"""
|
||||
self. headers = {
|
||||
self.headers = {
|
||||
'X-CIC-AUTOMERGE': 'server',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
@ -49,7 +50,7 @@ class UserMetadata:
|
||||
logg.info(f'Get sign material response status: {result.status_code}')
|
||||
result.raise_for_status()
|
||||
except requests.exceptions.HTTPError as error:
|
||||
raise RuntimeError(error)
|
||||
raise MetadataStoreError(error)
|
||||
|
||||
def edit(self, data: bytes, engine: str):
|
||||
"""
|
||||
@ -79,7 +80,7 @@ class UserMetadata:
|
||||
logg.info(f'Signed content submission status: {result.status_code}.')
|
||||
result.raise_for_status()
|
||||
except requests.exceptions.HTTPError as error:
|
||||
raise RuntimeError(error)
|
||||
raise MetadataStoreError(error)
|
||||
|
||||
def query(self):
|
||||
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.')
|
||||
result.raise_for_status()
|
||||
except requests.exceptions.HTTPError as error:
|
||||
raise RuntimeError(error)
|
||||
raise MetadataNotFoundError(error)
|
||||
|
@ -15,7 +15,7 @@ from cic_ussd.balance import BalanceManager, compute_operational_balance, get_ca
|
||||
from cic_ussd.chain import Chain
|
||||
from cic_ussd.db.models.user import AccountStatus, User
|
||||
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.metadata import blockchain_address_to_metadata_pointer
|
||||
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
|
||||
)
|
||||
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):
|
||||
|
@ -27,6 +27,7 @@ from cic_ussd.metadata.user import UserMetadata
|
||||
from cic_ussd.operations import (define_response_with_content,
|
||||
process_menu_interaction_requests,
|
||||
define_multilingual_responses)
|
||||
from cic_ussd.phone_number import process_phone_number
|
||||
from cic_ussd.redis import InMemoryStore
|
||||
from cic_ussd.requests import (get_request_endpoint,
|
||||
get_request_method,
|
||||
@ -151,6 +152,10 @@ def application(env, start_response):
|
||||
external_session_id = post_data.get('sessionId')
|
||||
user_input = post_data.get('text')
|
||||
|
||||
# add validation for phone number
|
||||
if phone_number:
|
||||
phone_number = process_phone_number(phone_number=phone_number, region=config.get('PHONE_NUMBER_REGION'))
|
||||
|
||||
# validate ip address
|
||||
if not check_ip(config=config, env=env):
|
||||
start_response('403 Sneaky, sneaky', errors_headers)
|
||||
|
@ -11,7 +11,7 @@ from cic_types.models.person import generate_vcard_from_contact_data, manage_ide
|
||||
# local imports
|
||||
from cic_ussd.chain import Chain
|
||||
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.operations import save_to_in_memory_ussd_session_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)
|
||||
|
||||
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')
|
||||
family_name = ussd_session.get('session_data').get('family_name')
|
||||
|
@ -5,6 +5,7 @@ import celery
|
||||
import sqlalchemy
|
||||
|
||||
# local imports
|
||||
from cic_ussd.error import MetadataStoreError
|
||||
|
||||
|
||||
class CriticalTask(celery.Task):
|
||||
@ -18,3 +19,9 @@ class CriticalSQLAlchemyTask(CriticalTask):
|
||||
sqlalchemy.exc.DatabaseError,
|
||||
sqlalchemy.exc.TimeoutError,
|
||||
)
|
||||
|
||||
|
||||
class CriticalMetadataTask(CriticalTask):
|
||||
autoretry_for = (
|
||||
MetadataStoreError,
|
||||
)
|
||||
|
@ -53,6 +53,18 @@ def process_account_creation_callback(self, result: str, url: str, status_code:
|
||||
session.add(user)
|
||||
session.commit()
|
||||
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
|
||||
cache.expire(task_id, timedelta(seconds=180))
|
||||
|
@ -8,6 +8,8 @@ import celery
|
||||
# local imports
|
||||
from cic_ussd.metadata import blockchain_address_to_metadata_pointer
|
||||
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
|
||||
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)
|
||||
user_metadata_client = UserMetadata(identifier=identifier)
|
||||
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):
|
||||
stripped_address = strip_0x(blockchain_address)
|
||||
phone_metadata_client = PhonePointerMetadata(identifier=phone, engine=engine)
|
||||
phone_metadata_client.create(data=stripped_address)
|
||||
|
Loading…
Reference in New Issue
Block a user