Compare commits

...

1 Commits

Author SHA1 Message Date
zhangjun.1
c4ddf89d7b feat: chat query event and join 2026-07-28 17:26:17 +08:00
4 changed files with 137 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package calendar
import (
"context"
"strings"
"github.com/larksuite/cli/errs"
"github.com/larksuite/cli/shortcuts/common"
)
const joinCalendarEventPath = "/open-apis/calendar/v4/events/join"
func resolveJoinCredential(runtime *common.RuntimeContext) string {
if token := strings.TrimSpace(runtime.Str("join-token")); token != "" {
return token
}
return strings.TrimSpace(runtime.Str("share-link"))
}
var CalendarJoin = common.Shortcut{
Service: "calendar",
Command: "+join",
Description: "Join a calendar event via the encrypted join token from an RSVP/share card, or via a shared meeting/event link",
Risk: "write",
Scopes: []string{"calendar:calendar.event:writeonly"},
AuthTypes: []string{"user", "bot"},
HasFormat: false,
Flags: []common.Flag{
{Name: "join-token", Desc: "encrypted join token issued with the RSVP/share card"},
{Name: "share-link", Desc: "shared meeting/event link (…/calendar/share?token=xxx) or the bare share token"},
},
DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
return common.NewDryRunAPI().
POST(joinCalendarEventPath).
Body(map[string]interface{}{"join_token": resolveJoinCredential(runtime)})
},
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
if err := rejectCalendarAutoBotFallback(runtime); err != nil {
return err
}
token := strings.TrimSpace(runtime.Str("join-token"))
shareLink := strings.TrimSpace(runtime.Str("share-link"))
if token == "" && shareLink == "" {
return errs.NewValidationError(errs.SubtypeInvalidArgument,
"one of --join-token or --share-link is required").WithParam("--join-token")
}
if token != "" && shareLink != "" {
return errs.NewValidationError(errs.SubtypeInvalidArgument,
"--join-token and --share-link are mutually exclusive, pass only one").WithParam("--share-link")
}
if token != "" {
if err := common.RejectDangerousCharsTyped("--join-token", token); err != nil {
return err
}
}
if shareLink != "" {
if err := common.RejectDangerousCharsTyped("--share-link", shareLink); err != nil {
return err
}
}
return nil
},
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
credential := resolveJoinCredential(runtime)
data, err := runtime.CallAPITyped("POST",
joinCalendarEventPath,
nil,
map[string]interface{}{
"join_token": credential,
})
if err != nil {
return err
}
eventID, _ := data["event_id"].(string)
runtime.Out(map[string]interface{}{
"event_id": eventID,
}, nil)
return nil
},
}

View File

@@ -18,5 +18,6 @@ func Shortcuts() []common.Shortcut {
CalendarMeeting,
CalendarSearchEvent,
CalendarGet,
CalendarJoin,
}
}

View File

@@ -38,6 +38,7 @@ lark-cli calendar +agenda --as user
| [`+room-find`](references/lark-calendar-room-find.md) | 针对一个或多个**明确的**时间块查找可用会议室(无明确时间时禁止直接调用,需先走 +suggestion |
| [`+rsvp`](references/lark-calendar-rsvp.md) | 回复日程(接受/拒绝/待定) |
| [`+suggestion`](references/lark-calendar-suggestion.md) | 根据非明确时间或一段时间范围,推荐多个可用时间块方案 |
| [`+join`](references/lark-calendar-join.md) | 加入日程:用 RSVP/分享卡片的加入 token或分享会议/日程的链接加入 |
### `+get` — 单日程详情

View File

@@ -0,0 +1,50 @@
# calendar +join
加入一个日程(把当前身份加为参会人)。支持两种加入凭证,二选一:
1. **加入 token**:日历下发 RSVP 卡片 / 分享日程卡片时写入卡片的加密 `join_token`
2. **分享链接**:用户「分享会议」/「分享日程」得到的链接(形如 `…/calendar/share?token=xxx`),或链接里的 `token` 原始值。
两种凭证的加密方案不同服务端会自动识别并按对应逻辑加入CLI 只需把用户给到的那一个透传即可。
## 命令
```bash
# 用 RSVP/分享卡片里的加入 token 加入
lark-cli calendar +join --join-token <join_token>
# 用分享会议/日程的链接加入(可直接粘贴完整链接)
lark-cli calendar +join --share-link "https://xxx.feishu.cn/calendar/share?token=xxx"
# 也可以只传链接里的 token 原始值
lark-cli calendar +join --share-link <share_token>
# bot 身份加入
lark-cli calendar +join --share-link "https://xxx.feishu.cn/calendar/share?token=xxx" --as bot
```
## 参数
| 参数 | 必填 | 说明 |
|------|------|------|
| `--join-token <token>` | 二选一 | RSVP/分享卡片中下发的加密加入 token |
| `--share-link <link>` | 二选一 | 分享会议/日程的链接(`…/calendar/share?token=xxx`)或链接里的 `token` 原始值 |
| `--dry-run` | 否 | 预览 API 调用,不执行 |
- `--join-token``--share-link` **必须且只能提供一个**,同时给会报错。
## 返回
成功返回加入日程的 `event_id`
## 提示
- 支持 `--as user`(默认)和 `--as bot` 两种身份。
- **加入 token 场景**:需要当前身份确实收到过该卡片(在卡片所在的群里),这是「收到卡片」的凭证校验。
- **分享链接场景**:链接本身即分享凭证,不做「在群里」校验;但分享人是否有权分享仍由服务端校验,无权限会返回加入失败。
- 链接可以直接粘贴完整 URLCLI/服务端会自动提取其中的 `token`
## 参考
- [lark-calendar](../SKILL.md) -- skill 入口与路由
- [lark-calendar-rsvp](lark-calendar-rsvp.md) -- 回复(接受/拒绝/待定)日程