Browse Source

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 years ago
parent
commit
35106537f2

+ 3 - 0
conf/defaults.ini

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

+ 3 - 0
conf/sample.ini

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

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

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

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

+ 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 {
 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 {

+ 5 - 6
pkg/models/org_user.go

@@ -18,21 +18,20 @@ var (
 type RoleType string
 type RoleType string
 
 
 const (
 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 {
 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
 	}
 	}
 
 

+ 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{
 	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))
 }
 }

+ 3 - 1
pkg/setting/setting.go

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

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

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

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

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

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

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

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

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

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

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