Channel banner permissions (#30917)
* Fixed save state panel for channel banner * Defined default background color * Updated test * WIP * wip * removed unused param * Updated tests * CI * Fixed mmctl test * Fixed TestDoAdvancedPermissionsMigration test * Test update * lint fix * lint fix --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d73222dca9
Коммит
a5e68639c2
@@ -378,9 +378,8 @@ func patchChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if patch.BannerInfo != nil {
|
if patch.BannerInfo != nil {
|
||||||
if channelBannerAppErr := canEditChannelBanner(c.App.License(), originalOldChannel); channelBannerAppErr != nil {
|
canEditChannelBanner(c, originalOldChannel)
|
||||||
channelBannerAppErr.Where = "patchChannel"
|
if c.Err != nil {
|
||||||
c.Err = channelBannerAppErr
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2459,14 +2458,23 @@ func convertGroupMessageToChannel(c *Context, w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func canEditChannelBanner(license *model.License, originalChannel *model.Channel) *model.AppError {
|
func canEditChannelBanner(c *Context, originalChannel *model.Channel) {
|
||||||
if !model.MinimumEnterpriseAdvancedLicense(license) {
|
if !model.MinimumEnterpriseAdvancedLicense(c.App.License()) {
|
||||||
return model.NewAppError("", "license_error.feature_unavailable.specific", map[string]any{"Feature": "Channel Banner"}, "feature is not available for the current license", http.StatusForbidden)
|
c.Err = model.NewAppError("patchChannel", "license_error.feature_unavailable.specific", map[string]any{"Feature": "Channel Banner"}, "feature is not available for the current license", http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
if originalChannel.Type != model.ChannelTypeOpen && originalChannel.Type != model.ChannelTypePrivate {
|
switch originalChannel.Type {
|
||||||
return model.NewAppError("", "api.channel.update_channel.banner_info.channel_type.not_allowed", nil, "", http.StatusBadRequest)
|
case model.ChannelTypePrivate:
|
||||||
|
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionManagePrivateChannelBanner) {
|
||||||
|
c.SetPermissionError(model.PermissionManagePrivateChannelBanner)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case model.ChannelTypeOpen:
|
||||||
|
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionManagePublicChannelBanner) {
|
||||||
|
c.SetPermissionError(model.PermissionManagePublicChannelBanner)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
c.Err = model.NewAppError("patchChannel", "api.channel.update_channel.banner_info.channel_type.not_allowed", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/v8/channels/web"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@@ -842,6 +844,52 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
require.Equal(t, "color", *patchedChannel.BannerInfo.BackgroundColor)
|
require.Equal(t, "color", *patchedChannel.BannerInfo.BackgroundColor)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should not be able to configure channel banner on a channel as a non-admin channel member", func(t *testing.T) {
|
||||||
|
client.Logout(context.Background())
|
||||||
|
th.LoginBasic()
|
||||||
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||||
|
defer func() {
|
||||||
|
th.App.Srv().RemoveLicense()
|
||||||
|
}()
|
||||||
|
|
||||||
|
patch := &model.ChannelPatch{
|
||||||
|
BannerInfo: &model.ChannelBannerInfo{
|
||||||
|
Enabled: model.NewPointer(true),
|
||||||
|
Text: model.NewPointer("banner text"),
|
||||||
|
BackgroundColor: model.NewPointer("color"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp, err := client.PatchChannel(context.Background(), th.BasicChannel.Id, patch)
|
||||||
|
require.Error(t, err)
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to configure channel banner as a team admin", func(t *testing.T) {
|
||||||
|
client.Logout(context.Background())
|
||||||
|
th.LoginTeamAdmin()
|
||||||
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||||
|
defer func() {
|
||||||
|
th.App.Srv().RemoveLicense()
|
||||||
|
}()
|
||||||
|
|
||||||
|
patch := &model.ChannelPatch{
|
||||||
|
BannerInfo: &model.ChannelBannerInfo{
|
||||||
|
Enabled: model.NewPointer(true),
|
||||||
|
Text: model.NewPointer("banner text"),
|
||||||
|
BackgroundColor: model.NewPointer("color"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
patchedChannel, resp, err := client.PatchChannel(context.Background(), th.BasicChannel2.Id, patch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
require.NotNil(t, patchedChannel.BannerInfo)
|
||||||
|
require.True(t, *patchedChannel.BannerInfo.Enabled)
|
||||||
|
require.Equal(t, "banner text", *patchedChannel.BannerInfo.Text)
|
||||||
|
require.Equal(t, "color", *patchedChannel.BannerInfo.BackgroundColor)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Cannot enable channel banner without configuring it", func(t *testing.T) {
|
t.Run("Cannot enable channel banner without configuring it", func(t *testing.T) {
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
@@ -958,6 +1006,147 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCanEditChannelBanner(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
t.Run("when license is nil", func(t *testing.T) {
|
||||||
|
channel := &model.Channel{
|
||||||
|
Type: model.ChannelTypeOpen,
|
||||||
|
}
|
||||||
|
|
||||||
|
th.App.Srv().SetLicense(nil)
|
||||||
|
|
||||||
|
webContext := &Context{
|
||||||
|
App: th.App,
|
||||||
|
AppContext: th.Context,
|
||||||
|
Params: &web.Params{
|
||||||
|
ChannelId: "channel_id",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
canEditChannelBanner(webContext, channel)
|
||||||
|
|
||||||
|
require.NotNil(t, webContext.Err)
|
||||||
|
assert.Equal(t, "api.context.permissions.app_error", webContext.Err.Id)
|
||||||
|
assert.Equal(t, http.StatusForbidden, webContext.Err.StatusCode)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when license is not E20 or Enterprise", func(t *testing.T) {
|
||||||
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)
|
||||||
|
th.App.Srv().SetLicense(license)
|
||||||
|
|
||||||
|
webContext := &Context{
|
||||||
|
App: th.App,
|
||||||
|
AppContext: th.Context,
|
||||||
|
Params: &web.Params{
|
||||||
|
ChannelId: "channel_id",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := &model.Channel{
|
||||||
|
Type: model.ChannelTypeOpen,
|
||||||
|
}
|
||||||
|
|
||||||
|
canEditChannelBanner(webContext, channel)
|
||||||
|
|
||||||
|
require.NotNil(t, webContext.Err)
|
||||||
|
assert.Equal(t, "api.context.permissions.app_error", webContext.Err.Id)
|
||||||
|
assert.Equal(t, http.StatusForbidden, webContext.Err.StatusCode)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when channel type is direct message", func(t *testing.T) {
|
||||||
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
||||||
|
th.App.Srv().SetLicense(license)
|
||||||
|
|
||||||
|
webContext := &Context{
|
||||||
|
App: th.App,
|
||||||
|
AppContext: th.Context,
|
||||||
|
Params: &web.Params{
|
||||||
|
ChannelId: "channel_id",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := &model.Channel{
|
||||||
|
Type: model.ChannelTypeDirect,
|
||||||
|
}
|
||||||
|
|
||||||
|
canEditChannelBanner(webContext, channel)
|
||||||
|
|
||||||
|
require.NotNil(t, webContext.Err)
|
||||||
|
assert.Equal(t, "api.channel.update_channel.banner_info.channel_type.not_allowed", webContext.Err.Id)
|
||||||
|
assert.Equal(t, http.StatusBadRequest, webContext.Err.StatusCode)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when channel type is group message", func(t *testing.T) {
|
||||||
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
||||||
|
th.App.Srv().SetLicense(license)
|
||||||
|
|
||||||
|
webContext := &Context{
|
||||||
|
App: th.App,
|
||||||
|
AppContext: th.Context,
|
||||||
|
Params: &web.Params{
|
||||||
|
ChannelId: "channel_id",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := &model.Channel{
|
||||||
|
Type: model.ChannelTypeGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
canEditChannelBanner(webContext, channel)
|
||||||
|
require.NotNil(t, webContext.Err)
|
||||||
|
assert.Equal(t, "api.channel.update_channel.banner_info.channel_type.not_allowed", webContext.Err.Id)
|
||||||
|
assert.Equal(t, http.StatusBadRequest, webContext.Err.StatusCode)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when channel type is open and license is valid", func(t *testing.T) {
|
||||||
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
||||||
|
th.App.Srv().SetLicense(license)
|
||||||
|
|
||||||
|
channel := th.CreatePublicChannel()
|
||||||
|
th.MakeUserChannelAdmin(th.BasicUser, channel)
|
||||||
|
|
||||||
|
webContext := &Context{
|
||||||
|
App: th.App,
|
||||||
|
AppContext: th.Context,
|
||||||
|
Params: &web.Params{
|
||||||
|
ChannelId: channel.Id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
webContext.AppContext = webContext.AppContext.WithSession(&model.Session{
|
||||||
|
UserId: th.BasicUser.Id,
|
||||||
|
})
|
||||||
|
|
||||||
|
canEditChannelBanner(webContext, channel)
|
||||||
|
assert.Nil(t, webContext.Err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when channel type is private and license is valid", func(t *testing.T) {
|
||||||
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
||||||
|
th.App.Srv().SetLicense(license)
|
||||||
|
|
||||||
|
channel := th.CreatePrivateChannel()
|
||||||
|
th.MakeUserChannelAdmin(th.BasicUser, channel)
|
||||||
|
|
||||||
|
webContext := &Context{
|
||||||
|
App: th.App,
|
||||||
|
AppContext: th.Context,
|
||||||
|
Params: &web.Params{
|
||||||
|
ChannelId: channel.Id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
webContext.AppContext = webContext.AppContext.WithSession(&model.Session{
|
||||||
|
UserId: th.BasicUser.Id,
|
||||||
|
})
|
||||||
|
|
||||||
|
canEditChannelBanner(webContext, channel)
|
||||||
|
assert.Nil(t, webContext.Err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestChannelUnicodeNames(t *testing.T) {
|
func TestChannelUnicodeNames(t *testing.T) {
|
||||||
th := Setup(t).InitBasic()
|
th := Setup(t).InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
@@ -5737,75 +5926,3 @@ func TestViewChannelWithoutCollapsedThreads(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Zero(t, threads.TotalUnreadMentions)
|
require.Zero(t, threads.TotalUnreadMentions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCanEditChannelBanner(t *testing.T) {
|
|
||||||
t.Run("when license is nil", func(t *testing.T) {
|
|
||||||
channel := &model.Channel{
|
|
||||||
Type: model.ChannelTypeOpen,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := canEditChannelBanner(nil, channel)
|
|
||||||
|
|
||||||
require.NotNil(t, err)
|
|
||||||
assert.Equal(t, "license_error.feature_unavailable.specific", err.Id)
|
|
||||||
assert.Equal(t, http.StatusForbidden, err.StatusCode)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("when license is not E20 or Enterprise", func(t *testing.T) {
|
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)
|
|
||||||
channel := &model.Channel{
|
|
||||||
Type: model.ChannelTypeOpen,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := canEditChannelBanner(license, channel)
|
|
||||||
|
|
||||||
require.NotNil(t, err)
|
|
||||||
assert.Equal(t, "license_error.feature_unavailable.specific", err.Id)
|
|
||||||
assert.Equal(t, http.StatusForbidden, err.StatusCode)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("when channel type is direct message", func(t *testing.T) {
|
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
|
||||||
channel := &model.Channel{
|
|
||||||
Type: model.ChannelTypeDirect,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := canEditChannelBanner(license, channel)
|
|
||||||
|
|
||||||
require.NotNil(t, err)
|
|
||||||
assert.Equal(t, "api.channel.update_channel.banner_info.channel_type.not_allowed", err.Id)
|
|
||||||
assert.Equal(t, http.StatusBadRequest, err.StatusCode)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("when channel type is group message", func(t *testing.T) {
|
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
|
||||||
channel := &model.Channel{
|
|
||||||
Type: model.ChannelTypeGroup,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := canEditChannelBanner(license, channel)
|
|
||||||
require.NotNil(t, err)
|
|
||||||
assert.Equal(t, "api.channel.update_channel.banner_info.channel_type.not_allowed", err.Id)
|
|
||||||
assert.Equal(t, http.StatusBadRequest, err.StatusCode)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("when channel type is open and license is valid", func(t *testing.T) {
|
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
|
||||||
channel := &model.Channel{
|
|
||||||
Type: model.ChannelTypeOpen,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := canEditChannelBanner(license, channel)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("when channel type is private and license is valid", func(t *testing.T) {
|
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced)
|
|
||||||
channel := &model.Channel{
|
|
||||||
Type: model.ChannelTypePrivate,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := canEditChannelBanner(license, channel)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
|||||||
model.PermissionEditBookmarkPrivateChannel.Id,
|
model.PermissionEditBookmarkPrivateChannel.Id,
|
||||||
model.PermissionDeleteBookmarkPrivateChannel.Id,
|
model.PermissionDeleteBookmarkPrivateChannel.Id,
|
||||||
model.PermissionOrderBookmarkPrivateChannel.Id,
|
model.PermissionOrderBookmarkPrivateChannel.Id,
|
||||||
|
model.PermissionManagePublicChannelBanner.Id,
|
||||||
|
model.PermissionManagePrivateChannelBanner.Id,
|
||||||
},
|
},
|
||||||
"team_user": {
|
"team_user": {
|
||||||
model.PermissionListTeamChannels.Id,
|
model.PermissionListTeamChannels.Id,
|
||||||
@@ -191,6 +193,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
|||||||
model.PermissionEditBookmarkPrivateChannel.Id,
|
model.PermissionEditBookmarkPrivateChannel.Id,
|
||||||
model.PermissionDeleteBookmarkPrivateChannel.Id,
|
model.PermissionDeleteBookmarkPrivateChannel.Id,
|
||||||
model.PermissionOrderBookmarkPrivateChannel.Id,
|
model.PermissionOrderBookmarkPrivateChannel.Id,
|
||||||
|
model.PermissionManagePublicChannelBanner.Id,
|
||||||
|
model.PermissionManagePrivateChannelBanner.Id,
|
||||||
},
|
},
|
||||||
"system_user": {
|
"system_user": {
|
||||||
model.PermissionListPublicTeams.Id,
|
model.PermissionListPublicTeams.Id,
|
||||||
|
|||||||
@@ -1173,6 +1173,22 @@ func (a *App) addSysConsoleMobileSecurityPermission() (permissionsMap, error) {
|
|||||||
return transformations, nil
|
return transformations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) getAddChannelBannerPermissionMigration() (permissionsMap, error) {
|
||||||
|
return permissionsMap{
|
||||||
|
permissionTransformation{
|
||||||
|
On: permissionOr(
|
||||||
|
isRole(model.ChannelAdminRoleId),
|
||||||
|
isRole(model.TeamAdminRoleId),
|
||||||
|
isRole(model.SystemAdminRoleId),
|
||||||
|
),
|
||||||
|
Add: []string{
|
||||||
|
model.PermissionManagePublicChannelBanner.Id,
|
||||||
|
model.PermissionManagePrivateChannelBanner.Id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Only sysadmins, team admins, and users with channels and groups managements have access to "convert channel to public"
|
// Only sysadmins, team admins, and users with channels and groups managements have access to "convert channel to public"
|
||||||
func (a *App) getRestrictAcessToChannelConversionToPublic() (permissionsMap, error) {
|
func (a *App) getRestrictAcessToChannelConversionToPublic() (permissionsMap, error) {
|
||||||
return []permissionTransformation{
|
return []permissionTransformation{
|
||||||
@@ -1243,6 +1259,7 @@ func (s *Server) doPermissionsMigrations() error {
|
|||||||
{Key: model.MigrationKeyFixReadAuditsPermission, Migration: a.getFixReadAuditsPermissionMigration},
|
{Key: model.MigrationKeyFixReadAuditsPermission, Migration: a.getFixReadAuditsPermissionMigration},
|
||||||
{Key: model.MigrationRemoveGetAnalyticsPermission, Migration: a.removeGetAnalyticsPermissionMigration},
|
{Key: model.MigrationRemoveGetAnalyticsPermission, Migration: a.removeGetAnalyticsPermissionMigration},
|
||||||
{Key: model.MigrationAddSysconsoleMobileSecurityPermission, Migration: a.addSysConsoleMobileSecurityPermission},
|
{Key: model.MigrationAddSysconsoleMobileSecurityPermission, Migration: a.addSysConsoleMobileSecurityPermission},
|
||||||
|
{Key: model.MigrationKeyAddChannelBannerPermissions, Migration: a.getAddChannelBannerPermissionMigration},
|
||||||
}
|
}
|
||||||
|
|
||||||
roles, err := s.Store().Role().GetAll()
|
roles, err := s.Store().Role().GetAll()
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ func TestHubSessionRevokeRace(t *testing.T) {
|
|||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
// We override the LastActivityAt which happens in NewWebConn.
|
// We override the LastActivityAt which happens in NewWebConn.
|
||||||
// This is needed to call RevokeSessionById which triggers the race.
|
// This is needed to call RevokeSessionById which triggers the race.
|
||||||
|
|
||||||
err = th.Service.AddSessionToCache(session)
|
err = th.Service.AddSessionToCache(session)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ func GetMockStoreForSetupFunctions() *mocks.Store {
|
|||||||
systemStore.On("GetByName", "products_boards").Return(&model.System{Name: "products_boards", Value: "true"}, nil)
|
systemStore.On("GetByName", "products_boards").Return(&model.System{Name: "products_boards", Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", "elasticsearch_fix_channel_index_migration").Return(&model.System{Name: "elasticsearch_fix_channel_index_migration", Value: "true"}, nil)
|
systemStore.On("GetByName", "elasticsearch_fix_channel_index_migration").Return(&model.System{Name: "elasticsearch_fix_channel_index_migration", Value: "true"}, nil)
|
||||||
systemStore.On("GetByName", model.MigrationAddSysconsoleMobileSecurityPermission).Return(&model.System{Name: model.MigrationAddSysconsoleMobileSecurityPermission, Value: "true"}, nil)
|
systemStore.On("GetByName", model.MigrationAddSysconsoleMobileSecurityPermission).Return(&model.System{Name: model.MigrationAddSysconsoleMobileSecurityPermission, Value: "true"}, nil)
|
||||||
|
systemStore.On("GetByName", model.MigrationKeyAddChannelBannerPermissions).Return(&model.System{Name: model.MigrationKeyAddChannelBannerPermissions, Value: "true"}, nil)
|
||||||
|
|
||||||
systemStore.On("InsertIfExists", mock.AnythingOfType("*model.System")).Return(&model.System{}, nil).Once()
|
systemStore.On("InsertIfExists", mock.AnythingOfType("*model.System")).Return(&model.System{}, nil).Once()
|
||||||
systemStore.On("Save", mock.AnythingOfType("*model.System")).Return(nil)
|
systemStore.On("Save", mock.AnythingOfType("*model.System")).Return(nil)
|
||||||
|
|
||||||
|
|||||||
@@ -246,6 +246,8 @@ func (s *MmctlUnitTestSuite) TestResetPermissionsCmd() {
|
|||||||
"edit_bookmark_private_channel",
|
"edit_bookmark_private_channel",
|
||||||
"delete_bookmark_private_channel",
|
"delete_bookmark_private_channel",
|
||||||
"order_bookmark_private_channel",
|
"order_bookmark_private_channel",
|
||||||
|
"manage_public_channel_banner",
|
||||||
|
"manage_private_channel_banner",
|
||||||
}
|
}
|
||||||
expectedPatch := &model.RolePatch{
|
expectedPatch := &model.RolePatch{
|
||||||
Permissions: &expectedPermissions,
|
Permissions: &expectedPermissions,
|
||||||
|
|||||||
@@ -54,4 +54,5 @@ const (
|
|||||||
MigrationKeyFixReadAuditsPermission = "fix_read_audits_permission"
|
MigrationKeyFixReadAuditsPermission = "fix_read_audits_permission"
|
||||||
MigrationRemoveGetAnalyticsPermission = "remove_get_analytics_permission"
|
MigrationRemoveGetAnalyticsPermission = "remove_get_analytics_permission"
|
||||||
MigrationAddSysconsoleMobileSecurityPermission = "add_sysconsole_mobile_security_permission"
|
MigrationAddSysconsoleMobileSecurityPermission = "add_sysconsole_mobile_security_permission"
|
||||||
|
MigrationKeyAddChannelBannerPermissions = "add_channel_banner_permissions"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -167,6 +167,8 @@ var PermissionGetLogs *Permission
|
|||||||
var PermissionGetAnalytics *Permission
|
var PermissionGetAnalytics *Permission
|
||||||
var PermissionReadLicenseInformation *Permission
|
var PermissionReadLicenseInformation *Permission
|
||||||
var PermissionManageLicenseInformation *Permission
|
var PermissionManageLicenseInformation *Permission
|
||||||
|
var PermissionManagePublicChannelBanner *Permission
|
||||||
|
var PermissionManagePrivateChannelBanner *Permission
|
||||||
|
|
||||||
var PermissionSysconsoleReadAbout *Permission
|
var PermissionSysconsoleReadAbout *Permission
|
||||||
var PermissionSysconsoleWriteAbout *Permission
|
var PermissionSysconsoleWriteAbout *Permission
|
||||||
@@ -1283,6 +1285,20 @@ func initializePermissions() {
|
|||||||
PermissionScopeChannel,
|
PermissionScopeChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PermissionManagePublicChannelBanner = &Permission{
|
||||||
|
"manage_public_channel_banner",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeChannel,
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionManagePrivateChannelBanner = &Permission{
|
||||||
|
"manage_private_channel_banner",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
PermissionScopeChannel,
|
||||||
|
}
|
||||||
|
|
||||||
PermissionReadOtherUsersTeams = &Permission{
|
PermissionReadOtherUsersTeams = &Permission{
|
||||||
"read_other_users_teams",
|
"read_other_users_teams",
|
||||||
"authentication.permissions.read_other_users_teams.name",
|
"authentication.permissions.read_other_users_teams.name",
|
||||||
@@ -2520,6 +2536,8 @@ func initializePermissions() {
|
|||||||
PermissionEditBookmarkPrivateChannel,
|
PermissionEditBookmarkPrivateChannel,
|
||||||
PermissionDeleteBookmarkPrivateChannel,
|
PermissionDeleteBookmarkPrivateChannel,
|
||||||
PermissionOrderBookmarkPrivateChannel,
|
PermissionOrderBookmarkPrivateChannel,
|
||||||
|
PermissionManagePublicChannelBanner,
|
||||||
|
PermissionManagePrivateChannelBanner,
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupScopedPermissions := []*Permission{
|
GroupScopedPermissions := []*Permission{
|
||||||
|
|||||||
@@ -914,6 +914,8 @@ func MakeDefaultRoles() map[string]*Role {
|
|||||||
PermissionEditBookmarkPrivateChannel.Id,
|
PermissionEditBookmarkPrivateChannel.Id,
|
||||||
PermissionDeleteBookmarkPrivateChannel.Id,
|
PermissionDeleteBookmarkPrivateChannel.Id,
|
||||||
PermissionOrderBookmarkPrivateChannel.Id,
|
PermissionOrderBookmarkPrivateChannel.Id,
|
||||||
|
PermissionManagePublicChannelBanner.Id,
|
||||||
|
PermissionManagePrivateChannelBanner.Id,
|
||||||
},
|
},
|
||||||
SchemeManaged: true,
|
SchemeManaged: true,
|
||||||
BuiltIn: true,
|
BuiltIn: true,
|
||||||
@@ -1000,6 +1002,8 @@ func MakeDefaultRoles() map[string]*Role {
|
|||||||
PermissionEditBookmarkPrivateChannel.Id,
|
PermissionEditBookmarkPrivateChannel.Id,
|
||||||
PermissionDeleteBookmarkPrivateChannel.Id,
|
PermissionDeleteBookmarkPrivateChannel.Id,
|
||||||
PermissionOrderBookmarkPrivateChannel.Id,
|
PermissionOrderBookmarkPrivateChannel.Id,
|
||||||
|
PermissionManagePublicChannelBanner.Id,
|
||||||
|
PermissionManagePrivateChannelBanner.Id,
|
||||||
},
|
},
|
||||||
SchemeManaged: true,
|
SchemeManaged: true,
|
||||||
BuiltIn: true,
|
BuiltIn: true,
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ export default class PermissionGroup extends React.PureComponent<Props, State> {
|
|||||||
if (!this.isInScope(permission)) {
|
if (!this.isInScope(permission)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const comesFromParent = this.fromParent(permission);
|
const comesFromParent = this.fromParent(permission);
|
||||||
const active = comesFromParent || this.props.role?.permissions?.indexOf(permission) !== -1;
|
const active = comesFromParent || this.props.role?.permissions?.indexOf(permission) !== -1;
|
||||||
const inherited = comesFromParent ? this.props.parentRole : undefined;
|
const inherited = comesFromParent ? this.props.parentRole : undefined;
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ class PermissionSystemSchemeSettings extends React.PureComponent<Props, State> {
|
|||||||
if (!this.state.loaded) {
|
if (!this.state.loaded) {
|
||||||
return <LoadingScreen/>;
|
return <LoadingScreen/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLicensed = this.props.license?.IsLicensed === 'true';
|
const isLicensed = this.props.license?.IsLicensed === 'true';
|
||||||
return (
|
return (
|
||||||
<div className='wrapper--fixed'>
|
<div className='wrapper--fixed'>
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import type {Role} from '@mattermost/types/roles';
|
|||||||
import GeneralConstants from 'mattermost-redux/constants/general';
|
import GeneralConstants from 'mattermost-redux/constants/general';
|
||||||
import Permissions from 'mattermost-redux/constants/permissions';
|
import Permissions from 'mattermost-redux/constants/permissions';
|
||||||
|
|
||||||
import {isEnterpriseLicense, isNonEnterpriseLicense} from 'utils/license_utils';
|
import {
|
||||||
|
isEnterpriseLicense,
|
||||||
|
isMinimumEnterpriseAdvancedLicense,
|
||||||
|
isNonEnterpriseLicense,
|
||||||
|
} from 'utils/license_utils';
|
||||||
|
|
||||||
import type {AdditionalValues, Group} from './types';
|
import type {AdditionalValues, Group} from './types';
|
||||||
|
|
||||||
@@ -286,6 +290,11 @@ export default class PermissionsTree extends React.PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMinimumEnterpriseAdvancedLicense(license)) {
|
||||||
|
publicChannelsGroup.permissions.push(Permissions.MANAGE_PUBLIC_CHANNEL_BANNER);
|
||||||
|
privateChannelsGroup.permissions.push(Permissions.MANAGE_PRIVATE_CHANNEL_BANNER);
|
||||||
|
}
|
||||||
|
|
||||||
this.groups = this.groups.filter((group) => {
|
this.groups = this.groups.filter((group) => {
|
||||||
if (group.isVisible) {
|
if (group.isVisible) {
|
||||||
return group.isVisible(this.props.license);
|
return group.isVisible(this.props.license);
|
||||||
|
|||||||
@@ -625,4 +625,24 @@ export const permissionRolesStrings: Record<string, Record<string, MessageDescri
|
|||||||
defaultMessage: 'Create, edit, and delete outgoing OAuth credentials.',
|
defaultMessage: 'Create, edit, and delete outgoing OAuth credentials.',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
manage_public_channel_banner: defineMessages({
|
||||||
|
name: {
|
||||||
|
id: 'admin.permissions.permission.manage_public_channel_banner.name',
|
||||||
|
defaultMessage: 'Manage Channel Banner',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
id: 'admin.permissions.permission.manage_public_channel_banner.description',
|
||||||
|
defaultMessage: 'Enable, disable and edit channel banner.',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
manage_private_channel_banner: defineMessages({
|
||||||
|
name: {
|
||||||
|
id: 'admin.permissions.permission.manage_private_channel_banner.name',
|
||||||
|
defaultMessage: 'Manage Channel Banner',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
id: 'admin.permissions.permission.manage_private_channel_banner.description',
|
||||||
|
defaultMessage: 'Enable, disable and edit channel banner.',
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,7 +54,17 @@ function ChannelSettingsModal({channelId, isOpen, onExited, focusOriginElement}:
|
|||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const channel = useSelector((state: GlobalState) => getChannel(state, channelId)) as Channel;
|
const channel = useSelector((state: GlobalState) => getChannel(state, channelId)) as Channel;
|
||||||
const shouldShowConfigurationTab = useSelector(selectChannelBannerEnabled);
|
const channelBannerEnabled = useSelector(selectChannelBannerEnabled);
|
||||||
|
|
||||||
|
const canManagePublicChannelBanner = useSelector((state: GlobalState) =>
|
||||||
|
haveIChannelPermission(state, channel.team_id, channel.id, Permissions.MANAGE_PUBLIC_CHANNEL_BANNER),
|
||||||
|
);
|
||||||
|
const canManagePrivateChannelBanner = useSelector((state: GlobalState) =>
|
||||||
|
haveIChannelPermission(state, channel.team_id, channel.id, Permissions.MANAGE_PRIVATE_CHANNEL_BANNER),
|
||||||
|
);
|
||||||
|
const hasManageChannelBannerPermission = (channel.type === 'O' && canManagePublicChannelBanner) || (channel.type === 'P' && canManagePrivateChannelBanner);
|
||||||
|
|
||||||
|
const shouldShowConfigurationTab = channelBannerEnabled && hasManageChannelBannerPermission;
|
||||||
|
|
||||||
const canArchivePrivateChannels = useSelector((state: GlobalState) =>
|
const canArchivePrivateChannels = useSelector((state: GlobalState) =>
|
||||||
haveIChannelPermission(state, channel.team_id, channel.id, Permissions.DELETE_PRIVATE_CHANNEL),
|
haveIChannelPermission(state, channel.team_id, channel.id, Permissions.DELETE_PRIVATE_CHANNEL),
|
||||||
|
|||||||
@@ -1749,8 +1749,12 @@
|
|||||||
"admin.permissions.permission.manage_outgoing_oauth_connections.name": "Manage Outgoing OAuth Credentials",
|
"admin.permissions.permission.manage_outgoing_oauth_connections.name": "Manage Outgoing OAuth Credentials",
|
||||||
"admin.permissions.permission.manage_outgoing_webhooks.description": "Create, edit, and delete outgoing webhooks.",
|
"admin.permissions.permission.manage_outgoing_webhooks.description": "Create, edit, and delete outgoing webhooks.",
|
||||||
"admin.permissions.permission.manage_outgoing_webhooks.name": "Manage Outgoing Webhooks",
|
"admin.permissions.permission.manage_outgoing_webhooks.name": "Manage Outgoing Webhooks",
|
||||||
|
"admin.permissions.permission.manage_private_channel_banner.description": "Enable, disable and edit channel banner.",
|
||||||
|
"admin.permissions.permission.manage_private_channel_banner.name": "Manage Channel Banner",
|
||||||
"admin.permissions.permission.manage_private_channel_properties.description": "Update private channel names, headers and purposes.",
|
"admin.permissions.permission.manage_private_channel_properties.description": "Update private channel names, headers and purposes.",
|
||||||
"admin.permissions.permission.manage_private_channel_properties.name": "Manage Channel Settings",
|
"admin.permissions.permission.manage_private_channel_properties.name": "Manage Channel Settings",
|
||||||
|
"admin.permissions.permission.manage_public_channel_banner.description": "Enable, disable and edit channel banner.",
|
||||||
|
"admin.permissions.permission.manage_public_channel_banner.name": "Manage Channel Banner",
|
||||||
"admin.permissions.permission.manage_public_channel_properties.description": "Update public channel names, headers and purposes.",
|
"admin.permissions.permission.manage_public_channel_properties.description": "Update public channel names, headers and purposes.",
|
||||||
"admin.permissions.permission.manage_public_channel_properties.name": "Manage Channel Settings",
|
"admin.permissions.permission.manage_public_channel_properties.name": "Manage Channel Settings",
|
||||||
"admin.permissions.permission.manage_roles.description": "Manage roles",
|
"admin.permissions.permission.manage_roles.description": "Manage roles",
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ const values = {
|
|||||||
DELETE_PUBLIC_CHANNEL: 'delete_public_channel',
|
DELETE_PUBLIC_CHANNEL: 'delete_public_channel',
|
||||||
CONVERT_PUBLIC_CHANNEL_TO_PRIVATE: 'convert_public_channel_to_private',
|
CONVERT_PUBLIC_CHANNEL_TO_PRIVATE: 'convert_public_channel_to_private',
|
||||||
CONVERT_PRIVATE_CHANNEL_TO_PUBLIC: 'convert_private_channel_to_public',
|
CONVERT_PRIVATE_CHANNEL_TO_PUBLIC: 'convert_private_channel_to_public',
|
||||||
|
MANAGE_PUBLIC_CHANNEL_BANNER: 'manage_public_channel_banner',
|
||||||
|
MANAGE_PRIVATE_CHANNEL_BANNER: 'manage_private_channel_banner',
|
||||||
DELETE_PRIVATE_CHANNEL: 'delete_private_channel',
|
DELETE_PRIVATE_CHANNEL: 'delete_private_channel',
|
||||||
EDIT_OTHER_USERS: 'edit_other_users',
|
EDIT_OTHER_USERS: 'edit_other_users',
|
||||||
READ_CHANNEL: 'read_channel',
|
READ_CHANNEL: 'read_channel',
|
||||||
|
|||||||
@@ -1307,6 +1307,8 @@ export const PermissionsScope = {
|
|||||||
[Permissions.EDIT_BOOKMARK_PRIVATE_CHANNEL]: 'channel_scope',
|
[Permissions.EDIT_BOOKMARK_PRIVATE_CHANNEL]: 'channel_scope',
|
||||||
[Permissions.DELETE_BOOKMARK_PRIVATE_CHANNEL]: 'channel_scope',
|
[Permissions.DELETE_BOOKMARK_PRIVATE_CHANNEL]: 'channel_scope',
|
||||||
[Permissions.ORDER_BOOKMARK_PRIVATE_CHANNEL]: 'channel_scope',
|
[Permissions.ORDER_BOOKMARK_PRIVATE_CHANNEL]: 'channel_scope',
|
||||||
|
[Permissions.MANAGE_PUBLIC_CHANNEL_BANNER]: 'channel_scope',
|
||||||
|
[Permissions.MANAGE_PRIVATE_CHANNEL_BANNER]: 'channel_scope',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DefaultRolePermissions = {
|
export const DefaultRolePermissions = {
|
||||||
@@ -1386,6 +1388,8 @@ export const DefaultRolePermissions = {
|
|||||||
Permissions.EDIT_BOOKMARK_PRIVATE_CHANNEL,
|
Permissions.EDIT_BOOKMARK_PRIVATE_CHANNEL,
|
||||||
Permissions.DELETE_BOOKMARK_PRIVATE_CHANNEL,
|
Permissions.DELETE_BOOKMARK_PRIVATE_CHANNEL,
|
||||||
Permissions.ORDER_BOOKMARK_PRIVATE_CHANNEL,
|
Permissions.ORDER_BOOKMARK_PRIVATE_CHANNEL,
|
||||||
|
Permissions.MANAGE_PUBLIC_CHANNEL_BANNER,
|
||||||
|
Permissions.MANAGE_PRIVATE_CHANNEL_BANNER,
|
||||||
],
|
],
|
||||||
team_admin: [
|
team_admin: [
|
||||||
Permissions.EDIT_OTHERS_POSTS,
|
Permissions.EDIT_OTHERS_POSTS,
|
||||||
@@ -1421,6 +1425,8 @@ export const DefaultRolePermissions = {
|
|||||||
Permissions.EDIT_BOOKMARK_PRIVATE_CHANNEL,
|
Permissions.EDIT_BOOKMARK_PRIVATE_CHANNEL,
|
||||||
Permissions.DELETE_BOOKMARK_PRIVATE_CHANNEL,
|
Permissions.DELETE_BOOKMARK_PRIVATE_CHANNEL,
|
||||||
Permissions.ORDER_BOOKMARK_PRIVATE_CHANNEL,
|
Permissions.ORDER_BOOKMARK_PRIVATE_CHANNEL,
|
||||||
|
Permissions.MANAGE_PUBLIC_CHANNEL_BANNER,
|
||||||
|
Permissions.MANAGE_PRIVATE_CHANNEL_BANNER,
|
||||||
],
|
],
|
||||||
guests: [
|
guests: [
|
||||||
Permissions.EDIT_POST,
|
Permissions.EDIT_POST,
|
||||||
|
|||||||
@@ -128,3 +128,11 @@ export function isMinimumEnterpriseLicense(license: ClientLicense): boolean {
|
|||||||
|
|
||||||
return getLicenseTier(license.SkuShortName) >= getLicenseTier(LicenseSkus.Enterprise);
|
return getLicenseTier(license.SkuShortName) >= getLicenseTier(LicenseSkus.Enterprise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isMinimumEnterpriseAdvancedLicense(license?: ClientLicense): boolean {
|
||||||
|
if (!license) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLicenseTier(license.SkuShortName) >= getLicenseTier(LicenseSkus.EnterpriseAdvanced);
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user