diff --git a/conf/defaults.ini b/conf/defaults.ini
index 218c91608cc..e16ef95178a 100644
--- a/conf/defaults.ini
+++ b/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
diff --git a/conf/sample.ini b/conf/sample.ini
index 7107f8354d6..544fa7e0c7d 100644
--- a/conf/sample.ini
+++ b/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
diff --git a/docs/sources/http_api/auth.md b/docs/sources/http_api/auth.md
index b526031fdeb..166a5a4fdb9 100644
--- a/docs/sources/http_api/auth.md
+++ b/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**:
diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md
index bb411002f08..91094b3157d 100644
--- a/docs/sources/installation/configuration.md
+++ b/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`.
diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go
index 4d2ed4707d9..e1ab038a2bb 100644
--- a/pkg/api/dashboard.go
+++ b/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 {
diff --git a/pkg/models/org_user.go b/pkg/models/org_user.go
index 67b081fd1ce..16251616509 100644
--- a/pkg/models/org_user.go
+++ b/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
}
diff --git a/pkg/services/sqlstore/migrations/org_mig.go b/pkg/services/sqlstore/migrations/org_mig.go
index 12e0a04256a..cf9b19f6f5b 100644
--- a/pkg/services/sqlstore/migrations/org_mig.go
+++ b/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))
}
diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go
index ef4a7c42e86..6a6df2b61fb 100644
--- a/pkg/setting/setting.go
+++ b/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")
diff --git a/public/app/features/admin/partials/edit_org.html b/public/app/features/admin/partials/edit_org.html
index 39028645b38..62535469497 100644
--- a/public/app/features/admin/partials/edit_org.html
+++ b/public/app/features/admin/partials/edit_org.html
@@ -29,7 +29,7 @@