Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions shortcuts/im/builders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,17 @@ func TestShortcutValidateBranches(t *testing.T) {
}
})

t.Run("ImChatSearch invalid chat-modes value", func(t *testing.T) {
runtime := newTestRuntimeContext(t, map[string]string{
"query": "ok",
"chat-modes": "group,bogus",
}, nil)
err := ImChatSearch.Validate(context.Background(), runtime)
if err == nil || !strings.Contains(err.Error(), "invalid --chat-modes value") {
t.Fatalf("ImChatSearch.Validate() error = %v", err)
}
})

t.Run("ImChatUpdate requires fields", func(t *testing.T) {
runtime := newTestRuntimeContext(t, map[string]string{
"chat-id": "oc_123",
Expand Down Expand Up @@ -693,6 +704,39 @@ func TestShortcutDryRunShapes(t *testing.T) {
}
})

t.Run("ImChatSearch dry run maps chat-modes to wire values", func(t *testing.T) {
runtime := newTestRuntimeContext(t, map[string]string{
"query": "team-alpha",
"chat-modes": "group,topic",
}, nil)
got := mustMarshalDryRun(t, ImChatSearch.DryRun(context.Background(), runtime))
if !strings.Contains(got, `"chat_modes":["default","thread"]`) {
t.Fatalf("ImChatSearch.DryRun() chat_modes mapping = %s", got)
}
})

t.Run("ImChatSearch dry run maps single chat-mode topic", func(t *testing.T) {
runtime := newTestRuntimeContext(t, map[string]string{
"query": "team-alpha",
"chat-modes": "topic",
}, nil)
got := mustMarshalDryRun(t, ImChatSearch.DryRun(context.Background(), runtime))
if !strings.Contains(got, `"chat_modes":["thread"]`) {
t.Fatalf("ImChatSearch.DryRun() chat_modes mapping = %s", got)
}
})

t.Run("ImChatSearch dry run dedupes chat-modes", func(t *testing.T) {
runtime := newTestRuntimeContext(t, map[string]string{
"query": "team-alpha",
"chat-modes": "group, group",
}, nil)
got := mustMarshalDryRun(t, ImChatSearch.DryRun(context.Background(), runtime))
if !strings.Contains(got, `"chat_modes":["default"]`) {
t.Fatalf("ImChatSearch.DryRun() chat_modes dedupe = %s", got)
}
})

t.Run("ImMessagesSearch dry run uses messages search endpoint", func(t *testing.T) {
runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{
"query": "incident",
Expand Down
27 changes: 27 additions & 0 deletions shortcuts/im/im_chat_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strconv"
"strings"

"github.com/larksuite/cli/errs"
"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/internal/util"
"github.com/larksuite/cli/shortcuts/common"
Expand All @@ -30,6 +31,7 @@ var ImChatSearch = common.Shortcut{
Flags: []common.Flag{
{Name: "query", Desc: "search keyword (max 64 chars)"},
{Name: "search-types", Desc: "chat types, comma-separated (private, external, public_joined, public_not_joined)"},
{Name: "chat-modes", Desc: "filter by chat mode, comma-separated (group, topic)"},
{Name: "member-ids", Desc: "filter by member open_ids, comma-separated"},
{Name: "is-manager", Type: "bool", Desc: "only show chats you created or manage"},
{Name: "disable-search-by-user", Type: "bool", Desc: "disable search-by-member-name (default: search by member name first, then group name)"},
Expand Down Expand Up @@ -71,6 +73,13 @@ var ImChatSearch = common.Shortcut{
}
}
}
if cm := runtime.Str("chat-modes"); cm != "" {
for _, mode := range common.SplitCSV(cm) {
if mode != "group" && mode != "topic" {
return errs.NewValidationError(errs.SubtypeInvalidArgument, "invalid --chat-modes value %q: expected one of group, topic", mode).WithParam("--chat-modes")
}
}
}
if mi := runtime.Str("member-ids"); mi != "" {
ids := common.SplitCSV(mi)
if len(ids) > 50 {
Expand Down Expand Up @@ -216,6 +225,24 @@ func buildSearchChatBody(runtime *common.RuntimeContext) map[string]interface{}
if st := runtime.Str("search-types"); st != "" {
filter["search_types"] = common.SplitCSV(st)
}
// chat_modes is a server-side filter. The CLI exposes group/topic; the wire
// expects default/thread. Map and dedupe (the API caps the list at 2, and
// there are only 2 distinct modes) while preserving the user's order.
if cm := runtime.Str("chat-modes"); cm != "" {
seen := map[string]bool{}
var modes []string
for _, mode := range common.SplitCSV(cm) {
wire := map[string]string{"group": "default", "topic": "thread"}[mode]
if wire == "" || seen[wire] {
continue
}
seen[wire] = true
modes = append(modes, wire)
}
if len(modes) > 0 {
filter["chat_modes"] = modes
}
}
if mi := runtime.Str("member-ids"); mi != "" {
filter["member_ids"] = common.SplitCSV(mi)
}
Expand Down
4 changes: 4 additions & 0 deletions skills/lark-im/references/lark-im-chat-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ lark-cli im +chat-search --query "project"
# Restrict by search types
lark-cli im +chat-search --query "project" --search-types "private,public_joined"

# Filter by chat mode (group = regular group, topic = topic/thread group)
lark-cli im +chat-search --query "project" --chat-modes "topic"

# Filter by member open_ids (with keyword)
lark-cli im +chat-search --query "project" --member-ids "ou_xxx,ou_yyy"

Expand Down Expand Up @@ -43,6 +46,7 @@ lark-cli im +chat-search --query "project" --dry-run
|------|------|------|------|
| `--query <keyword>` | No (at least one of `--query` / `--member-ids` required) | Max 64 characters | Search keyword. Supports matching localized chat names, member names, multilingual search, pinyin, and prefix fuzzy search. If the query contains `-`, it is automatically wrapped in quotes |
| `--search-types <types>` | No | Comma-separated: `private`, `external`, `public_joined`, `public_not_joined` | Restrict the visible chat types returned by search |
| `--chat-modes <modes>` | No | Comma-separated: `group`, `topic` | Filter by chat mode (server-side): `group` = regular group, `topic` = topic/thread group |
| `--member-ids <ids>` | No (at least one of `--query` / `--member-ids` required) | Up to 50, format `ou_xxx` | Filter by member open_ids; can be used alone or combined with `--query` |
| `--is-manager` | No | - | Only show chats you created or manage |
| `--disable-search-by-user` | No | - | Disable member-name-based matching and search by group name only |
Expand Down
Loading