from flask import jsonify, request, send_file, current_app from io import BytesIO from .. import files_bp from services.files.service import get_files_list, get_file_info, download_file_from_minio, delete_file, batch_delete_files, handle_chunk_upload, merge_chunks, upload_files_to_server from services.files.utils import FileType UPLOAD_FOLDER = "/data/uploads" ALLOWED_EXTENSIONS = {"txt", "pdf", "png", "jpg", "jpeg", "gif", "doc", "docx", "xls", "xlsx"} def allowed_file(filename): return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS @files_bp.route("/upload", methods=["POST"]) def upload_file(): if "files" not in request.files: return jsonify({"code": 400, "message": "未选择文件", "data": None}), 400 files = request.files.getlist("files") upload_result = upload_files_to_server(files) # 返回标准格式 return jsonify({"code": 0, "message": "上传成功", "data": upload_result["data"]}) @files_bp.route("", methods=["GET", "OPTIONS"]) def get_files(): """获取文件列表的API端点""" if request.method == "OPTIONS": return "", 200 try: current_page = int(request.args.get("currentPage", 1)) page_size = int(request.args.get("size", 10)) name_filter = request.args.get("name", "") sort_by = request.args.get("sort_by", "create_time") sort_order = request.args.get("sort_order", "desc") result, total = get_files_list(current_page, page_size, name_filter, sort_by, sort_order) return jsonify({"code": 0, "data": {"list": result, "total": total}, "message": "获取文件列表成功"}) except Exception as e: return jsonify({"code": 500, "message": f"获取文件列表失败: {str(e)}"}), 500 @files_bp.route("//download", methods=["GET", "OPTIONS"]) def download_file(file_id): try: current_app.logger.info(f"开始处理文件下载请求: {file_id}") # 获取文件信息 file = get_file_info(file_id) if not file: current_app.logger.error(f"文件不存在: {file_id}") return jsonify({"code": 404, "message": f"文件 {file_id} 不存在", "details": "文件记录不存在或已被删除"}), 404 if file["type"] == FileType.FOLDER.value: current_app.logger.error(f"不能下载文件夹: {file_id}") return jsonify({"code": 400, "message": "不能下载文件夹", "details": "请选择一个文件进行下载"}), 400 current_app.logger.info(f"文件信息获取成功: {file_id}, 存储位置: {file['parent_id']}/{file['location']}") try: # 从MinIO下载文件 file_data, filename = download_file_from_minio(file_id) # 创建内存文件对象 file_stream = BytesIO(file_data) # 返回文件 return send_file(file_stream, download_name=filename, as_attachment=True, mimetype="application/octet-stream") except Exception as e: current_app.logger.error(f"下载文件失败: {str(e)}") return jsonify({"code": 500, "message": "下载文件失败", "details": str(e)}), 500 except Exception as e: current_app.logger.error(f"处理下载请求时出错: {str(e)}") return jsonify({"code": 500, "message": "处理下载请求时出错", "details": str(e)}), 500 @files_bp.route("/", methods=["DELETE", "OPTIONS"]) def delete_file_route(file_id): """删除文件的API端点""" if request.method == "OPTIONS": return "", 200 try: success = delete_file(file_id) if success: return jsonify({"code": 0, "message": "文件删除成功"}) else: return jsonify({"code": 404, "message": f"文件 {file_id} 不存在"}), 404 except Exception as e: return jsonify({"code": 500, "message": f"删除文件失败: {str(e)}"}), 500 @files_bp.route("/batch", methods=["DELETE", "OPTIONS"]) def batch_delete_files_route(): """批量删除文件的API端点""" if request.method == "OPTIONS": return "", 200 try: data = request.json file_ids = data.get("ids", []) if not file_ids: return jsonify({"code": 400, "message": "未提供要删除的文件ID"}), 400 success_count = batch_delete_files(file_ids) return jsonify({"code": 0, "message": f"成功删除 {success_count}/{len(file_ids)} 个文件"}) except Exception as e: return jsonify({"code": 500, "message": f"批量删除文件失败: {str(e)}"}), 500 @files_bp.route("/upload/chunk", methods=["POST"]) def upload_chunk(): """ 处理文件分块上传 """ if "chunk" not in request.files: return jsonify({"code": 400, "message": "未选择文件分块", "data": None}), 400 chunk = request.files["chunk"] chunk_index = request.form.get("chunkIndex") total_chunks = request.form.get("totalChunks") upload_id = request.form.get("uploadId") file_name = request.form.get("fileName") parent_id = request.form.get("parent_id") if not all([chunk_index, total_chunks, upload_id, file_name]): return jsonify({"code": 400, "message": "缺少必要参数", "data": None}), 400 result = handle_chunk_upload(chunk, chunk_index, total_chunks, upload_id, file_name, parent_id) # 检查结果中是否有错误信息 if result.get("code", 0) != 0: # 如果有错误,返回相应的HTTP状态码 return jsonify(result), result.get("code", 500) return jsonify(result) @files_bp.route("/upload/merge", methods=["POST"]) def merge_upload(): """ 合并已上传的文件分块 """ data = request.json if not data: return jsonify({"code": 400, "message": "请求数据为空", "data": None}), 400 upload_id = data.get("uploadId") file_name = data.get("fileName") total_chunks = data.get("totalChunks") parent_id = data.get("parentId") if not all([upload_id, file_name, total_chunks]): return jsonify({"code": 400, "message": "缺少必要参数", "data": None}), 400 result = merge_chunks(upload_id, file_name, total_chunks, parent_id) # 检查结果中是否有错误信息 if result.get("code", 0) != 0: # 如果有错误,返回相应的HTTP状态码 return jsonify(result), result.get("code", 500) return jsonify(result)