Files
larksuite-cli/shortcuts/wiki/wiki_member_helpers.go
liujinkun2025 652e96906c feat(wiki): add +member-add / +member-remove / +member-list shortcuts (#997)
- +member-add: wrap POST /spaces/{id}/members; --member-type / --member-role
  enums, optional --need-notification query (omitted entirely when the flag
  is unset, instead of forcing need_notification=false), my_library
  resolution under --as user, flattened single-member output
- +member-remove: wrap DELETE /spaces/{id}/members/{member_id}; surfaces the
  required member_type + member_role body the API expects, my_library
  resolution, fallback to echoing the caller's inputs when the API omits
  the member echo
- +member-list: wrap GET /spaces/{id}/members; reuses the +space-list /
  +node-list pagination contract (single page by default, --page-all walks
  every page capped by --page-limit, --page-token resumes a cursor)
- All three reject bot identity + my_library upfront with a clear hint and
  declare the narrowest scope the API accepts (wiki:member:create /
  wiki:member:update / wiki:member:retrieve) so tokens carrying only the
  narrow scope are not false-rejected by the exact-string preflight
- skill docs: reference pages for the three new shortcuts + SKILL.md
  shortcuts table; switch the membership flow guidance from raw
  `wiki members create` to the new +member-add path

Change-Id: I158a86aa7f00bb7cecc7a4e99346f3fb151b3c09
2026-05-21 20:40:55 +08:00

71 lines
2.6 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package wiki
import (
"fmt"
"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/shortcuts/common"
)
// wikiMemberTypes is the set of member_type values the space-member APIs
// accept. Shared by +member-add and +member-remove so the two stay aligned.
var wikiMemberTypes = []string{
"openid", "userid", "email", "unionid", "openchat", "opendepartmentid",
}
// wikiMemberRoles is the set of member_role values the space-member APIs
// accept.
var wikiMemberRoles = []string{"admin", "member"}
// validateWikiMemberSpaceID enforces the two universal rules for the
// space-member shortcuts:
// - --space-id must be non-blank and a valid resource name
// - bot identity may not use the my_library alias (it has no meaning for a
// tenant_access_token; same contract as +node-list / +node-create)
func validateWikiMemberSpaceID(runtime *common.RuntimeContext, spaceID string) error {
if spaceID == "" {
return output.ErrValidation("--space-id is required and cannot be blank")
}
if runtime.As().IsBot() && spaceID == wikiMyLibrarySpaceID {
return output.ErrValidation("bot identity does not support --space-id my_library; use an explicit --space-id")
}
return validateOptionalResourceName(spaceID, "--space-id")
}
// resolveWikiMemberSpaceID transparently expands the my_library alias to the
// caller's real per-user space_id; raw IDs pass through. Mirrors the pattern
// used by +node-list so the three member shortcuts behave the same way.
func resolveWikiMemberSpaceID(runtime *common.RuntimeContext, spaceID string) (string, error) {
if spaceID != wikiMyLibrarySpaceID {
return spaceID, nil
}
resolved, err := resolveMyLibrarySpaceID(runtime)
if err != nil {
return "", err
}
fmt.Fprintf(runtime.IO().ErrOut, "Resolved my_library to space %s\n", common.MaskToken(resolved))
return resolved, nil
}
// wikiMemberRecord parses a /spaces/{id}/members member object into a stable
// flat map. Used by all three shortcuts so they emit the same shape.
func wikiMemberRecord(raw map[string]interface{}) map[string]interface{} {
if raw == nil {
// Callers (wikiMemberAddOutput, member-remove Execute) handle nil via
// for-range or per-field fallback against the caller's input spec.
return nil
}
out := map[string]interface{}{
"member_id": common.GetString(raw, "member_id"),
"member_type": common.GetString(raw, "member_type"),
"member_role": common.GetString(raw, "member_role"),
}
if t := common.GetString(raw, "type"); t != "" {
out["type"] = t
}
return out
}