fix(synchronizer-feishu): 用户同步 NPE 因 status 字段缺失,需判空保护
- Dominant language
- Java
- Stars
- 2k
- Forks
- 410
- PR merge metrics
- No merged PRs in 30d
Description
### 问题描述
MaxKey 管理端「同步器 → 飞书」点击“同步”时:
- **部门能正常同步**,但**成员(用户)全部同步失败**;
- 前端提示“操作失败”,控制台报 `Cannot read properties of undefined (reading 'refresh')`;
- 后端日志:
```
java.lang.NullPointerException: Cannot invoke "org.dromara.maxkey.synchronizer.feishu.entity.FeishuUserStatus.isIs_activated()"
because the return value of "org.dromara.maxkey.synchronizer.feishu.entity.FeishuUsers.getStatus()" is null
at org.dromara.maxkey.synchronizer.feishu.FeishuUsersService.buildUserInfoByFieldMapper(FeishuUsersService.java:153)
at org.dromara.maxkey.synchronizer.feishu.FeishuUsersService.sync(FeishuUsersService.java:70)
```
### 复现步骤
1. 飞书开放平台创建应用,配置 `contact:user.base:readonly`(及所需通讯录权限)并**发布上线**;
2. 在 MaxKey 飞书同步器中填写 App ID / Secret;
3. 执行“立即同步”。Token 获取正常,部门可拉到,执行到用户同步时 NPE。
### 根因
MaxKey 4.1.12 同步用户调用的是:
```
GET https://open.feishu.cn/open-apis/contact/v3/users/find_by_department?department_id=&page_size=50
```
该 v3 接口当前返回的用户对象**不包含 `status` 字段**,实际返回形如:
```json
{
"code": 0,
"data": {
"items": [
{
"name": "...",
"email": "...",
"employee_no": "...",
"open_id": "...",
"union_id": "...",
"user_id": "..."
}
]
}
}
```
而 `FeishuUsersService.buildUserInfoByFieldMapper`(第 153 行)直接解引用了 `status`,未判空:
```java
if (user.getStatus().isIs_activated()) {
userInfo.setStatus(1); // 在职
} else {
userInfo.setStatus(2); // 离职/未激活
}
```
`getStatus()` 返回 null → `isIs_activated()` NPE → 用户同步中断。
### 建议修复
请官方对用户对象做空值保护,例如:
```java
FeishuUserStatus status = user.getStatus();
boolean activated = (status != null && status.isIs_activated());
userInfo.setStatus(activated ? 1 : 2);
```
并明确 `status` 缺失(该接口不返回)时的默认值——当前我们按“未激活”(status=2)处理。
### 影响范围 / 备注
- 版本:`maxkey-mgt` + `maxkey-synchronizer-feishu` **4.1.12**(`maxkeytop/maxkey-mgt:latest`);
- 仅在 `users/find_by_department` 这种“精简字段”接口下触发;若改用含 `status` 的完整用户接口(如 `users/{user_id}`)则不会 NPE;
- 因为要验证能否仅依赖该接口配置,是否应同步该精简接口回归更多字段(`status`)也可一并评估。
Contributor guide
Research direction
Start in FeishuUsersService.java at buildUserInfoByFieldMapper, around line 153, and inspect how FeishuUsers status is read during sync. Reproduce the Feishu users/find_by_department response with no status field, then verify that synchronization completes and missing status produces the intended inactive status (2) without an exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100