From f758f9ff3a617dd5939e1e7851fdbe10d03cd5a8 Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Thu, 20 Apr 2017 17:14:15 +0200 Subject: [APIV4] GET /emoji/{emoji_id}/image for apiV4 (#6141) * implement GET /emoji/{emoji_id}/image for apiV4 * update per request --- api/emoji.go | 28 +++--------- api4/emoji.go | 28 ++++++++++++ api4/emoji_test.go | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++- app/emoji.go | 23 +++++++++- model/client4.go | 11 +++++ 5 files changed, 189 insertions(+), 23 deletions(-) diff --git a/api/emoji.go b/api/emoji.go index feb65877a..1a79cc536 100644 --- a/api/emoji.go +++ b/api/emoji.go @@ -4,7 +4,6 @@ package api import ( - "bytes" "image" "image/draw" "image/gif" @@ -190,28 +189,15 @@ func getEmojiImage(c *Context, w http.ResponseWriter, r *http.Request) { return } - if result := <-app.Srv.Store.Emoji().Get(id, true); result.Err != nil { - c.Err = result.Err + image, imageType, err := app.GetEmojiImage(id) + if err != nil { + c.Err = err return - } else { - var img []byte - - if data, err := app.ReadFile(getEmojiImagePath(id)); err != nil { - c.Err = model.NewLocAppError("getEmojiImage", "api.emoji.get_image.read.app_error", nil, err.Error()) - return - } else { - img = data - } - - if _, imageType, err := image.DecodeConfig(bytes.NewReader(img)); err != nil { - model.NewLocAppError("getEmojiImage", "api.emoji.get_image.decode.app_error", nil, err.Error()) - } else { - w.Header().Set("Content-Type", "image/"+imageType) - } - - w.Header().Set("Cache-Control", "max-age=2592000, public") - w.Write(img) } + + w.Header().Set("Content-Type", "image/"+imageType) + w.Header().Set("Cache-Control", "max-age=2592000, public") + w.Write(image) } func getEmojiImagePath(id string) string { diff --git a/api4/emoji.go b/api4/emoji.go index ff4919860..a9bfae924 100644 --- a/api4/emoji.go +++ b/api4/emoji.go @@ -22,6 +22,7 @@ func InitEmoji() { BaseRoutes.Emojis.Handle("", ApiSessionRequired(getEmojiList)).Methods("GET") BaseRoutes.Emoji.Handle("", ApiSessionRequired(deleteEmoji)).Methods("DELETE") BaseRoutes.Emoji.Handle("", ApiSessionRequired(getEmoji)).Methods("GET") + BaseRoutes.Emoji.Handle("/image", ApiSessionRequiredTrustRequester(getEmojiImage)).Methods("GET") } func createEmoji(c *Context, w http.ResponseWriter, r *http.Request) { @@ -129,3 +130,30 @@ func getEmoji(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(emoji.ToJson())) } } + +func getEmojiImage(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireEmojiId() + if c.Err != nil { + return + } + + if !*utils.Cfg.ServiceSettings.EnableCustomEmoji { + c.Err = model.NewAppError("getEmojiImage", "api.emoji.disabled.app_error", nil, "", http.StatusNotImplemented) + return + } + + if len(utils.Cfg.FileSettings.DriverName) == 0 { + c.Err = model.NewAppError("getEmojiImage", "api.emoji.storage.app_error", nil, "", http.StatusNotImplemented) + return + } + + image, imageType, err := app.GetEmojiImage(c.Params.EmojiId) + if err != nil { + c.Err = err + return + } + + w.Header().Set("Content-Type", "image/"+imageType) + w.Header().Set("Cache-Control", "max-age=2592000, public") + w.Write(image) +} diff --git a/api4/emoji_test.go b/api4/emoji_test.go index 23188a3d2..84d808e6d 100644 --- a/api4/emoji_test.go +++ b/api4/emoji_test.go @@ -4,6 +4,9 @@ package api4 import ( + "bytes" + "image" + _ "image/gif" "testing" "github.com/mattermost/platform/model" @@ -199,7 +202,6 @@ func TestGetEmojiList(t *testing.T) { t.Fatalf("should not get a deleted emoji %v", emojis[0].Id) } } - } func TestDeleteEmoji(t *testing.T) { @@ -296,5 +298,123 @@ func TestGetEmoji(t *testing.T) { _, resp = Client.GetEmoji(model.NewId()) CheckInternalErrorStatus(t, resp) +} + +func TestGetEmojiImage(t *testing.T) { + th := Setup().InitBasic() + defer TearDown() + Client := th.Client + + EnableCustomEmoji := *utils.Cfg.ServiceSettings.EnableCustomEmoji + DriverName := utils.Cfg.FileSettings.DriverName + defer func() { + *utils.Cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji + utils.Cfg.FileSettings.DriverName = DriverName + }() + *utils.Cfg.ServiceSettings.EnableCustomEmoji = true + + emoji1 := &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + emoji1, resp := Client.CreateEmoji(emoji1, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) + + *utils.Cfg.ServiceSettings.EnableCustomEmoji = false + + _, resp = Client.GetEmojiImage(emoji1.Id) + CheckNotImplementedStatus(t, resp) + CheckErrorMessage(t, resp, "api.emoji.disabled.app_error") + + utils.Cfg.FileSettings.DriverName = "" + *utils.Cfg.ServiceSettings.EnableCustomEmoji = true + + _, resp = Client.GetEmojiImage(emoji1.Id) + CheckNotImplementedStatus(t, resp) + CheckErrorMessage(t, resp, "api.emoji.storage.app_error") + utils.Cfg.FileSettings.DriverName = DriverName + + emojiImage, resp := Client.GetEmojiImage(emoji1.Id) + CheckNoError(t, resp) + if len(emojiImage) <= 0 { + t.Fatal("should return the image") + } + _, imageType, err := image.DecodeConfig(bytes.NewReader(emojiImage)) + if err != nil { + t.Fatalf("unable to identify received image: %v", err.Error()) + } else if imageType != "gif" { + t.Fatal("should've received gif data") + } + + emoji2 := &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + emoji2, resp = Client.CreateEmoji(emoji2, utils.CreateTestAnimatedGif(t, 10, 10, 10), "image.gif") + CheckNoError(t, resp) + + emojiImage, resp = Client.GetEmojiImage(emoji2.Id) + CheckNoError(t, resp) + if len(emojiImage) <= 0 { + t.Fatal("should return the image") + } + _, imageType, err = image.DecodeConfig(bytes.NewReader(emojiImage)) + if err != nil { + t.Fatalf("unable to identify received image: %v", err.Error()) + } else if imageType != "gif" { + t.Fatal("should've received gif data") + } + + emoji3 := &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + emoji3, resp = Client.CreateEmoji(emoji3, utils.CreateTestJpeg(t, 10, 10), "image.jpg") + CheckNoError(t, resp) + + emojiImage, resp = Client.GetEmojiImage(emoji3.Id) + CheckNoError(t, resp) + if len(emojiImage) <= 0 { + t.Fatal("should return the image") + } + _, imageType, err = image.DecodeConfig(bytes.NewReader(emojiImage)) + if err != nil { + t.Fatalf("unable to identify received image: %v", err.Error()) + } else if imageType != "jpeg" { + t.Fatal("should've received gif data") + } + + emoji4 := &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + emoji4, resp = Client.CreateEmoji(emoji4, utils.CreateTestPng(t, 10, 10), "image.png") + CheckNoError(t, resp) + + emojiImage, resp = Client.GetEmojiImage(emoji4.Id) + CheckNoError(t, resp) + if len(emojiImage) <= 0 { + t.Fatal("should return the image") + } + _, imageType, err = image.DecodeConfig(bytes.NewReader(emojiImage)) + if err != nil { + t.Fatalf("unable to identify received image: %v", err.Error()) + } else if imageType != "png" { + t.Fatal("should've received gif data") + } + + _, resp = Client.DeleteEmoji(emoji4.Id) + CheckNoError(t, resp) + + _, resp = Client.GetEmojiImage(emoji4.Id) + CheckNotFoundStatus(t, resp) + + _, resp = Client.GetEmojiImage(model.NewId()) + CheckInternalErrorStatus(t, resp) + + _, resp = Client.GetEmojiImage("") + CheckBadRequestStatus(t, resp) } diff --git a/app/emoji.go b/app/emoji.go index b0c8418aa..3e3350285 100644 --- a/app/emoji.go +++ b/app/emoji.go @@ -6,7 +6,6 @@ package app import ( "bytes" "image" - "image/color/palette" "image/draw" "image/gif" _ "image/jpeg" @@ -20,6 +19,7 @@ import ( "github.com/disintegration/imaging" "github.com/mattermost/platform/model" "github.com/mattermost/platform/utils" + "image/color/palette" ) const ( @@ -148,6 +148,27 @@ func GetEmoji(emojiId string) (*model.Emoji, *model.AppError) { } } +func GetEmojiImage(emojiId string) (imageByte []byte, imageType string, err *model.AppError) { + if result := <-Srv.Store.Emoji().Get(emojiId, true); result.Err != nil { + return nil, "", result.Err + } else { + var img []byte + + if data, err := ReadFile(getEmojiImagePath(emojiId)); err != nil { + return nil, "", model.NewAppError("getEmojiImage", "api.emoji.get_image.read.app_error", nil, err.Error(), http.StatusNotFound) + } else { + img = data + } + + _, imageType, err := image.DecodeConfig(bytes.NewReader(img)) + if err != nil { + return nil, "", model.NewAppError("getEmojiImage", "api.emoji.get_image.decode.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + return img, imageType, nil + } +} + func resizeEmojiGif(gifImg *gif.GIF) *gif.GIF { // Create a new RGBA image to hold the incremental frames. firstFrame := gifImg.Image[0].Bounds() diff --git a/model/client4.go b/model/client4.go index 4aa276026..04615f9e4 100644 --- a/model/client4.go +++ b/model/client4.go @@ -2489,6 +2489,17 @@ func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) { } } +// GetEmojiImage returns the emoji image. +func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) { + if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", ""); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else if data, err := ioutil.ReadAll(r.Body); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)} + } else { + return data, BuildResponse(r) + } +} + // Reaction Section // SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned. -- cgit v1.2.3-1-g7c22