mirror of
https://github.com/larksuite/cli.git
synced 2026-08-03 08:32:46 +08:00
Compare commits
2 Commits
codex/base
...
fix/base-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58d488e379 | ||
|
|
236bf7d253 |
@@ -195,7 +195,9 @@ func executeBaseURLResolve(runtime *common.RuntimeContext) error {
|
||||
switch classifyBaseURL(parsed) {
|
||||
case "base_url":
|
||||
out := resolveBaseURL(parsed)
|
||||
enrichBaseResolveHint(runtime, out, resolveBaseURLSelection(parsed))
|
||||
if err := enrichBaseResolveHint(runtime, out, resolveBaseURLSelection(parsed)); err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.OutFormat(out, nil, nil)
|
||||
return nil
|
||||
case "wiki_url":
|
||||
@@ -205,7 +207,9 @@ func executeBaseURLResolve(runtime *common.RuntimeContext) error {
|
||||
}
|
||||
selection := resolveBaseURLSelection(parsed)
|
||||
applyBaseURLSelection(out, selection)
|
||||
enrichBaseResolveHint(runtime, out, selection)
|
||||
if err := enrichBaseResolveHint(runtime, out, selection); err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.OutFormat(out, nil, nil)
|
||||
return nil
|
||||
case "record_share_url":
|
||||
@@ -422,15 +426,19 @@ func executeBaseTitleResolve(runtime *common.RuntimeContext) error {
|
||||
}
|
||||
}
|
||||
|
||||
func enrichBaseResolveHint(runtime *common.RuntimeContext, out map[string]interface{}, selection baseURLSelection) {
|
||||
func enrichBaseResolveHint(runtime *common.RuntimeContext, out map[string]interface{}, selection baseURLSelection) error {
|
||||
baseToken := strings.TrimSpace(common.GetString(out, "base_token"))
|
||||
selectedBlockID := strings.TrimSpace(common.GetString(out, "block_id"))
|
||||
if baseToken == "" || selectedBlockID == "" {
|
||||
out["hint"] = resolveHint("", nil)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if block, found, err := resolveSelectedBaseBlock(runtime, baseToken, selectedBlockID); err == nil && found {
|
||||
block, found, err := resolveSelectedBaseBlock(runtime, baseToken, selectedBlockID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found {
|
||||
out["block_type"] = block.Type
|
||||
if block.Name != "" {
|
||||
out["block_name"] = block.Name
|
||||
@@ -467,10 +475,11 @@ func enrichBaseResolveHint(runtime *common.RuntimeContext, out map[string]interf
|
||||
default:
|
||||
out["hint"] = resolveUnknownBlockHint()
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
out["hint"] = resolveUnknownBlockHint()
|
||||
return nil
|
||||
}
|
||||
|
||||
type resolvedBaseBlock struct {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -67,7 +68,10 @@ func TestBaseURLResolveBaseURL(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("unconfirmed selected block stays neutral", func(t *testing.T) {
|
||||
factory, stdout, _ := newExecuteFactory(t)
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
reg.Register(baseBlockListResolveStub("bas123",
|
||||
map[string]interface{}{"id": "tbl_other", "type": "table", "name": "Other"},
|
||||
))
|
||||
err := runShortcutWithAuthTypes(t, BaseURLResolve, authTypes(), []string{
|
||||
"+url-resolve", "--url", "https://example.larkoffice.com/base/bas123?table=tbl123&view=vew_stale&record=rec_stale", "--as", "user",
|
||||
}, factory, stdout)
|
||||
@@ -96,6 +100,15 @@ func TestBaseURLResolveBaseURL(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("block list error is returned", func(t *testing.T) {
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
reg.Register(baseBlockListScopeErrorStub("bas123"))
|
||||
err := runShortcutWithAuthTypes(t, BaseURLResolve, authTypes(), []string{
|
||||
"+url-resolve", "--url", "https://example.larkoffice.com/base/bas123?table=tbl123&view=vew_stale", "--as", "bot",
|
||||
}, factory, stdout)
|
||||
assertBaseBlockReadPermissionError(t, err, stdout)
|
||||
})
|
||||
|
||||
t.Run("field endpoint does not confirm untyped block", func(t *testing.T) {
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
reg.Register(baseBlockListResolveStub("bas123",
|
||||
@@ -269,6 +282,22 @@ func baseBlockListResolveStub(baseToken string, blocks ...map[string]interface{}
|
||||
}
|
||||
}
|
||||
|
||||
func baseBlockListScopeErrorStub(baseToken string) *httpmock.Stub {
|
||||
return &httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/base/v3/bases/" + baseToken + "/blocks/list",
|
||||
Body: map[string]interface{}{
|
||||
"code": 99991672,
|
||||
"msg": "access denied",
|
||||
"error": map[string]interface{}{
|
||||
"permission_violations": []interface{}{
|
||||
map[string]interface{}{"subject": "base:block:read"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseURLResolveWikiURL(t *testing.T) {
|
||||
t.Run("bitable", func(t *testing.T) {
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
@@ -309,6 +338,19 @@ func TestBaseURLResolveWikiURL(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bitable table coordinates return block list error", func(t *testing.T) {
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
reg.Register(wikiBaseNodeStub("wik123", "bas123", "Demo Base"))
|
||||
reg.Register(baseBlockListScopeErrorStub("bas123"))
|
||||
|
||||
err := runShortcutWithAuthTypes(t, BaseURLResolve, authTypes(), []string{
|
||||
"+url-resolve",
|
||||
"--url", "https://example.larkoffice.com/wiki/wik123?table=tbl123&view=vew_stale",
|
||||
"--as", "bot",
|
||||
}, factory, stdout)
|
||||
assertBaseBlockReadPermissionError(t, err, stdout)
|
||||
})
|
||||
|
||||
t.Run("bitable with dashboard selection", func(t *testing.T) {
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
reg.Register(wikiBaseNodeStub("wik123", "bas123", "Demo Base"))
|
||||
@@ -376,6 +418,33 @@ func wikiBaseNodeStub(wikiToken, baseToken, title string) *httpmock.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
func assertBaseBlockReadPermissionError(t *testing.T, err error, stdout interface {
|
||||
Len() int
|
||||
String() string
|
||||
}) {
|
||||
t.Helper()
|
||||
if err == nil {
|
||||
t.Fatal("expected block-list error to be returned")
|
||||
}
|
||||
p, ok := errs.ProblemOf(err)
|
||||
if !ok {
|
||||
t.Fatalf("expected typed problem, got %T %v", err, err)
|
||||
}
|
||||
if p.Category != errs.CategoryAuthorization || p.Subtype != errs.SubtypeAppScopeNotApplied || p.Code != 99991672 {
|
||||
t.Fatalf("unexpected problem: %#v", p)
|
||||
}
|
||||
var permissionErr *errs.PermissionError
|
||||
if !errors.As(err, &permissionErr) {
|
||||
t.Fatalf("expected PermissionError, got %T %v", err, err)
|
||||
}
|
||||
if len(permissionErr.MissingScopes) != 1 || permissionErr.MissingScopes[0] != "base:block:read" {
|
||||
t.Fatalf("missing scopes=%v", permissionErr.MissingScopes)
|
||||
}
|
||||
if stdout.Len() != 0 {
|
||||
t.Fatalf("stdout should stay empty when block-list fails: %s", stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseURLResolveRecordShareURL(t *testing.T) {
|
||||
t.Run("enriched", func(t *testing.T) {
|
||||
factory, stdout, reg := newExecuteFactory(t)
|
||||
|
||||
Reference in New Issue
Block a user