Jelajahi Sumber

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
Carl Bergquist 8 tahun lalu
induk
melakukan
35106537f2

+ 3 - 0
conf/defaults.ini

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

+ 3 - 0
conf/sample.ini

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

+ 1 - 1
docs/sources/http_api/auth.md

@@ -100,7 +100,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
 JSON Body schema:
 
 - **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**:
 

+ 6 - 2
docs/sources/installation/configuration.md

@@ -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
 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>
 

+ 1 - 1
pkg/api/dashboard.go

@@ -182,7 +182,7 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
 }
 
 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 {

+ 5 - 6
pkg/models/org_user.go

@@ -18,21 +18,20 @@ var (
 type RoleType string
 
 const (
-	ROLE_VIEWER           RoleType = "Viewer"
-	ROLE_EDITOR           RoleType = "Editor"
-	ROLE_READ_ONLY_EDITOR RoleType = "Read Only Editor"
-	ROLE_ADMIN            RoleType = "Admin"
+	ROLE_VIEWER RoleType = "Viewer"
+	ROLE_EDITOR RoleType = "Editor"
+	ROLE_ADMIN  RoleType = "Admin"
 )
 
 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 {
 	if r == ROLE_ADMIN {
 		return true
 	}
-	if r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR {
+	if r == ROLE_EDITOR {
 		return other != ROLE_ADMIN
 	}
 

+ 6 - 0
pkg/services/sqlstore/migrations/org_mig.go

@@ -83,4 +83,10 @@ func addOrgMigrations(mg *Migrator) {
 	mg.AddMigration("Update org_user table charset", NewTableCharsetMigration("org_user", []*Column{
 		{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))
 }

+ 3 - 1
pkg/setting/setting.go

@@ -106,6 +106,7 @@ var (
 	ExternalUserMngLinkUrl  string
 	ExternalUserMngLinkName string
 	ExternalUserMngInfo     string
+	ViewersCanEdit          bool
 
 	// Http auth
 	AdminUser     string
@@ -540,13 +541,14 @@ func NewConfigContext(args *CommandLineArgs) error {
 	AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
 	AllowUserOrgCreate = users.Key("allow_org_create").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)
 	LoginHint = users.Key("login_hint").String()
 	DefaultTheme = users.Key("default_theme").String()
 	ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
 	ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
 	ExternalUserMngInfo = users.Key("external_manage_info").String()
+	ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
 
 	// auth
 	auth := Cfg.Section("auth")

+ 1 - 1
public/app/features/admin/partials/edit_org.html

@@ -29,7 +29,7 @@
 			<td>{{orgUser.login}}</td>
 			<td>{{orgUser.email}}</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>
 			</td>
 			<td style="width: 1%">

+ 2 - 2
public/app/features/admin/partials/edit_user.html

@@ -59,7 +59,7 @@
 			</div>
 			<div class="gf-form">
 				<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 class="gf-form">
 				<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>
 			</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>
 			</td>
 			<td style="width: 1%">

+ 1 - 1
public/app/features/org/partials/add_user.html

@@ -25,7 +25,7 @@
 					</div>
 					<div class="gf-form max-width-10">
 						<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>
 					</div>
 					<div class="gf-form gf-size-auto">

+ 1 - 1
public/app/features/org/partials/invite.html

@@ -29,7 +29,7 @@
 					</div>
 					<div class="gf-form max-width-10">
 						<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>
 					</div>
 					<div class="gf-form gf-size-auto">

+ 1 - 1
public/app/features/org/partials/orgUsers.html

@@ -54,7 +54,7 @@
         <td><span class="ellipsis">{{user.email}}</span></td>
 				<td>{{user.lastSeenAtAge}}</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>
         </td>
         <td>