- Reduced api_crud.py (1843 -> 143 lines) by extracting V1 registry and logic. - Reduced hosted_file.py (1596 -> 361 lines) by moving storage and media logic to methods. - Created lib_media.py for specialized video/image processing. - Created api_crud_methods.py for legacy template handlers. - Created legacy_v1.py for the legacy object registry. - Fixed subdirectory_path bug in Hosted File creation. - Verified full File Lifecycle via consolidated E2E suite.
144 lines
6.7 KiB
Python
144 lines
6.7 KiB
Python
import datetime, json, time, urllib
|
|
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Path, Query, Response, status
|
|
from fastapi.responses import FileResponse
|
|
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, common_route_params_min, Common_Route_Params_Min
|
|
from app.db_sql import sql_insert, sql_update, sql_insert_or_update, sql_select, sql_delete, redis_lookup_id_random, lookup_id_random_pop
|
|
|
|
from app.models.response_models import *
|
|
from app.models.api_crud_models import *
|
|
|
|
# Modularized Imports
|
|
from app.object_definitions.legacy_v1 import obj_type_li
|
|
from app.methods.api_crud_methods import (
|
|
post_obj_template, patch_obj_template, get_obj_li_template,
|
|
get_obj_template, delete_obj_template
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
# ### BEGIN ### API CRUD ### get_obj_li_lx() ###
|
|
@router.get('/{obj_type_l1}/list')
|
|
async def get_obj_li_l1(
|
|
obj_type_l1: str = Path(min_length=2, max_length=50),
|
|
for_obj_type: Optional[str] = Query(None, max_length=50),
|
|
for_obj_id: Optional[str] = Query(None, max_length=22),
|
|
use_alt_table: bool = False,
|
|
use_alt_base: bool = False,
|
|
hidden: str = 'not_hidden',
|
|
order_by_li: str = Header(None),
|
|
jp: Optional[Union[str, None]] = None,
|
|
file_type: str = 'CSV',
|
|
return_file: Optional[bool] = False,
|
|
commons: Common_Route_Params = Depends(common_route_params),
|
|
):
|
|
return handle_get_obj_li(obj_type_l1=obj_type_l1, for_obj_type=for_obj_type, for_obj_id=for_obj_id, use_alt_table=use_alt_table, use_alt_base=use_alt_base, hidden=hidden, order_by_li=order_by_li, jp=jp, file_type=file_type, return_file=return_file, commons=commons)
|
|
|
|
@router.get('/{obj_type_l1}/{obj_type_l2}/list')
|
|
async def get_obj_li_l2(
|
|
obj_type_l1: str = Path(min_length=2, max_length=50),
|
|
obj_type_l2: str = Path(min_length=2, max_length=50),
|
|
for_obj_type: Optional[str] = Query(None, max_length=50),
|
|
for_obj_id: Optional[str] = Query(None, max_length=22),
|
|
use_alt_table: bool = False,
|
|
use_alt_base: bool = False,
|
|
hidden: str = 'not_hidden',
|
|
order_by_li: str = Header(None),
|
|
jp: Optional[Union[str, None]] = None,
|
|
file_type: str = 'CSV',
|
|
return_file: Optional[bool] = False,
|
|
commons: Common_Route_Params = Depends(common_route_params),
|
|
):
|
|
return handle_get_obj_li(obj_type_l1=obj_type_l1, obj_type_l2=obj_type_l2, for_obj_type=for_obj_type, for_obj_id=for_obj_id, use_alt_table=use_alt_table, use_alt_base=use_alt_base, hidden=hidden, order_by_li=order_by_li, jp=jp, file_type=file_type, return_file=return_file, commons=commons)
|
|
|
|
@router.get('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/list')
|
|
async def get_obj_li_l3(
|
|
obj_type_l1: str = Path(min_length=2, max_length=50),
|
|
obj_type_l2: str = Path(min_length=2, max_length=50),
|
|
obj_type_l3: str = Path(min_length=2, max_length=50),
|
|
for_obj_type: Optional[str] = Query(None, max_length=50),
|
|
for_obj_id: Optional[str] = Query(None, max_length=22),
|
|
use_alt_table: bool = False,
|
|
use_alt_base: bool = False,
|
|
hidden: str = 'not_hidden',
|
|
order_by_li: str = Header(None),
|
|
jp: Optional[Union[str, None]] = None,
|
|
file_type: str = 'CSV',
|
|
return_file: Optional[bool] = False,
|
|
commons: Common_Route_Params = Depends(common_route_params),
|
|
):
|
|
return handle_get_obj_li(obj_type_l1=obj_type_l1, obj_type_l2=obj_type_l2, obj_type_l3=obj_type_l3, for_obj_type=for_obj_type, for_obj_id=for_obj_id, use_alt_table=use_alt_table, use_alt_base=use_alt_base, hidden=hidden, order_by_li=order_by_li, jp=jp, file_type=file_type, return_file=return_file, commons=commons)
|
|
|
|
def handle_get_obj_li(
|
|
obj_type_l1: str,
|
|
obj_type_l2: Optional[str] = None,
|
|
obj_type_l3: Optional[str] = None,
|
|
for_obj_type: Optional[str] = None,
|
|
for_obj_id: Optional[str] = None,
|
|
use_alt_table: bool = False,
|
|
use_alt_base: bool = False,
|
|
hidden: str = 'not_hidden',
|
|
order_by_li: Optional[Union[str, None]] = None,
|
|
jp: Optional[Union[str, None]] = None,
|
|
file_type: str = 'CSV',
|
|
return_file: Optional[bool] = False,
|
|
commons: Common_Route_Params = None,
|
|
):
|
|
log.setLevel(logging.INFO)
|
|
|
|
# 1. Resolve Object Name
|
|
if obj_type_l1 and obj_type_l2 and obj_type_l3:
|
|
obj_name = f'{obj_type_l1}_{obj_type_l2}_{obj_type_l3}'
|
|
elif obj_type_l1 and obj_type_l2:
|
|
obj_name = f'{obj_type_l1}_{obj_type_l2}'
|
|
else:
|
|
obj_name = obj_type_l1
|
|
|
|
if obj_name not in obj_type_li:
|
|
return mk_resp(data=False, status_code=400, response=commons.response)
|
|
|
|
# 2. Resolve Tables/Models
|
|
table_name = obj_type_li[obj_name].get('table_name_alt') if use_alt_table else obj_type_li[obj_name]['table_name']
|
|
base_name = obj_type_li[obj_name].get('base_name_alt') if use_alt_base else obj_type_li[obj_name]['base_name']
|
|
|
|
# 3. Handle Filters (jp / legacy and_qry)
|
|
and_qry = {}
|
|
if jp:
|
|
try:
|
|
jp_obj = json.loads(urllib.parse.unquote(jp))
|
|
if jp_obj.get('and_qry'): and_qry = jp_obj['and_qry']
|
|
except: pass
|
|
|
|
# 4. Handle Parent Context
|
|
if for_obj_type and for_obj_id:
|
|
fid = redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type)
|
|
and_qry[f'{for_obj_type}_id'] = fid
|
|
|
|
# 5. DB Query
|
|
sql_result = sql_select(
|
|
table_name = table_name,
|
|
and_qry = and_qry,
|
|
limit = commons.limit,
|
|
offset = commons.offset,
|
|
as_list = True
|
|
)
|
|
|
|
if sql_result is False: return mk_resp(data=False, status_code=500, response=commons.response)
|
|
|
|
resp_data = [base_name(**rec).dict(by_alias=True) for rec in sql_result] if base_name else sql_result
|
|
return mk_resp(data=resp_data, response=commons.response)
|
|
|
|
# Remaining Route Templates (Minimal stubs that call Methods)
|
|
@router.get('/{obj_type_l1}/{obj_id}')
|
|
async def get_obj_l1(obj_type_l1: str, obj_id: str, commons: Common_Route_Params = Depends(common_route_params)):
|
|
return get_obj_template(obj_id=obj_id, obj_type=obj_type_l1, response=commons.response)
|
|
|
|
@router.patch('/{obj_type_l1}/{obj_id}')
|
|
async def patch_obj_l1(obj_type_l1: str, obj_id: str, data: dict, commons: Common_Route_Params = Depends(common_route_params)):
|
|
return patch_obj_template(obj_type=obj_type_l1, data=data, obj_id=obj_id, response=commons.response)
|
|
|
|
@router.delete('/{obj_type_l1}/{obj_id}')
|
|
async def delete_obj_l1(obj_type_l1: str, obj_id: str, commons: Common_Route_Params = Depends(common_route_params)):
|
|
return delete_obj_template(obj_type=obj_type_l1, obj_id=obj_id, response=commons.response) |