Skip to content

Commit 3514ee5

Browse files
feat: cli 支持记录分享 no-meego
Change-Id: Ie78da99096cc1fc8a4671d8178176f4c587466ba
1 parent 2a30124 commit 3514ee5

9 files changed

Lines changed: 265 additions & 1 deletion

shortcuts/base/base_shortcuts_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func TestShortcutsCatalog(t *testing.T) {
132132
"+table-list", "+table-get", "+table-create", "+table-update", "+table-delete",
133133
"+field-list", "+field-get", "+field-create", "+field-update", "+field-delete", "+field-search-options",
134134
"+view-list", "+view-get", "+view-create", "+view-delete", "+view-get-filter", "+view-set-filter", "+view-get-visible-fields", "+view-set-visible-fields", "+view-get-group", "+view-set-group", "+view-get-sort", "+view-set-sort", "+view-get-timebar", "+view-set-timebar", "+view-get-card", "+view-set-card", "+view-rename",
135-
"+record-list", "+record-search", "+record-get", "+record-upsert", "+record-batch-create", "+record-batch-update", "+record-upload-attachment", "+record-delete",
135+
"+record-list", "+record-search", "+record-get", "+record-upsert", "+record-batch-create", "+record-batch-update", "+record-share-link-create", "+record-share-link-batch-create", "+record-upload-attachment", "+record-delete",
136136
"+record-history-list",
137137
"+base-get", "+base-copy", "+base-create",
138138
"+role-create", "+role-delete", "+role-update", "+role-list", "+role-get", "+advperm-enable", "+advperm-disable",

shortcuts/base/record_ops.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,73 @@ func dryRunRecordHistoryList(_ context.Context, runtime *common.RuntimeContext)
112112
Set("base_token", runtime.Str("base-token"))
113113
}
114114

115+
func dryRunRecordShareBatch(_ context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
116+
recordIDs := deduplicateRecordIDs(runtime)
117+
return common.NewDryRunAPI().
118+
POST("/open-apis/base/v3/bases/:base_token/tables/:table_id/records/share_links/batch").
119+
Body(map[string]interface{}{"record_ids": recordIDs}).
120+
Set("base_token", runtime.Str("base-token")).
121+
Set("table_id", baseTableID(runtime))
122+
}
123+
124+
func dryRunRecordShare(_ context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
125+
return common.NewDryRunAPI().
126+
POST("/open-apis/base/v3/bases/:base_token/tables/:table_id/records/:record_id/share_links").
127+
Set("base_token", runtime.Str("base-token")).
128+
Set("table_id", baseTableID(runtime)).
129+
Set("record_id", runtime.Str("record-id"))
130+
}
131+
132+
func validateRecordShareBatch(runtime *common.RuntimeContext) error {
133+
recordIDs := deduplicateRecordIDs(runtime)
134+
if len(recordIDs) == 0 {
135+
return common.FlagErrorf("--record-ids is required and must not be empty")
136+
}
137+
if len(recordIDs) > maxShareBatchSize {
138+
return common.FlagErrorf("--record-ids exceeds maximum limit of %d (got %d)", maxShareBatchSize, len(recordIDs))
139+
}
140+
return nil
141+
}
142+
143+
func deduplicateRecordIDs(runtime *common.RuntimeContext) []string {
144+
raw := runtime.StrSlice("record-ids")
145+
seen := make(map[string]bool, len(raw))
146+
result := make([]string, 0, len(raw))
147+
for _, id := range raw {
148+
if id != "" && !seen[id] {
149+
seen[id] = true
150+
result = append(result, id)
151+
}
152+
}
153+
return result
154+
}
155+
156+
func executeRecordShareBatch(runtime *common.RuntimeContext) error {
157+
recordIDs := deduplicateRecordIDs(runtime)
158+
body := map[string]interface{}{
159+
"record_ids": recordIDs,
160+
}
161+
data, err := baseV3Call(runtime, "POST",
162+
baseV3Path("bases", runtime.Str("base-token"), "tables", baseTableID(runtime), "records", "share_links", "batch"),
163+
nil, body)
164+
if err != nil {
165+
return err
166+
}
167+
runtime.Out(data, nil)
168+
return nil
169+
}
170+
171+
func executeRecordShare(runtime *common.RuntimeContext) error {
172+
data, err := baseV3Call(runtime, "POST",
173+
baseV3Path("bases", runtime.Str("base-token"), "tables", baseTableID(runtime), "records", runtime.Str("record-id"), "share_links"),
174+
nil, nil)
175+
if err != nil {
176+
return err
177+
}
178+
runtime.Out(data, nil)
179+
return nil
180+
}
181+
115182
func validateRecordJSON(runtime *common.RuntimeContext) error {
116183
return nil
117184
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
2+
// SPDX-License-Identifier: MIT
3+
4+
package base
5+
6+
import (
7+
"context"
8+
9+
"github.com/larksuite/cli/shortcuts/common"
10+
)
11+
12+
const maxShareBatchSize = 100
13+
14+
var BaseRecordShareLinkBatchCreate = common.Shortcut{
15+
Service: "base",
16+
Command: "+record-share-link-batch-create",
17+
Description: "Batch generate record share links (max 100 records per request)",
18+
Risk: "read",
19+
Scopes: []string{"base:record:read"},
20+
AuthTypes: authTypes(),
21+
Flags: []common.Flag{
22+
baseTokenFlag(true),
23+
tableRefFlag(true),
24+
{Name: "record-ids", Type: "string_slice", Desc: "record IDs to generate share links for (comma-separated or repeatable, max 100)", Required: true},
25+
},
26+
Tips: []string{
27+
`Example: --base-token xxx --table-id tblxxx --record-ids rec001,rec002,rec003`,
28+
},
29+
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
30+
return validateRecordShareBatch(runtime)
31+
},
32+
DryRun: dryRunRecordShareBatch,
33+
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
34+
return executeRecordShareBatch(runtime)
35+
},
36+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
2+
// SPDX-License-Identifier: MIT
3+
4+
package base
5+
6+
import (
7+
"context"
8+
9+
"github.com/larksuite/cli/shortcuts/common"
10+
)
11+
12+
var BaseRecordShareLinkCreate = common.Shortcut{
13+
Service: "base",
14+
Command: "+record-share-link-create",
15+
Description: "Generate a share link for a single record",
16+
Risk: "read",
17+
Scopes: []string{"base:record:read"},
18+
AuthTypes: authTypes(),
19+
Flags: []common.Flag{
20+
baseTokenFlag(true),
21+
tableRefFlag(true),
22+
recordRefFlag(true),
23+
},
24+
Tips: []string{
25+
`Example: --base-token xxx --table-id tblxxx --record-id recxxx`,
26+
},
27+
DryRun: dryRunRecordShare,
28+
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
29+
return executeRecordShare(runtime)
30+
},
31+
}

shortcuts/base/shortcuts.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ func Shortcuts() []common.Shortcut {
4242
BaseRecordUpsert,
4343
BaseRecordBatchCreate,
4444
BaseRecordBatchUpdate,
45+
BaseRecordShareLinkCreate,
46+
BaseRecordShareLinkBatchCreate,
4547
BaseRecordUploadAttachment,
4648
BaseRecordDelete,
4749
BaseRecordHistoryList,

shortcuts/common/runner.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ func (ctx *RuntimeContext) StrArray(name string) []string {
181181
return v
182182
}
183183

184+
// StrSlice returns a string-slice flag value (supports CSV splitting and repeated flags).
185+
func (ctx *RuntimeContext) StrSlice(name string) []string {
186+
v, _ := ctx.Cmd.Flags().GetStringSlice(name)
187+
return v
188+
}
189+
184190
// ── API helpers ──
185191

186192
// CallAPI uses an internal HTTP wrapper with limited control over request/response.
@@ -849,6 +855,8 @@ func registerShortcutFlags(cmd *cobra.Command, s *Shortcut) {
849855
cmd.Flags().Int(fl.Name, d, desc)
850856
case "string_array":
851857
cmd.Flags().StringArray(fl.Name, nil, desc)
858+
case "string_slice":
859+
cmd.Flags().StringSlice(fl.Name, nil, desc)
852860
default:
853861
cmd.Flags().String(fl.Name, fl.Default, desc)
854862
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# base +record-share-link-batch-create
2+
3+
> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
4+
5+
批量生成记录分享链接(单次调用最多传入 100 条)。
6+
7+
## 适用场景(重点)
8+
9+
- 适合需要一次性获取多条记录分享链接的场景,例如批量导出分享链接、批量发送通知等。
10+
- 当需要处理的记录数超过 100 条时,需分批调用。
11+
12+
## 推荐命令
13+
14+
```bash
15+
# 请使用“,”来分隔多个 record id
16+
lark-cli base +record-share-link-batch-create \
17+
--base-token xxx \
18+
--table-id tbl_xxx \
19+
--record-ids rec001,rec002,rec003
20+
```
21+
22+
## 参数
23+
24+
| 参数 | 必填 | 说明 |
25+
|------|------|----|
26+
| `--base-token <token>` || Base Token |
27+
| `--table-id <id>` || 表 ID |
28+
| `--record-ids <ids...>` || 记录 ID 列表,需要使用逗号分隔,最多 100 条 |
29+
30+
## API 入参详情
31+
32+
**HTTP 方法和路径:**
33+
34+
```http
35+
POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/share_links/batch
36+
```
37+
38+
**请求体:**
39+
40+
```json
41+
{
42+
"record_ids": ["rec001", "rec002", "rec003"]
43+
}
44+
```
45+
46+
> CLI 会自动对 `--record-ids` 去重后再调用接口。
47+
48+
## 返回重点
49+
50+
- 成功时直接返回接口 `data` 字段内容,包含 `record_share_links` 映射(key 为 record_id,value 为分享链接)。结构如下:
51+
52+
```json
53+
{
54+
"record_share_links": {
55+
"rec001": "https://example.feishu.cn/record/TW2wrdbkoeoYXYcwvyIczJ2ZnFb",
56+
"rec002": "https://example.feishu.cn/record/aB3xKmNpQrStUvWxYz123456789",
57+
"rec003": "https://example.feishu.cn/record/cD4yLmNoPqRsTuVwXz987654321"
58+
}
59+
}
60+
```
61+
- 若部分记录ID无权限/不存在,则 record_share_links 中只会包括有效的记录ID对应的分享链接
62+
- 若全部记录ID都无权限/不存在,则会返回错误信息 `records do not exist or no read permission`
63+
64+
## 坑点
65+
66+
- ⚠️ 单次最多 100 条记录,超出会被 CLI 校验拦截。
67+
- ⚠️ 重复的 record_id 会在调用前自动去重。
68+
- ⚠️ `--record-ids` 为空时会被校验拦截。
69+
70+
## 参考
71+
72+
- [lark-base-record.md](lark-base-record.md) — record 索引页
73+
- [lark-base-record-share-link-create.md](lark-base-record-share-link-create.md) — 单条生成分享链接
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# base +record-share-link-create
2+
3+
> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
4+
5+
为单条记录生成分享链接。
6+
7+
## 推荐命令
8+
9+
```bash
10+
lark-cli base +record-share-link-create \
11+
--base-token xxx \
12+
--table-id tbl_xxx \
13+
--record-id rec_xxx
14+
```
15+
16+
## 参数
17+
18+
| 参数 | 必填 | 说明 |
19+
|------|------|------|
20+
| `--base-token <token>` || Base Token |
21+
| `--table-id <id>` || 表 ID |
22+
| `--record-id <id>` || 记录 ID |
23+
24+
## API 入参详情
25+
26+
**HTTP 方法和路径:**
27+
28+
```http
29+
POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/:record_id/share_links
30+
```
31+
32+
## 返回重点
33+
34+
- 成功时直接返回接口 `data` 字段内容,包含该记录的分享链接信息。结构如下:
35+
```json
36+
{
37+
"record_share_link": "https://example.feishu.cn/record/TW2wrdbkoeoYXYcwvyIczJ2ZnFb"
38+
}
39+
```
40+
- 若记录ID无权限/不存在,则会返回错误信息 `records do not exist or no read permission`
41+
42+
## 参考
43+
44+
- [lark-base-record.md](lark-base-record.md) — record 索引页
45+
- [lark-base-record-share-link-batch-create.md](lark-base-record-share-link-batch-create.md) — 批量生成分享链接

skills/lark-base/references/lark-base-record.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ record 相关命令索引。
1717
| [lark-base-record-upload-attachment.md](lark-base-record-upload-attachment.md) | `+record-upload-attachment` | 上传本地文件到附件字段并更新记录 |
1818
| [`../../lark-doc/references/lark-doc-media-download.md`](../../lark-doc/references/lark-doc-media-download.md) | `lark-cli docs +media-download` | 下载 Base 附件到本地(附件的 `file_token` 来自 `+record-get` 的附件字段) |
1919
| [lark-base-record-delete.md](lark-base-record-delete.md) | `+record-delete` | 删除记录 |
20+
| [lark-base-record-share-link-create.md](lark-base-record-share-link-create.md) | `+record-share-link-create` | 为单条记录生成分享链接 |
21+
| [lark-base-record-share-link-batch-create.md](lark-base-record-share-link-batch-create.md) | `+record-share-link-batch-create` | 批量生成记录分享链接(最多 100 条)|
2022

2123
## 说明
2224

0 commit comments

Comments
 (0)