""" 文件上传视图 """ from flask import Blueprint, request, jsonify, session, current_app from werkzeug.utils import secure_filename from app.utils.decorators import login_required from app.models.user import User from app.utils.cos_client import cos_client from config.database import db from config.cos_config import COSConfig import os upload_bp = Blueprint('upload', __name__) @upload_bp.route('/avatar', methods=['POST']) @login_required def upload_avatar(): """ 上传用户头像 """ try: # 检查是否有文件 if 'avatar' not in request.files: return jsonify({ 'success': False, 'message': '没有选择文件' }), 400 file = request.files['avatar'] # 检查文件名 if file.filename == '': return jsonify({ 'success': False, 'message': '没有选择文件' }), 400 # 验证文件类型 if not allowed_file(file.filename, COSConfig.ALLOWED_IMAGE_EXTENSIONS): return jsonify({ 'success': False, 'message': f'不支持的文件格式,只支持: {", ".join(COSConfig.ALLOWED_IMAGE_EXTENSIONS)}' }), 400 # 验证文件大小 file.seek(0, 2) # 移动到文件末尾 file_size = file.tell() file.seek(0) # 重置文件指针 if file_size > COSConfig.MAX_IMAGE_SIZE: size_mb = COSConfig.MAX_IMAGE_SIZE / 1024 / 1024 return jsonify({ 'success': False, 'message': f'文件大小超过限制,最大允许 {size_mb:.1f}MB' }), 400 # 获取当前用户 user = User.query.get(session['user_id']) if not user: return jsonify({ 'success': False, 'message': '用户不存在' }), 404 # 上传到COS upload_result = cos_client.upload_file( file_obj=file, folder_type='avatar', original_filename=file.filename ) if not upload_result['success']: current_app.logger.error(f"COS上传失败: {upload_result['error']}") return jsonify({ 'success': False, 'message': '文件上传失败,请重试' }), 500 # 删除旧头像(如果存在) if user.avatar_url: try: # 从URL中提取文件路径 old_file_key = extract_file_key_from_url(user.avatar_url) if old_file_key: cos_client.delete_file(old_file_key) current_app.logger.info(f"删除旧头像: {old_file_key}") except Exception as e: current_app.logger.warning(f"删除旧头像失败: {str(e)}") # 更新用户头像URL user.avatar_url = upload_result['url'] db.session.commit() current_app.logger.info(f"用户 {user.username} 头像上传成功: {upload_result['file_key']}") return jsonify({ 'success': True, 'message': '头像上传成功', 'avatar_url': upload_result['url'], 'file_key': upload_result['file_key'] }) except Exception as e: current_app.logger.error(f"头像上传异常: {str(e)}") db.session.rollback() return jsonify({ 'success': False, 'message': '服务器内部错误' }), 500 def allowed_file(filename, allowed_extensions): """ 检查文件扩展名是否允许 """ return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in allowed_extensions def extract_file_key_from_url(url): """ 从COS URL中提取文件路径 """ try: if not url: return None # 移除域名部分,只保留文件路径 if COSConfig.BUCKET_DOMAIN in url: return url.split(COSConfig.BUCKET_DOMAIN + '/')[-1] return None except Exception: return None @upload_bp.route('/test', methods=['GET', 'POST']) @login_required def test_upload(): """ 测试上传功能 """ if request.method == 'GET': return ''' 测试上传

测试文件上传

''' # POST 请求处理 if 'test_file' not in request.files: return '没有文件' file = request.files['test_file'] if file.filename == '': return '没有选择文件' # 上传到COS result = cos_client.upload_file( file_obj=file, folder_type='temp', original_filename=file.filename ) if result['success']: return f'''

上传成功!

文件路径: {result['file_key']}

访问URL: {result['url']}

''' else: return f'上传失败: {result["error"]}'