diff --git a/app/plugin_api.go b/app/plugin_api.go index 68098287f4..6d6de42f84 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -453,6 +453,19 @@ func (api *PluginAPI) GetEmojiImage(emojiId string) ([]byte, string, *model.AppE return api.app.GetEmojiImage(emojiId) } +func (api *PluginAPI) GetTeamIcon(teamId string) ([]byte, *model.AppError) { + team, err := api.app.GetTeam(teamId) + if err != nil { + return nil, err + } + + data, err := api.app.GetTeamIcon(team) + if err != nil { + return nil, err + } + return data, nil +} + // Plugin Section func (api *PluginAPI) GetPlugins() ([]*model.Manifest, *model.AppError) { diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index 206ba5d1cc..e195718bf8 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -311,3 +311,34 @@ func TestPluginAPIGetPlugins(t *testing.T) { assert.NotEmpty(t, plugins) assert.Equal(t, pluginManifests, plugins) } + +func TestPluginAPIGetTeamIcon(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + api := th.SetupPluginAPI() + + // Create an 128 x 128 image + img := image.NewRGBA(image.Rect(0, 0, 128, 128)) + // Draw a red dot at (2, 3) + img.Set(2, 3, color.RGBA{255, 0, 0, 255}) + buf := new(bytes.Buffer) + err := png.Encode(buf, img) + require.Nil(t, err) + dataBytes := buf.Bytes() + fileReader := bytes.NewReader(dataBytes) + + // Set the Team Icon + err = th.App.SetTeamIconFromFile(th.BasicTeam, fileReader) + require.Nil(t, err) + + // Get the team icon to check + imageProfile, err := api.GetTeamIcon(th.BasicTeam.Id) + require.Nil(t, err) + require.NotEmpty(t, imageProfile) + + colorful := color.NRGBA{255, 0, 0, 255} + byteReader := bytes.NewReader(imageProfile) + img2, _, err2 := image.Decode(byteReader) + require.Nil(t, err2) + require.Equal(t, img2.At(2, 3), colorful) +} diff --git a/app/team.go b/app/team.go index 6180611048..0152cbb6af 100644 --- a/app/team.go +++ b/app/team.go @@ -8,6 +8,7 @@ import ( "fmt" "image" "image/png" + "io" "mime/multipart" "net/http" "net/url" @@ -1093,10 +1094,10 @@ func (a *App) SetTeamIcon(teamId string, imageData *multipart.FileHeader) *model return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.open.app_error", nil, err.Error(), http.StatusBadRequest) } defer file.Close() - return a.SetTeamIconFromFile(teamId, file) + return a.SetTeamIconFromMultiPartFile(teamId, file) } -func (a *App) SetTeamIconFromFile(teamId string, file multipart.File) *model.AppError { +func (a *App) SetTeamIconFromMultiPartFile(teamId string, file multipart.File) *model.AppError { team, getTeamErr := a.GetTeam(teamId) if getTeamErr != nil { @@ -1118,14 +1119,16 @@ func (a *App) SetTeamIconFromFile(teamId string, file multipart.File) *model.App file.Seek(0, 0) + return a.SetTeamIconFromFile(team, file) +} + +func (a *App) SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppError { // Decode image into Image object img, _, err := image.Decode(file) if err != nil { return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode.app_error", nil, err.Error(), http.StatusBadRequest) } - file.Seek(0, 0) - orientation, _ := getImageOrientation(file) img = makeImageUpright(img, orientation) @@ -1139,7 +1142,7 @@ func (a *App) SetTeamIconFromFile(teamId string, file multipart.File) *model.App return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.encode.app_error", nil, err.Error(), http.StatusInternalServerError) } - path := "teams/" + teamId + "/teamIcon.png" + path := "teams/" + team.Id + "/teamIcon.png" if _, err := a.WriteFile(buf, path); err != nil { return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.write_file.app_error", nil, "", http.StatusInternalServerError) @@ -1147,7 +1150,7 @@ func (a *App) SetTeamIconFromFile(teamId string, file multipart.File) *model.App curTime := model.GetMillis() - if result := <-a.Srv.Store.Team().UpdateLastTeamIconUpdate(teamId, curTime); result.Err != nil { + if result := <-a.Srv.Store.Team().UpdateLastTeamIconUpdate(team.Id, curTime); result.Err != nil { return model.NewAppError("SetTeamIcon", "api.team.team_icon.update.app_error", nil, result.Err.Error(), http.StatusBadRequest) } diff --git a/plugin/api.go b/plugin/api.go index 9f93a31b30..0aa8c6771a 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -64,6 +64,11 @@ type API interface { // Minimum server version: 5.6 GetUsersInTeam(teamId string, page int, perPage int) ([]*model.User, *model.AppError) + // GetTeamIcon gets the Team Icon. + // + // Minimum server version: 5.6 + GetTeamIcon(teamId string) ([]byte, *model.AppError) + // UpdateUser updates a user. UpdateUser(user *model.User) (*model.User, *model.AppError) diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index 3f53f87c85..46b0c159fc 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -887,6 +887,35 @@ func (s *apiRPCServer) GetUsersInTeam(args *Z_GetUsersInTeamArgs, returns *Z_Get return nil } +type Z_GetTeamIconArgs struct { + A string +} + +type Z_GetTeamIconReturns struct { + A []byte + B *model.AppError +} + +func (g *apiRPCClient) GetTeamIcon(teamId string) ([]byte, *model.AppError) { + _args := &Z_GetTeamIconArgs{teamId} + _returns := &Z_GetTeamIconReturns{} + if err := g.client.Call("Plugin.GetTeamIcon", _args, _returns); err != nil { + log.Printf("RPC call to GetTeamIcon API failed: %s", err.Error()) + } + return _returns.A, _returns.B +} + +func (s *apiRPCServer) GetTeamIcon(args *Z_GetTeamIconArgs, returns *Z_GetTeamIconReturns) error { + if hook, ok := s.impl.(interface { + GetTeamIcon(teamId string) ([]byte, *model.AppError) + }); ok { + returns.A, returns.B = hook.GetTeamIcon(args.A) + } else { + return encodableError(fmt.Errorf("API GetTeamIcon called but not implemented.")) + } + return nil +} + type Z_UpdateUserArgs struct { A *model.User } diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index bf9cf4951f..2100da958c 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -1175,6 +1175,31 @@ func (_m *API) GetTeamByName(name string) (*model.Team, *model.AppError) { return r0, r1 } +// GetTeamIcon provides a mock function with given fields: teamId +func (_m *API) GetTeamIcon(teamId string) ([]byte, *model.AppError) { + ret := _m.Called(teamId) + + var r0 []byte + if rf, ok := ret.Get(0).(func(string) []byte); ok { + r0 = rf(teamId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { + r1 = rf(teamId) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // GetTeamMember provides a mock function with given fields: teamId, userId func (_m *API) GetTeamMember(teamId string, userId string) (*model.TeamMember, *model.AppError) { ret := _m.Called(teamId, userId)