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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ node_modules/
.vscode
.envrc
stream-cli
stream-cli-test
stream
latest_changes.txt
# Test coverage output
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/cheynewallace/tabby v1.1.1
github.com/gizak/termui/v3 v3.1.0
github.com/golang-jwt/jwt/v4 v4.4.1
github.com/gorilla/websocket v1.5.0
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
Expand All @@ -18,7 +19,6 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
Expand Down
192 changes: 192 additions & 0 deletions pkg/cmd/chat/blocklist/blocklist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package blocklist

import (
stream "github.com/GetStream/stream-chat-go/v5"
"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"

"github.com/GetStream/stream-cli/pkg/config"
"github.com/GetStream/stream-cli/pkg/utils"
)

func NewCmds() []*cobra.Command {
return []*cobra.Command{
listCmd(),
getCmd(),
createCmd(),
updateCmd(),
deleteCmd(),
}
}

func listCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "list-blocklists --output-format [json|tree]",
Short: "List all block lists",
Example: heredoc.Doc(`
# List all block lists
$ stream-cli chat list-blocklists
`),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := config.GetConfig(cmd).GetClient(cmd)
if err != nil {
return err
}

resp, err := c.ListBlocklists(cmd.Context())
if err != nil {
return err
}

return utils.PrintObject(cmd, resp)
},
}

fl := cmd.Flags()
fl.StringP("output-format", "o", "json", "[optional] Output format. Can be json or tree")

return cmd
}

func getCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get-blocklist [name] --output-format [json|tree]",
Short: "Get a block list by name",
Example: heredoc.Doc(`
# Get the 'profanity' block list
$ stream-cli chat get-blocklist profanity
`),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := config.GetConfig(cmd).GetClient(cmd)
if err != nil {
return err
}

resp, err := c.GetBlocklist(cmd.Context(), args[0])
if err != nil {
return err
}

return utils.PrintObject(cmd, resp)
},
}

fl := cmd.Flags()
fl.StringP("output-format", "o", "json", "[optional] Output format. Can be json or tree")

return cmd
}

func createCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-blocklist --name [name] --words [comma-separated-words]",
Short: "Create a block list",
Example: heredoc.Doc(`
# Create a block list named 'profanity' with some words
$ stream-cli chat create-blocklist --name profanity --words "badword1,badword2,badword3"
`),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := config.GetConfig(cmd).GetClient(cmd)
if err != nil {
return err
}

name, _ := cmd.Flags().GetString("name")
words, err := utils.GetStringSliceParam(cmd.Flags(), "words")
if err != nil {
return err
}

bl := &stream.BlocklistCreateRequest{
BlocklistBase: stream.BlocklistBase{
Name: name,
Words: words,
},
}

_, err = c.CreateBlocklist(cmd.Context(), bl)
if err != nil {
return err
}

cmd.Printf("Successfully created block list [%s]\n", name)
return nil
},
}

fl := cmd.Flags()
fl.StringP("name", "n", "", "[required] Block list name")
fl.StringP("words", "w", "", "[required] Comma-separated list of words to block")
_ = cmd.MarkFlagRequired("name")
_ = cmd.MarkFlagRequired("words")

return cmd
}

func updateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-blocklist --name [name] --words [comma-separated-words]",
Short: "Update a block list",
Example: heredoc.Doc(`
# Update the 'profanity' block list
$ stream-cli chat update-blocklist --name profanity --words "newword1,newword2"
`),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := config.GetConfig(cmd).GetClient(cmd)
if err != nil {
return err
}

name, _ := cmd.Flags().GetString("name")
words, err := utils.GetStringSliceParam(cmd.Flags(), "words")
if err != nil {
return err
}

_, err = c.UpdateBlocklist(cmd.Context(), name, words)
if err != nil {
return err
}

cmd.Printf("Successfully updated block list [%s]\n", name)
return nil
},
}

fl := cmd.Flags()
fl.StringP("name", "n", "", "[required] Block list name")
fl.StringP("words", "w", "", "[required] Comma-separated list of words to block")
_ = cmd.MarkFlagRequired("name")
_ = cmd.MarkFlagRequired("words")

return cmd
}

func deleteCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "delete-blocklist [name]",
Short: "Delete a block list",
Example: heredoc.Doc(`
# Delete the 'profanity' block list
$ stream-cli chat delete-blocklist profanity
`),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := config.GetConfig(cmd).GetClient(cmd)
if err != nil {
return err
}

_, err = c.DeleteBlocklist(cmd.Context(), args[0])
if err != nil {
return err
}

cmd.Printf("Successfully deleted block list [%s]\n", args[0])
return nil
},
}

return cmd
}
176 changes: 176 additions & 0 deletions pkg/cmd/chat/campaign/campaign.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package campaign

import (
"encoding/json"

"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"

"github.com/GetStream/stream-cli/pkg/config"
"github.com/GetStream/stream-cli/pkg/utils"
)

func NewCmds() []*cobra.Command {
return []*cobra.Command{
getCampaignCmd(),
queryCampaignsCmd(),
startCampaignCmd(),
stopCampaignCmd(),
}
}

func getHTTPClient(cmd *cobra.Command) (*utils.HTTPClient, error) {
appCfg, err := config.GetConfig(cmd).GetAppConfig(cmd)
if err != nil {
return nil, err
}
return utils.NewHTTPClient(appCfg.AccessKey, appCfg.AccessSecretKey, appCfg.ChatURL), nil
}

func getCampaignCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get-campaign [campaign-id]",
Short: "Get a campaign by ID",
Args: cobra.ExactArgs(1),
Example: heredoc.Doc(`
# Get campaign details
$ stream-cli chat get-campaign campaign-123
`),
RunE: func(cmd *cobra.Command, args []string) error {
h, err := getHTTPClient(cmd)
if err != nil {
return err
}

resp, err := h.DoRequest(cmd.Context(), "GET", "campaigns/"+args[0], nil)
if err != nil {
return err
}

var result interface{}
_ = json.Unmarshal(resp, &result)
return utils.PrintObject(cmd, result)
},
}

fl := cmd.Flags()
fl.StringP("output-format", "o", "json", "[optional] Output format")

return cmd
}

func queryCampaignsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "query-campaigns --filter [raw-json]",
Short: "Query campaigns",
Example: heredoc.Doc(`
# Query all campaigns
$ stream-cli chat query-campaigns --filter '{}'
`),
RunE: func(cmd *cobra.Command, args []string) error {
h, err := getHTTPClient(cmd)
if err != nil {
return err
}

filterStr, _ := cmd.Flags().GetString("filter")
body := map[string]interface{}{}
if filterStr != "" {
var filter interface{}
if err := json.Unmarshal([]byte(filterStr), &filter); err != nil {
return err
}
body["filter"] = filter
}

resp, err := h.DoRequest(cmd.Context(), "POST", "campaigns/query", body)
if err != nil {
return err
}

var result interface{}
_ = json.Unmarshal(resp, &result)
return utils.PrintObject(cmd, result)
},
}

fl := cmd.Flags()
fl.StringP("filter", "f", "", "[optional] Filter conditions as JSON")
fl.StringP("output-format", "o", "json", "[optional] Output format")

return cmd
}

func startCampaignCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "start-campaign [campaign-id]",
Short: "Start or schedule a campaign",
Args: cobra.ExactArgs(1),
Example: heredoc.Doc(`
# Start a campaign immediately
$ stream-cli chat start-campaign campaign-123

# Schedule a campaign
$ stream-cli chat start-campaign campaign-123 --scheduled-for "2025-12-01T10:00:00Z"
`),
RunE: func(cmd *cobra.Command, args []string) error {
h, err := getHTTPClient(cmd)
if err != nil {
return err
}

body := map[string]interface{}{}
scheduledFor, _ := cmd.Flags().GetString("scheduled-for")
if scheduledFor != "" {
body["scheduled_for"] = scheduledFor
}

resp, err := h.DoRequest(cmd.Context(), "POST", "campaigns/"+args[0]+"/start", body)
if err != nil {
return err
}

var result interface{}
_ = json.Unmarshal(resp, &result)
return utils.PrintObject(cmd, result)
},
}

fl := cmd.Flags()
fl.String("scheduled-for", "", "[optional] Schedule time in RFC3339 format")
fl.StringP("output-format", "o", "json", "[optional] Output format")

return cmd
}

func stopCampaignCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "stop-campaign [campaign-id]",
Short: "Stop a running campaign",
Args: cobra.ExactArgs(1),
Example: heredoc.Doc(`
# Stop a campaign
$ stream-cli chat stop-campaign campaign-123
`),
RunE: func(cmd *cobra.Command, args []string) error {
h, err := getHTTPClient(cmd)
if err != nil {
return err
}

resp, err := h.DoRequest(cmd.Context(), "POST", "campaigns/"+args[0]+"/stop", nil)
if err != nil {
return err
}

var result interface{}
_ = json.Unmarshal(resp, &result)
return utils.PrintObject(cmd, result)
},
}

fl := cmd.Flags()
fl.StringP("output-format", "o", "json", "[optional] Output format")

return cmd
}
Loading