Working on user module
This commit is contained in:
@@ -108,7 +108,7 @@ def sql_insert(sql:str=None, data:dict=None, table_name:str=None, id_random_leng
|
||||
|
||||
|
||||
# ### BEGIN ### Core Help CRUD ### sql_update() ###
|
||||
def sql_update(sql:str=None, data:dict=None, table_name:str=None, record_id:int=None, record_id_random:str=None, rm_id_random=None, id_random_length:int=8):
|
||||
def sql_update(sql:str=None, data:dict=None, table_name:str=None, record_id:int=None, record_id_random:str=None, rm_id_random=None, id_random_length:None|int=8):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
|
||||
@@ -11,6 +11,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.common_field_schema import default_num_bytes
|
||||
from ..models.user_model import User_Base, User_New_Base, User_Out_Base
|
||||
from ..models.user_methods import load_user_obj
|
||||
from ..models.response_model import *
|
||||
@@ -77,6 +78,51 @@ async def post_user_new_obj(
|
||||
return mk_resp(data=False, status_message='The user account was not created. Something seems to have gone wrong on insert.')
|
||||
|
||||
|
||||
@router.patch('/change_password/{user_id}', response_model=Resp_Body_Base)
|
||||
async def change_user_obj_password(
|
||||
user_id: Union[int,str],
|
||||
password: Optional[str] = Query(None, min_length=6, max_length=50),
|
||||
x_account_id: Optional[str] = Header(..., ),
|
||||
return_obj: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if password and len(password) >= 10: pass
|
||||
else:
|
||||
log.warning('The password given must be at least 10 characters. Generating a new random password.')
|
||||
password = secrets.token_urlsafe(default_num_bytes)
|
||||
|
||||
if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass
|
||||
else: return mk_resp(data=False, status_code=404) # Not Found
|
||||
|
||||
user_data = {}
|
||||
#user_data['user_id'] = user_id
|
||||
#user_data['username'] = username #????
|
||||
user_data['password'] = secure_hash_string(string=password)
|
||||
|
||||
table_name = 'user'
|
||||
user_rec_update_result = sql_update(data=user_data, table_name=table_name, record_id=user_id, id_random_length=None)
|
||||
|
||||
if return_obj:
|
||||
user_obj = load_user_obj(
|
||||
user_id=user_id,
|
||||
inc_contact=inc_contact,
|
||||
inc_organization=inc_organization,
|
||||
inc_person=inc_person
|
||||
).dict(by_alias=by_alias, exclude_unset=exclude_unset)
|
||||
data = user_obj
|
||||
else:
|
||||
data = True
|
||||
return mk_resp(data=data)
|
||||
#return mk_resp(data=None, status_code=501) # Not Implemented
|
||||
|
||||
|
||||
@router.patch('/{obj_id}', response_model=Resp_Body_Base)
|
||||
async def patch_user_obj(
|
||||
obj_id: str = Query(..., min_length=1, max_length=22),
|
||||
@@ -104,72 +150,114 @@ async def patch_user_obj(
|
||||
return result
|
||||
|
||||
|
||||
# This will look up a user based on the auth key given
|
||||
# This can only be done once per key. It will be deleted if found
|
||||
# A new one will need to be requested for a particular user each time
|
||||
@router.get('/authenticate/auth_key/{auth_key}', response_model=Resp_Body_Base)
|
||||
async def auth_key_get_user_obj(
|
||||
auth_key: str = Query(..., min_length=11, max_length=22),
|
||||
# ### BEGIN ### API User Routers ### user_authenticate() ###
|
||||
# Authenticate a username and password OR by authorization key
|
||||
# An authorization key can only be done once. It will be deleted if found.
|
||||
# A new key will need to be requested for a particular user each time.
|
||||
@router.get('/authenticate', response_model=Resp_Body_Base)
|
||||
async def user_authenticate(
|
||||
account_id: Optional[Union[int,str]] = None,
|
||||
username: Optional[str] = Query(None, min_length=2, max_length=50),
|
||||
password: Optional[str] = Query(None, min_length=6, max_length=50),
|
||||
auth_key: Optional[str] = Query(None, min_length=11, max_length=22),
|
||||
x_account_id: str = Header(...),
|
||||
by_alias: Optional[bool] = True,
|
||||
exclude_unset: Optional[bool] = True,
|
||||
exclude_none: Optional[bool] = True,
|
||||
inc_contact: bool = False,
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
exclude_none: bool = True,
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if sql_select_result := sql_select(table_name='user', field_name='auth_key', field_value=auth_key):
|
||||
log.debug(sql_select_result)
|
||||
if account_id and username and password:
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return mk_resp(data=False, status_code=404) # Not Found
|
||||
|
||||
resp_data = {}
|
||||
resp_data['user_id_random'] = sql_select_result.get('id_random')
|
||||
resp_data['username'] = sql_select_result.get('username')
|
||||
resp_data['enable'] = sql_select_result.get('enable')
|
||||
resp_data['enable_from'] = sql_select_result.get('enable_from')
|
||||
resp_data['enable_to'] = sql_select_result.get('enable_to')
|
||||
try:
|
||||
user_obj = User_Base(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset, exclude_none=exclude_none)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(user_obj)
|
||||
log.debug(user_obj.get('enable_from', None))
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
user_data = {}
|
||||
user_data['account_id'] = account_id
|
||||
user_data['username'] = username
|
||||
|
||||
sql_select(table_name='user', data=user_data)
|
||||
|
||||
sql = f"""
|
||||
SELECT `user`.id AS 'user_id', `user`.id_random AS 'user_id_random', `user`.password, `user`.enable, `user`.enable_from, `user`.enable_to
|
||||
FROM `user` AS `user`
|
||||
WHERE `user`.account_id = :account_id AND `user`.username = :username
|
||||
LIMIT 1
|
||||
"""
|
||||
|
||||
# This will return a list if selecting by account ID
|
||||
if user_rec_result := sql_select(data=user_data, sql=sql):
|
||||
user_id = user_rec_result.get('user_id', None)
|
||||
|
||||
if password_hash := user_rec_result.get('password', None):
|
||||
if verify_secure_hash_string(string=password, string_hash=password_hash):
|
||||
log.info('The username was found, and the password matched.')
|
||||
#return mk_resp(data=False, status_message='The username was found, and the password matched.')
|
||||
else:
|
||||
log.info('The username was found, but the password did not match.')
|
||||
return mk_resp(data=False, status_message='The username was found, but the password did not match.')
|
||||
else:
|
||||
log.error('The password has was not found. This should not happen.')
|
||||
return mk_resp(data=False, status_message='The password has was not found. This should not happen.')
|
||||
|
||||
else: return mk_resp(data=None, status_code=404, status_message='The user account was not found')
|
||||
elif auth_key:
|
||||
if user_rec_result := sql_select(table_name='user', field_name='auth_key', field_value=auth_key):
|
||||
update_user_data = {}
|
||||
update_user_data['id'] = user_rec_result.get('id', None)
|
||||
update_user_data['auth_key'] = None
|
||||
|
||||
if user_rec_update_result := sql_update(table_name='user', data=update_user_data):
|
||||
log.info('The user record was updated with a NULL auth_key')
|
||||
else:
|
||||
log.info('The user record was not updated with a NULL auth_key')
|
||||
log.debug(user_rec_update_result)
|
||||
|
||||
user_id = user_rec_result.get('id', None) # NOTE: This us looking for "id", not "user_id"
|
||||
else: return mk_resp(data=None, status_code=404, status_message='A user account with that auth key was not found')
|
||||
else:
|
||||
return mk_resp(data=None, status_code=400, status_message='One more user account fields was missing or unexpected.') # Bad Request
|
||||
log.debug(user_rec_result)
|
||||
|
||||
if isinstance(user_rec_result, dict):
|
||||
|
||||
current_utc_datetime = datetime.datetime.now(datetime.timezone.utc)
|
||||
|
||||
log.debug(user_obj.get('enable_from', None).astimezone(pytz.UTC))
|
||||
user_enable_from = user_obj.get('enable_from', None).astimezone(pytz.UTC)
|
||||
log.debug(user_enable_from)
|
||||
|
||||
log.debug(user_obj.get('enable_to', None))
|
||||
user_enable_to = user_obj.get('enable_to', None).astimezone(pytz.UTC)
|
||||
log.debug(user_enable_to)
|
||||
|
||||
if resp_data['enable']: pass
|
||||
if user_rec_result.get('enable', None):
|
||||
log.info('The user account is enabled')
|
||||
else:
|
||||
log.info('The user account has been disabled')
|
||||
if user_enable_from <= current_utc_datetime:
|
||||
log.info('Enable from datetime is valid')
|
||||
else:
|
||||
log.info('Enable from datetime is in the future. Please wait.')
|
||||
if user_enable_to >= current_utc_datetime:
|
||||
log.info('Enable to datetime is valid')
|
||||
else:
|
||||
log.info('Enable to datetime is in the past. Your user account has been disabled.')
|
||||
log.info('The user account is not enabled')
|
||||
return mk_resp(data=False, status_message='This user account is not enabled')
|
||||
|
||||
update_data = {}
|
||||
update_data['id'] = sql_select_result.get('id')
|
||||
update_data['auth_key'] = None
|
||||
if user_enable_from := user_rec_result.get('enable_from', None).astimezone(pytz.UTC):
|
||||
if user_enable_from <= current_utc_datetime:
|
||||
log.info('Enable from datetime is valid')
|
||||
else:
|
||||
log.info('Enable from datetime is in the future. Please wait.')
|
||||
return mk_resp(data=False, status_message='This account is not yet enabled')
|
||||
|
||||
if sql_update_resp := sql_update(table_name='user', data=update_data):
|
||||
log.info('The user record was updated with a NULL auth_key')
|
||||
else:
|
||||
log.info('The user record was not updated with a NULL auth_key')
|
||||
log.debug(sql_update_resp)
|
||||
if user_enable_to := user_rec_result.get('enable_to', None).astimezone(pytz.UTC):
|
||||
if user_enable_to >= current_utc_datetime:
|
||||
log.info('Enable to datetime is valid')
|
||||
else:
|
||||
log.info('Enable to datetime is in the past. Your user account has been disabled.')
|
||||
return mk_resp(data=False, status_message='This account is not enabled because the expiratation date has passed')
|
||||
|
||||
user_obj = load_user_obj(
|
||||
user_id=user_id,
|
||||
inc_contact=inc_contact,
|
||||
inc_organization=inc_organization,
|
||||
inc_person=inc_person
|
||||
).dict(by_alias=by_alias, exclude_unset=exclude_unset)
|
||||
data = user_obj
|
||||
return mk_resp(data=user_obj)
|
||||
else:
|
||||
return mk_resp(data=None, status_code=404)
|
||||
log.error('SQL result was unexpected. A dict result type was expected. This should not happen.')
|
||||
return mk_resp(data=False, status_code=500)
|
||||
# ### END ### API User Routers ### user_authenticate() ###
|
||||
|
||||
|
||||
@router.get('/list', response_model=Resp_Body_Base)
|
||||
@@ -239,9 +327,9 @@ async def lookup_user_obj(
|
||||
"""
|
||||
|
||||
# This will return a list if selecting by account ID
|
||||
user_obj_result = sql_select(data=data, sql=sql, as_list=as_list)
|
||||
if isinstance(user_obj_result, dict):
|
||||
user_id = user_obj_result.get('user_id', None)
|
||||
user_rec_result = sql_select(data=data, sql=sql, as_list=as_list)
|
||||
if isinstance(user_rec_result, dict):
|
||||
user_id = user_rec_result.get('user_id', None)
|
||||
user_obj = load_user_obj(
|
||||
user_id=user_id,
|
||||
inc_contact=inc_contact,
|
||||
@@ -249,9 +337,9 @@ async def lookup_user_obj(
|
||||
inc_person=inc_person
|
||||
).dict(by_alias=by_alias, exclude_unset=exclude_unset)
|
||||
data = user_obj
|
||||
elif isinstance(user_obj_result, list):
|
||||
elif isinstance(user_rec_result, list):
|
||||
user_obj_li = []
|
||||
for user_obj in user_obj_result:
|
||||
for user_obj in user_rec_result:
|
||||
user_id = user_obj.get('user_id', None)
|
||||
user_obj_li.append(
|
||||
load_user_obj(
|
||||
@@ -263,7 +351,7 @@ async def lookup_user_obj(
|
||||
)
|
||||
data = user_obj_li
|
||||
else:
|
||||
log.debug(user_obj_result)
|
||||
log.debug(user_rec_result)
|
||||
return mk_resp(data=None, status_code=404) # Not Found
|
||||
return mk_resp(data=data)
|
||||
|
||||
@@ -327,23 +415,15 @@ async def lookup_username_obj(
|
||||
return mk_resp(data=data)
|
||||
|
||||
|
||||
# Authenticate a username and password
|
||||
@router.get('/authenticate', response_model=Resp_Body_Base)
|
||||
async def user_authenticate(
|
||||
username: str = Query(..., min_length=2, max_length=50),
|
||||
password: str = Query(..., min_length=6, max_length=50),
|
||||
x_account_id: str = Header(...),
|
||||
):
|
||||
|
||||
return mk_resp(data=None, status_code=501) # Not Implemented
|
||||
|
||||
|
||||
@router.get('/{obj_id}', response_model=Resp_Body_Base)
|
||||
async def get_user_obj(
|
||||
obj_id: str = Query(..., min_length=1, max_length=22),
|
||||
x_account_id: str = Header(...),
|
||||
by_alias: Optional[bool] = True,
|
||||
exclude_unset: Optional[bool] = True,
|
||||
inc_contact: bool = False,
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
Reference in New Issue
Block a user