feat: 添加飞书tenant_access_token自动获取功能
- 在FeishuSheetsClient中添加_get_tenant_access_token()方法 - 实现token自动缓存和刷新机制(提前30分钟刷新) - 更新配置类支持FEISHU_APP_ID和FEISHU_APP_SECRET - 从.env中移除FEISHU_TOKEN,完全使用应用凭证 - 更新report.py和gui.py支持新的配置检查逻辑 - 更新FeishuScheduleManager配置检查逻辑 - 更新文档和示例文件说明新的配置方式 系统现在支持两种认证方式: 1. 推荐:使用应用凭证(FEISHU_APP_ID + FEISHU_APP_SECRET) 2. 备选:使用手动token(FEISHU_TOKEN) 所有功能测试通过,系统能自动获取、缓存和刷新token。
This commit is contained in:
@@ -5,5 +5,12 @@ CONFLUENCE_CONTENT_ID=155764524
|
||||
|
||||
# 飞书表格配置
|
||||
FEISHU_BASE_URL=https://open.feishu.cn/open-apis/sheets/v3
|
||||
FEISHU_TOKEN=your-feishu-api-token
|
||||
FEISHU_SPREADSHEET_TOKEN=EgNPssi2ghZ7BLtGiTxcIBUmnVh
|
||||
|
||||
# 飞书应用凭证(推荐方式,自动获取tenant_access_token)
|
||||
# 创建飞书自建应用后获取app_id和app_secret
|
||||
FEISHU_APP_ID=your-feishu-app-id
|
||||
FEISHU_APP_SECRET=your-feishu-app-secret
|
||||
|
||||
# 备选:手动配置token(不推荐,token会过期)
|
||||
# FEISHU_TOKEN=your-feishu-api-token
|
||||
|
||||
40
README.md
40
README.md
@@ -75,9 +75,16 @@ CONFLUENCE_CONTENT_ID=155764524
|
||||
|
||||
# 飞书表格配置(用于获取排班人员信息)
|
||||
FEISHU_BASE_URL=https://open.feishu.cn/open-apis/sheets/v3
|
||||
FEISHU_TOKEN=your-feishu-api-token
|
||||
FEISHU_SPREADSHEET_TOKEN=EgNPssi2ghZ7BLtGiTxcIBUmnVh
|
||||
|
||||
# 飞书应用凭证(推荐方式,自动获取tenant_access_token)
|
||||
# 创建飞书自建应用后获取app_id和app_secret
|
||||
FEISHU_APP_ID=your-feishu-app-id
|
||||
FEISHU_APP_SECRET=your-feishu-app-secret
|
||||
|
||||
# 备选:手动配置token(不推荐,token会过期)
|
||||
# FEISHU_TOKEN=your-feishu-api-token
|
||||
|
||||
# 数据库配置
|
||||
DATABASE_PATH=data/daily_logs.db
|
||||
|
||||
@@ -205,10 +212,29 @@ GUI 功能:
|
||||
- **`manager.py`** - 内容管理器,提供高级内容管理功能
|
||||
|
||||
### 飞书模块 (`src/feishu/`)
|
||||
- **`client.py`** - 飞书 API 客户端
|
||||
- **`client.py`** - 飞书 API 客户端,支持自动获取和刷新tenant_access_token
|
||||
- **`parser.py`** - 排班数据解析器
|
||||
- **`manager.py`** - 飞书排班管理器,缓存和刷新排班信息
|
||||
|
||||
#### Token 自动获取机制
|
||||
飞书模块现在支持两种认证方式:
|
||||
1. **推荐方式**:使用应用凭证(FEISHU_APP_ID + FEISHU_APP_SECRET)
|
||||
- 系统会自动调用飞书API获取tenant_access_token
|
||||
- token有效期2小时,系统会在过期前30分钟自动刷新
|
||||
- 无需手动管理token过期问题
|
||||
|
||||
2. **备选方式**:使用手动配置的FEISHU_TOKEN
|
||||
- 兼容旧配置方式
|
||||
- token过期后需要手动更新
|
||||
- 不推荐长期使用
|
||||
|
||||
#### 如何获取应用凭证
|
||||
1. 登录飞书开放平台:https://open.feishu.cn/
|
||||
2. 创建自建应用
|
||||
3. 在"凭证与基础信息"中获取App ID和App Secret
|
||||
4. 为应用添加"获取tenant_access_token"权限
|
||||
5. 将应用发布到企业(仅自建应用需要)
|
||||
|
||||
### 数据库模块 (`src/database/`)
|
||||
- **`base.py`** - 数据库基类,提供统一的连接管理
|
||||
- **`daily_logs.py`** - 每日交接班日志数据库
|
||||
@@ -271,7 +297,15 @@ python3 main.py report-today
|
||||
1. **连接失败**: 检查 `.env` 文件中的 API 令牌和 URL
|
||||
2. **数据库错误**: 确保 `data/` 目录存在且有写入权限
|
||||
3. **解析错误**: 检查 Confluence 页面结构是否发生变化
|
||||
4. **飞书数据获取失败**: 验证飞书表格权限和 token 有效性
|
||||
4. **飞书数据获取失败**:
|
||||
- 验证飞书表格权限
|
||||
- 检查应用凭证是否正确(FEISHU_APP_ID + FEISHU_APP_SECRET)
|
||||
- 确认应用已发布到企业(自建应用需要)
|
||||
- 检查网络连接是否能访问飞书API
|
||||
5. **飞书token获取失败**:
|
||||
- 确认应用有"获取tenant_access_token"权限
|
||||
- 检查app_id和app_secret是否正确
|
||||
- 查看日志文件获取详细错误信息
|
||||
|
||||
### 日志级别
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ class Config:
|
||||
FEISHU_BASE_URL = os.getenv('FEISHU_BASE_URL', 'https://open.feishu.cn/open-apis/sheets/v3')
|
||||
FEISHU_TOKEN = os.getenv('FEISHU_TOKEN')
|
||||
FEISHU_SPREADSHEET_TOKEN = os.getenv('FEISHU_SPREADSHEET_TOKEN')
|
||||
FEISHU_APP_ID = os.getenv('FEISHU_APP_ID')
|
||||
FEISHU_APP_SECRET = os.getenv('FEISHU_APP_SECRET')
|
||||
|
||||
# 数据库配置
|
||||
DATABASE_PATH = os.getenv('DATABASE_PATH', 'data/daily_logs.db')
|
||||
@@ -70,8 +72,17 @@ class Config:
|
||||
errors.append("CONFLUENCE_CONTENT_ID 未配置")
|
||||
|
||||
# 检查飞书配置(可选,但建议配置)
|
||||
if not cls.FEISHU_TOKEN:
|
||||
print("警告: FEISHU_TOKEN 未配置,排班功能将不可用")
|
||||
has_feishu_token = bool(cls.FEISHU_TOKEN)
|
||||
has_app_credentials = bool(cls.FEISHU_APP_ID and cls.FEISHU_APP_SECRET)
|
||||
|
||||
if not has_feishu_token and not has_app_credentials:
|
||||
print("警告: 飞书认证未配置,排班功能将不可用")
|
||||
print(" 请配置 FEISHU_TOKEN 或 FEISHU_APP_ID + FEISHU_APP_SECRET")
|
||||
elif has_app_credentials:
|
||||
print("信息: 使用飞书应用凭证自动获取token")
|
||||
elif has_feishu_token:
|
||||
print("信息: 使用手动配置的FEISHU_TOKEN")
|
||||
|
||||
if not cls.FEISHU_SPREADSHEET_TOKEN:
|
||||
print("警告: FEISHU_SPREADSHEET_TOKEN 未配置,排班功能将不可用")
|
||||
|
||||
@@ -88,7 +99,21 @@ class Config:
|
||||
"""打印配置摘要"""
|
||||
print("配置摘要:")
|
||||
print(f" Confluence: {'已配置' if cls.CONFLUENCE_BASE_URL else '未配置'}")
|
||||
print(f" 飞书: {'已配置' if cls.FEISHU_TOKEN else '未配置'}")
|
||||
|
||||
# 飞书配置详情
|
||||
has_feishu_token = bool(cls.FEISHU_TOKEN)
|
||||
has_app_credentials = bool(cls.FEISHU_APP_ID and cls.FEISHU_APP_SECRET)
|
||||
has_spreadsheet_token = bool(cls.FEISHU_SPREADSHEET_TOKEN)
|
||||
|
||||
if has_app_credentials:
|
||||
feishu_status = f"应用凭证 (ID: {cls.FEISHU_APP_ID[:8]}...)"
|
||||
elif has_feishu_token:
|
||||
feishu_status = "手动token"
|
||||
else:
|
||||
feishu_status = "未配置"
|
||||
|
||||
print(f" 飞书认证: {feishu_status}")
|
||||
print(f" 飞书表格: {'已配置' if has_spreadsheet_token else '未配置'}")
|
||||
print(f" 数据库路径: {cls.DATABASE_PATH}")
|
||||
print(f" 每日目标TEU: {cls.DAILY_TARGET_TEU}")
|
||||
print(f" 排班刷新天数: {cls.SCHEDULE_REFRESH_DAYS}")
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
"""
|
||||
飞书表格 API 客户端模块
|
||||
统一版本,支持月度表格和年度表格
|
||||
支持自动获取和刷新 tenant_access_token
|
||||
"""
|
||||
import requests
|
||||
from typing import Dict, List, Optional
|
||||
import time
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
import logging
|
||||
|
||||
from src.config import config
|
||||
@@ -22,31 +24,146 @@ class FeishuSheetsClient:
|
||||
"""飞书表格 API 客户端"""
|
||||
|
||||
def __init__(self, base_url: Optional[str] = None, token: Optional[str] = None,
|
||||
spreadsheet_token: Optional[str] = None):
|
||||
spreadsheet_token: Optional[str] = None, app_id: Optional[str] = None,
|
||||
app_secret: Optional[str] = None):
|
||||
"""
|
||||
初始化客户端
|
||||
|
||||
参数:
|
||||
base_url: 飞书 API 基础URL,如果为None则使用配置
|
||||
token: Bearer 认证令牌,如果为None则使用配置
|
||||
token: Bearer 认证令牌,如果为None则使用配置或自动获取
|
||||
spreadsheet_token: 表格 token,如果为None则使用配置
|
||||
app_id: 飞书应用ID,用于获取tenant_access_token
|
||||
app_secret: 飞书应用密钥,用于获取tenant_access_token
|
||||
"""
|
||||
self.base_url = (base_url or config.FEISHU_BASE_URL).rstrip('/')
|
||||
self.spreadsheet_token = spreadsheet_token or config.FEISHU_SPREADSHEET_TOKEN
|
||||
self.token = token or config.FEISHU_TOKEN
|
||||
self.app_id = app_id or config.FEISHU_APP_ID
|
||||
self.app_secret = app_secret or config.FEISHU_APP_SECRET
|
||||
|
||||
self.headers = {
|
||||
'Authorization': f'Bearer {self.token}',
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
# Token管理相关属性
|
||||
self._token = token or config.FEISHU_TOKEN
|
||||
self._token_expire_time = 0 # token过期时间戳
|
||||
self._token_obtained_time = 0 # token获取时间戳
|
||||
|
||||
# 使用 Session 重用连接
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update(self.headers)
|
||||
self.session.timeout = config.REQUEST_TIMEOUT
|
||||
|
||||
# 初始化headers
|
||||
self._update_session_headers()
|
||||
|
||||
logger.debug(f"飞书客户端初始化完成,基础URL: {self.base_url}")
|
||||
logger.debug(f"使用应用ID: {self.app_id[:8]}... 如果配置" if self.app_id else "未配置应用ID")
|
||||
|
||||
def _update_session_headers(self):
|
||||
"""更新session的headers"""
|
||||
if self._token:
|
||||
self.session.headers.update({
|
||||
'Authorization': f'Bearer {self._token}',
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
})
|
||||
else:
|
||||
# 如果没有token,移除Authorization头
|
||||
if 'Authorization' in self.session.headers:
|
||||
del self.session.headers['Authorization']
|
||||
|
||||
def _get_tenant_access_token(self) -> Tuple[str, int]:
|
||||
"""
|
||||
获取tenant_access_token
|
||||
|
||||
返回:
|
||||
(token, expire_time): token字符串和过期时间(秒)
|
||||
|
||||
异常:
|
||||
requests.exceptions.RequestException: 网络请求失败
|
||||
ValueError: API返回错误
|
||||
"""
|
||||
if not self.app_id or not self.app_secret:
|
||||
raise ValueError("未配置飞书应用ID和密钥,无法获取tenant_access_token")
|
||||
|
||||
token_url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
|
||||
|
||||
payload = {
|
||||
"app_id": self.app_id,
|
||||
"app_secret": self.app_secret
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json; charset=utf-8"
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info(f"正在获取tenant_access_token,应用ID: {self.app_id[:8]}...")
|
||||
response = requests.post(token_url, json=payload, headers=headers, timeout=config.REQUEST_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
if data.get('code') != 0:
|
||||
error_msg = f"获取tenant_access_token失败: {data.get('msg')}"
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
||||
token = data.get('tenant_access_token')
|
||||
expire = data.get('expire', 7200) # 默认2小时
|
||||
|
||||
if not token:
|
||||
raise ValueError("API返回的token为空")
|
||||
|
||||
logger.info(f"成功获取tenant_access_token,有效期: {expire}秒")
|
||||
return token, expire
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"获取tenant_access_token网络请求失败: {e}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"获取tenant_access_token失败: {e}")
|
||||
raise
|
||||
|
||||
def _ensure_valid_token(self):
|
||||
"""
|
||||
确保当前token有效,如果无效则重新获取
|
||||
|
||||
返回:
|
||||
bool: token是否有效
|
||||
"""
|
||||
current_time = time.time()
|
||||
|
||||
# 如果有手动配置的token,直接使用
|
||||
if config.FEISHU_TOKEN and self._token == config.FEISHU_TOKEN:
|
||||
logger.debug("使用手动配置的FEISHU_TOKEN")
|
||||
return True
|
||||
|
||||
# 检查token是否过期(提前30分钟刷新)
|
||||
if self._token and self._token_expire_time > 0:
|
||||
time_remaining = self._token_expire_time - current_time
|
||||
if time_remaining > 1800: # 剩余时间大于30分钟
|
||||
logger.debug(f"token仍然有效,剩余时间: {int(time_remaining)}秒")
|
||||
return True
|
||||
elif time_remaining > 0: # 剩余时间小于30分钟但大于0
|
||||
logger.info(f"token即将过期,剩余时间: {int(time_remaining)}秒,重新获取")
|
||||
else: # 已过期
|
||||
logger.info("token已过期,重新获取")
|
||||
|
||||
# 需要获取新token
|
||||
try:
|
||||
token, expire = self._get_tenant_access_token()
|
||||
self._token = token
|
||||
self._token_obtained_time = current_time
|
||||
self._token_expire_time = current_time + expire
|
||||
self._update_session_headers()
|
||||
logger.info(f"token获取成功,将在 {expire} 秒后过期")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"获取token失败: {e}")
|
||||
# 如果配置了备用token,尝试使用
|
||||
if config.FEISHU_TOKEN and config.FEISHU_TOKEN != self._token:
|
||||
logger.warning("使用备用FEISHU_TOKEN")
|
||||
self._token = config.FEISHU_TOKEN
|
||||
self._update_session_headers()
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_sheets_info(self) -> List[Dict[str, str]]:
|
||||
"""
|
||||
@@ -59,6 +176,10 @@ class FeishuSheetsClient:
|
||||
requests.exceptions.RequestException: 网络请求失败
|
||||
ValueError: API返回错误
|
||||
"""
|
||||
# 确保token有效
|
||||
if not self._ensure_valid_token():
|
||||
raise FeishuClientError("无法获取有效的飞书token")
|
||||
|
||||
url = f'{self.base_url}/spreadsheets/{self.spreadsheet_token}/sheets/query'
|
||||
|
||||
try:
|
||||
@@ -104,6 +225,10 @@ class FeishuSheetsClient:
|
||||
requests.exceptions.RequestException: 网络请求失败
|
||||
ValueError: API返回错误
|
||||
"""
|
||||
# 确保token有效
|
||||
if not self._ensure_valid_token():
|
||||
raise FeishuClientError("无法获取有效的飞书token")
|
||||
|
||||
if range_ is None:
|
||||
range_ = config.SHEET_RANGE
|
||||
|
||||
@@ -134,6 +259,26 @@ class FeishuSheetsClient:
|
||||
logger.error(f"解析表格数据失败: {e}, sheet_id: {sheet_id}")
|
||||
raise
|
||||
|
||||
def get_token_info(self) -> Dict[str, any]:
|
||||
"""
|
||||
获取当前token信息
|
||||
|
||||
返回:
|
||||
token信息字典
|
||||
"""
|
||||
current_time = time.time()
|
||||
time_remaining = self._token_expire_time - current_time if self._token_expire_time > 0 else 0
|
||||
|
||||
return {
|
||||
'has_token': bool(self._token),
|
||||
'token_preview': self._token[:20] + '...' if self._token and len(self._token) > 20 else self._token,
|
||||
'token_obtained_time': self._token_obtained_time,
|
||||
'token_expire_time': self._token_expire_time,
|
||||
'time_remaining': max(0, time_remaining),
|
||||
'using_app_credentials': bool(self.app_id and self.app_secret),
|
||||
'using_manual_token': bool(config.FEISHU_TOKEN and self._token == config.FEISHU_TOKEN)
|
||||
}
|
||||
|
||||
def test_connection(self) -> bool:
|
||||
"""
|
||||
测试飞书连接是否正常
|
||||
@@ -142,6 +287,12 @@ class FeishuSheetsClient:
|
||||
连接是否正常
|
||||
"""
|
||||
try:
|
||||
# 首先测试token获取
|
||||
if not self._ensure_valid_token():
|
||||
logger.error("无法获取有效的飞书token")
|
||||
return False
|
||||
|
||||
# 然后测试表格访问
|
||||
sheets = self.get_sheets_info()
|
||||
if sheets:
|
||||
logger.info(f"飞书连接测试成功,找到 {len(sheets)} 个表格")
|
||||
@@ -153,6 +304,27 @@ class FeishuSheetsClient:
|
||||
logger.error(f"飞书连接测试失败: {e}")
|
||||
return False
|
||||
|
||||
def refresh_token(self) -> bool:
|
||||
"""
|
||||
强制刷新token
|
||||
|
||||
返回:
|
||||
刷新是否成功
|
||||
"""
|
||||
try:
|
||||
logger.info("强制刷新token...")
|
||||
current_time = time.time()
|
||||
token, expire = self._get_tenant_access_token()
|
||||
self._token = token
|
||||
self._token_obtained_time = current_time
|
||||
self._token_expire_time = current_time + expire
|
||||
self._update_session_headers()
|
||||
logger.info(f"token刷新成功,将在 {expire} 秒后过期")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"强制刷新token失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 测试代码
|
||||
@@ -164,8 +336,17 @@ if __name__ == '__main__':
|
||||
# 测试连接
|
||||
client = FeishuSheetsClient()
|
||||
|
||||
# 显示token信息
|
||||
token_info = client.get_token_info()
|
||||
print("当前token信息:")
|
||||
print(f" 是否有token: {token_info['has_token']}")
|
||||
print(f" token预览: {token_info['token_preview']}")
|
||||
print(f" 剩余时间: {int(token_info['time_remaining'])}秒")
|
||||
print(f" 使用应用凭证: {token_info['using_app_credentials']}")
|
||||
print(f" 使用手动token: {token_info['using_manual_token']}")
|
||||
|
||||
if client.test_connection():
|
||||
print("飞书连接测试成功")
|
||||
print("\n飞书连接测试成功")
|
||||
|
||||
# 获取表格信息
|
||||
sheets = client.get_sheets_info()
|
||||
@@ -177,6 +358,10 @@ if __name__ == '__main__':
|
||||
sheet_id = sheets[0]['sheet_id']
|
||||
data = client.get_sheet_data(sheet_id, 'A1:C5')
|
||||
print(f"获取到表格数据,版本: {data.get('revision', '未知')}")
|
||||
|
||||
# 再次显示token信息
|
||||
token_info = client.get_token_info()
|
||||
print(f"\n测试后token剩余时间: {int(token_info['time_remaining'])}秒")
|
||||
else:
|
||||
print("飞书连接测试失败")
|
||||
print("\n飞书连接测试失败")
|
||||
sys.exit(1)
|
||||
@@ -42,8 +42,17 @@ class FeishuScheduleManager:
|
||||
|
||||
def _check_config(self, token: Optional[str], spreadsheet_token: Optional[str]) -> None:
|
||||
"""检查必要配置"""
|
||||
if not token and not config.FEISHU_TOKEN:
|
||||
logger.warning("飞书令牌未配置,排班功能将不可用")
|
||||
# 检查是否有任何可用的认证方式
|
||||
has_token = bool(token or config.FEISHU_TOKEN)
|
||||
has_app_credentials = bool(config.FEISHU_APP_ID and config.FEISHU_APP_SECRET)
|
||||
|
||||
if not has_token and not has_app_credentials:
|
||||
logger.warning("飞书认证未配置,排班功能将不可用")
|
||||
logger.warning("请配置 FEISHU_TOKEN 或 FEISHU_APP_ID + FEISHU_APP_SECRET")
|
||||
elif has_app_credentials:
|
||||
logger.info("使用飞书应用凭证自动获取token")
|
||||
elif has_token:
|
||||
logger.info("使用手动配置的FEISHU_TOKEN")
|
||||
|
||||
if not spreadsheet_token and not config.FEISHU_SPREADSHEET_TOKEN:
|
||||
logger.warning("飞书表格令牌未配置,排班功能将不可用")
|
||||
|
||||
@@ -487,7 +487,13 @@ class OrbitInGUI:
|
||||
|
||||
try:
|
||||
# 1. 检查飞书配置,如果配置完整则刷新排班信息
|
||||
if config.FEISHU_TOKEN and config.FEISHU_SPREADSHEET_TOKEN:
|
||||
# 支持应用凭证和手动token两种方式
|
||||
has_feishu_config = bool(config.FEISHU_SPREADSHEET_TOKEN) and (
|
||||
bool(config.FEISHU_APP_ID and config.FEISHU_APP_SECRET) or
|
||||
bool(config.FEISHU_TOKEN)
|
||||
)
|
||||
|
||||
if has_feishu_config:
|
||||
try:
|
||||
self.log_message("正在刷新排班信息...")
|
||||
self.logger.info("正在刷新排班信息...")
|
||||
@@ -507,6 +513,7 @@ class OrbitInGUI:
|
||||
else:
|
||||
self.log_message("飞书配置不完整,跳过排班信息刷新")
|
||||
self.logger.warning("飞书配置不完整,跳过排班信息刷新")
|
||||
self.logger.warning("需要配置 FEISHU_SPREADSHEET_TOKEN 和 (FEISHU_APP_ID+FEISHU_APP_SECRET 或 FEISHU_TOKEN)")
|
||||
|
||||
# 2. 尝试获取最新的作业数据
|
||||
self.log_message("正在尝试获取最新作业数据...")
|
||||
|
||||
@@ -181,9 +181,15 @@ class DailyReportGenerator:
|
||||
班次人员字典
|
||||
"""
|
||||
try:
|
||||
# 检查飞书配置
|
||||
if not config.FEISHU_TOKEN or not config.FEISHU_SPREADSHEET_TOKEN:
|
||||
# 检查飞书配置(支持应用凭证和手动token两种方式)
|
||||
has_feishu_config = bool(config.FEISHU_SPREADSHEET_TOKEN) and (
|
||||
bool(config.FEISHU_APP_ID and config.FEISHU_APP_SECRET) or
|
||||
bool(config.FEISHU_TOKEN)
|
||||
)
|
||||
|
||||
if not has_feishu_config:
|
||||
logger.warning("飞书配置不完整,跳过排班信息获取")
|
||||
logger.warning("需要配置 FEISHU_SPREADSHEET_TOKEN 和 (FEISHU_APP_ID+FEISHU_APP_SECRET 或 FEISHU_TOKEN)")
|
||||
return self._empty_personnel()
|
||||
|
||||
# 初始化飞书排班管理器
|
||||
|
||||
Reference in New Issue
Block a user