Merge branch 'advanced-permissions-phase-1'
Этот коммит содержится в:
60
app/app.go
60
app/app.go
@@ -8,6 +8,7 @@ import (
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -26,6 +27,8 @@ import (
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
)
|
||||
|
||||
const ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete"
|
||||
|
||||
type App struct {
|
||||
goroutineCount int32
|
||||
goroutineExitSignal chan struct{}
|
||||
@@ -71,7 +74,6 @@ type App struct {
|
||||
|
||||
htmlTemplateWatcher *utils.HTMLTemplateWatcher
|
||||
sessionCache *utils.Cache
|
||||
roles map[string]*model.Role
|
||||
configListenerId string
|
||||
licenseListenerId string
|
||||
disableConfigWatch bool
|
||||
@@ -155,7 +157,6 @@ func New(options ...Option) (outApp *App, outErr error) {
|
||||
|
||||
})
|
||||
app.regenerateClientConfig()
|
||||
app.setDefaultRolesBasedOnConfig()
|
||||
|
||||
l4g.Info(utils.T("api.server.new_server.init.info"))
|
||||
|
||||
@@ -196,7 +197,6 @@ func New(options ...Option) (outApp *App, outErr error) {
|
||||
|
||||
func (a *App) configOrLicenseListener() {
|
||||
a.regenerateClientConfig()
|
||||
a.setDefaultRolesBasedOnConfig()
|
||||
}
|
||||
|
||||
func (a *App) Shutdown() {
|
||||
@@ -495,3 +495,57 @@ func (a *App) Handle404(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
utils.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
|
||||
}
|
||||
|
||||
// This function migrates the default built in roles from code/config to the database.
|
||||
func (a *App) DoAdvancedPermissionsMigration() {
|
||||
// If the migration is already marked as completed, don't do it again.
|
||||
if result := <-a.Srv.Store.System().GetByName(ADVANCED_PERMISSIONS_MIGRATION_KEY); result.Err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l4g.Info("Migrating roles to database.")
|
||||
roles := model.MakeDefaultRoles()
|
||||
roles = utils.SetRolePermissionsFromConfig(roles, a.Config(), a.License() != nil)
|
||||
|
||||
allSucceeded := true
|
||||
|
||||
for _, role := range roles {
|
||||
if result := <-a.Srv.Store.Role().Save(role); result.Err != nil {
|
||||
// If this failed for reasons other than the role already existing, don't mark the migration as done.
|
||||
if result2 := <-a.Srv.Store.Role().GetByName(role.Name); result2.Err != nil {
|
||||
l4g.Critical("Failed to migrate role to database.")
|
||||
l4g.Critical(result.Err)
|
||||
allSucceeded = false
|
||||
} else {
|
||||
// If the role already existed, check it is the same and update if not.
|
||||
fetchedRole := result.Data.(*model.Role)
|
||||
if !reflect.DeepEqual(fetchedRole.Permissions, role.Permissions) ||
|
||||
fetchedRole.DisplayName != role.DisplayName ||
|
||||
fetchedRole.Description != role.Description ||
|
||||
fetchedRole.SchemeManaged != role.SchemeManaged {
|
||||
role.Id = fetchedRole.Id
|
||||
if result := <-a.Srv.Store.Role().Save(role); result.Err != nil {
|
||||
// Role is not the same, but failed to update.
|
||||
l4g.Critical("Failed to migrate role to database.")
|
||||
l4g.Critical(result.Err)
|
||||
allSucceeded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !allSucceeded {
|
||||
return
|
||||
}
|
||||
|
||||
system := model.System{
|
||||
Name: ADVANCED_PERMISSIONS_MIGRATION_KEY,
|
||||
Value: "true",
|
||||
}
|
||||
|
||||
if result := <-a.Srv.Store.System().Save(&system); result.Err != nil {
|
||||
l4g.Critical("Failed to mark advanced permissions migration as completed.")
|
||||
l4g.Critical(result.Err)
|
||||
}
|
||||
}
|
||||
|
||||
345
app/app_test.go
345
app/app_test.go
@@ -5,11 +5,11 @@ package app
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -72,3 +72,346 @@ func TestUpdateConfig(t *testing.T) {
|
||||
*cfg.ServiceSettings.SiteURL = "foo"
|
||||
})
|
||||
}
|
||||
|
||||
func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
||||
th := Setup()
|
||||
defer th.TearDown()
|
||||
|
||||
if testStoreSqlSupplier == nil {
|
||||
t.Skip("This test requires a TestStore to be run.")
|
||||
}
|
||||
|
||||
th.ResetRoleMigration()
|
||||
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
|
||||
roleNames := []string{
|
||||
"system_user",
|
||||
"system_admin",
|
||||
"team_user",
|
||||
"team_admin",
|
||||
"channel_user",
|
||||
"channel_admin",
|
||||
"system_post_all",
|
||||
"system_post_all_public",
|
||||
"system_user_access_token",
|
||||
"team_post_all",
|
||||
"team_post_all_public",
|
||||
}
|
||||
|
||||
roles1, err1 := th.App.GetRolesByNames(roleNames)
|
||||
assert.Nil(t, err1)
|
||||
assert.Equal(t, len(roles1), len(roleNames))
|
||||
|
||||
expected1 := map[string][]string{
|
||||
"channel_user": []string{
|
||||
model.PERMISSION_READ_CHANNEL.Id,
|
||||
model.PERMISSION_ADD_REACTION.Id,
|
||||
model.PERMISSION_REMOVE_REACTION.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_UPLOAD_FILE.Id,
|
||||
model.PERMISSION_GET_PUBLIC_LINK.Id,
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
model.PERMISSION_USE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_DELETE_POST.Id,
|
||||
model.PERMISSION_EDIT_POST.Id,
|
||||
},
|
||||
"channel_admin": []string{
|
||||
model.PERMISSION_MANAGE_CHANNEL_ROLES.Id,
|
||||
},
|
||||
"team_user": []string{
|
||||
model.PERMISSION_LIST_TEAM_CHANNELS.Id,
|
||||
model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
|
||||
model.PERMISSION_READ_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_VIEW_TEAM.Id,
|
||||
model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_INVITE_USER.Id,
|
||||
model.PERMISSION_ADD_USER_TO_TEAM.Id,
|
||||
},
|
||||
"team_post_all": []string{
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
},
|
||||
"team_post_all_public": []string{
|
||||
model.PERMISSION_CREATE_POST_PUBLIC.Id,
|
||||
},
|
||||
"team_admin": []string{
|
||||
model.PERMISSION_EDIT_OTHERS_POSTS.Id,
|
||||
model.PERMISSION_REMOVE_USER_FROM_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM.Id,
|
||||
model.PERMISSION_IMPORT_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_CHANNEL_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
|
||||
model.PERMISSION_MANAGE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_WEBHOOKS.Id,
|
||||
model.PERMISSION_DELETE_POST.Id,
|
||||
model.PERMISSION_DELETE_OTHERS_POSTS.Id,
|
||||
},
|
||||
"system_user": []string{
|
||||
model.PERMISSION_CREATE_DIRECT_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_GROUP_CHANNEL.Id,
|
||||
model.PERMISSION_PERMANENT_DELETE_USER.Id,
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
},
|
||||
"system_post_all": []string{
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
},
|
||||
"system_post_all_public": []string{
|
||||
model.PERMISSION_CREATE_POST_PUBLIC.Id,
|
||||
},
|
||||
"system_user_access_token": []string{
|
||||
model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_READ_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
|
||||
},
|
||||
"system_admin": []string{
|
||||
model.PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id,
|
||||
model.PERMISSION_MANAGE_SYSTEM.Id,
|
||||
model.PERMISSION_MANAGE_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
|
||||
model.PERMISSION_EDIT_OTHER_USERS.Id,
|
||||
model.PERMISSION_MANAGE_OAUTH.Id,
|
||||
model.PERMISSION_INVITE_USER.Id,
|
||||
model.PERMISSION_DELETE_POST.Id,
|
||||
model.PERMISSION_DELETE_OTHERS_POSTS.Id,
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
model.PERMISSION_ADD_USER_TO_TEAM.Id,
|
||||
model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_JOBS.Id,
|
||||
model.PERMISSION_CREATE_POST_PUBLIC.Id,
|
||||
model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_READ_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
|
||||
model.PERMISSION_LIST_TEAM_CHANNELS.Id,
|
||||
model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
|
||||
model.PERMISSION_READ_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_VIEW_TEAM.Id,
|
||||
model.PERMISSION_READ_CHANNEL.Id,
|
||||
model.PERMISSION_ADD_REACTION.Id,
|
||||
model.PERMISSION_REMOVE_REACTION.Id,
|
||||
model.PERMISSION_UPLOAD_FILE.Id,
|
||||
model.PERMISSION_GET_PUBLIC_LINK.Id,
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
model.PERMISSION_USE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_EDIT_OTHERS_POSTS.Id,
|
||||
model.PERMISSION_REMOVE_USER_FROM_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM.Id,
|
||||
model.PERMISSION_IMPORT_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_CHANNEL_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_WEBHOOKS.Id,
|
||||
model.PERMISSION_EDIT_POST.Id,
|
||||
},
|
||||
}
|
||||
|
||||
// Check the migration matches what's expected.
|
||||
for name, permissions := range expected1 {
|
||||
role, err := th.App.GetRoleByName(name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, role.Permissions, permissions)
|
||||
}
|
||||
|
||||
// Add a license and change the policy config.
|
||||
restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
|
||||
restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
|
||||
|
||||
defer func() {
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
|
||||
}()
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_TEAM_ADMIN
|
||||
})
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_TEAM_ADMIN
|
||||
})
|
||||
th.App.SetLicense(model.NewTestLicense())
|
||||
|
||||
// Check the migration doesn't change anything if run again.
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
|
||||
roles2, err2 := th.App.GetRolesByNames(roleNames)
|
||||
assert.Nil(t, err2)
|
||||
assert.Equal(t, len(roles2), len(roleNames))
|
||||
|
||||
for name, permissions := range expected1 {
|
||||
role, err := th.App.GetRoleByName(name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, permissions, role.Permissions)
|
||||
}
|
||||
|
||||
// Reset the database
|
||||
th.ResetRoleMigration()
|
||||
|
||||
// Do the migration again with different policy config settings and a license.
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
|
||||
// Check the role permissions.
|
||||
expected2 := map[string][]string{
|
||||
"channel_user": []string{
|
||||
model.PERMISSION_READ_CHANNEL.Id,
|
||||
model.PERMISSION_ADD_REACTION.Id,
|
||||
model.PERMISSION_REMOVE_REACTION.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_UPLOAD_FILE.Id,
|
||||
model.PERMISSION_GET_PUBLIC_LINK.Id,
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
model.PERMISSION_USE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_DELETE_POST.Id,
|
||||
model.PERMISSION_EDIT_POST.Id,
|
||||
},
|
||||
"channel_admin": []string{
|
||||
model.PERMISSION_MANAGE_CHANNEL_ROLES.Id,
|
||||
},
|
||||
"team_user": []string{
|
||||
model.PERMISSION_LIST_TEAM_CHANNELS.Id,
|
||||
model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
|
||||
model.PERMISSION_READ_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_VIEW_TEAM.Id,
|
||||
model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_INVITE_USER.Id,
|
||||
model.PERMISSION_ADD_USER_TO_TEAM.Id,
|
||||
},
|
||||
"team_post_all": []string{
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
},
|
||||
"team_post_all_public": []string{
|
||||
model.PERMISSION_CREATE_POST_PUBLIC.Id,
|
||||
},
|
||||
"team_admin": []string{
|
||||
model.PERMISSION_EDIT_OTHERS_POSTS.Id,
|
||||
model.PERMISSION_REMOVE_USER_FROM_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM.Id,
|
||||
model.PERMISSION_IMPORT_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_CHANNEL_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
|
||||
model.PERMISSION_MANAGE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_WEBHOOKS.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_DELETE_POST.Id,
|
||||
model.PERMISSION_DELETE_OTHERS_POSTS.Id,
|
||||
},
|
||||
"system_user": []string{
|
||||
model.PERMISSION_CREATE_DIRECT_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_GROUP_CHANNEL.Id,
|
||||
model.PERMISSION_PERMANENT_DELETE_USER.Id,
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
},
|
||||
"system_post_all": []string{
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
},
|
||||
"system_post_all_public": []string{
|
||||
model.PERMISSION_CREATE_POST_PUBLIC.Id,
|
||||
},
|
||||
"system_user_access_token": []string{
|
||||
model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_READ_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
|
||||
},
|
||||
"system_admin": []string{
|
||||
model.PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id,
|
||||
model.PERMISSION_MANAGE_SYSTEM.Id,
|
||||
model.PERMISSION_MANAGE_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
|
||||
model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
|
||||
model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
|
||||
model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
|
||||
model.PERMISSION_EDIT_OTHER_USERS.Id,
|
||||
model.PERMISSION_MANAGE_OAUTH.Id,
|
||||
model.PERMISSION_INVITE_USER.Id,
|
||||
model.PERMISSION_DELETE_POST.Id,
|
||||
model.PERMISSION_DELETE_OTHERS_POSTS.Id,
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
model.PERMISSION_ADD_USER_TO_TEAM.Id,
|
||||
model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_JOBS.Id,
|
||||
model.PERMISSION_CREATE_POST_PUBLIC.Id,
|
||||
model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_READ_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
|
||||
model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
|
||||
model.PERMISSION_LIST_TEAM_CHANNELS.Id,
|
||||
model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
|
||||
model.PERMISSION_READ_PUBLIC_CHANNEL.Id,
|
||||
model.PERMISSION_VIEW_TEAM.Id,
|
||||
model.PERMISSION_READ_CHANNEL.Id,
|
||||
model.PERMISSION_ADD_REACTION.Id,
|
||||
model.PERMISSION_REMOVE_REACTION.Id,
|
||||
model.PERMISSION_UPLOAD_FILE.Id,
|
||||
model.PERMISSION_GET_PUBLIC_LINK.Id,
|
||||
model.PERMISSION_CREATE_POST.Id,
|
||||
model.PERMISSION_USE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_EDIT_OTHERS_POSTS.Id,
|
||||
model.PERMISSION_REMOVE_USER_FROM_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM.Id,
|
||||
model.PERMISSION_IMPORT_TEAM.Id,
|
||||
model.PERMISSION_MANAGE_TEAM_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_CHANNEL_ROLES.Id,
|
||||
model.PERMISSION_MANAGE_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
|
||||
model.PERMISSION_MANAGE_WEBHOOKS.Id,
|
||||
model.PERMISSION_EDIT_POST.Id,
|
||||
},
|
||||
}
|
||||
|
||||
roles3, err3 := th.App.GetRolesByNames(roleNames)
|
||||
assert.Nil(t, err3)
|
||||
assert.Equal(t, len(roles3), len(roleNames))
|
||||
|
||||
for name, permissions := range expected2 {
|
||||
role, err := th.App.GetRoleByName(name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, permissions, role.Permissions, fmt.Sprintf("'%v' did not have expected permissions", name))
|
||||
}
|
||||
|
||||
// Remove the license.
|
||||
th.App.SetLicense(nil)
|
||||
|
||||
// Do the migration again.
|
||||
th.ResetRoleMigration()
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
|
||||
// Check the role permissions.
|
||||
roles4, err4 := th.App.GetRolesByNames(roleNames)
|
||||
assert.Nil(t, err4)
|
||||
assert.Equal(t, len(roles4), len(roleNames))
|
||||
|
||||
for name, permissions := range expected1 {
|
||||
role, err := th.App.GetRoleByName(name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, permissions, role.Permissions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
|
||||
"github.com/mattermost/mattermost-server/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/plugin"
|
||||
"github.com/mattermost/mattermost-server/plugin/pluginenv"
|
||||
@@ -43,12 +44,16 @@ func (*persistentTestStore) Close() {}
|
||||
|
||||
var testStoreContainer *storetest.RunningContainer
|
||||
var testStore *persistentTestStore
|
||||
var testStoreSqlSupplier *sqlstore.SqlSupplier
|
||||
var testClusterInterface *FakeClusterInterface
|
||||
|
||||
// UseTestStore sets the container and corresponding settings to use for tests. Once the tests are
|
||||
// complete (e.g. at the end of your TestMain implementation), you should call StopTestStore.
|
||||
func UseTestStore(container *storetest.RunningContainer, settings *model.SqlSettings) {
|
||||
testClusterInterface = &FakeClusterInterface{}
|
||||
testStoreContainer = container
|
||||
testStore = &persistentTestStore{store.NewLayeredStore(sqlstore.NewSqlSupplier(*settings, nil), nil, nil)}
|
||||
testStoreSqlSupplier = sqlstore.NewSqlSupplier(*settings, nil)
|
||||
testStore = &persistentTestStore{store.NewLayeredStore(testStoreSqlSupplier, nil, testClusterInterface)}
|
||||
}
|
||||
|
||||
func StopTestStore() {
|
||||
@@ -102,6 +107,9 @@ func setupTestHelper(enterprise bool) *TestHelper {
|
||||
}
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
|
||||
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
|
||||
th.App.Srv.Store.MarkSystemRanUnitTests()
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
|
||||
@@ -217,6 +225,7 @@ func (me *TestHelper) CreatePost(channel *model.Channel) *model.Post {
|
||||
UserId: me.BasicUser.Id,
|
||||
ChannelId: channel.Id,
|
||||
Message: "message_" + id,
|
||||
CreateAt: model.GetMillis() - 10000,
|
||||
}
|
||||
|
||||
utils.DisableDebugLogForTest()
|
||||
@@ -326,3 +335,45 @@ func (me *TestHelper) InstallPlugin(manifest *model.Manifest, hooks plugin.Hooks
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *TestHelper) ResetRoleMigration() {
|
||||
if _, err := testStoreSqlSupplier.GetMaster().Exec("DELETE from Roles"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testClusterInterface.sendClearRoleCacheMessage()
|
||||
|
||||
if _, err := testStoreSqlSupplier.GetMaster().Exec("DELETE from Systems where Name = :Name", map[string]interface{}{"Name": ADVANCED_PERMISSIONS_MIGRATION_KEY}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type FakeClusterInterface struct {
|
||||
clusterMessageHandler einterfaces.ClusterMessageHandler
|
||||
}
|
||||
|
||||
func (me *FakeClusterInterface) StartInterNodeCommunication() {}
|
||||
func (me *FakeClusterInterface) StopInterNodeCommunication() {}
|
||||
func (me *FakeClusterInterface) RegisterClusterMessageHandler(event string, crm einterfaces.ClusterMessageHandler) {
|
||||
me.clusterMessageHandler = crm
|
||||
}
|
||||
func (me *FakeClusterInterface) GetClusterId() string { return "" }
|
||||
func (me *FakeClusterInterface) IsLeader() bool { return false }
|
||||
func (me *FakeClusterInterface) GetMyClusterInfo() *model.ClusterInfo { return nil }
|
||||
func (me *FakeClusterInterface) GetClusterInfos() []*model.ClusterInfo { return nil }
|
||||
func (me *FakeClusterInterface) SendClusterMessage(cluster *model.ClusterMessage) {}
|
||||
func (me *FakeClusterInterface) NotifyMsg(buf []byte) {}
|
||||
func (me *FakeClusterInterface) GetClusterStats() ([]*model.ClusterStats, *model.AppError) {
|
||||
return nil, nil
|
||||
}
|
||||
func (me *FakeClusterInterface) GetLogs(page, perPage int) ([]string, *model.AppError) {
|
||||
return []string{}, nil
|
||||
}
|
||||
func (me *FakeClusterInterface) ConfigChanged(previousConfig *model.Config, newConfig *model.Config, sendToOtherServer bool) *model.AppError {
|
||||
return nil
|
||||
}
|
||||
func (me *FakeClusterInterface) sendClearRoleCacheMessage() {
|
||||
me.clusterMessageHandler(&model.ClusterMessage{
|
||||
Event: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func (a *App) SessionHasPermissionTo(session model.Session, permission *model.Permission) bool {
|
||||
if !a.CheckIfRolesGrantPermission(session.GetUserRoles(), permission.Id) {
|
||||
if !a.RolesGrantPermission(session.GetUserRoles(), permission.Id) {
|
||||
a.ClearSessionCacheForUser(session.UserId)
|
||||
return false
|
||||
}
|
||||
@@ -28,12 +28,12 @@ func (a *App) SessionHasPermissionToTeam(session model.Session, teamId string, p
|
||||
|
||||
teamMember := session.GetTeamByTeamId(teamId)
|
||||
if teamMember != nil {
|
||||
if a.CheckIfRolesGrantPermission(teamMember.GetRoles(), permission.Id) {
|
||||
if a.RolesGrantPermission(teamMember.GetRoles(), permission.Id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return a.CheckIfRolesGrantPermission(session.GetUserRoles(), permission.Id)
|
||||
return a.RolesGrantPermission(session.GetUserRoles(), permission.Id)
|
||||
}
|
||||
|
||||
func (a *App) SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool {
|
||||
@@ -48,7 +48,7 @@ func (a *App) SessionHasPermissionToChannel(session model.Session, channelId str
|
||||
ids := cmcresult.Data.(map[string]string)
|
||||
if roles, ok := ids[channelId]; ok {
|
||||
channelRoles = strings.Fields(roles)
|
||||
if a.CheckIfRolesGrantPermission(channelRoles, permission.Id) {
|
||||
if a.RolesGrantPermission(channelRoles, permission.Id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func (a *App) SessionHasPermissionToChannelByPost(session model.Session, postId
|
||||
if result := <-a.Srv.Store.Channel().GetMemberForPost(postId, session.UserId); result.Err == nil {
|
||||
channelMember = result.Data.(*model.ChannelMember)
|
||||
|
||||
if a.CheckIfRolesGrantPermission(channelMember.GetRoles(), permission.Id) {
|
||||
if a.RolesGrantPermission(channelMember.GetRoles(), permission.Id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func (a *App) HasPermissionTo(askingUserId string, permission *model.Permission)
|
||||
|
||||
roles := user.GetRoles()
|
||||
|
||||
return a.CheckIfRolesGrantPermission(roles, permission.Id)
|
||||
return a.RolesGrantPermission(roles, permission.Id)
|
||||
}
|
||||
|
||||
func (a *App) HasPermissionToTeam(askingUserId string, teamId string, permission *model.Permission) bool {
|
||||
@@ -134,7 +134,7 @@ func (a *App) HasPermissionToTeam(askingUserId string, teamId string, permission
|
||||
|
||||
roles := teamMember.GetRoles()
|
||||
|
||||
if a.CheckIfRolesGrantPermission(roles, permission.Id) {
|
||||
if a.RolesGrantPermission(roles, permission.Id) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ func (a *App) HasPermissionToChannel(askingUserId string, channelId string, perm
|
||||
channelMember, err := a.GetChannelMember(channelId, askingUserId)
|
||||
if err == nil {
|
||||
roles := channelMember.GetRoles()
|
||||
if a.CheckIfRolesGrantPermission(roles, permission.Id) {
|
||||
if a.RolesGrantPermission(roles, permission.Id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,7 @@ func (a *App) HasPermissionToChannelByPost(askingUserId string, postId string, p
|
||||
if result := <-a.Srv.Store.Channel().GetMemberForPost(postId, askingUserId); result.Err == nil {
|
||||
channelMember = result.Data.(*model.ChannelMember)
|
||||
|
||||
if a.CheckIfRolesGrantPermission(channelMember.GetRoles(), permission.Id) {
|
||||
if a.RolesGrantPermission(channelMember.GetRoles(), permission.Id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -181,17 +181,33 @@ func (a *App) HasPermissionToChannelByPost(askingUserId string, postId string, p
|
||||
return a.HasPermissionTo(askingUserId, permission)
|
||||
}
|
||||
|
||||
func (a *App) CheckIfRolesGrantPermission(roles []string, permissionId string) bool {
|
||||
for _, roleId := range roles {
|
||||
if role := a.Role(roleId); role == nil {
|
||||
l4g.Debug("Bad role in system " + roleId)
|
||||
return false
|
||||
} else {
|
||||
permissions := role.Permissions
|
||||
for _, permission := range permissions {
|
||||
if permission == permissionId {
|
||||
return true
|
||||
}
|
||||
func (a *App) HasPermissionToUser(askingUserId string, userId string) bool {
|
||||
if askingUserId == userId {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.HasPermissionTo(askingUserId, model.PERMISSION_EDIT_OTHER_USERS) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *App) RolesGrantPermission(roleNames []string, permissionId string) bool {
|
||||
roles, err := a.GetRolesByNames(roleNames)
|
||||
if err != nil {
|
||||
// This should only happen if something is very broken. We can't realistically
|
||||
// recover the situation, so deny permission and log an error.
|
||||
l4g.Error("Failed to get roles from database with role names: " + strings.Join(roleNames, ","))
|
||||
l4g.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, role := range roles {
|
||||
permissions := role.Permissions
|
||||
for _, permission := range permissions {
|
||||
if permission == permissionId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ func TestCheckIfRolesGrantPermission(t *testing.T) {
|
||||
permissionId string
|
||||
shouldGrant bool
|
||||
}{
|
||||
{[]string{model.SYSTEM_ADMIN_ROLE_ID}, th.App.Role(model.SYSTEM_ADMIN_ROLE_ID).Permissions[0], true},
|
||||
{[]string{model.SYSTEM_ADMIN_ROLE_ID}, model.PERMISSION_MANAGE_SYSTEM.Id, true},
|
||||
{[]string{model.SYSTEM_ADMIN_ROLE_ID}, "non-existant-permission", false},
|
||||
{[]string{model.CHANNEL_USER_ROLE_ID}, th.App.Role(model.CHANNEL_USER_ROLE_ID).Permissions[0], true},
|
||||
{[]string{model.CHANNEL_USER_ROLE_ID}, model.PERMISSION_READ_CHANNEL.Id, true},
|
||||
{[]string{model.CHANNEL_USER_ROLE_ID}, model.PERMISSION_MANAGE_SYSTEM.Id, false},
|
||||
{[]string{model.SYSTEM_ADMIN_ROLE_ID, model.CHANNEL_USER_ROLE_ID}, model.PERMISSION_MANAGE_SYSTEM.Id, true},
|
||||
{[]string{model.CHANNEL_USER_ROLE_ID, model.SYSTEM_ADMIN_ROLE_ID}, model.PERMISSION_MANAGE_SYSTEM.Id, true},
|
||||
@@ -29,7 +29,7 @@ func TestCheckIfRolesGrantPermission(t *testing.T) {
|
||||
}
|
||||
|
||||
for testnum, testcase := range cases {
|
||||
if th.App.CheckIfRolesGrantPermission(testcase.roles, testcase.permissionId) != testcase.shouldGrant {
|
||||
if th.App.RolesGrantPermission(testcase.roles, testcase.permissionId) != testcase.shouldGrant {
|
||||
t.Fatal("Failed test case ", testnum)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,6 +439,10 @@ func (a *App) UpdateChannelMemberRoles(channelId string, userId string, newRoles
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.CheckRolesExist(strings.Fields(newRoles)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
member.Roles = newRoles
|
||||
|
||||
if result := <-a.Srv.Store.Channel().UpdateMember(member); result.Err != nil {
|
||||
|
||||
@@ -249,7 +249,7 @@ func (a *App) trackConfig() {
|
||||
|
||||
a.SendDiagnostic(TRACK_CONFIG_TEAM, map[string]interface{}{
|
||||
"enable_user_creation": cfg.TeamSettings.EnableUserCreation,
|
||||
"enable_team_creation": cfg.TeamSettings.EnableTeamCreation,
|
||||
"enable_team_creation": *cfg.TeamSettings.EnableTeamCreation,
|
||||
"restrict_team_invite": *cfg.TeamSettings.RestrictTeamInvite,
|
||||
"restrict_public_channel_creation": *cfg.TeamSettings.RestrictPublicChannelCreation,
|
||||
"restrict_private_channel_creation": *cfg.TeamSettings.RestrictPrivateChannelCreation,
|
||||
|
||||
@@ -412,10 +412,6 @@ func TestImportValidateUserImportData(t *testing.T) {
|
||||
}
|
||||
data.Position = ptrStr("The Boss")
|
||||
|
||||
data.Roles = ptrStr("system_user wat")
|
||||
if err := validateUserImportData(&data); err == nil {
|
||||
t.Fatal("Validation should have failed due to too unrecognised role.")
|
||||
}
|
||||
data.Roles = nil
|
||||
if err := validateUserImportData(&data); err != nil {
|
||||
t.Fatal("Validation failed but should have been valid.")
|
||||
@@ -479,12 +475,6 @@ func TestImportValidateUserTeamsImportData(t *testing.T) {
|
||||
}
|
||||
data[0].Name = ptrStr("teamname")
|
||||
|
||||
// Invalid Roles
|
||||
data[0].Roles = ptrStr("wtf")
|
||||
if err := validateUserTeamsImportData(&data); err == nil {
|
||||
t.Fatal("Should have failed due to invalid roles.")
|
||||
}
|
||||
|
||||
// Valid (nil roles)
|
||||
data[0].Roles = nil
|
||||
if err := validateUserTeamsImportData(&data); err != nil {
|
||||
@@ -517,12 +507,6 @@ func TestImportValidateUserChannelsImportData(t *testing.T) {
|
||||
}
|
||||
data[0].Name = ptrStr("channelname")
|
||||
|
||||
// Invalid Roles
|
||||
data[0].Roles = ptrStr("wtf")
|
||||
if err := validateUserChannelsImportData(&data); err == nil {
|
||||
t.Fatal("Should have failed due to invalid roles.")
|
||||
}
|
||||
|
||||
// Valid (nil roles)
|
||||
data[0].Roles = nil
|
||||
if err := validateUserChannelsImportData(&data); err != nil {
|
||||
|
||||
@@ -113,7 +113,6 @@ func (a *App) License() *model.License {
|
||||
|
||||
func (a *App) SetLicense(license *model.License) bool {
|
||||
defer func() {
|
||||
a.setDefaultRolesBasedOnConfig()
|
||||
for _, listener := range a.licenseListeners {
|
||||
listener()
|
||||
}
|
||||
|
||||
11
app/post.go
11
app/post.go
@@ -124,7 +124,7 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo
|
||||
if a.License() != nil && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly &&
|
||||
!post.IsSystemMessage() &&
|
||||
channel.Name == model.DEFAULT_CHANNEL &&
|
||||
!a.CheckIfRolesGrantPermission(user.GetRoles(), model.PERMISSION_MANAGE_SYSTEM.Id) {
|
||||
!a.RolesGrantPermission(user.GetRoles(), model.PERMISSION_MANAGE_SYSTEM.Id) {
|
||||
return nil, model.NewAppError("createPost", "api.post.create_post.town_square_read_only", nil, "", http.StatusForbidden)
|
||||
}
|
||||
|
||||
@@ -326,13 +326,6 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model
|
||||
} else {
|
||||
oldPost = result.Data.(*model.PostList).Posts[post.Id]
|
||||
|
||||
if a.License() != nil {
|
||||
if *a.Config().ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_NEVER && post.Message != oldPost.Message {
|
||||
err := model.NewAppError("UpdatePost", "api.post.update_post.permissions_denied.app_error", nil, "", http.StatusForbidden)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if oldPost == nil {
|
||||
err := model.NewAppError("UpdatePost", "api.post.update_post.find.app_error", nil, "id="+post.Id, http.StatusBadRequest)
|
||||
return nil, err
|
||||
@@ -349,7 +342,7 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model
|
||||
}
|
||||
|
||||
if a.License() != nil {
|
||||
if *a.Config().ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_TIME_LIMIT && model.GetMillis() > oldPost.CreateAt+int64(*a.Config().ServiceSettings.PostEditTimeLimit*1000) && post.Message != oldPost.Message {
|
||||
if *a.Config().ServiceSettings.PostEditTimeLimit != -1 && model.GetMillis() > oldPost.CreateAt+int64(*a.Config().ServiceSettings.PostEditTimeLimit*1000) && post.Message != oldPost.Message {
|
||||
err := model.NewAppError("UpdatePost", "api.post.update_post.permissions_time_limit.app_error", map[string]interface{}{"timeLimit": *a.Config().ServiceSettings.PostEditTimeLimit}, "", http.StatusBadRequest)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -48,6 +48,43 @@ func TestUpdatePostEditAt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdatePostTimeLimit(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
post := &model.Post{}
|
||||
*post = *th.BasicPost
|
||||
|
||||
th.App.SetLicense(model.NewTestLicense())
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.PostEditTimeLimit = -1
|
||||
})
|
||||
if _, err := th.App.UpdatePost(post, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.PostEditTimeLimit = 1000000000
|
||||
})
|
||||
post.Message = model.NewId()
|
||||
if _, err := th.App.UpdatePost(post, true); err != nil {
|
||||
t.Fatal("should allow you to edit the post")
|
||||
}
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.PostEditTimeLimit = 1
|
||||
})
|
||||
post.Message = model.NewId()
|
||||
if _, err := th.App.UpdatePost(post, true); err == nil {
|
||||
t.Fatal("should fail on update old post")
|
||||
}
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.PostEditTimeLimit = -1
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) {
|
||||
// This test ensures that when replying to a root post made by a user who has since left the channel, the reply
|
||||
// post completes successfully. This is a regression test for PLT-6523.
|
||||
|
||||
86
app/role.go
86
app/role.go
@@ -1,17 +1,91 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (a *App) Role(id string) *model.Role {
|
||||
return a.roles[id]
|
||||
func (a *App) GetRole(id string) (*model.Role, *model.AppError) {
|
||||
if result := <-a.Srv.Store.Role().Get(id); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.Role), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) setDefaultRolesBasedOnConfig() {
|
||||
a.roles = utils.DefaultRolesBasedOnConfig(a.Config(), a.License() != nil)
|
||||
func (a *App) GetRoleByName(name string) (*model.Role, *model.AppError) {
|
||||
if result := <-a.Srv.Store.Role().GetByName(name); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.Role), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) GetRolesByNames(names []string) ([]*model.Role, *model.AppError) {
|
||||
if result := <-a.Srv.Store.Role().GetByNames(names); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.([]*model.Role), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) PatchRole(role *model.Role, patch *model.RolePatch) (*model.Role, *model.AppError) {
|
||||
// If patch is a no-op then short-circuit the store.
|
||||
if patch.Permissions != nil && reflect.DeepEqual(*patch.Permissions, role.Permissions) {
|
||||
return role, nil
|
||||
}
|
||||
|
||||
role.Patch(patch)
|
||||
role, err := a.UpdateRole(role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return role, err
|
||||
}
|
||||
|
||||
func (a *App) UpdateRole(role *model.Role) (*model.Role, *model.AppError) {
|
||||
if result := <-a.Srv.Store.Role().Save(role); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
a.sendUpdatedRoleEvent(role)
|
||||
|
||||
return role, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) CheckRolesExist(roleNames []string) *model.AppError {
|
||||
roles, err := a.GetRolesByNames(roleNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range roleNames {
|
||||
nameFound := false
|
||||
for _, role := range roles {
|
||||
if name == role.Name {
|
||||
nameFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !nameFound {
|
||||
return model.NewAppError("CheckRolesExist", "app.role.check_roles_exist.role_not_found", nil, "role="+name, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) sendUpdatedRoleEvent(role *model.Role) {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ROLE_UPDATED, "", "", "", nil)
|
||||
message.Add("role", role.ToJson())
|
||||
|
||||
a.Go(func() {
|
||||
a.Publish(message)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -160,6 +160,10 @@ func (a *App) UpdateTeamMemberRoles(teamId string, userId string, newRoles strin
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.CheckRolesExist(strings.Fields(newRoles)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
member.Roles = newRoles
|
||||
|
||||
if result := <-a.Srv.Store.Team().UpdateMember(member); result.Err != nil {
|
||||
|
||||
@@ -1241,6 +1241,10 @@ func (a *App) UpdateUserRoles(userId string, newRoles string, sendWebSocketEvent
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.CheckRolesExist(strings.Fields(newRoles)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Roles = newRoles
|
||||
uchan := a.Srv.Store.User().Update(user, true)
|
||||
schan := a.Srv.Store.Session().UpdateRoles(user.Id, newRoles)
|
||||
|
||||
Ссылка в новой задаче
Block a user