Files
OSIT-AE-API-FastAPI/app/routers/api_crud.py
Scott Idem 69622dbea6 refactor(core): modularize monolithic routers and methods
- 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.
2026-02-03 17:53:14 -05:00

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)