272 lines
11 KiB
Python
272 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
飞书权限检查工具
|
|
用于诊断和解决飞书API权限问题
|
|
"""
|
|
|
|
import logging
|
|
from typing import Dict, Any, List
|
|
from src.integrations.feishu_client import FeishuClient
|
|
from src.integrations.config_manager import config_manager
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class FeishuPermissionChecker:
|
|
"""飞书权限检查器"""
|
|
|
|
def __init__(self):
|
|
self.feishu_config = config_manager.get_feishu_config()
|
|
self.client = None
|
|
|
|
if self.feishu_config.get("app_id") and self.feishu_config.get("app_secret"):
|
|
self.client = FeishuClient(
|
|
self.feishu_config["app_id"],
|
|
self.feishu_config["app_secret"]
|
|
)
|
|
|
|
def check_permissions(self) -> Dict[str, Any]:
|
|
"""
|
|
检查飞书应用权限
|
|
|
|
Returns:
|
|
权限检查结果
|
|
"""
|
|
result = {
|
|
"success": False,
|
|
"checks": {},
|
|
"recommendations": [],
|
|
"errors": []
|
|
}
|
|
|
|
if not self.client:
|
|
result["errors"].append("飞书客户端未初始化,请检查配置")
|
|
return result
|
|
|
|
# 1. 检查访问令牌
|
|
try:
|
|
token = self.client._get_access_token()
|
|
if token:
|
|
result["checks"]["access_token"] = {
|
|
"status": "success",
|
|
"message": "访问令牌获取成功"
|
|
}
|
|
else:
|
|
result["checks"]["access_token"] = {
|
|
"status": "failed",
|
|
"message": "无法获取访问令牌"
|
|
}
|
|
result["errors"].append("无法获取访问令牌")
|
|
except Exception as e:
|
|
result["checks"]["access_token"] = {
|
|
"status": "failed",
|
|
"message": f"访问令牌获取失败: {e}"
|
|
}
|
|
result["errors"].append(f"访问令牌获取失败: {e}")
|
|
|
|
# 2. 检查应用权限
|
|
try:
|
|
app_token = self.feishu_config.get("app_token")
|
|
table_id = self.feishu_config.get("table_id")
|
|
|
|
if not app_token or not table_id:
|
|
result["errors"].append("缺少app_token或table_id配置")
|
|
return result
|
|
|
|
# 尝试获取表格信息
|
|
table_info = self._get_table_info(app_token, table_id)
|
|
if table_info:
|
|
result["checks"]["table_access"] = {
|
|
"status": "success",
|
|
"message": "可以访问表格"
|
|
}
|
|
else:
|
|
result["checks"]["table_access"] = {
|
|
"status": "failed",
|
|
"message": "无法访问表格"
|
|
}
|
|
result["errors"].append("无法访问表格")
|
|
|
|
except Exception as e:
|
|
result["checks"]["table_access"] = {
|
|
"status": "failed",
|
|
"message": f"表格访问失败: {e}"
|
|
}
|
|
result["errors"].append(f"表格访问失败: {e}")
|
|
|
|
# 3. 检查记录读取权限
|
|
try:
|
|
records = self.client.get_table_records(app_token, table_id, page_size=1)
|
|
if records.get("code") == 0:
|
|
result["checks"]["read_records"] = {
|
|
"status": "success",
|
|
"message": "可以读取记录"
|
|
}
|
|
else:
|
|
result["checks"]["read_records"] = {
|
|
"status": "failed",
|
|
"message": f"读取记录失败: {records.get('msg', '未知错误')}"
|
|
}
|
|
result["errors"].append(f"读取记录失败: {records.get('msg', '未知错误')}")
|
|
except Exception as e:
|
|
result["checks"]["read_records"] = {
|
|
"status": "failed",
|
|
"message": f"读取记录失败: {e}"
|
|
}
|
|
result["errors"].append(f"读取记录失败: {e}")
|
|
|
|
# 4. 检查记录更新权限
|
|
try:
|
|
# 先获取一条记录进行测试
|
|
records = self.client.get_table_records(app_token, table_id, page_size=1)
|
|
if records.get("code") == 0 and records.get("data", {}).get("items"):
|
|
test_record = records["data"]["items"][0]
|
|
record_id = test_record["record_id"]
|
|
|
|
# 尝试更新一个测试字段
|
|
update_result = self.client.update_table_record(
|
|
app_token,
|
|
table_id,
|
|
record_id,
|
|
{"测试字段": "权限测试"}
|
|
)
|
|
|
|
if update_result.get("code") == 0:
|
|
result["checks"]["update_records"] = {
|
|
"status": "success",
|
|
"message": "可以更新记录"
|
|
}
|
|
else:
|
|
result["checks"]["update_records"] = {
|
|
"status": "failed",
|
|
"message": f"更新记录失败: {update_result.get('msg', '未知错误')}"
|
|
}
|
|
result["errors"].append(f"更新记录失败: {update_result.get('msg', '未知错误')}")
|
|
else:
|
|
result["checks"]["update_records"] = {
|
|
"status": "failed",
|
|
"message": "没有记录可用于测试更新权限"
|
|
}
|
|
result["errors"].append("没有记录可用于测试更新权限")
|
|
|
|
except Exception as e:
|
|
result["checks"]["update_records"] = {
|
|
"status": "failed",
|
|
"message": f"更新记录测试失败: {e}"
|
|
}
|
|
result["errors"].append(f"更新记录测试失败: {e}")
|
|
|
|
# 5. 检查AI建议字段权限
|
|
try:
|
|
# 检查AI建议字段是否存在
|
|
table_fields = self._get_table_fields(app_token, table_id)
|
|
if table_fields:
|
|
ai_field_exists = any(
|
|
field.get("field_name") == "AI建议"
|
|
for field in table_fields.get("data", {}).get("items", [])
|
|
)
|
|
|
|
if ai_field_exists:
|
|
result["checks"]["ai_field"] = {
|
|
"status": "success",
|
|
"message": "AI建议字段存在"
|
|
}
|
|
else:
|
|
result["checks"]["ai_field"] = {
|
|
"status": "warning",
|
|
"message": "AI建议字段不存在"
|
|
}
|
|
result["recommendations"].append("请在飞书表格中添加'AI建议'字段")
|
|
else:
|
|
result["checks"]["ai_field"] = {
|
|
"status": "failed",
|
|
"message": "无法获取表格字段信息"
|
|
}
|
|
result["errors"].append("无法获取表格字段信息")
|
|
|
|
except Exception as e:
|
|
result["checks"]["ai_field"] = {
|
|
"status": "failed",
|
|
"message": f"检查AI建议字段失败: {e}"
|
|
}
|
|
result["errors"].append(f"检查AI建议字段失败: {e}")
|
|
|
|
# 生成建议
|
|
self._generate_recommendations(result)
|
|
|
|
# 判断整体状态
|
|
failed_checks = [check for check in result["checks"].values()
|
|
if check["status"] == "failed"]
|
|
if not failed_checks:
|
|
result["success"] = True
|
|
|
|
return result
|
|
|
|
def _get_table_info(self, app_token: str, table_id: str) -> Dict[str, Any]:
|
|
"""获取表格信息"""
|
|
try:
|
|
url = f"{self.client.base_url}/bitable/v1/apps/{app_token}/tables/{table_id}"
|
|
return self.client._make_request("GET", url)
|
|
except Exception as e:
|
|
logger.error(f"获取表格信息失败: {e}")
|
|
return None
|
|
|
|
def _get_table_fields(self, app_token: str, table_id: str) -> Dict[str, Any]:
|
|
"""获取表格字段信息"""
|
|
try:
|
|
url = f"{self.client.base_url}/bitable/v1/apps/{app_token}/tables/{table_id}/fields"
|
|
return self.client._make_request("GET", url)
|
|
except Exception as e:
|
|
logger.error(f"获取表格字段失败: {e}")
|
|
return None
|
|
|
|
def _generate_recommendations(self, result: Dict[str, Any]):
|
|
"""生成修复建议"""
|
|
recommendations = result["recommendations"]
|
|
|
|
# 基于检查结果生成建议
|
|
if "access_token" in result["checks"] and result["checks"]["access_token"]["status"] == "failed":
|
|
recommendations.append("检查飞书应用的app_id和app_secret是否正确")
|
|
recommendations.append("确认飞书应用已启用并获取了必要的权限")
|
|
|
|
if "table_access" in result["checks"] and result["checks"]["table_access"]["status"] == "failed":
|
|
recommendations.append("检查app_token和table_id是否正确")
|
|
recommendations.append("确认应用有访问该表格的权限")
|
|
|
|
if "update_records" in result["checks"] and result["checks"]["update_records"]["status"] == "failed":
|
|
recommendations.append("检查飞书应用是否有'编辑'权限")
|
|
recommendations.append("确认表格没有被锁定或只读")
|
|
recommendations.append("检查应用是否被添加到表格的协作者中")
|
|
|
|
if "ai_field" in result["checks"] and result["checks"]["ai_field"]["status"] == "warning":
|
|
recommendations.append("在飞书表格中添加'AI建议'字段")
|
|
recommendations.append("确保字段类型为'多行文本'或'单行文本'")
|
|
|
|
# 通用建议
|
|
if result["errors"]:
|
|
recommendations.append("查看飞书开放平台文档了解权限配置")
|
|
recommendations.append("联系飞书管理员确认应用权限设置")
|
|
|
|
def get_permission_summary(self) -> str:
|
|
"""获取权限检查摘要"""
|
|
result = self.check_permissions()
|
|
|
|
summary = "飞书权限检查结果:\n"
|
|
summary += f"整体状态: {'✅ 正常' if result['success'] else '❌ 异常'}\n\n"
|
|
|
|
summary += "检查项目:\n"
|
|
for check_name, check_result in result["checks"].items():
|
|
status_icon = "✅" if check_result["status"] == "success" else "⚠️" if check_result["status"] == "warning" else "❌"
|
|
summary += f" {status_icon} {check_name}: {check_result['message']}\n"
|
|
|
|
if result["recommendations"]:
|
|
summary += "\n修复建议:\n"
|
|
for i, rec in enumerate(result["recommendations"], 1):
|
|
summary += f" {i}. {rec}\n"
|
|
|
|
if result["errors"]:
|
|
summary += "\n错误信息:\n"
|
|
for i, error in enumerate(result["errors"], 1):
|
|
summary += f" {i}. {error}\n"
|
|
|
|
return summary
|