feat: validate .tsd on upload, auto-extract manifest metadata
This commit is contained in:
+34
-4
@@ -543,17 +543,47 @@ async def api_market_register(data: dict):
|
|||||||
|
|
||||||
@router.post("/market/upload")
|
@router.post("/market/upload")
|
||||||
async def api_market_upload(file: UploadFile = File(...), name: str = "", category: str = "", author: str = "", token: str = ""):
|
async def api_market_upload(file: UploadFile = File(...), name: str = "", category: str = "", author: str = "", token: str = ""):
|
||||||
import httpx
|
import httpx, io, zipfile, json as _json
|
||||||
|
|
||||||
|
# Validate .tsd
|
||||||
|
if not file.filename or not file.filename.endswith('.tsd'):
|
||||||
|
return {"error": "仅支持 .tsd 文件"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
zip_data = await file.read()
|
||||||
|
with zipfile.ZipFile(io.BytesIO(zip_data), 'r') as zf:
|
||||||
|
names = zf.namelist()
|
||||||
|
if 'manifest.json' not in names:
|
||||||
|
return {"error": "无效的仪表盘文件:缺少 manifest.json"}
|
||||||
|
if 'index.html' not in names:
|
||||||
|
return {"error": "无效的仪表盘文件:缺少 index.html"}
|
||||||
|
|
||||||
|
manifest = _json.loads(zf.read('manifest.json').decode('utf-8'))
|
||||||
|
actual_name = name or manifest.get('name', file.filename.replace('.tsd', ''))
|
||||||
|
actual_category = category or manifest.get('category', 'community')
|
||||||
|
actual_author = author or manifest.get('author', 'Unknown')
|
||||||
|
actual_version = manifest.get('version', '1.0.0')
|
||||||
|
supported = manifest.get('supported_games', 'all')
|
||||||
|
icon = manifest.get('config', {}).get('icon', '📦')
|
||||||
|
desc = manifest.get('description', '')
|
||||||
|
except zipfile.BadZipFile:
|
||||||
|
return {"error": "无效的 zip 文件"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"文件解析失败: {str(e)}"}
|
||||||
|
|
||||||
cfg = get_config()
|
cfg = get_config()
|
||||||
url = cfg.get("market_url", "http://127.0.0.1:5301")
|
url = cfg.get("market_url", "http://127.0.0.1:5301")
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=30) as client:
|
async with httpx.AsyncClient(timeout=30) as client:
|
||||||
files_httpx = {"file": (file.filename, await file.read(), file.content_type)}
|
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
f"{url}/api/collections/dashboards/records",
|
f"{url}/api/collections/dashboards/records",
|
||||||
headers={"Authorization": f"Bearer {token}"},
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
data={"name": name, "category": category, "author": author, "version": "1.0.0", "dashb_pending": true},
|
data={
|
||||||
files=files_httpx,
|
"name": actual_name, "category": actual_category, "author": actual_author,
|
||||||
|
"version": actual_version, "supported_games": supported,
|
||||||
|
"icon": icon, "description": desc, "dashb_pending": True,
|
||||||
|
},
|
||||||
|
files={"file": (file.filename, zip_data, file.content_type)},
|
||||||
)
|
)
|
||||||
return resp.json()
|
return resp.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user