PLT-7567: Integration of Team Icons (#8284)

* PLT-7567: Integration of Team Icons

* PLT-7567: Read replica workaround, upgrade logic moved, more concrete i18n key

* PLT-7567: Read replica workaround, corrections

* PLT-7567: upgrade correction
This commit is contained in:
Christian Hoff
2018-03-01 20:11:44 +01:00
committed by Joram Wilander
parent 51c7198d53
commit 2b3b6051d2
11 changed files with 421 additions and 13 deletions

View File

@@ -6,6 +6,7 @@ package api4
import (
"bytes"
"encoding/base64"
"fmt"
"net/http"
"strconv"
@@ -28,6 +29,10 @@ func (api *API) InitTeam() {
api.BaseRoutes.Team.Handle("", api.ApiSessionRequired(deleteTeam)).Methods("DELETE")
api.BaseRoutes.Team.Handle("/patch", api.ApiSessionRequired(patchTeam)).Methods("PUT")
api.BaseRoutes.Team.Handle("/stats", api.ApiSessionRequired(getTeamStats)).Methods("GET")
api.BaseRoutes.Team.Handle("/image", api.ApiSessionRequiredTrustRequester(getTeamIcon)).Methods("GET")
api.BaseRoutes.Team.Handle("/image", api.ApiSessionRequired(setTeamIcon)).Methods("POST")
api.BaseRoutes.TeamMembers.Handle("", api.ApiSessionRequired(getTeamMembers)).Methods("GET")
api.BaseRoutes.TeamMembers.Handle("/ids", api.ApiSessionRequired(getTeamMembersByIds)).Methods("POST")
api.BaseRoutes.TeamMembersForUser.Handle("", api.ApiSessionRequired(getTeamMembersForUser)).Methods("GET")
@@ -729,3 +734,81 @@ func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(result)))
}
}
func getTeamIcon(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireTeamId()
if c.Err != nil {
return
}
if !c.App.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
return
}
if team, err := c.App.GetTeam(c.Params.TeamId); err != nil {
c.Err = err
return
} else {
etag := strconv.FormatInt(team.LastTeamIconUpdate, 10)
if c.HandleEtag(etag, "Get Team Icon", w, r) {
return
}
if img, err := c.App.GetTeamIcon(team); err != nil {
c.Err = err
return
} else {
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%v, public", 24*60*60)) // 24 hrs
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
w.Write(img)
}
}
}
func setTeamIcon(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireTeamId()
if c.Err != nil {
return
}
if !c.App.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_MANAGE_TEAM) {
c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
return
}
if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize {
c.Err = model.NewAppError("setTeamIcon", "api.team.set_team_icon.too_large.app_error", nil, "", http.StatusBadRequest)
return
}
if err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize); err != nil {
c.Err = model.NewAppError("setTeamIcon", "api.team.set_team_icon.parse.app_error", nil, err.Error(), http.StatusBadRequest)
return
}
m := r.MultipartForm
imageArray, ok := m.File["image"]
if !ok {
c.Err = model.NewAppError("setTeamIcon", "api.team.set_team_icon.no_file.app_error", nil, "", http.StatusBadRequest)
return
}
if len(imageArray) <= 0 {
c.Err = model.NewAppError("setTeamIcon", "api.team.set_team_icon.array.app_error", nil, "", http.StatusBadRequest)
return
}
imageData := imageArray[0]
if err := c.App.SetTeamIcon(c.Params.TeamId, imageData); err != nil {
c.Err = err
return
}
c.LogAudit("")
ReturnStatusOK(w)
}

View File

@@ -15,6 +15,8 @@ import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCreateTeam(t *testing.T) {
@@ -1915,3 +1917,82 @@ func TestGetTeamInviteInfo(t *testing.T) {
_, resp = Client.GetTeamInviteInfo("junk")
CheckNotFoundStatus(t, resp)
}
func TestSetTeamIcon(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin()
defer th.TearDown()
Client := th.Client
team := th.BasicTeam
data, err := readTestFile("test.png")
if err != nil {
t.Fatal(err)
}
th.LoginTeamAdmin()
ok, resp := Client.SetTeamIcon(team.Id, data)
if !ok {
t.Fatal(resp.Error)
}
CheckNoError(t, resp)
ok, resp = Client.SetTeamIcon(model.NewId(), data)
if ok {
t.Fatal("Should return false, set team icon not allowed")
}
CheckForbiddenStatus(t, resp)
th.LoginBasic()
_, resp = Client.SetTeamIcon(team.Id, data)
if resp.StatusCode == http.StatusForbidden {
CheckForbiddenStatus(t, resp)
} else if resp.StatusCode == http.StatusUnauthorized {
CheckUnauthorizedStatus(t, resp)
} else {
t.Fatal("Should have failed either forbidden or unauthorized")
}
Client.Logout()
_, resp = Client.SetTeamIcon(team.Id, data)
if resp.StatusCode == http.StatusForbidden {
CheckForbiddenStatus(t, resp)
} else if resp.StatusCode == http.StatusUnauthorized {
CheckUnauthorizedStatus(t, resp)
} else {
t.Fatal("Should have failed either forbidden or unauthorized")
}
teamBefore, err := th.App.GetTeam(team.Id)
require.Nil(t, err)
_, resp = th.SystemAdminClient.SetTeamIcon(team.Id, data)
CheckNoError(t, resp)
teamAfter, err := th.App.GetTeam(team.Id)
require.Nil(t, err)
assert.True(t, teamBefore.LastTeamIconUpdate < teamAfter.LastTeamIconUpdate, "LastTeamIconUpdate should have been updated for team")
info := &model.FileInfo{Path: "teams/" + team.Id + "/teamIcon.png"}
if err := th.cleanupTestFile(info); err != nil {
t.Fatal(err)
}
}
func TestGetTeamIcon(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin()
defer th.TearDown()
Client := th.Client
team := th.BasicTeam
// should always fail because no initial image and no auto creation
_, resp := Client.GetTeamIcon(team.Id, "")
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.GetTeamIcon(team.Id, "")
CheckUnauthorizedStatus(t, resp)
}