feat(routers): migrate hosted_file hash lookup to V3 actions
Ported the legacy '/hosted_file/hash/{hash}' endpoint to the V3 actions router.
The new endpoint '/v3/action/hosted_file/hash/{hosted_file_hash}' supports:
- ID Vision: returns random string IDs instead of internal integers
- Local Check: verifies physical file existence on disk (check_for_local=True)
- Deduplication: enables frontend to check for existing files before upload
Also added PROJECT document for AE Hosted Files migration tracking.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,8 @@ from app.config import settings
|
||||
from app.db_sql import redis_lookup_id_random, sql_select, sql_update, sql_delete, get_id_random
|
||||
from app.methods.hosted_file_methods import (
|
||||
create_hosted_file_obj, load_hosted_file_obj, save_file,
|
||||
create_hosted_file_link, delete_hosted_file_link, get_hosted_file_link_rec_list
|
||||
create_hosted_file_link, delete_hosted_file_link, get_hosted_file_link_rec_list,
|
||||
lookup_file_hash, check_for_hosted_file_hash_file
|
||||
)
|
||||
from app.methods.lib_media import convert_file_method
|
||||
from app.methods.lib_media import clip_video_method
|
||||
@@ -354,6 +355,38 @@ async def download_file_by_hash_action(
|
||||
return FileResponse(full_file_path, filename=target_filename, media_type=media_type)
|
||||
|
||||
|
||||
@router.get('/hash/{hosted_file_hash}', response_model=Resp_Body_Base)
|
||||
async def check_hosted_file_obj_w_hash_action(
|
||||
response: Response,
|
||||
hosted_file_hash: str = Path(min_length=64, max_length=64),
|
||||
check_for_local: Optional[bool] = Query(True),
|
||||
account: AccountContext = Depends(get_account_context_optional),
|
||||
delay: DelayParams = Depends(),
|
||||
):
|
||||
"""
|
||||
Look up a hosted_file record by its hash (Deduplication Check).
|
||||
Optionally verifies physical file existence on disk.
|
||||
"""
|
||||
if delay.sleep_time_s > 0: await asyncio.sleep(delay.sleep_time_s)
|
||||
|
||||
if hfid := lookup_file_hash(file_hash=hosted_file_hash):
|
||||
obj_model = load_hosted_file_obj(hosted_file_id=hfid, model_as_dict=False)
|
||||
if not obj_model:
|
||||
return mk_resp(data=False, status_code=404, response=response, status_message="Record found but data could not be loaded.")
|
||||
|
||||
if check_for_local:
|
||||
# We use the model directly to access subdirectory_path even if it's excluded from dicts
|
||||
sub_dir = getattr(obj_model, 'subdirectory_path', '') or ''
|
||||
if check := check_for_hosted_file_hash_file(file_hash=hosted_file_hash, sub_dir=sub_dir):
|
||||
obj_model.hosted_file_found_check = True
|
||||
obj_model.hosted_file_size_check = check['file_size']
|
||||
|
||||
# mk_resp will handle model->dict conversion with proper ID Vision mapping
|
||||
return mk_resp(data=obj_model)
|
||||
|
||||
return mk_resp(data=False, status_code=404, response=response, status_message="No record found for this hash.")
|
||||
|
||||
|
||||
@router.delete('/{hosted_file_id}', response_model=Resp_Body_Base)
|
||||
async def delete_file_action(
|
||||
hosted_file_id: str = Path(min_length=11, max_length=22),
|
||||
|
||||
Reference in New Issue
Block a user