Files
OSIT-AE-API-FastAPI/app/methods/address_methods.py

414 lines
16 KiB
Python

from __future__ import annotations
import datetime
from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_insert, sql_select, sql_update
from app.lib_general import log, logging
from app.models.address_models import Address_Base
from app.models.common_field_schema import default_num_bytes
# ### BEGIN ### API Address Methods ### load_address_obj() ###
def load_address_obj(
address_id:int|str,
limit: int = 1000, # Probably not needed for the address
by_alias: bool = True,
exclude_unset: bool = True,
model_as_dict: bool = False,
enabled: str = 'enabled', # enabled, disabled, all # Probably not needed for the address
) -> Address_Base|dict|bool:
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
else: return False
if address_rec := sql_select(table_name='v_address', record_id=address_id): pass
else: return False
try:
address_obj = Address_Base(**address_rec)
log.debug(address_obj)
except ValidationError as e:
log.error(e.json())
return False
if model_as_dict:
return address_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
else:
return address_obj
# ### END ### API Address Methods ### load_address_obj() ###
# ### BEGIN ### API Address Methods ### get_address_rec_list() ###
def get_address_rec_list(
for_obj_type: str,
for_obj_id: str,
limit: int = 1000,
enabled: str = 'enabled', # enabled, disabled, all
) -> list|bool:
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
else: return False
data = {}
data[f'{for_obj_type}_id'] = for_obj_id
# data['for_obj_type'] = for_obj_type
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
# if enabled in ['enabled', 'disabled', 'all']:
# if enabled == 'enabled':
# data['enable'] = True
# sql_enabled = f'AND `tbl`.enable = :enable'
# elif enabled == 'disabled':
# data['enable'] = False
# sql_enabled = f'AND `tbl`.enable = :enable'
# elif enabled == 'all':
# sql_enabled = ''
sql_enabled = ''
if limit:
data['limit'] = limit
sql_limit = f'LIMIT :limit'
else:
sql_limit = ''
sql = f"""
SELECT `tbl`.id AS 'address_id', `tbl`.id_random AS 'address_id_random'
FROM `address` AS `tbl`
WHERE
{sql_obj_type_id}
{sql_enabled}
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
{sql_limit};
"""
if address_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
address_rec_li = address_rec_li_result
else:
address_rec_li = []
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(address_rec_li_result)
return address_rec_li
# ### END ### API Address Methods ### get_address_rec_list() ###
# ### BEGIN ### API Address Methods ### create_update_address_obj_v4() ###
# NOTE: This will create or update an address.
# Rewrite and updated 2021-08-25
def create_update_address_obj_v4(
address_dict_obj: Address_Base|dict,
address_id: int|str = None,
account_id: int|str = None,
for_type: str = None,
for_id: int|str = None,
create_sub_obj: bool = False,
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
return_outline: bool = False,
) -> int|bool:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
log.info('Checking requirements...')
if address_id:
log.info(f'Address ID passed. Update existing Address. Address ID: {address_id}')
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
else:
log.error('Address ID passed but is invalid. Failed requirement.')
return False
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
else:
log.error('Missing or invalid Account ID passed. Not required. Ignoring.')
log.info(f'Account ID: {account_id}')
log.info('Attempting to get Account ID from related object.')
if account_id := get_account_id_w_for_type_id(for_type='address', for_id=address_id): pass
else:
log.error('Unable to get Account ID from related object.')
False
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
else:
log.error('Missing or invalid For Type and For ID ID passed. Not required. Ignoring.')
log.info(f'For Type: {for_type} and For ID: {for_id}')
else:
log.info('No Address ID passed. Create new Address. Required: Account ID, For Type, For ID')
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
else:
log.error('Missing or invalid For Type and For ID ID passed. Failed requirement.')
log.info(f'For Type: {for_type} and For ID: {for_id}')
return False
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
else:
log.error('Missing or invalid Account ID passed. Failed requirement.')
log.info(f'Account ID: {account_id}')
if for_type and for_id:
log.info('Attempting to get Account ID from related object.')
if account_id := get_account_id_w_for_type_id(for_type=for_type, for_id=for_id): pass
else:
log.error('Unable to get Account ID from related object.')
False
else:
return False
log.debug(type(address_dict_obj))
if isinstance(address_dict_obj, dict):
address_dict = address_dict_obj
if address_id:
address_dict['address_id'] = address_id
if account_id:
address_dict['account_id'] = account_id
if for_type:
address_dict['for_type'] = for_type
if for_id:
address_dict['for_id'] = for_id
try:
address_obj = Address_Base(**address_dict)
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(address_obj)
except ValidationError as e:
log.error(e.json())
return False
else:
address_obj = address_dict_obj
if address_id:
# NOTE: Can't update the ID alias if it was never set.
address_obj.id = address_id
if account_id:
address_obj.account_id = account_id
if for_type:
address_obj.for_type = for_type
if for_id:
address_obj.for_id = for_id
address_dict = address_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
if address_id:
if address_dict_up_result := sql_update(data=address_dict, table_name='address', rm_id_random=True): pass
else:
log.warning(f'Address not updated. Address ID: {address_id}')
log.debug(address_dict_up_result)
return False
log.debug(address_dict_up_result)
else:
if address_dict_in_result := sql_insert(data=address_dict, table_name='address', rm_id_random=True, id_random_length=8): pass
else:
log.warning(f'Address not created.')
log.debug(address_dict_in_result)
return False
log.debug(address_dict_in_result)
address_id = address_dict_in_result
address_outline = {}
address_outline['address_id'] = address_id
# Should this outline include for_type and for_id? Probably later.
if return_outline:
log.debug(f'Returning the Address Outline: {address_outline}')
return address_outline
else:
log.debug(f'Returning the Address ID: {address_id}')
return address_id
# ### END ### API Address Methods ### create_update_address_obj_v4() ###
# ### BEGIN ### API Address Methods ### create_address_obj() ###
# Updated 2022-01-06
def create_address_obj(
account_id: int|str,
address_dict_obj: Address_Base,
for_type: str = None,
for_id: int|str = None,
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
) -> int|bool:
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# ### SECTION ### Secondary data validation
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
else: return False
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
else: return False
log.info('Create dictionary or Pydantic object')
log.debug(type(address_dict_obj))
if isinstance(address_dict_obj, dict):
address_dict = address_dict_obj
try:
address_obj = Contact_Base(**address_dict)
log.debug(address_obj)
except ValidationError as e:
log.error(e.json())
return False
else:
address_obj = address_dict_obj
address_obj.account_id = account_id
address_dict = address_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
# log.debug(type(address_dict_obj))
# if isinstance(address_dict_obj, dict):
# if account_id:
# address_obj_new['account_id'] = account_id
# if for_type:
# address_obj_new['for_type'] = for_type
# if for_id:
# address_obj_new['for_id'] = for_id
# try:
# address_obj_new = Address_Base(**address_obj_new)
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
# log.debug(address_obj_new)
# except ValidationError as e:
# log.error(e.json())
# return False
# else:
# if account_id:
# address_obj_new.account_id = account_id
# if for_type:
# address_obj_new.for_type = for_type
# if for_id:
# address_obj_new.for_id = for_id
# address_dict = address_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
# ### SECTION ### Process data
address_obj.account_id = account_id
address_obj.for_type = for_type
address_obj.for_id = for_id
address_dict['account_id'] = account_id
address_dict['for_type'] = for_type
address_dict['for_id'] = for_id
if address_dict_in_result := sql_insert(data=address_dict, table_name='address', rm_id_random=True, id_random_length=8): pass
else:
return False
log.debug(address_dict_in_result)
address_id = address_dict_in_result
log.inf(f'Returning the new address_id: {address_id}')
return address_id
# ### END ### API Address Methods ### create_address_obj() ###
# ### BEGIN ### API Address Methods ### update_address_obj() ###
# Updated 2022-01-06
def update_address_obj(
address_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
address_dict_obj: Address_Base,
create_sub_obj: bool = False,
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
) -> bool:
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# ### SECTION ### Secondary data validation
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
else: return False
log.info('Create dictionary or Pydantic object')
log.debug(type(address_dict_obj))
if isinstance(address_dict_obj, dict):
address_dict = address_dict_obj
try:
address_obj = Contact_Base(**address_dict)
log.debug(address_obj)
except ValidationError as e:
log.error(e.json())
return False
else:
address_obj = address_dict_obj
address_dict = address_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
# ### SECTION ### Process data
address_obj.id = address_id # Is this needed?
address_dict['id'] = address_id
log.debug(address_dict_obj)
# log.debug(address_dict_obj.dict(by_alias=True, exclude_unset=True))
log.debug(address_dict_obj.dict(by_alias=False, exclude_unset=True))
# log.debug(address_dict_obj.dict(by_alias=False, exclude_unset=False))
# address_dict = address_dict_obj.dict(by_alias=False, exclude_unset=True)
if address_dict_up_result := sql_update(data=address_dict, table_name='address', rm_id_random=True): pass
else:
log.warning(f'Address not updated.')
log.debug(address_dict_up_result)
return False
log.debug(address_dict_up_result)
return True
# ### END ### API Address Methods ### update_address_obj() ###
# ### BEGIN ### API Address Methods ### create_update_address_obj() ###
def create_update_address_obj(
address_id: int|str|None, # Ideally the int ID should be passed. This allows for updating of the id_random value.
address_obj: Address_Base,
process_address: bool = False,
process_organization: bool = False,
) -> bool:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if address_id:
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
else: return False
address_obj.id = address_id
else:
# Insert record now and update later
address_dict_in = address_obj.dict(by_alias=False, exclude_unset=True)
log.debug(address_dict_in)
address_in_result = sql_insert(
data = address_dict_in,
table_name = 'address',
rm_id_random = True,
id_random_length = default_num_bytes,
)
log.debug(address_in_result)
if isinstance(address_in_result, bool) and address_in_result is True:
return address_in_result
elif isinstance(address_in_result, int):
address_id = address_in_result
address_obj.id = address_id
else:
return False # This should not happen.
# Process address data
address_dict_up = address_obj.dict(by_alias=False, exclude_unset=True)
log.debug(address_dict_up)
# Update record
address_up_result = sql_update(
data = address_dict_up,
table_name = 'address',
rm_id_random = True,
)
log.debug(address_up_result)
if isinstance(address_up_result, bool) and address_up_result is True:
return address_id
elif isinstance(address_up_result, bool) and address_up_result is False:
return False
elif isinstance(address_up_result, int):
return address_up_result
else:
return False
# ### END ### API Address Methods ### create_update_address_obj() ###