mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
113 lines
3.4 KiB
Go
113 lines
3.4 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package doc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/larksuite/cli/errs"
|
|
"github.com/larksuite/cli/shortcuts/common"
|
|
)
|
|
|
|
// docsSceneContextKey lets in-process embedders pass a server-owned docs_ai
|
|
// scene without exposing it as a user-controlled CLI flag.
|
|
const docsSceneContextKey = "lark_cli_docs_scene"
|
|
|
|
type documentRef struct {
|
|
Kind string
|
|
Token string
|
|
}
|
|
|
|
func parseDocumentRef(input string) (documentRef, error) {
|
|
raw := strings.TrimSpace(input)
|
|
if raw == "" {
|
|
return documentRef{}, errs.NewValidationError(errs.SubtypeInvalidArgument, "--doc cannot be empty").WithParam("--doc")
|
|
}
|
|
|
|
if token, ok := extractDocumentToken(raw, "/wiki/"); ok {
|
|
return documentRef{Kind: "wiki", Token: token}, nil
|
|
}
|
|
if token, ok := extractDocumentToken(raw, "/docx/"); ok {
|
|
return documentRef{Kind: "docx", Token: token}, nil
|
|
}
|
|
if token, ok := extractDocumentToken(raw, "/doc/"); ok {
|
|
return documentRef{Kind: "doc", Token: token}, nil
|
|
}
|
|
if strings.Contains(raw, "://") {
|
|
return documentRef{}, errs.NewValidationError(errs.SubtypeInvalidArgument, "unsupported --doc input %q: use a docx URL/token or a wiki URL that resolves to docx", raw).WithParam("--doc")
|
|
}
|
|
if strings.ContainsAny(raw, "/?#") {
|
|
return documentRef{}, errs.NewValidationError(errs.SubtypeInvalidArgument, "unsupported --doc input %q: use a docx token or a wiki URL", raw).WithParam("--doc")
|
|
}
|
|
|
|
return documentRef{Kind: "docx", Token: raw}, nil
|
|
}
|
|
|
|
func extractDocumentToken(raw, marker string) (string, bool) {
|
|
idx := strings.Index(raw, marker)
|
|
if idx < 0 {
|
|
return "", false
|
|
}
|
|
token := raw[idx+len(marker):]
|
|
if end := strings.IndexAny(token, "/?#"); end >= 0 {
|
|
token = token[:end]
|
|
}
|
|
token = strings.TrimSpace(token)
|
|
if token == "" {
|
|
return "", false
|
|
}
|
|
return token, true
|
|
}
|
|
|
|
// doDocAPI executes an OpenAPI request against the docs_ai endpoints and returns
|
|
// the parsed "data" field from the standard Lark response envelope {code, msg, data}.
|
|
// CallAPITyped lifts the x-tt-logid response header onto the typed error so log_id
|
|
// surfaces for support escalations even when the body omits it.
|
|
func doDocAPI(runtime *common.RuntimeContext, method, apiPath string, body interface{}) (map[string]interface{}, error) {
|
|
return runtime.CallAPITyped(method, apiPath, nil, body)
|
|
}
|
|
|
|
func docsSceneFromContext(ctx context.Context) string {
|
|
if ctx == nil {
|
|
return ""
|
|
}
|
|
scene, _ := ctx.Value(docsSceneContextKey).(string)
|
|
return strings.TrimSpace(scene)
|
|
}
|
|
|
|
func injectDocsScene(runtime *common.RuntimeContext, body map[string]interface{}) {
|
|
if scene := docsSceneFromContext(runtime.Ctx()); scene != "" {
|
|
body["scene"] = scene
|
|
}
|
|
}
|
|
|
|
func buildDriveRouteExtra(docID string) (string, error) {
|
|
extra, err := json.Marshal(map[string]string{"drive_route_token": docID})
|
|
if err != nil {
|
|
return "", errs.NewInternalError(errs.SubtypeUnknown, "failed to marshal upload extra data: %v", err).WithCause(err)
|
|
}
|
|
return string(extra), nil
|
|
}
|
|
|
|
func appendDocWarning(data map[string]interface{}, warning string) {
|
|
if data == nil {
|
|
return
|
|
}
|
|
if strings.TrimSpace(warning) == "" {
|
|
return
|
|
}
|
|
switch existing := data["warnings"].(type) {
|
|
case []interface{}:
|
|
data["warnings"] = append(existing, warning)
|
|
case []string:
|
|
data["warnings"] = append(existing, warning)
|
|
case nil:
|
|
data["warnings"] = []string{warning}
|
|
default:
|
|
data["warnings"] = []interface{}{existing, warning}
|
|
}
|
|
}
|