import json
|
from flask import Flask, request, jsonify
|
from database import DatabaseConfig, init_database
|
from dao import ContentTypeDAO, ContentDAO
|
import logging
|
from datetime import datetime
|
from flask_cors import CORS
|
|
# 设置日志记录
|
logging.basicConfig(level=logging.INFO)
|
logger = logging.getLogger(__name__)
|
|
# 加载配置
|
with open("config.json") as f:
|
config = json.load(f)
|
|
app = Flask(__name__)
|
CORS(app)
|
|
# 初始化数据库
|
db_config = DatabaseConfig()
|
init_database() # 初始化数据库和表(如果不存在)
|
|
|
# 新的API端点:ContentType相关
|
@app.route("/api/v1/type/save", methods=["POST"])
|
def save_contenttype():
|
"""保存ContentType的API端点"""
|
connection = None
|
try:
|
# 从请求中获取JSON数据
|
data = request.get_json()
|
|
if not data:
|
return jsonify({"error": "未提供数据"}), 400
|
|
# 检查是否是单个对象还是列表
|
if isinstance(data, list):
|
# 处理多个记录 - 使用单个连接和事务
|
connection = db_config.get_connection()
|
if not connection:
|
return jsonify({"error": "数据库连接失败"}), 500
|
|
results = []
|
errors = []
|
try:
|
for i, item in enumerate(data):
|
# 为每个项目创建一个包含数据库连接的配置
|
class TempDbConfig:
|
def get_connection(self):
|
return connection
|
|
result, error = ContentTypeDAO.save_contenttype(
|
item, TempDbConfig()
|
)
|
if error:
|
errors.append({"index": i, "error": error, "data": item})
|
else:
|
results.append(result)
|
|
connection.commit() # 提交所有更改
|
|
response_data = {
|
"saved": results,
|
"errors": errors,
|
"total_saved": len(results),
|
}
|
if errors:
|
# 如果有错误,返回400状态码
|
status_code = (
|
400
|
if any(
|
err["error"] in ["代码已存在", "代码和名称是必需的"]
|
for err in errors
|
)
|
else 500
|
)
|
return jsonify(response_data), status_code
|
else:
|
# 如果没有错误,检查是否有更新的记录
|
has_updates = any("更新" in r["message"] for r in results)
|
return jsonify(response_data), 200 if has_updates else 201
|
except Exception as e:
|
if connection:
|
connection.rollback()
|
logger.error(f"批量保存ContentType时出错: {e}")
|
return jsonify({"error": "批量保存操作失败"}), 500
|
finally:
|
if connection:
|
connection.close()
|
else:
|
# 处理单个记录
|
result, error = ContentTypeDAO.save_contenttype(data, db_config)
|
|
if error:
|
if error == "代码已存在" or error == "代码和名称是必需的":
|
return jsonify({"error": error}), 400
|
else:
|
return jsonify({"error": error}), 500
|
|
return jsonify(result), 200 if "更新" in result["message"] else 201
|
|
except Exception as e:
|
if connection:
|
try:
|
connection.rollback()
|
connection.close()
|
except Exception as close_error:
|
logger.error(f"关闭连接时出错: {close_error}")
|
logger.error(f"save_contenttype中的意外错误: {e}")
|
return jsonify({"error": "无效的请求格式"}), 400
|
|
|
@app.route("/api/v1/type/get", methods=["GET"])
|
def get_contenttype():
|
"""从数据库检索ContentType的API端点"""
|
try:
|
# 获取查询参数
|
code = request.args.get("code", "").strip()
|
record_id = request.args.get("id")
|
limit = request.args.get("limit", type=int)
|
|
# 验证参数
|
if record_id and not record_id.isdigit():
|
return jsonify({"error": "无效的ID参数"}), 400
|
|
if limit and limit <= 0:
|
return jsonify({"error": "限制必须是正整数"}), 400
|
|
# 使用DAO进行数据库操作
|
result, error = ContentTypeDAO.get_contenttype(
|
contenttype=record_id, code=code, limit=limit, db_config=db_config
|
)
|
|
if error:
|
return jsonify({"error": error}), 500
|
|
result["timestamp"] = datetime.now().isoformat()
|
return jsonify(result), 200
|
|
except Exception as e:
|
logger.error(f"get_contenttype中的意外错误: {e}")
|
return jsonify({"error": "无效的请求参数"}), 400
|
|
|
# 新的API端点:Content相关
|
@app.route("/api/v1/content/save", methods=["POST"])
|
def save_content():
|
"""保存Content的API端点"""
|
connection = None
|
try:
|
# 从请求中获取JSON数据
|
data = request.get_json()
|
|
if not data:
|
return jsonify({"error": "未提供数据"}), 400
|
|
# 检查是否是单个对象还是列表
|
if isinstance(data, list):
|
# 处理多个记录 - 使用单个连接和事务
|
connection = db_config.get_connection()
|
if not connection:
|
return jsonify({"error": "数据库连接失败"}), 500
|
|
results = []
|
errors = []
|
try:
|
for i, item in enumerate(data):
|
# 为每个项目创建一个包含数据库连接的配置
|
class TempDbConfig:
|
def get_connection(self):
|
return connection
|
|
result, error = ContentDAO.save_content(item, TempDbConfig())
|
if error:
|
errors.append({"index": i, "error": error, "data": item})
|
else:
|
results.append(result)
|
|
connection.commit() # 提交所有更改
|
|
response_data = {
|
"saved": results,
|
"errors": errors,
|
"total_saved": len(results),
|
}
|
if errors:
|
# 如果有错误,返回400状态码
|
status_code = (
|
400
|
if any(
|
err["error"]
|
in ["类型、问题和答案是必需的", "指定的类型ID不存在"]
|
for err in errors
|
)
|
else 500
|
)
|
return jsonify(response_data), status_code
|
else:
|
return jsonify(response_data), 201
|
except Exception as e:
|
if connection:
|
connection.rollback()
|
logger.error(f"批量保存Content时出错: {e}")
|
return jsonify({"error": "批量保存操作失败"}), 500
|
finally:
|
if connection:
|
connection.close()
|
else:
|
# 处理单个记录
|
result, error = ContentDAO.save_content(data, db_config)
|
|
if error:
|
if error in ["类型、问题和答案是必需的", "指定的类型ID不存在"]:
|
return jsonify({"error": error}), 400
|
else:
|
return jsonify({"error": error}), 500
|
|
return jsonify(result), 201 if "更新" not in result["message"] else 200
|
|
except Exception as e:
|
if connection:
|
try:
|
connection.rollback()
|
connection.close()
|
except Exception as close_error:
|
logger.error(f"关闭连接时出错: {close_error}")
|
logger.error(f"save_content中的意外错误: {e}")
|
return jsonify({"error": "无效的请求格式"}), 400
|
|
|
@app.route("/api/v1/content/get", methods=["GET"])
|
def get_content():
|
"""从数据库检索Content的API端点"""
|
try:
|
# 获取查询参数
|
content_type = request.args.get("type", type=int)
|
record_id = request.args.get("id", type=int)
|
limit = request.args.get("limit", type=int)
|
|
# 验证参数
|
if record_id and record_id <= 0:
|
return jsonify({"error": "无效的ID参数"}), 400
|
|
if limit and limit <= 0:
|
return jsonify({"error": "限制必须是正整数"}), 400
|
|
# 使用DAO进行数据库操作
|
result, error = ContentDAO.get_content(
|
content_id=record_id,
|
content_type=content_type,
|
limit=limit,
|
db_config=db_config,
|
)
|
|
if error:
|
return jsonify({"error": error}), 500
|
|
result["timestamp"] = datetime.now().isoformat()
|
return jsonify(result), 200
|
|
except Exception as e:
|
logger.error(f"get_content中的意外错误: {e}")
|
return jsonify({"error": "无效的请求参数"}), 400
|
|
|
@app.route("/api/v1/content/delete", methods=["DELETE"])
|
def delete_content():
|
"""根据ID删除Content的API端点"""
|
try:
|
# 从请求中获取JSON数据
|
data = request.get_json()
|
if not data:
|
# 也可以从URL参数获取ID
|
content_id = request.args.get("id", type=int)
|
if content_id is None:
|
return jsonify({"error": "未提供数据或ID参数"}), 400
|
else:
|
# 从JSON数据中获取ID
|
content_id = data.get("id")
|
if content_id is None or not isinstance(content_id, int) or content_id <= 0:
|
return jsonify({"error": "ID是必需的,且必须是正整数"}), 400
|
|
# 使用DAO进行删除操作
|
result, error = ContentDAO.delete_content(content_id, db_config)
|
|
if error:
|
if error == "指定的ID不存在":
|
return jsonify({"error": error}), 404
|
else:
|
return jsonify({"error": error}), 500
|
|
return jsonify(result), 200
|
except Exception as e:
|
logger.error(f"delete_content中的意外错误: {e}")
|
return jsonify({"error": "无效的请求格式"}), 400
|
|
|
# 健康检查端点
|
@app.route("/health", methods=["GET"])
|
def health_check():
|
"""健康检查端点,验证服务是否正在运行"""
|
return (
|
jsonify(
|
{
|
"status": "OK",
|
"message": "服务正在运行",
|
"timestamp": datetime.now().isoformat(),
|
}
|
),
|
200,
|
)
|
|
|
if __name__ == "__main__":
|
# 获取服务器配置
|
server_config = config["server"]
|
logger.info(f"在 {server_config['host']}:{server_config['port']} 上启动服务器")
|
app.run(
|
host=server_config["host"],
|
port=server_config["port"],
|
debug=server_config["debug"],
|
)
|