mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
feat: Add detailed metadata to node files listing
Enhance the node files API to include comprehensive file metadata: - File size in bytes - File creation time (ISO 8601 format) - File modification time (ISO 8601 format) - File extension Create new NodeFile schema to support these additional fields while keeping the existing ProjectFile schema for backward compatibility. This provides users with better information to manage and identify files in the Web UI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5b75d633aa
commit
51a4c73e21
@ -192,14 +192,14 @@ async def get_compute_project_files(project: Project = Depends(dep_project)) ->
|
||||
return await project.list_files()
|
||||
|
||||
|
||||
@router.get("/projects/{project_id}/nodes/{node_type}/{node_id}/files", response_model=List[schemas.ProjectFile])
|
||||
@router.get("/projects/{project_id}/nodes/{node_type}/{node_id}/files", response_model=List[schemas.NodeFile])
|
||||
async def get_compute_node_files(
|
||||
node_type: str,
|
||||
node_id: str,
|
||||
project: Project = Depends(dep_project)
|
||||
) -> List[schemas.ProjectFile]:
|
||||
) -> List[schemas.NodeFile]:
|
||||
"""
|
||||
Return files belonging to a specific node.
|
||||
Return files belonging to a specific node with detailed metadata.
|
||||
"""
|
||||
|
||||
node_path = f"project-files/{node_type}/{node_id}"
|
||||
|
||||
@ -522,10 +522,10 @@ async def delete_disk_image(
|
||||
await node.delete(f"/disk_image/{disk_name}")
|
||||
|
||||
|
||||
@router.get("/{node_id}/files", response_model=List[schemas.ProjectFile], dependencies=[Depends(has_privilege("Node.Audit"))])
|
||||
async def list_node_files(node: Node = Depends(dep_node)) -> List[schemas.ProjectFile]:
|
||||
@router.get("/{node_id}/files", response_model=List[schemas.NodeFile], dependencies=[Depends(has_privilege("Node.Audit"))])
|
||||
async def list_node_files(node: Node = Depends(dep_node)) -> List[schemas.NodeFile]:
|
||||
"""
|
||||
List files in a node directory.
|
||||
List files in a node directory with detailed metadata.
|
||||
|
||||
Required privilege: Node.Audit
|
||||
"""
|
||||
|
||||
@ -18,6 +18,7 @@ import os
|
||||
import shutil
|
||||
import asyncio
|
||||
import hashlib
|
||||
import datetime
|
||||
|
||||
from uuid import UUID, uuid4
|
||||
from fastapi import HTTPException
|
||||
@ -420,10 +421,10 @@ class Project:
|
||||
|
||||
async def list_node_files(self, node_path: str):
|
||||
"""
|
||||
List files in a specific node directory.
|
||||
List files in a specific node directory with detailed metadata.
|
||||
|
||||
:param node_path: Relative path to node directory (e.g., "project-files/qemu/node-id")
|
||||
:returns: Array of files in the node directory
|
||||
:returns: Array of files in the node directory with metadata
|
||||
"""
|
||||
|
||||
node_full_path = os.path.normpath(os.path.join(self.path, node_path))
|
||||
@ -442,14 +443,37 @@ class Project:
|
||||
for filename in os.listdir(node_full_path):
|
||||
file_path = os.path.join(node_full_path, filename)
|
||||
if os.path.isfile(file_path) and not filename.endswith(".ghost"):
|
||||
file_info = {"path": filename}
|
||||
try:
|
||||
file_info["md5sum"] = await wait_run_in_executor(
|
||||
self._hash_file, file_path
|
||||
# Get file stat information
|
||||
stat_info = await wait_run_in_executor(os.stat, file_path)
|
||||
|
||||
# Get file extension
|
||||
_, extension = os.path.splitext(filename)
|
||||
extension = extension.lstrip('.')
|
||||
|
||||
# Format timestamps as ISO 8601
|
||||
created_at = await wait_run_in_executor(
|
||||
lambda: datetime.datetime.fromtimestamp(stat_info.st_ctime).isoformat()
|
||||
)
|
||||
except OSError:
|
||||
modified_at = await wait_run_in_executor(
|
||||
lambda: datetime.datetime.fromtimestamp(stat_info.st_mtime).isoformat()
|
||||
)
|
||||
|
||||
# Get MD5 checksum
|
||||
md5sum = await wait_run_in_executor(self._hash_file, file_path)
|
||||
|
||||
file_info = {
|
||||
"path": filename,
|
||||
"md5sum": md5sum,
|
||||
"size": stat_info.st_size,
|
||||
"created_at": created_at,
|
||||
"modified_at": modified_at,
|
||||
"extension": extension
|
||||
}
|
||||
files.append(file_info)
|
||||
except OSError as e:
|
||||
log.warning(f"Error getting metadata for file '{filename}': {e}")
|
||||
continue
|
||||
files.append(file_info)
|
||||
except OSError as e:
|
||||
log.error(f"Error listing node files: {e}")
|
||||
|
||||
|
||||
@ -105,6 +105,19 @@ class ProjectFile(BaseModel):
|
||||
md5sum: str = Field(..., description="File checksum")
|
||||
|
||||
|
||||
class NodeFile(BaseModel):
|
||||
"""
|
||||
Detailed file information for node files.
|
||||
"""
|
||||
|
||||
path: str = Field(..., description="File name")
|
||||
md5sum: str = Field(..., description="File checksum")
|
||||
size: int = Field(..., description="File size in bytes")
|
||||
created_at: str = Field(..., description="File creation time (ISO 8601)")
|
||||
modified_at: str = Field(..., description="File modification time (ISO 8601)")
|
||||
extension: str = Field(..., description="File extension")
|
||||
|
||||
|
||||
class ProjectCompression(str, Enum):
|
||||
"""
|
||||
Supported project compression.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user