From 001a4448ca5fb0018eeb442915b473b121c04bf3 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 6 Jan 2016 21:09:05 -0600 Subject: PLT-1429 adding sql storage for slash commands --- model/command.go | 121 +++++++++++++++++++++++++++++++++++++++++--------- model/command_test.go | 90 +++++++++++++++++++++++++++++++++---- 2 files changed, 182 insertions(+), 29 deletions(-) (limited to 'model') diff --git a/model/command.go b/model/command.go index 5aec5f534..253021896 100644 --- a/model/command.go +++ b/model/command.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. package model @@ -9,28 +9,27 @@ import ( ) const ( - RESP_EXECUTED = "executed" - RESP_NOT_IMPLEMENTED = "not implemented" + COMMAND_METHOD_POST = "P" + COMMAND_METHOD_GET = "G" ) type Command struct { - Command string `json:"command"` - Response string `json:"response"` - GotoLocation string `json:"goto_location"` - ChannelId string `json:"channel_id"` - Suggest bool `json:"-"` - Suggestions []*SuggestCommand `json:"suggestions"` -} - -func (o *Command) AddSuggestion(suggest *SuggestCommand) { - - if o.Suggest { - if o.Suggestions == nil { - o.Suggestions = make([]*SuggestCommand, 0, 128) - } - - o.Suggestions = append(o.Suggestions, suggest) - } + Id string `json:"id"` + Token string `json:"token"` + CreateAt int64 `json:"create_at"` + UpdateAt int64 `json:"update_at"` + DeleteAt int64 `json:"delete_at"` + CreatorId string `json:"creator_id"` + TeamId string `json:"team_id"` + Trigger string `json:"trigger"` + Method string `json:"method"` + Username string `json:"username"` + IconURL string `json:"icon_url"` + AutoComplete bool `json:"auto_complete"` + AutoCompleteDesc string `json:"auto_complete_desc"` + AutoCompleteHint string `json:"auto_complete_hint"` + DisplayName string `json:"display_name"` + URL string `json:"url"` } func (o *Command) ToJson() string { @@ -52,3 +51,85 @@ func CommandFromJson(data io.Reader) *Command { return nil } } + +func CommandListToJson(l []*Command) string { + b, err := json.Marshal(l) + if err != nil { + return "" + } else { + return string(b) + } +} + +func CommandListFromJson(data io.Reader) []*Command { + decoder := json.NewDecoder(data) + var o []*Command + err := decoder.Decode(&o) + if err == nil { + return o + } else { + return nil + } +} + +func (o *Command) IsValid() *AppError { + + if len(o.Id) != 26 { + return NewAppError("Command.IsValid", "Invalid Id", "") + } + + if len(o.Token) != 26 { + return NewAppError("Command.IsValid", "Invalid token", "") + } + + if o.CreateAt == 0 { + return NewAppError("Command.IsValid", "Create at must be a valid time", "id="+o.Id) + } + + if o.UpdateAt == 0 { + return NewAppError("Command.IsValid", "Update at must be a valid time", "id="+o.Id) + } + + if len(o.CreatorId) != 26 { + return NewAppError("Command.IsValid", "Invalid user id", "") + } + + if len(o.TeamId) != 26 { + return NewAppError("Command.IsValid", "Invalid team id", "") + } + + if len(o.Trigger) > 1024 { + return NewAppError("Command.IsValid", "Invalid trigger", "") + } + + if len(o.URL) == 0 || len(o.URL) > 1024 { + return NewAppError("Command.IsValid", "Invalid url", "") + } + + if !IsValidHttpUrl(o.URL) { + return NewAppError("Command.IsValid", "Invalid URL. Must be a valid URL and start with http:// or https://", "") + } + + if !(o.Method == COMMAND_METHOD_GET || o.Method == COMMAND_METHOD_POST) { + return NewAppError("Command.IsValid", "Invalid Method", "") + } + + return nil +} + +func (o *Command) PreSave() { + if o.Id == "" { + o.Id = NewId() + } + + if o.Token == "" { + o.Token = NewId() + } + + o.CreateAt = GetMillis() + o.UpdateAt = o.CreateAt +} + +func (o *Command) PreUpdate() { + o.UpdateAt = GetMillis() +} diff --git a/model/command_test.go b/model/command_test.go index 61302ea10..0581625d9 100644 --- a/model/command_test.go +++ b/model/command_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. package model @@ -9,17 +9,89 @@ import ( ) func TestCommandJson(t *testing.T) { + o := Command{Id: NewId()} + json := o.ToJson() + ro := CommandFromJson(strings.NewReader(json)) - command := &Command{Command: NewId(), Suggest: true} - command.AddSuggestion(&SuggestCommand{Suggestion: NewId()}) - json := command.ToJson() - result := CommandFromJson(strings.NewReader(json)) - - if command.Command != result.Command { + if o.Id != ro.Id { t.Fatal("Ids do not match") } +} - if command.Suggestions[0].Suggestion != result.Suggestions[0].Suggestion { - t.Fatal("Ids do not match") +func TestCommandIsValid(t *testing.T) { + o := Command{} + + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.Id = NewId() + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.CreateAt = GetMillis() + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.UpdateAt = GetMillis() + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.CreatorId = "123" + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.CreatorId = NewId() + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.Token = "123" + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") } + + o.Token = NewId() + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.TeamId = "123" + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.TeamId = NewId() + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.URL = "nowhere.com/" + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.URL = "http://nowhere.com/" + if err := o.IsValid(); err == nil { + t.Fatal("should be invalid") + } + + o.Method = COMMAND_METHOD_GET + if err := o.IsValid(); err != nil { + t.Fatal(err) + } +} + +func TestCommandPreSave(t *testing.T) { + o := Command{} + o.PreSave() +} + +func TestCommandPreUpdate(t *testing.T) { + o := Command{} + o.PreUpdate() } -- cgit v1.2.3-1-g7c22 From 3fba8e42b140c1189bf3c06882cce5e2231e63da Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Fri, 8 Jan 2016 12:41:26 -0600 Subject: partial fix for UI --- model/client.go | 20 ++++++++++++++++++- model/command_response.go | 40 ++++++++++++++++++++++++++++++++++++++ model/command_response_test.go | 19 ++++++++++++++++++ model/config.go | 44 +++++++++++++++++++++++++++--------------- model/version.go | 10 +++++----- 5 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 model/command_response.go create mode 100644 model/command_response_test.go (limited to 'model') diff --git a/model/client.go b/model/client.go index f1773f3c7..83d1d316c 100644 --- a/model/client.go +++ b/model/client.go @@ -372,7 +372,25 @@ func (c *Client) Command(channelId string, command string, suggest bool) (*Resul m["command"] = command m["channelId"] = channelId m["suggest"] = strconv.FormatBool(suggest) - if r, err := c.DoApiPost("/command", MapToJson(m)); err != nil { + if r, err := c.DoApiPost("/commands/execute", MapToJson(m)); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), CommandResponseFromJson(r.Body)}, nil + } +} + +func (c *Client) ListCommands() (*Result, *AppError) { + if r, err := c.DoApiPost("/commands/list", ""); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil + } +} + +func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) { + if r, err := c.DoApiPost("/commands/create", cmd.ToJson()); err != nil { return nil, err } else { return &Result{r.Header.Get(HEADER_REQUEST_ID), diff --git a/model/command_response.go b/model/command_response.go new file mode 100644 index 000000000..001384864 --- /dev/null +++ b/model/command_response.go @@ -0,0 +1,40 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +const ( + COMMAND_RESPONSE_TYPE_IN_CHANNEL = "in_channel" + COMMAND_RESPONSE_TYPE_EPHEMERAL = "ephemeral" +) + +type CommandResponse struct { + ResponseType string `json:"response_type"` + Text string `json:"text"` + Attachments interface{} `json:"attachments"` +} + +func (o *CommandResponse) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + +func CommandResponseFromJson(data io.Reader) *CommandResponse { + decoder := json.NewDecoder(data) + var o CommandResponse + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} diff --git a/model/command_response_test.go b/model/command_response_test.go new file mode 100644 index 000000000..7aa3e984b --- /dev/null +++ b/model/command_response_test.go @@ -0,0 +1,19 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "strings" + "testing" +) + +func TestCommandResponseJson(t *testing.T) { + o := CommandResponse{Text: "test"} + json := o.ToJson() + ro := CommandResponseFromJson(strings.NewReader(json)) + + if o.Text != ro.Text { + t.Fatal("Ids do not match") + } +} diff --git a/model/config.go b/model/config.go index ed56ed0c7..7d9ff41f1 100644 --- a/model/config.go +++ b/model/config.go @@ -24,22 +24,24 @@ const ( ) type ServiceSettings struct { - ListenAddress string - MaximumLoginAttempts int - SegmentDeveloperKey string - GoogleDeveloperKey string - EnableOAuthServiceProvider bool - EnableIncomingWebhooks bool - EnableOutgoingWebhooks bool - EnablePostUsernameOverride bool - EnablePostIconOverride bool - EnableTesting bool - EnableDeveloper *bool - EnableSecurityFixAlert *bool - SessionLengthWebInDays *int - SessionLengthMobileInDays *int - SessionLengthSSOInDays *int - SessionCacheInMinutes *int + ListenAddress string + MaximumLoginAttempts int + SegmentDeveloperKey string + GoogleDeveloperKey string + EnableOAuthServiceProvider bool + EnableIncomingWebhooks bool + EnableOutgoingWebhooks bool + EnableCommands *bool + EnableOnlyAdminIntegrations *bool + EnablePostUsernameOverride bool + EnablePostIconOverride bool + EnableTesting bool + EnableDeveloper *bool + EnableSecurityFixAlert *bool + SessionLengthWebInDays *int + SessionLengthMobileInDays *int + SessionLengthSSOInDays *int + SessionCacheInMinutes *int } type SSOSettings struct { @@ -330,6 +332,16 @@ func (o *Config) SetDefaults() { o.ServiceSettings.SessionCacheInMinutes = new(int) *o.ServiceSettings.SessionCacheInMinutes = 10 } + + if o.ServiceSettings.EnableCommands == nil { + o.ServiceSettings.EnableCommands = new(bool) + *o.ServiceSettings.EnableCommands = false + } + + if o.ServiceSettings.EnableOnlyAdminIntegrations == nil { + o.ServiceSettings.EnableOnlyAdminIntegrations = new(bool) + *o.ServiceSettings.EnableOnlyAdminIntegrations = true + } } func (o *Config) IsValid() *AppError { diff --git a/model/version.go b/model/version.go index 142ddb371..e6faf137c 100644 --- a/model/version.go +++ b/model/version.go @@ -24,10 +24,10 @@ var versions = []string{ } var CurrentVersion string = versions[0] -var BuildNumber = "_BUILD_NUMBER_" -var BuildDate = "_BUILD_DATE_" -var BuildHash = "_BUILD_HASH_" -var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_" +var BuildNumber = "dev" +var BuildDate = "Fri Jan 8 14:19:26 UTC 2016" +var BuildHash = "001a4448ca5fb0018eeb442915b473b121c04bf3" +var BuildEnterpriseReady = "false" func SplitVersion(version string) (int64, int64, int64) { parts := strings.Split(version, ".") @@ -73,7 +73,7 @@ func GetPreviousVersion(currentVersion string) (int64, int64) { } func IsOfficalBuild() bool { - return BuildNumber != "_BUILD_NUMBER_" + return BuildNumber != "dev" } func IsCurrentVersion(versionToCheck string) bool { -- cgit v1.2.3-1-g7c22 From e1f4cc4bb004a0a0d4bb6d68ff328233f9f72aa0 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Fri, 8 Jan 2016 22:57:38 -0600 Subject: Adding web service methods --- model/client.go | 29 ++++++++++++++++++++++++++++- model/command.go | 9 +++++++++ model/utils.go | 6 +++++- 3 files changed, 42 insertions(+), 2 deletions(-) (limited to 'model') diff --git a/model/client.go b/model/client.go index 83d1d316c..3a645e175 100644 --- a/model/client.go +++ b/model/client.go @@ -381,7 +381,16 @@ func (c *Client) Command(channelId string, command string, suggest bool) (*Resul } func (c *Client) ListCommands() (*Result, *AppError) { - if r, err := c.DoApiPost("/commands/list", ""); err != nil { + if r, err := c.DoApiGet("/commands/list", "", ""); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil + } +} + +func (c *Client) ListTeamCommands() (*Result, *AppError) { + if r, err := c.DoApiGet("/commands/list_team_commands", "", ""); err != nil { return nil, err } else { return &Result{r.Header.Get(HEADER_REQUEST_ID), @@ -398,6 +407,24 @@ func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) { } } +func (c *Client) RegenCommandToken(data map[string]string) (*Result, *AppError) { + if r, err := c.DoApiPost("/commands/regen_token", MapToJson(data)); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil + } +} + +func (c *Client) DeleteCommand(data map[string]string) (*Result, *AppError) { + if r, err := c.DoApiPost("/commands/delete", MapToJson(data)); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil + } +} + func (c *Client) GetAudits(id string, etag string) (*Result, *AppError) { if r, err := c.DoApiGet("/users/"+id+"/audits", "", etag); err != nil { return nil, err diff --git a/model/command.go b/model/command.go index 253021896..c917a46ea 100644 --- a/model/command.go +++ b/model/command.go @@ -133,3 +133,12 @@ func (o *Command) PreSave() { func (o *Command) PreUpdate() { o.UpdateAt = GetMillis() } + +func (o *Command) Sanatize() { + o.Token = "" + o.CreatorId = "" + o.Method = "" + o.URL = "" + o.Username = "" + o.IconURL = "" +} diff --git a/model/utils.go b/model/utils.go index 617c95efd..301e36f59 100644 --- a/model/utils.go +++ b/model/utils.go @@ -54,7 +54,11 @@ func AppErrorFromJson(data io.Reader) *AppError { if err == nil { return &er } else { - return NewAppError("AppErrorFromJson", "could not decode", err.Error()) + buf := new(bytes.Buffer) + buf.ReadFrom(data) + s := buf.String() + + return NewAppError("AppErrorFromJson", "could not decode", err.Error()+" "+s) } } -- cgit v1.2.3-1-g7c22 From b1a7c1acf139efbb5312b4aa939bd94155e6a9e6 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Sat, 9 Jan 2016 08:54:07 -0600 Subject: adding different commands --- model/command_response.go | 1 + 1 file changed, 1 insertion(+) (limited to 'model') diff --git a/model/command_response.go b/model/command_response.go index 001384864..9314f38ef 100644 --- a/model/command_response.go +++ b/model/command_response.go @@ -16,6 +16,7 @@ const ( type CommandResponse struct { ResponseType string `json:"response_type"` Text string `json:"text"` + GotoLocation string `json:"goto_location"` Attachments interface{} `json:"attachments"` } -- cgit v1.2.3-1-g7c22 From 27586a320add265f3e032d2cb21b27e93b51a2b0 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Mon, 1 Feb 2016 18:52:43 -0800 Subject: Adding loc to new command backend --- model/command.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'model') diff --git a/model/command.go b/model/command.go index c917a46ea..4a726b4ac 100644 --- a/model/command.go +++ b/model/command.go @@ -75,43 +75,43 @@ func CommandListFromJson(data io.Reader) []*Command { func (o *Command) IsValid() *AppError { if len(o.Id) != 26 { - return NewAppError("Command.IsValid", "Invalid Id", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "") } if len(o.Token) != 26 { - return NewAppError("Command.IsValid", "Invalid token", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.token.app_error", nil, "") } if o.CreateAt == 0 { - return NewAppError("Command.IsValid", "Create at must be a valid time", "id="+o.Id) + return NewLocAppError("Command.IsValid", "model.command.is_valid.create_at.app_error", nil, "") } if o.UpdateAt == 0 { - return NewAppError("Command.IsValid", "Update at must be a valid time", "id="+o.Id) + return NewLocAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "") } if len(o.CreatorId) != 26 { - return NewAppError("Command.IsValid", "Invalid user id", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "") } if len(o.TeamId) != 26 { - return NewAppError("Command.IsValid", "Invalid team id", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "") } if len(o.Trigger) > 1024 { - return NewAppError("Command.IsValid", "Invalid trigger", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "") } if len(o.URL) == 0 || len(o.URL) > 1024 { - return NewAppError("Command.IsValid", "Invalid url", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "") } if !IsValidHttpUrl(o.URL) { - return NewAppError("Command.IsValid", "Invalid URL. Must be a valid URL and start with http:// or https://", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.url_http.app_error", nil, "") } if !(o.Method == COMMAND_METHOD_GET || o.Method == COMMAND_METHOD_POST) { - return NewAppError("Command.IsValid", "Invalid Method", "") + return NewLocAppError("Command.IsValid", "model.command.is_valid.method.app_error", nil, "") } return nil -- cgit v1.2.3-1-g7c22 From 581785f5044eecdc7cf664e4c7fc59efc6babc96 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 2 Feb 2016 16:24:03 -0800 Subject: Fixing version --- model/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'model') diff --git a/model/version.go b/model/version.go index a5227f328..c1e4615da 100644 --- a/model/version.go +++ b/model/version.go @@ -84,7 +84,7 @@ func GetPreviousVersion(version string) string { } func IsOfficalBuild() bool { - return BuildNumber != "dev" + return BuildNumber != "_BUILD_NUMBER_" } func IsCurrentVersion(versionToCheck string) bool { -- cgit v1.2.3-1-g7c22 From 4da7b0ccbd1b393613037f8ee5870d5660b36a84 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 3 Feb 2016 12:16:37 -0800 Subject: Fixing based on feedback --- model/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'model') diff --git a/model/command.go b/model/command.go index 4a726b4ac..56d88f13c 100644 --- a/model/command.go +++ b/model/command.go @@ -134,7 +134,7 @@ func (o *Command) PreUpdate() { o.UpdateAt = GetMillis() } -func (o *Command) Sanatize() { +func (o *Command) Sanitize() { o.Token = "" o.CreatorId = "" o.Method = "" -- cgit v1.2.3-1-g7c22 From dffc5323ecd9c7bc1af0ea06ef4827078f9bcd52 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Thu, 4 Feb 2016 08:03:42 -0800 Subject: PLT-1429 Fixing code review comments --- model/version.go | 1 - 1 file changed, 1 deletion(-) (limited to 'model') diff --git a/model/version.go b/model/version.go index c1e4615da..69529e7a1 100644 --- a/model/version.go +++ b/model/version.go @@ -26,7 +26,6 @@ var versions = []string{ } var CurrentVersion string = versions[0] - var BuildNumber = "_BUILD_NUMBER_" var BuildDate = "_BUILD_DATE_" var BuildHash = "_BUILD_HASH_" -- cgit v1.2.3-1-g7c22