Manual Cherrypick: Add audits for accessing posts without membership (#31266) (#35022)

Automatic Merge
Этот коммит содержится в:
Daniel Espino García
2026-01-26 11:23:28 +01:00
коммит произвёл GitHub
родитель 12dce033d6
Коммит 21a86506f9
79 изменённых файлов: 1707 добавлений и 1001 удалений

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

@@ -91,42 +91,52 @@ func (a *App) SessionHasPermissionToTeams(c request.CTX, session model.Session,
return true
}
func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session, channelID string, permission *model.Permission) bool {
// SessionHasPermissionToChannel checks if the session has permission to the given channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has the specified permission for the channel, otherwise false.
// isMember: used for auditing access without membership. True if the user is a member of the channel, otherwise false.
func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session, channelID string, permission *model.Permission) (hasPermission bool, isMember bool) {
if channelID == "" {
return false
return false, false
}
channel, appErr := a.GetChannel(c, channelID)
if appErr != nil && appErr.StatusCode == http.StatusNotFound {
return false
return false, false
} else if appErr != nil {
c.Logger().Warn("Failed to get channel", mlog.String("channel_id", channelID), mlog.Err(appErr))
}
if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) {
return true
if session.IsUnrestricted() {
return true, false
}
if appErr == nil && a.isChannelArchivedAndHidden(channel) {
return false
return false, false
}
isMember = false
ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true)
var channelRoles []string
if err == nil {
if roles, ok := ids[channelID]; ok {
isMember = true
channelRoles = strings.Fields(roles)
if a.RolesGrantPermission(channelRoles, permission.Id) {
return true
return true, isMember
}
}
}
if appErr == nil && channel.TeamId != "" {
return a.SessionHasPermissionToTeam(session, channel.TeamId, permission)
return a.SessionHasPermissionToTeam(session, channel.TeamId, permission), isMember
}
return a.SessionHasPermissionTo(session, permission)
return a.SessionHasPermissionTo(session, permission), isMember
}
// SessionHasPermissionToChannels returns true only if user has access to all channels.
@@ -221,6 +231,21 @@ func (a *App) SessionHasPermissionToChannelByPost(session model.Session, postID
return a.SessionHasPermissionTo(session, permission)
}
func (a *App) SessionHasPermissionToReadPost(rctx request.CTX, session model.Session, postID string) (hasPErmission bool, isMember bool) {
if postID == "" {
return false, false
}
channel, err := a.Srv().Store().Channel().GetForPost(postID)
if err != nil {
// Original implementation (SessionHasPermissionToChannelByPost) still checks for
// general permissions even if the channel is not found, and some tests rely on this behavior.
return a.SessionHasPermissionTo(session, model.PermissionReadChannelContent), false
}
return a.SessionHasPermissionToReadChannel(rctx, session, channel)
}
func (a *App) SessionHasPermissionToCategory(c request.CTX, session model.Session, userID, teamID, categoryId string) bool {
if a.SessionHasPermissionTo(session, model.PermissionEditOtherUsers) {
return true
@@ -298,11 +323,21 @@ func (a *App) HasPermissionToTeam(c request.CTX, askingUserId string, teamID str
return a.HasPermissionTo(askingUserId, permission)
}
func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channelID string, permission *model.Permission) bool {
// HasPermissionToChannel determines if the specified user has the given permission on the provided channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has the specified permission for the channel, otherwise false.
// isMember: used for auditing access without membership. True if the user is a member of the channel, otherwise false.
func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channelID string, permission *model.Permission) (hasPermission bool, isMember bool) {
if channelID == "" || askingUserId == "" {
return false
return false, false
}
isMember = false
// We call GetAllChannelMembersForUser instead of just getting
// a single member from the DB, because it's cache backed
// and this is a very frequent call.
@@ -310,19 +345,20 @@ func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channel
var channelRoles []string
if err == nil {
if roles, ok := ids[channelID]; ok {
isMember = true
channelRoles = strings.Fields(roles)
if a.RolesGrantPermission(channelRoles, permission.Id) {
return true
return true, isMember
}
}
}
channel, appErr := a.GetChannel(c, channelID)
if appErr == nil && channel.TeamId != "" {
return a.HasPermissionToTeam(c, askingUserId, channel.TeamId, permission)
return a.HasPermissionToTeam(c, askingUserId, channel.TeamId, permission), isMember
}
return a.HasPermissionTo(askingUserId, permission)
return a.HasPermissionTo(askingUserId, permission), isMember
}
func (a *App) HasPermissionToChannelByPost(c request.CTX, askingUserId string, postID string, permission *model.Permission) bool {
@@ -411,34 +447,53 @@ func (a *App) SessionHasPermissionToManageBot(rctx request.CTX, session model.Se
return nil
}
func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Session, channel *model.Channel) bool {
// SessionHasPermissionToReadChannel checks whether the given session has permission
// to read the specified channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has permission to read the channel, false otherwise
// isMember: used for auditing access without membership. True if the user is a member of the channel, false otherwise
func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Session, channel *model.Channel) (hasPermission bool, isMember bool) {
if session.IsUnrestricted() {
return true
return true, false
}
return a.HasPermissionToReadChannel(c, session.UserId, channel)
}
func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool {
// HasPermissionToReadChannel determines if the specified user has permission to read the given channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has permission to read the channel, false otherwise
// isMember: used for auditing access without membership. True if the user is a member of the channel, false otherwise
func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) (hasPermission bool, isMember bool) {
if a.isChannelArchivedAndHidden(channel) {
return false
return false, false
}
if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) {
return true
if ok, member := a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent); ok {
return true, member
}
if channel.Type == model.ChannelTypeOpen && !*a.Config().ComplianceSettings.Enable {
return a.HasPermissionToTeam(c, userID, channel.TeamId, model.PermissionReadPublicChannel)
return a.HasPermissionToTeam(c, userID, channel.TeamId, model.PermissionReadPublicChannel), false
}
return false
return false, false
}
func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool {
if a.isChannelArchivedAndHidden(channel) {
return false
}
if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) {
if ok, _ := a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent); ok {
return true
}

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

@@ -238,7 +238,9 @@ func TestSessionHasPermissionToChannel(t *testing.T) {
}
t.Run("basic user can access basic channel", func(t *testing.T) {
assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction))
ok, isMember := th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction)
assert.True(t, ok)
assert.True(t, isMember)
})
t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) {
@@ -247,7 +249,9 @@ func TestSessionHasPermissionToChannel(t *testing.T) {
})
err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id)
require.Nil(t, err)
assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel))
ok, _ := th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)
assert.False(t, ok)
})
t.Run("basic user can access archived channel if setting is on", func(t *testing.T) {
@@ -256,7 +260,20 @@ func TestSessionHasPermissionToChannel(t *testing.T) {
})
err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id)
require.Nil(t, err)
assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel))
ok, isMember := th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)
assert.True(t, ok)
assert.True(t, isMember)
})
t.Run("admin user can access channel if not a member", func(t *testing.T) {
adminSession := model.Session{
UserId: th.SystemAdminUser.Id,
Roles: model.SystemAdminRoleId,
}
ok, isMember := th.App.SessionHasPermissionToChannel(th.Context, adminSession, th.BasicChannel.Id, model.PermissionAddReaction)
assert.True(t, ok)
assert.False(t, isMember)
})
t.Run("does not panic if fetching channel causes an error", func(t *testing.T) {
@@ -287,7 +304,9 @@ func TestSessionHasPermissionToChannel(t *testing.T) {
// If there's an error returned from the GetChannel call the code should continue to cascade and since there
// are no session level permissions in this test case, the permission should be denied.
assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicUser.Id, model.PermissionAddReaction))
ok, isMember := th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicUser.Id, model.PermissionAddReaction)
assert.False(t, ok)
assert.False(t, isMember)
// MM-63624, check with TeamSettings.ExperimentalViewArchivedChannels off
th.App.Srv().SetStore(mainHelper.GetStore())
@@ -296,7 +315,9 @@ func TestSessionHasPermissionToChannel(t *testing.T) {
})
th.App.Srv().SetStore(&mockStore)
assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicUser.Id, model.PermissionAddReaction))
ok, isMember = th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicUser.Id, model.PermissionAddReaction)
assert.False(t, ok)
assert.False(t, isMember)
})
}
@@ -796,6 +817,7 @@ func TestHasPermissionToReadChannel(t *testing.T) {
channelIsOpen bool
canReadPublicChannel bool
expected bool
isAdmin bool
}{
{
name: "Cannot read archived channels if the config doesn't allow it",
@@ -857,10 +879,25 @@ func TestHasPermissionToReadChannel(t *testing.T) {
canReadPublicChannel: true,
expected: true,
},
{
name: "Can read private channels if it is a sysadmin and it is not member of the channel",
configComplianceEnabled: false,
channelDeleted: false,
canReadChannel: false,
channelIsOpen: false,
canReadPublicChannel: false,
expected: true,
isAdmin: true,
},
}
for _, tc := range ttcc {
t.Run(tc.name, func(t *testing.T) {
user := th.BasicUser2
if tc.isAdmin {
user = th.SystemAdminUser
}
th.App.UpdateConfig(func(cfg *model.Config) {
configViewArchived := tc.configViewArchived
configComplianceEnabled := tc.configComplianceEnabled
@@ -880,7 +917,7 @@ func TestHasPermissionToReadChannel(t *testing.T) {
channel = th.CreatePrivateChannel(th.Context, team)
}
if tc.canReadChannel {
_, err := th.App.AddUserToChannel(th.Context, th.BasicUser2, channel, false)
_, err := th.App.AddUserToChannel(th.Context, user, channel, false)
require.Nil(t, err)
}
@@ -891,8 +928,13 @@ func TestHasPermissionToReadChannel(t *testing.T) {
require.Nil(t, err)
}
result := th.App.HasPermissionToReadChannel(th.Context, th.BasicUser2.Id, channel)
result, isMember := th.App.HasPermissionToReadChannel(th.Context, user.Id, channel)
require.Equal(t, tc.expected, result)
if result {
require.Equal(t, tc.canReadChannel, isMember)
} else {
require.Equal(t, false, isMember)
}
})
}
}
@@ -1006,3 +1048,226 @@ func TestHasPermissionToChannelByPost(t *testing.T) {
require.Equal(t, true, th.App.HasPermissionToChannelByPost(th.Context, th.SystemAdminUser.Id, post.Id, model.PermissionReadChannel))
})
}
func TestHasPermissionToChannel(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
channel := th.CreateChannel(th.Context, th.BasicTeam)
_, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, channel, false)
assert.Nil(t, appErr)
archivedChannel := th.CreateChannel(th.Context, th.BasicTeam)
_, appErr = th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false)
assert.Nil(t, appErr)
appErr = th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id)
assert.Nil(t, appErr)
t.Run("read channel", func(t *testing.T) {
ok, isMember := th.App.HasPermissionToChannel(th.Context, th.BasicUser.Id, channel.Id, model.PermissionReadChannel)
assert.True(t, ok)
assert.True(t, isMember)
ok, isMember = th.App.HasPermissionToChannel(th.Context, th.BasicUser2.Id, channel.Id, model.PermissionReadChannel)
assert.False(t, ok)
assert.False(t, isMember)
})
t.Run("read archived channel", func(t *testing.T) {
ok, isMember := th.App.HasPermissionToChannel(th.Context, th.BasicUser.Id, archivedChannel.Id, model.PermissionReadChannel)
assert.True(t, ok)
assert.True(t, isMember)
ok, isMember = th.App.HasPermissionToChannel(th.Context, th.BasicUser2.Id, archivedChannel.Id, model.PermissionReadChannel)
assert.False(t, ok)
assert.False(t, isMember)
})
t.Run("read public channel", func(t *testing.T) {
ok, isMember := th.App.HasPermissionToChannel(th.Context, th.BasicUser.Id, channel.Id, model.PermissionReadPublicChannel)
assert.True(t, ok)
assert.True(t, isMember)
ok, isMember = th.App.HasPermissionToChannel(th.Context, th.BasicUser2.Id, channel.Id, model.PermissionReadPublicChannel)
assert.True(t, ok)
assert.False(t, isMember)
})
t.Run("read channel - user is admin", func(t *testing.T) {
ok, isMember := th.App.HasPermissionToChannel(th.Context, th.SystemAdminUser.Id, channel.Id, model.PermissionReadChannel)
assert.True(t, ok)
assert.False(t, isMember)
})
}
func TestSessionHasPermissionToReadChannel(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
channel := th.CreateChannel(th.Context, th.BasicTeam)
_, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, channel, false)
assert.Nil(t, appErr)
archivedChannel := th.CreateChannel(th.Context, th.BasicTeam)
_, appErr = th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false)
assert.Nil(t, appErr)
appErr = th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id)
assert.Nil(t, appErr)
t.Run("basic user can read channel", func(t *testing.T) {
session := model.Session{
UserId: th.BasicUser.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadChannel(th.Context, session, channel)
assert.True(t, ok)
assert.True(t, isMember)
})
t.Run("basic user cannot read channel if not a member and not public", func(t *testing.T) {
privateChannel := th.CreatePrivateChannel(th.Context, th.BasicTeam)
session := model.Session{
UserId: th.BasicUser2.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadChannel(th.Context, session, privateChannel)
assert.False(t, ok)
assert.False(t, isMember)
})
t.Run("basic user can read archived channel if member", func(t *testing.T) {
session := model.Session{
UserId: th.BasicUser.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadChannel(th.Context, session, archivedChannel)
assert.True(t, ok)
assert.True(t, isMember)
})
t.Run("non-member can read public channel", func(t *testing.T) {
session := model.Session{
UserId: th.BasicUser2.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadChannel(th.Context, session, channel)
assert.True(t, ok)
assert.False(t, isMember)
})
t.Run("admin can read any channel", func(t *testing.T) {
session := model.Session{
UserId: th.SystemAdminUser.Id,
Roles: model.SystemAdminRoleId,
}
ok, isMember := th.App.SessionHasPermissionToReadChannel(th.Context, session, channel)
assert.True(t, ok)
assert.False(t, isMember)
})
}
func TestSessionHasPermissionToReadPost(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
// Create a post in a public channel, ensure basic user can read it.
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "hello world",
}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, err)
t.Run("basic user can read their post", func(t *testing.T) {
session := model.Session{
UserId: th.BasicUser.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, post.Id)
assert.True(t, ok)
assert.True(t, isMember)
})
t.Run("other member in channel can read post", func(t *testing.T) {
// Add BasicUser2 to channel
_, aerr := th.App.AddUserToChannel(th.Context, th.BasicUser2, th.BasicChannel, false)
require.Nil(t, aerr)
session := model.Session{
UserId: th.BasicUser2.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, post.Id)
assert.True(t, ok)
assert.True(t, isMember)
})
t.Run("non-member can read post in public channel", func(t *testing.T) {
// Remove BasicUser2 from channel
aerr := th.App.removeUserFromChannel(th.Context, th.BasicUser2.Id, th.SystemAdminUser.Id, th.BasicChannel)
assert.Nil(t, aerr)
session := model.Session{
UserId: th.BasicUser2.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, post.Id)
assert.True(t, ok)
assert.False(t, isMember)
})
t.Run("non-member cannot read post in private channel", func(t *testing.T) {
privateChan := th.CreatePrivateChannel(th.Context, th.BasicTeam)
privatePost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: privateChan.Id,
Message: "private message",
}, privateChan, model.CreatePostFlags{})
require.Nil(t, err)
session := model.Session{
UserId: th.BasicUser2.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, privatePost.Id)
assert.False(t, ok)
assert.False(t, isMember)
})
t.Run("admin can read post even if not a channel member", func(t *testing.T) {
privateChan := th.CreatePrivateChannel(th.Context, th.BasicTeam)
privatePost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: privateChan.Id,
Message: "private admin",
}, privateChan, model.CreatePostFlags{})
require.Nil(t, err)
session := model.Session{
UserId: th.SystemAdminUser.Id,
Roles: model.SystemAdminRoleId,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, privatePost.Id)
assert.True(t, ok)
assert.False(t, isMember)
})
t.Run("returns false for empty postID", func(t *testing.T) {
session := model.Session{
UserId: th.BasicUser.Id,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, "")
assert.False(t, ok)
assert.False(t, isMember)
})
t.Run("returns permission based on system level if postID is missing", func(t *testing.T) {
// To simulate a missing post, use a postID that doesn't exist
session := model.Session{
UserId: th.SystemAdminUser.Id,
Roles: model.SystemAdminRoleId,
}
ok, isMember := th.App.SessionHasPermissionToReadPost(th.Context, session, model.NewId())
assert.True(t, ok)
assert.False(t, isMember)
// Basic user, should be false
session = model.Session{
UserId: th.BasicUser2.Id,
}
ok, isMember = th.App.SessionHasPermissionToReadPost(th.Context, session, model.NewId())
assert.False(t, ok)
assert.False(t, isMember)
})
}

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

@@ -77,7 +77,7 @@ func (a *App) SendAutoResponse(rctx request.CTX, channel *model.Channel, receive
UserId: receiver.Id,
}
if _, err := a.CreatePost(rctx, autoResponderPost, channel, model.CreatePostFlags{}); err != nil {
if _, _, err := a.CreatePost(rctx, autoResponderPost, channel, model.CreatePostFlags{}); err != nil {
return false, err
}

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

@@ -110,7 +110,7 @@ func TestSendAutoResponseIfNecessary(t *testing.T) {
channel := th.CreateDmChannel(receiver)
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: channel.Id,
Message: NewTestId(),
UserId: th.BasicUser.Id,
@@ -141,7 +141,7 @@ func TestSendAutoResponseIfNecessary(t *testing.T) {
channel := th.CreateDmChannel(receiver)
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: channel.Id,
Message: NewTestId(),
UserId: th.BasicUser.Id,
@@ -159,7 +159,7 @@ func TestSendAutoResponseIfNecessary(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: th.BasicChannel.Id,
Message: NewTestId(),
UserId: th.BasicUser.Id,
@@ -200,7 +200,7 @@ func TestSendAutoResponseIfNecessary(t *testing.T) {
botUser, err := th.App.GetUser(bot.UserId)
assert.Nil(t, err)
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: channel.Id,
Message: NewTestId(),
UserId: botUser.Id,
@@ -236,7 +236,7 @@ func TestSendAutoResponseIfNecessary(t *testing.T) {
// which needs to be cleaned up.
require.NoError(t, th.GetSqlStore().Post().PermanentDeleteByUser(th.Context, th.BasicUser.Id))
savedPost, err := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
ChannelId: channel.Id,
Message: patch.NotifyProps["auto_responder_message"],
UserId: receiver.Id,
@@ -274,7 +274,7 @@ func TestSendAutoResponseSuccess(t *testing.T) {
userUpdated1, err := th.App.PatchUser(th.Context, user.Id, patch, true)
require.Nil(t, err)
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: th.BasicChannel.Id,
Message: "zz" + model.NewId() + "a",
UserId: th.BasicUser.Id,
@@ -319,7 +319,7 @@ func TestSendAutoResponseSuccessOnThread(t *testing.T) {
userUpdated1, err := th.App.PatchUser(th.Context, user.Id, patch, true)
require.Nil(t, err)
parentPost, _ := th.App.CreatePost(th.Context, &model.Post{
parentPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: th.BasicChannel.Id,
Message: "zz" + model.NewId() + "a",
UserId: th.BasicUser.Id,
@@ -327,7 +327,7 @@ func TestSendAutoResponseSuccessOnThread(t *testing.T) {
th.BasicChannel,
model.CreatePostFlags{SetOnline: true})
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: th.BasicChannel.Id,
Message: "zz" + model.NewId() + "a",
UserId: th.BasicUser.Id,
@@ -373,7 +373,7 @@ func TestSendAutoResponseFailure(t *testing.T) {
userUpdated1, err := th.App.PatchUser(th.Context, user.Id, patch, true)
require.Nil(t, err)
savedPost, _ := th.App.CreatePost(th.Context, &model.Post{
savedPost, _, _ := th.App.CreatePost(th.Context, &model.Post{
ChannelId: th.BasicChannel.Id,
Message: "zz" + model.NewId() + "a",
UserId: th.BasicUser.Id,

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

@@ -157,7 +157,7 @@ func (a *App) CreateBot(rctx request.CTX, bot *model.Bot) (*model.Bot, *model.Ap
Message: T("api.bot.teams_channels.add_message_mobile"),
}
if _, err := a.CreatePostAsUser(rctx, botAddPost, rctx.Session().Id, true); err != nil {
if _, _, err := a.CreatePostAsUser(rctx, botAddPost, rctx.Session().Id, true); err != nil {
return nil, err
}
}
@@ -565,7 +565,7 @@ func (a *App) notifySysadminsBotOwnerDeactivated(rctx request.CTX, userID string
Type: model.PostTypeSystemGeneric,
}
_, appErr = a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true})
if appErr != nil {
return appErr
}

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

@@ -847,7 +847,7 @@ func (a *App) postChannelPrivacyMessage(c request.CTX, user *model.User, channel
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postChannelPrivacyMessage", "api.channel.post_channel_privacy_message.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -902,7 +902,7 @@ func (a *App) RestoreChannel(c request.CTX, channel *model.Channel, userID strin
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
c.Logger().Warn("Failed to post unarchive message", mlog.Err(err))
}
} else {
@@ -923,7 +923,7 @@ func (a *App) RestoreChannel(c request.CTX, channel *model.Channel, userID strin
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
c.Logger().Error("Failed to post unarchive message", mlog.Err(err))
}
})
@@ -1560,7 +1560,7 @@ func (a *App) DeleteChannel(c request.CTX, channel *model.Channel, userID string
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
c.Logger().Warn("Failed to post archive message", mlog.Err(err))
}
} else {
@@ -1578,7 +1578,7 @@ func (a *App) DeleteChannel(c request.CTX, channel *model.Channel, userID string
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
c.Logger().Warn("Failed to post archive message", mlog.Err(err))
}
}
@@ -1900,7 +1900,7 @@ func (a *App) PostUpdateChannelHeaderMessage(c request.CTX, userID string, chann
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("", "api.channel.post_update_channel_header_message_and_forget.post.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -1933,7 +1933,7 @@ func (a *App) PostUpdateChannelPurposeMessage(c request.CTX, userID string, chan
"new_purpose": newChannelPurpose,
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("", "app.channel.post_update_channel_purpose_message.post.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -1960,7 +1960,7 @@ func (a *App) PostUpdateChannelDisplayNameMessage(c request.CTX, userID string,
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("PostUpdateChannelDisplayNameMessage", "api.channel.post_update_channel_displayname_message_and_forget.create_post.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2477,7 +2477,7 @@ func (a *App) postJoinChannelMessage(c request.CTX, user *model.User, channel *m
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postJoinChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2495,7 +2495,7 @@ func (a *App) postJoinTeamMessage(c request.CTX, user *model.User, channel *mode
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postJoinTeamMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2578,7 +2578,7 @@ func (a *App) postLeaveChannelMessage(c request.CTX, user *model.User, channel *
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postLeaveChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2607,7 +2607,7 @@ func (a *App) PostAddToChannelMessage(c request.CTX, user *model.User, addedUser
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postAddToChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2629,7 +2629,7 @@ func (a *App) postAddToTeamMessage(c request.CTX, user *model.User, addedUser *m
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postAddToTeamMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2661,7 +2661,7 @@ func (a *App) postRemoveFromChannelMessage(c request.CTX, removerUserId string,
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postRemoveFromChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -2894,9 +2894,16 @@ func (a *App) ValidateUserPermissionsOnChannels(c request.CTX, userId string, ch
continue
}
if channel.Type == model.ChannelTypePrivate && a.HasPermissionToChannel(c, userId, channelId, model.PermissionManagePrivateChannelMembers) {
allowedChannelIds = append(allowedChannelIds, channelId)
} else if channel.Type == model.ChannelTypeOpen && a.HasPermissionToChannel(c, userId, channelId, model.PermissionManagePublicChannelMembers) {
allowedPrivate := false
if channel.Type == model.ChannelTypePrivate {
allowedPrivate, _ = a.HasPermissionToChannel(c, userId, channelId, model.PermissionManagePrivateChannelMembers)
}
allowedPublic := false
if channel.Type == model.ChannelTypeOpen {
allowedPublic, _ = a.HasPermissionToChannel(c, userId, channelId, model.PermissionManagePublicChannelMembers)
}
if allowedPrivate || allowedPublic {
allowedChannelIds = append(allowedChannelIds, channelId)
} else {
c.Logger().Info("Invite users to team - no permission to add members to that channel. UserId: " + userId + " ChannelId: " + channelId)
@@ -3453,7 +3460,7 @@ func (a *App) postChannelMoveMessage(c request.CTX, user *model.User, channel *m
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postChannelMoveMessage", "api.team.move_channel.post.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -3967,7 +3974,7 @@ func (a *App) postMessageForConvertGroupMessageToChannel(c request.CTX, channelI
return appErr
}
if _, appErr := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); appErr != nil {
if _, _, appErr := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); appErr != nil {
c.Logger().Error("Failed to create post for notifying about GM converted to private channel", mlog.Err(appErr))
return model.NewAppError(

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

@@ -269,7 +269,7 @@ func TestMoveChannel(t *testing.T) {
ChannelId: channel.Id,
Message: "test",
}
post, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{})
post, _, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{})
require.Nil(t, appErr)
// Post a reply to the thread
@@ -279,7 +279,7 @@ func TestMoveChannel(t *testing.T) {
RootId: post.Id,
Message: "reply",
}
_, appErr = th.App.CreatePost(th.Context, reply, channel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, reply, channel, model.CreatePostFlags{})
require.Nil(t, appErr)
// Check that the thread count before move
@@ -772,7 +772,7 @@ func TestUsersAndPostsCreateActivityInChannel(t *testing.T) {
Message: "root post",
UserId: th.BasicUser.Id,
}
_, err = th.App.CreatePost(th.Context, post, channel1, model.CreatePostFlags{})
_, _, err = th.App.CreatePost(th.Context, post, channel1, model.CreatePostFlags{})
require.Nil(t, err, "Failed to create post.")
_, err = th.App.AddUserToChannel(th.Context, user, channel2, false)
@@ -799,7 +799,7 @@ func TestUsersAndPostsCreateActivityInChannel(t *testing.T) {
}
err = th.App.RemoveUserFromChannel(th.Context, user4.Id, user4.Id, channel4)
require.Nil(t, err, "Failed to create post.")
_, err = th.App.CreatePost(th.Context, post2, channel5, model.CreatePostFlags{})
_, _, err = th.App.CreatePost(th.Context, post2, channel5, model.CreatePostFlags{})
require.Nil(t, err, "Failed to create post.")
_, err = th.App.AddUserToChannel(th.Context, user, channel6, false)
require.Nil(t, err, "Failed to add user to channel.")
@@ -845,7 +845,7 @@ func TestLeaveDefaultChannel(t *testing.T) {
Message: "root post",
UserId: th.BasicUser.Id,
}
rpost, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
rpost, _, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
reply := &model.Post{
@@ -854,7 +854,7 @@ func TestLeaveDefaultChannel(t *testing.T) {
UserId: th.BasicUser.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, reply, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, reply, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
threads, appErr := th.App.GetThreadsForUser(th.BasicUser.Id, townSquare.TeamId, model.GetUserThreadsOpts{})
@@ -884,7 +884,7 @@ func TestLeaveChannel(t *testing.T) {
UserId: th.BasicUser.Id,
}
rpost, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
rpost, _, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
reply := &model.Post{
@@ -893,7 +893,7 @@ func TestLeaveChannel(t *testing.T) {
UserId: th.BasicUser.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, reply, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, reply, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
return rpost
@@ -1805,7 +1805,7 @@ func TestMarkChannelAsUnreadFromPost(t *testing.T) {
_, appErr := th.App.AddUserToChannel(th.Context, u2, c2, false)
require.Nil(t, appErr)
p4, appErr := th.App.CreatePost(th.Context, &model.Post{
p4, _, appErr := th.App.CreatePost(th.Context, &model.Post{
UserId: u2.Id,
ChannelId: c2.Id,
Message: "@" + u1.Username,
@@ -1813,7 +1813,7 @@ func TestMarkChannelAsUnreadFromPost(t *testing.T) {
require.Nil(t, appErr)
th.CreatePost(c2)
_, appErr = th.App.CreatePost(th.Context, &model.Post{
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{
UserId: u2.Id,
ChannelId: c2.Id,
RootId: p4.Id,
@@ -1841,7 +1841,7 @@ func TestMarkChannelAsUnreadFromPost(t *testing.T) {
th.CreatePost(dc)
th.CreatePost(dc)
_, appErr := th.App.CreatePost(th.Context, &model.Post{ChannelId: dc.Id, UserId: th.BasicUser.Id, Message: "testReply", RootId: dm1.Id}, dc, model.CreatePostFlags{})
_, _, appErr := th.App.CreatePost(th.Context, &model.Post{ChannelId: dc.Id, UserId: th.BasicUser.Id, Message: "testReply", RootId: dm1.Id}, dc, model.CreatePostFlags{})
assert.Nil(t, appErr)
response, appErr := th.App.MarkChannelAsUnreadFromPost(th.Context, dm1.Id, u2.Id, true)
@@ -2491,11 +2491,13 @@ func TestPatchChannelModerationsForChannel(t *testing.T) {
_, appErr := th.App.PatchChannelModerationsForChannel(th.Context, channel.DeepCopy(), addCreatePosts)
require.Nil(t, appErr)
require.True(t, th.App.SessionHasPermissionToChannel(th.Context, mockSession, channel.Id, model.PermissionCreatePost))
ok, _ := th.App.SessionHasPermissionToChannel(th.Context, mockSession, channel.Id, model.PermissionCreatePost)
require.True(t, ok)
_, appErr = th.App.PatchChannelModerationsForChannel(th.Context, channel.DeepCopy(), removeCreatePosts)
require.Nil(t, appErr)
require.False(t, th.App.SessionHasPermissionToChannel(th.Context, mockSession, channel.Id, model.PermissionCreatePost))
ok, _ = th.App.SessionHasPermissionToChannel(th.Context, mockSession, channel.Id, model.PermissionCreatePost)
require.False(t, ok)
})
}
@@ -2609,7 +2611,7 @@ func TestViewChannelCollapsedThreadsTurnedOff(t *testing.T) {
Message: "root post @" + u1.Username,
UserId: u2.Id,
}
rpost1, appErr := th.App.CreatePost(th.Context, post1, c1, model.CreatePostFlags{SetOnline: true})
rpost1, _, appErr := th.App.CreatePost(th.Context, post1, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// mention the user in a reply post
@@ -2619,7 +2621,7 @@ func TestViewChannelCollapsedThreadsTurnedOff(t *testing.T) {
UserId: u2.Id,
RootId: rpost1.Id,
}
_, appErr = th.App.CreatePost(th.Context, post2, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, post2, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// Check we have unread mention in the thread
@@ -2686,19 +2688,19 @@ func TestMarkChannelAsUnreadFromPostCollapsedThreadsTurnedOff(t *testing.T) {
// user1: a root post
// user2: Another root mention @u1
user1Mention := " @" + th.BasicUser.Username
rootPost1, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "first root mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
rootPost1, _, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "first root mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hello"}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hello"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
replyPost1, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
replyPost1, _, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another reply"}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another reply"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "a root post"}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "a root post"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another root mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another root mention" + user1Mention}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
t.Run("Mark reply post as unread", func(t *testing.T) {
@@ -2756,17 +2758,17 @@ func TestMarkUnreadCRTOffUpdatesThreads(t *testing.T) {
appErr := th.App.PermanentDeleteUser(th.Context, user3)
require.Nil(t, appErr)
}()
rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "root post"}, th.BasicChannel, model.CreatePostFlags{})
rootPost, _, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "root post"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
r1, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "reply 1"}, th.BasicChannel, model.CreatePostFlags{})
r1, _, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "reply 1"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "reply 2 @" + user3.Username}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "reply 2 @" + user3.Username}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
_, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "reply 3"}, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "reply 3"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
editedPost := r1.Clone()
editedPost.Message += " edited"
_, appErr = th.App.UpdatePost(th.Context, editedPost, &model.UpdatePostOptions{SafeUpdate: false})
_, _, appErr = th.App.UpdatePost(th.Context, editedPost, &model.UpdatePostOptions{SafeUpdate: false})
require.Nil(t, appErr)
th.LinkUserToTeam(user3, th.BasicTeam)
@@ -3309,7 +3311,7 @@ func TestGetChannelFileCount(t *testing.T) {
Message: "This is a test post",
UserId: th.BasicUser.Id,
}
post, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{})
post, _, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{})
require.Nil(t, appErr)
fileInfo1 := &model.FileInfo{

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

@@ -70,7 +70,12 @@ func (a *App) CreateCommandPost(c request.CTX, post *model.Post, teamID string,
}
if response.ResponseType == model.CommandResponseTypeInChannel {
return a.CreatePostMissingChannel(c, post, true, true)
// The post is only used for tests, so even if there are membership issues, we won't send the post to the client.
createdPost, _, appErr := a.CreatePostMissingChannel(c, post, true, true)
if appErr != nil {
return nil, appErr
}
return createdPost, nil
}
if (response.ResponseType == "" || response.ResponseType == model.CommandResponseTypeEphemeral) && (response.Text != "" || response.Attachments != nil) {

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

@@ -556,7 +556,7 @@ func TestExportDMandGMPost(t *testing.T) {
Message: "aa" + model.NewId() + "a",
UserId: th1.BasicUser.Id,
}
_, appErr := th1.App.CreatePost(th1.Context, p1, dmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr := th1.App.CreatePost(th1.Context, p1, dmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
p2 := &model.Post{
@@ -564,7 +564,7 @@ func TestExportDMandGMPost(t *testing.T) {
Message: "bb" + model.NewId() + "a",
UserId: th1.BasicUser.Id,
}
_, appErr = th1.App.CreatePost(th1.Context, p2, dmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th1.App.CreatePost(th1.Context, p2, dmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// GM posts
@@ -573,7 +573,7 @@ func TestExportDMandGMPost(t *testing.T) {
Message: "cc" + model.NewId() + "a",
UserId: th1.BasicUser.Id,
}
_, appErr = th1.App.CreatePost(th1.Context, p3, gmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th1.App.CreatePost(th1.Context, p3, gmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
p4 := &model.Post{
@@ -581,7 +581,7 @@ func TestExportDMandGMPost(t *testing.T) {
Message: "dd" + model.NewId() + "a",
UserId: th1.BasicUser.Id,
}
_, appErr = th1.App.CreatePost(th1.Context, p4, gmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th1.App.CreatePost(th1.Context, p4, gmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
posts, err := th1.App.Srv().Store().Post().GetDirectPostParentsForExportAfter(1000, "0000000", false)
@@ -646,7 +646,7 @@ func TestExportPostWithProps(t *testing.T) {
},
UserId: th1.BasicUser.Id,
}
_, appErr := th1.App.CreatePost(th1.Context, p1, dmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr := th1.App.CreatePost(th1.Context, p1, dmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
p2 := &model.Post{
@@ -657,7 +657,7 @@ func TestExportPostWithProps(t *testing.T) {
},
UserId: th1.BasicUser.Id,
}
_, appErr = th1.App.CreatePost(th1.Context, p2, gmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th1.App.CreatePost(th1.Context, p2, gmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
posts, err := th1.App.Srv().Store().Post().GetDirectPostParentsForExportAfter(1000, "0000000", false)
@@ -1079,7 +1079,7 @@ func TestBuildPostReplies(t *testing.T) {
fileIDs = append(fileIDs, info.Id)
}
post, err := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, RootId: rootID, FileIds: fileIDs}, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, RootId: rootID, FileIds: fileIDs}, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
return post
@@ -1640,7 +1640,7 @@ func TestExportDeactivatedUserDMs(t *testing.T) {
Message: initialMessage,
UserId: th1.BasicUser.Id,
}
initialPostCreated, appErr := th1.App.CreatePost(th1.Context, initialPost, dmChannel, model.CreatePostFlags{SetOnline: true})
initialPostCreated, _, appErr := th1.App.CreatePost(th1.Context, initialPost, dmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// 2. Have user2 reply with TWO types of replies:
@@ -1653,7 +1653,7 @@ func TestExportDeactivatedUserDMs(t *testing.T) {
UserId: user2.Id,
RootId: initialPostCreated.Id, // This makes it a threaded reply
}
_, appErr = th1.App.CreatePost(th1.Context, threadedReply, dmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th1.App.CreatePost(th1.Context, threadedReply, dmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// 2b. User2 sends a standalone reply (NOT in a thread)
@@ -1664,7 +1664,7 @@ func TestExportDeactivatedUserDMs(t *testing.T) {
UserId: user2.Id,
// No RootId, making it a standalone message, not a thread reply
}
_, appErr = th1.App.CreatePost(th1.Context, nonThreadedReply, dmChannel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th1.App.CreatePost(th1.Context, nonThreadedReply, dmChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// 3. Now deactivate user2

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

@@ -1460,12 +1460,12 @@ func populateZipfile(w *zip.Writer, fileDatas []model.FileData) error {
return nil
}
func (a *App) SearchFilesInTeamForUser(c request.CTX, terms string, userId string, teamId string, isOrSearch bool, includeDeletedChannels bool, timeZoneOffset int, page, perPage int) (*model.FileInfoList, *model.AppError) {
func (a *App) SearchFilesInTeamForUser(c request.CTX, terms string, userId string, teamId string, isOrSearch bool, includeDeletedChannels bool, timeZoneOffset int, page, perPage int) (*model.FileInfoList, bool, *model.AppError) {
paramsList := model.ParseSearchParams(strings.TrimSpace(terms), timeZoneOffset)
includeDeleted := includeDeletedChannels && *a.Config().TeamSettings.ExperimentalViewArchivedChannels
if !*a.Config().ServiceSettings.EnableFileSearch {
return nil, model.NewAppError("SearchFilesInTeamForUser", "store.sql_file_info.search.disabled", nil, fmt.Sprintf("teamId=%v userId=%v", teamId, userId), http.StatusNotImplemented)
return nil, false, model.NewAppError("SearchFilesInTeamForUser", "store.sql_file_info.search.disabled", nil, fmt.Sprintf("teamId=%v userId=%v", teamId, userId), http.StatusNotImplemented)
}
finalParamsList := []*model.SearchParams{}
@@ -1489,7 +1489,7 @@ func (a *App) SearchFilesInTeamForUser(c request.CTX, terms string, userId strin
// If the processed search params are empty, return empty search results.
if len(finalParamsList) == 0 {
return model.NewFileInfoList(), nil
return model.NewFileInfoList(), true, nil
}
fileInfoSearchResults, nErr := a.Srv().Store().FileInfo().Search(c, finalParamsList, userId, teamId, page, perPage)
@@ -1497,26 +1497,27 @@ func (a *App) SearchFilesInTeamForUser(c request.CTX, terms string, userId strin
var appErr *model.AppError
switch {
case errors.As(nErr, &appErr):
return nil, appErr
return nil, false, appErr
default:
return nil, model.NewAppError("SearchFilesInTeamForUser", "app.post.search.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
return nil, false, model.NewAppError("SearchFilesInTeamForUser", "app.post.search.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
}
if appErr := a.filterInaccessibleFiles(fileInfoSearchResults, filterFileOptions{assumeSortedCreatedAt: true}); appErr != nil {
return nil, appErr
return nil, false, appErr
}
if appErr := a.FilterFilesByChannelPermissions(c, fileInfoSearchResults, userId); appErr != nil {
return nil, appErr
allFilesHaveMembership, appErr := a.FilterFilesByChannelPermissions(c, fileInfoSearchResults, userId)
if appErr != nil {
return nil, false, appErr
}
return fileInfoSearchResults, nil
return fileInfoSearchResults, allFilesHaveMembership, nil
}
func (a *App) FilterFilesByChannelPermissions(rctx request.CTX, fileList *model.FileInfoList, userID string) *model.AppError {
func (a *App) FilterFilesByChannelPermissions(rctx request.CTX, fileList *model.FileInfoList, userID string) (bool, *model.AppError) {
if fileList == nil || fileList.FileInfos == nil || len(fileList.FileInfos) == 0 {
return nil
return true, nil // On an empty file list, we consider all files as having membership
}
channels := make(map[string]*model.Channel)
@@ -1530,7 +1531,7 @@ func (a *App) FilterFilesByChannelPermissions(rctx request.CTX, fileList *model.
channelIDs := slices.Collect(maps.Keys(channels))
channelList, err := a.GetChannels(rctx, channelIDs)
if err != nil && err.StatusCode != http.StatusNotFound {
return err
return false, err
}
for _, channel := range channelList {
channels[channel.Id] = channel
@@ -1540,6 +1541,7 @@ func (a *App) FilterFilesByChannelPermissions(rctx request.CTX, fileList *model.
channelReadPermission := make(map[string]bool)
filteredFiles := make(map[string]*model.FileInfo)
filteredOrder := []string{}
allFilesHaveMembership := true
for _, fileID := range fileList.Order {
fileInfo, ok := fileList.FileInfos[fileID]
@@ -1550,10 +1552,14 @@ func (a *App) FilterFilesByChannelPermissions(rctx request.CTX, fileList *model.
if _, ok := channelReadPermission[fileInfo.ChannelId]; !ok {
channel := channels[fileInfo.ChannelId]
allowed := false
isMember := true
if channel != nil {
allowed = a.HasPermissionToReadChannel(rctx, userID, channel)
allowed, isMember = a.HasPermissionToReadChannel(rctx, userID, channel)
}
channelReadPermission[fileInfo.ChannelId] = allowed
if allowed {
allFilesHaveMembership = allFilesHaveMembership && isMember
}
}
if channelReadPermission[fileInfo.ChannelId] {
@@ -1565,7 +1571,7 @@ func (a *App) FilterFilesByChannelPermissions(rctx request.CTX, fileList *model.
fileList.FileInfos = filteredFiles
fileList.Order = filteredOrder
return nil
return allFilesHaveMembership, nil
}
func (a *App) ExtractContentFromFileInfo(rctx request.CTX, fileInfo *model.FileInfo) error {

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

@@ -299,13 +299,13 @@ func TestMigrateFilenamesToFileInfos(t *testing.T) {
fpath := fmt.Sprintf("/teams/%v/channels/%v/users/%v/%v/test.png", th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, fileID)
_, err := th.App.WriteFile(file, fpath)
require.Nil(t, err)
rpost, err := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/test.png", th.BasicChannel.Id, th.BasicUser.Id, fileID)}}, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
rpost, _, err := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/test.png", th.BasicChannel.Id, th.BasicUser.Id, fileID)}}, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
infos = th.App.MigrateFilenamesToFileInfos(th.Context, rpost)
assert.Equal(t, 1, len(infos))
rpost, err = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/../../test.png", th.BasicChannel.Id, th.BasicUser.Id, fileID)}}, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
rpost, _, err = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/../../test.png", th.BasicChannel.Id, th.BasicUser.Id, fileID)}}, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
infos = th.App.MigrateFilenamesToFileInfos(th.Context, rpost)
@@ -482,7 +482,7 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
page := 0
results, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
results, allFilesHaveMembership, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
require.Nil(t, err)
require.NotNil(t, results)
@@ -495,6 +495,7 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
fileInfos[1].Id,
fileInfos[0].Id,
}, results.Order)
require.True(t, allFilesHaveMembership)
})
t.Run("should not return later pages of fileInfos from database", func(t *testing.T) {
@@ -503,11 +504,12 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
page := 1
results, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
results, allFilesHaveMembership, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
require.Nil(t, err)
require.NotNil(t, results)
assert.Equal(t, []string{}, results.Order)
require.True(t, allFilesHaveMembership)
})
t.Run("should return first page of fileInfos from ElasticSearch", func(t *testing.T) {
@@ -533,11 +535,12 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
th.App.Srv().Platform().SearchEngine.ElasticsearchEngine = nil
}()
results, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
results, allFilesHaveMembership, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
require.Nil(t, err)
require.NotNil(t, results)
assert.Equal(t, resultsPage, results.Order)
require.True(t, allFilesHaveMembership)
es.AssertExpectations(t)
})
@@ -561,11 +564,12 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
th.App.Srv().Platform().SearchEngine.ElasticsearchEngine = nil
}()
results, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
results, allFilesHaveMembership, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
require.Nil(t, err)
require.NotNil(t, results)
assert.Equal(t, resultsPage, results.Order)
require.True(t, allFilesHaveMembership)
es.AssertExpectations(t)
})
@@ -586,7 +590,7 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
th.App.Srv().Platform().SearchEngine.ElasticsearchEngine = nil
}()
results, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
results, allFilesHaveMembership, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
require.Nil(t, err)
require.NotNil(t, results)
@@ -599,6 +603,7 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
fileInfos[1].Id,
fileInfos[0].Id,
}, results.Order)
require.True(t, allFilesHaveMembership)
es.AssertExpectations(t)
})
@@ -619,10 +624,11 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
th.App.Srv().Platform().SearchEngine.ElasticsearchEngine = nil
}()
results, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
results, allFilesHaveMembership, err := th.App.SearchFilesInTeamForUser(th.Context, searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
require.Nil(t, err)
assert.Equal(t, []string{}, results.Order)
require.True(t, allFilesHaveMembership)
es.AssertExpectations(t)
})
}
@@ -749,16 +755,18 @@ func TestSetFileSearchableContent(t *testing.T) {
})
require.NoError(t, err)
result, appErr := th.App.SearchFilesInTeamForUser(th.Context, "searchable", th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, 0, 60)
result, allFilesHaveMembership, appErr := th.App.SearchFilesInTeamForUser(th.Context, "searchable", th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, 0, 60)
require.Nil(t, appErr)
assert.Equal(t, 0, len(result.Order))
require.True(t, allFilesHaveMembership)
appErr = th.App.SetFileSearchableContent(th.Context, fileInfo.Id, "searchable")
require.Nil(t, appErr)
result, appErr = th.App.SearchFilesInTeamForUser(th.Context, "searchable", th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, 0, 60)
result, allFilesHaveMembership, appErr = th.App.SearchFilesInTeamForUser(th.Context, "searchable", th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, 0, 60)
require.Nil(t, appErr)
assert.Equal(t, 1, len(result.Order))
require.True(t, allFilesHaveMembership)
}
func TestPermanentDeleteFilesByPost(t *testing.T) {
@@ -786,7 +794,7 @@ func TestPermanentDeleteFilesByPost(t *testing.T) {
FileIds: []string{info1.Id},
}
post, err = th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err = th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
assert.Nil(t, err)
err = th.App.PermanentDeleteFilesByPost(th.Context, post.Id)
@@ -810,7 +818,7 @@ func TestPermanentDeleteFilesByPost(t *testing.T) {
CreateAt: 0,
}
post, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
assert.Nil(t, err)
err = th.App.PermanentDeleteFilesByPost(th.Context, post.Id)
@@ -853,7 +861,7 @@ func TestFilterFilesByChannelPermissions(t *testing.T) {
fileList.Order = []string{fileInfo1.Id, fileInfo2.Id, fileInfo3.Id}
// BasicUser should have access to all files
appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
_, appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
require.Nil(t, appErr)
require.Len(t, fileList.FileInfos, 3)
require.Len(t, fileList.Order, 3)
@@ -866,7 +874,7 @@ func TestFilterFilesByChannelPermissions(t *testing.T) {
fileList.FileInfos[fileInfo3.Id] = fileInfo3
fileList.Order = []string{fileInfo1.Id, fileInfo2.Id, fileInfo3.Id}
appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, guestUser.Id)
_, appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, guestUser.Id)
require.Nil(t, appErr)
require.Len(t, fileList.FileInfos, 3)
require.Len(t, fileList.Order, 3)
@@ -904,7 +912,7 @@ func TestFilterFilesByChannelPermissions(t *testing.T) {
fileList.FileInfos[fileInfo3.Id] = fileInfo3
fileList.Order = []string{fileInfo1.Id, fileInfo2.Id, fileInfo3.Id}
appErr = th.App.FilterFilesByChannelPermissions(th.Context, fileList, guestUser.Id)
_, appErr = th.App.FilterFilesByChannelPermissions(th.Context, fileList, guestUser.Id)
require.Nil(t, appErr)
require.Len(t, fileList.FileInfos, 0)
require.Len(t, fileList.Order, 0)
@@ -912,14 +920,14 @@ func TestFilterFilesByChannelPermissions(t *testing.T) {
t.Run("should handle empty file list", func(t *testing.T) {
fileList := model.NewFileInfoList()
appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
_, appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
require.Nil(t, appErr)
require.Len(t, fileList.FileInfos, 0)
require.Len(t, fileList.Order, 0)
})
t.Run("should handle nil file list", func(t *testing.T) {
appErr := th.App.FilterFilesByChannelPermissions(th.Context, nil, th.BasicUser.Id)
_, appErr := th.App.FilterFilesByChannelPermissions(th.Context, nil, th.BasicUser.Id)
require.Nil(t, appErr)
})
@@ -933,7 +941,7 @@ func TestFilterFilesByChannelPermissions(t *testing.T) {
fileList.FileInfos[fileWithoutChannel.Id] = fileWithoutChannel
fileList.Order = []string{fileWithoutChannel.Id}
appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
_, appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
require.Nil(t, appErr)
require.Len(t, fileList.FileInfos, 0)
require.Len(t, fileList.Order, 0)
@@ -949,7 +957,7 @@ func TestFilterFilesByChannelPermissions(t *testing.T) {
fileList.FileInfos[fileWithInvalidChannel.Id] = fileWithInvalidChannel
fileList.Order = []string{fileWithInvalidChannel.Id}
appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
_, appErr := th.App.FilterFilesByChannelPermissions(th.Context, fileList, th.BasicUser.Id)
require.Nil(t, appErr)
require.Len(t, fileList.FileInfos, 0)
require.Len(t, fileList.Order, 0)

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

@@ -518,7 +518,7 @@ func (th *TestHelper) CreatePost(channel *model.Channel, postOptions ...PostOpti
}
var err *model.AppError
if post, err = th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if post, _, err = th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
panic(err)
}
return post
@@ -533,7 +533,7 @@ func (th *TestHelper) CreateMessagePost(channel *model.Channel, message string)
}
var err *model.AppError
if post, err = th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if post, _, err = th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
panic(err)
}
return post
@@ -553,7 +553,7 @@ func (th *TestHelper) CreatePostReply(root *model.Post) *model.Post {
if err != nil {
panic(err)
}
if post, err = th.App.CreatePost(th.Context, post, ch, model.CreatePostFlags{SetOnline: true}); err != nil {
if post, _, err = th.App.CreatePost(th.Context, post, ch, model.CreatePostFlags{SetOnline: true}); err != nil {
panic(err)
}
return post
@@ -861,7 +861,7 @@ func (th *TestHelper) PostPatch(post *model.Post, message string, options ...Pos
optionFunc(postPatch)
}
updatedPost, appErr := th.App.PatchPost(th.Context, post.Id, postPatch, nil)
updatedPost, _, appErr := th.App.PatchPost(th.Context, post.Id, postPatch, nil)
if appErr != nil {
panic(appErr)
}

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

@@ -280,7 +280,7 @@ func (a *App) DoPostActionWithCookie(c request.CTX, postID, actionId, userID, se
response.Update.IsPinned = originalIsPinned
response.Update.HasReactions = originalHasReactions
if _, appErr = a.UpdatePost(c, response.Update, &model.UpdatePostOptions{SafeUpdate: false}); appErr != nil {
if _, _, appErr = a.UpdatePost(c, response.Update, &model.UpdatePostOptions{SafeUpdate: false}); appErr != nil {
return "", appErr
}
}

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

@@ -59,7 +59,7 @@ func TestPostActionInvalidURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -113,7 +113,7 @@ func TestPostActionEmptyResponse(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -157,7 +157,7 @@ func TestPostActionEmptyResponse(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -268,7 +268,7 @@ func TestPostAction(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -305,7 +305,7 @@ func TestPostAction(t *testing.T) {
},
}
post2, err := th.App.CreatePostAsUser(th.Context, &menuPost, "", true)
post2, _, err := th.App.CreatePostAsUser(th.Context, &menuPost, "", true)
require.Nil(t, err)
attachments2, ok := post2.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -363,7 +363,7 @@ func TestPostAction(t *testing.T) {
},
}
postplugin, err := th.App.CreatePostAsUser(th.Context, &interactivePostPlugin, "", true)
postplugin, _, err := th.App.CreatePostAsUser(th.Context, &interactivePostPlugin, "", true)
require.Nil(t, err)
attachmentsPlugin, ok := postplugin.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -411,7 +411,7 @@ func TestPostAction(t *testing.T) {
},
}
postSiteURL, err := th.App.CreatePostAsUser(th.Context, &interactivePostSiteURL, "", true)
postSiteURL, _, err := th.App.CreatePostAsUser(th.Context, &interactivePostSiteURL, "", true)
require.Nil(t, err)
attachmentsSiteURL, ok := postSiteURL.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -453,7 +453,7 @@ func TestPostAction(t *testing.T) {
},
}
postSubpath, err := th.App.CreatePostAsUser(th.Context, &interactivePostSubpath, "", true)
postSubpath, _, err := th.App.CreatePostAsUser(th.Context, &interactivePostSubpath, "", true)
require.Nil(t, err)
attachmentsSubpath, ok := postSubpath.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
@@ -529,7 +529,7 @@ func TestPostActionProps(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -715,7 +715,7 @@ func TestPostActionRelativeURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -755,7 +755,7 @@ func TestPostActionRelativeURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -795,7 +795,7 @@ func TestPostActionRelativeURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -835,7 +835,7 @@ func TestPostActionRelativeURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -875,7 +875,7 @@ func TestPostActionRelativeURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -953,7 +953,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -993,7 +993,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -1033,7 +1033,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)
@@ -1073,7 +1073,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
},
}
post, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
post, _, err := th.App.CreatePostAsUser(th.Context, &interactivePost, "", true)
require.Nil(t, err)
attachments, ok := post.GetProp(model.PostPropsAttachments).([]*model.SlackAttachment)
require.True(t, ok)

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

@@ -825,7 +825,7 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
a.sanitizeProfiles(userThread.Participants, false)
userThread.Post.SanitizeProps()
sanitizedPost, err := a.SanitizePostMetadataForUser(c, userThread.Post, uid)
sanitizedPost, isMemberForPreview, err := a.SanitizePostMetadataForUser(c, userThread.Post, uid)
if err != nil {
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypeWebsocket, model.NotificationReasonParseError, model.NotificationNoPlatform)
a.NotificationsLog().Error("Failed to sanitize metadata",
@@ -849,6 +849,18 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
message.Add("previous_unread_mentions", previousUnreadMentions)
message.Add("previous_unread_replies", previousUnreadReplies)
auditRec := a.MakeAuditRecord(c, "websocketPost", model.AuditStatusSuccess)
defer a.LogAuditRec(c, auditRec, nil)
model.AddEventParameterToAuditRec(auditRec, "post_id", userThread.Post.Id)
if !isMemberForPreview {
previewPost := userThread.Post.GetPreviewPost()
if previewPost != nil {
model.AddEventParameterToAuditRec(auditRec, "preview_post_id", previewPost.Post.Id)
}
model.AddEventParameterToAuditRec(auditRec, "non_channel_member_access", true)
}
auditRec.Success()
a.Publish(message)
}
}
@@ -1008,7 +1020,7 @@ func (a *App) RemoveNotifications(c request.CTX, post *model.Post, channel *mode
a.sanitizeProfiles(userThread.Participants, false)
userThread.Post.SanitizeProps()
sanitizedPost, err1 := a.SanitizePostMetadataForUser(c, userThread.Post, userID)
sanitizedPost, isMemberForPreview, err1 := a.SanitizePostMetadataForUser(c, userThread.Post, userID)
if err1 != nil {
return err1
}
@@ -1019,6 +1031,18 @@ func (a *App) RemoveNotifications(c request.CTX, post *model.Post, channel *mode
c.Logger().Warn("Failed to encode thread to JSON")
}
auditRec := a.MakeAuditRecord(c, "websocketPost", model.AuditStatusSuccess)
defer a.LogAuditRec(c, auditRec, nil)
model.AddEventParameterToAuditRec(auditRec, "post_id", userThread.Post.Id)
if !isMemberForPreview {
previewPost := userThread.Post.GetPreviewPost()
if previewPost != nil {
model.AddEventParameterToAuditRec(auditRec, "preview_post_id", previewPost.Post.Id)
}
model.AddEventParameterToAuditRec(auditRec, "non_channel_member_access", true)
}
auditRec.Success()
message := model.NewWebSocketEvent(model.WebsocketEventThreadUpdated, team.Id, "", userID, nil, "")
message.Add("thread", string(payload))
message.Add("previous_unread_mentions", previousUnreadMentions)
@@ -1451,7 +1475,7 @@ func getMentionsEnabledFields(post *model.Post) model.StringArray {
// allowChannelMentions returns whether or not the channel mentions are allowed for the given post.
func (a *App) allowChannelMentions(c request.CTX, post *model.Post, numProfiles int) bool {
if !a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseChannelMentions) {
if ok, _ := a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseChannelMentions); !ok {
return false
}
@@ -1472,7 +1496,7 @@ func (a *App) allowGroupMentions(c request.CTX, post *model.Post) bool {
return false
}
if !a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseGroupMentions) {
if ok, _ := a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseGroupMentions); !ok {
return false
}

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

@@ -45,7 +45,7 @@ func TestSendNotifications(t *testing.T) {
_, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser2, th.BasicChannel, false)
require.Nil(t, appErr)
post1, createPostErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
post1, _, createPostErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "@" + th.BasicUser2.Username,
@@ -76,7 +76,7 @@ func TestSendNotifications(t *testing.T) {
Message: fmt.Sprintf("hello @%s group", *group.Name),
CreateAt: model.GetMillis() - 10000,
}
groupMentionPost, createPostErr := th.App.CreatePost(th.Context, groupMentionPost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
groupMentionPost, _, createPostErr := th.App.CreatePost(th.Context, groupMentionPost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, createPostErr)
mentions, err := th.App.SendNotifications(th.Context, groupMentionPost, th.BasicTeam, th.BasicChannel, th.BasicUser, nil, true)
@@ -96,7 +96,7 @@ func TestSendNotifications(t *testing.T) {
dm, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
require.Nil(t, appErr)
post2, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
post2, _, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: dm.Id,
Message: "dm message",
@@ -112,7 +112,7 @@ func TestSendNotifications(t *testing.T) {
appErr = th.App.Srv().InvalidateAllCaches()
require.Nil(t, appErr)
post3, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
post3, _, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: dm.Id,
Message: "dm message",
@@ -137,7 +137,7 @@ func TestSendNotifications(t *testing.T) {
}
channel := th.CreateGroupChannel(th.Context, users[0], users[1])
post2, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
post2, _, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: users[0].Id,
ChannelId: channel.Id,
Message: "gm message",
@@ -153,7 +153,7 @@ func TestSendNotifications(t *testing.T) {
appErr = th.App.Srv().InvalidateAllCaches()
require.Nil(t, appErr)
post3, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
post3, _, appErr := th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: users[0].Id,
ChannelId: channel.Id,
Message: "gm message",
@@ -179,7 +179,7 @@ func TestSendNotifications(t *testing.T) {
Props: model.StringInterface{model.PostPropsFromWebhook: "true", model.PostPropsOverrideUsername: "a bot"},
}
rootPost, appErr := th.App.CreatePostMissingChannel(th.Context, rootPost, false, true)
rootPost, _, appErr := th.App.CreatePostMissingChannel(th.Context, rootPost, false, true)
require.Nil(t, appErr)
childPost := &model.Post{
@@ -188,7 +188,7 @@ func TestSendNotifications(t *testing.T) {
RootId: rootPost.Id,
Message: "a reply",
}
childPost, appErr = th.App.CreatePostMissingChannel(th.Context, childPost, false, true)
childPost, _, appErr = th.App.CreatePostMissingChannel(th.Context, childPost, false, true)
require.Nil(t, appErr)
postList := model.PostList{
@@ -361,7 +361,7 @@ func TestSendNotifications_MentionsFollowers(t *testing.T) {
}
// Use CreatePost instead of SendNotifications here since we need that to set up some threads state
_, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
received1 := <-messages1
@@ -580,7 +580,7 @@ func TestSendNotificationsWithManyUsers(t *testing.T) {
users = append(users, user)
}
_, appErr1 := th.App.CreatePostMissingChannel(th.Context, &model.Post{
_, _, appErr1 := th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "@channel",
@@ -600,7 +600,7 @@ func TestSendNotificationsWithManyUsers(t *testing.T) {
}
})
_, appErr1 = th.App.CreatePostMissingChannel(th.Context, &model.Post{
_, _, appErr1 = th.App.CreatePostMissingChannel(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "@channel",
@@ -2860,7 +2860,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
Message: "root post by user1",
UserId: u1.Id,
}
rpost, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
rpost, _, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost1 := &model.Post{
@@ -2869,7 +2869,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
UserId: u2.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost2 := &model.Post{
@@ -2878,7 +2878,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
UserId: u1.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
threadMembership, appErr := th.App.GetThreadMembershipForUser(u2.Id, rpost.Id)
@@ -2910,7 +2910,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
Props: model.StringInterface{model.PostPropsFromWebhook: "true", model.PostPropsOverrideUsername: "a bot"},
}
rootPost, appErr := th.App.CreatePostMissingChannel(th.Context, rootPost, false, true)
rootPost, _, appErr := th.App.CreatePostMissingChannel(th.Context, rootPost, false, true)
require.Nil(t, appErr)
childPost := &model.Post{
@@ -2919,7 +2919,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
RootId: rootPost.Id,
Message: "a reply",
}
childPost, appErr = th.App.CreatePostMissingChannel(th.Context, childPost, false, true)
childPost, _, appErr = th.App.CreatePostMissingChannel(th.Context, childPost, false, true)
require.Nil(t, appErr)
postList := model.PostList{
@@ -2955,7 +2955,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
Message: "root post by user1",
UserId: u1.Id,
}
rpost, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
rpost, _, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// Remove user1 from the channel
@@ -2968,7 +2968,7 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
UserId: u2.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// Ensure user1 is not auto-following the thread
@@ -3001,7 +3001,7 @@ func TestChannelAutoFollowThreads(t *testing.T) {
Message: "root post by user3",
UserId: u3.Id,
}
rpost, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
rpost, _, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost1 := &model.Post{
@@ -3010,7 +3010,7 @@ func TestChannelAutoFollowThreads(t *testing.T) {
UserId: u1.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// user-2 starts auto-following thread
@@ -3032,7 +3032,7 @@ func TestChannelAutoFollowThreads(t *testing.T) {
UserId: u1.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
// Do NOT start auto-following thread, once "un-followed"
@@ -3064,7 +3064,7 @@ func TestRemoveNotifications(t *testing.T) {
Message: "root post by user1",
UserId: u1.Id,
}
rootPost, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
rootPost, _, appErr := th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost1 := &model.Post{
@@ -3073,7 +3073,7 @@ func TestRemoveNotifications(t *testing.T) {
UserId: u2.Id,
RootId: rootPost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost2 := &model.Post{
@@ -3082,7 +3082,7 @@ func TestRemoveNotifications(t *testing.T) {
UserId: u1.Id,
RootId: rootPost.Id,
}
replyPost2, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
replyPost2, _, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
_, appErr = th.App.DeletePost(th.Context, replyPost2.Id, u1.Id)
@@ -3121,7 +3121,7 @@ func TestRemoveNotifications(t *testing.T) {
Message: "root post by user1",
UserId: u1.Id,
}
rootPost, appErr = th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
rootPost, _, appErr = th.App.CreatePost(th.Context, rootPost, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost1 := &model.Post{
@@ -3130,7 +3130,7 @@ func TestRemoveNotifications(t *testing.T) {
UserId: u2.Id,
RootId: rootPost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
_, _, appErr = th.App.CreatePost(th.Context, replyPost1, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
replyPost2 := &model.Post{
@@ -3139,7 +3139,7 @@ func TestRemoveNotifications(t *testing.T) {
UserId: u1.Id,
RootId: rootPost.Id,
}
replyPost2, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
replyPost2, _, appErr = th.App.CreatePost(th.Context, replyPost2, c1, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
_, appErr = th.App.DeletePost(th.Context, replyPost2.Id, u1.Id)

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

@@ -164,7 +164,7 @@ func (a *App) upgradePlanAdminNotifyPost(c request.CTX, workspaceName string, us
props["trial"] = trial
post.SetProps(props)
_, appErr = a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true})
_, _, appErr = a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true})
if appErr != nil {
c.Logger().Warn("Error creating post", mlog.Err(appErr))

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

@@ -61,8 +61,18 @@ func (ms *mockSuite) UserCanSeeOtherUser(c request.CTX, userID string, otherUser
return true, nil
}
func (ms *mockSuite) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool {
return true
func (ms *mockSuite) HasPermissionToReadChannel(rctx request.CTX, userID string, channel *model.Channel) (bool, bool) {
return true, true
}
func (ms *mockSuite) MakeAuditRecord(rctx request.CTX, event string, initialStatus string) *model.AuditRecord {
return &model.AuditRecord{
Status: initialStatus,
EventName: event,
}
}
func (ms *mockSuite) LogAuditRec(rctx request.CTX, auditRec *model.AuditRecord, err error) {
}
func setupDBStore(tb testing.TB) (store.Store, *model.SqlSettings) {

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

@@ -48,21 +48,56 @@ func (_m *SuiteIFace) GetSession(token string) (*model.Session, *model.AppError)
return r0, r1
}
// HasPermissionToReadChannel provides a mock function with given fields: c, userID, channel
func (_m *SuiteIFace) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool {
ret := _m.Called(c, userID, channel)
// HasPermissionToReadChannel provides a mock function with given fields: rctx, userID, channel
func (_m *SuiteIFace) HasPermissionToReadChannel(rctx request.CTX, userID string, channel *model.Channel) (bool, bool) {
ret := _m.Called(rctx, userID, channel)
if len(ret) == 0 {
panic("no return value specified for HasPermissionToReadChannel")
}
var r0 bool
var r1 bool
if rf, ok := ret.Get(0).(func(request.CTX, string, *model.Channel) (bool, bool)); ok {
return rf(rctx, userID, channel)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, *model.Channel) bool); ok {
r0 = rf(c, userID, channel)
r0 = rf(rctx, userID, channel)
} else {
r0 = ret.Get(0).(bool)
}
if rf, ok := ret.Get(1).(func(request.CTX, string, *model.Channel) bool); ok {
r1 = rf(rctx, userID, channel)
} else {
r1 = ret.Get(1).(bool)
}
return r0, r1
}
// LogAuditRec provides a mock function with given fields: rctx, auditRec, err
func (_m *SuiteIFace) LogAuditRec(rctx request.CTX, auditRec *model.AuditRecord, err error) {
_m.Called(rctx, auditRec, err)
}
// MakeAuditRecord provides a mock function with given fields: rctx, event, initialStatus
func (_m *SuiteIFace) MakeAuditRecord(rctx request.CTX, event string, initialStatus string) *model.AuditRecord {
ret := _m.Called(rctx, event, initialStatus)
if len(ret) == 0 {
panic("no return value specified for MakeAuditRecord")
}
var r0 *model.AuditRecord
if rf, ok := ret.Get(0).(func(request.CTX, string, string) *model.AuditRecord); ok {
r0 = rf(rctx, event, initialStatus)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AuditRecord)
}
}
return r0
}
@@ -84,9 +119,9 @@ func (_m *SuiteIFace) RolesGrantPermission(roleNames []string, permissionId stri
return r0
}
// UserCanSeeOtherUser provides a mock function with given fields: c, userID, otherUserId
func (_m *SuiteIFace) UserCanSeeOtherUser(c request.CTX, userID string, otherUserId string) (bool, *model.AppError) {
ret := _m.Called(c, userID, otherUserId)
// UserCanSeeOtherUser provides a mock function with given fields: rctx, userID, otherUserId
func (_m *SuiteIFace) UserCanSeeOtherUser(rctx request.CTX, userID string, otherUserId string) (bool, *model.AppError) {
ret := _m.Called(rctx, userID, otherUserId)
if len(ret) == 0 {
panic("no return value specified for UserCanSeeOtherUser")
@@ -95,16 +130,16 @@ func (_m *SuiteIFace) UserCanSeeOtherUser(c request.CTX, userID string, otherUse
var r0 bool
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, string) (bool, *model.AppError)); ok {
return rf(c, userID, otherUserId)
return rf(rctx, userID, otherUserId)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, string) bool); ok {
r0 = rf(c, userID, otherUserId)
r0 = rf(rctx, userID, otherUserId)
} else {
r0 = ret.Get(0).(bool)
}
if rf, ok := ret.Get(1).(func(request.CTX, string, string) *model.AppError); ok {
r1 = rf(c, userID, otherUserId)
r1 = rf(rctx, userID, otherUserId)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)

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

@@ -28,8 +28,10 @@ const (
type SuiteIFace interface {
GetSession(token string) (*model.Session, *model.AppError)
RolesGrantPermission(roleNames []string, permissionId string) bool
HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool
UserCanSeeOtherUser(c request.CTX, userID string, otherUserId string) (bool, *model.AppError)
HasPermissionToReadChannel(rctx request.CTX, userID string, channel *model.Channel) (bool, bool)
UserCanSeeOtherUser(rctx request.CTX, userID string, otherUserId string) (bool, *model.AppError)
MakeAuditRecord(rctx request.CTX, event string, initialStatus string) *model.AuditRecord
LogAuditRec(rctx request.CTX, auditRec *model.AuditRecord, err error)
}
type webConnActivityMessage struct {

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

@@ -591,7 +591,7 @@ func (api *PluginAPI) SearchPostsInTeamForUser(teamID string, userID string, sea
includeDeletedChannels = *searchParams.IncludeDeletedChannels
}
results, appErr := api.app.SearchPostsForUser(api.ctx, terms, userID, teamID, isOrSearch, includeDeletedChannels, timeZoneOffset, page, perPage)
results, _, appErr := api.app.SearchPostsForUser(api.ctx, terms, userID, teamID, isOrSearch, includeDeletedChannels, timeZoneOffset, page, perPage)
if results != nil {
results = results.ForPlugin()
}
@@ -773,7 +773,7 @@ func (api *PluginAPI) DeleteGroupSyncable(groupID string, syncableID string, syn
func (api *PluginAPI) CreatePost(post *model.Post) (*model.Post, *model.AppError) {
post.AddProp(model.PostPropsFromPlugin, "true")
post, appErr := api.app.CreatePostMissingChannel(api.ctx, post, true, true)
post, _, appErr := api.app.CreatePostMissingChannel(api.ctx, post, true, true)
if post != nil {
post = post.ForPlugin()
}
@@ -793,11 +793,13 @@ func (api *PluginAPI) GetReactions(postID string) ([]*model.Reaction, *model.App
}
func (api *PluginAPI) SendEphemeralPost(userID string, post *model.Post) *model.Post {
return api.app.SendEphemeralPost(api.ctx, userID, post).ForPlugin()
newPost, _ := api.app.SendEphemeralPost(api.ctx, userID, post)
return newPost.ForPlugin()
}
func (api *PluginAPI) UpdateEphemeralPost(userID string, post *model.Post) *model.Post {
return api.app.UpdateEphemeralPost(api.ctx, userID, post).ForPlugin()
newPost, _ := api.app.UpdateEphemeralPost(api.ctx, userID, post)
return newPost.ForPlugin()
}
func (api *PluginAPI) DeleteEphemeralPost(userID, postID string) {
@@ -858,7 +860,7 @@ func (api *PluginAPI) GetPostsForChannel(channelID string, page, perPage int) (*
}
func (api *PluginAPI) UpdatePost(post *model.Post) (*model.Post, *model.AppError) {
post, appErr := api.app.UpdatePost(api.ctx, post, &model.UpdatePostOptions{SafeUpdate: false})
post, _, appErr := api.app.UpdatePost(api.ctx, post, &model.UpdatePostOptions{SafeUpdate: false})
if post != nil {
post = post.ForPlugin()
}
@@ -1104,7 +1106,8 @@ func (api *PluginAPI) HasPermissionToTeam(userID, teamID string, permission *mod
}
func (api *PluginAPI) HasPermissionToChannel(userID, channelID string, permission *model.Permission) bool {
return api.app.HasPermissionToChannel(api.ctx, userID, channelID, permission)
ok, _ := api.app.HasPermissionToChannel(api.ctx, userID, channelID, permission)
return ok
}
func (api *PluginAPI) RolesGrantPermission(roleNames []string, permissionId string) bool {

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

@@ -112,7 +112,7 @@ func TestHookMessageWillBePosted(t *testing.T) {
Message: "message_",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
if assert.NotNil(t, err) {
assert.Equal(t, "Post rejected by plugin. rejected", err.Message)
}
@@ -154,7 +154,7 @@ func TestHookMessageWillBePosted(t *testing.T) {
Message: "message_",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
if assert.NotNil(t, err) {
assert.Equal(t, "Post rejected by plugin. rejected", err.Message)
}
@@ -195,7 +195,7 @@ func TestHookMessageWillBePosted(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
post, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
assert.Equal(t, "message", post.Message)
@@ -240,7 +240,7 @@ func TestHookMessageWillBePosted(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
post, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
assert.Equal(t, "message_fromplugin", post.Message)
@@ -307,7 +307,7 @@ func TestHookMessageWillBePosted(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
post, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
assert.Equal(t, "prefix_message_suffix", post.Message)
})
@@ -353,7 +353,7 @@ func TestHookMessageHasBeenPosted(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
}
@@ -394,11 +394,11 @@ func TestHookMessageWillBeUpdated(t *testing.T) {
Message: "message_",
CreateAt: model.GetMillis() - 10000,
}
post, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
assert.Equal(t, "message_", post.Message)
post.Message = post.Message + "edited_"
post, err = th.App.UpdatePost(th.Context, post, &model.UpdatePostOptions{SafeUpdate: true})
post, _, err = th.App.UpdatePost(th.Context, post, &model.UpdatePostOptions{SafeUpdate: true})
require.Nil(t, err)
assert.Equal(t, "message_edited_fromplugin", post.Message)
}
@@ -444,11 +444,11 @@ func TestHookMessageHasBeenUpdated(t *testing.T) {
Message: "message_",
CreateAt: model.GetMillis() - 10000,
}
post, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
assert.Equal(t, "message_", post.Message)
post.Message = post.Message + "edited"
_, err = th.App.UpdatePost(th.Context, post, &model.UpdatePostOptions{SafeUpdate: true})
_, _, err = th.App.UpdatePost(th.Context, post, &model.UpdatePostOptions{SafeUpdate: true})
require.Nil(t, err)
}
@@ -492,7 +492,7 @@ func TestHookMessageHasBeenDeleted(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
_, err = th.App.DeletePost(th.Context, post.Id, th.BasicUser.Id)
require.Nil(t, err)
@@ -1081,7 +1081,7 @@ func TestHookContext(t *testing.T) {
Message: "not this",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(ctx, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(ctx, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
}
@@ -1670,7 +1670,7 @@ func TestHookMessagesWillBeConsumed(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, newPost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, newPost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
post, err := th.App.GetSinglePost(th.Context, newPost.Id, true)
@@ -1695,7 +1695,7 @@ func TestHookMessagesWillBeConsumed(t *testing.T) {
Message: "message",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, newPost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, newPost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
post, err := th.App.GetSinglePost(th.Context, newPost.Id, true)

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

@@ -765,7 +765,7 @@ func TestPluginPanicLogs(t *testing.T) {
Message: "message_",
CreateAt: model.GetMillis() - 10000,
}
_, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
_, _, err := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
assert.Nil(t, err)
th.TestLogger.Flush()

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

@@ -37,32 +37,32 @@ const (
var atMentionPattern = regexp.MustCompile(`\B@`)
func (a *App) CreatePostAsUser(c request.CTX, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError) {
func (a *App) CreatePostAsUser(c request.CTX, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, bool, *model.AppError) {
// Check that channel has not been deleted
channel, errCh := a.Srv().Store().Channel().Get(post.ChannelId, true)
if errCh != nil {
err := model.NewAppError("CreatePostAsUser", "api.context.invalid_param.app_error", map[string]any{"Name": "post.channel_id"}, "", http.StatusBadRequest).Wrap(errCh)
return nil, err
return nil, false, err
}
if strings.HasPrefix(post.Type, model.PostSystemMessagePrefix) {
err := model.NewAppError("CreatePostAsUser", "api.context.invalid_param.app_error", map[string]any{"Name": "post.type"}, "", http.StatusBadRequest)
return nil, err
return nil, false, err
}
if channel.DeleteAt != 0 {
err := model.NewAppError("createPost", "api.post.create_post.can_not_post_to_deleted.error", nil, "", http.StatusBadRequest)
return nil, err
return nil, false, err
}
rp, err := a.CreatePost(c, post, channel, model.CreatePostFlags{TriggerWebhooks: true, SetOnline: setOnline})
rp, isMemberForPreviews, err := a.CreatePost(c, post, channel, model.CreatePostFlags{TriggerWebhooks: true, SetOnline: setOnline})
if err != nil {
if err.Id == "api.post.create_post.root_id.app_error" ||
err.Id == "api.post.create_post.channel_root_id.app_error" {
err.StatusCode = http.StatusBadRequest
}
return nil, err
return nil, false, err
}
// Update the Channel LastViewAt only if:
@@ -115,19 +115,19 @@ func (a *App) CreatePostAsUser(c request.CTX, post *model.Post, currentSessionId
}
}
return rp, nil
return rp, isMemberForPreviews, nil
}
func (a *App) CreatePostMissingChannel(c request.CTX, post *model.Post, triggerWebhooks bool, setOnline bool) (*model.Post, *model.AppError) {
func (a *App) CreatePostMissingChannel(c request.CTX, post *model.Post, triggerWebhooks bool, setOnline bool) (*model.Post, bool, *model.AppError) {
channel, err := a.Srv().Store().Channel().Get(post.ChannelId, true)
if err != nil {
errCtx := map[string]any{"channel_id": post.ChannelId}
var nfErr *store.ErrNotFound
switch {
case errors.As(err, &nfErr):
return nil, model.NewAppError("CreatePostMissingChannel", "app.channel.get.existing.app_error", errCtx, "", http.StatusNotFound).Wrap(err)
return nil, false, model.NewAppError("CreatePostMissingChannel", "app.channel.get.existing.app_error", errCtx, "", http.StatusNotFound).Wrap(err)
default:
return nil, model.NewAppError("CreatePostMissingChannel", "app.channel.get.find.app_error", errCtx, "", http.StatusInternalServerError).Wrap(err)
return nil, false, model.NewAppError("CreatePostMissingChannel", "app.channel.get.find.app_error", errCtx, "", http.StatusInternalServerError).Wrap(err)
}
}
@@ -168,7 +168,7 @@ func (a *App) deduplicateCreatePost(rctx request.CTX, post *model.Post) (foundPo
// If the other thread finished creating the post, return the created post back to the
// client, making the API call feel idempotent.
actualPost, err := a.GetPostIfAuthorized(rctx, postID, rctx.Session(), false)
actualPost, err, _ := a.GetPostIfAuthorized(rctx, postID, rctx.Session(), false)
if err != nil && err.StatusCode == http.StatusForbidden {
rctx.Logger().Warn("Ignoring pending_post_id for which the user is unauthorized", mlog.String("pending_post_id", post.PendingPostId), mlog.String("post_id", postID), mlog.Err(err))
return nil, nil
@@ -181,17 +181,25 @@ func (a *App) deduplicateCreatePost(rctx request.CTX, post *model.Post) (foundPo
return actualPost, nil
}
func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel, flags model.CreatePostFlags) (savedPost *model.Post, err *model.AppError) {
func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel, flags model.CreatePostFlags) (savedPost *model.Post, isMemberForPreviews bool, err *model.AppError) {
if !a.Config().FeatureFlags.EnableSharedChannelsDMs && channel.IsShared() && (channel.Type == model.ChannelTypeDirect || channel.Type == model.ChannelTypeGroup) {
return nil, model.NewAppError("CreatePost", "app.post.create_post.shared_dm_or_gm.app_error", nil, "", http.StatusBadRequest)
return nil, false, model.NewAppError("CreatePost", "app.post.create_post.shared_dm_or_gm.app_error", nil, "", http.StatusBadRequest)
}
foundPost, err := a.deduplicateCreatePost(c, post)
if err != nil {
return nil, err
return nil, false, err
}
if foundPost != nil {
return foundPost, nil
isMemberForPreviews = true
if previewPost := foundPost.GetPreviewPost(); previewPost != nil {
var member *model.ChannelMember
member, err = a.GetChannelMember(c, previewPost.Post.ChannelId, c.Session().UserId)
if err != nil || member == nil {
isMemberForPreviews = false
}
}
return foundPost, isMemberForPreviews, nil
}
// If we get this far, we've recorded the client-provided pending post id to the cache.
@@ -224,7 +232,7 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
return nil
})
if err != nil {
return nil, model.NewAppError("CreatePost", "api.post.post_priority.persistent_notification_validation_error.request_error", nil, "", http.StatusInternalServerError).Wrap(err)
return nil, false, model.NewAppError("CreatePost", "api.post.post_priority.persistent_notification_validation_error.request_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
}
@@ -245,9 +253,9 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
var nfErr *store.ErrNotFound
switch {
case errors.As(nErr, &nfErr):
return nil, model.NewAppError("CreatePost", MissingAccountError, nil, "", http.StatusNotFound).Wrap(nErr)
return nil, false, model.NewAppError("CreatePost", MissingAccountError, nil, "", http.StatusNotFound).Wrap(nErr)
default:
return nil, model.NewAppError("CreatePost", "app.user.get.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
return nil, false, model.NewAppError("CreatePost", "app.user.get.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
}
@@ -264,16 +272,18 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
}
var ephemeralPost *model.Post
if post.Type == "" && !a.HasPermissionToChannel(c, user.Id, channel.Id, model.PermissionUseChannelMentions) {
mention := post.DisableMentionHighlights()
if mention != "" {
T := i18n.GetUserTranslations(user.Locale)
ephemeralPost = &model.Post{
UserId: user.Id,
RootId: post.RootId,
ChannelId: channel.Id,
Message: T("model.post.channel_notifications_disabled_in_channel.message", model.StringInterface{"ChannelName": channel.Name, "Mention": mention}),
Props: model.StringInterface{model.PostPropsMentionHighlightDisabled: true},
if post.Type == "" {
if hasPermission, _ := a.HasPermissionToChannel(c, user.Id, channel.Id, model.PermissionUseChannelMentions); !hasPermission {
mention := post.DisableMentionHighlights()
if mention != "" {
T := i18n.GetUserTranslations(user.Locale)
ephemeralPost = &model.Post{
UserId: user.Id,
RootId: post.RootId,
ChannelId: channel.Id,
Message: T("model.post.channel_notifications_disabled_in_channel.message", model.StringInterface{"ChannelName": channel.Name, "Mention": mention}),
Props: model.StringInterface{model.PostPropsMentionHighlightDisabled: true},
}
}
}
}
@@ -283,23 +293,23 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
if pchan != nil {
result := <-pchan
if result.NErr != nil {
return nil, model.NewAppError("createPost", "api.post.create_post.root_id.app_error", nil, "", http.StatusBadRequest).Wrap(result.NErr)
return nil, false, model.NewAppError("createPost", "api.post.create_post.root_id.app_error", nil, "", http.StatusBadRequest).Wrap(result.NErr)
}
parentPostList = result.Data
if len(parentPostList.Posts) == 0 || !parentPostList.IsChannelId(post.ChannelId) {
return nil, model.NewAppError("createPost", "api.post.create_post.channel_root_id.app_error", nil, "", http.StatusInternalServerError)
return nil, false, model.NewAppError("createPost", "api.post.create_post.channel_root_id.app_error", nil, "", http.StatusInternalServerError)
}
rootPost := parentPostList.Posts[post.RootId]
if rootPost.RootId != "" {
return nil, model.NewAppError("createPost", "api.post.create_post.root_id.app_error", nil, "", http.StatusBadRequest)
return nil, false, model.NewAppError("createPost", "api.post.create_post.root_id.app_error", nil, "", http.StatusBadRequest)
}
}
post.Hashtags, _ = model.ParseHashtags(post.Message)
if err = a.FillInPostProps(c, post, channel); err != nil {
return nil, err
return nil, false, err
}
// Temporary fix so old plugins don't clobber new fields in SlackAttachment struct, see MM-13088
@@ -344,7 +354,7 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
}, plugin.MessageWillBePostedID)
if rejectionError != nil {
return nil, rejectionError
return nil, false, rejectionError
}
// Pre-fill the CreateAt field for link previews to get the correct timestamp.
@@ -364,18 +374,18 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
var invErr *store.ErrInvalidInput
switch {
case errors.As(nErr, &appErr):
return nil, appErr
return nil, false, appErr
case errors.As(nErr, &invErr):
return nil, model.NewAppError("CreatePost", "app.post.save.existing.app_error", nil, "", http.StatusBadRequest).Wrap(nErr)
return nil, false, model.NewAppError("CreatePost", "app.post.save.existing.app_error", nil, "", http.StatusBadRequest).Wrap(nErr)
default:
return nil, model.NewAppError("CreatePost", "app.post.save.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
return nil, false, model.NewAppError("CreatePost", "app.post.save.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
}
// Update the mapping from pending post id to the actual post id, for any clients that
// might be duplicating requests.
if appErr := a.Srv().seenPendingPostIdsCache.SetWithExpiry(post.PendingPostId, rpost.Id, pendingPostIDsCacheTTL); appErr != nil {
return nil, model.NewAppError("CreatePost", "api.post.deduplicate_create_post.cache_error", nil, "", http.StatusInternalServerError).Wrap(appErr)
return nil, false, model.NewAppError("CreatePost", "api.post.deduplicate_create_post.cache_error", nil, "", http.StatusInternalServerError).Wrap(appErr)
}
if a.Metrics() != nil {
@@ -420,7 +430,7 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
mlog.String("reason", model.NotificationReasonResolvePersistentNotificationError),
mlog.Err(appErr),
)
return nil, appErr
return nil, false, appErr
}
}
@@ -444,12 +454,12 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
a.SendEphemeralPost(c, post.UserId, ephemeralPost)
}
rpost, err = a.SanitizePostMetadataForUser(c, rpost, c.Session().UserId)
rpost, isMemberForPreviews, err = a.SanitizePostMetadataForUser(c, rpost, c.Session().UserId)
if err != nil {
return nil, err
return nil, false, err
}
return rpost, nil
return rpost, isMemberForPreviews, nil
}
func (a *App) addPostPreviewProp(rctx request.CTX, post *model.Post) (*model.Post, error) {
@@ -515,15 +525,17 @@ func (a *App) FillInPostProps(c request.CTX, post *model.Post, channel *model.Ch
}
for _, mentioned := range mentionedChannels {
if mentioned.Type == model.ChannelTypeOpen && a.HasPermissionToReadChannel(c, post.UserId, mentioned) {
team, err := a.Srv().Store().Team().Get(mentioned.TeamId)
if err != nil {
c.Logger().Warn("Failed to get team of the channel mention", mlog.String("team_id", channel.TeamId), mlog.String("channel_id", channel.Id), mlog.Err(err))
continue
}
channelMentionsProp[mentioned.Name] = map[string]any{
"display_name": mentioned.DisplayName,
"team_name": team.Name,
if mentioned.Type == model.ChannelTypeOpen {
if ok, _ := a.HasPermissionToReadChannel(c, post.UserId, mentioned); ok {
team, err := a.Srv().Store().Team().Get(mentioned.TeamId)
if err != nil {
c.Logger().Warn("Failed to get team of the channel mention", mlog.String("team_id", channel.TeamId), mlog.String("channel_id", channel.Id), mlog.Err(err))
continue
}
channelMentionsProp[mentioned.Name] = map[string]any{
"display_name": mentioned.DisplayName,
"team_name": team.Name,
}
}
}
}
@@ -536,7 +548,12 @@ func (a *App) FillInPostProps(c request.CTX, post *model.Post, channel *model.Ch
}
matched := atMentionPattern.MatchString(post.Message)
if a.Srv().License() != nil && *a.Srv().License().Features.LDAPGroups && matched && !a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseGroupMentions) {
shouldAddProp := false
if a.Srv().License() != nil && *a.Srv().License().Features.LDAPGroups && matched {
hasPermission, _ := a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseGroupMentions)
shouldAddProp = !hasPermission
}
if shouldAddProp {
post.AddProp(model.PostPropsGroupHighlightDisabled, true)
}
@@ -593,7 +610,7 @@ func (a *App) handlePostEvents(c request.CTX, post *model.Post, user *model.User
return nil
}
func (a *App) SendEphemeralPost(c request.CTX, userID string, post *model.Post) *model.Post {
func (a *App) SendEphemeralPost(c request.CTX, userID string, post *model.Post) (*model.Post, bool) {
post.Type = model.PostTypeEphemeral
// fill in fields which haven't been specified which have sensible defaults
@@ -612,7 +629,7 @@ func (a *App) SendEphemeralPost(c request.CTX, userID string, post *model.Post)
post = a.PreparePostForClientWithEmbedsAndImages(c, post, true, false, true)
post = model.AddPostActionCookies(post, a.PostActionCookieSecret())
sanitizedPost, appErr := a.SanitizePostMetadataForUser(c, post, userID)
sanitizedPost, isMemberForPreviews, appErr := a.SanitizePostMetadataForUser(c, post, userID)
if appErr != nil {
c.Logger().Error("Failed to sanitize post metadata for user", mlog.String("user_id", userID), mlog.Err(appErr))
@@ -630,10 +647,10 @@ func (a *App) SendEphemeralPost(c request.CTX, userID string, post *model.Post)
message.Add("post", postJSON)
a.Publish(message)
return post
return post, isMemberForPreviews
}
func (a *App) UpdateEphemeralPost(c request.CTX, userID string, post *model.Post) *model.Post {
func (a *App) UpdateEphemeralPost(c request.CTX, userID string, post *model.Post) (*model.Post, bool) {
post.Type = model.PostTypeEphemeral
post.UpdateAt = model.GetMillis()
@@ -646,7 +663,7 @@ func (a *App) UpdateEphemeralPost(c request.CTX, userID string, post *model.Post
post = a.PreparePostForClientWithEmbedsAndImages(c, post, true, false, true)
post = model.AddPostActionCookies(post, a.PostActionCookieSecret())
sanitizedPost, appErr := a.SanitizePostMetadataForUser(c, post, userID)
sanitizedPost, isMemberForPreviews, appErr := a.SanitizePostMetadataForUser(c, post, userID)
if appErr != nil {
c.Logger().Error("Failed to sanitize post metadata for user", mlog.String("user_id", userID), mlog.Err(appErr))
@@ -664,7 +681,7 @@ func (a *App) UpdateEphemeralPost(c request.CTX, userID string, post *model.Post
message.Add("post", postJSON)
a.Publish(message)
return post
return post, isMemberForPreviews
}
func (a *App) DeleteEphemeralPost(rctx request.CTX, userID, postID string) {
@@ -685,7 +702,7 @@ func (a *App) DeleteEphemeralPost(rctx request.CTX, userID, postID string) {
a.Publish(message)
}
func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updatePostOptions *model.UpdatePostOptions) (*model.Post, *model.AppError) {
func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updatePostOptions *model.UpdatePostOptions) (*model.Post, bool, *model.AppError) {
if updatePostOptions == nil {
updatePostOptions = model.DefaultUpdatePostOptions()
}
@@ -698,11 +715,11 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
var invErr *store.ErrInvalidInput
switch {
case errors.As(nErr, &invErr):
return nil, model.NewAppError("UpdatePost", "app.post.get.app_error", nil, "", http.StatusBadRequest).Wrap(nErr)
return nil, false, model.NewAppError("UpdatePost", "app.post.get.app_error", nil, "", http.StatusBadRequest).Wrap(nErr)
case errors.As(nErr, &nfErr):
return nil, model.NewAppError("UpdatePost", "app.post.get.app_error", nil, "", http.StatusNotFound).Wrap(nErr)
return nil, false, model.NewAppError("UpdatePost", "app.post.get.app_error", nil, "", http.StatusNotFound).Wrap(nErr)
default:
return nil, model.NewAppError("UpdatePost", "app.post.get.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
return nil, false, model.NewAppError("UpdatePost", "app.post.get.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
}
oldPost := postLists.Posts[receivedUpdatedPost.Id]
@@ -710,26 +727,26 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
var appErr *model.AppError
if oldPost == nil {
appErr = model.NewAppError("UpdatePost", "api.post.update_post.find.app_error", nil, "id="+receivedUpdatedPost.Id, http.StatusBadRequest)
return nil, appErr
return nil, false, appErr
}
if oldPost.DeleteAt != 0 {
appErr = model.NewAppError("UpdatePost", "api.post.update_post.permissions_details.app_error", map[string]any{"PostId": receivedUpdatedPost.Id}, "", http.StatusBadRequest)
return nil, appErr
return nil, false, appErr
}
if oldPost.IsSystemMessage() {
appErr = model.NewAppError("UpdatePost", "api.post.update_post.system_message.app_error", nil, "id="+receivedUpdatedPost.Id, http.StatusBadRequest)
return nil, appErr
return nil, false, appErr
}
channel, appErr := a.GetChannel(c, oldPost.ChannelId)
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
if channel.DeleteAt != 0 {
return nil, model.NewAppError("UpdatePost", "api.post.update_post.can_not_update_post_in_deleted.error", nil, "", http.StatusBadRequest)
return nil, false, model.NewAppError("UpdatePost", "api.post.update_post.can_not_update_post_in_deleted.error", nil, "", http.StatusBadRequest)
}
newPost := oldPost.Clone()
@@ -748,7 +765,7 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
var fileIds []string
fileIds, appErr = a.processPostFileChanges(c, receivedUpdatedPost, oldPost, updatePostOptions)
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
newPost.FileIds = fileIds
}
@@ -759,7 +776,7 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
}
if appErr = a.FillInPostProps(c, newPost, nil); appErr != nil {
return nil, appErr
return nil, false, appErr
}
if receivedUpdatedPost.IsRemote() {
@@ -773,7 +790,7 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
return newPost != nil
}, plugin.MessageWillBeUpdatedID)
if newPost == nil {
return nil, model.NewAppError("UpdatePost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
return nil, false, model.NewAppError("UpdatePost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
}
// Always use incoming metadata when provided, otherwise retain existing
if receivedUpdatedPost.Metadata != nil {
@@ -788,9 +805,9 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
if nErr != nil {
switch {
case errors.As(nErr, &appErr):
return nil, appErr
return nil, false, appErr
default:
return nil, model.NewAppError("UpdatePost", "app.post.update.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
return nil, false, model.NewAppError("UpdatePost", "app.post.update.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
}
@@ -812,20 +829,20 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
rpost, nErr = a.addPostPreviewProp(c, rpost)
if nErr != nil {
return nil, model.NewAppError("UpdatePost", "app.post.update.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
return nil, false, model.NewAppError("UpdatePost", "app.post.update.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
message := model.NewWebSocketEvent(model.WebsocketEventPostEdited, "", rpost.ChannelId, "", nil, "")
appErr = a.publishWebsocketEventForPost(c, rpost, message)
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
a.invalidateCacheForChannelPosts(rpost.ChannelId)
userID := c.Session().UserId
sanitizedPost, appErr := a.SanitizePostMetadataForUser(c, rpost, userID)
sanitizedPost, isMemberForPreviews, appErr := a.SanitizePostMetadataForUser(c, rpost, userID)
if appErr != nil {
mlog.Error("Failed to sanitize post metadata for user", mlog.String("user_id", userID), mlog.Err(appErr))
@@ -836,7 +853,7 @@ func (a *App) UpdatePost(c request.CTX, receivedUpdatedPost *model.Post, updateP
}
rpost = sanitizedPost
return rpost, nil
return rpost, isMemberForPreviews, nil
}
func (a *App) publishWebsocketEventForPost(rctx request.CTX, post *model.Post, message *model.WebSocketEvent) *model.AppError {
@@ -945,7 +962,9 @@ func (a *App) setupBroadcastHookForPermalink(rctx request.CTX, post *model.Post,
// In case the user does have permission to read, we set the metadata back.
// Note that this is the return value to the post creator, and has nothing to do
// with the content of the websocket broadcast to that user or any other.
if a.HasPermissionToReadChannel(rctx, post.UserId, permalinkPreviewedChannel) {
// We also don't check the membership for the previewed post, since
// the broadcast handler will create the audit events if needed.
if ok, _ := a.HasPermissionToReadChannel(rctx, post.UserId, permalinkPreviewedChannel); ok {
post.AddProp(model.PostPropsPreviewedPost, previewProp)
post.Metadata.Embeds = append(post.Metadata.Embeds, &model.PostEmbed{Type: model.PostEmbedPermalink, Data: permalinkPreviewedPost})
}
@@ -954,39 +973,39 @@ func (a *App) setupBroadcastHookForPermalink(rctx request.CTX, post *model.Post,
return nil
}
func (a *App) PatchPost(c request.CTX, postID string, patch *model.PostPatch, patchPostOptions *model.UpdatePostOptions) (*model.Post, *model.AppError) {
func (a *App) PatchPost(c request.CTX, postID string, patch *model.PostPatch, patchPostOptions *model.UpdatePostOptions) (*model.Post, bool, *model.AppError) {
if patchPostOptions == nil {
patchPostOptions = model.DefaultUpdatePostOptions()
}
post, err := a.GetSinglePost(c, postID, false)
if err != nil {
return nil, err
return nil, false, err
}
channel, err := a.GetChannel(c, post.ChannelId)
if err != nil {
return nil, err
return nil, false, err
}
if channel.DeleteAt != 0 {
err = model.NewAppError("PatchPost", "api.post.patch_post.can_not_update_post_in_deleted.error", nil, "", http.StatusBadRequest)
return nil, err
return nil, false, err
}
if !a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseChannelMentions) {
if ok, _ := a.HasPermissionToChannel(c, post.UserId, post.ChannelId, model.PermissionUseChannelMentions); !ok {
patch.DisableMentionHighlights()
}
post.Patch(patch)
patchPostOptions.SafeUpdate = false
updatedPost, err := a.UpdatePost(c, post, patchPostOptions)
updatedPost, isMemberForPreviews, err := a.UpdatePost(c, post, patchPostOptions)
if err != nil {
return nil, err
return nil, false, err
}
return updatedPost, nil
return updatedPost, isMemberForPreviews, nil
}
func (a *App) GetPostsPage(options model.GetPostsOptions) (*model.PostList, *model.AppError) {
@@ -1715,13 +1734,13 @@ func (a *App) SearchPostsInTeam(teamID string, paramsList []*model.SearchParams)
})
}
func (a *App) SearchPostsForUser(c request.CTX, terms string, userID string, teamID string, isOrSearch bool, includeDeletedChannels bool, timeZoneOffset int, page, perPage int) (*model.PostSearchResults, *model.AppError) {
func (a *App) SearchPostsForUser(c request.CTX, terms string, userID string, teamID string, isOrSearch bool, includeDeletedChannels bool, timeZoneOffset int, page, perPage int) (*model.PostSearchResults, bool, *model.AppError) {
var postSearchResults *model.PostSearchResults
paramsList := model.ParseSearchParams(strings.TrimSpace(terms), timeZoneOffset)
includeDeleted := includeDeletedChannels && *a.Config().TeamSettings.ExperimentalViewArchivedChannels
if !*a.Config().ServiceSettings.EnablePostSearch {
return nil, model.NewAppError("SearchPostsForUser", "store.sql_post.search.disabled", nil, fmt.Sprintf("teamId=%v userId=%v", teamID, userID), http.StatusNotImplemented)
return nil, false, model.NewAppError("SearchPostsForUser", "store.sql_post.search.disabled", nil, fmt.Sprintf("teamId=%v userId=%v", teamID, userID), http.StatusNotImplemented)
}
finalParamsList := []*model.SearchParams{}
@@ -1748,7 +1767,7 @@ func (a *App) SearchPostsForUser(c request.CTX, terms string, userID string, tea
// If the processed search params are empty, return empty search results.
if len(finalParamsList) == 0 {
return model.MakePostSearchResults(model.NewPostList(), nil), nil
return model.MakePostSearchResults(model.NewPostList(), nil), true, nil
}
postSearchResults, err := a.Srv().Store().Post().SearchPostsForUser(c, finalParamsList, userID, teamID, page, perPage)
@@ -1756,26 +1775,27 @@ func (a *App) SearchPostsForUser(c request.CTX, terms string, userID string, tea
var appErr *model.AppError
switch {
case errors.As(err, &appErr):
return nil, appErr
return nil, false, appErr
default:
return nil, model.NewAppError("SearchPostsForUser", "app.post.search.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
return nil, false, model.NewAppError("SearchPostsForUser", "app.post.search.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
}
if appErr := a.filterInaccessiblePosts(postSearchResults.PostList, filterPostOptions{assumeSortedCreatedAt: true}); appErr != nil {
return nil, appErr
return nil, false, appErr
}
if appErr := a.FilterPostsByChannelPermissions(c, postSearchResults.PostList, userID); appErr != nil {
return nil, appErr
allPostHaveMembership, appErr := a.FilterPostsByChannelPermissions(c, postSearchResults.PostList, userID)
if appErr != nil {
return nil, false, appErr
}
return postSearchResults, nil
return postSearchResults, allPostHaveMembership, nil
}
func (a *App) FilterPostsByChannelPermissions(rctx request.CTX, postList *model.PostList, userID string) *model.AppError {
func (a *App) FilterPostsByChannelPermissions(rctx request.CTX, postList *model.PostList, userID string) (bool, *model.AppError) {
if postList == nil || postList.Posts == nil || len(postList.Posts) == 0 {
return nil
return true, nil // On an empty post list, we consider all posts as having membership
}
channels := make(map[string]*model.Channel)
@@ -1789,7 +1809,7 @@ func (a *App) FilterPostsByChannelPermissions(rctx request.CTX, postList *model.
channelIDs := slices.Collect(maps.Keys(channels))
channelList, err := a.GetChannels(rctx, channelIDs)
if err != nil && err.StatusCode != http.StatusNotFound {
return err
return false, err
}
for _, channel := range channelList {
channels[channel.Id] = channel
@@ -1799,6 +1819,7 @@ func (a *App) FilterPostsByChannelPermissions(rctx request.CTX, postList *model.
channelReadPermission := make(map[string]bool)
filteredPosts := make(map[string]*model.Post)
filteredOrder := []string{}
allPostHaveMembership := true
for _, postID := range postList.Order {
post, ok := postList.Posts[postID]
@@ -1809,10 +1830,14 @@ func (a *App) FilterPostsByChannelPermissions(rctx request.CTX, postList *model.
if _, ok := channelReadPermission[post.ChannelId]; !ok {
channel := channels[post.ChannelId]
allowed := false
isMember := true
if channel != nil {
allowed = a.HasPermissionToReadChannel(rctx, userID, channel)
allowed, isMember = a.HasPermissionToReadChannel(rctx, userID, channel)
}
channelReadPermission[post.ChannelId] = allowed
if allowed {
allPostHaveMembership = allPostHaveMembership && isMember
}
}
if channelReadPermission[post.ChannelId] {
@@ -1824,7 +1849,7 @@ func (a *App) FilterPostsByChannelPermissions(rctx request.CTX, postList *model.
postList.Posts = filteredPosts
postList.Order = filteredOrder
return nil
return allPostHaveMembership, nil
}
func (a *App) GetFileInfosForPostWithMigration(rctx request.CTX, postID string, includeDeleted bool) ([]*model.FileInfo, *model.AppError) {
@@ -2176,28 +2201,29 @@ func (a *App) GetThreadMembershipsForUser(userID, teamID string) ([]*model.Threa
return a.Srv().Store().Thread().GetMembershipsForUser(userID, teamID)
}
func (a *App) GetPostIfAuthorized(c request.CTX, postID string, session *model.Session, includeDeleted bool) (*model.Post, *model.AppError) {
func (a *App) GetPostIfAuthorized(c request.CTX, postID string, session *model.Session, includeDeleted bool) (*model.Post, *model.AppError, bool) {
post, err := a.GetSinglePost(c, postID, includeDeleted)
if err != nil {
return nil, err
return nil, err, false
}
channel, err := a.GetChannel(c, post.ChannelId)
if err != nil {
return nil, err
return nil, err, false
}
if !a.SessionHasPermissionToReadChannel(c, *session, channel) {
ok, isMember := a.SessionHasPermissionToReadChannel(c, *session, channel)
if !ok {
if channel.Type == model.ChannelTypeOpen && !*a.Config().ComplianceSettings.Enable {
if !a.SessionHasPermissionToTeam(*session, channel.TeamId, model.PermissionReadPublicChannel) {
return nil, model.MakePermissionError(session, []*model.Permission{model.PermissionReadPublicChannel})
return nil, model.MakePermissionError(session, []*model.Permission{model.PermissionReadPublicChannel}), false
}
} else {
return nil, model.MakePermissionError(session, []*model.Permission{model.PermissionReadChannelContent})
return nil, model.MakePermissionError(session, []*model.Permission{model.PermissionReadChannelContent}), false
}
}
return post, nil
return post, nil, isMember
}
// GetPostsByIds response bool value indicates, if the post is inaccessible due to cloud plan's limit.
@@ -2380,7 +2406,7 @@ func (a *App) CheckPostReminders(rctx request.CTX) {
},
}
if _, err := a.CreatePost(request.EmptyContext(a.Log()), dm, ch, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(request.EmptyContext(a.Log()), dm, ch, model.CreatePostFlags{SetOnline: true}); err != nil {
rctx.Logger().Error("Failed to post reminder message", mlog.Err(err))
}
}
@@ -2448,9 +2474,9 @@ func (a *App) GetPostInfo(c request.CTX, postID string) (*model.PostInfo, *model
if channel.Type == model.ChannelTypeOpen {
hasPermissionToAccessChannel = true
} else if channel.Type == model.ChannelTypePrivate {
hasPermissionToAccessChannel = a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionManagePrivateChannelMembers)
hasPermissionToAccessChannel, _ = a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionManagePrivateChannelMembers)
} else if channel.Type == model.ChannelTypeDirect || channel.Type == model.ChannelTypeGroup {
hasPermissionToAccessChannel = a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent)
hasPermissionToAccessChannel, _ = a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent)
}
}
@@ -2567,7 +2593,7 @@ func (a *App) ValidateMoveOrCopy(c request.CTX, wpl *model.WranglerPostList, ori
return nil
}
func (a *App) CopyWranglerPostlist(c request.CTX, wpl *model.WranglerPostList, targetChannel *model.Channel) (*model.Post, *model.AppError) {
func (a *App) CopyWranglerPostlist(c request.CTX, wpl *model.WranglerPostList, targetChannel *model.Channel) (*model.Post, bool, *model.AppError) {
var appErr *model.AppError
var newRootPost *model.Post
@@ -2587,15 +2613,15 @@ func (a *App) CopyWranglerPostlist(c request.CTX, wpl *model.WranglerPostList, t
for _, fileID := range post.FileIds {
oldFileInfo, appErr = a.GetFileInfo(c, fileID)
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
fileBytes, appErr = a.GetFile(c, fileID)
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
newFileInfo, appErr = a.UploadFile(c, fileBytes, targetChannel.Id, oldFileInfo.Name)
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
newFileIDs = append(newFileIDs, newFileInfo.Id)
@@ -2605,6 +2631,8 @@ func (a *App) CopyWranglerPostlist(c request.CTX, wpl *model.WranglerPostList, t
}
}
var isMemberForPreviews bool
for i, post := range wpl.Posts {
var reactions []*model.Reaction
@@ -2620,16 +2648,16 @@ func (a *App) CopyWranglerPostlist(c request.CTX, wpl *model.WranglerPostList, t
newPost.ChannelId = targetChannel.Id
if i == 0 {
newPost, appErr = a.CreatePost(c, newPost, targetChannel, model.CreatePostFlags{})
newPost, isMemberForPreviews, appErr = a.CreatePost(c, newPost, targetChannel, model.CreatePostFlags{})
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
newRootPost = newPost.Clone()
} else {
newPost.RootId = newRootPost.Id
newPost, appErr = a.CreatePost(c, newPost, targetChannel, model.CreatePostFlags{})
newPost, _, appErr = a.CreatePost(c, newPost, targetChannel, model.CreatePostFlags{})
if appErr != nil {
return nil, appErr
return nil, false, appErr
}
}
@@ -2643,7 +2671,7 @@ func (a *App) CopyWranglerPostlist(c request.CTX, wpl *model.WranglerPostList, t
}
}
return newRootPost, nil
return newRootPost, isMemberForPreviews, nil
}
func (a *App) MoveThread(c request.CTX, postID string, sourceChannelID, channelID string, user *model.User) *model.AppError {
@@ -2689,7 +2717,7 @@ func (a *App) MoveThread(c request.CTX, postID string, sourceChannelID, channelI
// To simulate the move, we first copy the original messages(s) to the
// new channel and later delete the original messages(s).
newRootPost, appErr := a.CopyWranglerPostlist(c, wpl, targetChannel)
newRootPost, _, appErr := a.CopyWranglerPostlist(c, wpl, targetChannel)
if appErr != nil {
return appErr
}
@@ -2702,7 +2730,7 @@ func (a *App) MoveThread(c request.CTX, postID string, sourceChannelID, channelI
ephemeralPostProps := model.StringInterface{
"TranslationID": "app.post.move_thread.from_another_channel",
}
_, appErr = a.CreatePost(c, &model.Post{
_, _, appErr = a.CreatePost(c, &model.Post{
UserId: user.Id,
Type: model.PostTypeWrangler,
RootId: newRootPost.Id,
@@ -2750,7 +2778,7 @@ func (a *App) MoveThread(c request.CTX, postID string, sourceChannelID, channelI
ephemeralPostProps["NumMessages"] = wpl.NumPosts()
_, appErr = a.CreatePost(c, &model.Post{
_, _, appErr = a.CreatePost(c, &model.Post{
UserId: user.Id,
Type: model.PostTypeWrangler,
ChannelId: originalChannel.Id,
@@ -2871,7 +2899,8 @@ func (a *App) SendTestMessage(c request.CTX, userID string) (*model.Post, *model
UserId: bot.UserId,
}
post, err = a.CreatePost(c, post, channel, model.CreatePostFlags{ForceNotification: true})
// We don't check the preview membership because the test message does not send a link to a different post.
post, _, err = a.CreatePost(c, post, channel, model.CreatePostFlags{ForceNotification: true})
if err != nil {
return nil, model.NewAppError("SendTestMessage", "app.notifications.send_test_message.errors.create_post", nil, "", http.StatusInternalServerError).Wrap(err)
}

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

@@ -24,7 +24,7 @@ func testSaveAcknowledgementForPost(t *testing.T) {
defer th.TearDown()
t.Run("save acknowledgment for post should save acknowledgement", func(t *testing.T) {
post, err := th.App.CreatePostAsUser(th.Context, &model.Post{
post, _, err := th.App.CreatePostAsUser(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "message",
@@ -41,7 +41,7 @@ func testSaveAcknowledgementForPost(t *testing.T) {
})
t.Run("saving acknowledgment should update the post's update_at", func(t *testing.T) {
post, err := th.App.CreatePostAsUser(th.Context, &model.Post{
post, _, err := th.App.CreatePostAsUser(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "message",
@@ -65,7 +65,7 @@ func testDeleteAcknowledgementForPost(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
defer th.TearDown()
post, err1 := th.App.CreatePostAsUser(th.Context, &model.Post{
post, _, err1 := th.App.CreatePostAsUser(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
CreateAt: model.GetMillis(),
@@ -138,7 +138,7 @@ func testGetAcknowledgementsForPostList(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
defer th.TearDown()
p1, err := th.App.CreatePostAsUser(th.Context, &model.Post{
p1, _, err := th.App.CreatePostAsUser(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
CreateAt: model.GetMillis(),
@@ -146,7 +146,7 @@ func testGetAcknowledgementsForPostList(t *testing.T) {
}, "", true)
require.Nil(t, err)
p2, err := th.App.CreatePostAsUser(th.Context, &model.Post{
p2, _, err := th.App.CreatePostAsUser(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
CreateAt: model.GetMillis(),
@@ -154,7 +154,7 @@ func testGetAcknowledgementsForPostList(t *testing.T) {
}, "", true)
require.Nil(t, err)
p3, err := th.App.CreatePostAsUser(th.Context, &model.Post{
p3, _, err := th.App.CreatePostAsUser(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
CreateAt: model.GetMillis(),

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

@@ -228,50 +228,48 @@ func removeEmbeddedPostsFromMetadata(post *model.Post) {
post.Metadata.Embeds = newEmbeds
}
func (a *App) sanitizePostMetadataForUserAndChannel(c request.CTX, post *model.Post, previewedPost *model.PreviewPost, previewedChannel *model.Channel, userID string) *model.Post {
if post.Metadata == nil || len(post.Metadata.Embeds) == 0 || previewedPost == nil {
return post
}
if previewedChannel != nil && !a.HasPermissionToReadChannel(c, userID, previewedChannel) {
removePermalinkMetadataFromPost(post)
}
return post
}
func (a *App) SanitizePostMetadataForUser(c request.CTX, post *model.Post, userID string) (*model.Post, *model.AppError) {
func (a *App) SanitizePostMetadataForUser(c request.CTX, post *model.Post, userID string) (*model.Post, bool, *model.AppError) {
if post.Metadata == nil || len(post.Metadata.Embeds) == 0 {
return post, nil
return post, true, nil
}
previewPost := post.GetPreviewPost()
if previewPost == nil {
return post, nil
return post, true, nil
}
previewedChannel, err := a.GetChannel(c, previewPost.Post.ChannelId)
if err != nil {
return nil, err
return nil, false, err
}
if previewedChannel != nil && !a.HasPermissionToReadChannel(c, userID, previewedChannel) {
removePermalinkMetadataFromPost(post)
isMember := true
if previewedChannel != nil {
var hasPermission bool
hasPermission, isMember = a.HasPermissionToReadChannel(c, userID, previewedChannel)
if !hasPermission {
removePermalinkMetadataFromPost(post)
// Since we remove the permalink metadata, we return true
isMember = true
}
}
return post, nil
return post, isMember, nil
}
func (a *App) SanitizePostListMetadataForUser(c request.CTX, postList *model.PostList, userID string) (*model.PostList, *model.AppError) {
func (a *App) SanitizePostListMetadataForUser(c request.CTX, postList *model.PostList, userID string) (*model.PostList, bool, *model.AppError) {
clonedPostList := postList.Clone()
allPreviewsHaveMembership := true
for postID, post := range clonedPostList.Posts {
sanitizedPost, err := a.SanitizePostMetadataForUser(c, post, userID)
sanitizedPost, isMember, err := a.SanitizePostMetadataForUser(c, post, userID)
if err != nil {
return nil, err
return nil, false, err
}
clonedPostList.Posts[postID] = sanitizedPost
allPreviewsHaveMembership = allPreviewsHaveMembership && isMember
}
return clonedPostList, nil
return clonedPostList, allPreviewsHaveMembership, nil
}
func (a *App) getFileMetadataForPost(rctx request.CTX, post *model.Post, fromMaster bool) ([]*model.FileInfo, int64, *model.AppError) {

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

@@ -194,7 +194,7 @@ func TestPreparePostForClient(t *testing.T) {
fileInfo.ChannelId = th.BasicChannel.Id
require.Nil(t, err)
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
FileIds: []string{fileInfo.Id},
@@ -222,7 +222,7 @@ func TestPreparePostForClient(t *testing.T) {
emoji := th.CreateEmoji()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: ":" + emoji.Name + ": :taco:",
@@ -266,7 +266,7 @@ func TestPreparePostForClient(t *testing.T) {
emoji3 := th.CreateEmoji()
emoji4 := th.CreateEmoji()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: ":" + emoji3.Name + ": :taco:",
@@ -307,7 +307,7 @@ func TestPreparePostForClient(t *testing.T) {
*cfg.ServiceSettings.EnablePostIconOverride = override
})
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "Test",
@@ -364,7 +364,7 @@ func TestPreparePostForClient(t *testing.T) {
th := setup(t)
defer th.TearDown()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: fmt.Sprintf("This is ![our logo](%s/test-image2.png) and ![our icon](%s/test-image1.png)", server.URL, server.URL),
@@ -393,7 +393,7 @@ func TestPreparePostForClient(t *testing.T) {
th := setup(t)
defer th.TearDown()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "some post",
@@ -426,7 +426,7 @@ func TestPreparePostForClient(t *testing.T) {
th := setup(t)
defer th.TearDown()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: `This is our logo: ` + server.URL + `/test-image2.png
@@ -462,7 +462,7 @@ func TestPreparePostForClient(t *testing.T) {
th := setup(t)
defer th.TearDown()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: `This is our web page: ` + server.URL,
@@ -537,7 +537,7 @@ func TestPreparePostForClient(t *testing.T) {
}
prepost.AddProp(model.PostPropsUnsafeLinks, "true")
post, err := th.App.CreatePost(th.Context, prepost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, prepost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
clientPost := th.App.PreparePostForClient(th.Context, post, false, false, false)
@@ -553,7 +553,7 @@ func TestPreparePostForClient(t *testing.T) {
Message: `Bla bla bla: ` + fmt.Sprintf(tc.link, server.URL),
}
post, err := th.App.CreatePost(th.Context, prepost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, err := th.App.CreatePost(th.Context, prepost, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, err)
clientPost := th.App.PreparePostForClient(th.Context, post, false, false, false)
@@ -569,7 +569,7 @@ func TestPreparePostForClient(t *testing.T) {
th := setup(t)
defer th.TearDown()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Props: map[string]any{
@@ -610,7 +610,7 @@ func TestPreparePostForClient(t *testing.T) {
fileInfo, err := th.App.DoUploadFile(th.Context, time.Now(), th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, "test.txt", []byte("test"), true)
require.Nil(t, err)
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
Message: "test",
FileIds: []string{fileInfo.Id},
UserId: th.BasicUser.Id,
@@ -645,7 +645,7 @@ func TestPreparePostForClient(t *testing.T) {
th.Context.Session().UserId = th.BasicUser.Id
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
referencedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "hello world",
@@ -655,7 +655,7 @@ func TestPreparePostForClient(t *testing.T) {
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
previewPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: link,
@@ -703,7 +703,7 @@ func TestPreparePostForClient(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
referencedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: testCase.Channel.Id,
Message: "hello world",
@@ -713,7 +713,7 @@ func TestPreparePostForClient(t *testing.T) {
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
previewPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: link,
@@ -741,7 +741,7 @@ func TestPreparePostForClient(t *testing.T) {
th.Context.Session().UserId = th.BasicUser.Id
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
referencedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: `This is our logo: ` + server.URL + `/test-image2.png`,
@@ -751,7 +751,7 @@ func TestPreparePostForClient(t *testing.T) {
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
previewPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: link,
@@ -778,7 +778,7 @@ func TestPreparePostForClient(t *testing.T) {
th.Context.Session().UserId = th.BasicUser.Id
nestedPermalinkPost, err := th.App.CreatePost(th.Context, &model.Post{
nestedPermalinkPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: `This is our logo: ` + server.URL + `/test-image2.png`,
@@ -788,7 +788,7 @@ func TestPreparePostForClient(t *testing.T) {
nestedLink := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, nestedPermalinkPost.Id)
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
referencedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: nestedLink,
@@ -798,7 +798,7 @@ func TestPreparePostForClient(t *testing.T) {
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
previewPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: link,
@@ -825,7 +825,7 @@ func TestPreparePostForClient(t *testing.T) {
th.Context.Session().UserId = th.BasicUser.Id
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
referencedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "hello world",
@@ -834,7 +834,7 @@ func TestPreparePostForClient(t *testing.T) {
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
previewPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: link,
@@ -951,7 +951,7 @@ func testProxyOpenGraphImage(t *testing.T, th *TestHelper, shouldProxy bool) {
serverURL = server.URL
defer server.Close()
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: `This is our web page: ` + server.URL,
@@ -2963,131 +2963,6 @@ func TestContainsPermalink(t *testing.T) {
}
}
func TestSanitizePostMetadataForUserAndChannel(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
defer th.TearDown()
enableLinkPreviews := *th.App.Config().ServiceSettings.EnableLinkPreviews
siteURL := *th.App.Config().ServiceSettings.SiteURL
defer func() {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.ServiceSettings.EnableLinkPreviews = &enableLinkPreviews
cfg.ServiceSettings.SiteURL = &siteURL
})
}()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.EnableLinkPreviews = true
*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
})
t.Run("should not preview for users with no access to the channel", func(t *testing.T) {
directChannel, err := th.App.createDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
assert.Nil(t, err)
userID := model.NewId()
post := &model.Post{
Id: userID,
Metadata: &model.PostMetadata{
Embeds: []*model.PostEmbed{
{
Type: model.PostEmbedPermalink,
Data: &model.PreviewPost{
PostID: "permalink_post_id",
Post: &model.Post{
Id: "permalink_post_id",
Message: "permalink post message",
ChannelId: directChannel.Id,
},
},
},
},
},
}
previewedPost := model.NewPreviewPost(post, th.BasicTeam, directChannel)
actual := th.App.sanitizePostMetadataForUserAndChannel(th.Context, post, previewedPost, directChannel, th.BasicUser2.Id)
assert.NotNil(t, actual.Metadata.Embeds[0].Data)
guestID := model.NewId()
guest := &model.User{
Email: "success+" + guestID + "@simulator.amazonses.com",
Username: "un_" + guestID,
Nickname: "nn_" + guestID,
Password: "Password1",
EmailVerified: true,
}
guest, appErr := th.App.CreateGuest(th.Context, guest)
require.Nil(t, appErr)
actual = th.App.sanitizePostMetadataForUserAndChannel(th.Context, post, previewedPost, directChannel, guest.Id)
assert.Len(t, actual.Metadata.Embeds, 0)
})
t.Run("should not preview for archived channels", func(t *testing.T) {
experimentalViewArchivedChannels := *th.App.Config().TeamSettings.ExperimentalViewArchivedChannels
defer func() {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.TeamSettings.ExperimentalViewArchivedChannels = &experimentalViewArchivedChannels
})
}()
publicChannel, err := th.App.CreateChannel(th.Context, &model.Channel{
Name: model.NewId(),
Type: model.ChannelTypeOpen,
TeamId: th.BasicTeam.Id,
CreatorId: th.SystemAdminUser.Id,
}, true)
require.Nil(t, err)
require.NotEmpty(t, publicChannel.Id)
err = th.App.DeleteChannel(th.Context, publicChannel, th.SystemAdminUser.Id)
require.Nil(t, err)
publicChannel, err = th.App.GetChannel(th.Context, publicChannel.Id)
require.Nil(t, err)
require.NotEmpty(t, publicChannel.Id)
require.NotEqual(t, 0, publicChannel.DeleteAt)
post := &model.Post{
Id: th.BasicUser.Id,
Metadata: &model.PostMetadata{
Embeds: []*model.PostEmbed{
{
Type: model.PostEmbedPermalink,
Data: &model.PreviewPost{
PostID: "permalink_post_id",
Post: &model.Post{
Id: "permalink_post_id",
Message: "permalink post message",
ChannelId: publicChannel.Id,
},
},
},
},
},
}
previewedPost := model.NewPreviewPost(post, th.BasicTeam, publicChannel)
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.ExperimentalViewArchivedChannels = true
})
actual := th.App.sanitizePostMetadataForUserAndChannel(th.Context, post, previewedPost, publicChannel, th.BasicUser.Id)
assert.NotNil(t, actual.Metadata.Embeds[0].Data)
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.ExperimentalViewArchivedChannels = false
})
actual = th.App.sanitizePostMetadataForUserAndChannel(th.Context, post, previewedPost, publicChannel, th.BasicUser.Id)
assert.Len(t, actual.Metadata.Embeds, 0)
})
}
func TestSanitizePostMetaDataForAudit(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
@@ -3099,7 +2974,7 @@ func TestSanitizePostMetaDataForAudit(t *testing.T) {
th.Context.Session().UserId = th.BasicUser.Id
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
referencedPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: "hello world",
@@ -3109,7 +2984,7 @@ func TestSanitizePostMetaDataForAudit(t *testing.T) {
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
previewPost, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: th.BasicChannel.Id,
Message: link,
@@ -3202,15 +3077,16 @@ func TestSanitizePostMetadataForUser(t *testing.T) {
},
}
sanitizedPost, err := th.App.SanitizePostMetadataForUser(th.Context, post, th.BasicUser.Id)
sanitizedPost, isMemberForPreviews, err := th.App.SanitizePostMetadataForUser(th.Context, post, th.BasicUser.Id)
require.Nil(t, err)
require.NotNil(t, sanitizedPost)
require.Equal(t, 1, len(sanitizedPost.Metadata.Embeds))
require.Equal(t, model.PostEmbedLink, sanitizedPost.Metadata.Embeds[0].Type)
require.True(t, isMemberForPreviews)
})
t.Run("should remove embeds for archived channels if the config does not allow it", func(t *testing.T) {
t.Run("should not remove embeds for archived channels", func(t *testing.T) {
publicChannel, err := th.App.CreateChannel(th.Context, &model.Channel{
Name: model.NewId(),
Type: model.ChannelTypeOpen,
@@ -3264,7 +3140,7 @@ func TestSanitizePostMetadataForUser(t *testing.T) {
*cfg.TeamSettings.ExperimentalViewArchivedChannels = true
})
sanitizedPost, err := th.App.SanitizePostMetadataForUser(th.Context, post, th.BasicUser.Id)
sanitizedPost, _, err := th.App.SanitizePostMetadataForUser(th.Context, post, th.BasicUser.Id)
require.Nil(t, err)
require.NotNil(t, sanitizedPost)
@@ -3275,7 +3151,7 @@ func TestSanitizePostMetadataForUser(t *testing.T) {
*cfg.TeamSettings.ExperimentalViewArchivedChannels = false
})
sanitizedPost, err = th.App.SanitizePostMetadataForUser(th.Context, post, th.BasicUser.Id)
sanitizedPost, _, err = th.App.SanitizePostMetadataForUser(th.Context, post, th.BasicUser.Id)
require.Nil(t, err)
require.NotNil(t, sanitizedPost)

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

@@ -99,7 +99,7 @@ func postHardenedModeCheck(hardenedModeEnabled, isIntegration bool, props model.
func userCreatePostPermissionCheckWithApp(c request.CTX, a *App, userId, channelId string) *model.AppError {
hasPermission := false
if a.HasPermissionToChannel(c, userId, channelId, model.PermissionCreatePost) {
if ok, _ := a.HasPermissionToChannel(c, userId, channelId, model.PermissionCreatePost); ok {
hasPermission = true
} else if channel, err := a.GetChannel(c, channelId); err == nil {
// Temporary permission check method until advanced permissions, please do not copy

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

@@ -219,7 +219,7 @@ func TestSendPersistentNotifications(t *testing.T) {
},
},
}
_, appErr = th.App.CreatePost(th.Context, p1, th.BasicChannel, model.CreatePostFlags{})
_, _, appErr = th.App.CreatePost(th.Context, p1, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
err := th.App.SendPersistentNotifications()
@@ -263,7 +263,7 @@ func TestSendPersistentNotificationsBotSender(t *testing.T) {
// Simulate old timestamp so persistent notifications are sent right away
CreateAt: time.Now().Add(-5 * time.Minute).UnixMilli(),
}
post, appErr = th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{})
post, _, appErr = th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
assert.EventuallyWithT(t, func(c *assert.CollectT) {
@@ -314,7 +314,7 @@ func TestSendPersistentNotificationsBotSenderNotInChannel(t *testing.T) {
},
CreateAt: time.Now().Add(-5 * time.Minute).UnixMilli(),
}
post, appErr = th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
post, _, appErr = th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{SetOnline: true})
require.Nil(t, appErr)
assert.EventuallyWithT(t, func(c *assert.CollectT) {

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

@@ -13,7 +13,7 @@ import (
"github.com/mattermost/mattermost/server/public/shared/request"
)
func (a *App) RestorePostVersion(c request.CTX, userID, postID, restoreVersionID string) (*model.Post, *model.AppError) {
func (a *App) RestorePostVersion(c request.CTX, userID, postID, restoreVersionID string) (*model.Post, bool, *model.AppError) {
toRestorePostVersion, err := a.Srv().Store().Post().GetSingle(c, restoreVersionID, true)
if err != nil {
var statusCode int
@@ -25,24 +25,24 @@ func (a *App) RestorePostVersion(c request.CTX, userID, postID, restoreVersionID
statusCode = http.StatusInternalServerError
}
return nil, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.get_single.app_error", nil, err.Error(), statusCode)
return nil, false, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.get_single.app_error", nil, err.Error(), statusCode)
}
// restoreVersionID needs to be an old version of postID
// this is only a safeguard and this should never happen in practice.
if toRestorePostVersion.OriginalId != postID {
return nil, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.not_an_history_item.app_error", nil, "", http.StatusBadRequest)
return nil, false, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.not_an_history_item.app_error", nil, "", http.StatusBadRequest)
}
// the user needs to be the author of the post
// this is only a safeguard and this should never happen in practice.
if toRestorePostVersion.UserId != userID {
return nil, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.not_allowed.app_error", nil, "", http.StatusForbidden)
return nil, false, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.not_allowed.app_error", nil, "", http.StatusForbidden)
}
// the old version of post needs to be a deleted post
if toRestorePostVersion.DeleteAt == 0 {
return nil, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.not_valid_post_history_item.app_error", nil, "", http.StatusBadRequest)
return nil, false, model.NewAppError("RestorePostVersion", "app.post.restore_post_version.not_valid_post_history_item.app_error", nil, "", http.StatusBadRequest)
}
postPatch := &model.PostPatch{

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

@@ -34,9 +34,10 @@ func TestRestorePostVersion(t *testing.T) {
require.Equal(t, "new message 2", editHistory[0].Message)
// now we'll restore a post version
restoredPost, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, editHistory[0].Id)
restoredPost, isMemberForPreview, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, editHistory[0].Id)
require.Nil(t, appErr)
require.Equal(t, "new message 2", restoredPost.Message)
require.True(t, isMemberForPreview)
// verify from database
fetchedPost, err = th.App.Srv().Store().Post().GetSingle(th.Context, post.Id, true)
@@ -85,10 +86,11 @@ func TestRestorePostVersion(t *testing.T) {
require.Equal(t, 1, len(editHistory[1].FileIds))
// now we'll restore a post version
restoredPost, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, editHistory[1].Id)
restoredPost, isMemberForPreview, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, editHistory[1].Id)
require.Nil(t, appErr)
require.Equal(t, "original message", restoredPost.Message)
require.Equal(t, 1, len(restoredPost.FileIds))
require.True(t, isMemberForPreview)
// verify from database
fetchedPost, err = th.App.Srv().Store().Post().GetSingle(th.Context, post.Id, true)
@@ -125,7 +127,7 @@ func TestRestorePostVersion(t *testing.T) {
// now we'll restore a post version
otherPost := th.CreatePost(th.BasicChannel)
restoredPost, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, otherPost.Id)
restoredPost, _, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, otherPost.Id)
require.NotNil(t, appErr)
require.Equal(t, http.StatusBadRequest, appErr.StatusCode)
require.Equal(t, "app.post.restore_post_version.not_an_history_item.app_error", appErr.Id)
@@ -138,7 +140,7 @@ func TestRestorePostVersion(t *testing.T) {
})
t.Run("should return an error if the post does not exist", func(t *testing.T) {
restoredPost, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, model.NewId(), model.NewId())
restoredPost, _, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, model.NewId(), model.NewId())
require.NotNil(t, appErr)
require.Equal(t, http.StatusNotFound, appErr.StatusCode)
require.Equal(t, "app.post.restore_post_version.get_single.app_error", appErr.Id)
@@ -150,7 +152,7 @@ func TestRestorePostVersion(t *testing.T) {
// now we'll restore a post version
invalidRestorePostIUd := model.NewId()
restoredPost, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, invalidRestorePostIUd)
restoredPost, _, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, invalidRestorePostIUd)
require.NotNil(t, appErr)
require.Equal(t, http.StatusNotFound, appErr.StatusCode)
require.Equal(t, "app.post.restore_post_version.get_single.app_error", appErr.Id)
@@ -172,7 +174,7 @@ func TestRestorePostVersion(t *testing.T) {
require.Equal(t, "other post original message", otherPostEditHistory[0].Message)
// we'll specify post's ID and other post's version ID, his should fail
restoredPost, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, otherPostEditHistory[0].Id)
restoredPost, _, appErr := th.App.RestorePostVersion(th.Context, th.BasicUser.Id, post.Id, otherPostEditHistory[0].Id)
require.NotNil(t, appErr)
require.Equal(t, "app.post.restore_post_version.not_an_history_item.app_error", appErr.Id)
require.Equal(t, http.StatusBadRequest, appErr.StatusCode)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@@ -111,7 +111,7 @@ func TestSharedChannelSyncForReactionActions(t *testing.T) {
channel := th.CreateChannel(th.Context, th.BasicTeam, WithShared(true))
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: user.Id,
ChannelId: channel.Id,
Message: "Hello folks",
@@ -146,7 +146,7 @@ func TestSharedChannelSyncForReactionActions(t *testing.T) {
channel := th.CreateChannel(th.Context, th.BasicTeam, WithShared(true))
post, err := th.App.CreatePost(th.Context, &model.Post{
post, _, err := th.App.CreatePost(th.Context, &model.Post{
UserId: user.Id,
ChannelId: channel.Id,
Message: "Hello folks",

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

@@ -136,7 +136,7 @@ func (a *App) SendReportToUser(rctx request.CTX, job *model.Job, format string)
FileIds: []string{fileInfo.Id},
}
_, err = a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true})
_, _, err = a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true})
return err
}
@@ -250,7 +250,7 @@ func (a *App) StartUsersBatchExport(rctx request.CTX, ro *model.UserReportOption
UserId: systemBot.UserId,
}
if _, err := a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
rctx.Logger().Error("Failed to post batch export message", mlog.Err(err))
}
})

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

@@ -195,7 +195,7 @@ func (a *App) postScheduledPost(rctx request.CTX, scheduledPost *model.Scheduled
TriggerWebhooks: true,
SetOnline: false,
}
_, appErr = a.CreatePost(rctx, post, channel, createPostFlags)
_, _, appErr = a.CreatePost(rctx, post, channel, createPostFlags)
if appErr != nil {
rctx.Logger().Error(
"App.processScheduledPostBatch: failed to post scheduled post",
@@ -454,7 +454,7 @@ func (a *App) notifyUser(rctx request.CTX, userId string, userFailedMessages []*
UserId: systemBot.UserId,
}
if _, err := a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(rctx, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
rctx.Logger().Error("Failed to post notification about failed scheduled messages", mlog.Err(err))
}
}

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

@@ -366,7 +366,7 @@ func TestApp_RemoteUnsharing(t *testing.T) {
UserId: th.BasicUser.Id,
Message: "Test message after remote 1 unshare",
}
_, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{})
_, _, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{})
require.Nil(t, appErr)
// Get post count after creating the test post but before "remote-initiated unshare"

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

@@ -114,7 +114,7 @@ func (cfg *AutoPostCreator) CreateRandomPostNested(c request.CTX, rootID string)
post.UserId = cfg.UsersToPostFrom[i]
}
}
rpost, err := cfg.a.CreatePostMissingChannel(c, post, true, true)
rpost, _, err := cfg.a.CreatePostMissingChannel(c, post, true, true)
if err != nil {
return nil, err
}

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

@@ -46,7 +46,7 @@ func (*HeaderProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandA
switch channel.Type {
case model.ChannelTypeOpen:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelProperties) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelProperties); !ok {
return &model.CommandResponse{
Text: args.T("api.command_channel_header.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,
@@ -54,7 +54,7 @@ func (*HeaderProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandA
}
case model.ChannelTypePrivate:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelProperties) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelProperties); !ok {
return &model.CommandResponse{
Text: args.T("api.command_channel_header.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,

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

@@ -46,14 +46,14 @@ func (*PurposeProvider) DoCommand(a *app.App, c request.CTX, args *model.Command
switch channel.Type {
case model.ChannelTypeOpen:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelProperties) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelProperties); !ok {
return &model.CommandResponse{
Text: args.T("api.command_channel_purpose.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,
}
}
case model.ChannelTypePrivate:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelProperties) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelProperties); !ok {
return &model.CommandResponse{
Text: args.T("api.command_channel_purpose.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,

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

@@ -49,14 +49,14 @@ func (*RenameProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandA
switch channel.Type {
case model.ChannelTypeOpen:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelProperties) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelProperties); !ok {
return &model.CommandResponse{
Text: args.T("api.command_channel_rename.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,
}
}
case model.ChannelTypePrivate:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelProperties) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelProperties); !ok {
return &model.CommandResponse{
Text: args.T("api.command_channel_rename.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,

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

@@ -89,7 +89,7 @@ func (*EchoProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArg
time.Sleep(time.Duration(delay) * time.Second)
if _, err := a.CreatePostMissingChannel(c, post, true, true); err != nil {
if _, _, err := a.CreatePostMissingChannel(c, post, true, true); err != nil {
c.Logger().Error("Unable to create /echo post.", mlog.Err(err))
}
})

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

@@ -126,7 +126,7 @@ func (*groupmsgProvider) DoCommand(a *app.App, c request.CTX, args *model.Comman
post.Message = parsedMessage
post.ChannelId = groupChannel.Id
post.UserId = args.UserId
if _, err := a.CreatePostMissingChannel(c, post, true, true); err != nil {
if _, _, err := a.CreatePostMissingChannel(c, post, true, true); err != nil {
return &model.CommandResponse{Text: args.T("api.command_groupmsg.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
}
}

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

@@ -274,7 +274,7 @@ func (i *InviteProvider) checkPermissions(a *app.App, c request.CTX, args *model
for _, targetChannel := range targetChannels {
switch targetChannel.Type {
case model.ChannelTypeOpen:
if !a.HasPermissionToChannel(c, args.UserId, targetChannel.Id, model.PermissionManagePublicChannelMembers) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, targetChannel.Id, model.PermissionManagePublicChannelMembers); !ok {
*resps = append(*resps, args.T("api.command_invite.permission.app_error", map[string]any{
"User": targetUser.Username,
"Channel": targetChannel.Name,
@@ -282,7 +282,7 @@ func (i *InviteProvider) checkPermissions(a *app.App, c request.CTX, args *model
continue
}
case model.ChannelTypePrivate:
if !a.HasPermissionToChannel(c, args.UserId, targetChannel.Id, model.PermissionManagePrivateChannelMembers) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, targetChannel.Id, model.PermissionManagePrivateChannelMembers); !ok {
if _, err = a.GetChannelMember(c, targetChannel.Id, args.UserId); err == nil {
// User doing the inviting is a member of the channel.
*resps = append(*resps, args.T("api.command_invite.permission.app_error", map[string]any{

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

@@ -55,11 +55,11 @@ func (*JoinProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArg
switch channel.Type {
case model.ChannelTypeOpen:
if !a.HasPermissionToChannel(c, args.UserId, channel.Id, model.PermissionJoinPublicChannels) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, channel.Id, model.PermissionJoinPublicChannels); !ok {
return &model.CommandResponse{Text: args.T("api.command_join.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
}
case model.ChannelTypePrivate:
if !a.HasPermissionToChannel(c, args.UserId, channel.Id, model.PermissionReadChannel) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, channel.Id, model.PermissionReadChannel); !ok {
return &model.CommandResponse{Text: args.T("api.command_join.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
}
default:

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

@@ -672,7 +672,7 @@ func (*LoadTestProvider) URLCommand(a *app.App, c request.CTX, args *model.Comma
post.ChannelId = args.ChannelId
post.UserId = args.UserId
if _, err := a.CreatePostMissingChannel(c, post, false, true); err != nil {
if _, _, err := a.CreatePostMissingChannel(c, post, false, true); err != nil {
return &model.CommandResponse{Text: "Unable to create post", ResponseType: model.CommandResponseTypeEphemeral}, err
}
}
@@ -721,7 +721,7 @@ func (*LoadTestProvider) JSONCommand(a *app.App, c request.CTX, args *model.Comm
post.Message = message
}
if _, err := a.CreatePostMissingChannel(c, &post, false, true); err != nil {
if _, _, err := a.CreatePostMissingChannel(c, &post, false, true); err != nil {
return &model.CommandResponse{Text: "Unable to create post", ResponseType: model.CommandResponseTypeEphemeral}, err
}

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

@@ -100,7 +100,7 @@ func (*msgProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs
post.Message = parsedMessage
post.ChannelId = targetChannelID
post.UserId = args.UserId
if _, err = a.CreatePostMissingChannel(c, post, true, true); err != nil {
if _, _, err = a.CreatePostMissingChannel(c, post, true, true); err != nil {
return &model.CommandResponse{Text: args.T("api.command_msg.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
}
}

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

@@ -75,14 +75,14 @@ func doCommand(a *app.App, c request.CTX, args *model.CommandArgs, message strin
switch channel.Type {
case model.ChannelTypeOpen:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelMembers) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePublicChannelMembers); !ok {
return &model.CommandResponse{
Text: args.T("api.command_remove.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,
}
}
case model.ChannelTypePrivate:
if !a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelMembers) {
if ok, _ := a.HasPermissionToChannel(c, args.UserId, args.ChannelId, model.PermissionManagePrivateChannelMembers); !ok {
return &model.CommandResponse{
Text: args.T("api.command_remove.permission.app_error"),
ResponseType: model.CommandResponseTypeEphemeral,

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

@@ -344,7 +344,7 @@ func (th *TestHelper) createPost(tb testing.TB, channel *model.Channel) *model.P
CreateAt: model.GetMillis() - 10000,
}
post, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{SetOnline: true})
post, _, appErr := th.App.CreatePost(th.Context, post, channel, model.CreatePostFlags{SetOnline: true})
require.Nil(tb, appErr)
return post
}

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

@@ -1288,7 +1288,7 @@ func (a *App) postLeaveTeamMessage(c request.CTX, user *model.User, channel *mod
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postRemoveFromChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}
@@ -1306,7 +1306,7 @@ func (a *App) postRemoveFromTeamMessage(c request.CTX, user *model.User, channel
},
}
if _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
if _, _, err := a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true}); err != nil {
return model.NewAppError("postRemoveFromTeamMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, "", http.StatusInternalServerError).Wrap(err)
}

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

@@ -1187,12 +1187,14 @@ func TestAppUpdateTeamScheme(t *testing.T) {
},
}
// ensure user can update channel properties before applying the scheme
require.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, channel.Id, model.PermissionManagePublicChannelProperties))
ok, _ := th.App.SessionHasPermissionToChannel(th.Context, session, channel.Id, model.PermissionManagePublicChannelProperties)
require.True(t, ok)
// apply the team scheme
team2.SchemeId = &team2Scheme.Id
_, appErr = th.App.UpdateTeamScheme(team2)
require.Nil(t, appErr)
require.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, channel.Id, model.PermissionManagePublicChannelProperties))
ok, _ = th.App.SessionHasPermissionToChannel(th.Context, session, channel.Id, model.PermissionManagePublicChannelProperties)
require.False(t, ok)
}
func TestGetTeamMembers(t *testing.T) {

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

@@ -2895,7 +2895,7 @@ func (a *App) UpdateThreadFollowForUserFromChannelAdd(c request.CTX, userID, tea
}
a.sanitizeProfiles(userThread.Participants, false)
userThread.Post.SanitizeProps()
sanitizedPost, appErr := a.SanitizePostMetadataForUser(c, userThread.Post, userID)
sanitizedPost, isMemberForPreviews, appErr := a.SanitizePostMetadataForUser(c, userThread.Post, userID)
if appErr != nil {
return appErr
}
@@ -2909,6 +2909,16 @@ func (a *App) UpdateThreadFollowForUserFromChannelAdd(c request.CTX, userID, tea
message.Add("previous_unread_replies", int64(0))
message.Add("previous_unread_mentions", int64(0))
auditRec := a.MakeAuditRecord(c, "websocketPost", model.AuditStatusSuccess)
defer a.LogAuditRec(c, auditRec, nil)
model.AddEventParameterToAuditRec(auditRec, "post_id", userThread.Post.Id)
model.AddEventParameterToAuditRec(auditRec, "user_id", userID)
model.AddEventParameterToAuditRec(auditRec, "source", "UpdateThreadFollowForUserFromChannelAdd")
if !isMemberForPreviews {
model.AddEventParameterToAuditRec(auditRec, "non_channel_member_access", true)
}
auditRec.Success()
a.Publish(message)
return nil
}

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

@@ -2180,9 +2180,9 @@ func TestUpdateThreadReadForUser(t *testing.T) {
*cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn
})
rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, model.CreatePostFlags{})
rootPost, _, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
replyPost, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, model.CreatePostFlags{})
replyPost, _, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, model.CreatePostFlags{})
require.Nil(t, appErr)
threads, appErr := th.App.GetThreadsForUser(th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{})
require.Nil(t, appErr)

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

@@ -151,7 +151,8 @@ func (h *permalinkBroadcastHook) Process(msg *platform.HookedWebSocketEvent, web
}
rctx := request.EmptyContext(webConn.Platform.Log())
if !webConn.Suite.HasPermissionToReadChannel(rctx, webConn.UserId, previewChannel) {
ok, isMember := webConn.Suite.HasPermissionToReadChannel(rctx, webConn.UserId, previewChannel)
if !ok {
// Do nothing.
// In this case, the sanitized post is already attached to the ws event.
return nil
@@ -164,6 +165,16 @@ func (h *permalinkBroadcastHook) Process(msg *platform.HookedWebSocketEvent, web
}
msg.Add("post", postJSON)
auditRec := webConn.Suite.MakeAuditRecord(rctx, "websocketPost", model.AuditStatusSuccess)
defer webConn.Suite.LogAuditRec(rctx, auditRec, nil)
model.AddEventParameterToAuditRec(auditRec, "channel_id", previewChannel.Id)
model.AddEventParameterToAuditRec(auditRec, "user_id", webConn.UserId)
model.AddEventParameterToAuditRec(auditRec, "source", "permalinkBroadcastHook")
if !isMember {
model.AddEventParameterToAuditRec(auditRec, "non_channel_member_access", true)
}
return nil
}

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

@@ -371,7 +371,7 @@ func (a *App) CreateWebhookPost(c request.CTX, userID string, channel *model.Cha
}
for _, split := range splits {
if _, err = a.CreatePost(c, split, channel, model.CreatePostFlags{}); err != nil {
if _, _, err := a.CreatePost(c, split, channel, model.CreatePostFlags{}); err != nil {
return nil, model.NewAppError("CreateWebhookPost", "api.post.create_webhook_post.creating.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
}
@@ -847,7 +847,12 @@ func (a *App) HandleIncomingWebhook(c request.CTX, hookID string, req *model.Inc
return model.NewAppError("HandleIncomingWebhook", "web.incoming_webhook.user.app_error", map[string]any{"user": hook.UserId}, "", http.StatusForbidden).Wrap(resultU.NErr)
}
if channel.Type != model.ChannelTypeOpen && !a.HasPermissionToChannel(c, hook.UserId, channel.Id, model.PermissionReadChannelContent) {
restrictedChannel := false
if channel.Type != model.ChannelTypeOpen {
hasPermission, _ := a.HasPermissionToChannel(c, hook.UserId, channel.Id, model.PermissionReadChannelContent)
restrictedChannel = !hasPermission
}
if restrictedChannel {
return model.NewAppError("HandleIncomingWebhook", "web.incoming_webhook.permissions.app_error", map[string]any{"user": hook.UserId, "channel": channel.Id}, "", http.StatusForbidden)
}