142 lines
4.5 KiB
Python
142 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from datetime import datetime
|
|
from typing import Iterator
|
|
|
|
import database
|
|
from app_config import get_config
|
|
from app_security import is_safe_path
|
|
from flask import Blueprint, jsonify, send_from_directory
|
|
from flask_login import current_user, login_required
|
|
from services.client_log import log_to_client
|
|
from services.time_utils import BEIJING_TZ
|
|
|
|
config = get_config()
|
|
SCREENSHOTS_DIR = config.SCREENSHOTS_DIR
|
|
_IMAGE_EXTENSIONS = (".png", ".jpg", ".jpeg")
|
|
|
|
api_screenshots_bp = Blueprint("api_screenshots", __name__)
|
|
|
|
|
|
def _get_user_prefix(user_id: int) -> str:
|
|
user_info = database.get_user_by_id(user_id)
|
|
return user_info["username"] if user_info else f"user{user_id}"
|
|
|
|
|
|
def _is_user_screenshot(filename: str, username_prefix: str) -> bool:
|
|
return filename.startswith(username_prefix + "_") and filename.lower().endswith(_IMAGE_EXTENSIONS)
|
|
|
|
|
|
def _iter_user_screenshot_entries(username_prefix: str) -> Iterator[os.DirEntry]:
|
|
if not os.path.exists(SCREENSHOTS_DIR):
|
|
return
|
|
|
|
with os.scandir(SCREENSHOTS_DIR) as entries:
|
|
for entry in entries:
|
|
if (not entry.is_file()) or (not _is_user_screenshot(entry.name, username_prefix)):
|
|
continue
|
|
yield entry
|
|
|
|
|
|
def _build_display_name(filename: str) -> str:
|
|
base_name, ext = filename.rsplit(".", 1)
|
|
parts = base_name.split("_", 1)
|
|
if len(parts) > 1:
|
|
return f"{parts[1]}.{ext}"
|
|
return filename
|
|
|
|
|
|
@api_screenshots_bp.route("/api/screenshots", methods=["GET"])
|
|
@login_required
|
|
def get_screenshots():
|
|
"""获取当前用户的截图列表"""
|
|
user_id = current_user.id
|
|
username_prefix = _get_user_prefix(user_id)
|
|
|
|
try:
|
|
screenshots = []
|
|
for entry in _iter_user_screenshot_entries(username_prefix):
|
|
filename = entry.name
|
|
stat = entry.stat()
|
|
created_time = datetime.fromtimestamp(stat.st_mtime, tz=BEIJING_TZ)
|
|
|
|
screenshots.append(
|
|
{
|
|
"filename": filename,
|
|
"display_name": _build_display_name(filename),
|
|
"size": stat.st_size,
|
|
"created": created_time.strftime("%Y-%m-%d %H:%M:%S"),
|
|
"_created_ts": stat.st_mtime,
|
|
}
|
|
)
|
|
|
|
screenshots.sort(key=lambda item: item.get("_created_ts", 0), reverse=True)
|
|
for item in screenshots:
|
|
item.pop("_created_ts", None)
|
|
|
|
return jsonify(screenshots)
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@api_screenshots_bp.route("/screenshots/<filename>")
|
|
@login_required
|
|
def serve_screenshot(filename):
|
|
"""提供截图文件访问"""
|
|
user_id = current_user.id
|
|
username_prefix = _get_user_prefix(user_id)
|
|
|
|
if not _is_user_screenshot(filename, username_prefix):
|
|
return jsonify({"error": "无权访问"}), 403
|
|
|
|
if not is_safe_path(SCREENSHOTS_DIR, filename):
|
|
return jsonify({"error": "非法路径"}), 403
|
|
|
|
return send_from_directory(SCREENSHOTS_DIR, filename)
|
|
|
|
|
|
@api_screenshots_bp.route("/api/screenshots/<filename>", methods=["DELETE"])
|
|
@login_required
|
|
def delete_screenshot(filename):
|
|
"""删除指定截图"""
|
|
user_id = current_user.id
|
|
username_prefix = _get_user_prefix(user_id)
|
|
|
|
if not _is_user_screenshot(filename, username_prefix):
|
|
return jsonify({"error": "无权删除"}), 403
|
|
|
|
if not is_safe_path(SCREENSHOTS_DIR, filename):
|
|
return jsonify({"error": "非法路径"}), 403
|
|
|
|
try:
|
|
filepath = os.path.join(SCREENSHOTS_DIR, filename)
|
|
if os.path.exists(filepath):
|
|
os.remove(filepath)
|
|
log_to_client(f"删除截图: {filename}", user_id)
|
|
return jsonify({"success": True})
|
|
return jsonify({"error": "文件不存在"}), 404
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@api_screenshots_bp.route("/api/screenshots/clear", methods=["POST"])
|
|
@login_required
|
|
def clear_all_screenshots():
|
|
"""清空当前用户的所有截图"""
|
|
user_id = current_user.id
|
|
username_prefix = _get_user_prefix(user_id)
|
|
|
|
try:
|
|
deleted_count = 0
|
|
for entry in _iter_user_screenshot_entries(username_prefix):
|
|
os.remove(entry.path)
|
|
deleted_count += 1
|
|
|
|
log_to_client(f"清理了 {deleted_count} 个截图文件", user_id)
|
|
return jsonify({"success": True, "deleted": deleted_count})
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|