import datetime, pytz, time from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, Response, status from pydantic import BaseModel, EmailStr, Field from typing import Dict, List, Optional, Set, Union from app.lib_general import log, logging, common_route_params, Common_Route_Params from app.config import settings from app.db_sql import sql_insert, sql_update, sql_insert_or_update, sql_select, sql_delete, get_id_random, redis_lookup_id_random from app.routers.api_crud import delete_obj_template, get_obj_template, get_obj_li_template, patch_obj_template, post_obj_template # from app.methods.membership_person_methods import load_membership_person_obj from app.methods.person_methods import create_person_kiss, create_update_person_obj_v4b, handle_email_person_auth_key_url, get_person_rec_list, get_person_rec_w_external_id, load_person_obj, update_person_obj, update_person_kiss from app.models.common_field_schema import default_num_bytes from app.models.person_models import Person_Base from app.models.response_models import Resp_Body_Base, mk_resp router = APIRouter() # ### BEGIN ### API Person Routers ### post_person_obj() ### # Updated 2022-01-06 @router.post('/person', response_model=Resp_Body_Base) async def post_person_obj( person_obj: Person_Base, contact_id: str = Query(None, min_length=11, max_length=22), organization_id: str = Query(None, min_length=11, max_length=22), user_id: str = Query(None, min_length=11, max_length=22), inc_address: bool = False, inc_contact: bool = False, inc_organization: bool = False, inc_user: bool = False, return_obj: bool = True, commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) # ### SECTION ### Secondary data validation if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass elif contact_id is None: pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The contact ID was invalid or not found.') if organization_id := redis_lookup_id_random(record_id_random=organization_id, table_name='organization'): pass elif organization_id is None: pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The organization ID was invalid or not found.') if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass elif user_id is None: pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The user ID was invalid or not found.') # ### SECTION ### Process data if person_id := create_person_kiss( account_id = commons.x_account_id, person_dict_obj = person_obj, contact_id = contact_id, organization_id = organization_id, user_id = user_id, ): pass else: log.warning('Likely bad request') return mk_resp(data=False, status_code=400, response=commons.response, status_message='Not created. Something failed while processing the data. Check the field names and data types.') # Bad Request # ### SECTION ### Return successful results if return_obj: person_obj = load_person_obj( person_id = person_id, inc_address = inc_address, inc_contact = inc_contact, inc_organization = inc_organization, inc_user = inc_user ).dict(by_alias=commons.by_alias, exclude_unset=commons.exclude_unset) data = person_obj else: person_id_random = get_id_random(record_id=person_id, table_name='person') data = {} data['person_id'] = person_id data['person_id_random'] = person_id_random return mk_resp(data=data, response=commons.response) # ### END ### API Person Routers ### post_person_obj() ### # ### BEGIN ### API Person Routers ### patch_person_obj() ### # Updated 2022-01-06 @router.patch('/person/{person_id}', response_model=Resp_Body_Base) async def patch_person_obj( person_obj: Person_Base, person_id: str = Query(..., min_length=11, max_length=22), contact_id: str = Query(None, min_length=11, max_length=22), organization_id: str = Query(None, min_length=11, max_length=22), user_id: str = Query(None, min_length=11, max_length=22), inc_address: bool = False, inc_contact: bool = False, inc_organization: bool = False, inc_user: bool = False, return_obj: Optional[bool] = True, commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) # ### SECTION ### Secondary data validation person_id_random = person_id # This is used later for the response data if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The person ID was invalid or not found.') if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass elif contact_id is None: pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The contact ID was invalid or not found.') if organization_id := redis_lookup_id_random(record_id_random=organization_id, table_name='organization'): pass elif organization_id is None: pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The organization ID was invalid or not found.') if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass elif user_id is None: pass else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The user ID was invalid or not found.') # ### SECTION ### Process data if person_update_result := update_person_kiss( person_id = person_id, person_dict_obj = person_obj, contact_id = contact_id, organization_id = organization_id, user_id = user_id, ): pass else: log.warning('Likely bad request') return mk_resp(data=False, status_code=400, response=commons.response, status_message='Not updated. Something failed while processing the data. Check the field names and data types.') # Bad Request # ### SECTION ### Return successful results if return_obj: person_obj = load_person_obj( person_id = person_id, inc_address = inc_address, inc_contact = inc_contact, inc_organization = inc_organization, inc_user = inc_user ).dict(by_alias=commons.by_alias, exclude_unset=commons.exclude_unset) data = person_obj else: data = {} data['person_id'] = person_id data['person_id_random'] = person_id_random return mk_resp(data=data, response=commons.response) # ### END ### API Person Routers ### patch_person_obj() ### @router.get('/person/list', response_model=Resp_Body_Base) async def get_person_obj_li( for_obj_type: Optional[str] = Query(None, min_length=2, max_length=50), for_obj_id: Optional[str] = Query(None, min_length=11, max_length=22), commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) obj_type = 'person' result = get_obj_li_template( obj_type=obj_type, for_obj_type=for_obj_type, for_obj_id=for_obj_id, by_alias=True, exclude_unset=True, ) return result # ### BEGIN ### API Person ### person_obj_external_id() ### # NOTE: This endpoint is a little different. It will likely be used to help log in the person/user coming from an external service (Cvent). # Updated 2021-08-19 @router.get('/person/external_id', response_model=Resp_Body_Base) async def person_obj_external_id( external_id: str = Query(..., min_length=5, max_length=75), inc_address: bool = False, inc_contact: bool = False, inc_user: bool = False, inc_user_role_list: bool = False, commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) account_id = commons.x_account_id if person_data := get_person_rec_w_external_id(account_id=account_id, external_id=external_id): pass else: return mk_resp(data=None, status_code=404, response=commons.response) person_id = person_data.get('person_id') if person_dict := load_person_obj( person_id = person_id, limit = commons.limit, model_as_dict = True, # NOTE: returning model as a dict enabled = commons.enabled, inc_address = inc_address, inc_contact = inc_contact, inc_user = inc_user, inc_user_role_list = inc_user_role_list, ): if isinstance(person_dict, dict): response_data = person_dict else: response_data = person_dict else: return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request return mk_resp(data=response_data, response=commons.response) # ### END ### API Person ### person_obj_external_id() ### # ### BEGIN ### API Person ### lookup_email() ### # Updated 2021-12-01 @router.get('/person/lookup_email', response_model=Resp_Body_Base) async def lookup_email( email: str = Query(..., min_length=5, max_length=75), inc_address: bool = False, inc_contact: bool = False, inc_user: bool = False, inc_user_role_list: bool = False, commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) account_id = commons.x_account_id # import time # time.sleep(1) # Updated 2021-12-13 if person_rec_list_result := get_person_rec_list( #account_id = account_id, for_obj_type = 'account', for_obj_id = account_id, email = email, enabled = commons.enabled, limit = commons.limit, offset = commons.offset, ): person_result_list = [] for person_rec in person_rec_list_result: if load_person_result := load_person_obj( person_id = person_rec.get('person_id', None), inc_address = inc_address, inc_contact = inc_contact, inc_user = inc_user, inc_user_role_list = inc_user_role_list, enabled = commons.enabled, limit = commons.limit, by_alias = commons.by_alias, exclude_unset = commons.exclude_unset, # model_as_dict = model_as_dict, ): person_result_list.append(load_person_result) else: person_result_list.append(None) response_data = person_result_list elif isinstance(person_rec_list_result, list) or person_rec_list_result is None: # Empty list or None log.info('No results') return mk_resp(data=None, status_code=404, response=commons.response) # Not Found else: log.warning('Likely bad request') return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request return mk_resp(data=response_data, response=commons.response) # ### END ### API Person ### lookup_email() ### # ### BEGIN ### API Person ### email_create_url() ### # Updated 2021-12-03 @router.get('/person/{person_id}/email_auth_key_url', response_model=Resp_Body_Base) async def email_auth_key_url( person_id: str = Query(..., min_length=11, max_length=22), root_url: Optional[str] = Query(None, min_length=10, max_length=100), # Absolute min = 7 commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) account_id = commons.x_account_id if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass else: return mk_resp(data=False, status_code=404, response=commons.response) # Not Found if result := handle_email_person_auth_key_url( account_id = account_id, person_id = person_id, root_url = root_url, ): log.info('Email with create URL was sent.') return mk_resp(data=True, response=commons.response) else: log.warning('Email with create URL was not sent.') return mk_resp(data=False, status_code=500, response=commons.response) # ### END ### API Person ### email_create_url() ### # ### BEGIN ### API Person ### get_person_obj() ### # Updated 2021-12-15 @router.get('/person/{person_id}', response_model=Resp_Body_Base) async def get_person_obj( person_id: str = Query(..., min_length=11, max_length=22), auth_key: str = Query(None, min_length=11, max_length=22), # If passed, it must match in the person record. New 2021-12-15 inc_address: bool = False, # Priority l1 # inc_archive_list: bool = False, # Priority l3 inc_contact: bool = False, # Priority l1 inc_event_list: bool = False, # Priority l1 # inc_hosted_file_list: bool = False, # Priority l3 inc_journal_list: bool = False, # Priority l2 # inc_journal_entry_list: bool = False, # Priority l3 inc_membership_cfg: bool = False, # The list of all # inc_membership_group: bool = False, # The primary membership group # inc_membership_group_list: bool = False, # inc_membership_person_group: bool = False, inc_membership_person_group_list: bool = False, # List of membership group for a person - 2022-01-11 inc_membership_person: bool = False, inc_membership_person_profile: bool = False, # Membership profile for a person - 2022-01-11 inc_membership_person_type: bool = False, # Primary membership type for a person - 2022-01-11 # inc_membership_person_type_list: bool = False, # The list of all membership types a person is a part of # inc_membership_person_type_list: bool = False, # inc_membership_type_list: bool = False, inc_order_closed_count: bool = False, # NEW Priority l1 inc_order_line_list: bool = False, # Priority l1 inc_order_list: bool = False, # Priority l1 inc_order_cart: bool = False, # NEW Priority l1 # inc_order_cart_list: bool = False, # Priority l1 inc_organization: bool = False, # Priority l1 # inc_organization_list: bool = False, inc_post_list: bool = False, # Priority l2 inc_post_comment_list: bool = False, # Priority l3 inc_user: bool = False, # Priority l1 commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) # ### SECTION ### Secondary data validation if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass else: return mk_resp(data=None, status_code=404, response=commons.response) if person_rec_result := load_person_obj( person_id = person_id, auth_key = auth_key, limit = commons.limit, exclude_unset = False, model_as_dict = False, # NOTE: returning model as a dict enabled = commons.enabled, inc_address = inc_address, # inc_archive_list = inc_archive_list, inc_contact = inc_contact, inc_event_list = inc_event_list, # inc_hosted_file_list = inc_hosted_file_list, inc_journal_list = inc_journal_list, # inc_journal_entry_list = inc_journal_entry_list, inc_membership_cfg = inc_membership_cfg, inc_membership_person_group_list = inc_membership_person_group_list, inc_membership_person = inc_membership_person, inc_membership_person_profile = inc_membership_person_profile, inc_membership_person_type = inc_membership_person_type, # inc_membership_person_type = inc_membership_person_type, inc_order_closed_count = inc_order_closed_count, inc_order_line_list = inc_order_line_list, inc_order_list = inc_order_list, inc_order_cart = inc_order_cart, inc_order_cart_v3 = inc_order_cart, # inc_order_cart_list = inc_order_cart_list, inc_organization = inc_organization, # inc_organization_list = inc_organization_list, inc_post_list = inc_post_list, inc_post_comment_list = inc_post_comment_list, inc_user = inc_user, ): log.info('Loading successful. Returning result') return mk_resp(data=person_rec_result, response=commons.response) elif isinstance(person_rec_result, list) or person_rec_result is None: # Empty list or None log.info('No results') if auth_key: log.info('It is likely the auth_key did not match.') return mk_resp(data=None, status_code=404, response=commons.response) # Not Found else: log.warning('Likely bad request') return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request # ### END ### API Person ### get_person_obj() ### # ### BEGIN ### API Person ### get_account_obj_person_list() ### # Updated 2022-01-05 @router.get('/account/{account_id}/person/list', response_model=Resp_Body_Base) async def get_account_obj_person_list( account_id: str = Query(..., min_length=11, max_length=22), inc_address: bool = False, inc_contact: bool = False, # inc_membership_group_list: bool = False, # The list of all membership groups a person is a part of inc_membership_person: bool = False, # inc_membership_person_type: bool = False, # inc_order: bool = False, # inc_organization: bool = False, inc_user: bool = False, commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass else: return mk_resp(data=None, status_code=404, response=commons.response) response_data = None # Updated 2022-01-17 if person_rec_list_result := get_person_rec_list( for_obj_type = 'account', for_obj_id = account_id, limit = commons.limit, offset = commons.offset, enabled = commons.enabled, ): person_result_list = [] for person_rec in person_rec_list_result: if load_person_result := load_person_obj( person_id = person_rec.get('person_id', None), limit = commons.limit, by_alias = commons.by_alias, exclude_unset = commons.exclude_unset, # model_as_dict = model_as_dict, enabled = commons.enabled, inc_address = inc_address, inc_contact = inc_contact, inc_membership_person = inc_membership_person, inc_user = inc_user, ): person_result_list.append(load_person_result) else: person_result_list.append(None) response_data = person_result_list elif isinstance(person_rec_list_result, list) or person_rec_list_result is None: # Empty list or None log.info('No results') return mk_resp(data=None, status_code=404, response=commons.response) # Not Found else: log.warning('Likely bad request') return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request return mk_resp(data=response_data, response=commons.response) # ### END ### API Person ### get_account_obj_person_list() ### @router.delete('/person/{obj_id}', response_model=Resp_Body_Base) async def delete_person_obj( obj_id: str = Query(..., min_length=11, max_length=22), commons: Common_Route_Params = Depends(common_route_params), ): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) obj_type = 'person' result = delete_obj_template( obj_type=obj_type, obj_id=obj_id, ) return result