File size: 2,874 Bytes
e5d8d3a
033070f
e5d8d3a
033070f
e5d8d3a
033070f
e5d8d3a
 
 
 
 
 
 
 
 
 
 
 
 
c8f3989
e5d8d3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8f3989
e5d8d3a
 
 
033070f
 
 
 
 
 
 
 
c8f3989
033070f
 
 
 
 
 
 
 
 
 
 
 
 
 
c8f3989
033070f
c8f3989
033070f
 
 
 
 
c8f3989
033070f
 
 
 
 
 
c8f3989
 
033070f
 
 
 
 
 
 
c8f3989
033070f
c8f3989
 
033070f
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""API 工具函数"""
import os
import traceback
from functools import wraps
from pathlib import Path
from flask import request, jsonify


def get_demo_directory(create=False):
    """获取 demo 目录路径"""
    from backend.app_context import get_demo_directory as _get_demo_dir
    return _get_demo_dir(create=create)


def handle_api_error(operation_name: str, error: Exception) -> dict:
    """
    统一的 API 错误处理
    
    Args:
        operation_name: 操作名称(如 'Save failed'、'Delete failed')
        error: 异常对象
        
    Returns:
        标准错误响应字典
    """
    error_msg = f'{operation_name}: {str(error)}'
    print(f"❌ {error_msg}")
    traceback.print_exc()
    return {
        'success': False,
        'message': error_msg
    }


def handle_api_success(result: dict, operation_name: str = None) -> dict:
    """
    处理 API 成功响应,打印日志
    
    Args:
        result: 操作结果字典
        operation_name: 可选的操作名称,用于日志
        
    Returns:
        结果字典
    """
    if result.get('success'):
        if operation_name:
            print(f"✓ {operation_name}")
        elif result.get('message'):
            print(f"✓ {result.get('message')}")
    else:
        message = result.get('message', 'Operation failed')
        print(f"❌ {message}")
    return result


def get_admin_token() -> str:
    """
    获取管理员token(从环境变量读取)
    
    Returns:
        管理员token字符串,如果未设置则返回None
    """
    return os.environ.get('INFORADAR_ADMIN_TOKEN')


def validate_admin_token(request_token: str) -> tuple[bool, str]:
    """
    验证管理员token是否有效
    
    Args:
        request_token: 要验证的token
    
    Returns:
        (是否有效, 错误信息)
    """
    admin_token = get_admin_token()
    
    # 如果未配置INFORADAR_ADMIN_TOKEN,返回未启用状态
    if admin_token is None:
        return False, 'Admin features are not enabled'
    
    # 验证token
    if request_token == admin_token:
        return True, ''
    else:
        return False, 'Invalid admin token'


def require_admin(f):
    """
    装饰器:要求管理员权限才能访问的API
    
    检查请求头中的 X-Admin-Token 是否与配置的 INFORADAR_ADMIN_TOKEN 匹配
    如果未配置 INFORADAR_ADMIN_TOKEN,视为全是普通用户,拒绝所有写操作
    """
    @wraps(f)
    def wrapper(*args, **kwargs):
        request_token = request.headers.get('X-Admin-Token')
        is_valid, error_message = validate_admin_token(request_token)
        
        if not is_valid:
            return {
                'success': False,
                'message': 'Admin permission required'
            }, 403
        
        return f(*args, **kwargs)
    return wrapper