From e651ad589b238741c31f174a385063266cdc9d66 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Fri, 27 Mar 2026 02:28:27 +0800 Subject: [PATCH] feat(symbols): add DELETE API for removing custom symbol files - Add DELETE /v3/symbols/{symbol_id:path} endpoint - Prevent deletion of built-in symbols (:/ prefix or in resource directory) - Clear symbol size cache after deletion - Require Symbol.Allocate privilege --- gns3server/api/routes/controller/symbols.py | 45 ++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/gns3server/api/routes/controller/symbols.py b/gns3server/api/routes/controller/symbols.py index c6dee1315..9701c97ea 100644 --- a/gns3server/api/routes/controller/symbols.py +++ b/gns3server/api/routes/controller/symbols.py @@ -27,7 +27,8 @@ from typing import List from gns3server.controller import Controller from gns3server import schemas -from gns3server.controller.controller_error import ControllerError, ControllerNotFoundError +from gns3server.controller.controller_error import ControllerError, ControllerNotFoundError, ControllerForbiddenError +from gns3server.utils.get_resource import get_resource from .dependencies.rbac import has_privilege @@ -131,3 +132,45 @@ async def upload_symbol(symbol_id: str, request: Request) -> None: # Reset the symbol list controller.symbols.list() + + +@router.delete( + "/{symbol_id:path}", + status_code=status.HTTP_204_NO_CONTENT, + dependencies=[Depends(has_privilege("Symbol.Allocate"))] +) +async def delete_symbol(symbol_id: str) -> None: + """ + Delete a custom symbol file. + + Required privilege: Symbol.Allocate + """ + + controller = Controller.instance() + + # Cannot delete built-in symbols + if symbol_id.startswith(":/"): + raise ControllerForbiddenError("Cannot delete built-in symbols") + + try: + symbol_path = controller.symbols.get_path(symbol_id) + except (KeyError, ControllerNotFoundError) as e: + raise ControllerNotFoundError(f"Symbol '{symbol_id}' not found: {e}") + + # Check if it's a built-in symbol (in resource directory) + symbols_resource_dir = get_resource("symbols") + if symbols_resource_dir and os.path.commonprefix([symbols_resource_dir, symbol_path]) == symbols_resource_dir: + raise ControllerForbiddenError("Cannot delete built-in symbols") + + # Delete the file + try: + os.remove(symbol_path) + log.info(f"Deleted symbol file '{symbol_path}'") + except OSError as e: + raise ControllerError(f"Could not delete symbol file '{symbol_path}': {e}") + + # Clear the symbol size cache + controller.symbols._symbol_size_cache.pop(symbol_id, None) + + # Reset the symbol list + controller.symbols.list()