summaryrefslogtreecommitdiffstats
path: root/api4
diff options
context:
space:
mode:
Diffstat (limited to 'api4')
-rw-r--r--api4/apitestlib.go27
-rw-r--r--api4/channel_test.go7
-rw-r--r--api4/system.go41
-rw-r--r--api4/system_test.go64
-rw-r--r--api4/team.go83
-rw-r--r--api4/team_test.go81
-rw-r--r--api4/webhook.go1
7 files changed, 263 insertions, 41 deletions
diff --git a/api4/apitestlib.go b/api4/apitestlib.go
index e55ca8c8b..2bb80ddfb 100644
--- a/api4/apitestlib.go
+++ b/api4/apitestlib.go
@@ -510,18 +510,6 @@ func CheckUserSanitization(t *testing.T, user *model.User) {
}
}
-func CheckTeamSanitization(t *testing.T, team *model.Team) {
- t.Helper()
-
- if team.Email != "" {
- t.Fatal("email wasn't blank")
- }
-
- if team.AllowedDomains != "" {
- t.Fatal("'allowed domains' wasn't blank")
- }
-}
-
func CheckEtag(t *testing.T, data interface{}, resp *model.Response) {
t.Helper()
@@ -669,21 +657,6 @@ func CheckInternalErrorStatus(t *testing.T, resp *model.Response) {
}
}
-func CheckPayLoadTooLargeStatus(t *testing.T, resp *model.Response) {
- t.Helper()
-
- if resp.Error == nil {
- t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusRequestEntityTooLarge))
- return
- }
-
- if resp.StatusCode != http.StatusRequestEntityTooLarge {
- t.Log("actual: " + strconv.Itoa(resp.StatusCode))
- t.Log("expected: " + strconv.Itoa(http.StatusRequestEntityTooLarge))
- t.Fatal("wrong status code")
- }
-}
-
func readTestFile(name string) ([]byte, error) {
path, _ := utils.FindDir("tests")
file, err := os.Open(path + "/" + name)
diff --git a/api4/channel_test.go b/api4/channel_test.go
index e65918707..51c32cf71 100644
--- a/api4/channel_test.go
+++ b/api4/channel_test.go
@@ -13,7 +13,6 @@ import (
"testing"
"github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store/sqlstore"
)
func TestCreateChannel(t *testing.T) {
@@ -909,7 +908,7 @@ func TestDeleteChannel(t *testing.T) {
// successful delete by channel admin
th.MakeUserChannelAdmin(user, publicChannel6)
th.MakeUserChannelAdmin(user, privateChannel7)
- sqlstore.ClearChannelCaches()
+ th.App.Srv.Store.Channel().ClearCaches()
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckNoError(t, resp)
@@ -960,7 +959,7 @@ func TestDeleteChannel(t *testing.T) {
// // cannot delete by channel admin
th.MakeUserChannelAdmin(user, publicChannel6)
th.MakeUserChannelAdmin(user, privateChannel7)
- sqlstore.ClearChannelCaches()
+ th.App.Srv.Store.Channel().ClearCaches()
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckForbiddenStatus(t, resp)
@@ -1001,7 +1000,7 @@ func TestDeleteChannel(t *testing.T) {
// cannot delete by channel admin
th.MakeUserChannelAdmin(user, publicChannel6)
th.MakeUserChannelAdmin(user, privateChannel7)
- sqlstore.ClearChannelCaches()
+ th.App.Srv.Store.Channel().ClearCaches()
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckForbiddenStatus(t, resp)
diff --git a/api4/system.go b/api4/system.go
index 2355cb476..c1541f0b5 100644
--- a/api4/system.go
+++ b/api4/system.go
@@ -8,7 +8,6 @@ import (
"io"
"net/http"
"runtime"
- "strconv"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/mattermost-server/model"
@@ -29,6 +28,7 @@ func (api *API) InitSystem() {
api.BaseRoutes.ApiRoot.Handle("/audits", api.ApiSessionRequired(getAudits)).Methods("GET")
api.BaseRoutes.ApiRoot.Handle("/email/test", api.ApiSessionRequired(testEmail)).Methods("POST")
+ api.BaseRoutes.ApiRoot.Handle("/file/s3_test", api.ApiSessionRequired(testS3)).Methods("POST")
api.BaseRoutes.ApiRoot.Handle("/database/recycle", api.ApiSessionRequired(databaseRecycle)).Methods("POST")
api.BaseRoutes.ApiRoot.Handle("/caches/invalidate", api.ApiSessionRequired(invalidateCaches)).Methods("POST")
@@ -246,14 +246,7 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- respCfg := map[string]string{}
- for k, v := range c.App.ClientConfig() {
- respCfg[k] = v
- }
-
- respCfg["NoAccounts"] = strconv.FormatBool(c.App.IsFirstUserAccount())
-
- w.Write([]byte(model.MapToJson(respCfg)))
+ w.Write([]byte(model.MapToJson(c.App.ClientConfigWithNoAccounts())))
}
func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -384,3 +377,33 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(rows.ToJson()))
}
+
+func testS3(c *Context, w http.ResponseWriter, r *http.Request) {
+ cfg := model.ConfigFromJson(r.Body)
+ if cfg == nil {
+ cfg = c.App.Config()
+ }
+
+ if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
+ c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
+ return
+ }
+
+ err := utils.CheckMandatoryS3Fields(&cfg.FileSettings)
+ if err != nil {
+ c.Err = err
+ return
+ }
+
+ license := c.App.License()
+ backend, appErr := utils.NewFileBackend(&cfg.FileSettings, license != nil && *license.Features.Compliance)
+ if appErr == nil {
+ appErr = backend.TestConnection()
+ }
+ if appErr != nil {
+ c.Err = appErr
+ return
+ }
+
+ ReturnStatusOK(w)
+}
diff --git a/api4/system_test.go b/api4/system_test.go
index 01b4934ae..e39486b77 100644
--- a/api4/system_test.go
+++ b/api4/system_test.go
@@ -1,7 +1,9 @@
package api4
import (
+ "fmt"
"net/http"
+ "os"
"strings"
"testing"
@@ -466,3 +468,65 @@ func TestGetAnalyticsOld(t *testing.T) {
_, resp = Client.GetAnalyticsOld("", th.BasicTeam.Id)
CheckUnauthorizedStatus(t, resp)
}
+
+func TestS3TestConnection(t *testing.T) {
+ th := Setup().InitBasic().InitSystemAdmin()
+ defer th.TearDown()
+ Client := th.Client
+
+ s3Host := os.Getenv("CI_HOST")
+ if s3Host == "" {
+ s3Host = "dockerhost"
+ }
+
+ s3Port := os.Getenv("CI_MINIO_PORT")
+ if s3Port == "" {
+ s3Port = "9001"
+ }
+
+ s3Endpoint := fmt.Sprintf("%s:%s", s3Host, s3Port)
+ config := model.Config{
+ FileSettings: model.FileSettings{
+ DriverName: model.NewString(model.IMAGE_DRIVER_S3),
+ AmazonS3AccessKeyId: model.MINIO_ACCESS_KEY,
+ AmazonS3SecretAccessKey: model.MINIO_SECRET_KEY,
+ AmazonS3Bucket: "",
+ AmazonS3Endpoint: "",
+ AmazonS3SSL: model.NewBool(false),
+ },
+ }
+
+ _, resp := Client.TestS3Connection(&config)
+ CheckForbiddenStatus(t, resp)
+
+ _, resp = th.SystemAdminClient.TestS3Connection(&config)
+ CheckBadRequestStatus(t, resp)
+ if resp.Error.Message != "S3 Bucket is required" {
+ t.Fatal("should return error - missing s3 bucket")
+ }
+
+ config.FileSettings.AmazonS3Bucket = model.MINIO_BUCKET
+ _, resp = th.SystemAdminClient.TestS3Connection(&config)
+ CheckBadRequestStatus(t, resp)
+ if resp.Error.Message != "S3 Endpoint is required" {
+ t.Fatal("should return error - missing s3 endpoint")
+ }
+
+ config.FileSettings.AmazonS3Endpoint = s3Endpoint
+ _, resp = th.SystemAdminClient.TestS3Connection(&config)
+ CheckBadRequestStatus(t, resp)
+ if resp.Error.Message != "S3 Region is required" {
+ t.Fatal("should return error - missing s3 region")
+ }
+
+ config.FileSettings.AmazonS3Region = "us-east-1"
+ _, resp = th.SystemAdminClient.TestS3Connection(&config)
+ CheckOKStatus(t, resp)
+
+ config.FileSettings.AmazonS3Bucket = "Wrong_bucket"
+ _, resp = th.SystemAdminClient.TestS3Connection(&config)
+ CheckInternalErrorStatus(t, resp)
+ if resp.Error.Message != "Error checking if bucket exists." {
+ t.Fatal("should return error ")
+ }
+}
diff --git a/api4/team.go b/api4/team.go
index d770aee22..8e4c5c312 100644
--- a/api4/team.go
+++ b/api4/team.go
@@ -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)
+}
diff --git a/api4/team_test.go b/api4/team_test.go
index faa90e511..04a0e9ae4 100644
--- a/api4/team_test.go
+++ b/api4/team_test.go
@@ -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)
+}
diff --git a/api4/webhook.go b/api4/webhook.go
index e19f14704..853cf43f3 100644
--- a/api4/webhook.go
+++ b/api4/webhook.go
@@ -510,7 +510,6 @@ func commandWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
}
func decodePayload(payload io.Reader) (*model.IncomingWebhookRequest, *model.AppError) {
- decodeError := &model.AppError{}
incomingWebhookPayload, decodeError := model.IncomingWebhookRequestFromJson(payload)
if decodeError != nil {