From 46c562871feaa2f6da46e921b09f63bc58c8cc1b Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Thu, 11 Mar 2021 18:19:25 -0500 Subject: [PATCH] Working finally getting this to interact with the actual front end. --- app/db_sql.py | 2 +- app/main.py | 10 ++- app/models/api_model.py | 41 +++++++++ app/routers/address.py | 1 - app/routers/api.py | 169 +++++++++++++++++++++++++++++++++++ app/routers/contact.py | 1 - app/routers/event_exhibit.py | 1 - app/routers/order.py | 56 ++++++++++++ 8 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 app/models/api_model.py create mode 100644 app/routers/api.py diff --git a/app/db_sql.py b/app/db_sql.py index e26ed77..1c94c69 100644 --- a/app/db_sql.py +++ b/app/db_sql.py @@ -282,7 +282,7 @@ def sql_select( as_dict=True, as_list=None ): - log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) if table_name and not (record_id or record_id_random or field_name or field_value or sql or data): diff --git a/app/main.py b/app/main.py index 5d4fc2c..fdf9684 100644 --- a/app/main.py +++ b/app/main.py @@ -18,7 +18,7 @@ from .lib_general import * from .log import * # Import the routers here first: -from .routers import api_crud, account, address, archive, archive_content, contact, event, event_exhibit, event_registration, event_session, membership, order, order_cart, organization, page, person, post, post_comment, product, site, user, websockets # , items, journals +from .routers import api_crud, api, account, address, archive, archive_content, contact, event, event_exhibit, event_registration, event_session, membership, order, order_cart, organization, page, person, post, post_comment, product, site, user, websockets # , items, journals from .db_sql import db @@ -53,6 +53,14 @@ app.include_router( #dependencies=[Depends(get_account_header)], #responses={404: {'description': 'Not found'}}, ) +app.include_router( + api.router, + prefix='/api', + tags=['API'], + #dependencies=[Depends(get_token_header)], + #dependencies=[Depends(get_account_header)], + #responses={404: {'description': 'Not found'}}, +) app.include_router( account.router, prefix='/account', diff --git a/app/models/api_model.py b/app/models/api_model.py new file mode 100644 index 0000000..c9025b4 --- /dev/null +++ b/app/models/api_model.py @@ -0,0 +1,41 @@ +from __future__ import annotations +import datetime, hashlib, logging, os, pytz, redis, secrets + +from typing import Dict, List, Optional, Set, Union +from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator + +from ..lib_general import * + +from .common_field_schema import base_fields, default_num_bytes + + +class Api_Base(BaseModel): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + id: Optional[int] + name: Optional[str] + secret_key: Optional[str] + enable: Optional[bool] + enable_from: Optional[datetime.datetime] = Field( + default_factory=lambda:datetime.datetime.now, + ) + enable_to: Optional[datetime.datetime] + + temporary_token: str = Field( + default_factory=lambda:secrets.token_urlsafe(default_num_bytes), + ) + expire_on: Optional[datetime.datetime] = Field( + default_factory=datetime.datetime.now, + ) + + created_on: Optional[datetime.datetime] = None + updated_on: Optional[datetime.datetime] = None + + _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) + + class Config: + underscore_attrs_are_private = True + #fields = base_fields + +#Account_Base.update_forward_refs() diff --git a/app/routers/address.py b/app/routers/address.py index 91fe3c2..085be5e 100644 --- a/app/routers/address.py +++ b/app/routers/address.py @@ -5,7 +5,6 @@ from pydantic import BaseModel, EmailStr, Field from typing import Dict, List, Optional, Set, Union from ..lib_general import * -from ..log import * from app.config import settings from app.db_sql import * diff --git a/app/routers/api.py b/app/routers/api.py new file mode 100644 index 0000000..93362ec --- /dev/null +++ b/app/routers/api.py @@ -0,0 +1,169 @@ +import datetime +#from datetime import datetime, time, timedelta +from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, status +from pydantic import BaseModel, EmailStr, Field +from typing import Dict, List, Optional, Set, Union + +from ..lib_general import * +from app.config import settings +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.api_model import Api_Base +from ..models.response_model import * + + +router = APIRouter() + + + +@router.get('/temp_token', response_model=Resp_Body_Base) +async def get_api_temp_token( + x_aether_api_key: Optional[str] = Header(None), + x_aether_api_token: Optional[str] = Header(None), + x_aether_api_token_expire_on: Optional[str] = Header(None), + ): + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + table_name_select = 'api_key' + field_name = 'secret_key' + field_value = x_aether_api_key + + if x_aether_api_key: + log.debug(f'Contains a value in x_aether_api_key: {x_aether_api_key}') + sql_result = sql_select(table_name=table_name_select, field_name=field_name, field_value=field_value) + else: + return mk_resp(data=False, status_code=400) + + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + if sql_result: + log.debug(type(sql_result)) + log.debug(sql_result) + + base_name = Api_Base + resp_data = base_name(**sql_result).dict(by_alias=True, exclude_unset=False) + log.debug(resp_data) + + return mk_resp(data=resp_data) + else: + log.debug(sql_result) + return mk_resp(data=False, status_code=404) + + #obj_type = 'api' + #result = get_obj_template( + #obj_type=obj_type, + #obj_id=obj_id, + #by_alias=True, + #exclude_unset=True, + #) + #return result + + +@router.post('', response_model=Resp_Body_Base) +async def post_api_obj( + obj: Api_Base, + x_account_id: str = Header(...), + return_obj: Optional[bool] = True, + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'api' + obj_data_dict = obj.dict(by_alias=False, exclude_unset=True) + result = post_obj_template( + obj_type=obj_type, + data=obj_data_dict, + return_obj=True, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.patch('/{obj_id}', response_model=Resp_Body_Base) +async def patch_api_obj( + obj_id: str = Query(..., min_length=1, max_length=22), + obj: Api_Base = None, + x_account_id: Optional[str] = Header(..., ), + return_obj: Optional[bool] = True, + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'api' + obj_data_dict = obj.dict(by_alias=False, exclude_unset=True) + obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=obj_type) + obj_data_dict['id_random'] = obj_id + result = patch_obj_template( + obj_type=obj_type, + data=obj_data_dict, + obj_id=obj_id, + return_obj=True, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.get('/list', response_model=Resp_Body_Base) +async def get_api_obj_li( + for_obj_type: Optional[str] = Query(None, min_length=2, max_length=50), + for_obj_id: Optional[str] = Query(None, min_length=1, max_length=22), + x_account_id: str = Header(...), + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'api' + 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 + + +@router.get('/{obj_id}', response_model=Resp_Body_Base) +async def get_api_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, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'api' + result = get_obj_template( + obj_type=obj_type, + obj_id=obj_id, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.delete('/{obj_id}', response_model=Resp_Body_Base) +async def delete_api_obj( + obj_id: str = Query(..., min_length=1, max_length=22), + x_account_id: str = Header(...), + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'api' + result = delete_obj_template( + obj_type=obj_type, + obj_id=obj_id, + ) + return result diff --git a/app/routers/contact.py b/app/routers/contact.py index f532588..aad8813 100644 --- a/app/routers/contact.py +++ b/app/routers/contact.py @@ -5,7 +5,6 @@ from pydantic import BaseModel, EmailStr, Field from typing import Dict, List, Optional, Set, Union from ..lib_general import * -from ..log import * from app.config import settings from app.db_sql import * diff --git a/app/routers/event_exhibit.py b/app/routers/event_exhibit.py index 75481bd..6705558 100644 --- a/app/routers/event_exhibit.py +++ b/app/routers/event_exhibit.py @@ -5,7 +5,6 @@ from pydantic import BaseModel, EmailStr, Field from typing import Dict, List, Optional, Set, Union from ..lib_general import * -from ..log import * from app.config import settings from app.db_sql import * diff --git a/app/routers/order.py b/app/routers/order.py index 828f0ec..309faf1 100644 --- a/app/routers/order.py +++ b/app/routers/order.py @@ -72,6 +72,7 @@ async def patch_order_obj( async def get_order_obj_li( for_obj_type: Optional[str] = Query(None, min_length=2, max_length=50), for_obj_id: Optional[str] = Query(None, min_length=1, max_length=22), + order_status: Optional[str] = 'complete', x_account_id: str = Header(...), by_alias: Optional[bool] = True, exclude_unset: Optional[bool] = True, @@ -89,6 +90,61 @@ async def get_order_obj_li( ) return result + person_id = redis_lookup_id_random(record_id_random=person_id_random, table_name='person') + + data = {} + data['person_id'] = person_id + + if obj_type == 'person': # and check there is an ID as well! + sql_account_person_user = f"""`order`.person_id = :person_id""" + + if order_status: + data['status'] = order_status + sql_status = f"""AND `order`.status = :status""" + else: + sql_status = '' + + + # if from_datetime and to_datetime: + # data['from_datetime'] = from_datetime + # data['to_datetime'] = to_datetime + # sql_from_to_datetime = f"""AND `order`.created_on >= :from_datetime AND `order`.created_on <= :to_datetime""" + # elif from_datetime: + # data['from_datetime'] = from_datetime + # sql_from_to_datetime = f"""AND `order`.created_on >= :from_datetime""" + # elif to_datetime: + # data['to_datetime'] = to_datetime + # sql_from_to_datetime = f"""AND `order`.created_on <= :to_datetime""" + # else: + # sql_from_to_datetime = '' + + if limit := request.args.get('limit', default=None, type=int): + data['limit'] = limit + sql_limit = f"""LIMIT :limit""" + else: + sql_limit = '' + + sql = f""" + SELECT `order`.id AS 'order_id', `order`.id_random AS 'order_id_random' + FROM `order` AS `order` + WHERE {sql_account_person_user} + {sql_status} + /*{sql_from_to_datetime}*/ + ORDER BY `order`.created_on DESC, `order`.updated_on DESC + {sql_limit}; + """ + + if sql_result := sql_select(data=data, sql=sql, as_list=True): + resp_data_li = [] + for record in sql_result: + resp_data = base_name(**record).dict(by_alias=by_alias, exclude_unset=exclude_unset) + resp_data_li.append(resp_data) + + return mk_resp(data=resp_data_li) + else: + log.debug(sql_result) + return mk_resp(data=False, status_code=404) + @router.get('/{obj_id}', response_model=Resp_Body_Base) async def get_order_obj(