Merge branch 'master' of github.com:mattermost/mattermost-server into top-dms-clean

Этот коммит содержится в:
Shivashis Padhi
2022-07-27 17:03:34 +05:30
родитель db192aff1b eba08cbb11
Коммит 849aea452c
79 изменённых файлов: 1724 добавлений и 381 удалений

Просмотреть файл

@@ -322,8 +322,8 @@ func SetupWithStoreMock(tb testing.TB) *TestHelper {
return th
}
func SetupEnterpriseWithStoreMock(tb testing.TB) *TestHelper {
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, nil)
func SetupEnterpriseWithStoreMock(tb testing.TB, options ...app.Option) *TestHelper {
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, options)
statusMock := mocks.StatusStore{}
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
@@ -381,7 +381,7 @@ func (th *TestHelper) TearDown() {
func closeBody(r *http.Response) {
if r.Body != nil {
_, _ = io.Copy(ioutil.Discard, r.Body)
_, _ = io.Copy(io.Discard, r.Body)
_ = r.Body.Close()
}
}

Просмотреть файл

@@ -5,7 +5,6 @@ package api4
import (
"io"
"io/ioutil"
"net/http"
"github.com/mattermost/mattermost-server/v6/audit"
@@ -33,7 +32,7 @@ func getBrandImage(c *Context, w http.ResponseWriter, r *http.Request) {
}
func uploadBrandImage(c *Context, w http.ResponseWriter, r *http.Request) {
defer io.Copy(ioutil.Discard, r.Body)
defer io.Copy(io.Discard, r.Body)
if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize {
c.Err = model.NewAppError("uploadBrandImage", "api.admin.upload_brand_image.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge)

Просмотреть файл

@@ -6,7 +6,6 @@ package api4
import (
"encoding/json"
"io"
"io/ioutil"
"net/http"
"github.com/mattermost/mattermost-server/v6/app"
@@ -32,7 +31,7 @@ func (api *API) InitEmoji() {
}
func createEmoji(c *Context, w http.ResponseWriter, r *http.Request) {
defer io.Copy(ioutil.Discard, r.Body)
defer io.Copy(io.Discard, r.Body)
if !*c.App.Config().ServiceSettings.EnableCustomEmoji {
c.Err = model.NewAppError("createEmoji", "api.emoji.disabled.app_error", nil, "", http.StatusNotImplemented)

Просмотреть файл

@@ -34,6 +34,8 @@ func (api *API) InitPost() {
api.BaseRoutes.Post.Handle("", api.APISessionRequired(updatePost)).Methods("PUT")
api.BaseRoutes.Post.Handle("/patch", api.APISessionRequired(patchPost)).Methods("PUT")
api.BaseRoutes.PostForUser.Handle("/set_unread", api.APISessionRequired(setPostUnread)).Methods("POST")
api.BaseRoutes.PostForUser.Handle("/reminder", api.APISessionRequired(setPostReminder)).Methods("POST")
api.BaseRoutes.Post.Handle("/pin", api.APISessionRequired(pinPost)).Methods("POST")
api.BaseRoutes.Post.Handle("/unpin", api.APISessionRequired(unpinPost)).Methods("POST")
}
@@ -401,7 +403,7 @@ func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
// Post is inaccessible due to cloud plan's limit.
if err.Id == "app.post.cloud.get.app_error" {
w.Header().Set(model.HeaderHasInaccessiblePosts, "true")
w.Header().Set(model.HeaderFirstInaccessiblePostTime, "1")
}
return
@@ -438,7 +440,7 @@ func getPostsByIds(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
postsList, hasInaccessiblePosts, err := c.App.GetPostsByIds(postIDs)
postsList, firstInaccessiblePostTime, err := c.App.GetPostsByIds(postIDs)
if err != nil {
c.Err = err
return
@@ -471,7 +473,7 @@ func getPostsByIds(c *Context, w http.ResponseWriter, r *http.Request) {
posts = append(posts, post)
}
w.Header().Set(model.HeaderHasInaccessiblePosts, strconv.FormatBool(hasInaccessiblePosts))
w.Header().Set(model.HeaderFirstInaccessiblePostTime, strconv.FormatInt(firstInaccessiblePostTime, 10))
if err := json.NewEncoder(w).Encode(posts); err != nil {
mlog.Warn("Error while writing response", mlog.Err(err))
@@ -842,6 +844,36 @@ func setPostUnread(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
func setPostReminder(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequirePostId().RequireUserId()
if c.Err != nil {
return
}
if c.AppContext.Session().UserId != c.Params.UserId && !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
c.SetPermissionError(model.PermissionEditOtherUsers)
return
}
if !c.App.SessionHasPermissionToChannelByPost(*c.AppContext.Session(), c.Params.PostId, model.PermissionReadChannel) {
c.SetPermissionError(model.PermissionReadChannel)
return
}
var reminder model.PostReminder
if jsonErr := json.NewDecoder(r.Body).Decode(&reminder); jsonErr != nil {
c.SetInvalidParam("target_time")
return
}
appErr := c.App.SetPostReminder(c.Params.PostId, c.Params.UserId, reminder.TargetTime)
if appErr != nil {
c.Err = appErr
return
}
ReturnStatusOK(w)
}
func saveIsPinnedPost(c *Context, w http.ResponseWriter, isPinned bool) {
c.RequirePostId()
if c.Err != nil {
@@ -898,7 +930,13 @@ func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
infos, err := c.App.GetFileInfosForPostWithMigration(c.Params.PostId)
includeDeleted, _ := strconv.ParseBool(r.URL.Query().Get("include_deleted"))
if includeDeleted && !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) {
c.SetPermissionError(model.PermissionManageSystem)
return
}
infos, err := c.App.GetFileInfosForPostWithMigration(c.Params.PostId, includeDeleted)
if err != nil {
c.Err = err
return

Просмотреть файл

@@ -2623,6 +2623,39 @@ func TestGetFileInfosForPost(t *testing.T) {
require.Error(t, err)
CheckForbiddenStatus(t, resp)
// Delete post
th.SystemAdminClient.DeletePost(post.Id)
// Normal client should get 404 when trying to access deleted post normally
_, resp, err = client.GetFileInfosForPost(post.Id, "")
require.Error(t, err)
CheckNotFoundStatus(t, resp)
// Normal client should get unauthorized when trying to access deleted post
_, resp, err = client.GetFileInfosForPostIncludeDeleted(post.Id, "")
require.Error(t, err)
CheckForbiddenStatus(t, resp)
// System client should get 404 when trying to access deleted post normally
_, resp, err = th.SystemAdminClient.GetFileInfosForPost(post.Id, "")
require.Error(t, err)
CheckNotFoundStatus(t, resp)
// System client should be able to access deleted post with include_deleted param
infos, _, err = th.SystemAdminClient.GetFileInfosForPostIncludeDeleted(post.Id, "")
require.NoError(t, err)
require.Len(t, infos, 3, "missing file infos")
found = false
for _, info := range infos {
if info.Id == fileIds[0] {
found = true
}
}
require.True(t, found, "missing file info")
client.Logout()
_, resp, err = client.GetFileInfosForPost(model.NewId(), "")
require.Error(t, err)
@@ -3131,3 +3164,63 @@ func TestGetPostStripActionIntegrations(t *testing.T) {
// integration must be omitted
require.Nil(t, action["integration"])
}
func TestPostReminder(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
client := th.Client
userWSClient, err := th.CreateWebSocketClient()
require.NoError(t, err)
defer userWSClient.Close()
userWSClient.Listen()
targetTime := time.Now().UTC().Unix()
resp, err := client.SetPostReminder(&model.PostReminder{
TargetTime: targetTime,
PostId: th.BasicPost.Id,
UserId: th.BasicUser.Id,
})
require.NoError(t, err)
CheckOKStatus(t, resp)
post, _, err := client.GetPost(th.BasicPost.Id, "")
require.NoError(t, err)
user, _, err := client.GetUser(post.UserId, "")
require.NoError(t, err)
var caught bool
func() {
for {
select {
case ev := <-userWSClient.EventChannel:
if ev.EventType() == model.WebsocketEventEphemeralMessage {
caught = true
data := ev.GetData()
post, ok := data["post"].(string)
require.True(t, ok)
var parsedPost model.Post
err := json.Unmarshal([]byte(post), &parsedPost)
require.NoError(t, err)
assert.Equal(t, model.PostTypeEphemeral, parsedPost.Type)
assert.Equal(t, th.BasicUser.Id, parsedPost.UserId)
assert.Equal(t, th.BasicPost.Id, parsedPost.RootId)
require.Equal(t, float64(targetTime), parsedPost.GetProp("target_time").(float64))
require.Equal(t, th.BasicPost.Id, parsedPost.GetProp("post_id").(string))
require.Equal(t, user.Username, parsedPost.GetProp("username").(string))
require.Equal(t, th.BasicTeam.Name, parsedPost.GetProp("team_name").(string))
return
}
case <-time.After(1 * time.Second):
return
}
}
}()
require.Truef(t, caught, "User should have received %s event", model.WebsocketEventEphemeralMessage)
}

Просмотреть файл

@@ -6,7 +6,6 @@ package api4
import (
"encoding/json"
"io"
"io/ioutil"
"net/http"
"time"
@@ -222,7 +221,7 @@ func uploadRemoteData(c *Context, w http.ResponseWriter, r *http.Request) {
}
func remoteSetProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
defer io.Copy(ioutil.Discard, r.Body)
defer io.Copy(io.Discard, r.Body)
c.RequireUserId()
if c.Err != nil {

Просмотреть файл

@@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"path"
"reflect"
@@ -527,7 +526,7 @@ func getRedirectLocation(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
io.Copy(ioutil.Discard, res.Body)
io.Copy(io.Discard, res.Body)
res.Body.Close()
}()

Просмотреть файл

@@ -9,7 +9,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"regexp"
"strconv"
@@ -1610,7 +1609,7 @@ func getTeamIcon(c *Context, w http.ResponseWriter, r *http.Request) {
}
func setTeamIcon(c *Context, w http.ResponseWriter, r *http.Request) {
defer io.Copy(ioutil.Discard, r.Body)
defer io.Copy(io.Discard, r.Body)
c.RequireTeamId()
if c.Err != nil {

Просмотреть файл

@@ -207,7 +207,7 @@ func TestUploadData(t *testing.T) {
CreateAt: model.GetMillis(),
UserId: th.BasicUser2.Id,
ChannelId: th.BasicChannel.Id,
Filename: "upload",
Filename: "upload.zip",
FileSize: 8 * 1024 * 1024,
}
us, err := th.App.CreateUploadSession(th.Context, us)
@@ -281,6 +281,9 @@ func TestUploadData(t *testing.T) {
require.NoError(t, err)
require.NotEmpty(t, info)
require.Equal(t, u.Filename, info.Name)
require.Equal(t, u.FileSize, info.Size)
require.Equal(t, "zip", info.Extension)
require.Equal(t, "application/zip", info.MimeType)
file, _, err := th.Client.GetFile(info.Id)
require.NoError(t, err)

Просмотреть файл

@@ -7,7 +7,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strconv"
"strings"
@@ -419,7 +418,7 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
}
func setProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
defer io.Copy(ioutil.Discard, r.Body)
defer io.Copy(io.Discard, r.Body)
c.RequireUserId()
if c.Err != nil {
@@ -1881,11 +1880,6 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
c.App.AttachSessionCookies(c.AppContext, w, r)
}
// For context see: https://mattermost.atlassian.net/browse/MM-39583
if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud {
c.App.AttachCloudSessionCookie(c.AppContext, w, r)
}
userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
if err != nil && err.StatusCode != http.StatusNotFound {
c.Err = err

Просмотреть файл

@@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"regexp"
"strings"
@@ -3610,14 +3611,61 @@ func TestLoginCookies(t *testing.T) {
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
th.Client.HTTPHeader[model.HeaderRequestedWith] = model.HeaderRequestedWithXML
_, resp, _ := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
val := strings.Split(resp.Header["Set-Cookie"][0], ";")
cloudSessionCookie := strings.Split(val[0], "=")[1]
domain := strings.Split(val[2], "=")[1]
found := false
cookies := resp.Header.Values("Set-Cookie")
for i := range cookies {
if strings.Contains(cookies[i], "MMCLOUDURL") {
found = true
assert.Contains(t, cookies[i], "MMCLOUDURL=testchips;", "should contain MMCLOUDURL")
assert.Contains(t, cookies[i], "Domain=mattermost.com;", "should contain Domain=mattermost.com")
break
}
}
assert.True(t, found, "Did not find MMCLOUDURL cookie")
})
assert.Equal(t, "testchips", cloudSessionCookie)
assert.Equal(t, "mattermost.com", domain)
t.Run("should return cookie with MMCLOUDURL for cloud installations when doing cws login", func(t *testing.T) {
token := model.NewRandomString(64)
os.Setenv("CWS_CLOUD_TOKEN", token)
updateConfig := func(cfg *model.Config) {
*cfg.ServiceSettings.SiteURL = "https://testchips.cloud.mattermost.com"
}
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic()
defer th.TearDown()
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
form := url.Values{}
form.Add("login_id", th.SystemAdminUser.Email)
form.Add("cws_token", token)
th.Client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
r, _ := th.Client.DoAPIRequestWithHeaders(
http.MethodPost,
th.Client.APIURL+"/users/login/cws",
form.Encode(),
map[string]string{
"Content-Type": "application/x-www-form-urlencoded",
},
)
defer closeBody(r)
cookies := r.Cookies()
found := false
for i := range cookies {
if cookies[i].Name == model.SessionCookieCloudUrl {
found = true
assert.Equal(t, "testchips", cookies[i].Value)
}
}
assert.True(t, found, "should have found cookie")
})
t.Run("should NOT return cookie with MMCLOUDURL for cloud installations without expected format of cloud URL", func(t *testing.T) {