mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
* MM-68952: Resolve public channel mentions for non-members under Compliance Channel mention name resolution reused HasPermissionToReadChannel, a content-read check that returns false for non-members of a public channel when Compliance Monitoring is enabled (MM-45272) or when the channel is on another team (MM-66791). As a result, the channel_mentions post prop was stripped per-viewer (since #34235), and the webapp fell back to rendering the raw (anonymized) channel slug instead of a clickable link. Introduce HasPermissionToResolveChannelMention, which exposes only a public channel display name and link (not content) and is therefore independent of ComplianceSettings, while still requiring team membership for public channels (blocks cross-team disclosure) and channel membership for private/DM/GM channels. Switch the three mention call sites (FillInPostProps, sanitizeChannelMentionsForUser, channelMentionsBroadcastHook) to the new helper. HasPermissionToReadChannel and all content-read paths are unchanged. * MM-68952: Add author-side and E2E coverage for channel mention resolution Add a Go test (TestFillInPostPropsChannelMentionResolution) that exercises the author-side persistence of the channel_mentions prop in FillInPostProps. It locks in the new behavior: an author who is a team member but not a member of a referenced public channel now persists the mention prop even when Compliance Monitoring is enabled, while public channels on other teams and private channels the author is not in are still dropped. Add a Playwright spec (channel_mention_resolution.spec.ts) with a license-free cross-team case (a public channel mention stays unresolved for a viewer not on the channel's team) and a license-gated case (with Compliance enabled, a team member who is not in the channel sees the resolved mention link). * MM-68952: Tighten channel mention test assertions and fix lint Use strings.Builder when assembling the test message to avoid the golangci-lint stringsbuilder (modernize) warning about string += string in a loop. Tighten the cross-team public and private non-member cases to assert.Nil on the resolved mentions so the contract requires no persisted channel_mentions map rather than merely an empty one. --------- Co-authored-by: Hanzo Dev <[email protected]>
221 lines
6.0 KiB
Go
221 lines
6.0 KiB
Go
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
|
|
|
// Regenerate this file using `make platform-mocks`.
|
|
|
|
package mocks
|
|
|
|
import (
|
|
model "github.com/mattermost/mattermost/server/public/model"
|
|
mock "github.com/stretchr/testify/mock"
|
|
|
|
request "github.com/mattermost/mattermost/server/public/shared/request"
|
|
)
|
|
|
|
// SuiteIFace is an autogenerated mock type for the SuiteIFace type
|
|
type SuiteIFace struct {
|
|
mock.Mock
|
|
}
|
|
|
|
// GetSession provides a mock function with given fields: token
|
|
func (_m *SuiteIFace) GetSession(token string) (*model.Session, *model.AppError) {
|
|
ret := _m.Called(token)
|
|
|
|
if len(ret) == 0 {
|
|
panic("no return value specified for GetSession")
|
|
}
|
|
|
|
var r0 *model.Session
|
|
var r1 *model.AppError
|
|
if rf, ok := ret.Get(0).(func(string) (*model.Session, *model.AppError)); ok {
|
|
return rf(token)
|
|
}
|
|
if rf, ok := ret.Get(0).(func(string) *model.Session); ok {
|
|
r0 = rf(token)
|
|
} else {
|
|
if ret.Get(0) != nil {
|
|
r0 = ret.Get(0).(*model.Session)
|
|
}
|
|
}
|
|
|
|
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
|
|
r1 = rf(token)
|
|
} else {
|
|
if ret.Get(1) != nil {
|
|
r1 = ret.Get(1).(*model.AppError)
|
|
}
|
|
}
|
|
|
|
return r0, r1
|
|
}
|
|
|
|
// HasPermissionToFileAction provides a mock function with given fields: rctx, userID, roles, channelID, action
|
|
func (_m *SuiteIFace) HasPermissionToFileAction(rctx request.CTX, userID string, roles string, channelID string, action string) bool {
|
|
ret := _m.Called(rctx, userID, roles, channelID, action)
|
|
|
|
if len(ret) == 0 {
|
|
panic("no return value specified for HasPermissionToFileAction")
|
|
}
|
|
|
|
var r0 bool
|
|
if rf, ok := ret.Get(0).(func(request.CTX, string, string, string, string) bool); ok {
|
|
r0 = rf(rctx, userID, roles, channelID, action)
|
|
} else {
|
|
r0 = ret.Get(0).(bool)
|
|
}
|
|
|
|
return r0
|
|
}
|
|
|
|
// 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(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
|
|
}
|
|
|
|
// HasPermissionToResolveChannelMention provides a mock function with given fields: rctx, userID, channel
|
|
func (_m *SuiteIFace) HasPermissionToResolveChannelMention(rctx request.CTX, userID string, channel *model.Channel) bool {
|
|
ret := _m.Called(rctx, userID, channel)
|
|
|
|
if len(ret) == 0 {
|
|
panic("no return value specified for HasPermissionToResolveChannelMention")
|
|
}
|
|
|
|
var r0 bool
|
|
if rf, ok := ret.Get(0).(func(request.CTX, string, *model.Channel) bool); ok {
|
|
r0 = rf(rctx, userID, channel)
|
|
} else {
|
|
r0 = ret.Get(0).(bool)
|
|
}
|
|
|
|
return r0
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// MFARequired provides a mock function with given fields: rctx
|
|
func (_m *SuiteIFace) MFARequired(rctx request.CTX) *model.AppError {
|
|
ret := _m.Called(rctx)
|
|
|
|
if len(ret) == 0 {
|
|
panic("no return value specified for MFARequired")
|
|
}
|
|
|
|
var r0 *model.AppError
|
|
if rf, ok := ret.Get(0).(func(request.CTX) *model.AppError); ok {
|
|
r0 = rf(rctx)
|
|
} else {
|
|
if ret.Get(0) != nil {
|
|
r0 = ret.Get(0).(*model.AppError)
|
|
}
|
|
}
|
|
|
|
return r0
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// RolesGrantPermission provides a mock function with given fields: roleNames, permissionId
|
|
func (_m *SuiteIFace) RolesGrantPermission(roleNames []string, permissionId string) bool {
|
|
ret := _m.Called(roleNames, permissionId)
|
|
|
|
if len(ret) == 0 {
|
|
panic("no return value specified for RolesGrantPermission")
|
|
}
|
|
|
|
var r0 bool
|
|
if rf, ok := ret.Get(0).(func([]string, string) bool); ok {
|
|
r0 = rf(roleNames, permissionId)
|
|
} else {
|
|
r0 = ret.Get(0).(bool)
|
|
}
|
|
|
|
return r0
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
|
|
var r0 bool
|
|
var r1 *model.AppError
|
|
if rf, ok := ret.Get(0).(func(request.CTX, string, string) (bool, *model.AppError)); ok {
|
|
return rf(rctx, userID, otherUserId)
|
|
}
|
|
if rf, ok := ret.Get(0).(func(request.CTX, string, string) bool); ok {
|
|
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(rctx, userID, otherUserId)
|
|
} else {
|
|
if ret.Get(1) != nil {
|
|
r1 = ret.Get(1).(*model.AppError)
|
|
}
|
|
}
|
|
|
|
return r0, r1
|
|
}
|
|
|
|
// NewSuiteIFace creates a new instance of SuiteIFace. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
|
// The first argument is typically a *testing.T value.
|
|
func NewSuiteIFace(t interface {
|
|
mock.TestingT
|
|
Cleanup(func())
|
|
}) *SuiteIFace {
|
|
mock := &SuiteIFace{}
|
|
mock.Mock.Test(t)
|
|
|
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
|
|
|
return mock
|
|
}
|