diff --git a/app/routers/api_v3_actions_event_file.py b/app/routers/api_v3_actions_event_file.py index 3359071..f3eac0b 100644 --- a/app/routers/api_v3_actions_event_file.py +++ b/app/routers/api_v3_actions_event_file.py @@ -14,7 +14,7 @@ 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, handle_delete_hosted_file + create_hosted_file_link, delete_hosted_file_link, get_hosted_file_link_rec_list ) from app.methods.event_file_methods import create_event_file_obj, load_event_file_obj from app.lib_general_v3 import ( @@ -296,26 +296,63 @@ async def delete_event_file_action( if not ef_id_int: raise HTTPException(status_code=404, detail="Event file not found.") - ef_rec = sql_select(sql="SELECT hosted_file_id FROM event_file WHERE id = :id", data={'id': ef_id_int}) + # Fetch hosted_file_id + the parent the link was originally created against. + # hosted_file_link uses for_type/for_id as link target, NOT 'event_file'. + ef_rec = sql_select( + sql="SELECT hosted_file_id, for_type, for_id FROM event_file WHERE id = :id", + data={'id': ef_id_int} + ) hf_id_int = ef_rec.get('hosted_file_id') if ef_rec else None + for_type = ef_rec.get('for_type') if ef_rec else None + for_id_int = ef_rec.get('for_id') if ef_rec else None link_cleaned = False - if hf_id_int: - link_cleaned = handle_delete_hosted_file( - account_id=account.account_id, - hosted_file_id=hf_id_int, - link_to_type='event_file', - link_to_id=ef_id_int, - rm_orphan=rm_orphan, - ) - if not link_cleaned: - log.warning(f"handle_delete_hosted_file returned False for hosted_file {hf_id_int} / event_file {ef_id_int}") + orphan_cleaned = False + if hf_id_int: + # Step 1: Remove the hosted_file_link using the correct parent type/id. + # A missing link (old orphan from pre-fix period) is non-fatal — log and continue. + if for_type and for_id_int: + link_result = delete_hosted_file_link( + account_id=account.account_id, + hosted_file_id=hf_id_int, + link_to_type=for_type, + link_to_id=for_id_int, + ) + if link_result: + link_cleaned = True + else: + log.warning(f"hosted_file_link not found (already removed or never created): hosted_file={hf_id_int} {for_type}:{for_id_int}") + + # Step 2: Orphan check — clean up physical file + hosted_file record if no links remain. + if rm_orphan: + remaining = get_hosted_file_link_rec_list(hosted_file_id=hf_id_int) + if not remaining: + hf_obj = load_hosted_file_obj(hosted_file_id=hf_id_int) + if hf_obj: + file_path = os.path.join( + settings.FILES_PATH['hosted_files_root'], + hf_obj.subdirectory_path or '', + f'{hf_obj.hash_sha256}.file' + ) + if os.path.exists(file_path): + try: + pathlib.Path(file_path).unlink() + log.info(f"Deleted physical file: {file_path}") + except OSError as e: + log.error(f"Failed to delete physical file {file_path}: {e}") + else: + log.warning(f"Physical file already absent from disk: {file_path}") + sql_delete(table_name='hosted_file', record_id=hf_id_int) + orphan_cleaned = True + + # Step 3: Always remove the event_file row. sql_delete(table_name='event_file', record_id=ef_id_int) return mk_resp(data={ 'event_file_deleted': True, - 'hosted_file_link_cleaned': bool(link_cleaned), + 'hosted_file_link_cleaned': link_cleaned, + 'orphan_cleaned': orphan_cleaned, })