Replace Read Only Editor role with ViewersCanEdit setting (#10166)

* removes readonly editor role

* adds viewersCanEdit setting

This enable you to allow viewers to edit/inspect
dashboards in grafana in their own browser without
allowing them to save dashboards

* remove read only editor option from all dropdowns

* migrates all read only viewers to viewers

* docs: replace readOnlyEditor with viewersCanEdit
This commit is contained in:
Carl Bergquist 2017-12-13 18:53:42 +01:00 committed by Torkel Ödegaard
parent dfde6e75ed
commit 35106537f2
13 changed files with 34 additions and 17 deletions

View File

@ -221,6 +221,9 @@ external_manage_link_url =
external_manage_link_name = external_manage_link_name =
external_manage_info = external_manage_info =
# Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard.
viewers_can_edit = false
[auth] [auth]
# Set to true to disable (hide) the login form, useful if you use OAuth # Set to true to disable (hide) the login form, useful if you use OAuth
disable_login_form = false disable_login_form = false

View File

@ -205,6 +205,9 @@ log_queries =
;external_manage_link_name = ;external_manage_link_name =
;external_manage_info = ;external_manage_info =
# Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard.
;viewers_can_edit = false
[auth] [auth]
# Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false # Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false
;disable_login_form = false ;disable_login_form = false

View File

@ -100,7 +100,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
JSON Body schema: JSON Body schema:
- **name** The key name - **name** The key name
- **role** Sets the access level/Grafana Role for the key. Can be one of the following values: `Viewer`, `Editor`, `Read Only Editor` or `Admin`. - **role** Sets the access level/Grafana Role for the key. Can be one of the following values: `Viewer`, `Editor` or `Admin`.
**Example Response**: **Example Response**:

View File

@ -292,10 +292,14 @@ organization to be created for that new user.
The role new users will be assigned for the main organization (if the The role new users will be assigned for the main organization (if the
above setting is set to true). Defaults to `Viewer`, other valid above setting is set to true). Defaults to `Viewer`, other valid
options are `Admin` and `Editor` and `Read Only Editor`. e.g. : options are `Admin` and `Editor`. e.g. :
`auto_assign_org_role = Read Only Editor` `auto_assign_org_role = Viewer`
### viewers can edit
Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard.
Defaults to `false`.
<hr> <hr>

View File

@ -182,7 +182,7 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
} }
func canEditDashboard(role m.RoleType) bool { func canEditDashboard(role m.RoleType) bool {
return role == m.ROLE_ADMIN || role == m.ROLE_EDITOR || role == m.ROLE_READ_ONLY_EDITOR return role == m.ROLE_ADMIN || role == m.ROLE_EDITOR || setting.ViewersCanEdit
} }
func GetHomeDashboard(c *middleware.Context) Response { func GetHomeDashboard(c *middleware.Context) Response {

View File

@ -18,21 +18,20 @@ var (
type RoleType string type RoleType string
const ( const (
ROLE_VIEWER RoleType = "Viewer" ROLE_VIEWER RoleType = "Viewer"
ROLE_EDITOR RoleType = "Editor" ROLE_EDITOR RoleType = "Editor"
ROLE_READ_ONLY_EDITOR RoleType = "Read Only Editor" ROLE_ADMIN RoleType = "Admin"
ROLE_ADMIN RoleType = "Admin"
) )
func (r RoleType) IsValid() bool { func (r RoleType) IsValid() bool {
return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR
} }
func (r RoleType) Includes(other RoleType) bool { func (r RoleType) Includes(other RoleType) bool {
if r == ROLE_ADMIN { if r == ROLE_ADMIN {
return true return true
} }
if r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR { if r == ROLE_EDITOR {
return other != ROLE_ADMIN return other != ROLE_ADMIN
} }

View File

@ -83,4 +83,10 @@ func addOrgMigrations(mg *Migrator) {
mg.AddMigration("Update org_user table charset", NewTableCharsetMigration("org_user", []*Column{ mg.AddMigration("Update org_user table charset", NewTableCharsetMigration("org_user", []*Column{
{Name: "role", Type: DB_NVarchar, Length: 20}, {Name: "role", Type: DB_NVarchar, Length: 20},
})) }))
const migrateReadOnlyViewersToViewers = `UPDATE org_user SET role = 'Viewer' WHERE role = 'Read Only Editor'`
mg.AddMigration("Migrate all Read Only Viewers to Viewers", new(RawSqlMigration).
Sqlite(migrateReadOnlyViewersToViewers).
Postgres(migrateReadOnlyViewersToViewers).
Mysql(migrateReadOnlyViewersToViewers))
} }

View File

@ -106,6 +106,7 @@ var (
ExternalUserMngLinkUrl string ExternalUserMngLinkUrl string
ExternalUserMngLinkName string ExternalUserMngLinkName string
ExternalUserMngInfo string ExternalUserMngInfo string
ViewersCanEdit bool
// Http auth // Http auth
AdminUser string AdminUser string
@ -540,13 +541,14 @@ func NewConfigContext(args *CommandLineArgs) error {
AllowUserSignUp = users.Key("allow_sign_up").MustBool(true) AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true) AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
AutoAssignOrg = users.Key("auto_assign_org").MustBool(true) AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Read Only Editor", "Viewer"}) AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false) VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
LoginHint = users.Key("login_hint").String() LoginHint = users.Key("login_hint").String()
DefaultTheme = users.Key("default_theme").String() DefaultTheme = users.Key("default_theme").String()
ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String() ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
ExternalUserMngLinkName = users.Key("external_manage_link_name").String() ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
ExternalUserMngInfo = users.Key("external_manage_info").String() ExternalUserMngInfo = users.Key("external_manage_info").String()
ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
// auth // auth
auth := Cfg.Section("auth") auth := Cfg.Section("auth")

View File

@ -29,7 +29,7 @@
<td>{{orgUser.login}}</td> <td>{{orgUser.login}}</td>
<td>{{orgUser.email}}</td> <td>{{orgUser.email}}</td>
<td> <td>
<select type="text" ng-model="orgUser.role" class="gf-form-input max-width-8" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="updateOrgUser(orgUser)"> <select type="text" ng-model="orgUser.role" class="gf-form-input max-width-8" ng-options="f for f in ['Viewer', 'Editor', 'Admin']" ng-change="updateOrgUser(orgUser)">
</select> </select>
</td> </td>
<td style="width: 1%"> <td style="width: 1%">

View File

@ -59,7 +59,7 @@
</div> </div>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label">Role</span> <span class="gf-form-label">Role</span>
<select type="text" ng-model="newOrg.role" class="gf-form-input width-10" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']"></select> <select type="text" ng-model="newOrg.role" class="gf-form-input width-10" ng-options="f for f in ['Viewer', 'Editor', 'Admin']"></select>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<button class="btn btn-success gf-form-btn" ng-click="addOrgUser()">Add</button> <button class="btn btn-success gf-form-btn" ng-click="addOrgUser()">Add</button>
@ -78,7 +78,7 @@
{{org.name}} <span class="label label-info" ng-show="org.orgId === user.orgId">Current</span> {{org.name}} <span class="label label-info" ng-show="org.orgId === user.orgId">Current</span>
</td> </td>
<td> <td>
<select type="text" ng-model="org.role" class="gf-form-input max-width-12" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="updateOrgUser(org)"> <select type="text" ng-model="org.role" class="gf-form-input max-width-12" ng-options="f for f in ['Viewer', 'Editor', 'Admin']" ng-change="updateOrgUser(org)">
</select> </select>
</td> </td>
<td style="width: 1%"> <td style="width: 1%">

View File

@ -25,7 +25,7 @@
</div> </div>
<div class="gf-form max-width-10"> <div class="gf-form max-width-10">
<span class="gf-form-label">Role</span> <span class="gf-form-label">Role</span>
<select ng-model="invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']"> <select ng-model="invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Admin']">
</select> </select>
</div> </div>
<div class="gf-form gf-size-auto"> <div class="gf-form gf-size-auto">

View File

@ -29,7 +29,7 @@
</div> </div>
<div class="gf-form max-width-10"> <div class="gf-form max-width-10">
<span class="gf-form-label">Role</span> <span class="gf-form-label">Role</span>
<select ng-model="invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']"> <select ng-model="invite.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Admin']">
</select> </select>
</div> </div>
<div class="gf-form gf-size-auto"> <div class="gf-form gf-size-auto">

View File

@ -54,7 +54,7 @@
<td><span class="ellipsis">{{user.email}}</span></td> <td><span class="ellipsis">{{user.email}}</span></td>
<td>{{user.lastSeenAtAge}}</td> <td>{{user.lastSeenAtAge}}</td>
<td> <td>
<select type="text" ng-model="user.role" class="input-medium" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)"> <select type="text" ng-model="user.role" class="input-medium" ng-options="f for f in ['Viewer', 'Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
</select> </select>
</td> </td>
<td> <td>