feat: allow admins to update audit checklist configuration
This commit is contained in:
@@ -26,6 +26,7 @@ import ipaddress
|
||||
import re
|
||||
import requests as http_requests
|
||||
from authenticator.radius_login import check_radius_login, check_radius_login_extended
|
||||
from config_upload import install_config_files, normalize_json, validate_xlsx
|
||||
|
||||
# Database imports
|
||||
import models
|
||||
@@ -2615,6 +2616,7 @@ async def admin_tools_page(request: Request, msg: str = None, msg_type: str = "s
|
||||
"request": request,
|
||||
"tools_list": get_available_tools(),
|
||||
"os_metadata": OS_METADATA,
|
||||
"os_config": OS_CONFIG,
|
||||
"message": message,
|
||||
"user": user,
|
||||
"user_info": user,
|
||||
@@ -2930,6 +2932,63 @@ async def admin_delete_tool(
|
||||
params = urlencode({"msg": f"Lỗi khi xóa: {str(e)}", "msg_type": "error"})
|
||||
return RedirectResponse(url=f"{request.url_for('admin_tools')}?{params}", status_code=303)
|
||||
|
||||
@app.post("/admin/checklists/upload", name="admin_checklists_upload")
|
||||
async def admin_upload_checklist_config(
|
||||
request: Request,
|
||||
os_type: str = Form(...),
|
||||
checklist_file: Optional[UploadFile] = File(None),
|
||||
config_file: Optional[UploadFile] = File(None),
|
||||
):
|
||||
"""Upload/replace the checklist XLSX and rule JSON for an OS. Admin only."""
|
||||
user = require_admin_session(request)
|
||||
if not user:
|
||||
return RedirectResponse(url=request.url_for('login'), status_code=303)
|
||||
|
||||
from urllib.parse import urlencode
|
||||
|
||||
os_info = OS_CONFIG.get(os_type)
|
||||
if not os_info:
|
||||
params = urlencode({"msg": "Hệ điều hành không hợp lệ", "msg_type": "error"})
|
||||
return RedirectResponse(url=f"{request.url_for('admin_tools')}?{params}", status_code=303)
|
||||
|
||||
has_checklist = bool(checklist_file and checklist_file.filename)
|
||||
has_config = bool(config_file and config_file.filename)
|
||||
if not has_checklist and not has_config:
|
||||
params = urlencode({"msg": "Cần chọn ít nhất một file checklist hoặc rule config", "msg_type": "error"})
|
||||
return RedirectResponse(url=f"{request.url_for('admin_tools')}?{params}", status_code=303)
|
||||
|
||||
pending_files = []
|
||||
try:
|
||||
if has_checklist:
|
||||
if not checklist_file.filename.lower().endswith('.xlsx'):
|
||||
raise ValueError("Checklist phải là file .xlsx")
|
||||
checklist_content = validate_xlsx(await checklist_file.read())
|
||||
pending_files.append((os_info['checklist'], checklist_content))
|
||||
|
||||
if has_config:
|
||||
if not config_file.filename.lower().endswith('.json'):
|
||||
raise ValueError("Rule config phải là file .json")
|
||||
normalized_config = normalize_json(await config_file.read())
|
||||
pending_files.append((os_info['config'], normalized_config))
|
||||
|
||||
install_config_files(CONFIG_FOLDER, pending_files)
|
||||
|
||||
print(Fore.GREEN + f"[ADMIN] Checklist/config updated for {os_type} by {user.get('username')}" + Fore.RESET)
|
||||
changed = ', '.join(name for name, _ in pending_files)
|
||||
params = urlencode({"msg": f"Đã cập nhật: {changed}", "msg_type": "success"})
|
||||
except (ValueError, UnicodeDecodeError, json.JSONDecodeError) as exc:
|
||||
for target_name, _ in pending_files:
|
||||
temp_path = os.path.join(CONFIG_FOLDER, target_name) + '.tmp'
|
||||
if os.path.exists(temp_path):
|
||||
os.remove(temp_path)
|
||||
params = urlencode({"msg": str(exc), "msg_type": "error"})
|
||||
except Exception as exc:
|
||||
print(Fore.RED + f"[ADMIN] Checklist/config upload error: {exc}" + Fore.RESET)
|
||||
params = urlencode({"msg": f"Lỗi cập nhật checklist/config: {exc}", "msg_type": "error"})
|
||||
|
||||
return RedirectResponse(url=f"{request.url_for('admin_tools')}?{params}", status_code=303)
|
||||
|
||||
|
||||
@app.post("/admin/docs/upload", name="admin_docs_upload")
|
||||
async def admin_upload_doc(
|
||||
request: Request,
|
||||
|
||||
Reference in New Issue
Block a user