mirror of
https://github.com/larksuite/cli.git
synced 2026-08-03 08:32:46 +08:00
Compare commits
1 Commits
feat/chat_
...
feat/slide
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dae3e5501d |
@@ -1,85 +0,0 @@
|
||||
// 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
|
||||
},
|
||||
}
|
||||
@@ -18,6 +18,5 @@ func Shortcuts() []common.Shortcut {
|
||||
CalendarMeeting,
|
||||
CalendarSearchEvent,
|
||||
CalendarGet,
|
||||
CalendarJoin,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ 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` — 单日程详情
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# 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 场景**:需要当前身份确实收到过该卡片(在卡片所在的群里),这是「收到卡片」的凭证校验。
|
||||
- **分享链接场景**:链接本身即分享凭证,不做「在群里」校验;但分享人是否有权分享仍由服务端校验,无权限会返回加入失败。
|
||||
- 链接可以直接粘贴完整 URL,CLI/服务端会自动提取其中的 `token`。
|
||||
|
||||
## 参考
|
||||
|
||||
- [lark-calendar](../SKILL.md) -- skill 入口与路由
|
||||
- [lark-calendar-rsvp](lark-calendar-rsvp.md) -- 回复(接受/拒绝/待定)日程
|
||||
@@ -1464,6 +1464,7 @@
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
表格元素, 用于展示结构化数据
|
||||
宽高分配规则参考 HTML table 的整体值 / 子项值处理逻辑, 但在 SXSD 中做确定化约束, 以保证跨端实现一致。
|
||||
边框规则:
|
||||
- 后设置优先:相邻单元格线条只有一个颜色, 如果均设置, 则右下单元格的设置覆盖左上单元格
|
||||
- 不设置边框属性时使用默认样式
|
||||
@@ -1476,6 +1477,8 @@
|
||||
- id: 表格唯一标识符(可选)
|
||||
- topLeftX/topLeftY: 左上角坐标
|
||||
- flipX/flipY: 水平/垂直翻转
|
||||
- width: 表格目标总宽度(可选)。若设置, 优先用于为未填写列宽的列分配剩余宽度; 当所有列宽均为空时, 所有列均分该值; 当所有列均已填写且该值大于已填写列宽总和时, 多出空间继续分配给现有列, 默认按各列当前宽度作为权重分配; 当已填写列宽之和超过或无法容纳该值时, 保留已填写列宽, 并以最终列宽总和回写 table.width
|
||||
- height: 表格目标总高度(可选)。若设置, 优先用于为未填写行高的行分配剩余高度; 当所有行高均为空时, 所有行均分该值; 当所有行均已填写且该值大于已填写行高总和时, 多出空间继续分配给现有行, 默认按各行当前高度作为权重分配; 当已填写行高之和超过或无法容纳该值时, 保留已填写行高, 并以最终行高总和回写 table.height
|
||||
table 子元素:
|
||||
- colgroup: 列组元素, 用于定义列的宽度
|
||||
- tr: 行元素, 包含多个单元格
|
||||
@@ -1484,10 +1487,10 @@
|
||||
- col: 列元素
|
||||
col 属性:
|
||||
- span: 列跨数, 默认为1, 可选
|
||||
- width: 列宽度, 默认值为110, 可选
|
||||
- width: 列宽度输入值, 默认值为110, 可选。无 table.width 时, 已填写列保持原值, 空列使用默认值; 有 table.width 时, 已填写列保持原值, 空列优先均分剩余宽度; 若不存在空列且 table.width 大于已填写列宽总和, 则多出空间按各列当前宽度作为权重分配到所有列; 若剩余宽度不足则空列回退为默认值, 并以最终列宽总和作为 table.width
|
||||
|
||||
tr 属性:
|
||||
- height: 行高, 默认为单元格高度
|
||||
- height: 行高输入值, 默认值为37, 可选。无 table.height 时, 已填写行保持原值, 空行使用默认值; 有 table.height 时, 已填写行保持原值, 空行优先均分剩余高度; 若不存在空行且 table.height 大于已填写行高总和, 则多出空间按各行当前高度作为权重分配到所有行; 若剩余高度不足则空行回退为默认值, 并以最终行高总和作为 table.height。若行高低于内容高度, 需要手动修改行高
|
||||
tr 子元素:
|
||||
- td: 单元格元素, 用于显示数据
|
||||
|
||||
@@ -1543,6 +1546,8 @@
|
||||
<xs:attribute name="topLeftY" type="sml:YType" use="required"/>
|
||||
<xs:attribute name="flipX" type="xs:boolean" use="optional" default="false"/>
|
||||
<xs:attribute name="flipY" type="xs:boolean" use="optional" default="false"/>
|
||||
<xs:attribute name="width" type="sml:PositiveSize" use="optional"/>
|
||||
<xs:attribute name="height" type="sml:PositiveSize" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
|
||||
@@ -248,6 +248,26 @@
|
||||
- `<tr>` 内为 `<td>`
|
||||
- `<td>` 内可放 `<content>`
|
||||
|
||||
`<table>` 可选设置 `width` 和 `height`,分别表示表格的目标总宽度和总高度:
|
||||
|
||||
```xml
|
||||
<table topLeftX="80" topLeftY="120" width="800" height="300">
|
||||
<colgroup>
|
||||
<col width="240"/>
|
||||
<col/>
|
||||
</colgroup>
|
||||
<tr height="80">
|
||||
<td><content textType="body"><p>表头 1</p></content></td>
|
||||
<td><content textType="body"><p>表头 2</p></content></td>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
- 已设置的列宽和行高优先保留;未设置的列宽、行高优先使用目标总宽度或总高度分配剩余空间。
|
||||
- 如果所有列宽或行高都未设置,则目标总宽度或总高度会在各列或各行之间分配。
|
||||
- 如果目标尺寸不足以容纳已设置的尺寸,则保留已设置值,并以最终列宽或行高总和为准。
|
||||
- 行高低于单元格内容高度时,需要手动增大行高。
|
||||
|
||||
### `<chart>`
|
||||
|
||||
图表元素必须至少包含:
|
||||
|
||||
Reference in New Issue
Block a user