diff options
author | Asaad Mahmood <Unknowngi@live.com> | 2015-10-27 20:15:33 +0500 |
---|---|---|
committer | Asaad Mahmood <Unknowngi@live.com> | 2015-10-27 20:15:33 +0500 |
commit | 179c4ea684af8d2a021cc6f0042bc4408f39b0bb (patch) | |
tree | 7789805249e5c962f1175f301beb74272dee30c0 /api | |
parent | 68b02ffb9eeb7a414feae8ed89b4011ccecf96bc (diff) | |
parent | 50eb3d9fe46d6364b6f12201edfe0a401be3ccdd (diff) | |
download | chat-179c4ea684af8d2a021cc6f0042bc4408f39b0bb.tar.gz chat-179c4ea684af8d2a021cc6f0042bc4408f39b0bb.tar.bz2 chat-179c4ea684af8d2a021cc6f0042bc4408f39b0bb.zip |
Merge branch 'master' of https://github.com/mattermost/platform into ui-improvements
Diffstat (limited to 'api')
-rw-r--r-- | api/command.go | 77 | ||||
-rw-r--r-- | api/file.go | 22 | ||||
-rw-r--r-- | api/post.go | 42 | ||||
-rw-r--r-- | api/post_test.go | 40 | ||||
-rw-r--r-- | api/templates/password_change_body.html | 2 | ||||
-rw-r--r-- | api/user.go | 13 |
6 files changed, 135 insertions, 61 deletions
diff --git a/api/command.go b/api/command.go index 54f863c48..b2a4f4a0b 100644 --- a/api/command.go +++ b/api/command.go @@ -17,14 +17,23 @@ import ( type commandHandler func(c *Context, command *model.Command) bool -var commands = []commandHandler{ - logoutCommand, - joinCommand, - loadTestCommand, - echoCommand, - shrugCommand, -} - +var ( + cmds = map[string]string{ + "logoutCommand": "/logout", + "joinCommand": "/join", + "loadTestCommand": "/loadtest", + "echoCommand": "/echo", + "shrugCommand": "/shrug", + } + commands = []commandHandler{ + logoutCommand, + joinCommand, + loadTestCommand, + echoCommand, + shrugCommand, + } + commandNotImplementedErr = model.NewAppError("checkCommand", "Command not implemented", "") +) var echoSem chan bool func InitCommand(r *mux.Router) { @@ -45,7 +54,14 @@ func command(c *Context, w http.ResponseWriter, r *http.Request) { checkCommand(c, command) if c.Err != nil { - return + if c.Err != commandNotImplementedErr { + return + } else { + c.Err = nil + command.Response = model.RESP_NOT_IMPLEMENTED + w.Write([]byte(command.ToJson())) + return + } } else { w.Write([]byte(command.ToJson())) } @@ -66,6 +82,23 @@ func checkCommand(c *Context, command *model.Command) bool { } } + if !command.Suggest { + implemented := false + for _, cmd := range cmds { + bounds := len(cmd) + if len(command.Command) < bounds { + continue + } + if command.Command[:bounds] == cmd { + implemented = true + } + } + if !implemented { + c.Err = commandNotImplementedErr + return false + } + } + for _, v := range commands { if v(c, command) || c.Err != nil { @@ -78,7 +111,7 @@ func checkCommand(c *Context, command *model.Command) bool { func logoutCommand(c *Context, command *model.Command) bool { - cmd := "/logout" + cmd := cmds["logoutCommand"] if strings.Index(command.Command, cmd) == 0 { command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Logout"}) @@ -97,7 +130,7 @@ func logoutCommand(c *Context, command *model.Command) bool { } func echoCommand(c *Context, command *model.Command) bool { - cmd := "/echo" + cmd := cmds["echoCommand"] maxThreads := 100 if !command.Suggest && strings.Index(command.Command, cmd) == 0 { @@ -162,10 +195,10 @@ func echoCommand(c *Context, command *model.Command) bool { } func shrugCommand(c *Context, command *model.Command) bool { - cmd := "/shrug" + cmd := cmds["shrugCommand"] if !command.Suggest && strings.Index(command.Command, cmd) == 0 { - message := "¯\\_(ツ)_/¯" + message := `¯\\\_(ツ)_/¯` parameters := strings.SplitN(command.Command, " ", 2) if len(parameters) > 1 { @@ -192,7 +225,7 @@ func shrugCommand(c *Context, command *model.Command) bool { func joinCommand(c *Context, command *model.Command) bool { // looks for "/join channel-name" - cmd := "/join" + cmd := cmds["joinCommand"] if strings.Index(command.Command, cmd) == 0 { @@ -242,7 +275,7 @@ func joinCommand(c *Context, command *model.Command) bool { } func loadTestCommand(c *Context, command *model.Command) bool { - cmd := "/loadtest" + cmd := cmds["loadTestCommand"] // This command is only available when EnableTesting is true if !utils.Cfg.ServiceSettings.EnableTesting { @@ -304,7 +337,7 @@ func contains(items []string, token string) bool { } func loadTestSetupCommand(c *Context, command *model.Command) bool { - cmd := "/loadtest setup" + cmd := cmds["loadTestCommand"] + " setup" if strings.Index(command.Command, cmd) == 0 && !command.Suggest { tokens := strings.Fields(strings.TrimPrefix(command.Command, cmd)) @@ -390,8 +423,8 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool { } func loadTestUsersCommand(c *Context, command *model.Command) bool { - cmd1 := "/loadtest users" - cmd2 := "/loadtest users fuzz" + cmd1 := cmds["loadTestCommand"] + " users" + cmd2 := cmds["loadTestCommand"] + " users fuzz" if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { cmd := cmd1 @@ -420,8 +453,8 @@ func loadTestUsersCommand(c *Context, command *model.Command) bool { } func loadTestChannelsCommand(c *Context, command *model.Command) bool { - cmd1 := "/loadtest channels" - cmd2 := "/loadtest channels fuzz" + cmd1 := cmds["loadTestCommand"] + " channels" + cmd2 := cmds["loadTestCommand"] + " channels fuzz" if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { cmd := cmd1 @@ -451,8 +484,8 @@ func loadTestChannelsCommand(c *Context, command *model.Command) bool { } func loadTestPostsCommand(c *Context, command *model.Command) bool { - cmd1 := "/loadtest posts" - cmd2 := "/loadtest posts fuzz" + cmd1 := cmds["loadTestCommand"] + " posts" + cmd2 := cmds["loadTestCommand"] + " posts fuzz" if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { cmd := cmd1 diff --git a/api/file.go b/api/file.go index 94eea516a..f65be145d 100644 --- a/api/file.go +++ b/api/file.go @@ -52,6 +52,8 @@ const ( RotatedCCW = 6 RotatedCCWMirrored = 7 RotatedCW = 8 + + MaxImageSize = 4096 * 2160 // 4k resolution ) var fileInfoCache *utils.Cache = utils.NewLru(1000) @@ -125,6 +127,21 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { uid := model.NewId() + if model.IsFileExtImage(filepath.Ext(files[i].Filename)) { + imageNameList = append(imageNameList, uid+"/"+filename) + imageDataList = append(imageDataList, buf.Bytes()) + + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(bytes.NewReader(buf.Bytes())) + if err != nil { + c.Err = model.NewAppError("uploadFile", "Unable to upload image file.", err.Error()) + return + } else if config.Width*config.Height > MaxImageSize { + c.Err = model.NewAppError("uploadFile", "Unable to upload image file. File is too large.", err.Error()) + return + } + } + path := "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + c.Session.UserId + "/" + uid + "/" + filename if err := writeFile(buf.Bytes(), path); err != nil { @@ -132,11 +149,6 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { return } - if model.IsFileExtImage(filepath.Ext(files[i].Filename)) { - imageNameList = append(imageNameList, uid+"/"+filename) - imageDataList = append(imageDataList, buf.Bytes()) - } - encName := utils.UrlEncode(filename) fileUrl := "/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + encName diff --git a/api/post.go b/api/post.go index 79f84e04d..b8588fe6a 100644 --- a/api/post.go +++ b/api/post.go @@ -820,45 +820,23 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) { return } - plainSearchParams, hashtagSearchParams := model.ParseSearchParams(terms) + paramsList := model.ParseSearchParams(terms) + channels := []store.StoreChannel{} - var hchan store.StoreChannel - if hashtagSearchParams != nil { - hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagSearchParams) + for _, params := range paramsList { + channels = append(channels, Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, params)) } - var pchan store.StoreChannel - if plainSearchParams != nil { - pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, plainSearchParams) - } - - mainList := &model.PostList{} - if hchan != nil { - if result := <-hchan; result.Err != nil { + posts := &model.PostList{} + for _, channel := range channels { + if result := <-channel; result.Err != nil { c.Err = result.Err return } else { - mainList = result.Data.(*model.PostList) + data := result.Data.(*model.PostList) + posts.Extend(data) } } - plainList := &model.PostList{} - if pchan != nil { - if result := <-pchan; result.Err != nil { - c.Err = result.Err - return - } else { - plainList = result.Data.(*model.PostList) - } - } - - for _, postId := range plainList.Order { - if _, ok := mainList.Posts[postId]; !ok { - mainList.AddPost(plainList.Posts[postId]) - mainList.AddOrder(postId) - } - - } - - w.Write([]byte(mainList.ToJson())) + w.Write([]byte(posts.ToJson())) } diff --git a/api/post_test.go b/api/post_test.go index ac9d5668b..e54e9ef0c 100644 --- a/api/post_test.go +++ b/api/post_test.go @@ -427,12 +427,18 @@ func TestSearchPostsInChannel(t *testing.T) { channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel) + channel3 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} + channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel) + post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"} post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post) post3 := &model.Post{ChannelId: channel2.Id, Message: "other message with no return"} post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post) + post4 := &model.Post{ChannelId: channel3.Id, Message: "other message with no return"} + post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post) + if result := Client.Must(Client.SearchPosts("channel:")).Data.(*model.PostList); len(result.Order) != 0 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } @@ -476,6 +482,10 @@ func TestSearchPostsInChannel(t *testing.T) { if result := Client.Must(Client.SearchPosts("sgtitlereview channel: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 1 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } + + if result := Client.Must(Client.SearchPosts("channel: " + channel2.Name + " channel: " + channel3.Name)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned :) %v :) %v", result.Posts, result.Order) + } } func TestSearchPostsFromUser(t *testing.T) { @@ -510,11 +520,12 @@ func TestSearchPostsFromUser(t *testing.T) { post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"} post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post) + // includes "X has joined the channel" messages for both user2 and user3 + if result := Client.Must(Client.SearchPosts("from: " + user1.Username)).Data.(*model.PostList); len(result.Order) != 1 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } - // note that this includes the "User2 has joined the channel" system messages if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } @@ -526,6 +537,33 @@ func TestSearchPostsFromUser(t *testing.T) { if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " in:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } + + user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user3.Id)) + + Client.LoginByEmail(team.Name, user3.Email, "pwd") + Client.Must(Client.JoinChannel(channel1.Id)) + Client.Must(Client.JoinChannel(channel2.Id)) + + // wait for the join/leave messages to be created for user3 since they're done asynchronously + time.Sleep(100 * time.Millisecond) + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username)).Data.(*model.PostList); len(result.Order) != 5 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name + " joined")).Data.(*model.PostList); len(result.Order) != 2 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } } func TestGetPostsCache(t *testing.T) { diff --git a/api/templates/password_change_body.html b/api/templates/password_change_body.html index 47a93fcb9..2e1df3ff2 100644 --- a/api/templates/password_change_body.html +++ b/api/templates/password_change_body.html @@ -18,7 +18,7 @@ <tr> <td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;"> <h2 style="font-weight: normal; margin-top: 10px;">You updated your password</h2> - <p>You updated your password for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} by {{.Props.Method}}.<br> If this change wasn't initiated by you, please reply to this email and let us know.</p> + <p>You updated your password for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} by {{.Props.Method}}.<br>If this change wasn't initiated by you, please contact your system administrator.</p> </td> </tr> <tr> diff --git a/api/user.go b/api/user.go index 3071e1b26..3796a50ee 100644 --- a/api/user.go +++ b/api/user.go @@ -814,6 +814,7 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "max-age=86400, public") // 24 hrs } + w.Header().Set("Content-Type", "image/png") w.Write(img) } } @@ -854,6 +855,18 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { return } + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(file) + if err != nil { + c.Err = model.NewAppError("uploadProfileFile", "Could not decode profile image config.", err.Error()) + return + } else if config.Width*config.Height > MaxImageSize { + c.Err = model.NewAppError("uploadProfileFile", "Unable to upload profile image. File is too large.", err.Error()) + return + } + + file.Seek(0, 0) + // Decode image into Image object img, _, err := image.Decode(file) if err != nil { |