Skip to content
Open
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
57 changes: 57 additions & 0 deletions docs/stream-cli_chat_list-members.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## stream-cli chat list-members

List members of a channel

### Synopsis

List and paginate members of a channel using the Stream Chat API.

This command supports optional filters, offset/limit for pagination,
and sort fields (e.g. "user_id", "created_at").


```
stream-cli chat list-members --type [channel-type] --id [channel-id] [flags]
```

### Examples

```
# List first 10 members of 'red-team'
$ stream-cli chat list-members --type messaging --id red-team

# Filter members whose name includes 'tom'
$ stream-cli chat list-members --type messaging --id red-team --filter '{"name":{"$q":"tom"}}'

# Get next page of members (10 offset)
$ stream-cli chat list-members --type messaging --id red-team --offset 10 --limit 10

# Sort members by user_id ascending
$ stream-cli chat list-members --type messaging --id red-team --sort user_id:1

```

### Options

```
--filter string [optional] JSON string to filter members
-h, --help help for list-members
-i, --id string [required] Channel ID
--limit int [optional] Pagination limit (default 10) (default 10)
--offset int [optional] Pagination offset (default 0)
-o, --output-format string [optional] Output format. Can be json or tree (default "json")
--sort string [optional] Sorting field and direction (e.g., user_id:1 or created_at:-1)
-t, --type string [required] Channel type such as 'messaging' or 'livestream'
```

### Options inherited from parent commands

```
--app string [optional] Application name to use as it's defined in the configuration file
--config string [optional] Explicit config file path
```

### SEE ALSO

* [stream-cli chat](stream-cli_chat.md) - Allows you to interact with your Chat applications

105 changes: 105 additions & 0 deletions pkg/cmd/chat/channel/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package channel
import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"

stream "github.com/GetStream/stream-chat-go/v5"
Expand All @@ -28,6 +30,7 @@ func NewCmds() []*cobra.Command {
assignRoleCmd(),
hideCmd(),
showCmd(),
listMembersCmd(),
}
}

Expand Down Expand Up @@ -610,3 +613,105 @@ func showCmd() *cobra.Command {

return cmd
}

func listMembersCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "list-members --type [channel-type] --id [channel-id]",
Short: "List members of a channel",
Long: heredoc.Doc(`
List and paginate members of a channel using the Stream Chat API.

This command supports optional filters, offset/limit for pagination,
and sort fields (e.g. "user_id", "created_at").
`),
Example: heredoc.Doc(`
# List first 10 members of 'red-team'
$ stream-cli chat list-members --type messaging --id red-team

# Filter members whose name includes 'tom'
$ stream-cli chat list-members --type messaging --id red-team --filter '{"name":{"$q":"tom"}}'

# Get next page of members (10 offset)
$ stream-cli chat list-members --type messaging --id red-team --offset 10 --limit 10

# Sort members by user_id ascending
$ stream-cli chat list-members --type messaging --id red-team --sort user_id:1
`),
RunE: func(cmd *cobra.Command, args []string) error {
// client
c, err := config.GetConfig(cmd).GetClient(cmd)
if err != nil {
return err
}

// required flags
chanType, _ := cmd.Flags().GetString("type")
chanID, _ := cmd.Flags().GetString("id")

// optional flags
rawFilter, _ := cmd.Flags().GetString("filter")
offset, _ := cmd.Flags().GetInt("offset")
limit, _ := cmd.Flags().GetInt("limit")
rawSort, _ := cmd.Flags().GetString("sort")

// parse filter JSON
filter := map[string]interface{}{}
if rawFilter != "" {
err = json.Unmarshal([]byte(rawFilter), &filter)
if err != nil {
return fmt.Errorf("invalid filter JSON: %w", err)
}
}

// parse sort
var sortOption *stream.SortOption
if rawSort != "" {
parts := strings.Split(rawSort, ":")
if len(parts) != 2 {
return errors.New("sort format must be field:direction (e.g., user_id:1)")
}
direction := 1
if parts[1] == "-1" {
direction = -1
}
sortOption = &stream.SortOption{
Field: parts[0],
Direction: direction,
}
}

// build query
q := &stream.QueryOption{
Filter: filter,
Offset: offset,
Limit: limit,
}

if sortOption == nil {
sortOption = &stream.SortOption{Field: "user_id", Direction: 1}
}

ch := c.Channel(chanType, chanID)
membersResp, err := ch.QueryMembers(cmd.Context(), q, sortOption)
if err != nil {
return err
}

return utils.PrintObject(cmd, membersResp.Members)
},
}

// flags
fl := cmd.Flags()
fl.StringP("type", "t", "", "[required] Channel type such as 'messaging' or 'livestream'")
fl.StringP("id", "i", "", "[required] Channel ID")
fl.String("filter", "", "[optional] JSON string to filter members")
fl.String("sort", "", "[optional] Sorting field and direction (e.g., user_id:1 or created_at:-1)")
fl.Int("offset", 0, "[optional] Pagination offset (default 0)")
fl.Int("limit", 10, "[optional] Pagination limit (default 10)")
fl.StringP("output-format", "o", "json", "[optional] Output format. Can be json or tree")
_ = cmd.MarkFlagRequired("type")
_ = cmd.MarkFlagRequired("id")

return cmd
}
24 changes: 24 additions & 0 deletions pkg/cmd/chat/channel/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,27 @@ func TestHideAndShowChannel(t *testing.T) {
require.NoError(t, err)
require.Contains(t, cmd.OutOrStdout().(*bytes.Buffer).String(), "Successfully shown channel")
}

func TestListMembers(t *testing.T) {
cmd := test.GetRootCmdWithSubCommands(NewCmds()...)
ch := test.InitChannel(t)
u := test.CreateUser()
t.Cleanup(func() {
test.DeleteChannel(ch)
test.DeleteUser(u)
})

// Add member so they show up in the member list
cmd.SetArgs([]string{"add-members", "-t", "messaging", "-i", ch, u})
_, err := cmd.ExecuteC()
require.NoError(t, err)

// Now list members
cmd.SetArgs([]string{"list-members", "-t", "messaging", "-i", ch})
_, err = cmd.ExecuteC()
require.NoError(t, err)

// Assert the user ID is in the output
out := cmd.OutOrStdout().(*bytes.Buffer).String()
require.Contains(t, out, u)
}