mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Cfg: Move ViewersCanEdit into cfg (#64876)
move ViewersCanEdit into cfg
This commit is contained in:
parent
7fd7c6ed78
commit
6b6cf5f4b7
@ -9,7 +9,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafanads"
|
||||
)
|
||||
|
||||
@ -68,7 +67,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
Grants: []string{string(org.RoleEditor)},
|
||||
}
|
||||
|
||||
if setting.ViewersCanEdit {
|
||||
if hs.Cfg.ViewersCanEdit {
|
||||
datasourcesExplorerRole.Grants = append(datasourcesExplorerRole.Grants, string(org.RoleViewer))
|
||||
}
|
||||
|
||||
|
@ -697,7 +697,7 @@ func setUpACL() {
|
||||
}
|
||||
}).Return(result, nil)
|
||||
|
||||
guardian.InitLegacyGuardian(store, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), store, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
func setUpRBACGuardian(t *testing.T) {
|
||||
|
@ -65,6 +65,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
reqCanAccessTeams := middleware.AdminOrEditorAndFeatureEnabled(hs.Cfg.EditorsCanAdmin)
|
||||
reqSnapshotPublicModeOrSignedIn := middleware.SnapshotPublicModeOrSignedIn(hs.Cfg)
|
||||
redirectFromLegacyPanelEditURL := middleware.RedirectFromLegacyPanelEditURL(hs.Cfg)
|
||||
ensureEditorOrViewerCanEdit := middleware.EnsureEditorOrViewerCanEdit(hs.Cfg)
|
||||
authorize := ac.Middleware(hs.AccessControl)
|
||||
authorizeInOrg := ac.AuthorizeInOrgMiddleware(hs.AccessControl, hs.accesscontrolService, hs.userService)
|
||||
quota := middleware.Quota(hs.QuotaService)
|
||||
@ -177,7 +178,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
if f, ok := reqSignedIn.(func(c *contextmodel.ReqContext)); ok {
|
||||
f(c)
|
||||
}
|
||||
middleware.EnsureEditorOrViewerCanEdit(c)
|
||||
ensureEditorOrViewerCanEdit(c)
|
||||
}, ac.EvalPermission(ac.ActionDatasourcesExplore)), hs.Index)
|
||||
|
||||
r.Get("/playlists/", reqSignedIn, hs.Index)
|
||||
|
@ -340,6 +340,6 @@ func setUp(confs ...setUpConf) *HTTPServer {
|
||||
dashSvc := &dashboards.FakeDashboardService{}
|
||||
qResult := aclMockResp
|
||||
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(store, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), store, dashSvc, teamSvc)
|
||||
return hs
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(nil, nil).Maybe()
|
||||
hs.DashboardService = dashSvc
|
||||
|
||||
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), sc.sqlStore, dashSvc, teamSvc)
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
@ -133,7 +133,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
dashSvc := dashboards.NewFakeDashboardService(t)
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(nil, errutil.Error{PublicMessage: "some error"}).Maybe()
|
||||
|
||||
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(sc.cfg, sc.sqlStore, dashSvc, teamSvc)
|
||||
d := setUpSnapshotTest(t, 0, ts.URL)
|
||||
hs := buildHttpServer(d, true)
|
||||
hs.DashboardService = dashSvc
|
||||
@ -153,7 +153,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
dashSvc := dashboards.NewFakeDashboardService(t)
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(nil, dashboards.ErrDashboardNotFound).Maybe()
|
||||
|
||||
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(sc.cfg, sc.sqlStore, dashSvc, teamSvc)
|
||||
d := setUpSnapshotTest(t, 0, ts.URL)
|
||||
hs := buildHttpServer(d, true)
|
||||
hs.DashboardService = dashSvc
|
||||
@ -185,7 +185,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
{Role: &editorRole, Permission: dashboards.PERMISSION_EDIT},
|
||||
}
|
||||
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResultACL, nil)
|
||||
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(sc.cfg, sc.sqlStore, dashSvc, teamSvc)
|
||||
d := setUpSnapshotTest(t, 0, ts.URL)
|
||||
hs := buildHttpServer(d, true)
|
||||
hs.DashboardService = dashSvc
|
||||
|
@ -9,12 +9,13 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/api"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/api"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
@ -165,7 +166,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
{Role: &editorRole, Permission: dashboards.PERMISSION_EDIT},
|
||||
}
|
||||
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
guardian.InitLegacyGuardian(hs.Cfg, mockSQLStore, dashboardService, teamService)
|
||||
}
|
||||
|
||||
// This tests two scenarios:
|
||||
@ -274,12 +275,8 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
}
|
||||
|
||||
setUp := func() {
|
||||
origCanEdit := setting.ViewersCanEdit
|
||||
t.Cleanup(func() {
|
||||
setting.ViewersCanEdit = origCanEdit
|
||||
})
|
||||
setting.ViewersCanEdit = false
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
cfg.ViewersCanEdit = false
|
||||
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
|
||||
}
|
||||
|
||||
// This tests six scenarios:
|
||||
@ -370,18 +367,14 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
role := org.RoleViewer
|
||||
|
||||
setUpInner := func() {
|
||||
origCanEdit := setting.ViewersCanEdit
|
||||
t.Cleanup(func() {
|
||||
setting.ViewersCanEdit = origCanEdit
|
||||
})
|
||||
setting.ViewersCanEdit = false
|
||||
cfg.ViewersCanEdit = false
|
||||
|
||||
dashboardService := dashboards.NewFakeDashboardService(t)
|
||||
qResult := []*dashboards.DashboardACLInfoDTO{
|
||||
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_EDIT},
|
||||
}
|
||||
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
|
||||
@ -414,24 +407,20 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
role := org.RoleViewer
|
||||
|
||||
setUpInner := func() {
|
||||
origCanEdit := setting.ViewersCanEdit
|
||||
t.Cleanup(func() {
|
||||
setting.ViewersCanEdit = origCanEdit
|
||||
})
|
||||
setting.ViewersCanEdit = true
|
||||
cfg.ViewersCanEdit = true
|
||||
|
||||
dashboardService := dashboards.NewFakeDashboardService(t)
|
||||
qResult := []*dashboards.DashboardACLInfoDTO{
|
||||
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_VIEW},
|
||||
}
|
||||
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
|
||||
setUpInner()
|
||||
|
||||
require.True(t, setting.ViewersCanEdit)
|
||||
require.True(t, cfg.ViewersCanEdit)
|
||||
sc.sqlStore = mockSQLStore
|
||||
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
|
||||
|
||||
@ -452,18 +441,14 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
role := org.RoleViewer
|
||||
|
||||
setUpInner := func() {
|
||||
origCanEdit := setting.ViewersCanEdit
|
||||
t.Cleanup(func() {
|
||||
setting.ViewersCanEdit = origCanEdit
|
||||
})
|
||||
setting.ViewersCanEdit = true
|
||||
cfg.ViewersCanEdit = true
|
||||
|
||||
dashboardService := dashboards.NewFakeDashboardService(t)
|
||||
qResult := []*dashboards.DashboardACLInfoDTO{
|
||||
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_ADMIN},
|
||||
}
|
||||
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
|
||||
@ -509,12 +494,13 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
role := org.RoleEditor
|
||||
|
||||
setUpInner := func() {
|
||||
cfg := setting.NewCfg()
|
||||
dashboardService := dashboards.NewFakeDashboardService(t)
|
||||
qResult := []*dashboards.DashboardACLInfoDTO{
|
||||
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_VIEW},
|
||||
}
|
||||
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
|
||||
@ -782,7 +768,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(nil, nil)
|
||||
qResult := &dashboards.Dashboard{}
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
|
||||
guardian.InitLegacyGuardian(sqlmock, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), sqlmock, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
cmd := dtos.CalculateDiffOptions{
|
||||
@ -901,7 +887,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
|
||||
qResult2 := []*dashboards.DashboardACLInfoDTO{{OrgID: testOrgID, DashboardID: 1, UserID: testUserID, Permission: dashboards.PERMISSION_EDIT}}
|
||||
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult2, nil)
|
||||
guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService)
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), mockSQLStore, dashboardService, teamService)
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) {
|
||||
fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background())
|
||||
|
@ -245,7 +245,7 @@ func createFolderScenario(t *testing.T, desc string, url string, routePattern st
|
||||
qResult := &dashboards.Dashboard{}
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
|
||||
store := dbtest.NewFakeDB()
|
||||
guardian.InitLegacyGuardian(store, dashSvc, teamSvc)
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), store, dashSvc, teamSvc)
|
||||
folderPermissions := acmock.NewMockedPermissionsService()
|
||||
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
hs := HTTPServer{
|
||||
|
@ -133,7 +133,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
ExternalUserMngInfo: setting.ExternalUserMngInfo,
|
||||
ExternalUserMngLinkUrl: setting.ExternalUserMngLinkUrl,
|
||||
ExternalUserMngLinkName: setting.ExternalUserMngLinkName,
|
||||
ViewersCanEdit: setting.ViewersCanEdit,
|
||||
ViewersCanEdit: hs.Cfg.ViewersCanEdit,
|
||||
AngularSupportEnabled: hs.Cfg.AngularSupportEnabled,
|
||||
EditorsCanAdmin: hs.Cfg.EditorsCanAdmin,
|
||||
DisableSanitizeHtml: hs.Cfg.DisableSanitizeHtml,
|
||||
|
@ -83,9 +83,11 @@ func removeForceLoginParams(str string) string {
|
||||
return forceLoginParamsRegexp.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
func EnsureEditorOrViewerCanEdit(c *contextmodel.ReqContext) {
|
||||
if !c.SignedInUser.HasRole(org.RoleEditor) && !setting.ViewersCanEdit {
|
||||
accessForbidden(c)
|
||||
func EnsureEditorOrViewerCanEdit(cfg *setting.Cfg) func(c *contextmodel.ReqContext) {
|
||||
return func(c *contextmodel.ReqContext) {
|
||||
if !c.SignedInUser.HasRole(org.RoleEditor) && !cfg.ViewersCanEdit {
|
||||
accessForbidden(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func (s *Service) getUsageStats(ctx context.Context) (map[string]interface{}, error) {
|
||||
@ -30,7 +29,7 @@ func (s *Service) getUsageStats(ctx context.Context) (map[string]interface{}, er
|
||||
// FIXME: Move this to accesscontrol OSS.
|
||||
// FIXME: Access Control OSS usage stats is currently disabled if Enterprise is enabled.
|
||||
m["stats.authz.viewers_can_edit.count"] = 0
|
||||
if setting.ViewersCanEdit {
|
||||
if s.cfg.ViewersCanEdit {
|
||||
m["stats.authz.viewers_can_edit.count"] = 1
|
||||
}
|
||||
|
||||
|
@ -836,7 +836,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
||||
accesscontrolmock.New(),
|
||||
foldertest.NewFakeService(),
|
||||
)
|
||||
guardian.InitLegacyGuardian(sqlStore, service, &teamtest.FakeService{})
|
||||
guardian.InitLegacyGuardian(cfg, sqlStore, service, &teamtest.FakeService{})
|
||||
|
||||
savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore)
|
||||
savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.ID, sqlStore)
|
||||
|
@ -23,7 +23,7 @@ var _ DashboardGuardian = new(AccessControlDashboardGuardian)
|
||||
|
||||
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardId.
|
||||
func NewAccessControlDashboardGuardian(
|
||||
ctx context.Context, dashboardId int64, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardId int64, user *user.SignedInUser,
|
||||
store db.DB, ac accesscontrol.AccessControl,
|
||||
folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService,
|
||||
@ -48,6 +48,7 @@ func NewAccessControlDashboardGuardian(
|
||||
|
||||
return &AccessControlDashboardGuardian{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
log: log.New("dashboard.permissions"),
|
||||
dashboard: dashboard,
|
||||
user: user,
|
||||
@ -61,7 +62,7 @@ func NewAccessControlDashboardGuardian(
|
||||
|
||||
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardUID.
|
||||
func NewAccessControlDashboardGuardianByUID(
|
||||
ctx context.Context, dashboardUID string, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardUID string, user *user.SignedInUser,
|
||||
store db.DB, ac accesscontrol.AccessControl,
|
||||
folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService,
|
||||
@ -85,6 +86,7 @@ func NewAccessControlDashboardGuardianByUID(
|
||||
}
|
||||
|
||||
return &AccessControlDashboardGuardian{
|
||||
cfg: cfg,
|
||||
ctx: ctx,
|
||||
log: log.New("dashboard.permissions"),
|
||||
dashboard: dashboard,
|
||||
@ -101,13 +103,14 @@ func NewAccessControlDashboardGuardianByUID(
|
||||
// This constructor should be preferred over the other two if the dashboard in available
|
||||
// since it avoids querying the database for fetching the dashboard.
|
||||
func NewAccessControlDashboardGuardianByDashboard(
|
||||
ctx context.Context, dashboard *dashboards.Dashboard, user *user.SignedInUser,
|
||||
ctx context.Context, cfg *setting.Cfg, dashboard *dashboards.Dashboard, user *user.SignedInUser,
|
||||
store db.DB, ac accesscontrol.AccessControl,
|
||||
folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService,
|
||||
dashboardService dashboards.DashboardService,
|
||||
) (*AccessControlDashboardGuardian, error) {
|
||||
return &AccessControlDashboardGuardian{
|
||||
cfg: cfg,
|
||||
ctx: ctx,
|
||||
log: log.New("dashboard.permissions"),
|
||||
dashboard: dashboard,
|
||||
@ -121,6 +124,7 @@ func NewAccessControlDashboardGuardianByDashboard(
|
||||
}
|
||||
|
||||
type AccessControlDashboardGuardian struct {
|
||||
cfg *setting.Cfg
|
||||
ctx context.Context
|
||||
log log.Logger
|
||||
dashboard *dashboards.Dashboard
|
||||
@ -151,7 +155,7 @@ func (a *AccessControlDashboardGuardian) CanEdit() (bool, error) {
|
||||
return false, ErrGuardianDashboardNotFound
|
||||
}
|
||||
|
||||
if setting.ViewersCanEdit {
|
||||
if a.cfg.ViewersCanEdit {
|
||||
return a.CanView()
|
||||
}
|
||||
|
||||
|
@ -108,13 +108,14 @@ func TestAccessControlDashboardGuardian_CanSave(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, testDashSvc(t))
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, nil, testDashSvc(t))
|
||||
can, err := guardian.CanSave()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanEdit(t *testing.T) {
|
||||
tests := []accessControlGuardianTestCase{
|
||||
{
|
||||
@ -199,12 +200,11 @@ func TestAccessControlDashboardGuardian_CanEdit(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, testDashSvc(t))
|
||||
cfg := setting.NewCfg()
|
||||
cfg.ViewersCanEdit = tt.viewersCanEdit
|
||||
dashSvc := testDashSvc(t)
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, cfg, dashSvc)
|
||||
|
||||
if tt.viewersCanEdit {
|
||||
setting.ViewersCanEdit = true
|
||||
defer func() { setting.ViewersCanEdit = false }()
|
||||
}
|
||||
can, err := guardian.CanEdit()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
@ -283,7 +283,7 @@ func TestAccessControlDashboardGuardian_CanView(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, testDashSvc(t))
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, nil, testDashSvc(t))
|
||||
|
||||
can, err := guardian.CanView()
|
||||
require.NoError(t, err)
|
||||
@ -387,7 +387,7 @@ func TestAccessControlDashboardGuardian_CanAdmin(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, testDashSvc(t))
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, nil, testDashSvc(t))
|
||||
|
||||
can, err := guardian.CanAdmin()
|
||||
require.NoError(t, err)
|
||||
@ -467,7 +467,7 @@ func TestAccessControlDashboardGuardian_CanDelete(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, testDashSvc(t))
|
||||
guardian, _ := setupAccessControlGuardianTest(t, tt.dashUID, tt.permissions, nil, testDashSvc(t))
|
||||
|
||||
can, err := guardian.CanDelete()
|
||||
require.NoError(t, err)
|
||||
@ -531,7 +531,7 @@ func TestAccessControlDashboardGuardian_CanCreate(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, "0", tt.permissions, nil)
|
||||
guardian, _ := setupAccessControlGuardianTest(t, "0", tt.permissions, nil, nil)
|
||||
|
||||
can, err := guardian.CanCreate(tt.folderID, tt.isFolder)
|
||||
require.NoError(t, err)
|
||||
@ -563,7 +563,7 @@ func TestAccessControlDashboardGuardian_GetHiddenACL(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian, _ := setupAccessControlGuardianTest(t, "1", nil, testDashSvc(t))
|
||||
guardian, _ := setupAccessControlGuardianTest(t, "1", nil, nil, testDashSvc(t))
|
||||
|
||||
mocked := accesscontrolmock.NewMockedPermissionsService()
|
||||
guardian.dashboardPermissionsService = mocked
|
||||
@ -585,7 +585,10 @@ func TestAccessControlDashboardGuardian_GetHiddenACL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []accesscontrol.Permission, dashboardSvc dashboards.DashboardService) (*AccessControlDashboardGuardian, *dashboards.Dashboard) {
|
||||
func setupAccessControlGuardianTest(t *testing.T, uid string,
|
||||
permissions []accesscontrol.Permission,
|
||||
cfg *setting.Cfg,
|
||||
dashboardSvc dashboards.DashboardService) (*AccessControlDashboardGuardian, *dashboards.Dashboard) {
|
||||
t.Helper()
|
||||
store := db.InitTestDB(t)
|
||||
|
||||
@ -626,13 +629,13 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
|
||||
require.NoError(t, err)
|
||||
|
||||
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
|
||||
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
|
||||
cfg, routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
|
||||
require.NoError(t, err)
|
||||
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(
|
||||
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
|
||||
cfg, routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
|
||||
require.NoError(t, err)
|
||||
|
||||
g, err := NewAccessControlDashboardGuardian(context.Background(), dash.ID, &user.SignedInUser{OrgID: 1}, store, ac, folderPermissions, dashboardPermissions, dashboardSvc)
|
||||
g, err := NewAccessControlDashboardGuardian(context.Background(), cfg, dash.ID, &user.SignedInUser{OrgID: 1}, store, ac, folderPermissions, dashboardPermissions, dashboardSvc)
|
||||
require.NoError(t, err)
|
||||
g.dashboard = dash
|
||||
return g, dash
|
||||
|
@ -42,6 +42,7 @@ type DashboardGuardian interface {
|
||||
}
|
||||
|
||||
type dashboardGuardianImpl struct {
|
||||
cfg *setting.Cfg
|
||||
user *user.SignedInUser
|
||||
dashId int64
|
||||
orgId int64
|
||||
@ -73,7 +74,7 @@ var NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId
|
||||
}
|
||||
|
||||
// newDashboardGuardian creates a dashboard guardian by the provided dashId.
|
||||
func newDashboardGuardian(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
if dashId != 0 {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
ID: dashId,
|
||||
@ -89,6 +90,7 @@ func newDashboardGuardian(ctx context.Context, dashId int64, orgId int64, user *
|
||||
}
|
||||
|
||||
return &dashboardGuardianImpl{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
dashId: dashId,
|
||||
orgId: orgId,
|
||||
@ -101,7 +103,7 @@ func newDashboardGuardian(ctx context.Context, dashId int64, orgId int64, user *
|
||||
}
|
||||
|
||||
// newDashboardGuardianByUID creates a dashboard guardian by the provided dashUID.
|
||||
func newDashboardGuardianByUID(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID string, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
dashID := int64(0)
|
||||
if dashUID != "" {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
@ -120,6 +122,7 @@ func newDashboardGuardianByUID(ctx context.Context, dashUID string, orgId int64,
|
||||
}
|
||||
|
||||
return &dashboardGuardianImpl{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
dashId: dashID,
|
||||
orgId: orgId,
|
||||
@ -134,8 +137,9 @@ func newDashboardGuardianByUID(ctx context.Context, dashUID string, orgId int64,
|
||||
// newDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboard.
|
||||
// This constructor should be preferred over the other two if the dashboard in available
|
||||
// since it avoids querying the database for fetching the dashboard.
|
||||
func newDashboardGuardianByDashboard(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
|
||||
return &dashboardGuardianImpl{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
dashId: dash.ID,
|
||||
orgId: orgId,
|
||||
@ -152,7 +156,7 @@ func (g *dashboardGuardianImpl) CanSave() (bool, error) {
|
||||
}
|
||||
|
||||
func (g *dashboardGuardianImpl) CanEdit() (bool, error) {
|
||||
if setting.ViewersCanEdit {
|
||||
if g.cfg.ViewersCanEdit {
|
||||
return g.HasPermission(dashboards.PERMISSION_VIEW)
|
||||
}
|
||||
|
||||
|
@ -714,7 +714,7 @@ func TestGuardianGetHiddenACL(t *testing.T) {
|
||||
UserID: 1,
|
||||
Login: "user1",
|
||||
}
|
||||
g, err := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
g, err := newDashboardGuardian(context.Background(), cfg, dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
require.NoError(t, err)
|
||||
|
||||
hiddenACL, err := g.GetHiddenACL(cfg)
|
||||
@ -735,7 +735,7 @@ func TestGuardianGetHiddenACL(t *testing.T) {
|
||||
qResult := &dashboards.Dashboard{}
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Run(func(args mock.Arguments) {
|
||||
}).Return(qResult, nil)
|
||||
g, err := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
g, err := newDashboardGuardian(context.Background(), cfg, dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
require.NoError(t, err)
|
||||
|
||||
hiddenACL, err := g.GetHiddenACL(cfg)
|
||||
@ -777,7 +777,7 @@ func TestGuardianGetACLWithoutDuplicates(t *testing.T) {
|
||||
UserID: 1,
|
||||
Login: "user1",
|
||||
}
|
||||
g, err := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
g, err := newDashboardGuardian(context.Background(), setting.NewCfg(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
require.NoError(t, err)
|
||||
|
||||
acl, err := g.GetACLWithoutDuplicates()
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
type scenarioContext struct {
|
||||
@ -54,7 +55,7 @@ func orgRoleScenario(desc string, t *testing.T, role org.RoleType, fn scenarioFu
|
||||
UID: q.UID,
|
||||
}
|
||||
}).Return(qResult, nil)
|
||||
guard, err := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, fakeDashboardService, &teamtest.FakeService{})
|
||||
guard, err := newDashboardGuardian(context.Background(), setting.NewCfg(), dashboardID, orgID, user, store, fakeDashboardService, &teamtest.FakeService{})
|
||||
require.NoError(t, err)
|
||||
|
||||
sc := &scenarioContext{
|
||||
@ -86,7 +87,7 @@ func apiKeyScenario(desc string, t *testing.T, role org.RoleType, fn scenarioFun
|
||||
UID: q.UID,
|
||||
}
|
||||
}).Return(qResult, nil)
|
||||
guard, err := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
guard, err := newDashboardGuardian(context.Background(), setting.NewCfg(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{})
|
||||
require.NoError(t, err)
|
||||
|
||||
sc := &scenarioContext{
|
||||
@ -128,7 +129,7 @@ func permissionScenario(desc string, dashboardID int64, sc *scenarioContext,
|
||||
}).Return(qResultDash, nil)
|
||||
|
||||
sc.permissionScenario = desc
|
||||
g, err := newDashboardGuardian(context.Background(), dashboardID, sc.givenUser.OrgID, sc.givenUser, store, dashSvc, teamSvc)
|
||||
g, err := newDashboardGuardian(context.Background(), setting.NewCfg(), dashboardID, sc.givenUser.OrgID, sc.givenUser, store, dashSvc, teamSvc)
|
||||
require.NoError(t, err)
|
||||
sc.g = g
|
||||
|
||||
|
@ -8,51 +8,52 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
type Provider struct{}
|
||||
|
||||
func ProvideService(
|
||||
store db.DB, ac accesscontrol.AccessControl,
|
||||
cfg *setting.Cfg, store db.DB, ac accesscontrol.AccessControl,
|
||||
folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService,
|
||||
dashboardService dashboards.DashboardService, teamService team.Service,
|
||||
) *Provider {
|
||||
if !ac.IsDisabled() {
|
||||
// TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935
|
||||
InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
InitAccessControlGuardian(cfg, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
} else {
|
||||
InitLegacyGuardian(store, dashboardService, teamService)
|
||||
InitLegacyGuardian(cfg, store, dashboardService, teamService)
|
||||
}
|
||||
return &Provider{}
|
||||
}
|
||||
|
||||
func InitLegacyGuardian(store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) {
|
||||
func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
return newDashboardGuardian(ctx, dashId, orgId, user, store, dashSvc, teamSvc)
|
||||
return newDashboardGuardian(ctx, cfg, dashId, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
return newDashboardGuardianByUID(ctx, dashUID, orgId, user, store, dashSvc, teamSvc)
|
||||
return newDashboardGuardianByUID(ctx, cfg, dashUID, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
|
||||
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
return newDashboardGuardianByDashboard(ctx, dash, orgId, user, store, dashSvc, teamSvc)
|
||||
return newDashboardGuardianByDashboard(ctx, cfg, dash, orgId, user, store, dashSvc, teamSvc)
|
||||
}
|
||||
}
|
||||
|
||||
func InitAccessControlGuardian(
|
||||
store db.DB, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
cfg *setting.Cfg, store db.DB, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardService dashboards.DashboardService,
|
||||
) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
return NewAccessControlDashboardGuardian(ctx, cfg, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
}
|
||||
|
||||
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardianByUID(ctx, dashUID, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
return NewAccessControlDashboardGuardianByUID(ctx, cfg, dashUID, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
}
|
||||
|
||||
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardianByDashboard(ctx, dash, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
return NewAccessControlDashboardGuardianByDashboard(ctx, cfg, dash, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ func validateAndUnMarshalArrayResponse(t *testing.T, resp response.Response) lib
|
||||
func scenarioWithPanel(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
||||
t.Helper()
|
||||
store := dbtest.NewFakeDB()
|
||||
guardian.InitLegacyGuardian(store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{})
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{})
|
||||
|
||||
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
|
||||
command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel")
|
||||
@ -446,7 +446,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(),
|
||||
)
|
||||
guardian.InitLegacyGuardian(sqlStore, dashboardService, &teamtest.FakeService{})
|
||||
guardian.InitLegacyGuardian(sqlStore.Cfg, sqlStore, dashboardService, &teamtest.FakeService{})
|
||||
service := LibraryElementService{
|
||||
Cfg: sqlStore.Cfg,
|
||||
SQLStore: sqlStore,
|
||||
|
@ -779,7 +779,7 @@ func scenarioWithLibraryPanel(t *testing.T, desc string, fn func(t *testing.T, s
|
||||
UID: q.UID,
|
||||
}
|
||||
}).Return(result, nil)
|
||||
guardian.InitLegacyGuardian(store, dashSvc, &teamtest.FakeService{})
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), store, dashSvc, &teamtest.FakeService{})
|
||||
t.Helper()
|
||||
|
||||
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
|
||||
|
@ -114,7 +114,7 @@ func (s *ServiceImpl) GetNavTree(c *contextmodel.ReqContext, hasEditPerm bool, p
|
||||
}
|
||||
|
||||
canExplore := func(context *contextmodel.ReqContext) bool {
|
||||
return c.OrgRole == org.RoleAdmin || c.OrgRole == org.RoleEditor || setting.ViewersCanEdit
|
||||
return c.OrgRole == org.RoleAdmin || c.OrgRole == org.RoleEditor || s.cfg.ViewersCanEdit
|
||||
}
|
||||
|
||||
if setting.ExploreEnabled && hasAccess(canExplore, ac.EvalPermission(ac.ActionDatasourcesExplore)) {
|
||||
|
@ -102,7 +102,6 @@ var (
|
||||
ExternalUserMngLinkUrl string
|
||||
ExternalUserMngLinkName string
|
||||
ExternalUserMngInfo string
|
||||
ViewersCanEdit bool
|
||||
|
||||
// HTTP auth
|
||||
SigV4AuthEnabled bool
|
||||
@ -330,6 +329,7 @@ type Cfg struct {
|
||||
// DistributedCache
|
||||
RemoteCacheOptions *RemoteCacheOptions
|
||||
|
||||
ViewersCanEdit bool
|
||||
EditorsCanAdmin bool
|
||||
|
||||
ApiKeyMaxSecondsToLive int64
|
||||
@ -1567,7 +1567,7 @@ func readUserSettings(iniFile *ini.File, cfg *Cfg) error {
|
||||
ExternalUserMngLinkName = valueAsString(users, "external_manage_link_name", "")
|
||||
ExternalUserMngInfo = valueAsString(users, "external_manage_info", "")
|
||||
|
||||
ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
|
||||
cfg.ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
|
||||
cfg.EditorsCanAdmin = users.Key("editors_can_admin").MustBool(false)
|
||||
|
||||
userInviteMaxLifetimeVal := valueAsString(users, "user_invite_max_lifetime_duration", "24h")
|
||||
|
Loading…
Reference in New Issue
Block a user