From b57e51e8e75641c4320478e2628750aa55014b09 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 17 Mar 2021 19:30:13 +0000 Subject: [PATCH] Work membership and general clean up --- app/lib_general.py | 26 ++++++----- app/models/__init__.py | 0 app/models/membership_methods.py | 22 ++++----- app/models/membership_model.py | 6 +-- app/models/order_cart_methods.py | 2 +- app/models/order_methods.py | 7 +-- app/models/response_model.py | 21 ++++----- app/routers/membership.py | 79 ++++++++++++++++++++++++++++++++ 8 files changed, 118 insertions(+), 45 deletions(-) create mode 100644 app/models/__init__.py diff --git a/app/lib_general.py b/app/lib_general.py index 681067d..56ff913 100644 --- a/app/lib_general.py +++ b/app/lib_general.py @@ -10,17 +10,18 @@ from .log import * from .db_sql import sql_select -async def get_token_header(x_token: str = Header(...)): +# ### BEGIN ### API Lib General ### async get_token_header() ### +async def get_token_header(x_token:str = Header(...)): if x_token != 'fake-super-secret-token': raise HTTPException(status_code=400, detail='X-Token header invalid') +# ### END ### API Lib General ### async get_token_header() ### -async def get_account_header(x_account_id: str = Header(...)): +# ### BEGIN ### API Lib General ### async get_account_header() ### +async def get_account_header(x_account_id:str = Header(...)): log.setLevel(logging.WARNING) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - print('get_account_header(): '+x_account_id) - if len(x_account_id): log.info('The x-account-id header has a value.') if account_id := redis_lookup_id_random(table_name='account', record_id_random=x_account_id): @@ -38,24 +39,22 @@ async def get_account_header(x_account_id: str = Header(...)): account = { 'id': None, 'id_random': None } return account +# ### END ### API Lib General ### async get_account_header() ### +# ### BEGIN ### API Lib General ### redis_lookup_id_random() ### # Just return the value if it is an integer # Check if the id_random value is a string and the correct length # Attempt to look up id_random key in Redis # If success then return the ID number # If not success and there is a table_name then check the database table passed # If found in database table then store in Redis and return the ID number -def redis_lookup_id_random(record_id_random=None, table_name=None): +def redis_lookup_id_random(record_id_random:int|str, table_name:str): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - if record_id_random is None: return False - if isinstance(record_id_random, bool): return False - if isinstance(record_id_random, int): - return record_id_random - elif isinstance(record_id_random, str): - pass + if isinstance(record_id_random, str): pass + elif isinstance(record_id_random, int): return record_id_random else: log.warning(f'Unexpected data type: {str(type(record_id_random))} Expected type is a string 11 or 22 characters long.') return False @@ -119,11 +118,13 @@ def redis_lookup_id_random(record_id_random=None, table_name=None): log.setLevel(logging.ERROR) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.error('We should not be here. Something unexpected happened.') return False # Just in case +# ### BEGIN ### API Lib General ### redis_lookup_id_random() ### +# ### BEGIN ### API Lib General ### lookup_id_random_pop() ### # Look up and resolve id_random values to their id # Remove the unneeded *_id_random key from the dict -def lookup_id_random_pop(obj_data=None): +def lookup_id_random_pop(obj_data:dict): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) @@ -236,3 +237,4 @@ def lookup_id_random_pop(obj_data=None): obj_data.pop('from_object_id_random') return obj_data +# ### END ### API Lib General ### lookup_id_random_pop() ### diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/models/membership_methods.py b/app/models/membership_methods.py index bdb7a2e..12646c7 100644 --- a/app/models/membership_methods.py +++ b/app/models/membership_methods.py @@ -5,8 +5,7 @@ from typing import Dict, List, Optional, Set, Union from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator from ..lib_general import * -from ..log import * -from .db_sql import sql_select +from ..db_sql import sql_select #from .address_model import Address_Base #from .contact_model import Contact_Base @@ -160,17 +159,16 @@ def save_membership_obj(order_obj_new:Membership_Base=None): else: return False log.debug(order_line_obj_resp) return order_id - # ### END ### API Membership Model ### save_membership_obj() ### +# ### END ### API Membership Model ### save_membership_obj() ### -# ### BEGIN ### API Membership Model ### get_membership_obj() ### -def get_membership_obj(membership_id=None, inc_membership_profile=None, inc_membership_cfg=None, inc_cust_profile=None): +# ### BEGIN ### API Membership Model ### load_membership_obj() ### +def load_membership_obj(membership_id:int|str, inc_membership_profile:bool=False, inc_membership_cfg:bool=False, inc_extended_profile:bool=False) -> Membership_Base: log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) if membership_id := redis_lookup_id_random(record_id_random=membership_id, table_name='membership'): pass - else: - return False + else: return False if membership_rec := sql_select(table_name='v_membership', record_id=membership_id): #log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL @@ -190,14 +188,14 @@ def get_membership_obj(membership_id=None, inc_membership_profile=None, inc_memb membership_rec['cfg'] = membership_cfg_rec - if inc_cust_profile: + if inc_extended_profile: account_code = membership_rec.get('account_code', None) table_name = f'c_{account_code}_membership_profile' - if cust_profile_rec := sql_select(table_name=table_name, field_name='membership_id', field_value=membership_id): + if extended_profile_rec := sql_select(table_name=table_name, field_name='membership_id', field_value=membership_id): #log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL - log.debug(cust_profile_rec) + log.debug(extended_profile_rec) - membership_rec['cust_profile'] = cust_profile_rec + membership_rec['extended_profile'] = extended_profile_rec #log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(membership_rec) @@ -211,4 +209,4 @@ def get_membership_obj(membership_id=None, inc_membership_profile=None, inc_memb log.error(e.json()) return membership_obj -# ### END ### API Membership Model ### get_membership_obj() ### +# ### END ### API Membership Model ### load_membership_obj() ### diff --git a/app/models/membership_model.py b/app/models/membership_model.py index bd23757..2d8769d 100644 --- a/app/models/membership_model.py +++ b/app/models/membership_model.py @@ -36,8 +36,8 @@ class Membership_Cfg_Base(BaseModel): reject_message: Optional[str] renew_message: Optional[str] - #cust_membership_profile: Optional[str] # list of dicts outlining custom membership profile fields for client - cust_membership_profile: Optional[Json] = '[]' # list of dicts outlining custom membership profile fields for client + #extended_membership_profile: Optional[str] # list of dicts outlining extended (custom) membership profile fields for client + extended_membership_profile: Optional[Json] = '[]' # list of dicts outlining extended (custom) membership profile fields for client default_no_reply_email: Optional[str] default_no_reply_name: Optional[str] @@ -216,7 +216,7 @@ class Membership_Base(BaseModel): user: 'Optional[User_Base]' = User_Base() cfg: 'Optional[Membership_Cfg_Base]' = Membership_Cfg_Base() - cust_profile: Optional[dict] = {} + extended_profile: Optional[dict] = {} _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) diff --git a/app/models/order_cart_methods.py b/app/models/order_cart_methods.py index d14f456..a812235 100644 --- a/app/models/order_cart_methods.py +++ b/app/models/order_cart_methods.py @@ -11,7 +11,7 @@ from .order_cart_model import Order_Cart_Base # ### BEGIN ### API Order Cart Methods ### load_order_cart_obj() ### -def load_order_cart_obj(order_cart_id:int|str=None, inc_order_cart_line_li=None, inc_order_cart_cfg=None): +def load_order_cart_obj(order_cart_id:int|str, inc_order_cart_line_li:bool=False, inc_order_cart_cfg:bool=False): log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) diff --git a/app/models/order_methods.py b/app/models/order_methods.py index 9558145..6de290f 100644 --- a/app/models/order_methods.py +++ b/app/models/order_methods.py @@ -13,13 +13,10 @@ from .order_model import Order_Base # ### BEGIN ### API Order Model ### save_order_obj() ### -def save_order_obj(order_obj_new:Order_Base=None, repl_order_line_list:bool=False): +def save_order_obj(order_obj_new:Order_Base, repl_order_line_list:bool=False): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - if not order_obj_new: - return False - log.debug(order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True)) order_line_obj_li_curr = [] # Initialize to store order_line list @@ -160,7 +157,7 @@ def save_order_obj(order_obj_new:Order_Base=None, repl_order_line_list:bool=Fals # ### BEGIN ### API Order Model ### load_order_obj() ### -def load_order_obj(order_id=None, inc_order_line_li=None, inc_order_cfg=None, inc_person_obj=None, inc_user_obj=None): +def load_order_obj(order_id:int|str, inc_order_line_li:bool=False, inc_order_cfg:bool=False, inc_person_obj:bool=False, inc_user_obj:bool=False): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) diff --git a/app/models/response_model.py b/app/models/response_model.py index 23768fa..8895947 100644 --- a/app/models/response_model.py +++ b/app/models/response_model.py @@ -5,13 +5,13 @@ from typing import Dict, List, Optional, Set, Union from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from ..lib_general import * -from ..log import * from app.config import settings from .common_field_schema import base_fields, default_num_bytes +# ### BEGIN ### API Response Model ### Resp_Body_Base() ### # The pydantic BaseModel to help make consistent REST responses - STI 2021-03-05 class Resp_Body_Base(BaseModel): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL @@ -19,16 +19,18 @@ class Resp_Body_Base(BaseModel): data: Union[dict, list] meta: Optional[dict] +# ### END ### API Response Model ### Resp_Body_Base() ### -# The make response function for REST - STI 2021-03-05 -def mk_resp(data:dict={}, dict_to_json:bool=None, status_code:int=200, status_message:str=None, status_name:str=None, success:bool=True, details:bool=None, by_alias:bool=True, exclude_unset:bool=True): +# ### BEGIN ### API Response Model ### mk_resp() ### +# The make response function for REST - STI 2021-03-17 +def mk_resp(data:None|bool|dict|list, dict_to_json:bool=False, status_code:int=200, status_message:str='', status_name:str='', success:bool=True, details:str='', by_alias:bool=True, exclude_unset:bool=True): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - if data is None: data = { 'result': None } - elif data == False: data = { 'result': False } - elif data == True: data = { 'result': True } + if data is None: data = { 'result': data } + elif data == False: data = { 'result': data } + elif data == True: data = { 'result': data } resp_body = {} resp_body['data'] = data @@ -54,11 +56,6 @@ def mk_resp(data:dict={}, dict_to_json:bool=None, status_code:int=200, status_me log.debug(type(resp_body['data'])) resp_body = Resp_Body_Base(**resp_body).dict(by_alias=by_alias, exclude_unset=exclude_unset) - #resp_body_json = resp_body.json(by_alias=True, exclude_unset=False) - #response = app.response_class( - #response=resp_body_json, - #status=status_code, - #mimetype='application/json' - #) return resp_body +# ### END ### API Response Model ### mk_resp() ### \ No newline at end of file diff --git a/app/routers/membership.py b/app/routers/membership.py index 9c17b40..c044030 100644 --- a/app/routers/membership.py +++ b/app/routers/membership.py @@ -12,6 +12,7 @@ from app.db_sql import * from .api_crud import delete_obj_template, get_obj_template, get_obj_li_template, patch_obj_template, post_obj_template from ..models.membership_model import Membership_Base +from ..models.membership_methods import load_membership_obj from ..models.response_model import * @@ -90,6 +91,84 @@ async def get_membership_obj_li( return result +# Look up is only for account, person, or user records +@router.get('/lookup', response_model=Resp_Body_Base) +async def lookup_membership_obj( + for_obj_id: Union[int,str], + for_obj_type: str = Query(..., min_length=2, max_length=50), + x_account_id: str = Header(...), + inc_membership_profile: bool = True, + inc_membership_cfg: bool = True, + inc_extended_profile: bool = True, + by_alias: bool = True, + exclude_unset: bool = True, + ): + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'membership' + base_name = Membership_Base + + if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass + else: return mk_resp(data=False, status_code=404) # Not Found + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + + data = {} + as_list = False + if for_obj_type == 'account' and for_obj_id: + data['account_id'] = for_obj_id + sql_where_for_obj_type = """`membership`.account_id = :account_id""" + sql_limit = '' + as_list = True + elif for_obj_type == 'person' and for_obj_id: + data['person_id'] = for_obj_id + sql_where_for_obj_type = """`membership`.person_id = :person_id""" + sql_limit = 'LIMIT 1' + elif for_obj_type == 'user' and for_obj_id: + data['user_id'] = for_obj_id + sql_where_for_obj_type = """`membership`.user_id = :user_id""" + sql_limit = 'LIMIT 1' + else: + log.debug(f'Object type={for_obj_type}; Object ID={for_obj_id}') + return mk_resp(data=False, status_code=400) # Bad Request + + sql = f""" + SELECT id AS 'membership_id', id_random AS 'membership_id_random' + FROM `membership` AS `membership` + WHERE {sql_where_for_obj_type} + {sql_limit} + """ + + # This will return a list if selecting by account ID + membership_obj_result = sql_select(data=data, sql=sql, as_list=as_list) + if isinstance(membership_obj_result, dict): + membership_id = membership_obj_result.get('membership_id', None) + membership_obj = load_membership_obj( + membership_id=membership_id, + inc_membership_profile=inc_membership_profile, + inc_membership_cfg=inc_membership_cfg, + inc_extended_profile=inc_extended_profile + ).dict(by_alias=by_alias, exclude_unset=exclude_unset) + data = membership_obj + elif isinstance(membership_obj_result, list): + membership_obj_li = [] + for membership_obj in membership_obj_result: + membership_id = membership_obj.get('membership_id', None) + membership_obj_li.append( + load_membership_obj( + membership_id=membership_id, + inc_membership_profile=inc_membership_profile, + inc_membership_cfg=inc_membership_cfg, + inc_extended_profile=inc_extended_profile + ).dict(by_alias=by_alias, exclude_unset=exclude_unset) + ) + data = membership_obj_li + else: + log.debug(membership_obj_result) + return mk_resp(data=None, status_code=404) # Not Found + return mk_resp(data=data) + + @router.get('/{obj_id}', response_model=Resp_Body_Base) async def get_membership_obj( obj_id: str = Query(..., min_length=1, max_length=22),