diff --git a/admin/dashboard/blueprints/fun_command_rules.py b/admin/dashboard/blueprints/fun_command_rules.py index 9cfa0be..5170884 100644 --- a/admin/dashboard/blueprints/fun_command_rules.py +++ b/admin/dashboard/blueprints/fun_command_rules.py @@ -81,12 +81,11 @@ def _validate_payload(payload: Dict[str, Any], service) -> str: return "" -def _allowed_file(filename: str, media_type: str) -> bool: - """判断上传文件扩展名是否允许。""" - if "." not in filename: - return False - ext = filename.rsplit(".", 1)[1].lower() - return ext in ALLOWED_EXTENSIONS.get(media_type, set()) +def _extract_file_ext(filename: str) -> str: + """从原始文件名提取扩展名(小写,不含点)。""" + if "." not in str(filename or ""): + return "" + return str(filename).rsplit(".", 1)[1].lower().strip() @fun_command_rules_bp.route("/") @@ -115,9 +114,19 @@ def api_upload_media(): if not upload_file or not upload_file.filename: return jsonify({"success": False, "message": "文件名为空"}), 400 - filename = secure_filename(upload_file.filename) - if not _allowed_file(filename, media_type): - return jsonify({"success": False, "message": f"不支持的文件类型: {filename}"}), 400 + # 注意:secure_filename 对中文文件名会清洗成 “wav” 这类无点字符串, + # 若直接基于清洗后文件名做扩展名校验会误判。这里改为优先使用原始文件名提取扩展名。 + raw_filename = str(upload_file.filename or "").strip() + file_ext = _extract_file_ext(raw_filename) + if file_ext not in ALLOWED_EXTENSIONS.get(media_type, set()): + return jsonify({"success": False, "message": f"不支持的文件类型: {raw_filename}"}), 400 + + # 生成安全文件名:basename 走 secure_filename,扩展名使用原始提取值兜底。 + raw_basename = raw_filename.rsplit(".", 1)[0] if "." in raw_filename else raw_filename + safe_basename = secure_filename(raw_basename).strip() + if not safe_basename: + safe_basename = "upload_file" + filename = f"{safe_basename}.{file_ext}" # 按媒体类型分目录,便于后续清理和排查。 upload_root = os.path.join(current_app.root_path, "static", "uploads", "fun_command_rules", media_type)