From ed707ea1eaeb8ceed334030b68080618c337404b Mon Sep 17 00:00:00 2001 From: Anton Prokhorov Date: Tue, 21 Mar 2023 15:33:56 +0000 Subject: [PATCH] Refactor result handlers (#125) Now templates for all result are unified and can be reused in telegram, lark and CLI --- Makefile | 3 + cmd/client/json.go | 103 ------ cmd/client/main.go | 86 +++-- cmd/client/terminal.go | 201 ----------- internal/actions/actions.go | 31 +- internal/actions/dns_records.go | 32 +- internal/actions/events.go | 16 +- internal/actions/http_routes.go | 32 +- internal/actions/mock/Actions.go | 182 ++++++---- internal/actions/mock/ResultHandler.go | 79 +---- internal/actions/payloads.go | 43 ++- internal/actions/user.go | 16 +- internal/actions/users.go | 25 +- internal/actionsdb/dns_records.go | 20 +- internal/actionsdb/events.go | 16 +- internal/actionsdb/http_routes.go | 20 +- internal/actionsdb/payloads.go | 46 ++- internal/actionsdb/user.go | 4 +- internal/actionsdb/user_test.go | 4 +- internal/actionsdb/users.go | 24 +- internal/cmd/cmd.go | 147 +++++--- internal/cmd/cmd_test.go | 56 +-- internal/cmd/generated.go | 329 ++++++++++-------- internal/cmd/utils.go | 15 - internal/codegen/code.go | 42 +-- internal/codegen/main.go | 54 +-- internal/modules/api/api.go | 2 +- internal/modules/api/api_test.go | 26 +- internal/modules/api/apiclient/client_test.go | 4 +- internal/modules/api/apiclient/generated.go | 46 +-- internal/modules/api/apiclient/utils.go | 2 +- internal/modules/api/generated.go | 4 +- internal/modules/lark/lark.go | 88 ++--- internal/modules/lark/result.go | 186 ---------- internal/modules/telegram/notifier.go | 1 - internal/modules/telegram/result.go | 232 ------------ internal/modules/telegram/telegram.go | 152 +++++--- internal/results/json.go | 17 + internal/results/templates.go | 156 +++++++++ internal/results/text.go | 31 ++ 40 files changed, 1133 insertions(+), 1440 deletions(-) delete mode 100644 cmd/client/json.go delete mode 100644 cmd/client/terminal.go delete mode 100644 internal/cmd/utils.go delete mode 100644 internal/modules/lark/result.go delete mode 100644 internal/modules/telegram/result.go create mode 100644 internal/results/json.go create mode 100644 internal/results/templates.go create mode 100644 internal/results/text.go diff --git a/Makefile b/Makefile index a2a52d7..b9653b3 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,9 @@ mock-actions: --outpkg actions_mock \ --name ResultHandler +.PHONY: mock-deps + @go install github.com/vektra/mockery/v2@latest + # # Code generation # diff --git a/cmd/client/json.go b/cmd/client/json.go deleted file mode 100644 index 01afbb9..0000000 --- a/cmd/client/json.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "io" - - "github.com/russtone/sonar/internal/actions" -) - -var _ actions.ResultHandler = &jsonHandler{} - -type jsonHandler struct { - writer io.Writer -} - -func (h *jsonHandler) json(data interface{}) { - json.NewEncoder(h.writer).Encode(data) -} - -// -// User -// - -func (h *jsonHandler) UserCurrent(ctx context.Context, res actions.UserCurrentResult) { - h.json(res) -} - -// -// Payloads -// - -func (h *jsonHandler) PayloadsCreate(ctx context.Context, res actions.PayloadsCreateResult) { - h.json(res) -} - -func (h *jsonHandler) PayloadsList(ctx context.Context, res actions.PayloadsListResult) { - h.json(res) -} - -func (h *jsonHandler) PayloadsUpdate(ctx context.Context, res actions.PayloadsUpdateResult) { - h.json(res) -} - -func (h *jsonHandler) PayloadsDelete(ctx context.Context, res actions.PayloadsDeleteResult) { - h.json(res) -} - -// -// DNS records -// - -func (h *jsonHandler) DNSRecordsCreate(ctx context.Context, res actions.DNSRecordsCreateResult) { - h.json(res) -} - -func (h *jsonHandler) DNSRecordsList(ctx context.Context, res actions.DNSRecordsListResult) { - h.json(res) -} - -func (h *jsonHandler) DNSRecordsDelete(ctx context.Context, res actions.DNSRecordsDeleteResult) { - h.json(res) -} - -// -// HTTP routes -// - -func (h *jsonHandler) HTTPRoutesCreate(ctx context.Context, res actions.HTTPRoutesCreateResult) { - h.json(res) -} - -func (h *jsonHandler) HTTPRoutesList(ctx context.Context, res actions.HTTPRoutesListResult) { - h.json(res) -} - -func (h *jsonHandler) HTTPRoutesDelete(ctx context.Context, res actions.HTTPRoutesDeleteResult) { - h.json(res) -} - -// -// Users -// - -func (h *jsonHandler) UsersCreate(ctx context.Context, res actions.UsersCreateResult) { - h.json(res) -} - -func (h *jsonHandler) UsersDelete(ctx context.Context, res actions.UsersDeleteResult) { - h.json(res) -} - -// -// Events -// - -func (h *jsonHandler) EventsList(ctx context.Context, res actions.EventsListResult) { - h.json(res) -} - -func (h *jsonHandler) EventsGet(ctx context.Context, res actions.EventsGetResult) { - h.json(res) -} diff --git a/cmd/client/main.go b/cmd/client/main.go index e3caddd..6b9de64 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -2,10 +2,14 @@ package main import ( "context" + "encoding/json" + "html/template" "os" "reflect" + "strings" "github.com/adrg/xdg" + validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/gookit/color" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -13,23 +17,15 @@ import ( "github.com/russtone/sonar/internal/actions" "github.com/russtone/sonar/internal/cmd" "github.com/russtone/sonar/internal/modules/api/apiclient" + "github.com/russtone/sonar/internal/results" "github.com/russtone/sonar/internal/utils/slice" ) -func main() { +func init() { + validation.ErrorTag = "err" +} - // Allow "help" and "completion" commands to execute without any - // API requests. - if len(os.Args) > 1 && - (os.Args[1] == "help" || - os.Args[1] == "completion" || - slice.StringsContains(os.Args, "-h") || - slice.StringsContains(os.Args, "--help")) { - root := cmd.New(nil, nil, nil).Root(&actions.User{}, true) - addJSONFlag(root) - root.Execute() - return - } +func main() { // // Config @@ -66,14 +62,6 @@ func main() { client := apiclient.New(srv.URL, srv.Token, srv.Insecure, srv.Proxy) - // - // User - // - - user, err := client.UserCurrent(context.Background()) - if err != nil { - fatal(err) - } // // Command @@ -83,24 +71,56 @@ func main() { // Args are is not yet parsed so just seach for "--json". if slice.StringsContains(os.Args, "--json") { - handler = &jsonHandler{os.Stdout} + handler = &results.JSON{Encoder: json.NewEncoder(os.Stdout)} } else { - handler = &terminalHandler{srv.BaseURL().Hostname()} + handler = &results.Text{ + Templates: results.DefaultTemplates(results.TemplateOptions{ + Markup: map[string]string{ + "": "", + "": "", + "": "", + "": "", + "
":    "",
+					"
": "", + "": "", + "": "", + }, + ExtraFuncs: template.FuncMap{ + "domain": func() string { + return srv.BaseURL().Hostname() + }, + }, + }), + OnText: func(ctx context.Context, message string) { + if !strings.HasSuffix(message, "\n") { + message += "\n" + } + color.Print(message) + }, + } } - root := cmd.New(client, handler, nil).Root(user, true) - addJSONFlag(root) - addContextCmd(&cfg, root) - root.SilenceErrors = true - root.SilenceUsage = true + c := cmd.New( + client, + handler, + cmd.Local(), + cmd.PreExec(preExec(&cfg)), + ) - if err := root.Execute(); err != nil { - fatal(err) - } + c.Exec(context.Background(), os.Args[1:]) } var jsonOutput bool +func preExec(cfg *Config) func(context.Context, *cobra.Command) { + return func(ctx context.Context, root *cobra.Command) { + addJSONFlag(root) + addContextCmd(cfg, root) + root.SilenceErrors = true + root.SilenceUsage = true + } +} + func addJSONFlag(root *cobra.Command) { for _, cmd := range root.Commands() { if cmd.HasSubCommands() { @@ -121,7 +141,7 @@ func addContextCmd(cfg *Config, root *cobra.Command) { cmd := &cobra.Command{ Use: "ctx", Short: "Change current context parameters", - RunE: func(cmd *cobra.Command, args []string) error { + Run: func(cmd *cobra.Command, args []string) { if err := viper.Unmarshal(&cfg); err != nil { fatalf("Fail to unmarshal config: %v", err) @@ -142,8 +162,6 @@ func addContextCmd(cfg *Config, root *cobra.Command) { color.Bold.Print(field.Tag.Get("mapstructure") + ": ") color.Println(v.FieldByName(field.Name)) } - - return nil }, } diff --git a/cmd/client/terminal.go b/cmd/client/terminal.go deleted file mode 100644 index 026a1b1..0000000 --- a/cmd/client/terminal.go +++ /dev/null @@ -1,201 +0,0 @@ -package main - -import ( - "bytes" - "context" - "fmt" - "os" - "strings" - "text/template" - - "github.com/Masterminds/sprig" - "github.com/gookit/color" - - "github.com/russtone/sonar/internal/actions" -) - -func tpl(s string) *template.Template { - return template.Must(template. - New(""). - Funcs(sprig.TxtFuncMap()). - Funcs(template.FuncMap{ - // This is nesessary for templates to compile. - // It will be replaced later with correct function. - "domain": func() string { return "" }, - }). - Parse(s), - ) -} - -var _ actions.ResultHandler = &terminalHandler{} - -type terminalHandler struct { - domain string -} - -func (h *terminalHandler) getDomain() string { - return h.domain -} - -func (h *terminalHandler) txtResult(txt string) { - color.Println(txt) -} - -func (h *terminalHandler) tplResult(tpl *template.Template, data interface{}) { - buf := &bytes.Buffer{} - - tpl.Funcs(template.FuncMap{ - "domain": h.getDomain, - }) - - if err := tpl.Execute(buf, data); err != nil { - color.Error.Println(err) - os.Exit(1) - } - - color.Println(strings.TrimRight(buf.String(), "\n")) -} - -// -// User -// - -var userCurrentTemplate = tpl("" + - "Name: {{ .Name }}\n" + - "Telegram ID: {{ .Params.TelegramID }}\n" + - "API token: {{ .Params.APIToken }}\n" + - "Admin: {{ .IsAdmin }}", -) - -func (h *terminalHandler) UserCurrent(ctx context.Context, res actions.UserCurrentResult) { - h.tplResult(userCurrentTemplate, res) -} - -// -// Payloads -// - -var ( - payload = `[{{ .Name }}] - {{ .Subdomain }}.{{ domain }} ({{ .NotifyProtocols | join ", " }}) ({{ .StoreEvents }})` - - payloadTemplate = tpl(payload) - - payloadsTemplate = tpl(fmt.Sprintf(`{{ range . }}%s -{{ else }}nothing found{{ end }}`, payload)) -) - -func (h *terminalHandler) PayloadsCreate(ctx context.Context, res actions.PayloadsCreateResult) { - h.tplResult(payloadTemplate, res) -} - -func (h *terminalHandler) PayloadsList(ctx context.Context, res actions.PayloadsListResult) { - h.tplResult(payloadsTemplate, res) -} - -func (h *terminalHandler) PayloadsUpdate(ctx context.Context, res actions.PayloadsUpdateResult) { - h.tplResult(payloadTemplate, res) -} - -func (h *terminalHandler) PayloadsDelete(ctx context.Context, res actions.PayloadsDeleteResult) { - h.txtResult(fmt.Sprintf("payload %q deleted", res.Name)) -} - -// -// DNS records -// - -var ( - dnsRecord = ` -{{- $r := . -}} -{{- range $value := .Values -}} -[{{ $r.Index }}] - {{ $r.Name }}.{{ $r.PayloadSubdomain }}.{{ domain }} {{ $r.TTL }} IN {{ $r.Type }} {{ $value }} -{{ end -}}` - - dnsRecordTemplate = tpl(dnsRecord) - - dnsRecordsTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end -}}`, dnsRecord)) -) - -func (h *terminalHandler) DNSRecordsCreate(ctx context.Context, res actions.DNSRecordsCreateResult) { - h.tplResult(dnsRecordTemplate, res) -} - -func (h *terminalHandler) DNSRecordsList(ctx context.Context, res actions.DNSRecordsListResult) { - h.tplResult(dnsRecordsTemplate, res) -} - -func (h *terminalHandler) DNSRecordsDelete(ctx context.Context, res actions.DNSRecordsDeleteResult) { - h.txtResult("dns record deleted") -} - -// -// HTTP routes -// - -var ( - httpRoute = ` -{{- $r := . -}} -[{{ $r.Index }}] - {{ $r.Method }} {{ $r.Path }} -> {{ $r.Code }}` - - httpRouteTemplate = tpl(httpRoute) - - httpRoutesTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end }}`, httpRoute)) -) - -func (h *terminalHandler) HTTPRoutesCreate(ctx context.Context, res actions.HTTPRoutesCreateResult) { - h.tplResult(httpRouteTemplate, res) -} - -func (h *terminalHandler) HTTPRoutesList(ctx context.Context, res actions.HTTPRoutesListResult) { - h.tplResult(httpRoutesTemplate, res) -} - -func (h *terminalHandler) HTTPRoutesDelete(ctx context.Context, res actions.HTTPRoutesDeleteResult) { - h.txtResult("http route deleted") -} - -// -// Users -// - -func (h *terminalHandler) UsersCreate(ctx context.Context, res actions.UsersCreateResult) { - h.txtResult(fmt.Sprintf("user %q created", res.Name)) -} - -func (h *terminalHandler) UsersDelete(ctx context.Context, res actions.UsersDeleteResult) { - h.txtResult(fmt.Sprintf("user %q deleted", res.Name)) -} - -// -// Events -// - -var ( - event = ` -{{- $e := . -}} -[{{ $e.Index }}] - {{ $e.Protocol | upper }} from {{ $e.RemoteAddr }} at {{ $e.ReceivedAt }}` - - eventTemplate = tpl(event + ` - -{{ $e.RW | b64dec }} -`) - - eventsTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end -}}`, event)) -) - -func (h *terminalHandler) EventsList(ctx context.Context, res actions.EventsListResult) { - h.tplResult(eventsTemplate, res) -} - -func (h *terminalHandler) EventsGet(ctx context.Context, res actions.EventsGetResult) { - h.tplResult(eventTemplate, res) -} diff --git a/internal/actions/actions.go b/internal/actions/actions.go index 6ddda37..ff9ff1a 100644 --- a/internal/actions/actions.go +++ b/internal/actions/actions.go @@ -1,6 +1,8 @@ package actions import ( + "context" + validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/spf13/cobra" @@ -15,18 +17,33 @@ type Actions interface { PayloadsActions UsersActions DNSActions - UserActions + ProfileActions EventsActions HTTPActions } +type Result interface { + ResultID() string +} + +type TextResult struct { + Text string +} + +func (s TextResult) ResultID() string { + return "text" +} + +type ErrorResult struct { + Error errors.Error +} + +func (e ErrorResult) ResultID() string { + return "error" +} + type ResultHandler interface { - PayloadsHandler - DNSRecordsHandler - UsersHandler - UserHandler - EventsHandler - HTTPRoutesHandler + OnResult(context.Context, Result) } type PrepareCommandFunc func(*cobra.Command, []string) errors.Error diff --git a/internal/actions/dns_records.go b/internal/actions/dns_records.go index ab5c8be..e4e42a6 100644 --- a/internal/actions/dns_records.go +++ b/internal/actions/dns_records.go @@ -15,17 +15,11 @@ import ( ) type DNSActions interface { - DNSRecordsCreate(context.Context, DNSRecordsCreateParams) (DNSRecordsCreateResult, errors.Error) - DNSRecordsDelete(context.Context, DNSRecordsDeleteParams) (DNSRecordsDeleteResult, errors.Error) + DNSRecordsCreate(context.Context, DNSRecordsCreateParams) (*DNSRecordsCreateResult, errors.Error) + DNSRecordsDelete(context.Context, DNSRecordsDeleteParams) (*DNSRecordsDeleteResult, errors.Error) DNSRecordsList(context.Context, DNSRecordsListParams) (DNSRecordsListResult, errors.Error) } -type DNSRecordsHandler interface { - DNSRecordsCreate(context.Context, DNSRecordsCreateResult) - DNSRecordsList(context.Context, DNSRecordsListResult) - DNSRecordsDelete(context.Context, DNSRecordsDeleteResult) -} - type DNSRecord struct { Index int64 `json:"index"` PayloadSubdomain string `json:"payloadSubdomain"` @@ -60,7 +54,13 @@ func (p DNSRecordsCreateParams) Validate() error { ) } -type DNSRecordsCreateResult *DNSRecord +type DNSRecordsCreateResult struct { + DNSRecord +} + +func (r DNSRecordsCreateResult) ResultID() string { + return "dns-records/create" +} func DNSRecordsCreateCommand(p *DNSRecordsCreateParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -99,7 +99,13 @@ func (p DNSRecordsDeleteParams) Validate() error { ) } -type DNSRecordsDeleteResult *DNSRecord +type DNSRecordsDeleteResult struct { + DNSRecord +} + +func (r DNSRecordsDeleteResult) ResultID() string { + return "dns-records/delete" +} func DNSRecordsDeleteCommand(p *DNSRecordsDeleteParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -135,7 +141,11 @@ func (p DNSRecordsListParams) Validate() error { ) } -type DNSRecordsListResult []*DNSRecord +type DNSRecordsListResult []DNSRecord + +func (r DNSRecordsListResult) ResultID() string { + return "dns-records/list" +} func DNSRecordsListCommand(p *DNSRecordsListParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ diff --git a/internal/actions/events.go b/internal/actions/events.go index 30dcd1b..d088e24 100644 --- a/internal/actions/events.go +++ b/internal/actions/events.go @@ -13,7 +13,7 @@ import ( type EventsActions interface { EventsList(context.Context, EventsListParams) (EventsListResult, errors.Error) - EventsGet(context.Context, EventsGetParams) (EventsGetResult, errors.Error) + EventsGet(context.Context, EventsGetParams) (*EventsGetResult, errors.Error) } type EventsHandler interface { @@ -50,7 +50,11 @@ func (p EventsListParams) Validate() error { ) } -type EventsListResult []*Event +type EventsListResult []Event + +func (r EventsListResult) ResultID() string { + return "events/list" +} func EventsListCommand(p *EventsListParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -83,7 +87,13 @@ func (p EventsGetParams) Validate() error { ) } -type EventsGetResult *Event +type EventsGetResult struct { + Event +} + +func (r EventsGetResult) ResultID() string { + return "events/get" +} func EventsGetCommand(p *EventsGetParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ diff --git a/internal/actions/http_routes.go b/internal/actions/http_routes.go index 6a95a51..6dec54f 100644 --- a/internal/actions/http_routes.go +++ b/internal/actions/http_routes.go @@ -19,17 +19,11 @@ import ( ) type HTTPActions interface { - HTTPRoutesCreate(context.Context, HTTPRoutesCreateParams) (HTTPRoutesCreateResult, errors.Error) - HTTPRoutesDelete(context.Context, HTTPRoutesDeleteParams) (HTTPRoutesDeleteResult, errors.Error) + HTTPRoutesCreate(context.Context, HTTPRoutesCreateParams) (*HTTPRoutesCreateResult, errors.Error) + HTTPRoutesDelete(context.Context, HTTPRoutesDeleteParams) (*HTTPRoutesDeleteResult, errors.Error) HTTPRoutesList(context.Context, HTTPRoutesListParams) (HTTPRoutesListResult, errors.Error) } -type HTTPRoutesHandler interface { - HTTPRoutesCreate(context.Context, HTTPRoutesCreateResult) - HTTPRoutesList(context.Context, HTTPRoutesListResult) - HTTPRoutesDelete(context.Context, HTTPRoutesDeleteResult) -} - type HTTPRoute struct { Index int64 `json:"index"` PayloadSubdomain string `json:"payloadSubdomain"` @@ -69,7 +63,13 @@ func (p HTTPRoutesCreateParams) Validate() error { ) } -type HTTPRoutesCreateResult *HTTPRoute +type HTTPRoutesCreateResult struct { + HTTPRoute +} + +func (r HTTPRoutesCreateResult) ResultID() string { + return "http-routes/create" +} func HTTPRoutesCreateCommand(p *HTTPRoutesCreateParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -148,7 +148,13 @@ func (p HTTPRoutesDeleteParams) Validate() error { ) } -type HTTPRoutesDeleteResult *HTTPRoute +type HTTPRoutesDeleteResult struct { + HTTPRoute +} + +func (r HTTPRoutesDeleteResult) ResultID() string { + return "http-routes/delete" +} func HTTPRoutesDeleteCommand(p *HTTPRoutesDeleteParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -184,7 +190,11 @@ func (p HTTPRoutesListParams) Validate() error { ) } -type HTTPRoutesListResult []*HTTPRoute +type HTTPRoutesListResult []HTTPRoute + +func (r HTTPRoutesListResult) ResultID() string { + return "http-routes/list" +} func HTTPRoutesListCommand(p *HTTPRoutesListParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ diff --git a/internal/actions/mock/Actions.go b/internal/actions/mock/Actions.go index cf3bb82..5a28390 100644 --- a/internal/actions/mock/Actions.go +++ b/internal/actions/mock/Actions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery v2.23.0. DO NOT EDIT. package actions_mock @@ -18,19 +18,22 @@ type Actions struct { } // DNSRecordsCreate provides a mock function with given fields: _a0, _a1 -func (_m *Actions) DNSRecordsCreate(_a0 context.Context, _a1 actions.DNSRecordsCreateParams) (actions.DNSRecordsCreateResult, errors.Error) { +func (_m *Actions) DNSRecordsCreate(_a0 context.Context, _a1 actions.DNSRecordsCreateParams) (*actions.DNSRecordsCreateResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.DNSRecordsCreateResult - if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsCreateParams) actions.DNSRecordsCreateResult); ok { + var r0 *actions.DNSRecordsCreateResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsCreateParams) (*actions.DNSRecordsCreateResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsCreateParams) *actions.DNSRecordsCreateResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.DNSRecordsCreateResult) + r0 = ret.Get(0).(*actions.DNSRecordsCreateResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.DNSRecordsCreateParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -43,19 +46,22 @@ func (_m *Actions) DNSRecordsCreate(_a0 context.Context, _a1 actions.DNSRecordsC } // DNSRecordsDelete provides a mock function with given fields: _a0, _a1 -func (_m *Actions) DNSRecordsDelete(_a0 context.Context, _a1 actions.DNSRecordsDeleteParams) (actions.DNSRecordsDeleteResult, errors.Error) { +func (_m *Actions) DNSRecordsDelete(_a0 context.Context, _a1 actions.DNSRecordsDeleteParams) (*actions.DNSRecordsDeleteResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.DNSRecordsDeleteResult - if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsDeleteParams) actions.DNSRecordsDeleteResult); ok { + var r0 *actions.DNSRecordsDeleteResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsDeleteParams) (*actions.DNSRecordsDeleteResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsDeleteParams) *actions.DNSRecordsDeleteResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.DNSRecordsDeleteResult) + r0 = ret.Get(0).(*actions.DNSRecordsDeleteResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.DNSRecordsDeleteParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -72,6 +78,10 @@ func (_m *Actions) DNSRecordsList(_a0 context.Context, _a1 actions.DNSRecordsLis ret := _m.Called(_a0, _a1) var r0 actions.DNSRecordsListResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsListParams) (actions.DNSRecordsListResult, errors.Error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, actions.DNSRecordsListParams) actions.DNSRecordsListResult); ok { r0 = rf(_a0, _a1) } else { @@ -80,7 +90,6 @@ func (_m *Actions) DNSRecordsList(_a0 context.Context, _a1 actions.DNSRecordsLis } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.DNSRecordsListParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -93,19 +102,22 @@ func (_m *Actions) DNSRecordsList(_a0 context.Context, _a1 actions.DNSRecordsLis } // EventsGet provides a mock function with given fields: _a0, _a1 -func (_m *Actions) EventsGet(_a0 context.Context, _a1 actions.EventsGetParams) (actions.EventsGetResult, errors.Error) { +func (_m *Actions) EventsGet(_a0 context.Context, _a1 actions.EventsGetParams) (*actions.EventsGetResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.EventsGetResult - if rf, ok := ret.Get(0).(func(context.Context, actions.EventsGetParams) actions.EventsGetResult); ok { + var r0 *actions.EventsGetResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.EventsGetParams) (*actions.EventsGetResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.EventsGetParams) *actions.EventsGetResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.EventsGetResult) + r0 = ret.Get(0).(*actions.EventsGetResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.EventsGetParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -122,6 +134,10 @@ func (_m *Actions) EventsList(_a0 context.Context, _a1 actions.EventsListParams) ret := _m.Called(_a0, _a1) var r0 actions.EventsListResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.EventsListParams) (actions.EventsListResult, errors.Error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, actions.EventsListParams) actions.EventsListResult); ok { r0 = rf(_a0, _a1) } else { @@ -130,7 +146,6 @@ func (_m *Actions) EventsList(_a0 context.Context, _a1 actions.EventsListParams) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.EventsListParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -143,19 +158,22 @@ func (_m *Actions) EventsList(_a0 context.Context, _a1 actions.EventsListParams) } // HTTPRoutesCreate provides a mock function with given fields: _a0, _a1 -func (_m *Actions) HTTPRoutesCreate(_a0 context.Context, _a1 actions.HTTPRoutesCreateParams) (actions.HTTPRoutesCreateResult, errors.Error) { +func (_m *Actions) HTTPRoutesCreate(_a0 context.Context, _a1 actions.HTTPRoutesCreateParams) (*actions.HTTPRoutesCreateResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.HTTPRoutesCreateResult - if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesCreateParams) actions.HTTPRoutesCreateResult); ok { + var r0 *actions.HTTPRoutesCreateResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesCreateParams) (*actions.HTTPRoutesCreateResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesCreateParams) *actions.HTTPRoutesCreateResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.HTTPRoutesCreateResult) + r0 = ret.Get(0).(*actions.HTTPRoutesCreateResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.HTTPRoutesCreateParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -168,19 +186,22 @@ func (_m *Actions) HTTPRoutesCreate(_a0 context.Context, _a1 actions.HTTPRoutesC } // HTTPRoutesDelete provides a mock function with given fields: _a0, _a1 -func (_m *Actions) HTTPRoutesDelete(_a0 context.Context, _a1 actions.HTTPRoutesDeleteParams) (actions.HTTPRoutesDeleteResult, errors.Error) { +func (_m *Actions) HTTPRoutesDelete(_a0 context.Context, _a1 actions.HTTPRoutesDeleteParams) (*actions.HTTPRoutesDeleteResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.HTTPRoutesDeleteResult - if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesDeleteParams) actions.HTTPRoutesDeleteResult); ok { + var r0 *actions.HTTPRoutesDeleteResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesDeleteParams) (*actions.HTTPRoutesDeleteResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesDeleteParams) *actions.HTTPRoutesDeleteResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.HTTPRoutesDeleteResult) + r0 = ret.Get(0).(*actions.HTTPRoutesDeleteResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.HTTPRoutesDeleteParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -197,6 +218,10 @@ func (_m *Actions) HTTPRoutesList(_a0 context.Context, _a1 actions.HTTPRoutesLis ret := _m.Called(_a0, _a1) var r0 actions.HTTPRoutesListResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesListParams) (actions.HTTPRoutesListResult, errors.Error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, actions.HTTPRoutesListParams) actions.HTTPRoutesListResult); ok { r0 = rf(_a0, _a1) } else { @@ -205,7 +230,6 @@ func (_m *Actions) HTTPRoutesList(_a0 context.Context, _a1 actions.HTTPRoutesLis } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.HTTPRoutesListParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -218,19 +242,22 @@ func (_m *Actions) HTTPRoutesList(_a0 context.Context, _a1 actions.HTTPRoutesLis } // PayloadsCreate provides a mock function with given fields: _a0, _a1 -func (_m *Actions) PayloadsCreate(_a0 context.Context, _a1 actions.PayloadsCreateParams) (actions.PayloadsCreateResult, errors.Error) { +func (_m *Actions) PayloadsCreate(_a0 context.Context, _a1 actions.PayloadsCreateParams) (*actions.PayloadsCreateResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.PayloadsCreateResult - if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsCreateParams) actions.PayloadsCreateResult); ok { + var r0 *actions.PayloadsCreateResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsCreateParams) (*actions.PayloadsCreateResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsCreateParams) *actions.PayloadsCreateResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.PayloadsCreateResult) + r0 = ret.Get(0).(*actions.PayloadsCreateResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.PayloadsCreateParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -243,19 +270,22 @@ func (_m *Actions) PayloadsCreate(_a0 context.Context, _a1 actions.PayloadsCreat } // PayloadsDelete provides a mock function with given fields: _a0, _a1 -func (_m *Actions) PayloadsDelete(_a0 context.Context, _a1 actions.PayloadsDeleteParams) (actions.PayloadsDeleteResult, errors.Error) { +func (_m *Actions) PayloadsDelete(_a0 context.Context, _a1 actions.PayloadsDeleteParams) (*actions.PayloadsDeleteResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.PayloadsDeleteResult - if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsDeleteParams) actions.PayloadsDeleteResult); ok { + var r0 *actions.PayloadsDeleteResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsDeleteParams) (*actions.PayloadsDeleteResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsDeleteParams) *actions.PayloadsDeleteResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.PayloadsDeleteResult) + r0 = ret.Get(0).(*actions.PayloadsDeleteResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.PayloadsDeleteParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -272,6 +302,10 @@ func (_m *Actions) PayloadsList(_a0 context.Context, _a1 actions.PayloadsListPar ret := _m.Called(_a0, _a1) var r0 actions.PayloadsListResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsListParams) (actions.PayloadsListResult, errors.Error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsListParams) actions.PayloadsListResult); ok { r0 = rf(_a0, _a1) } else { @@ -280,7 +314,6 @@ func (_m *Actions) PayloadsList(_a0 context.Context, _a1 actions.PayloadsListPar } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.PayloadsListParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -293,19 +326,22 @@ func (_m *Actions) PayloadsList(_a0 context.Context, _a1 actions.PayloadsListPar } // PayloadsUpdate provides a mock function with given fields: _a0, _a1 -func (_m *Actions) PayloadsUpdate(_a0 context.Context, _a1 actions.PayloadsUpdateParams) (actions.PayloadsUpdateResult, errors.Error) { +func (_m *Actions) PayloadsUpdate(_a0 context.Context, _a1 actions.PayloadsUpdateParams) (*actions.PayloadsUpdateResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.PayloadsUpdateResult - if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsUpdateParams) actions.PayloadsUpdateResult); ok { + var r0 *actions.PayloadsUpdateResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsUpdateParams) (*actions.PayloadsUpdateResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.PayloadsUpdateParams) *actions.PayloadsUpdateResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.PayloadsUpdateResult) + r0 = ret.Get(0).(*actions.PayloadsUpdateResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.PayloadsUpdateParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -317,20 +353,23 @@ func (_m *Actions) PayloadsUpdate(_a0 context.Context, _a1 actions.PayloadsUpdat return r0, r1 } -// UserCurrent provides a mock function with given fields: _a0 -func (_m *Actions) UserCurrent(_a0 context.Context) (actions.UserCurrentResult, errors.Error) { +// ProfileGet provides a mock function with given fields: _a0 +func (_m *Actions) ProfileGet(_a0 context.Context) (*actions.ProfileGetResult, errors.Error) { ret := _m.Called(_a0) - var r0 actions.UserCurrentResult - if rf, ok := ret.Get(0).(func(context.Context) actions.UserCurrentResult); ok { + var r0 *actions.ProfileGetResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context) (*actions.ProfileGetResult, errors.Error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) *actions.ProfileGetResult); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.UserCurrentResult) + r0 = ret.Get(0).(*actions.ProfileGetResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context) errors.Error); ok { r1 = rf(_a0) } else { @@ -343,19 +382,22 @@ func (_m *Actions) UserCurrent(_a0 context.Context) (actions.UserCurrentResult, } // UsersCreate provides a mock function with given fields: _a0, _a1 -func (_m *Actions) UsersCreate(_a0 context.Context, _a1 actions.UsersCreateParams) (actions.UsersCreateResult, errors.Error) { +func (_m *Actions) UsersCreate(_a0 context.Context, _a1 actions.UsersCreateParams) (*actions.UsersCreateResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.UsersCreateResult - if rf, ok := ret.Get(0).(func(context.Context, actions.UsersCreateParams) actions.UsersCreateResult); ok { + var r0 *actions.UsersCreateResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.UsersCreateParams) (*actions.UsersCreateResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.UsersCreateParams) *actions.UsersCreateResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.UsersCreateResult) + r0 = ret.Get(0).(*actions.UsersCreateResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.UsersCreateParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -368,19 +410,22 @@ func (_m *Actions) UsersCreate(_a0 context.Context, _a1 actions.UsersCreateParam } // UsersDelete provides a mock function with given fields: _a0, _a1 -func (_m *Actions) UsersDelete(_a0 context.Context, _a1 actions.UsersDeleteParams) (actions.UsersDeleteResult, errors.Error) { +func (_m *Actions) UsersDelete(_a0 context.Context, _a1 actions.UsersDeleteParams) (*actions.UsersDeleteResult, errors.Error) { ret := _m.Called(_a0, _a1) - var r0 actions.UsersDeleteResult - if rf, ok := ret.Get(0).(func(context.Context, actions.UsersDeleteParams) actions.UsersDeleteResult); ok { + var r0 *actions.UsersDeleteResult + var r1 errors.Error + if rf, ok := ret.Get(0).(func(context.Context, actions.UsersDeleteParams) (*actions.UsersDeleteResult, errors.Error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, actions.UsersDeleteParams) *actions.UsersDeleteResult); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(actions.UsersDeleteResult) + r0 = ret.Get(0).(*actions.UsersDeleteResult) } } - var r1 errors.Error if rf, ok := ret.Get(1).(func(context.Context, actions.UsersDeleteParams) errors.Error); ok { r1 = rf(_a0, _a1) } else { @@ -391,3 +436,18 @@ func (_m *Actions) UsersDelete(_a0 context.Context, _a1 actions.UsersDeleteParam return r0, r1 } + +type mockConstructorTestingTNewActions interface { + mock.TestingT + Cleanup(func()) +} + +// NewActions creates a new instance of Actions. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewActions(t mockConstructorTestingTNewActions) *Actions { + mock := &Actions{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/actions/mock/ResultHandler.go b/internal/actions/mock/ResultHandler.go index 1f56373..37d9189 100644 --- a/internal/actions/mock/ResultHandler.go +++ b/internal/actions/mock/ResultHandler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery v2.23.0. DO NOT EDIT. package actions_mock @@ -15,77 +15,22 @@ type ResultHandler struct { mock.Mock } -// DNSRecordsCreate provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) DNSRecordsCreate(_a0 context.Context, _a1 actions.DNSRecordsCreateResult) { +// OnResult provides a mock function with given fields: _a0, _a1 +func (_m *ResultHandler) OnResult(_a0 context.Context, _a1 actions.Result) { _m.Called(_a0, _a1) } -// DNSRecordsDelete provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) DNSRecordsDelete(_a0 context.Context, _a1 actions.DNSRecordsDeleteResult) { - _m.Called(_a0, _a1) -} - -// DNSRecordsList provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) DNSRecordsList(_a0 context.Context, _a1 actions.DNSRecordsListResult) { - _m.Called(_a0, _a1) -} - -// EventsGet provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) EventsGet(_a0 context.Context, _a1 actions.EventsGetResult) { - _m.Called(_a0, _a1) -} - -// EventsList provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) EventsList(_a0 context.Context, _a1 actions.EventsListResult) { - _m.Called(_a0, _a1) -} - -// HTTPRoutesCreate provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) HTTPRoutesCreate(_a0 context.Context, _a1 actions.HTTPRoutesCreateResult) { - _m.Called(_a0, _a1) -} - -// HTTPRoutesDelete provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) HTTPRoutesDelete(_a0 context.Context, _a1 actions.HTTPRoutesDeleteResult) { - _m.Called(_a0, _a1) -} - -// HTTPRoutesList provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) HTTPRoutesList(_a0 context.Context, _a1 actions.HTTPRoutesListResult) { - _m.Called(_a0, _a1) -} - -// PayloadsCreate provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) PayloadsCreate(_a0 context.Context, _a1 actions.PayloadsCreateResult) { - _m.Called(_a0, _a1) -} - -// PayloadsDelete provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) PayloadsDelete(_a0 context.Context, _a1 actions.PayloadsDeleteResult) { - _m.Called(_a0, _a1) -} - -// PayloadsList provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) PayloadsList(_a0 context.Context, _a1 actions.PayloadsListResult) { - _m.Called(_a0, _a1) +type mockConstructorTestingTNewResultHandler interface { + mock.TestingT + Cleanup(func()) } -// PayloadsUpdate provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) PayloadsUpdate(_a0 context.Context, _a1 actions.PayloadsUpdateResult) { - _m.Called(_a0, _a1) -} +// NewResultHandler creates a new instance of ResultHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewResultHandler(t mockConstructorTestingTNewResultHandler) *ResultHandler { + mock := &ResultHandler{} + mock.Mock.Test(t) -// UserCurrent provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) UserCurrent(_a0 context.Context, _a1 actions.UserCurrentResult) { - _m.Called(_a0, _a1) -} + t.Cleanup(func() { mock.AssertExpectations(t) }) -// UsersCreate provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) UsersCreate(_a0 context.Context, _a1 actions.UsersCreateResult) { - _m.Called(_a0, _a1) -} - -// UsersDelete provides a mock function with given fields: _a0, _a1 -func (_m *ResultHandler) UsersDelete(_a0 context.Context, _a1 actions.UsersDeleteResult) { - _m.Called(_a0, _a1) + return mock } diff --git a/internal/actions/payloads.go b/internal/actions/payloads.go index 7e55e0b..a278b56 100644 --- a/internal/actions/payloads.go +++ b/internal/actions/payloads.go @@ -13,19 +13,12 @@ import ( ) type PayloadsActions interface { - PayloadsCreate(context.Context, PayloadsCreateParams) (PayloadsCreateResult, errors.Error) - PayloadsUpdate(context.Context, PayloadsUpdateParams) (PayloadsUpdateResult, errors.Error) - PayloadsDelete(context.Context, PayloadsDeleteParams) (PayloadsDeleteResult, errors.Error) + PayloadsCreate(context.Context, PayloadsCreateParams) (*PayloadsCreateResult, errors.Error) + PayloadsUpdate(context.Context, PayloadsUpdateParams) (*PayloadsUpdateResult, errors.Error) + PayloadsDelete(context.Context, PayloadsDeleteParams) (*PayloadsDeleteResult, errors.Error) PayloadsList(context.Context, PayloadsListParams) (PayloadsListResult, errors.Error) } -type PayloadsHandler interface { - PayloadsCreate(context.Context, PayloadsCreateResult) - PayloadsList(context.Context, PayloadsListResult) - PayloadsUpdate(context.Context, PayloadsUpdateResult) - PayloadsDelete(context.Context, PayloadsDeleteResult) -} - type Payload struct { Subdomain string `json:"subdomain"` Name string `json:"name"` @@ -54,7 +47,13 @@ func (p PayloadsCreateParams) Validate() error { ) } -type PayloadsCreateResult *Payload +type PayloadsCreateResult struct { + Payload +} + +func (r PayloadsCreateResult) ResultID() string { + return "payloads/create" +} func PayloadsCreateCommand(p *PayloadsCreateParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -95,7 +94,13 @@ func (p PayloadsUpdateParams) Validate() error { ) } -type PayloadsUpdateResult *Payload +type PayloadsUpdateResult struct { + Payload +} + +func (r PayloadsUpdateResult) ResultID() string { + return "payloads/update" +} func PayloadsUpdateCommand(p *PayloadsUpdateParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -135,7 +140,13 @@ func (p PayloadsDeleteParams) Validate() error { validation.Field(&p.Name, validation.Required)) } -type PayloadsDeleteResult *Payload +type PayloadsDeleteResult struct { + Payload +} + +func (r PayloadsDeleteResult) ResultID() string { + return "payloads/delete" +} func PayloadsDeleteCommand(p *PayloadsDeleteParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -163,7 +174,11 @@ func (p PayloadsListParams) Validate() error { return nil } -type PayloadsListResult []*Payload +type PayloadsListResult []Payload + +func (r PayloadsListResult) ResultID() string { + return "payloads/list" +} func PayloadsListCommand(p *PayloadsListParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ diff --git a/internal/actions/user.go b/internal/actions/user.go index 8137ec4..793a20f 100644 --- a/internal/actions/user.go +++ b/internal/actions/user.go @@ -8,19 +8,21 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -type UserActions interface { - UserCurrent(context.Context) (UserCurrentResult, errors.Error) +type ProfileActions interface { + ProfileGet(context.Context) (*ProfileGetResult, errors.Error) } -type UserHandler interface { - UserCurrent(context.Context, UserCurrentResult) +type ProfileGetResult struct { + User } -type UserCurrentResult *User +func (r ProfileGetResult) ResultID() string { + return "profile/get" +} -func UserCurrentCommand(local bool) (*cobra.Command, PrepareCommandFunc) { +func ProfileGetCommand(local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ - Use: "user", + Use: "profile", Short: "Get current user info", } diff --git a/internal/actions/users.go b/internal/actions/users.go index d47adfa..d3383f8 100644 --- a/internal/actions/users.go +++ b/internal/actions/users.go @@ -12,13 +12,8 @@ import ( ) type UsersActions interface { - UsersCreate(context.Context, UsersCreateParams) (UsersCreateResult, errors.Error) - UsersDelete(context.Context, UsersDeleteParams) (UsersDeleteResult, errors.Error) -} - -type UsersHandler interface { - UsersCreate(context.Context, UsersCreateResult) - UsersDelete(context.Context, UsersDeleteResult) + UsersCreate(context.Context, UsersCreateParams) (*UsersCreateResult, errors.Error) + UsersDelete(context.Context, UsersDeleteParams) (*UsersDeleteResult, errors.Error) } type User struct { @@ -43,7 +38,13 @@ func (p UsersCreateParams) Validate() error { validation.Field(&p.Name, validation.Required)) } -type UsersCreateResult *User +type UsersCreateResult struct { + User +} + +func (r UsersCreateResult) ResultID() string { + return "users/create" +} func UsersCreateCommand(p *UsersCreateParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ @@ -81,7 +82,13 @@ func (p UsersDeleteParams) Validate() error { validation.Field(&p.Name, validation.Required)) } -type UsersDeleteResult *User +type UsersDeleteResult struct { + User +} + +func (r UsersDeleteResult) ResultID() string { + return "users/delete" +} func UsersDeleteCommand(p *UsersDeleteParams, local bool) (*cobra.Command, PrepareCommandFunc) { cmd := &cobra.Command{ diff --git a/internal/actionsdb/dns_records.go b/internal/actionsdb/dns_records.go index 537cb7d..8cb52ab 100644 --- a/internal/actionsdb/dns_records.go +++ b/internal/actionsdb/dns_records.go @@ -10,12 +10,8 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func DNSRecord(m *models.DNSRecord, payloadSubdomain string) *actions.DNSRecord { - if m == nil { - return nil - } - - return &actions.DNSRecord{ +func DNSRecord(m models.DNSRecord, payloadSubdomain string) actions.DNSRecord { + return actions.DNSRecord{ Index: m.Index, PayloadSubdomain: payloadSubdomain, Name: m.Name, @@ -27,7 +23,7 @@ func DNSRecord(m *models.DNSRecord, payloadSubdomain string) *actions.DNSRecord } } -func (act *dbactions) DNSRecordsCreate(ctx context.Context, p actions.DNSRecordsCreateParams) (actions.DNSRecordsCreateResult, errors.Error) { +func (act *dbactions) DNSRecordsCreate(ctx context.Context, p actions.DNSRecordsCreateParams) (*actions.DNSRecordsCreateResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -60,10 +56,10 @@ func (act *dbactions) DNSRecordsCreate(ctx context.Context, p actions.DNSRecords return nil, errors.Internal(err) } - return DNSRecord(rec, payload.Subdomain), nil + return &actions.DNSRecordsCreateResult{DNSRecord(*rec, payload.Subdomain)}, nil } -func (act *dbactions) DNSRecordsDelete(ctx context.Context, p actions.DNSRecordsDeleteParams) (actions.DNSRecordsDeleteResult, errors.Error) { +func (act *dbactions) DNSRecordsDelete(ctx context.Context, p actions.DNSRecordsDeleteParams) (*actions.DNSRecordsDeleteResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -90,7 +86,7 @@ func (act *dbactions) DNSRecordsDelete(ctx context.Context, p actions.DNSRecords return nil, errors.Internal(err) } - return DNSRecord(rec, payload.Subdomain), nil + return &actions.DNSRecordsDeleteResult{DNSRecord(*rec, payload.Subdomain)}, nil } func (act *dbactions) DNSRecordsList(ctx context.Context, p actions.DNSRecordsListParams) (actions.DNSRecordsListResult, errors.Error) { @@ -113,10 +109,10 @@ func (act *dbactions) DNSRecordsList(ctx context.Context, p actions.DNSRecordsLi return nil, errors.Internal(err) } - res := make([]*actions.DNSRecord, 0) + res := make([]actions.DNSRecord, 0) for _, r := range recs { - res = append(res, DNSRecord(r, payload.Subdomain)) + res = append(res, DNSRecord(*r, payload.Subdomain)) } return res, nil diff --git a/internal/actionsdb/events.go b/internal/actionsdb/events.go index 257e02a..93951b7 100644 --- a/internal/actionsdb/events.go +++ b/internal/actionsdb/events.go @@ -11,12 +11,8 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func Event(m *models.Event) *actions.Event { - if m == nil { - return nil - } - - return &actions.Event{ +func Event(m models.Event) actions.Event { + return actions.Event{ Index: m.Index, Protocol: m.Protocol.String(), R: base64.StdEncoding.EncodeToString(m.R), @@ -55,16 +51,16 @@ func (act *dbactions) EventsList(ctx context.Context, p actions.EventsListParams return nil, errors.Internal(err) } - res := make([]*actions.Event, 0) + res := make([]actions.Event, 0) for _, r := range recs { - res = append(res, Event(r)) + res = append(res, Event(*r)) } return res, nil } -func (act *dbactions) EventsGet(ctx context.Context, p actions.EventsGetParams) (actions.EventsGetResult, errors.Error) { +func (act *dbactions) EventsGet(ctx context.Context, p actions.EventsGetParams) (*actions.EventsGetResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -84,5 +80,5 @@ func (act *dbactions) EventsGet(ctx context.Context, p actions.EventsGetParams) return nil, errors.Internal(err) } - return Event(r), nil + return &actions.EventsGetResult{Event(*r)}, nil } diff --git a/internal/actionsdb/http_routes.go b/internal/actionsdb/http_routes.go index c2624a4..8c32fae 100644 --- a/internal/actionsdb/http_routes.go +++ b/internal/actionsdb/http_routes.go @@ -11,12 +11,8 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func HTTPRoute(m *models.HTTPRoute, payloadSubdomain string) *actions.HTTPRoute { - if m == nil { - return nil - } - - return &actions.HTTPRoute{ +func HTTPRoute(m models.HTTPRoute, payloadSubdomain string) actions.HTTPRoute { + return actions.HTTPRoute{ Index: m.Index, PayloadSubdomain: payloadSubdomain, Method: m.Method, @@ -29,7 +25,7 @@ func HTTPRoute(m *models.HTTPRoute, payloadSubdomain string) *actions.HTTPRoute } } -func (act *dbactions) HTTPRoutesCreate(ctx context.Context, p actions.HTTPRoutesCreateParams) (actions.HTTPRoutesCreateResult, errors.Error) { +func (act *dbactions) HTTPRoutesCreate(ctx context.Context, p actions.HTTPRoutesCreateParams) (*actions.HTTPRoutesCreateResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -69,10 +65,10 @@ func (act *dbactions) HTTPRoutesCreate(ctx context.Context, p actions.HTTPRoutes return nil, errors.Internal(err) } - return HTTPRoute(rec, payload.Subdomain), nil + return &actions.HTTPRoutesCreateResult{HTTPRoute(*rec, payload.Subdomain)}, nil } -func (act *dbactions) HTTPRoutesDelete(ctx context.Context, p actions.HTTPRoutesDeleteParams) (actions.HTTPRoutesDeleteResult, errors.Error) { +func (act *dbactions) HTTPRoutesDelete(ctx context.Context, p actions.HTTPRoutesDeleteParams) (*actions.HTTPRoutesDeleteResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -99,7 +95,7 @@ func (act *dbactions) HTTPRoutesDelete(ctx context.Context, p actions.HTTPRoutes return nil, errors.Internal(err) } - return HTTPRoute(rec, payload.Subdomain), nil + return &actions.HTTPRoutesDeleteResult{HTTPRoute(*rec, payload.Subdomain)}, nil } func (act *dbactions) HTTPRoutesList(ctx context.Context, p actions.HTTPRoutesListParams) (actions.HTTPRoutesListResult, errors.Error) { @@ -122,10 +118,10 @@ func (act *dbactions) HTTPRoutesList(ctx context.Context, p actions.HTTPRoutesLi return nil, errors.Internal(err) } - res := make([]*actions.HTTPRoute, 0) + res := make([]actions.HTTPRoute, 0) for _, r := range recs { - res = append(res, HTTPRoute(r, payload.Subdomain)) + res = append(res, HTTPRoute(*r, payload.Subdomain)) } return res, nil diff --git a/internal/actionsdb/payloads.go b/internal/actionsdb/payloads.go index 40134a2..4417fe9 100644 --- a/internal/actionsdb/payloads.go +++ b/internal/actionsdb/payloads.go @@ -11,12 +11,8 @@ import ( "github.com/russtone/sonar/internal/utils/slice" ) -func Payload(m *models.Payload) *actions.Payload { - if m == nil { - return nil - } - - return &actions.Payload{ +func Payload(m models.Payload) actions.Payload { + return actions.Payload{ Subdomain: m.Subdomain, Name: m.Name, NotifyProtocols: m.NotifyProtocols.Strings(), @@ -25,7 +21,7 @@ func Payload(m *models.Payload) *actions.Payload { } } -func (act *dbactions) PayloadsCreate(ctx context.Context, p actions.PayloadsCreateParams) (actions.PayloadsCreateResult, errors.Error) { +func (act *dbactions) PayloadsCreate(ctx context.Context, p actions.PayloadsCreateParams) (*actions.PayloadsCreateResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -44,7 +40,7 @@ func (act *dbactions) PayloadsCreate(ctx context.Context, p actions.PayloadsCrea return nil, errors.Internal(err) } - payload := &models.Payload{ + rec := &models.Payload{ UserID: u.ID, Subdomain: subdomain, Name: p.Name, @@ -52,15 +48,15 @@ func (act *dbactions) PayloadsCreate(ctx context.Context, p actions.PayloadsCrea StoreEvents: p.StoreEvents, } - err = act.db.PayloadsCreate(payload) + err = act.db.PayloadsCreate(rec) if err != nil { return nil, errors.Internal(err) } - return Payload(payload), nil + return &actions.PayloadsCreateResult{Payload(*rec)}, nil } -func (act *dbactions) PayloadsUpdate(ctx context.Context, p actions.PayloadsUpdateParams) (actions.PayloadsUpdateResult, errors.Error) { +func (act *dbactions) PayloadsUpdate(ctx context.Context, p actions.PayloadsUpdateParams) (*actions.PayloadsUpdateResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -70,7 +66,7 @@ func (act *dbactions) PayloadsUpdate(ctx context.Context, p actions.PayloadsUpda return nil, errors.Validation(err) } - payload, err := act.db.PayloadsGetByUserAndName(u.ID, p.Name) + rec, err := act.db.PayloadsGetByUserAndName(u.ID, p.Name) if err == sql.ErrNoRows { return nil, errors.NotFoundf("payload with name %q not found", p.Name) } else if err != nil { @@ -78,26 +74,26 @@ func (act *dbactions) PayloadsUpdate(ctx context.Context, p actions.PayloadsUpda } if p.NewName != "" { - payload.Name = p.NewName + rec.Name = p.NewName } if p.NotifyProtocols != nil { - payload.NotifyProtocols = models.ProtoCategories(slice.StringsDedup(p.NotifyProtocols)...) + rec.NotifyProtocols = models.ProtoCategories(slice.StringsDedup(p.NotifyProtocols)...) } if p.StoreEvents != nil { - payload.StoreEvents = *p.StoreEvents + rec.StoreEvents = *p.StoreEvents } - err = act.db.PayloadsUpdate(payload) + err = act.db.PayloadsUpdate(rec) if err != nil { return nil, errors.Internal(err) } - return Payload(payload), nil + return &actions.PayloadsUpdateResult{Payload(*rec)}, nil } -func (act *dbactions) PayloadsDelete(ctx context.Context, p actions.PayloadsDeleteParams) (actions.PayloadsDeleteResult, errors.Error) { +func (act *dbactions) PayloadsDelete(ctx context.Context, p actions.PayloadsDeleteParams) (*actions.PayloadsDeleteResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -107,18 +103,18 @@ func (act *dbactions) PayloadsDelete(ctx context.Context, p actions.PayloadsDele return nil, errors.Validation(err) } - payload, err := act.db.PayloadsGetByUserAndName(u.ID, p.Name) + rec, err := act.db.PayloadsGetByUserAndName(u.ID, p.Name) if err == sql.ErrNoRows { return nil, errors.NotFoundf("you don't have payload with name %q", p.Name) } else if err != nil { return nil, errors.Internal(err) } - if err := act.db.PayloadsDelete(payload.ID); err != nil { + if err := act.db.PayloadsDelete(rec.ID); err != nil { return nil, errors.Internal(err) } - return Payload(payload), nil + return &actions.PayloadsDeleteResult{Payload(*rec)}, nil } func (act *dbactions) PayloadsList(ctx context.Context, p actions.PayloadsListParams) (actions.PayloadsListResult, errors.Error) { @@ -131,15 +127,15 @@ func (act *dbactions) PayloadsList(ctx context.Context, p actions.PayloadsListPa return nil, errors.Validation(err) } - payloads, err := act.db.PayloadsFindByUserAndName(u.ID, p.Name) + recs, err := act.db.PayloadsFindByUserAndName(u.ID, p.Name) if err != nil { return nil, errors.Internal(err) } - res := make([]*actions.Payload, 0) + res := make([]actions.Payload, 0) - for _, p := range payloads { - res = append(res, Payload(p)) + for _, r := range recs { + res = append(res, Payload(*r)) } return res, nil diff --git a/internal/actionsdb/user.go b/internal/actionsdb/user.go index 749df72..7436f24 100644 --- a/internal/actionsdb/user.go +++ b/internal/actionsdb/user.go @@ -7,11 +7,11 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func (act *dbactions) UserCurrent(ctx context.Context) (actions.UserCurrentResult, errors.Error) { +func (act *dbactions) ProfileGet(ctx context.Context) (*actions.ProfileGetResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) } - return User(u), nil + return &actions.ProfileGetResult{User(*u)}, nil } diff --git a/internal/actionsdb/user_test.go b/internal/actionsdb/user_test.go index 3ad2845..059422b 100644 --- a/internal/actionsdb/user_test.go +++ b/internal/actionsdb/user_test.go @@ -17,13 +17,13 @@ func TestUserCurrent_Success(t *testing.T) { ctx := actionsdb.SetUser(context.Background(), u) - usr, err := acts.UserCurrent(ctx) + usr, err := acts.ProfileGet(ctx) assert.NoError(t, err) assert.EqualValues(t, "user1", usr.Name) } func TestUserCurrent_Error(t *testing.T) { - _, err := acts.UserCurrent(context.Background()) + _, err := acts.ProfileGet(context.Background()) assert.Error(t, err) assert.IsType(t, &errors.InternalError{}, err) } diff --git a/internal/actionsdb/users.go b/internal/actionsdb/users.go index f3fb7b9..764e384 100644 --- a/internal/actionsdb/users.go +++ b/internal/actionsdb/users.go @@ -9,12 +9,8 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func User(m *models.User) *actions.User { - if m == nil { - return nil - } - - return &actions.User{ +func User(m models.User) actions.User { + return actions.User{ Name: m.Name, Params: m.Params, IsAdmin: m.IsAdmin, @@ -22,7 +18,7 @@ func User(m *models.User) *actions.User { } } -func (act *dbactions) UsersCreate(ctx context.Context, p actions.UsersCreateParams) (actions.UsersCreateResult, errors.Error) { +func (act *dbactions) UsersCreate(ctx context.Context, p actions.UsersCreateParams) (*actions.UsersCreateResult, errors.Error) { u, err := GetUser(ctx) if err != nil { return nil, errors.Internal(err) @@ -38,33 +34,33 @@ func (act *dbactions) UsersCreate(ctx context.Context, p actions.UsersCreatePara // TODO: check telegram.id and api.token duplicate - user := &models.User{ + rec := &models.User{ Name: p.Name, Params: p.Params, IsAdmin: p.IsAdmin, CreatedBy: &u.ID, } - if err := act.db.UsersCreate(user); err != nil { + if err := act.db.UsersCreate(rec); err != nil { return nil, errors.Internal(err) } - return User(user), nil + return &actions.UsersCreateResult{User(*rec)}, nil } -func (act *dbactions) UsersDelete(ctx context.Context, p actions.UsersDeleteParams) (actions.UsersDeleteResult, errors.Error) { +func (act *dbactions) UsersDelete(ctx context.Context, p actions.UsersDeleteParams) (*actions.UsersDeleteResult, errors.Error) { if err := p.Validate(); err != nil { return nil, errors.Validation(err) } - user, err := act.db.UsersGetByName(p.Name) + rec, err := act.db.UsersGetByName(p.Name) if err != nil { return nil, errors.NotFoundf("user with name %q not found", p.Name) } - if err := act.db.UsersDelete(user.ID); err != nil { + if err := act.db.UsersDelete(rec.ID); err != nil { return nil, errors.Internal(err) } - return User(user), nil + return &actions.UsersDeleteResult{User(*rec)}, nil } diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 2bb13a2..715768a 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -3,8 +3,10 @@ package cmd import ( "bytes" "context" + "strings" "github.com/Masterminds/sprig" + "github.com/google/shlex" "github.com/spf13/cobra" "github.com/russtone/sonar/internal/actions" @@ -18,29 +20,42 @@ func init() { cobra.AddTemplateFuncs(sprig.TxtFuncMap()) } -type ResultHandler func(context.Context, interface{}) -type PreExec func(*cobra.Command, *actions.User) - -type command struct { +type Command struct { actions actions.Actions handler actions.ResultHandler - preExec PreExec + + preExec func(context.Context, *cobra.Command) + local bool } -type Command interface { - Root(*actions.User, bool) *cobra.Command - Exec(context.Context, *actions.User, bool, []string) (string, errors.Error) +type CommandOption func(*Command) + +func PreExec(f func(context.Context, *cobra.Command)) func(*Command) { + return func(c *Command) { + c.preExec = f + } +} + +func Local() func(*Command) { + return func(c *Command) { + c.local = true + } } -func New(actions actions.Actions, handler actions.ResultHandler, preExec PreExec) Command { - return &command{ - actions: actions, - handler: handler, - preExec: preExec, +func New(acts actions.Actions, h actions.ResultHandler, opts ...CommandOption) *Command { + c := &Command{ + actions: acts, + handler: h, } + + for _, opt := range opts { + opt(c) + } + + return c } -func (c *command) Root(u *actions.User, local bool) *cobra.Command { +func (c *Command) root(user *actions.User) *cobra.Command { var root = &cobra.Command{ Use: "sonar", Short: "CLI to control sonar server", @@ -52,17 +67,16 @@ func (c *command) Root(u *actions.User, local bool) *cobra.Command { // Currently, there are no default commands available // for unauthorized users, but some controller can implement - // their own unauthorized commands and add this commands to root - // using `preExec`. - if u == nil { + // their own unauthorized commands. + if user == nil { return root } // Main payloads commands - root.AddCommand(c.PayloadsCreate(local)) - root.AddCommand(c.PayloadsList(local)) - root.AddCommand(c.PayloadsUpdate(local)) - root.AddCommand(c.PayloadsDelete(local)) + root.AddCommand(c.PayloadsCreate()) + root.AddCommand(c.PayloadsList()) + root.AddCommand(c.PayloadsUpdate()) + root.AddCommand(c.PayloadsDelete()) // DNS dns := &cobra.Command{ @@ -70,9 +84,9 @@ func (c *command) Root(u *actions.User, local bool) *cobra.Command { Short: "Manage DNS records", } - dns.AddCommand(c.DNSRecordsCreate(local)) - dns.AddCommand(c.DNSRecordsDelete(local)) - dns.AddCommand(c.DNSRecordsList(local)) + dns.AddCommand(c.DNSRecordsCreate()) + dns.AddCommand(c.DNSRecordsDelete()) + dns.AddCommand(c.DNSRecordsList()) root.AddCommand(dns) @@ -82,8 +96,8 @@ func (c *command) Root(u *actions.User, local bool) *cobra.Command { Short: "Payloads events", } - events.AddCommand(c.EventsList(local)) - events.AddCommand(c.EventsGet(local)) + events.AddCommand(c.EventsList()) + events.AddCommand(c.EventsGet()) root.AddCommand(events) @@ -93,24 +107,24 @@ func (c *command) Root(u *actions.User, local bool) *cobra.Command { Short: "Manage HTTP routes", } - http.AddCommand(c.HTTPRoutesCreate(local)) - http.AddCommand(c.HTTPRoutesDelete(local)) - http.AddCommand(c.HTTPRoutesList(local)) + http.AddCommand(c.HTTPRoutesCreate()) + http.AddCommand(c.HTTPRoutesDelete()) + http.AddCommand(c.HTTPRoutesList()) root.AddCommand(http) // User - root.AddCommand(c.UserCurrent(local)) + root.AddCommand(c.ProfileGet()) // Users - if u.IsAdmin { + if user.IsAdmin { users := &cobra.Command{ Use: "users", Short: "Manage users", } - users.AddCommand(c.UsersCreate(local)) - users.AddCommand(c.UsersDelete(local)) + users.AddCommand(c.UsersCreate()) + users.AddCommand(c.UsersDelete()) root.AddCommand(users) } @@ -118,11 +132,18 @@ func (c *command) Root(u *actions.User, local bool) *cobra.Command { return root } -func (c *command) Exec(ctx context.Context, u *actions.User, local bool, args []string) (string, errors.Error) { - root := c.Root(u, local) +func (c *Command) Exec(ctx context.Context, args []string) { + + profile, err := c.actions.ProfileGet(ctx) + if err != nil { + c.handler.OnResult(ctx, actions.ErrorResult{errors.Unauthorized()}) + return + } + + root := c.root(&profile.User) if c.preExec != nil { - c.preExec(root, u) + c.preExec(ctx, root) } root.SetArgs(args) @@ -134,17 +155,57 @@ func (c *command) Exec(ctx context.Context, u *actions.User, local bool, args [] // There is no subcommands which means that user is unauthorized // and no commands available for unauthorized users in current controller. if !root.HasAvailableSubCommands() { - return "", errors.Unauthorized() + c.handler.OnResult(ctx, actions.ErrorResult{errors.Unauthorized()}) + return } if err := root.ExecuteContext(ctx); err != nil { - e, ok := err.(errors.Error) - if !ok { - return bb.String(), errors.Internal(err) - } + c.handler.OnResult(ctx, actions.ErrorResult{errors.Internal(err)}) + return + } - return bb.String(), e + if bb.String() != "" { + c.handler.OnResult(ctx, actions.TextResult{bb.String()}) } +} - return bb.String(), nil +func (c *Command) ParseAndExec(ctx context.Context, s string) { + args, _ := shlex.Split(strings.TrimLeft(s, "/")) + c.Exec(ctx, args) } + +func DefaultMessengersPreExec(ctx context.Context, root *cobra.Command) { + root.SetHelpTemplate(helpTemplate) + root.SetUsageTemplate(usageTemplate) + root.CompletionOptions = cobra.CompletionOptions{ + DisableDefaultCmd: true, + } +} + +var helpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` + +var usageTemplate = ` +Usage:{{if .Runnable}}{{if .HasParent}} + {{.UseLine | replace "sonar " "/"}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + {{if .HasParent}}{{.CommandPath | replace "sonar " "/"}} {{else}}/{{end}}[command]{{end}}{{if gt (len .Aliases) 0}} + +Aliases: + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +Examples: +{{.Example}}{{end}}{{if .HasAvailableSubCommands}} + +Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + /{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{if .HasParent}}{{.CommandPath | replace "sonar " "/"}} {{else}}/{{end}}[command] --help" for more information about a command.{{end}}` diff --git a/internal/cmd/cmd_test.go b/internal/cmd/cmd_test.go index 94e8024..df5458a 100644 --- a/internal/cmd/cmd_test.go +++ b/internal/cmd/cmd_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/google/shlex" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/russtone/sonar/internal/actions" @@ -17,14 +16,14 @@ import ( ) var ( - ctx = context.WithValue(context.Background(), "key", "value") + ctx = context.Background() ) -func prepare() (cmd.Command, *actions_mock.Actions, *actions_mock.ResultHandler) { +func prepare() (*cmd.Command, *actions_mock.Actions, *actions_mock.ResultHandler) { actions := &actions_mock.Actions{} handler := &actions_mock.ResultHandler{} - c := cmd.New(actions, handler, nil) + c := cmd.New(actions, handler) return c, actions, handler } @@ -54,7 +53,7 @@ func TestCmd(t *testing.T) { }, StoreEvents: true, }, - (actions.PayloadsCreateResult)(nil), + &actions.PayloadsCreateResult{}, }, // List @@ -65,7 +64,7 @@ func TestCmd(t *testing.T) { actions.PayloadsListParams{ Name: "substr", }, - (actions.PayloadsListResult)(nil), + actions.PayloadsListResult{}, }, // Update @@ -79,7 +78,7 @@ func TestCmd(t *testing.T) { NotifyProtocols: []string{models.ProtoCategoryDNS.String()}, StoreEvents: pointer.Bool(false), }, - (actions.PayloadsUpdateResult)(nil), + &actions.PayloadsUpdateResult{}, }, // Delete @@ -90,7 +89,7 @@ func TestCmd(t *testing.T) { actions.PayloadsDeleteParams{ Name: "test", }, - (actions.PayloadsDeleteResult)(nil), + &actions.PayloadsDeleteResult{}, }, // @@ -110,7 +109,7 @@ func TestCmd(t *testing.T) { Values: []string{"192.168.1.1"}, Strategy: models.DNSStrategyAll, }, - (actions.DNSRecordsCreateResult)(nil), + &actions.DNSRecordsCreateResult{}, }, { `dns new -p payload -n name -t mx -l 120 -s round-robin "10 mx.example.com."`, @@ -123,7 +122,7 @@ func TestCmd(t *testing.T) { Values: []string{"10 mx.example.com."}, Strategy: models.DNSStrategyRoundRobin, }, - (actions.DNSRecordsCreateResult)(nil), + &actions.DNSRecordsCreateResult{}, }, { `dns new -p payload -n name -t a -l 100 -s rebind 1.1.1.1 2.2.2.2 3.3.3.3`, @@ -136,7 +135,7 @@ func TestCmd(t *testing.T) { Values: []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}, Strategy: models.DNSStrategyRebind, }, - (actions.DNSRecordsCreateResult)(nil), + &actions.DNSRecordsCreateResult{}, }, // List @@ -147,7 +146,7 @@ func TestCmd(t *testing.T) { actions.DNSRecordsListParams{ PayloadName: "payload", }, - (actions.DNSRecordsListResult)(nil), + actions.DNSRecordsListResult{}, }, // Delete @@ -159,7 +158,7 @@ func TestCmd(t *testing.T) { PayloadName: "payload", Index: 1, }, - (actions.DNSRecordsDeleteResult)(nil), + &actions.DNSRecordsDeleteResult{}, }, // @@ -179,7 +178,7 @@ func TestCmd(t *testing.T) { }, IsAdmin: true, }, - (actions.UsersCreateResult)(nil), + &actions.UsersCreateResult{}, }, // Delete @@ -190,7 +189,7 @@ func TestCmd(t *testing.T) { actions.UsersDeleteParams{ Name: "test", }, - (actions.UsersDeleteResult)(nil), + &actions.UsersDeleteResult{}, }, // @@ -198,10 +197,10 @@ func TestCmd(t *testing.T) { // { - "user", - "UserCurrent", + "profile", + "ProfileGet", nil, - (actions.UserCurrentResult)(nil), + &actions.ProfileGetResult{}, }, // @@ -218,7 +217,7 @@ func TestCmd(t *testing.T) { Count: 5, After: 3, }, - (actions.EventsListResult)(nil), + actions.EventsListResult{}, }, { "events list -p test -c 5 -b 3 -r", @@ -229,7 +228,7 @@ func TestCmd(t *testing.T) { Before: 3, Reverse: true, }, - (actions.EventsListResult)(nil), + actions.EventsListResult{}, }, // Get @@ -241,7 +240,7 @@ func TestCmd(t *testing.T) { PayloadName: "test", Index: 5, }, - (actions.EventsGetResult)(nil), + &actions.EventsGetResult{}, }, // @@ -264,7 +263,7 @@ func TestCmd(t *testing.T) { Body: "dGVzdA==", IsDynamic: true, }, - (actions.HTTPRoutesCreateResult)(nil), + &actions.HTTPRoutesCreateResult{}, }, // List @@ -275,7 +274,7 @@ func TestCmd(t *testing.T) { actions.HTTPRoutesListParams{ PayloadName: "payload", }, - (actions.HTTPRoutesListResult)(nil), + actions.HTTPRoutesListResult{}, }, // Delete @@ -287,7 +286,7 @@ func TestCmd(t *testing.T) { PayloadName: "payload", Index: 1, }, - (actions.HTTPRoutesDeleteResult)(nil), + &actions.HTTPRoutesDeleteResult{}, }, } @@ -305,14 +304,15 @@ func TestCmd(t *testing.T) { Return(tt.result, nil) } - hnd.On(tt.action, ctx, tt.result) + acts.On("ProfileGet", ctx). + Return(&actions.ProfileGetResult{User: actions.User{IsAdmin: true}}, nil) + + hnd.On("OnResult", ctx, tt.result) args, err := shlex.Split(tt.cmdline) require.NoError(t, err) - _, err = c.Exec(ctx, &actions.User{IsAdmin: true}, true, args) - - assert.NoError(t, err) + c.Exec(ctx, args) acts.AssertExpectations(t) hnd.AssertExpectations(t) diff --git a/internal/cmd/generated.go b/internal/cmd/generated.go index e2d9fe3..99fb584 100644 --- a/internal/cmd/generated.go +++ b/internal/cmd/generated.go @@ -7,432 +7,461 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func (c *command) DNSRecordsCreate(local bool) *cobra.Command { +func (c *Command) DNSRecordsCreate() *cobra.Command { var params actions.DNSRecordsCreateParams - cmd, prepareFunc := actions.DNSRecordsCreateCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.DNSRecordsCreateCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.DNSRecordsCreate(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.DNSRecordsCreate(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) DNSRecordsDelete(local bool) *cobra.Command { +func (c *Command) DNSRecordsDelete() *cobra.Command { var params actions.DNSRecordsDeleteParams - cmd, prepareFunc := actions.DNSRecordsDeleteCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.DNSRecordsDeleteCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.DNSRecordsDelete(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.DNSRecordsDelete(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) DNSRecordsList(local bool) *cobra.Command { +func (c *Command) DNSRecordsList() *cobra.Command { var params actions.DNSRecordsListParams - cmd, prepareFunc := actions.DNSRecordsListCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.DNSRecordsListCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.DNSRecordsList(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.DNSRecordsList(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) EventsGet(local bool) *cobra.Command { +func (c *Command) EventsGet() *cobra.Command { var params actions.EventsGetParams - cmd, prepareFunc := actions.EventsGetCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.EventsGetCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.EventsGet(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.EventsGet(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) EventsList(local bool) *cobra.Command { +func (c *Command) EventsList() *cobra.Command { var params actions.EventsListParams - cmd, prepareFunc := actions.EventsListCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.EventsListCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.EventsList(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.EventsList(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) HTTPRoutesCreate(local bool) *cobra.Command { +func (c *Command) HTTPRoutesCreate() *cobra.Command { var params actions.HTTPRoutesCreateParams - cmd, prepareFunc := actions.HTTPRoutesCreateCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.HTTPRoutesCreateCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.HTTPRoutesCreate(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.HTTPRoutesCreate(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) HTTPRoutesDelete(local bool) *cobra.Command { +func (c *Command) HTTPRoutesDelete() *cobra.Command { var params actions.HTTPRoutesDeleteParams - cmd, prepareFunc := actions.HTTPRoutesDeleteCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.HTTPRoutesDeleteCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.HTTPRoutesDelete(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.HTTPRoutesDelete(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) HTTPRoutesList(local bool) *cobra.Command { +func (c *Command) HTTPRoutesList() *cobra.Command { var params actions.HTTPRoutesListParams - cmd, prepareFunc := actions.HTTPRoutesListCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.HTTPRoutesListCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.HTTPRoutesList(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.HTTPRoutesList(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) PayloadsCreate(local bool) *cobra.Command { +func (c *Command) PayloadsCreate() *cobra.Command { var params actions.PayloadsCreateParams - cmd, prepareFunc := actions.PayloadsCreateCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.PayloadsCreateCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.PayloadsCreate(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.PayloadsCreate(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) PayloadsDelete(local bool) *cobra.Command { +func (c *Command) PayloadsDelete() *cobra.Command { var params actions.PayloadsDeleteParams - cmd, prepareFunc := actions.PayloadsDeleteCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.PayloadsDeleteCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.PayloadsDelete(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.PayloadsDelete(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) PayloadsList(local bool) *cobra.Command { +func (c *Command) PayloadsList() *cobra.Command { var params actions.PayloadsListParams - cmd, prepareFunc := actions.PayloadsListCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.PayloadsListCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.PayloadsList(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.PayloadsList(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) PayloadsUpdate(local bool) *cobra.Command { +func (c *Command) PayloadsUpdate() *cobra.Command { var params actions.PayloadsUpdateParams - cmd, prepareFunc := actions.PayloadsUpdateCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.PayloadsUpdateCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.PayloadsUpdate(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.PayloadsUpdate(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) UserCurrent(local bool) *cobra.Command { - cmd, prepareFunc := actions.UserCurrentCommand(local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { +func (c *Command) ProfileGet() *cobra.Command { + cmd, prepareFunc := actions.ProfileGetCommand(c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } - res, err := c.actions.UserCurrent(cmd.Context()) + res, err := c.actions.ProfileGet(cmd.Context()) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.UserCurrent(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) UsersCreate(local bool) *cobra.Command { +func (c *Command) UsersCreate() *cobra.Command { var params actions.UsersCreateParams - cmd, prepareFunc := actions.UsersCreateCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.UsersCreateCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.UsersCreate(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.UsersCreate(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } -func (c *command) UsersDelete(local bool) *cobra.Command { +func (c *Command) UsersDelete() *cobra.Command { var params actions.UsersDeleteParams - cmd, prepareFunc := actions.UsersDeleteCommand(¶ms, local) - - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { + cmd, prepareFunc := actions.UsersDeleteCommand(¶ms, c.local) + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } res, err := c.actions.UsersDelete(cmd.Context(), params) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.UsersDelete(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd } diff --git a/internal/cmd/utils.go b/internal/cmd/utils.go deleted file mode 100644 index de720ab..0000000 --- a/internal/cmd/utils.go +++ /dev/null @@ -1,15 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - - "github.com/russtone/sonar/internal/utils/errors" -) - -type runEFunc func(*cobra.Command, []string) errors.Error - -func RunE(f runEFunc) func(*cobra.Command, []string) error { - return func(cmd *cobra.Command, args []string) error { - return f(cmd, args) - } -} diff --git a/internal/codegen/code.go b/internal/codegen/code.go index 22ec5b1..3a5caff 100644 --- a/internal/codegen/code.go +++ b/internal/codegen/code.go @@ -10,38 +10,40 @@ import ( ) {{ range . }} -func (c *command) {{ .Name }}(local bool) *cobra.Command { - {{- if ne .Params.Name "" }} - var params actions.{{ .Params.Name }} +func (c *Command) {{ .Name }}() *cobra.Command { + {{- if ne .Params.TypeName "" }} + var params actions.{{ .Params.TypeName }} - cmd, prepareFunc := actions.{{ .Name }}Command(¶ms, local) + cmd, prepareFunc := actions.{{ .Name }}Command(¶ms, c.local) {{ else }} - cmd, prepareFunc := actions.{{ .Name }}Command(local) + cmd, prepareFunc := actions.{{ .Name }}Command(c.local) {{ end }} - cmd.RunE = RunE(func(cmd *cobra.Command, args []string) errors.Error { - + cmd.Run = func(cmd *cobra.Command, args []string) { if prepareFunc != nil { if err := prepareFunc(cmd, args); err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } } - {{- if ne .Params.Name "" }} + {{- if ne .Params.TypeName "" }} if err := params.Validate(); err != nil { - return errors.Validation(err) + c.handler.OnResult(cmd.Context(), actions.ErrorResult{errors.Validation(err)}) + return } {{ end }} - res, err := c.actions.{{ .Name }}(cmd.Context(){{ if ne .Params.Name "" }}, params{{ end }}) + res, err := c.actions.{{ .Name }}(cmd.Context(){{ if ne .Params.TypeName "" }}, params{{ end }}) if err != nil { - return err + c.handler.OnResult(cmd.Context(), actions.ErrorResult{err}) + return } - c.handler.{{ .Name }}(cmd.Context(), res) + c.handler.OnResult(cmd.Context(), res) - return nil - }) + return + } return cmd @@ -59,8 +61,8 @@ import ( {{ range . }} func (api *API) {{ .Name }}(w http.ResponseWriter, r *http.Request) { - {{ if ne .Params.Name "" }} - var params actions.{{ .Params.Name }} + {{ if ne .Params.TypeName "" }} + var params actions.{{ .Params.TypeName }} {{ end }} {{- range .Params.Types }} @@ -70,7 +72,7 @@ func (api *API) {{ .Name }}(w http.ResponseWriter, r *http.Request) { } {{ end }} - res, err := api.actions.{{ .Name }}(r.Context(){{ if ne .Params.Name "" }}, params{{ end }}) + res, err := api.actions.{{ .Name }}(r.Context(){{ if ne .Params.TypeName "" }}, params{{ end }}) if err != nil { api.handleError(w, r, err) return @@ -92,8 +94,8 @@ import ( ) {{ range . }} -func (c *Client) {{ .Name }}(ctx context.Context{{ if ne .Params.Name "" }}, params actions.{{ .Params.Name }}{{ end }}) (actions.{{ .Result }}, errors.Error) { - var res actions.{{ .Result }} +func (c *Client) {{ .Name }}(ctx context.Context{{ if ne .Params.TypeName "" }}, params actions.{{ .Params.TypeName }}{{ end }}) ({{ .Result }}, errors.Error) { + var res {{ .Result }} err := handle(c.client.R(). {{- range .Params.Types }} diff --git a/internal/codegen/main.go b/internal/codegen/main.go index c02acf5..222c101 100644 --- a/internal/codegen/main.go +++ b/internal/codegen/main.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "reflect" - "regexp" "strings" "text/template" @@ -24,14 +23,16 @@ func init() { } type Action struct { - Name string - Params struct { - Name string - Types []string + Name string // DNSRecordsCreate + Resource string // dns-records + Verb string // create + Params struct { + TypeName string // DNSRecordsCreateParams + Types []string // ["JSON", "Path", "Query"] } - Result string - HTTPMethod string - HTTPPath string + Result string // DNSRecordsCreateResult + HTTPMethod string // POST + HTTPPath string // /dns-records } var tags = map[string]string{ @@ -60,18 +61,31 @@ func main() { // HTTP Method (for API and API client). if strings.Contains(m.Name, "Create") { act.HTTPMethod = "POST" + act.Resource = resourceName(strings.Replace(m.Name, "Create", "", 1)) + act.Verb = "create" } else if strings.Contains(m.Name, "Update") { act.HTTPMethod = "PUT" + act.Resource = resourceName(strings.Replace(m.Name, "Update", "", 1)) + act.Verb = "update" } else if strings.Contains(m.Name, "Delete") { act.HTTPMethod = "DELETE" - } else { + act.Resource = resourceName(strings.Replace(m.Name, "Delete", "", 1)) + act.Verb = "delete" + } else if strings.Contains(m.Name, "Get") { + act.HTTPMethod = "GET" + act.Resource = resourceName(strings.Replace(m.Name, "Get", "", 1)) + act.Verb = "get" + } else if strings.Contains(m.Name, "List") { act.HTTPMethod = "GET" + act.Resource = resourceName(strings.Replace(m.Name, "List", "", 1)) + act.Verb = "list" + } else { + fmt.Fprintf(os.Stderr, "invalid name: %q\n", m.Name) + os.Exit(1) } // HTTP path (with paramters). - act.HTTPPath += "/" + strings.ToLower(pathName( - regexp.MustCompile(`^[A-Z]+[a-z]+`).FindString(m.Name), - )) + act.HTTPPath = "/" + act.Resource // Actions arguments. for j := 0; j < m.Type.NumIn(); j++ { @@ -82,7 +96,7 @@ func main() { continue } - act.Params.Name = arg.Name() + act.Params.TypeName = arg.Name() // Iterate parameters fields and save which // of them came from path, query and json. @@ -107,11 +121,11 @@ func main() { res := m.Type.Out(j) // We only need *Result return type. - if !strings.Contains(res.Name(), "Result") { + if !strings.Contains(res.String(), "Result") { continue } - act.Result = res.Name() + act.Result = res.String() } acts = append(acts, act) @@ -148,9 +162,9 @@ func contains(items []string, item string) bool { return false } -// DNSRecords -> DNS-Records -// Users -> Users -func pathName(s string) string { +// DNSRecords -> dns-records +// Users -> users +func resourceName(s string) string { for i := 0; i < len(s); i++ { if s[i] > 'A' && s[i] < 'Z' { continue @@ -160,8 +174,8 @@ func pathName(s string) string { break } - return s[:i-1] + "-" + s[i-1:] + return strings.ToLower(s[:i-1] + "-" + s[i-1:]) } - return s + return strings.ToLower(s) } diff --git a/internal/modules/api/api.go b/internal/modules/api/api.go index 0604599..73e6a46 100644 --- a/internal/modules/api/api.go +++ b/internal/modules/api/api.go @@ -48,7 +48,7 @@ func (api *API) Router() http.Handler { r.Use(api.checkAuth()) - r.Get("/user", api.UserCurrent) + r.Get("/profile", api.ProfileGet) r.Route("/payloads", func(r chi.Router) { r.Get("/", api.PayloadsList) diff --git a/internal/modules/api/api_test.go b/internal/modules/api/api_test.go index f623dc3..99956b9 100644 --- a/internal/modules/api/api_test.go +++ b/internal/modules/api/api_test.go @@ -149,7 +149,7 @@ func TestAPI(t *testing.T) { path: "/payloads", token: User1Token, json: `{"name": "test", "notifyProtocols": ["dns", "smtp"], "storeEvents": true}`, - schema: (actions.PayloadsCreateResult)(nil), + schema: actions.PayloadsCreateResult{}, result: map[string]matcher{ "$.subdomain": regex(regexp.MustCompile("^[a-f0-9]{8}$")), "$.name": equal("test"), @@ -232,7 +232,7 @@ func TestAPI(t *testing.T) { path: "/payloads/payload1", token: User1Token, json: `{"name":"test", "notifyProtocols": ["smtp"], "storeEvents": false}`, - schema: (actions.PayloadsUpdateResult)(nil), + schema: actions.PayloadsUpdateResult{}, result: map[string]matcher{ "$.name": equal("test"), "$.notifyProtocols": equal([]interface{}{models.ProtoCategorySMTP.String()}), @@ -245,7 +245,7 @@ func TestAPI(t *testing.T) { path: "/payloads/payload1", token: User1Token, json: `{"name":"test", "notifyProtocols": ["smtp"], "storeEvents": null}`, - schema: (actions.PayloadsUpdateResult)(nil), + schema: actions.PayloadsUpdateResult{}, result: map[string]matcher{ "$.name": equal("test"), "$.notifyProtocols": equal([]interface{}{models.ProtoCategorySMTP.String()}), @@ -295,7 +295,7 @@ func TestAPI(t *testing.T) { method: "DELETE", path: "/payloads/payload1", token: User1Token, - schema: (actions.PayloadsDeleteResult)(nil), + schema: actions.PayloadsDeleteResult{}, status: 200, }, { @@ -320,7 +320,7 @@ func TestAPI(t *testing.T) { path: "/dns-records", token: User1Token, json: `{"payloadName": "payload1", "name": "test", "type": "a", "ttl": 100, "values": ["127.0.0.1"], "strategy": "all"}`, - schema: (actions.DNSRecordsCreateResult)(nil), + schema: actions.DNSRecordsCreateResult{}, result: map[string]matcher{ "$.name": equal("test"), "$.type": equal("A"), @@ -397,7 +397,7 @@ func TestAPI(t *testing.T) { method: "DELETE", path: "/dns-records/payload1/1", token: User1Token, - schema: (actions.DNSRecordsDeleteResult)(nil), + schema: actions.DNSRecordsDeleteResult{}, result: map[string]matcher{ "$.name": equal("test-a"), }, @@ -430,9 +430,9 @@ func TestAPI(t *testing.T) { { method: "GET", - path: "/user", + path: "/profile", token: User1Token, - schema: (actions.UserCurrentResult)(nil), + schema: actions.ProfileGetResult{}, result: map[string]matcher{ "$.name": equal("user1"), }, @@ -469,7 +469,7 @@ func TestAPI(t *testing.T) { path: "/users", token: AdminToken, json: `{"name": "test", "params": {"api.token": "token", "telegram.id": 1234}}`, - schema: (actions.UsersCreateResult)(nil), + schema: actions.UsersCreateResult{}, result: map[string]matcher{ "$.name": equal("test"), "$.isAdmin": equal(false), @@ -519,7 +519,7 @@ func TestAPI(t *testing.T) { method: "DELETE", path: "/users/user1", token: AdminToken, - schema: (actions.UsersCreateResult)(nil), + schema: actions.UsersCreateResult{}, status: 200, }, { @@ -558,7 +558,7 @@ func TestAPI(t *testing.T) { method: "GET", path: "/events/payload1/2", token: User1Token, - schema: (actions.EventsGetResult)(nil), + schema: actions.EventsGetResult{}, result: map[string]matcher{ "$.protocol": equal("http"), }, @@ -584,7 +584,7 @@ func TestAPI(t *testing.T) { "body": "dGVzdA==", "isDynamic": true }`, - schema: (actions.HTTPRoutesCreateResult)(nil), + schema: actions.HTTPRoutesCreateResult{}, result: map[string]matcher{ "$.method": equal("GET"), "$.path": equal("/test"), @@ -662,7 +662,7 @@ func TestAPI(t *testing.T) { method: "DELETE", path: "/http-routes/payload1/1", token: User1Token, - schema: (actions.HTTPRoutesDeleteResult)(nil), + schema: actions.HTTPRoutesDeleteResult{}, result: map[string]matcher{ "$.path": equal("/get"), }, diff --git a/internal/modules/api/apiclient/client_test.go b/internal/modules/api/apiclient/client_test.go index e1b054b..ec37bde 100644 --- a/internal/modules/api/apiclient/client_test.go +++ b/internal/modules/api/apiclient/client_test.go @@ -472,9 +472,9 @@ func TestClient(t *testing.T) { case actions.HTTPRoutesDeleteParams: res, err = uc.HTTPRoutesDelete(context.Background(), p) - // User + // Profile default: - res, err = uc.UserCurrent(context.Background()) + res, err = uc.ProfileGet(context.Background()) } if tt.err != nil { diff --git a/internal/modules/api/apiclient/generated.go b/internal/modules/api/apiclient/generated.go index 456ddc4..90142a0 100644 --- a/internal/modules/api/apiclient/generated.go +++ b/internal/modules/api/apiclient/generated.go @@ -7,8 +7,8 @@ import ( "github.com/russtone/sonar/internal/utils/errors" ) -func (c *Client) DNSRecordsCreate(ctx context.Context, params actions.DNSRecordsCreateParams) (actions.DNSRecordsCreateResult, errors.Error) { - var res actions.DNSRecordsCreateResult +func (c *Client) DNSRecordsCreate(ctx context.Context, params actions.DNSRecordsCreateParams) (*actions.DNSRecordsCreateResult, errors.Error) { + var res *actions.DNSRecordsCreateResult err := handle(c.client.R(). SetBody(params). @@ -24,8 +24,8 @@ func (c *Client) DNSRecordsCreate(ctx context.Context, params actions.DNSRecords return res, nil } -func (c *Client) DNSRecordsDelete(ctx context.Context, params actions.DNSRecordsDeleteParams) (actions.DNSRecordsDeleteResult, errors.Error) { - var res actions.DNSRecordsDeleteResult +func (c *Client) DNSRecordsDelete(ctx context.Context, params actions.DNSRecordsDeleteParams) (*actions.DNSRecordsDeleteResult, errors.Error) { + var res *actions.DNSRecordsDeleteResult err := handle(c.client.R(). SetPathParams(toPath(params)). @@ -58,8 +58,8 @@ func (c *Client) DNSRecordsList(ctx context.Context, params actions.DNSRecordsLi return res, nil } -func (c *Client) EventsGet(ctx context.Context, params actions.EventsGetParams) (actions.EventsGetResult, errors.Error) { - var res actions.EventsGetResult +func (c *Client) EventsGet(ctx context.Context, params actions.EventsGetParams) (*actions.EventsGetResult, errors.Error) { + var res *actions.EventsGetResult err := handle(c.client.R(). SetPathParams(toPath(params)). @@ -93,8 +93,8 @@ func (c *Client) EventsList(ctx context.Context, params actions.EventsListParams return res, nil } -func (c *Client) HTTPRoutesCreate(ctx context.Context, params actions.HTTPRoutesCreateParams) (actions.HTTPRoutesCreateResult, errors.Error) { - var res actions.HTTPRoutesCreateResult +func (c *Client) HTTPRoutesCreate(ctx context.Context, params actions.HTTPRoutesCreateParams) (*actions.HTTPRoutesCreateResult, errors.Error) { + var res *actions.HTTPRoutesCreateResult err := handle(c.client.R(). SetBody(params). @@ -110,8 +110,8 @@ func (c *Client) HTTPRoutesCreate(ctx context.Context, params actions.HTTPRoutes return res, nil } -func (c *Client) HTTPRoutesDelete(ctx context.Context, params actions.HTTPRoutesDeleteParams) (actions.HTTPRoutesDeleteResult, errors.Error) { - var res actions.HTTPRoutesDeleteResult +func (c *Client) HTTPRoutesDelete(ctx context.Context, params actions.HTTPRoutesDeleteParams) (*actions.HTTPRoutesDeleteResult, errors.Error) { + var res *actions.HTTPRoutesDeleteResult err := handle(c.client.R(). SetPathParams(toPath(params)). @@ -144,8 +144,8 @@ func (c *Client) HTTPRoutesList(ctx context.Context, params actions.HTTPRoutesLi return res, nil } -func (c *Client) PayloadsCreate(ctx context.Context, params actions.PayloadsCreateParams) (actions.PayloadsCreateResult, errors.Error) { - var res actions.PayloadsCreateResult +func (c *Client) PayloadsCreate(ctx context.Context, params actions.PayloadsCreateParams) (*actions.PayloadsCreateResult, errors.Error) { + var res *actions.PayloadsCreateResult err := handle(c.client.R(). SetBody(params). @@ -161,8 +161,8 @@ func (c *Client) PayloadsCreate(ctx context.Context, params actions.PayloadsCrea return res, nil } -func (c *Client) PayloadsDelete(ctx context.Context, params actions.PayloadsDeleteParams) (actions.PayloadsDeleteResult, errors.Error) { - var res actions.PayloadsDeleteResult +func (c *Client) PayloadsDelete(ctx context.Context, params actions.PayloadsDeleteParams) (*actions.PayloadsDeleteResult, errors.Error) { + var res *actions.PayloadsDeleteResult err := handle(c.client.R(). SetPathParams(toPath(params)). @@ -195,8 +195,8 @@ func (c *Client) PayloadsList(ctx context.Context, params actions.PayloadsListPa return res, nil } -func (c *Client) PayloadsUpdate(ctx context.Context, params actions.PayloadsUpdateParams) (actions.PayloadsUpdateResult, errors.Error) { - var res actions.PayloadsUpdateResult +func (c *Client) PayloadsUpdate(ctx context.Context, params actions.PayloadsUpdateParams) (*actions.PayloadsUpdateResult, errors.Error) { + var res *actions.PayloadsUpdateResult err := handle(c.client.R(). SetBody(params). @@ -213,13 +213,13 @@ func (c *Client) PayloadsUpdate(ctx context.Context, params actions.PayloadsUpda return res, nil } -func (c *Client) UserCurrent(ctx context.Context) (actions.UserCurrentResult, errors.Error) { - var res actions.UserCurrentResult +func (c *Client) ProfileGet(ctx context.Context) (*actions.ProfileGetResult, errors.Error) { + var res *actions.ProfileGetResult err := handle(c.client.R().SetError(&APIError{}). SetResult(&res). SetContext(ctx). - Get("/user")) + Get("/profile")) if err != nil { return nil, err @@ -228,8 +228,8 @@ func (c *Client) UserCurrent(ctx context.Context) (actions.UserCurrentResult, er return res, nil } -func (c *Client) UsersCreate(ctx context.Context, params actions.UsersCreateParams) (actions.UsersCreateResult, errors.Error) { - var res actions.UsersCreateResult +func (c *Client) UsersCreate(ctx context.Context, params actions.UsersCreateParams) (*actions.UsersCreateResult, errors.Error) { + var res *actions.UsersCreateResult err := handle(c.client.R(). SetBody(params). @@ -245,8 +245,8 @@ func (c *Client) UsersCreate(ctx context.Context, params actions.UsersCreatePara return res, nil } -func (c *Client) UsersDelete(ctx context.Context, params actions.UsersDeleteParams) (actions.UsersDeleteResult, errors.Error) { - var res actions.UsersDeleteResult +func (c *Client) UsersDelete(ctx context.Context, params actions.UsersDeleteParams) (*actions.UsersDeleteResult, errors.Error) { + var res *actions.UsersDeleteResult err := handle(c.client.R(). SetPathParams(toPath(params)). diff --git a/internal/modules/api/apiclient/utils.go b/internal/modules/api/apiclient/utils.go index 065d898..2affc4f 100644 --- a/internal/modules/api/apiclient/utils.go +++ b/internal/modules/api/apiclient/utils.go @@ -5,10 +5,10 @@ import ( "net/url" "strings" - "github.com/russtone/sonar/internal/utils/errors" "github.com/fatih/structs" "github.com/go-resty/resty/v2" "github.com/gorilla/schema" + "github.com/russtone/sonar/internal/utils/errors" ) var encoder = schema.NewEncoder() diff --git a/internal/modules/api/generated.go b/internal/modules/api/generated.go index 0050600..e233c87 100644 --- a/internal/modules/api/generated.go +++ b/internal/modules/api/generated.go @@ -232,9 +232,9 @@ func (api *API) PayloadsUpdate(w http.ResponseWriter, r *http.Request) { responseJSON(w, res, http.StatusOK) } -func (api *API) UserCurrent(w http.ResponseWriter, r *http.Request) { +func (api *API) ProfileGet(w http.ResponseWriter, r *http.Request) { - res, err := api.actions.UserCurrent(r.Context()) + res, err := api.actions.ProfileGet(r.Context()) if err != nil { api.handleError(w, r, err) return diff --git a/internal/modules/lark/lark.go b/internal/modules/lark/lark.go index bdff29a..1e90892 100644 --- a/internal/modules/lark/lark.go +++ b/internal/modules/lark/lark.go @@ -10,13 +10,11 @@ import ( "net/http" "net/url" "strconv" - "strings" "sync" "text/template" "time" "github.com/Masterminds/sprig" - "github.com/google/shlex" lark "github.com/larksuite/oapi-sdk-go/v3" larkcard "github.com/larksuite/oapi-sdk-go/v3/card" larkcore "github.com/larksuite/oapi-sdk-go/v3/core" @@ -26,20 +24,20 @@ import ( larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1" "github.com/larksuite/oapi-sdk-go/v3/event/dispatcher" - "github.com/spf13/cobra" "github.com/russtone/sonar/internal/actions" "github.com/russtone/sonar/internal/actionsdb" "github.com/russtone/sonar/internal/cmd" "github.com/russtone/sonar/internal/database" "github.com/russtone/sonar/internal/database/models" + "github.com/russtone/sonar/internal/results" "github.com/russtone/sonar/internal/utils/errors" ) type Lark struct { db *database.DB cfg *Config - cmd cmd.Command + cmd *cmd.Command actions actions.Actions client *lark.Client tls *tls.Config @@ -93,19 +91,40 @@ func New(cfg *Config, db *database.DB, tlsConfig *tls.Config, actions actions.Ac tls: tlsConfig, } - lrk.cmd = cmd.New(actions, lrk, lrk.preExec) + lrk.cmd = cmd.New( + actions, + &results.Text{ + Templates: results.DefaultTemplates(results.TemplateOptions{ + Markup: map[string]string{ + "": "**", + "": "**", + "": "", + "": "", + "
":    "",
+					"
": "", + "": "", + "": "", + }, + ExtraFuncs: template.FuncMap{ + "domain": func() string { return domain }, + }, + }), + OnText: func(ctx context.Context, message string) { + msgID, err := GetMessageID(ctx) + if err != nil { + // TODO: logs + return + } + // TODO: refactor + lrk.mdMessage("", msgID, message) + }, + }, + cmd.PreExec(cmd.DefaultMessengersPreExec), + ) return lrk, nil } -func (lrk *Lark) preExec(root *cobra.Command, u *actions.User) { - root.SetHelpTemplate(helpTemplate) - root.SetUsageTemplate(usageTemplate) - root.CompletionOptions = cobra.CompletionOptions{ - DisableDefaultCmd: true, - } -} - func (lrk *Lark) Start() error { // Sometimes the same event is sent several times, so keep recent event ids @@ -257,15 +276,8 @@ func (lrk *Lark) Start() error { ctx = SetMessageID(ctx, *msgID) ctx = actionsdb.SetUser(ctx, user) - args, _ := shlex.Split(strings.TrimLeft(msg.Text, "/")) - - // It is important to pass false as "local" here to disable - // dangerous commands. - if out, err := lrk.cmd.Exec(ctx, actionsdb.User(user), false, args); err != nil { - lrk.handleError(*userID, msgID, err) - } else if out != "" { - lrk.txtMessage(*userID, msgID, out) - } + + lrk.cmd.ParseAndExec(ctx, msg.Text) return nil }, @@ -442,35 +454,3 @@ func tpl(s string) *template.Template { Parse(s), ) } - -func (lrk *Lark) getDomain() string { - return lrk.domain -} - -func (lrk *Lark) txtResult(ctx context.Context, txt string) { - u, err := actionsdb.GetUser(ctx) - if err != nil { - return - } - - if msgID, err := GetMessageID(ctx); err == nil && msgID != nil { - lrk.mdMessage(u.Params.LarkUserID, msgID, txt) - } else { - lrk.mdMessage(u.Params.LarkUserID, nil, txt) - } -} - -func (lrk *Lark) tplResult(ctx context.Context, tpl *template.Template, data interface{}) { - tpl.Funcs(template.FuncMap{ - "domain": lrk.getDomain, - }) - - buf := &bytes.Buffer{} - - if err := tpl.Execute(buf, data); err != nil { - // lrk.handleError(u.Params.LarkUserID, nil, errors.Internal(err)) - log.Println(err) - } - - lrk.txtResult(ctx, buf.String()) -} diff --git a/internal/modules/lark/result.go b/internal/modules/lark/result.go deleted file mode 100644 index 37f4c5f..0000000 --- a/internal/modules/lark/result.go +++ /dev/null @@ -1,186 +0,0 @@ -package lark - -import ( - "context" - "fmt" - - "github.com/russtone/sonar/internal/actions" -) - -// Ensure Lark implemenents actions.ResultHandler interface. -var _ actions.ResultHandler = (*Lark)(nil) - -// TODO: move into common module -var ( - helpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} -{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` - - usageTemplate = ` -Usage:{{if .Runnable}}{{if .HasParent}} - {{.UseLine | replace "sonar " "/"}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - {{if .HasParent}}{{.CommandPath | replace "sonar " "/"}} {{else}}/{{end}}[command]{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - /{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{if .HasParent}}{{.CommandPath | replace "sonar " "/"}} {{else}}/{{end}}[command] --help" for more information about a command.{{end}} -` - - codeTemplate = tpl(`{{ . }}`) -) - -// -// User -// - -var userCurrentTemplate = tpl("" + - "**Lark ID:** {{ .Params.LarkUserID }}\n" + - "**API token:** {{ .Params.APIToken }}", -) - -func (lrk *Lark) UserCurrent(ctx context.Context, res actions.UserCurrentResult) { - lrk.tplResult(ctx, userCurrentTemplate, res) -} - -// -// Payloads -// - -var ( - payload = `**[{{ .Name }}]** - {{ .Subdomain }}.{{ domain }} ({{ .NotifyProtocols | join ", " }}) ({{ .StoreEvents }})` - - payloadTemplate = tpl(payload) - - payloadsTemplate = tpl(fmt.Sprintf(`{{ range . }}%s -{{ else }}nothing found{{ end }}`, payload)) -) - -func (lrk *Lark) PayloadsCreate(ctx context.Context, res actions.PayloadsCreateResult) { - lrk.tplResult(ctx, payloadTemplate, res) -} - -func (lrk *Lark) PayloadsList(ctx context.Context, res actions.PayloadsListResult) { - lrk.tplResult(ctx, payloadsTemplate, res) -} - -func (lrk *Lark) PayloadsUpdate(ctx context.Context, res actions.PayloadsUpdateResult) { - lrk.tplResult(ctx, payloadTemplate, res) -} - -func (lrk *Lark) PayloadsDelete(ctx context.Context, res actions.PayloadsDeleteResult) { - lrk.txtResult(ctx, fmt.Sprintf("payload %q deleted", res.Name)) -} - -// -// DNS records -// - -var ( - dnsRecord = ` -{{- $r := . -}} -{{- range $value := .Values -}} -**[{{ $r.Index }}]** - {{ $r.Name }}.{{ $r.PayloadSubdomain }}.{{ domain }} {{ $r.TTL }} IN {{ $r.Type }} {{ $value }} -{{ end -}}` - - dnsRecordTemplate = tpl(dnsRecord) - - dnsRecordsTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end }}`, dnsRecord)) -) - -func (lrk *Lark) DNSRecordsCreate(ctx context.Context, res actions.DNSRecordsCreateResult) { - lrk.tplResult(ctx, dnsRecordTemplate, res) -} - -func (lrk *Lark) DNSRecordsList(ctx context.Context, res actions.DNSRecordsListResult) { - lrk.tplResult(ctx, dnsRecordsTemplate, res) -} - -func (lrk *Lark) DNSRecordsDelete(ctx context.Context, res actions.DNSRecordsDeleteResult) { - lrk.txtResult(ctx, "dns record deleted") -} - -// -// HTTP routes -// - -var ( - httpRoute = ` -{{- $r := . -}} -**[{{ $r.Index }}] - **{{ $r.Method }} {{ $r.Path }} -> {{ $r.Code }}` - - httpRouteTemplate = tpl(httpRoute) - - httpRoutesTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end }}`, httpRoute)) -) - -func (lrk *Lark) HTTPRoutesCreate(ctx context.Context, res actions.HTTPRoutesCreateResult) { - lrk.tplResult(ctx, httpRouteTemplate, res) -} - -func (lrk *Lark) HTTPRoutesList(ctx context.Context, res actions.HTTPRoutesListResult) { - lrk.tplResult(ctx, httpRoutesTemplate, res) -} - -func (lrk *Lark) HTTPRoutesDelete(ctx context.Context, res actions.HTTPRoutesDeleteResult) { - lrk.txtResult(ctx, "http route deleted") -} - -// -// Users -// - -func (lrk *Lark) UsersCreate(ctx context.Context, res actions.UsersCreateResult) { - lrk.txtResult(ctx, fmt.Sprintf("user %q created", res.Name)) -} - -func (lrk *Lark) UsersDelete(ctx context.Context, res actions.UsersDeleteResult) { - lrk.txtResult(ctx, fmt.Sprintf("user %q deleted", res.Name)) -} - -// -// Events -// - -var ( - eventCommon = ` -{{- $e := . -}} -**[{{ $e.Index }}]** - {{ $e.Protocol | upper }} from {{ $e.RemoteAddr }} at {{ $e.ReceivedAt }}` - - eventTemplate = tpl(eventCommon + ` - -{{ $e.RW | b64dec }} -`) - - eventsTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end -}}`, eventCommon)) -) - -func (lrk *Lark) EventsList(ctx context.Context, res actions.EventsListResult) { - lrk.tplResult(ctx, eventsTemplate, res) -} - -func (lrk *Lark) EventsGet(ctx context.Context, res actions.EventsGetResult) { -} diff --git a/internal/modules/telegram/notifier.go b/internal/modules/telegram/notifier.go index 6d2dc65..ace3212 100644 --- a/internal/modules/telegram/notifier.go +++ b/internal/modules/telegram/notifier.go @@ -27,7 +27,6 @@ var ( ) func (tg *Telegram) Notify(u *models.User, p *models.Payload, e *models.Event) error { - var header, body bytes.Buffer headerData := struct { diff --git a/internal/modules/telegram/result.go b/internal/modules/telegram/result.go deleted file mode 100644 index 96f905a..0000000 --- a/internal/modules/telegram/result.go +++ /dev/null @@ -1,232 +0,0 @@ -package telegram - -import ( - "bytes" - "context" - "fmt" - "html/template" - - "github.com/Masterminds/sprig" - "github.com/russtone/sonar/internal/actions" - "github.com/russtone/sonar/internal/actionsdb" - "github.com/russtone/sonar/internal/utils/errors" -) - -var ( - helpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} -{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` - - usageTemplate = ` -Usage:{{if .Runnable}}{{if .HasParent}} - {{.UseLine | replace "sonarctl " "/"}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - {{if .HasParent}}{{.CommandPath | replace "sonarctl " "/"}} {{else}}/{{end}}[command]{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - /{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{if .HasParent}}{{.CommandPath | replace "sonarctl " "/"}} {{else}}/{{end}}[command] --help" for more information about a command.{{end}} -` - - codeTemplate = tpl(`{{ . }}`) -) - -func tpl(s string) *template.Template { - return template.Must(template. - New(""). - Funcs(sprig.FuncMap()). - Funcs(template.FuncMap{ - // This is nesessary for templates to compile. - // It will be replaced later with correct function. - "domain": func() string { return "" }, - }). - Parse(s), - ) -} - -func (tg *Telegram) getDomain() string { - return tg.domain -} - -func (tg *Telegram) txtResult(ctx context.Context, txt string) { - u, err := actionsdb.GetUser(ctx) - if err != nil { - return - } - - tg.txtMessage(u.Params.TelegramID, txt) -} - -func (tg *Telegram) tplResult(ctx context.Context, tpl *template.Template, data interface{}) { - u, err := actionsdb.GetUser(ctx) - if err != nil { - return - } - - tpl.Funcs(template.FuncMap{ - "domain": tg.getDomain, - }) - - buf := &bytes.Buffer{} - - if err := tpl.Execute(buf, data); err != nil { - tg.handleError(u.Params.TelegramID, errors.Internal(err)) - } - - tg.htmlMessage(u.Params.TelegramID, buf.String()) -} - -// -// User -// - -var userCurrentTemplate = tpl("" + - "Telegram ID: {{ .Params.TelegramID }}\n" + - "API token: {{ .Params.APIToken }}", -) - -func (tg *Telegram) UserCurrent(ctx context.Context, res actions.UserCurrentResult) { - tg.tplResult(ctx, userCurrentTemplate, res) -} - -// -// Payloads -// - -var ( - payload = `[{{ .Name }}] - {{ .Subdomain }}.{{ domain }} ({{ .NotifyProtocols | join ", " }}) ({{ .StoreEvents }})` - - payloadTemplate = tpl(payload) - - payloadsTemplate = tpl(fmt.Sprintf(`{{ range . }}%s -{{ else }}nothing found{{ end }}`, payload)) -) - -func (tg *Telegram) PayloadsCreate(ctx context.Context, res actions.PayloadsCreateResult) { - tg.tplResult(ctx, payloadTemplate, res) -} - -func (tg *Telegram) PayloadsList(ctx context.Context, res actions.PayloadsListResult) { - tg.tplResult(ctx, payloadsTemplate, res) -} - -func (tg *Telegram) PayloadsUpdate(ctx context.Context, res actions.PayloadsUpdateResult) { - tg.tplResult(ctx, payloadTemplate, res) -} - -func (tg *Telegram) PayloadsDelete(ctx context.Context, res actions.PayloadsDeleteResult) { - tg.txtResult(ctx, fmt.Sprintf("payload %q deleted", res.Name)) -} - -// -// DNS records -// - -var ( - dnsRecord = ` -{{- $r := . -}} -{{- range $value := .Values -}} -[{{ $r.Index }}] - {{ $r.Name }}.{{ $r.PayloadSubdomain }}.{{ domain }} {{ $r.TTL }} IN {{ $r.Type }} {{ $value }} -{{ end -}}` - - dnsRecordTemplate = tpl(dnsRecord) - - dnsRecordsTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end }}`, dnsRecord)) -) - -func (tg *Telegram) DNSRecordsCreate(ctx context.Context, res actions.DNSRecordsCreateResult) { - tg.tplResult(ctx, dnsRecordTemplate, res) -} - -func (tg *Telegram) DNSRecordsList(ctx context.Context, res actions.DNSRecordsListResult) { - tg.tplResult(ctx, dnsRecordsTemplate, res) -} - -func (tg *Telegram) DNSRecordsDelete(ctx context.Context, res actions.DNSRecordsDeleteResult) { - tg.txtResult(ctx, "dns record deleted") -} - -// -// HTTP routes -// - -var ( - httpRoute = ` -{{- $r := . -}} -[{{ $r.Index }}] - {{ $r.Method }} {{ $r.Path }} -> {{ $r.Code }}` - - httpRouteTemplate = tpl(httpRoute) - - httpRoutesTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end }}`, httpRoute)) -) - -func (tg *Telegram) HTTPRoutesCreate(ctx context.Context, res actions.HTTPRoutesCreateResult) { - tg.tplResult(ctx, httpRouteTemplate, res) -} - -func (tg *Telegram) HTTPRoutesList(ctx context.Context, res actions.HTTPRoutesListResult) { - tg.tplResult(ctx, httpRoutesTemplate, res) -} - -func (tg *Telegram) HTTPRoutesDelete(ctx context.Context, res actions.HTTPRoutesDeleteResult) { - tg.txtResult(ctx, "http route deleted") -} - -// -// Users -// - -func (tg *Telegram) UsersCreate(ctx context.Context, res actions.UsersCreateResult) { - tg.txtResult(ctx, fmt.Sprintf("user %q created", res.Name)) -} - -func (tg *Telegram) UsersDelete(ctx context.Context, res actions.UsersDeleteResult) { - tg.txtResult(ctx, fmt.Sprintf("user %q deleted", res.Name)) -} - -// -// Events -// - -var ( - event = ` -{{- $e := . -}} -[{{ $e.Index }}] - {{ $e.Protocol | upper }} from {{ $e.RemoteAddr }} at {{ $e.ReceivedAt }}` - - eventTemplate = tpl(event + ` - -{{ $e.RW | b64dec }} -`) - - eventsTemplate = tpl(fmt.Sprintf(` -{{- range . -}} -%s -{{ else }}nothing found{{ end -}}`, event)) -) - -func (tg *Telegram) EventsList(ctx context.Context, res actions.EventsListResult) { - tg.tplResult(ctx, eventsTemplate, res) -} - -func (tg *Telegram) EventsGet(ctx context.Context, res actions.EventsGetResult) { -} diff --git a/internal/modules/telegram/telegram.go b/internal/modules/telegram/telegram.go index e1f42a9..c13ad6b 100644 --- a/internal/modules/telegram/telegram.go +++ b/internal/modules/telegram/telegram.go @@ -4,19 +4,19 @@ import ( "bytes" "context" "fmt" + "html/template" "net/http" "net/url" - "strings" + "github.com/Masterminds/sprig" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" - "github.com/google/shlex" - "github.com/spf13/cobra" "github.com/russtone/sonar/internal/actions" "github.com/russtone/sonar/internal/actionsdb" "github.com/russtone/sonar/internal/cmd" "github.com/russtone/sonar/internal/database" "github.com/russtone/sonar/internal/database/models" + "github.com/russtone/sonar/internal/results" "github.com/russtone/sonar/internal/utils" "github.com/russtone/sonar/internal/utils/errors" ) @@ -25,7 +25,7 @@ type Telegram struct { api *tgbotapi.BotAPI db *database.DB cfg *Config - cmd cmd.Command + cmd *cmd.Command actions actions.Actions bot tgbotapi.User @@ -67,7 +67,38 @@ func New(cfg *Config, db *database.DB, actions actions.Actions, domain string) ( actions: actions, } - tg.cmd = cmd.New(actions, tg, tg.preExec) + tg.cmd = cmd.New( + actions, + &results.Text{ + Templates: results.DefaultTemplates(results.TemplateOptions{ + Markup: map[string]string{ + "": "", + "": "", + "": "", + "": "", + "": "", + "": "", + "
":    "
",
+					"
": "
", + }, + ExtraFuncs: template.FuncMap{ + "domain": func() string { + return domain + }, + }, + HTML: true, + }), + OnText: func(ctx context.Context, message string) { + chatID, err := GetChatID(ctx) + if err != nil { + // TODO: logging + return + } + tg.htmlMessage(chatID, message) + }, + }, + cmd.PreExec(cmd.DefaultMessengersPreExec), + ) return tg, nil } @@ -124,26 +155,16 @@ func (tg *Telegram) Start() error { continue } - var user *models.User + ctx := SetChatID(context.Background(), chat.ID) // Only registered users should be able to use bot. if chat.IsGroup() && fromUser == nil { - user = nil + ctx = actionsdb.SetUser(ctx, nil) } else { - user = chatUser + ctx = actionsdb.SetUser(ctx, chatUser) } - ctx := SetChatID(context.Background(), chat.ID) - ctx = actionsdb.SetUser(ctx, user) - args, _ := shlex.Split(strings.TrimLeft(update.Message.Text, "/")) - - // It is important to pass false as "local" here to disable - // dangerous commands. - if out, err := tg.cmd.Exec(ctx, actionsdb.User(user), false, args); err != nil { - tg.handleError(chat.ID, err) - } else if out != "" { - tg.htmlMessage(chat.ID, out) - } + tg.cmd.ParseAndExec(ctx, update.Message.Text) } return nil @@ -169,30 +190,23 @@ func (tg *Telegram) isDeletedFromGroup(msg *tgbotapi.Message) bool { return msg.LeftChatMember != nil && msg.LeftChatMember.ID == tg.bot.ID } -func (tg *Telegram) preExec(root *cobra.Command, u *actions.User) { - root.SetHelpTemplate(helpTemplate) - root.SetUsageTemplate(usageTemplate) - root.CompletionOptions = cobra.CompletionOptions{ - DisableDefaultCmd: true, - } - - cmd := &cobra.Command{ - Use: "id", - Short: "Show current telegram chat id", - RunE: cmd.RunE(func(cmd *cobra.Command, args []string) errors.Error { - chatID, err := GetChatID(cmd.Context()) - if err != nil { - return errors.Internal(err) - } - - tg.txtMessage(chatID, fmt.Sprintf("%d", chatID)) - - return nil - }), - } - - root.AddCommand(cmd) -} +// TODO +// func (tg *Telegram) preExec(root *cobra.Command, u *actions.User) { +// cmd := &cobra.Command{ +// Use: "id", +// Short: "Show current telegram chat id", +// Run: func(cmd *cobra.Command, args []string) { +// chatID, err := GetChatID(cmd.Context()) +// if err != nil { +// return errors.Internal(err) +// } +// +// tg.txtMessage(chatID, fmt.Sprintf("%d", chatID)) +// }, +// } +// +// root.AddCommand(cmd) +// } func (tg *Telegram) handleError(chatID int64, err errors.Error) { tg.txtMessage(chatID, err.Error()) @@ -215,7 +229,10 @@ func (tg *Telegram) htmlMessage(chatID int64, html string) { ) msg.ParseMode = tgbotapi.ModeHTML msg.DisableWebPagePreview = true - tg.api.Send(msg) + _, err := tg.api.Send(msg) + if err != nil { + fmt.Println(err) + } } func (tg *Telegram) docMessage(chatID int64, name string, caption string, data []byte) { @@ -229,3 +246,50 @@ func (tg *Telegram) docMessage(chatID int64, name string, caption string, data [ msg.ParseMode = tgbotapi.ModeHTML tg.api.Send(msg) } + +func tpl(s string) *template.Template { + return template.Must(template. + New(""). + Funcs(sprig.FuncMap()). + Funcs(template.FuncMap{ + // This is nesessary for templates to compile. + // It will be replaced later with correct function. + "domain": func() string { return "" }, + }). + Parse(s), + ) +} + +func (tg *Telegram) getDomain() string { + return tg.domain +} + +func (tg *Telegram) txtResult(ctx context.Context, txt string) { + u, err := actionsdb.GetUser(ctx) + if err != nil { + return + } + + tg.txtMessage(u.Params.TelegramID, txt) +} + +func (tg *Telegram) tplResult(ctx context.Context, tpl *template.Template, data interface{}) { + u, err := actionsdb.GetUser(ctx) + if err != nil { + return + } + + tpl.Funcs(template.FuncMap{ + "domain": tg.getDomain, + }) + + buf := &bytes.Buffer{} + + if err := tpl.Execute(buf, data); err != nil { + tg.handleError(u.Params.TelegramID, errors.Internal(err)) + } + + tg.htmlMessage(u.Params.TelegramID, buf.String()) +} + +var codeTemplate = tpl(`{{ . }}`) diff --git a/internal/results/json.go b/internal/results/json.go new file mode 100644 index 0000000..e2eceb0 --- /dev/null +++ b/internal/results/json.go @@ -0,0 +1,17 @@ +package results + +import ( + "context" + "encoding/json" + + "github.com/russtone/sonar/internal/actions" +) + +type JSON struct { + Encoder *json.Encoder +} + +func (h *JSON) OnResult(ctx context.Context, res actions.Result) { + h.Encoder.Encode(res) +} + diff --git a/internal/results/templates.go b/internal/results/templates.go new file mode 100644 index 0000000..bfbc625 --- /dev/null +++ b/internal/results/templates.go @@ -0,0 +1,156 @@ +package results + +import ( + "fmt" + "io" + "strings" + + "html/template" + htmltemplate "html/template" + texttemplate "text/template" + + "github.com/Masterminds/sprig" +) + +type Template interface { + Execute(io.Writer, any) error +} + +func MakeTemplate(s string, opts TemplateOptions) Template { + + // Replace all pseudotags like "" or "" using + // provided markup map. + // TODO: maybe move to Execute function, after executing template + for tag, replacement := range opts.Markup { + s = strings.ReplaceAll(s, tag, replacement) + } + + if opts.HTML { + return htmltemplate.Must(htmltemplate. + New(""). + Funcs(sprig.FuncMap()). + Funcs(opts.ExtraFuncs). + Parse(s), + ) + } else { + return texttemplate.Must(texttemplate. + New(""). + Funcs(sprig.FuncMap()). + Funcs(opts.ExtraFuncs). + Parse(s), + ) + } + +} + +type TemplateOptions struct { + Markup map[string]string + ExtraFuncs template.FuncMap + HTML bool +} + +func DefaultTemplates(opts TemplateOptions) map[string]Template { + return map[string]Template{ + "profile/get": MakeTemplate(profileGet, opts), + "payloads/get": MakeTemplate(payloadsGet, opts), + "payloads/list": MakeTemplate(payloadsList, opts), + "payloads/create": MakeTemplate(payloadsCreate, opts), + "payloads/update": MakeTemplate(payloadsUpdate, opts), + "payloads/delete": MakeTemplate(payloadsDelete, opts), + "dns-records/list": MakeTemplate(dnsRecordsList, opts), + "dns-records/create": MakeTemplate(dnsRecordsCreate, opts), + "dns-records/delete": MakeTemplate(dnsRecordsDelete, opts), + "http-routes/list": MakeTemplate(httpRoutesList, opts), + "http-routes/create": MakeTemplate(httpRoutesCreate, opts), + "http-routes/delete": MakeTemplate(httpRoutesDelete, opts), + "events/list": MakeTemplate(eventsList, opts), + "events/get": MakeTemplate(eventsGet, opts), + "text": MakeTemplate(text, opts), + "error": MakeTemplate(err, opts), + } +} + +// +// Profile +// + +var profileGet = "" + + "Name: {{ .Name }}\n" + + "Telegram ID: {{ .Params.TelegramID }}\n" + + "API token: {{ .Params.APIToken }}\n" + + "Admin: {{ .IsAdmin }}" + +// +// Payloads +// + +var payload = ` +{{- $p := . -}} +[{{ $p.Name }}] - {{ $p.Subdomain }}.{{ domain }} ({{ $p.NotifyProtocols | join ", " }}) ({{ $p.StoreEvents }})` + +var payloadsGet = payload +var payloadsList = fmt.Sprintf(`{{ range . }}%s +{{ else }}nothing found{{ end }}`, payload) +var payloadsCreate = payload +var payloadsUpdate = payload +var payloadsDelete = `payload "{{ .Name }}" deleted` + +// +// DNS records +// + +var dnsRecord = ` +{{- $r := . -}} +{{- range $value := .Values -}} +[{{ $r.Index }}] - {{ $r.Name }}.{{ $r.PayloadSubdomain }}.{{ domain }} {{ $r.TTL }} IN {{ $r.Type }} {{ $value }} +{{ end -}}` + +var dnsRecordsList = fmt.Sprintf(` +{{- range . -}} +%s +{{ else }}nothing found{{ end }}`, dnsRecord) +var dnsRecordsCreate = dnsRecord +var dnsRecordsDelete = `dns record deleted` + +// +// HTTP routes +// + +var httpRoute = ` +{{- $r := . -}} +[{{ $r.Index }}] - {{ $r.Method }} {{ $r.Path }} -> {{ $r.Code }}` + +var httpRoutesList = fmt.Sprintf(` +{{- range . -}} +%s +{{ else }}nothing found{{ end }}`, httpRoute) +var httpRoutesCreate = httpRoute +var httpRoutesDelete = "http route deleted" + +// +// Users +// + +var usersCreate = `user "{{ .Name }}" created` +var usersDelete = `user "{{ .Name }}" deleted` + +// +// Events +// + +var event = ` +{{- $e := . -}} +[{{ $e.Index }}] - {{ $e.Protocol | upper }} from {{ $e.RemoteAddr }} at {{ $e.ReceivedAt }}` + +var eventsGet = event + ` + +
{{ $e.RW | b64dec }}
` + +var eventsList = fmt.Sprintf(` +{{- range . -}} +%s +{{ else }}nothing found{{ end -}}`, event) + +var text = "{{ .Text }}" + +var err = "{{ .Error }}" diff --git a/internal/results/text.go b/internal/results/text.go new file mode 100644 index 0000000..de38443 --- /dev/null +++ b/internal/results/text.go @@ -0,0 +1,31 @@ +package results + +import ( + "bytes" + "context" + "fmt" + + "github.com/russtone/sonar/internal/actions" +) + +type Text struct { + Templates map[string]Template + OnText func(ctx context.Context, message string) +} + +func (h *Text) OnResult(ctx context.Context, res actions.Result) { + tpl, ok := h.Templates[res.ResultID()] + if !ok { + h.OnText(ctx, fmt.Sprintf("no template for %q", res.ResultID())) + return + } + + buf := &bytes.Buffer{} + + if err := tpl.Execute(buf, res); err != nil { + h.OnText(ctx, fmt.Sprintf("template error for %q: %v", res.ResultID(), err)) + return + } + + h.OnText(ctx, buf.String()) +}