From e545dae5e842c78a0bb1ea63806cb3ad171fd114 Mon Sep 17 00:00:00 2001 From: Aleksandr Soloshenko Date: Wed, 29 Jan 2025 20:58:12 +0700 Subject: [PATCH 1/2] [webhooks] implement webhooks management commands --- .gitignore | 1 + README.md | 34 ++++-------------- cmd/smsgate/smsgate.go | 2 +- go.mod | 3 +- go.sum | 6 ++++ internal/commands/webhooks/delete.go | 19 ++++++++-- internal/commands/webhooks/list.go | 20 +++++++++-- internal/commands/webhooks/register.go | 43 ++++++++++++++++------- internal/core/output/json.go | 14 ++++++++ internal/core/output/output.go | 3 ++ internal/core/output/text.go | 48 ++++++++++++++++++++++++++ 11 files changed, 146 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 3cd7da6..2dda5e2 100644 --- a/.gitignore +++ b/.gitignore @@ -125,3 +125,4 @@ $RECYCLE.BIN/ # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +go.work* diff --git a/README.md b/README.md index edae5e7..50dd10d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # SMS Gateway for Androidâ„¢ CLI -A command-line interface for working with SMS Gateway for Android. +A command-line interface for interacting with the SMS Gateway for Android API. ## Table of Contents @@ -16,8 +16,6 @@ A command-line interface for working with SMS Gateway for Android. - [Output Formats](#output-formats) - [Usage](#usage) - [Commands](#commands) - - [Send a message](#send-a-message) - - [Get the status of a sent message](#get-the-status-of-a-sent-message) - [Exit codes](#exit-codes) - [Examples](#examples) - [Output formats](#output-formats-1) @@ -91,32 +89,14 @@ smsgate [global options] command [command options] [arguments...] ### Commands -The CLI supports the following commands: +The CLI offers two main groups of commands: -- `send` - send a message with single or multiple recipients -- `status` - get the status of a sent message by message ID +- **Messages**: Commands for sending messages and checking their status. +- **Webhooks**: Commands for managing webhooks, including creating, updating, and deleting them. -#### Send a message - -Syntax: -```bash -smsgate send [options] 'Message content' -``` - -| Option | Description | Default value | Example | -| --------------------------- | ------------------------------------------------------------------------------------------ | ------------- | ----------------------- | -| `--id` | Message ID, will be generated if not provided | empty | `zXDYfTmTVf3iMd16zzdBj` | -| `--phone`, `--phones`, `-p` | Phone number, can be used multiple times or with comma-separated values, E.164 format | **required** | `+19162255887` | -| `--sim`, `--simNumber` | One-based SIM card slot number, if empty, the default SIM card will be used | empty | `2` | -| `--ttl` | Time-to-live (TTL), if empty, the message will not expire
Conflicts with `--validUntil` | empty | `1h30m` | -| `--validUntil` | Valid until, if empty, the message will not expire
Conflicts with `--ttl` | empty | `2024-12-31T23:59:59Z` | - -#### Get the status of a sent message - -Syntax: -```bash -smsgate status 'Message ID' -``` +For a complete list of available commands, you can: +- Run `smsgate help` or `smsgate --help` in your terminal. +- Visit the official documentation at [docs.sms-gate.app](https://docs.sms-gate.app/integration/cli/#commands). ### Exit codes diff --git a/cmd/smsgate/smsgate.go b/cmd/smsgate/smsgate.go index ed61480..09bf456 100644 --- a/cmd/smsgate/smsgate.go +++ b/cmd/smsgate/smsgate.go @@ -91,7 +91,7 @@ func main() { } app.Commands = append(app.Commands, messages.Commands...) - // app.Commands = append(app.Commands, webhooks.Commands...) + app.Commands = append(app.Commands, webhooks.Commands...) if err := app.Run(os.Args); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) diff --git a/go.mod b/go.mod index bef18a0..d423247 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module github.com/android-sms-gateway/cli go 1.23.2 require ( - github.com/android-sms-gateway/client-go v1.1.0 + github.com/android-sms-gateway/client-go v1.4.0 + github.com/capcom6/go-helpers v0.0.0-20240521035631-865ee2879fa3 github.com/joho/godotenv v1.5.1 github.com/urfave/cli/v2 v2.27.5 ) diff --git a/go.sum b/go.sum index f797d80..838785c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,11 @@ github.com/android-sms-gateway/client-go v1.1.0 h1:mAPsueRrY/qOdQAU5yO3uLQAb7Po+3jBxB1tiqyClvg= github.com/android-sms-gateway/client-go v1.1.0/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4= +github.com/android-sms-gateway/client-go v1.3.1-0.20250129225754-59c34aa9d1c0 h1:OQgfNIUB32Ui1plEtfjjRAP85fpW8gBQgc69g5IAimI= +github.com/android-sms-gateway/client-go v1.3.1-0.20250129225754-59c34aa9d1c0/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4= +github.com/android-sms-gateway/client-go v1.4.0 h1:yc6VqbiF1p/a0Ygw49VrKYHwcBJQIidcBz4C30jb27Q= +github.com/android-sms-gateway/client-go v1.4.0/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4= +github.com/capcom6/go-helpers v0.0.0-20240521035631-865ee2879fa3 h1:mq9rmBMCCzqGnZtbQqFSd+Ua3fahqUOYaTf26YFhWJc= +github.com/capcom6/go-helpers v0.0.0-20240521035631-865ee2879fa3/go.mod h1:WDqc7HZNqHxUTisArkYIBZtqUfJBVyPWeQI+FMwEzAw= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= diff --git a/internal/commands/webhooks/delete.go b/internal/commands/webhooks/delete.go index f14ef8d..68e59cc 100644 --- a/internal/commands/webhooks/delete.go +++ b/internal/commands/webhooks/delete.go @@ -1,7 +1,10 @@ package webhooks import ( + "fmt" + "github.com/android-sms-gateway/cli/internal/core/codes" + "github.com/android-sms-gateway/cli/internal/utils/metadata" "github.com/urfave/cli/v2" ) @@ -18,9 +21,19 @@ var delete = &cli.Command{ return cli.Exit("ID is empty", codes.ParamsError) } - // client := metadata.GetClient(c.App.Metadata) - // renderer := metadata.GetRenderer(c.App.Metadata) + client := metadata.GetClient(c.App.Metadata) + renderer := metadata.GetRenderer(c.App.Metadata) + + err := client.DeleteWebhook(c.Context, id) + if err != nil { + return cli.Exit(err.Error(), codes.ClientError) + } - return cli.Exit("Not implemented", codes.ParamsError) + b, err := renderer.Success() + if err != nil { + return cli.Exit(err.Error(), codes.OutputError) + } + fmt.Println(b) + return nil }, } diff --git a/internal/commands/webhooks/list.go b/internal/commands/webhooks/list.go index f62c74f..7b13a03 100644 --- a/internal/commands/webhooks/list.go +++ b/internal/commands/webhooks/list.go @@ -1,7 +1,10 @@ package webhooks import ( + "fmt" + "github.com/android-sms-gateway/cli/internal/core/codes" + "github.com/android-sms-gateway/cli/internal/utils/metadata" "github.com/urfave/cli/v2" ) @@ -11,9 +14,20 @@ var list = &cli.Command{ Aliases: []string{"l", "ls"}, Usage: "List webhooks", Action: func(c *cli.Context) error { - // client := metadata.GetClient(c.App.Metadata) - // renderer := metadata.GetRenderer(c.App.Metadata) + client := metadata.GetClient(c.App.Metadata) + renderer := metadata.GetRenderer(c.App.Metadata) + + res, err := client.ListWebhooks(c.Context) + if err != nil { + return cli.Exit(err.Error(), codes.ClientError) + } + + b, err := renderer.Webhooks(res) + if err != nil { + return cli.Exit(err.Error(), codes.OutputError) + } + fmt.Println(b) - return cli.Exit("Not implemented", codes.ParamsError) + return nil }, } diff --git a/internal/commands/webhooks/register.go b/internal/commands/webhooks/register.go index eeb2005..db0eb69 100644 --- a/internal/commands/webhooks/register.go +++ b/internal/commands/webhooks/register.go @@ -1,8 +1,13 @@ package webhooks import ( + "fmt" + "strings" + "github.com/android-sms-gateway/cli/internal/core/codes" + "github.com/android-sms-gateway/cli/internal/utils/metadata" "github.com/android-sms-gateway/client-go/smsgateway" + "github.com/capcom6/go-helpers/slices" "github.com/urfave/cli/v2" ) @@ -15,13 +20,16 @@ var register = &cli.Command{ Flags: []cli.Flag{ &cli.StringFlag{ Name: "id", - Usage: "ID", + Usage: "ID, optional", Required: false, }, &cli.StringFlag{ - Name: "event", - Aliases: []string{"e"}, - Usage: "Event", + Name: "event", + Aliases: []string{"e"}, + Usage: "Event, one of: " + strings.Join( + slices.Map(smsgateway.WebhookEventTypes(), func(e smsgateway.WebhookEvent) string { return string(e) }), + ", ", + ), Required: true, Action: func(c *cli.Context, event string) error { if !smsgateway.IsValidWebhookEvent(event) { @@ -38,15 +46,26 @@ var register = &cli.Command{ return cli.Exit("URL is empty", codes.ParamsError) } - // client := metadata.GetClient(c.App.Metadata) - // renderer := metadata.GetRenderer(c.App.Metadata) + client := metadata.GetClient(c.App.Metadata) + renderer := metadata.GetRenderer(c.App.Metadata) + + req := smsgateway.Webhook{ + ID: c.String("id"), + URL: url, + Event: c.String("event"), + } + + res, err := client.RegisterWebhook(c.Context, req) + if err != nil { + return cli.Exit(err.Error(), codes.ClientError) + } - // req := smsgateway.Webhook{ - // ID: c.String("id"), - // URL: url, - // Event: c.String("event"), - // } + b, err := renderer.Webhook(res) + if err != nil { + return cli.Exit(err.Error(), codes.OutputError) + } + fmt.Println(b) - return cli.Exit("Not implemented", codes.ParamsError) + return nil }, } diff --git a/internal/core/output/json.go b/internal/core/output/json.go index 4b1e1ae..0005730 100644 --- a/internal/core/output/json.go +++ b/internal/core/output/json.go @@ -25,3 +25,17 @@ func NewJSONOutput() *JSONOutput { func (o *JSONOutput) MessageState(src smsgateway.MessageState) (string, error) { return o.marshaler(src) } + +func (o *JSONOutput) Webhook(src smsgateway.Webhook) (string, error) { + return o.marshaler(src) +} + +func (o *JSONOutput) Webhooks(src []smsgateway.Webhook) (string, error) { + return o.marshaler(src) +} + +func (o *JSONOutput) Success() (string, error) { + return "", nil +} + +var _ Renderer = (*JSONOutput)(nil) diff --git a/internal/core/output/output.go b/internal/core/output/output.go index b770229..e789f21 100644 --- a/internal/core/output/output.go +++ b/internal/core/output/output.go @@ -16,6 +16,9 @@ const ( type Renderer interface { MessageState(src smsgateway.MessageState) (string, error) + Webhook(src smsgateway.Webhook) (string, error) + Webhooks(src []smsgateway.Webhook) (string, error) + Success() (string, error) } var ErrUnsupportedFormat = errors.New("unsupported format") diff --git a/internal/core/output/text.go b/internal/core/output/text.go index 204ed76..b6be41b 100644 --- a/internal/core/output/text.go +++ b/internal/core/output/text.go @@ -66,3 +66,51 @@ func (*TextOutput) MessageState(src smsgateway.MessageState) (string, error) { return builder.String(), nil } + +// Webhook formats a single smsgateway.Webhook into a string representation. +// The output includes the ID, Event, and URL of the webhook. +func (*TextOutput) Webhook(src smsgateway.Webhook) (string, error) { + builder := strings.Builder{} + builder.WriteString("ID: ") + builder.WriteString(src.ID) + builder.WriteString("\nEvent: ") + builder.WriteString(src.Event) + builder.WriteString("\nURL: ") + builder.WriteString(src.URL) + + return builder.String(), nil +} + +// Webhooks formats a slice of smsgateway.Webhook into a single string representation. +// Each webhook's string representation is separated by "---". +// Returns the formatted string and any error encountered during formatting. +func (o *TextOutput) Webhooks(src []smsgateway.Webhook) (string, error) { + if len(src) == 0 { + return "Empty result", nil + } + + builder := strings.Builder{} + + for i, w := range src { + b, err := o.Webhook(w) + if err != nil { + return "", err + } + builder.WriteString(b) + + if i == len(src)-1 { + continue + } + + builder.WriteString("\n---\n") + } + + return builder.String(), nil +} + +// Success returns a string indicating success. +func (*TextOutput) Success() (string, error) { + return "Success", nil +} + +var _ Renderer = (*TextOutput)(nil) From ea7e3d0211b54474a8bfaf0ebebc51239f2c0193 Mon Sep 17 00:00:00 2001 From: Aleksandr Soloshenko Date: Fri, 31 Jan 2025 09:08:36 +0700 Subject: [PATCH 2/2] [actions] add linter --- .github/workflows/go.yml | 59 ++++++++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 18 ------------ 2 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/go.yml delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..0bdc18f --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,59 @@ +name: Go + +on: + push: + branches: [master] + paths: + - "**.go" + - "go.mod" + - "go.sum" + pull_request: + branches: [master] + paths: + - "**.go" + - "go.mod" + - "go.sum" + +jobs: + golangci: + name: Lint + runs-on: ubuntu-latest + steps: + # step 1: checkout repository code + - name: Checkout code into workspace directory + uses: actions/checkout@v4 + + # step 2: set up go + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: stable + + # step 3: run golangci-lint + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + version: latest + args: --timeout=5m + + test: + name: Test + runs-on: ubuntu-latest + steps: + # step 1: checkout repository code + - name: Checkout code into workspace directory + uses: actions/checkout@v4 + + # step 2: set up go + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: stable + + # step 3: install dependencies + - name: Install all Go dependencies + run: go mod download + + # step 4: run test + - name: Run coverage + run: go test -race -coverprofile=coverage.out -covermode=atomic ./... diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 2a61356..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: test - -on: - pull_request: - push: - -permissions: - contents: read - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: stable - - run: go test -v ./...