mirror of
https://github.com/larksuite/cli.git
synced 2026-08-03 08:32:46 +08:00
Compare commits
1 Commits
codex/cli-
...
feat/drive
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6727934941 |
@@ -28,7 +28,7 @@ var DriveImport = common.Shortcut{
|
||||
ConditionalScopes: []string{"wiki:node:retrieve"},
|
||||
AuthTypes: []string{"user", "bot"},
|
||||
Flags: []common.Flag{
|
||||
{Name: "file", Desc: "local file path (e.g. .docx, .xlsx, .md, .base, .pptx; large files auto use multipart upload; .base is capped at 20MB, .pptx at 500MB)", Required: true},
|
||||
{Name: "file", Desc: "local file path (e.g. .docx, .xlsx, .md, .base, .pptx, .png; large files auto use multipart upload; .base is capped at 20MB, .pptx at 500MB)", Required: true},
|
||||
{Name: "type", Desc: "target document type (docx, sheet, bitable, slides)", Required: true},
|
||||
{Name: "folder-token", Desc: "target folder token (omit for root folder; API accepts empty mount_key as root)"},
|
||||
{Name: "name", Desc: "imported file name (default: local file name without extension)"},
|
||||
|
||||
@@ -48,6 +48,7 @@ var driveImportExtToDocTypes = map[string][]string{
|
||||
"csv": {"sheet", "bitable"},
|
||||
"base": {"bitable"},
|
||||
"pptx": {"slides"},
|
||||
"png": {"slides"},
|
||||
}
|
||||
|
||||
var driveImportConcurrentOperationCodes = []int{232140101, 232140100, 233523001}
|
||||
@@ -230,7 +231,7 @@ func validateDriveImportFileSize(ext, docType string, fileSize int64) error {
|
||||
func validateDriveImportSpec(spec driveImportSpec) error {
|
||||
ext := spec.FileExtension()
|
||||
if ext == "" {
|
||||
return errs.NewValidationError(errs.SubtypeInvalidArgument, "file must have an extension (e.g. .md, .docx, .xlsx, .pptx)").WithParam("--file")
|
||||
return errs.NewValidationError(errs.SubtypeInvalidArgument, "file must have an extension (e.g. .md, .docx, .xlsx, .pptx, .png)").WithParam("--file")
|
||||
}
|
||||
|
||||
switch spec.DocType {
|
||||
@@ -241,7 +242,7 @@ func validateDriveImportSpec(spec driveImportSpec) error {
|
||||
|
||||
supportedTypes, ok := driveImportExtToDocTypes[ext]
|
||||
if !ok {
|
||||
return errs.NewValidationError(errs.SubtypeInvalidArgument, "unsupported file extension: %s. Supported extensions are: docx, doc, txt, md, mark, markdown, html, xlsx, xls, csv, base, pptx", ext).WithParam("--file")
|
||||
return errs.NewValidationError(errs.SubtypeInvalidArgument, "unsupported file extension: %s. Supported extensions are: docx, doc, txt, md, mark, markdown, html, xlsx, xls, csv, base, pptx, png", ext).WithParam("--file")
|
||||
}
|
||||
|
||||
typeAllowed := false
|
||||
@@ -262,8 +263,8 @@ func validateDriveImportSpec(spec driveImportSpec) error {
|
||||
hint = fmt.Sprintf(".xls files can only be imported as 'sheet', not '%s'", spec.DocType)
|
||||
case "base":
|
||||
hint = fmt.Sprintf(".base files can only be imported as 'bitable', not '%s'", spec.DocType)
|
||||
case "pptx":
|
||||
hint = fmt.Sprintf(".pptx files can only be imported as 'slides', not '%s'", spec.DocType)
|
||||
case "pptx", "png":
|
||||
hint = fmt.Sprintf(".%s files can only be imported as 'slides', not '%s'", ext, spec.DocType)
|
||||
default:
|
||||
hint = fmt.Sprintf(".%s files can only be imported as 'docx', not '%s'", ext, spec.DocType)
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ func TestValidateDriveImportSpec(t *testing.T) {
|
||||
name: "pptx slides ok",
|
||||
spec: driveImportSpec{FilePath: "./deck.pptx", DocType: "slides"},
|
||||
},
|
||||
{
|
||||
name: "png slides ok",
|
||||
spec: driveImportSpec{FilePath: "./screenshot.png", DocType: "slides"},
|
||||
},
|
||||
{
|
||||
name: "base non bitable rejected",
|
||||
spec: driveImportSpec{FilePath: "./snapshot.base", DocType: "sheet"},
|
||||
@@ -52,6 +56,11 @@ func TestValidateDriveImportSpec(t *testing.T) {
|
||||
spec: driveImportSpec{FilePath: "./deck.pptx", DocType: "docx"},
|
||||
wantErr: ".pptx files can only be imported as 'slides'",
|
||||
},
|
||||
{
|
||||
name: "png non slides rejected",
|
||||
spec: driveImportSpec{FilePath: "./screenshot.png", DocType: "docx"},
|
||||
wantErr: ".png files can only be imported as 'slides'",
|
||||
},
|
||||
{
|
||||
name: "unknown extension rejected",
|
||||
spec: driveImportSpec{FilePath: "./data.rtf", DocType: "docx"},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: lark-drive
|
||||
version: 1.0.0
|
||||
description: "飞书云空间(云盘/云存储):管理 Drive 文件和文件夹,包含上传/下载、创建文件夹、复制/移动/删除、查看元数据、评论/权限/订阅、标题、版本和本地文件导入。用户需要整理云盘目录、处理云空间资源 URL/token、判断链接类型/真实 token/标题,或导入 Word/Markdown/Excel/CSV/PPTX/.base 为 docx/sheet/bitable/slides 时使用;doubao.com 云空间 URL/token 也按资源路径和 token 路由,不回退 WebFetch。不负责:文档内容编辑(走 lark-doc)、表格/Base 表内数据操作(走 lark-sheets/lark-base)、知识空间节点/成员管理(走 lark-wiki)、原生 Markdown 文件读写/patch/diff(走 lark-markdown)。"
|
||||
description: "飞书云空间(云盘/云存储):管理 Drive 文件和文件夹,包含上传/下载、创建文件夹、复制/移动/删除、查看元数据、评论/权限/订阅、标题、版本和本地文件导入。用户需要整理云盘目录、处理云空间资源 URL/token、判断链接类型/真实 token/标题,或导入 Word/Markdown/Excel/CSV/PPTX/PNG/.base 为 docx/sheet/bitable/slides 时使用;doubao.com 云空间 URL/token 也按资源路径和 token 路由,不回退 WebFetch。不负责:文档内容编辑(走 lark-doc)、表格/Base 表内数据操作(走 lark-sheets/lark-base)、知识空间节点/成员管理(走 lark-wiki)、原生 Markdown 文件读写/patch/diff(走 lark-markdown)。"
|
||||
metadata:
|
||||
requires:
|
||||
bins: ["lark-cli"]
|
||||
@@ -31,7 +31,7 @@ metadata:
|
||||
- 用户给出 doubao.com 的云空间资源 URL/token,或明确提到豆包里的 file/folder/docx/sheet/bitable/wiki 资源时,仍按资源类型、URL 路径和 token 路由到本 skill;不要因为域名不是飞书而回退到 WebFetch。
|
||||
- 用户要把本地 `.xlsx` / `.csv` / `.base` 导入成 Base / 多维表格 / bitable,第一步必须使用 `lark-cli drive +import --type bitable`。
|
||||
- 用户要把本地 `.md` / `.docx` / `.doc` / `.txt` / `.html` 导入成在线文档,使用 `lark-cli drive +import --type docx`。
|
||||
- 用户要把本地 `.pptx` 导入成飞书幻灯片,使用 `lark-cli drive +import --type slides`;当前 PPTX 导入上限是 500MB。
|
||||
- 用户要把本地 `.pptx` 或 `.png` 导入成飞书幻灯片,使用 `lark-cli drive +import --type slides`;当前 PPTX 导入上限是 500MB,PNG 由服务端校验大小限制。
|
||||
- 批量执行 `drive +import` 且目标是同一个位置(同一 `--folder-token`、默认根目录,或同一 `--target-token`)时,必须串行执行;不要并发导入到同一位置,服务端可能返回并发冲突错误。
|
||||
- 用户要在 Drive 里上传、创建、读取、局部 patch 或覆盖更新**原生 `.md` 文件**(不是导入成 docx),切到 [`lark-markdown`](../lark-markdown/SKILL.md)。
|
||||
- 用户要比较原生 `.md` 文件的**历史版本差异**,或比较远端 Markdown 与本地草稿,切到 [`lark-markdown`](../lark-markdown/SKILL.md) 的 `lark-cli markdown +diff`;需要版本号时先用 `drive +version-history`。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||||
|
||||
将本地文件(如 Word、TXT、Markdown、Excel、PPTX 等)导入并转换为飞书在线云文档(docx、sheet、bitable、slides)。底层统一通过 `POST /open-apis/drive/v1/import_tasks` 接口创建导入任务,并在 shortcut 内做有限次数轮询 `GET /open-apis/drive/v1/import_tasks/:ticket`。
|
||||
将本地文件(如 Word、TXT、Markdown、Excel、PPTX、PNG 等)导入并转换为飞书在线云文档(docx、sheet、bitable、slides)。底层统一通过 `POST /open-apis/drive/v1/import_tasks` 接口创建导入任务,并在 shortcut 内做有限次数轮询 `GET /open-apis/drive/v1/import_tasks/:ticket`。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 当用户说“把本地 Excel / CSV / `.base` 快照导入成 Base / 多维表格 / bitable 文档”时,第一步必须使用 `drive +import --type bitable`。
|
||||
@@ -55,6 +55,9 @@ lark-cli drive +import --file ./snapshot.base --type bitable --name "快照还
|
||||
# 导入 PPTX 为飞书幻灯片 (slides)(文件不能超过 500MB)
|
||||
lark-cli drive +import --file ./deck.pptx --type slides --name "项目汇报"
|
||||
|
||||
# 导入 PNG 为飞书幻灯片 (slides)
|
||||
lark-cli drive +import --file ./screenshot.png --type slides --name "图片转幻灯片"
|
||||
|
||||
# 导入到指定文件夹,并指定导入后的文件名
|
||||
lark-cli drive +import --file ./data.csv --type bitable --folder-token <FOLDER_TOKEN> --name "导入数据表"
|
||||
|
||||
@@ -101,6 +104,7 @@ lark-cli drive +import --file ./README.md --type docx --dry-run
|
||||
| `.csv` | `sheet`, `bitable` | CSV 数据文件 |
|
||||
| `.base` | `bitable` | 多维表格快照文件 |
|
||||
| `.pptx` | `slides` | Microsoft PowerPoint 演示文稿 |
|
||||
| `.png` | `slides` | PNG 图片(Image to Slide) |
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 用户口头说的 “Base” / “多维表格” / “bitable”,在命令里统一对应 `--type bitable`。
|
||||
@@ -111,6 +115,7 @@ lark-cli drive +import --file ./README.md --type docx --dry-run
|
||||
> - `.xls` 文件**只能**导入为 `sheet`
|
||||
> - `.base` 文件**只能**导入为 `bitable`
|
||||
> - `.pptx` 文件**只能**导入为 `slides`
|
||||
> - `.png` 文件**只能**导入为 `slides`
|
||||
> - 例如:`.csv` 文件不能导入为 `docx`,`.md` 文件不能导入为 `sheet`
|
||||
|
||||
> [!IMPORTANT]
|
||||
|
||||
@@ -55,3 +55,46 @@ func TestDriveImportDryRunFolderTokenWikiProbe(t *testing.T) {
|
||||
t.Fatalf("data.api.2.body.point.mount_key = %q, want fldcnImportDryRunTarget\nstdout:\n%s", got, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDriveImportPNGToSlidesDryRun(t *testing.T) {
|
||||
setDriveDryRunConfigEnv(t)
|
||||
|
||||
workDir := t.TempDir()
|
||||
if err := os.WriteFile(workDir+"/screenshot.png", []byte("fake png for dry run"), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"drive", "+import",
|
||||
"--file", "screenshot.png",
|
||||
"--type", "slides",
|
||||
"--name", "image-to-slide",
|
||||
"--dry-run",
|
||||
},
|
||||
WorkDir: workDir,
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
out := result.Stdout
|
||||
if got := clie2e.DryRunGet(out, "api.0.url").String(); got != "/open-apis/drive/v1/medias/upload_all" {
|
||||
t.Fatalf("data.api.0.url = %q, want upload_all\nstdout:\n%s", got, out)
|
||||
}
|
||||
if got := clie2e.DryRunGet(out, "api.0.body.extra").String(); got != `{"file_extension":"png","obj_type":"slides"}` {
|
||||
t.Fatalf("data.api.0.body.extra = %q, want PNG-to-slides metadata\nstdout:\n%s", got, out)
|
||||
}
|
||||
if got := clie2e.DryRunGet(out, "api.1.url").String(); got != "/open-apis/drive/v1/import_tasks" {
|
||||
t.Fatalf("data.api.1.url = %q, want import_tasks\nstdout:\n%s", got, out)
|
||||
}
|
||||
if got := clie2e.DryRunGet(out, "api.1.body.file_extension").String(); got != "png" {
|
||||
t.Fatalf("data.api.1.body.file_extension = %q, want png\nstdout:\n%s", got, out)
|
||||
}
|
||||
if got := clie2e.DryRunGet(out, "api.1.body.type").String(); got != "slides" {
|
||||
t.Fatalf("data.api.1.body.type = %q, want slides\nstdout:\n%s", got, out)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user