Initial commit: core-api service extraction from portainer-core
Build and Push / build (release) Successful in 43s
Build and Push / build (release) Successful in 43s
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
Static Files Controller
|
||||
|
||||
Serves static files for widgets and other frontend assets.
|
||||
"""
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import FileResponse, HTMLResponse
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
from src.controllers.base import BaseController
|
||||
from src.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class StaticController(BaseController):
|
||||
"""
|
||||
Controller for serving static files
|
||||
|
||||
Provides endpoints for:
|
||||
- Organizr widgets
|
||||
- Other static assets
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(prefix="/static", tags=["Static"])
|
||||
self.static_dir = Path(__file__).parent.parent.parent / "static"
|
||||
|
||||
def create_router(self) -> APIRouter:
|
||||
"""Create and configure the router"""
|
||||
router = APIRouter(prefix=self.prefix, tags=self.tags)
|
||||
|
||||
@router.get(
|
||||
"/widgets/{filename}",
|
||||
response_class=HTMLResponse,
|
||||
summary="Get widget file"
|
||||
)
|
||||
async def get_widget(filename: str):
|
||||
"""
|
||||
Serve widget HTML files
|
||||
|
||||
Args:
|
||||
filename: Widget filename (e.g., service-control.html)
|
||||
|
||||
Returns:
|
||||
HTML file content
|
||||
"""
|
||||
widget_path = self.static_dir / "widgets" / filename
|
||||
|
||||
if not widget_path.exists():
|
||||
return HTMLResponse(
|
||||
content=f"<h1>404 - Widget not found</h1><p>{filename}</p>",
|
||||
status_code=404
|
||||
)
|
||||
|
||||
if not widget_path.is_file():
|
||||
return HTMLResponse(
|
||||
content=f"<h1>400 - Not a file</h1>",
|
||||
status_code=400
|
||||
)
|
||||
|
||||
# Security: Ensure the path is within the static directory
|
||||
try:
|
||||
widget_path.resolve().relative_to(self.static_dir.resolve())
|
||||
except ValueError:
|
||||
return HTMLResponse(
|
||||
content=f"<h1>403 - Forbidden</h1>",
|
||||
status_code=403
|
||||
)
|
||||
|
||||
logger.info(f"Serving widget: {filename}")
|
||||
return FileResponse(
|
||||
widget_path,
|
||||
media_type="text/html",
|
||||
headers={
|
||||
"Cache-Control": "no-cache, no-store, must-revalidate",
|
||||
"Pragma": "no-cache",
|
||||
"Expires": "0"
|
||||
}
|
||||
)
|
||||
|
||||
@router.get(
|
||||
"/widgets",
|
||||
summary="List available widgets"
|
||||
)
|
||||
async def list_widgets():
|
||||
"""
|
||||
List all available widget files
|
||||
|
||||
Returns:
|
||||
List of widget filenames
|
||||
"""
|
||||
widgets_dir = self.static_dir / "widgets"
|
||||
|
||||
if not widgets_dir.exists():
|
||||
return {"widgets": [], "message": "Widgets directory not found"}
|
||||
|
||||
widgets = []
|
||||
for file in widgets_dir.glob("*.html"):
|
||||
widgets.append({
|
||||
"name": file.name,
|
||||
"url": f"/static/widgets/{file.name}",
|
||||
"size": file.stat().st_size
|
||||
})
|
||||
|
||||
return {
|
||||
"widgets": widgets,
|
||||
"count": len(widgets)
|
||||
}
|
||||
|
||||
return router
|
||||
|
||||
|
||||
# Create controller instance
|
||||
static_controller = StaticController()
|
||||
Reference in New Issue
Block a user