You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fileUpload/upload_service.py_20250414

210 lines
7.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from flask import Flask, request, jsonify
import os
# 默认配置
DEFAULT_UPLOAD_FOLDER = "/mnt/sese/"
ALLOWED_EXTENSIONS = {
'png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'webp', # 图片类型
'mp4', 'mov', 'wmv', 'avi', 'm4v', 'mpg', 'mpeg', 'flv', 'mkv', '3gp', 'webm' # 视频类型
}
MAX_FILE_SIZE = 88 * 1024 * 1024 # 88MB
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = DEFAULT_UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_FILE_SIZE
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def list_files(directory):
"""列出指定目录下的所有文件并按时间排序"""
if not os.path.exists(directory):
return []
files = []
for root, _, filenames in os.walk(directory):
for filename in filenames:
files.append(os.path.relpath(os.path.join(root, filename), directory))
files.sort(key=lambda x: os.path.getmtime(os.path.join(directory, x)), reverse=True) # 按时间降序排序
return files
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# 检查是否上传了文件
if 'file' not in request.files:
return jsonify({'status': 'error', 'message': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'status': 'error', 'message': 'No selected file'}), 400
# 获取自定义路径并检查合法性
custom_path = request.form.get('customPath', DEFAULT_UPLOAD_FOLDER).strip()
if custom_path:
# 验证路径合法性
if not os.path.isabs(custom_path): # 必须是绝对路径
return jsonify({'status': 'error', 'message': 'Path must be an absolute path'}), 400
if ".." in custom_path: # 禁止路径包含 ".." 防止目录跳跃
return jsonify({'status': 'error', 'message': 'Path not allowed'}), 400
else:
custom_path = DEFAULT_UPLOAD_FOLDER # 默认路径
# 创建完整保存路径
save_dir = os.path.abspath(custom_path)
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 检查文件类型并保存
if file and allowed_file(file.filename):
filepath = os.path.join(save_dir, file.filename)
file.save(filepath)
uploaded_files = list_files(save_dir) # 列举上传路径中的文件
return jsonify({'status': 'success', 'message': f'File uploaded to {save_dir}/{file.filename}',
'files': uploaded_files}), 200
return jsonify({'status': 'error', 'message': 'File type not allowed'}), 400
# GET 请求返回 HTML 页面
files = list_files(DEFAULT_UPLOAD_FOLDER)
# 显示最新10个文件超出部分隐藏
files_to_show = files[:10]
files_hidden = files[10:]
files_list_html = ''.join(
f'<li>{file}</li>'
for file in files_to_show
)
hidden_files_html = ''.join(
f'<li class="hidden-file">{file}</li>'
for file in files_hidden
)
files_all_json = jsonify(files=files) # 传回所有文件列表后续可以通过AJAX加载所有文件
html_template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload</title>
<style>
body {{
font-family: Arial, sans-serif;
background-color: #f4f7fc;
padding: 20px;
}}
h1 {{
color: #4b4f56;
font-size: 2rem;
}}
ul {{
list-style-type: none;
padding-left: 0;
}}
li {{
margin: 5px 0;
padding: 10px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
}}
.hidden-file {{
display: none;
}}
button {{
padding: 10px 20px;
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}}
button:hover {{
background-color: #218838;
}}
</style>
<script>
function uploadFile(event) {{
event.preventDefault();
const formData = new FormData(document.getElementById('uploadForm'));
const uploadButton = document.getElementById('uploadButton');
const progressIndicator = document.getElementById('progressIndicator');
const messageBox = document.getElementById('messageBox');
// 禁用按钮,显示上传中提示
uploadButton.disabled = true;
progressIndicator.style.display = 'inline-block';
fetch('/upload', {{
method: 'POST',
body: formData
}})
.then(response => response.json())
.then(data => {{
progressIndicator.style.display = 'none'; // 隐藏进度指示
uploadButton.disabled = false; // 启用按钮
if (data.status === 'success') {{
messageBox.innerHTML = '<p style="color:green;">' + data.message + '</p>';
updateFileList(data.files); // 更新文件列表
}} else {{
messageBox.innerHTML = '<p style="color:red;">' + data.message + '</p>';
}}
}})
.catch(error => {{
progressIndicator.style.display = 'none'; // 隐藏进度指示
uploadButton.disabled = false; // 启用按钮
messageBox.innerHTML = '<p style="color:red;">Upload failed</p>';
}});
}}
function updateFileList(files) {{
const filesListHtml = files.map(file => '<li>' + file + '</li>').join('');
document.getElementById('filesList').innerHTML = filesListHtml;
}}
function showAllFiles() {{
// 读取所有文件并显示
fetch('/upload')
.then(response => response.json())
.then(data => {{
if (data.files) {{
updateFileList(data.files); // 更新文件列表显示
document.getElementById('showMoreButton').style.display = 'none'; // 隐藏"查看全部"按钮
}}
}});
}}
</script>
</head>
<body>
<h1>Upload a file</h1>
<form id="uploadForm" onsubmit="uploadFile(event)" enctype="multipart/form-data">
<label for="customPath">Custom Path (default: {DEFAULT_UPLOAD_FOLDER}):</label>
<input type="text" id="customPath" name="customPath" placeholder="Enter absolute path (e.g., /mnt/self/)">
<input type="file" name="file" required>
<button id="uploadButton" type="submit">Upload</button>
<span id="progressIndicator" style="display:none;">Uploading...</span>
</form>
<div id="messageBox"></div>
<h2>Uploaded files (Latest files displayed):</h2>
<ul id="filesList">
{files_list_html}
{hidden_files_html}
</ul>
<button id="showMoreButton" onclick="showAllFiles()">Show All Files</button>
</body>
</html>
"""
return html_template
if __name__ == '__main__':
if not os.path.exists(DEFAULT_UPLOAD_FOLDER):
os.makedirs(DEFAULT_UPLOAD_FOLDER)
app.run(host='0.0.0.0', port=8066)