Download app.py from WACATW/pan: direct link, hf CLI and curl.
- Browser
- Download file 25.8 kB
-
https://huggingface.co/spaces/WACATW/pan/resolve/main/app.py
- Command line
-
hf download hf://spaces/WACATW/pan/app.py
-
curl -L -o app.py https://huggingface.co/spaces/WACATW/pan/resolve/main/app.py
25.8 kB
| import os | |
| import io | |
| import json | |
| import mimetypes | |
| from datetime import datetime | |
| from flask import Flask, render_template, request, jsonify, send_file, abort, session, redirect, url_for | |
| from werkzeug.security import generate_password_hash, check_password_hash | |
| import re | |
| import uuid | |
| #GRAPHICAL_API_TOKEN = "676767" | |
| def safe_filename(filename): | |
| """安全的文件名处理,支持中文""" | |
| if not filename: | |
| return 'unnamed' | |
| # 移除路径分隔符和危险字符 | |
| filename = re.sub(r'[\\/:*?"<>|\x00-\x1f]', '_', filename) | |
| # 移除开头的点和空格 | |
| filename = filename.lstrip('. ') | |
| # 确保文件名不为空 | |
| if not filename: | |
| filename = 'unnamed' | |
| return filename | |
| def safe_username(username): | |
| """安全的用户名处理""" | |
| if not username: | |
| return None | |
| # 只允许字母、数字、下划线、中文 | |
| if not re.match(r'^[a-zA-Z0-9_\u4e00-\u9fa5]{3,20}$', username): | |
| return None | |
| return username | |
| app = Flask(__name__) | |
| app.config['MAX_CONTENT_LENGTH'] = 500 * 1024 * 1024 * 1024 | |
| app.secret_key = os.environ.get('SECRET_KEY', 'cloud-disk-secret-key-2024') | |
| # Session cookie 配置 | |
| app.config['SESSION_COOKIE_SAMESITE'] = 'None' | |
| app.config['SESSION_COOKIE_SECURE'] = True | |
| app.config['SESSION_COOKIE_HTTPONLY'] = True | |
| app.config['PERMANENT_SESSION_LIFETIME'] = 30 * 24 * 60 * 60 | |
| # 如果是 HTTPS 环境,取消下面两行的注释 | |
| # app.config['SESSION_COOKIE_SAMESITE'] = 'None' | |
| # app.config['SESSION_COOKIE_SECURE'] = True | |
| # Configuration | |
| STORAGE_BASE_PATH = os.environ.get('STORAGE_PATH', '/data') | |
| USERS_FILE = os.path.join(STORAGE_BASE_PATH, 'users.json') | |
| MAX_STORAGE_PER_USER = 1 * 1024 * 1024 * 1024 # 1GB per user | |
| # Ensure storage directory exists | |
| os.makedirs(STORAGE_BASE_PATH, exist_ok=True) | |
| # Initialize users file | |
| if not os.path.exists(USERS_FILE): | |
| with open(USERS_FILE, 'w', encoding='utf-8') as f: | |
| json.dump({}, f) | |
| def load_users(): | |
| """加载用户数据""" | |
| try: | |
| with open(USERS_FILE, 'r', encoding='utf-8') as f: | |
| return json.load(f) | |
| except: | |
| return {} | |
| def save_users(users): | |
| """保存用户数据""" | |
| with open(USERS_FILE, 'w', encoding='utf-8') as f: | |
| json.dump(users, f, ensure_ascii=False, indent=2) | |
| def get_user_storage_path(username): | |
| """获取用户的存储目录""" | |
| return os.path.join(STORAGE_BASE_PATH, 'users', username) | |
| def ensure_user_storage(username): | |
| """确保用户存储目录存在""" | |
| path = get_user_storage_path(username) | |
| os.makedirs(path, exist_ok=True) | |
| return path | |
| def calculate_user_storage(username): | |
| """计算用户已使用的存储空间""" | |
| user_path = get_user_storage_path(username) | |
| if not os.path.exists(user_path): | |
| return 0 | |
| total_size = 0 | |
| for dirpath, dirnames, filenames in os.walk(user_path): | |
| for filename in filenames: | |
| filepath = os.path.join(dirpath, filename) | |
| try: | |
| total_size += os.path.getsize(filepath) | |
| except: | |
| pass | |
| return total_size | |
| def get_current_user(): | |
| """获取当前登录用户""" | |
| return session.get('username') | |
| def login_required_api(): | |
| """API 登录检查装饰器辅助函数""" | |
| username = get_current_user() | |
| if not username: | |
| return False, jsonify({'success': False, 'error': '请先登录', 'need_login': True}) | |
| return True, username | |
| def get_full_path(username, path=''): | |
| """获取用户目录下的完整路径""" | |
| user_path = get_user_storage_path(username) | |
| if path and path != '/': | |
| # 规范化路径,防止路径遍历 | |
| path = path.strip('/') | |
| full_path = os.path.normpath(os.path.join(user_path, path)) | |
| # 确保路径在用户目录内 | |
| if not full_path.startswith(os.path.normpath(user_path)): | |
| return None | |
| return full_path | |
| return user_path | |
| def list_files(username, path=''): | |
| """列出用户目录下的文件""" | |
| full_path = get_full_path(username, path) | |
| if not full_path or not os.path.exists(full_path): | |
| return [] | |
| result = [] | |
| try: | |
| for item in os.listdir(full_path): | |
| item_path = os.path.join(full_path, item) | |
| is_dir = os.path.isdir(item_path) | |
| stat = os.stat(item_path) | |
| result.append({ | |
| 'name': item, | |
| 'type': 'directory' if is_dir else 'file', | |
| 'size': stat.st_size if not is_dir else 0, | |
| 'modified': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S') | |
| }) | |
| # Sort: directories first, then files | |
| result.sort(key=lambda x: (x['type'] != 'directory', x['name'].lower())) | |
| return result | |
| except Exception as e: | |
| print(f"Error listing files: {e}") | |
| return [] | |
| def upload_file(username, file_storage, path=''): | |
| """上传文件到用户目录""" | |
| # 检查配额 | |
| used_storage = calculate_user_storage(username) | |
| file_content = file_storage.read() | |
| file_size = len(file_content) | |
| if used_storage + file_size > MAX_STORAGE_PER_USER: | |
| return False, f"存储空间不足,您已使用 {format_size(used_storage)},还剩 {format_size(MAX_STORAGE_PER_USER - used_storage)}" | |
| full_path = get_full_path(username, path) | |
| if not full_path: | |
| return False, "路径无效" | |
| try: | |
| filename = safe_filename(file_storage.filename) | |
| file_path = os.path.join(full_path, filename) | |
| os.makedirs(os.path.dirname(file_path), exist_ok=True) | |
| with open(file_path, 'wb') as f: | |
| f.write(file_content) | |
| return True, "上传成功" | |
| except Exception as e: | |
| print(f"Error uploading file: {e}") | |
| return False, str(e) | |
| def download_file(username, filename, path=''): | |
| """下载用户文件""" | |
| full_path = get_full_path(username, path) | |
| if not full_path: | |
| return None | |
| file_path = os.path.join(full_path, filename) | |
| if os.path.exists(file_path) and os.path.isfile(file_path): | |
| return file_path | |
| return None | |
| def create_directory(username, dirname, path=''): | |
| """创建文件夹""" | |
| full_path = get_full_path(username, path) | |
| if not full_path: | |
| return False, "路径无效" | |
| try: | |
| dirname = safe_filename(dirname) | |
| dir_path = os.path.join(full_path, dirname) | |
| os.makedirs(dir_path, exist_ok=True) | |
| return True, "文件夹创建成功" | |
| except Exception as e: | |
| print(f"Error creating directory: {e}") | |
| return False, str(e) | |
| def delete_item(username, filename, path=''): | |
| """删除文件或文件夹""" | |
| full_path = get_full_path(username, path) | |
| if not full_path: | |
| return False, "路径无效" | |
| try: | |
| item_path = os.path.join(full_path, filename) | |
| if os.path.isdir(item_path): | |
| import shutil | |
| shutil.rmtree(item_path) | |
| else: | |
| os.remove(item_path) | |
| return True, "删除成功" | |
| except Exception as e: | |
| print(f"Error deleting item: {e}") | |
| return False, str(e) | |
| def format_size(size_bytes): | |
| """格式化文件大小""" | |
| if size_bytes == 0 or size_bytes == '-': | |
| return '0 B' | |
| try: | |
| size_bytes = int(size_bytes) | |
| for unit in ['B', 'KB', 'MB', 'GB', 'TB']: | |
| if size_bytes < 1024.0: | |
| return f"{size_bytes:.2f} {unit}" | |
| size_bytes /= 1024.0 | |
| return f"{size_bytes:.2f} PB" | |
| except: | |
| return '-' | |
| # Template filter | |
| app.jinja_env.filters['format_size'] = format_size | |
| def index(): | |
| """主页面""" | |
| username = get_current_user() | |
| if not username: | |
| return redirect(url_for('login_page')) | |
| current_path = request.args.get('path', '') | |
| files = list_files(username, current_path) | |
| # Build breadcrumb | |
| breadcrumb = [] | |
| if current_path: | |
| parts = current_path.strip('/').split('/') | |
| acc = '' | |
| for part in parts: | |
| acc += '/' + part if acc else part | |
| breadcrumb.append({'name': part, 'path': acc}) | |
| # Calculate storage | |
| used_storage = calculate_user_storage(username) | |
| storage_percent = (used_storage / MAX_STORAGE_PER_USER) * 100 | |
| return render_template('index.html', | |
| username=username, | |
| files=files, | |
| current_path=current_path, | |
| breadcrumb=breadcrumb, | |
| used_storage=used_storage, | |
| max_storage=MAX_STORAGE_PER_USER, | |
| storage_percent=storage_percent, | |
| used_storage_formatted=format_size(used_storage), | |
| max_storage_formatted=format_size(MAX_STORAGE_PER_USER)) | |
| def login_page(): | |
| """登录页面(支持表单提交)""" | |
| if get_current_user(): | |
| return redirect(url_for('index')) | |
| error = None | |
| if request.method == 'POST': | |
| # 表单提交方式 | |
| username = request.form.get('username', '').strip() | |
| password = request.form.get('password', '') | |
| if not username or not password: | |
| error = '请输入用户名和密码' | |
| else: | |
| users = load_users() | |
| user = users.get(username) | |
| if not user or not check_password_hash(user['password_hash'], password): | |
| error = '用户名或密码错误' | |
| else: | |
| # 登录成功 | |
| ensure_user_storage(username) | |
| session['username'] = username | |
| session.permanent = True | |
| # 打印日志验证 | |
| print("写入session成功,username=", username, "session内容=", session.get("username")) | |
| return redirect(url_for('index')) | |
| return render_template('login.html', error=error) | |
| def register_page(): | |
| """注册页面(支持表单提交)""" | |
| if get_current_user(): | |
| return redirect(url_for('index')) | |
| error = None | |
| if request.method == 'POST': | |
| # 表单提交方式 | |
| username = request.form.get('username', '').strip() | |
| password = request.form.get('password', '') | |
| confirm_password = request.form.get('confirm_password', '') | |
| # 验证用户名 | |
| if not safe_username(username): | |
| error = '用户名格式不正确,3-20位字母、数字、下划线或中文' | |
| # 验证密码 | |
| elif len(password) < 6: | |
| error = '密码至少6位' | |
| elif password != confirm_password: | |
| error = '两次密码不一致' | |
| else: | |
| # 检查用户是否存在 | |
| users = load_users() | |
| if username in users: | |
| error = '用户名已存在' | |
| else: | |
| # 创建用户 | |
| users[username] = { | |
| 'password_hash': generate_password_hash(password), | |
| 'created_at': datetime.now().isoformat(), | |
| 'max_storage': MAX_STORAGE_PER_USER | |
| } | |
| save_users(users) | |
| # 创建用户目录 | |
| ensure_user_storage(username) | |
| # 自动登录 | |
| session['username'] = username | |
| session.permanent = True | |
| return redirect(url_for('index')) | |
| return render_template('register.html', error=error) | |
| # ========== Auth APIs ========== | |
| def api_register(): | |
| """注册 API""" | |
| data = request.get_json() | |
| username = data.get('username', '').strip() | |
| password = data.get('password', '') | |
| confirm_password = data.get('confirm_password', '') | |
| # 验证用户名 | |
| if not safe_username(username): | |
| return jsonify({'success': False, 'error': '用户名格式不正确,3-20位字母、数字、下划线或中文'}) | |
| # 验证密码 | |
| if len(password) < 6: | |
| return jsonify({'success': False, 'error': '密码至少6位'}) | |
| if password != confirm_password: | |
| return jsonify({'success': False, 'error': '两次密码不一致'}) | |
| # 检查用户是否存在 | |
| users = load_users() | |
| if username in users: | |
| return jsonify({'success': False, 'error': '用户名已存在'}) | |
| # 创建用户 | |
| users[username] = { | |
| 'password_hash': generate_password_hash(password), | |
| 'created_at': datetime.now().isoformat(), | |
| 'max_storage': MAX_STORAGE_PER_USER | |
| } | |
| save_users(users) | |
| # 创建用户目录 | |
| ensure_user_storage(username) | |
| # 自动登录 | |
| session['username'] = username | |
| return jsonify({'success': True, 'message': '注册成功', 'username': username}) | |
| def api_login(): | |
| """登录 API""" | |
| data = request.get_json() | |
| username = data.get('username', '').strip() | |
| password = data.get('password', '') | |
| if not username or not password: | |
| return jsonify({'success': False, 'error': '请输入用户名和密码'}) | |
| users = load_users() | |
| user = users.get(username) | |
| if not user or not check_password_hash(user['password_hash'], password): | |
| return jsonify({'success': False, 'error': '用户名或密码错误'}) | |
| # 确保用户目录存在 | |
| ensure_user_storage(username) | |
| session['username'] = username | |
| return jsonify({'success': True, 'message': '登录成功', 'username': username}) | |
| def api_logout(): | |
| """退出登录 API""" | |
| session.pop('username', None) | |
| return jsonify({'success': True, 'message': '已退出登录'}) | |
| def api_user_info(): | |
| """获取用户信息 API""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return result | |
| username = result | |
| used_storage = calculate_user_storage(username) | |
| return jsonify({ | |
| 'success': True, | |
| 'username': username, | |
| 'used_storage': used_storage, | |
| 'max_storage': MAX_STORAGE_PER_USER, | |
| 'used_storage_formatted': format_size(used_storage), | |
| 'max_storage_formatted': format_size(MAX_STORAGE_PER_USER), | |
| 'storage_percent': (used_storage / MAX_STORAGE_PER_USER) * 100 | |
| }) | |
| # ========== File APIs ========== | |
| def api_list(): | |
| """API: 列出文件""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return result | |
| username = result | |
| path = request.args.get('path', '') | |
| files = list_files(username, path) | |
| return jsonify({'success': True, 'files': files, 'path': path}) | |
| def api_upload(): | |
| """API: 上传文件""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return result | |
| username = result | |
| if 'file' not in request.files: | |
| return jsonify({'success': False, 'error': '没有选择文件'}) | |
| file = request.files['file'] | |
| if file.filename == '': | |
| return jsonify({'success': False, 'error': '没有选择文件'}) | |
| path = request.form.get('path', '') | |
| success, message = upload_file(username, file, path) | |
| return jsonify({'success': success, 'message': message}) | |
| def api_download(): | |
| """API: 下载文件""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return redirect(url_for('login_page')) | |
| username = result | |
| filename = request.args.get('filename', '') | |
| path = request.args.get('path', '') | |
| if not filename: | |
| abort(400) | |
| file_path = download_file(username, filename, path) | |
| if not file_path: | |
| abort(404) | |
| # Determine MIME type | |
| mime_type, _ = mimetypes.guess_type(filename) | |
| if not mime_type: | |
| mime_type = 'application/octet-stream' | |
| return send_file( | |
| file_path, | |
| mimetype=mime_type, | |
| as_attachment=True, | |
| download_name=filename | |
| ) | |
| def api_mkdir(): | |
| """API: 创建文件夹""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return result | |
| username = result | |
| data = request.get_json() | |
| dirname = data.get('dirname', '') | |
| path = data.get('path', '') | |
| if not dirname: | |
| return jsonify({'success': False, 'error': '请输入文件夹名称'}) | |
| success, message = create_directory(username, dirname, path) | |
| return jsonify({'success': success, 'message': message}) | |
| def api_delete(): | |
| """API: 删除文件/文件夹""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return result | |
| username = result | |
| data = request.get_json() | |
| filename = data.get('filename', '') | |
| path = data.get('path', '') | |
| if not filename: | |
| return jsonify({'success': False, 'error': '请选择要删除的文件'}) | |
| success, message = delete_item(username, filename, path) | |
| return jsonify({'success': success, 'message': message}) | |
| def api_storage_info(): | |
| """API: 获取存储信息""" | |
| is_logged_in, result = login_required_api() | |
| if not is_logged_in: | |
| return result | |
| username = result | |
| used_storage = calculate_user_storage(username) | |
| return jsonify({ | |
| 'success': True, | |
| 'storage_type': 'local', | |
| 'used_storage': used_storage, | |
| 'max_storage': MAX_STORAGE_PER_USER, | |
| 'used_storage_formatted': format_size(used_storage), | |
| 'max_storage_formatted': format_size(MAX_STORAGE_PER_USER), | |
| 'storage_percent': (used_storage / MAX_STORAGE_PER_USER) * 100 | |
| }) | |
| # 1. 查看文本文件接口 | |
| def api_view(): | |
| if 'username' not in session: | |
| return jsonify({'success': False, 'error': '未登录'}), 401 | |
| filename = request.args.get('filename') | |
| current_path = request.args.get('path', '') | |
| if not filename or filename == 'undefined': | |
| return jsonify({'success': False, 'error': '文件名无效'}), 400 | |
| user_dir = get_user_storage_path(session['username']) | |
| file_path = os.path.join(user_dir, current_path, filename) | |
| # 安全检查:防止路径穿越 | |
| if not os.path.abspath(file_path).startswith(os.path.abspath(user_dir)): | |
| return jsonify({'success': False, 'error': '非法路径'}), 403 | |
| if not os.path.isfile(file_path): | |
| return jsonify({'success': False, 'error': '文件不存在'}), 404 | |
| # 限制文件大小,比如只允许查看 2MB 以内的文本 | |
| if os.path.getsize(file_path) > 2 * 1024 * 1024: | |
| return jsonify({'success': False, 'error': '文件过大,不支持在线预览'}), 400 | |
| # 判断是否为文本文件 | |
| text_extensions = ['.txt', '.md', '.py', '.json', '.html', '.css', '.js', '.log', '.csv', '.xml'] | |
| ext = os.path.splitext(file_path)[1].lower() | |
| if ext not in text_extensions: | |
| return jsonify({'success': False, 'error': '该文件类型不支持在线查看'}), 400 | |
| try: | |
| with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: | |
| content = f.read() | |
| return jsonify({'success': True, 'content': content, 'filename': filename}) | |
| except Exception as e: | |
| return jsonify({'success': False, 'error': str(e)}), 500 | |
| # 2. 移动文件接口 | |
| def api_move(): | |
| if 'username' not in session: | |
| return jsonify({'success': False, 'error': '未登录'}), 401 | |
| data = request.get_json() | |
| filename = data.get('filename') | |
| source_path = data.get('source_path', '') | |
| target_dir = data.get('target_dir', '') | |
| if not filename: | |
| return jsonify({'success': False, 'error': '文件名无效'}), 400 | |
| user_dir = get_user_storage_path(session['username']) | |
| abs_source = os.path.join(user_dir, source_path, filename) | |
| abs_target_dir = os.path.join(user_dir, target_dir) | |
| # 安全检查 | |
| if not os.path.abspath(abs_source).startswith(os.path.abspath(user_dir)) or \ | |
| not os.path.abspath(abs_target_dir).startswith(os.path.abspath(user_dir)): | |
| return jsonify({'success': False, 'error': '非法路径'}), 403 | |
| if not os.path.exists(abs_source): | |
| return jsonify({'success': False, 'error': '源文件不存在'}), 404 | |
| try: | |
| os.makedirs(abs_target_dir, exist_ok=True) | |
| shutil.move(abs_source, os.path.join(abs_target_dir, filename)) | |
| return jsonify({'success': True, 'message': '移动成功'}) | |
| except Exception as e: | |
| return jsonify({'success': False, 'error': str(e)}), 500 | |
| # 配置区域:设置你的固定 API Token(请务必修改为一个复杂的字符串) | |
| GRAPHICAL_API_TOKEN = "676767" | |
| def check_graphical_auth(): | |
| """检查图形化编程 API 的认证""" | |
| token = request.headers.get('X-API-Token') or request.args.get('token') | |
| print(f"!!!后端收到 token: '{token}' | 后端预期密码: '{GRAPHICAL_API_TOKEN}'") | |
| if token != GRAPHICAL_API_TOKEN: | |
| return False, jsonify({'success': False, 'error': 'Token 无效'}), 401 | |
| return True, None | |
| def graphical_upload(): | |
| """图形化编程专用:通过 JSON 上传文件""" | |
| auth_result = check_graphical_auth() | |
| if not auth_result[0]: return auth_result[1], auth_result[2] | |
| data = request.get_json() | |
| username = data.get('username') # 需要在请求中指定用户名 | |
| filename = data.get('filename') | |
| content_base64 = data.get('content') # Base64 编码的文件内容 | |
| if not username or not filename or not content_base64: | |
| return jsonify({'success': False, 'error': '缺少必要参数'}), 400 | |
| import base64 | |
| try: | |
| file_content = base64.b64decode(content_base64) | |
| except: | |
| return jsonify({'success': False, 'error': '内容解码失败'}), 400 | |
| # 检查用户是否存在(可选) | |
| users = load_users() | |
| if username not in users: | |
| return jsonify({'success': False, 'error': '用户不存在'}), 404 | |
| ensure_user_storage(username) | |
| # 调用原有的上传逻辑 | |
| class FileStorage: | |
| def __init__(self, filename, content): | |
| self.filename = filename | |
| self.content = content | |
| def read(self): | |
| return self.content | |
| success, message = upload_file(username, FileStorage(filename, file_content)) | |
| return jsonify({'success': success, 'message': message}) | |
| def graphical_download(): | |
| """图形化编程专用:通过 GET 下载文件""" | |
| auth_result = check_graphical_auth() | |
| if not auth_result[0]: return auth_result[1], auth_result[2] | |
| username = request.args.get('username') | |
| filename = request.args.get('filename') | |
| path = request.args.get('path', '') | |
| if not username or not filename: | |
| return jsonify({'success': False, 'error': '缺少用户名或文件名'}), 400 | |
| users = load_users() | |
| if username not in users: | |
| return jsonify({'success': False, 'error': '用户不存在'}), 404 | |
| file_path = download_file(username, filename, path) | |
| if not file_path: | |
| return jsonify({'success': False, 'error': '文件不存在'}), 404 | |
| # 返回 Base64 编码的文件内容 | |
| import base64 | |
| try: | |
| with open(file_path, 'rb') as f: | |
| file_content = f.read() | |
| content_base64 = base64.b64encode(file_content).decode('utf-8') | |
| return jsonify({ | |
| 'success': True, | |
| 'filename': filename, | |
| 'content': content_base64 | |
| }) | |
| except Exception as e: | |
| return jsonify({'success': False, 'error': str(e)}), 500 | |
| def graphical_list(): | |
| """图形化编程专用:列出文件""" | |
| auth_result = check_graphical_auth() | |
| if not auth_result[0]: return auth_result[1], auth_result[2] | |
| username = request.args.get('username') | |
| path = request.args.get('path', '') | |
| if not username: | |
| return jsonify({'success': False, 'error': '缺少用户名'}), 400 | |
| users = load_users() | |
| if username not in users: | |
| return jsonify({'success': False, 'error': '用户不存在'}), 404 | |
| files = list_files(username, path) | |
| return jsonify({'success': True, 'files': files, 'path': path}) | |
| def graphical_delete(): | |
| """图形化编程专用:删除文件""" | |
| auth_result = check_graphical_auth() | |
| if not auth_result[0]: return auth_result[1], auth_result[2] | |
| data = request.get_json() | |
| username = data.get('username') | |
| filename = data.get('filename') | |
| path = data.get('path', '') | |
| if not username or not filename: | |
| return jsonify({'success': False, 'error': '缺少用户名或文件名'}), 400 | |
| users = load_users() | |
| if username not in users: | |
| return jsonify({'success': False, 'error': '用户不存在'}), 404 | |
| success, message = delete_item(username, filename, path) | |
| return jsonify({'success': success, 'message': message}) | |
| if __name__ == '__main__': | |
| port = int(os.environ.get('PORT', 7860)) | |
| app.run(host='0.0.0.0', port=port, debug=False) | |