diff --git a/pkg/api/api.go b/pkg/api/api.go
index b47c632a918..5ae51b58904 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -96,12 +96,15 @@ func Register(r *macaron.Macaron) {
r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
r.Post("/using/:id", wrap(UserSetUsingOrg))
r.Get("/orgs", wrap(GetSignedInUserOrgList))
+
r.Post("/stars/dashboard/:id", wrap(StarDashboard))
r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))
+
r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
r.Get("/quotas", wrap(GetUserQuotas))
+
r.Get("/preferences", wrap(GetUserPreferences))
- r.Put("/preferences", bind(dtos.UpdateUserPrefsCmd{}), wrap(UpdateUserPreferences))
+ r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateUserPreferences))
})
// users (admin permission required)
@@ -132,6 +135,9 @@ func Register(r *macaron.Macaron) {
r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
+ // prefs
+ r.Get("/preferences", wrap(GetOrgPreferences))
+ r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
}, reqOrgAdmin)
// create new org
diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go
index fc4aa59fbb0..b55a1377bd8 100644
--- a/pkg/api/dashboard.go
+++ b/pkg/api/dashboard.go
@@ -159,22 +159,20 @@ func canEditDashboard(role m.RoleType) bool {
}
func GetHomeDashboard(c *middleware.Context) {
- // Checking if there is any preference set for home dashboard
- query := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
-
- if err := bus.Dispatch(&query); err != nil {
+ prefsQuery := m.GetPreferencesWithDefaultsQuery{OrgId: c.OrgId, UserId: c.UserId}
+ if err := bus.Dispatch(&prefsQuery); err != nil {
c.JsonApiErr(500, "Failed to get preferences", err)
}
- if query.Result.HomeDashboardId != 0 {
- query := m.GetDashboardSlugByIdQuery{Id: query.Result.HomeDashboardId}
- err := bus.Dispatch(&query)
+ if prefsQuery.Result.HomeDashboardId != 0 {
+ slugQuery := m.GetDashboardSlugByIdQuery{Id: prefsQuery.Result.HomeDashboardId}
+ err := bus.Dispatch(&slugQuery)
if err != nil {
c.JsonApiErr(500, "Failed to get slug from database", err)
return
}
- dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + query.Result}
+ dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + slugQuery.Result}
c.JSON(200, &dashRedirect)
return
}
diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go
index a95bd464f35..8db36be2140 100644
--- a/pkg/api/dtos/models.go
+++ b/pkg/api/dtos/models.go
@@ -33,6 +33,7 @@ type CurrentUser struct {
OrgRole m.RoleType `json:"orgRole"`
IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
GravatarUrl string `json:"gravatarUrl"`
+ Timezone string `json:"timezone"`
}
type DashboardMeta struct {
diff --git a/pkg/api/dtos/prefs.go b/pkg/api/dtos/prefs.go
index 77ef0a1da14..97e20bb4011 100644
--- a/pkg/api/dtos/prefs.go
+++ b/pkg/api/dtos/prefs.go
@@ -1,15 +1,12 @@
package dtos
-type UserPrefs struct {
- Theme string `json:"theme"`
- ThemeDefault string `json:"themeDefault"`
- HomeDashboardId int64 `json:"homeDashboardId"`
- HomeDashboardIdDefault int64 `json:"homeDashboardIdDefault"`
- Timezone string `json:"timezone"`
- TimezoneDefault string `json:"timezoneDefault"`
-}
-
-type UpdateUserPrefsCmd struct {
+type Prefs struct {
+ Theme string `json:"theme"`
+ HomeDashboardId int64 `json:"homeDashboardId"`
+ Timezone string `json:"timezone"`
+}
+
+type UpdatePrefsCmd struct {
Theme string `json:"theme"`
HomeDashboardId int64 `json:"homeDashboardId"`
Timezone string `json:"timezone"`
diff --git a/pkg/api/index.go b/pkg/api/index.go
index a376f9504a4..575ea35cfaf 100644
--- a/pkg/api/index.go
+++ b/pkg/api/index.go
@@ -2,6 +2,7 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
+ "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
@@ -14,6 +15,12 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
return nil, err
}
+ prefsQuery := m.GetPreferencesWithDefaultsQuery{OrgId: c.OrgId, UserId: c.UserId}
+ if err := bus.Dispatch(&prefsQuery); err != nil {
+ return nil, err
+ }
+ prefs := prefsQuery.Result
+
var data = dtos.IndexViewData{
User: &dtos.CurrentUser{
Id: c.UserId,
@@ -21,12 +28,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
Login: c.Login,
Email: c.Email,
Name: c.Name,
- LightTheme: c.Theme == "light",
OrgId: c.OrgId,
OrgName: c.OrgName,
OrgRole: c.OrgRole,
GravatarUrl: dtos.GetGravatarUrl(c.Email),
IsGrafanaAdmin: c.IsGrafanaAdmin,
+ LightTheme: prefs.Theme == "light",
+ Timezone: prefs.Timezone,
},
Settings: settings,
AppUrl: setting.AppUrl,
diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go
index ed51ddaa9ae..795b8994470 100644
--- a/pkg/api/preferences.go
+++ b/pkg/api/preferences.go
@@ -22,34 +22,52 @@ func SetHomeDashboard(c *middleware.Context, cmd m.SavePreferencesCommand) Respo
// GET /api/user/preferences
func GetUserPreferences(c *middleware.Context) Response {
- userPrefs := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
+ return getPreferencesFor(c.OrgId, c.UserId)
+}
- if err := bus.Dispatch(&userPrefs); err != nil {
- c.JsonApiErr(500, "Failed to get preferences", err)
+func getPreferencesFor(orgId int64, userId int64) Response {
+ prefsQuery := m.GetPreferencesQuery{UserId: userId, OrgId: orgId}
+
+ if err := bus.Dispatch(&prefsQuery); err != nil {
+ return ApiError(500, "Failed to get preferences", err)
}
- dto := dtos.UserPrefs{
- Theme: userPrefs.Result.Theme,
- HomeDashboardId: userPrefs.Result.HomeDashboardId,
- Timezone: userPrefs.Result.Timezone,
+ dto := dtos.Prefs{
+ Theme: prefsQuery.Result.Theme,
+ HomeDashboardId: prefsQuery.Result.HomeDashboardId,
+ Timezone: prefsQuery.Result.Timezone,
}
return Json(200, &dto)
}
// PUT /api/user/preferences
-func UpdateUserPreferences(c *middleware.Context, dtoCmd dtos.UpdateUserPrefsCmd) Response {
+func UpdateUserPreferences(c *middleware.Context, dtoCmd dtos.UpdatePrefsCmd) Response {
+ return updatePreferencesFor(c.OrgId, c.UserId, &dtoCmd)
+}
+
+func updatePreferencesFor(orgId int64, userId int64, dtoCmd *dtos.UpdatePrefsCmd) Response {
saveCmd := m.SavePreferencesCommand{
- UserId: c.UserId,
- OrgId: c.OrgId,
+ UserId: userId,
+ OrgId: orgId,
Theme: dtoCmd.Theme,
Timezone: dtoCmd.Timezone,
HomeDashboardId: dtoCmd.HomeDashboardId,
}
if err := bus.Dispatch(&saveCmd); err != nil {
- c.JsonApiErr(500, "Failed to save preferences", err)
+ return ApiError(500, "Failed to save preferences", err)
}
- return ApiSuccess("User preferences updated")
+ return ApiSuccess("Preferences updated")
+}
+
+// GET /api/org/preferences
+func GetOrgPreferences(c *middleware.Context) Response {
+ return getPreferencesFor(c.OrgId, 0)
+}
+
+// PUT /api/org/preferences
+func UpdateOrgPreferences(c *middleware.Context, dtoCmd dtos.UpdatePrefsCmd) Response {
+ return updatePreferencesFor(c.OrgId, 0, &dtoCmd)
}
diff --git a/pkg/models/preferences.go b/pkg/models/preferences.go
index 523a3bfc83f..4c77bc96d4d 100644
--- a/pkg/models/preferences.go
+++ b/pkg/models/preferences.go
@@ -33,6 +33,14 @@ type GetPreferencesQuery struct {
Result *Preferences
}
+type GetPreferencesWithDefaultsQuery struct {
+ Id int64
+ OrgId int64
+ UserId int64
+
+ Result *Preferences
+}
+
// ---------------------
// COMMANDS
type SavePreferencesCommand struct {
diff --git a/pkg/models/user.go b/pkg/models/user.go
index 2842bad490d..a231156b7b0 100644
--- a/pkg/models/user.go
+++ b/pkg/models/user.go
@@ -136,7 +136,6 @@ type SignedInUser struct {
Login string
Name string
Email string
- Theme string
ApiKeyId int64
IsGrafanaAdmin bool
}
diff --git a/pkg/services/sqlstore/preferences.go b/pkg/services/sqlstore/preferences.go
index 1b5fa79d879..d120c485ed3 100644
--- a/pkg/services/sqlstore/preferences.go
+++ b/pkg/services/sqlstore/preferences.go
@@ -9,9 +9,44 @@ import (
func init() {
bus.AddHandler("sql", GetPreferences)
+ bus.AddHandler("sql", GetPreferencesWithDefaults)
bus.AddHandler("sql", SavePreferences)
}
+func GetPreferencesWithDefaults(query *m.GetPreferencesWithDefaultsQuery) error {
+
+ prefs := make([]*m.Preferences, 0)
+ filter := "(org_id=? AND user_id=?) OR (org_id=? AND user_id=0)"
+ err := x.Where(filter, query.OrgId, query.UserId, query.OrgId).
+ OrderBy("user_id ASC").
+ Find(&prefs)
+
+ if err != nil {
+ return err
+ }
+
+ res := &m.Preferences{
+ Theme: "dark",
+ Timezone: "browser",
+ HomeDashboardId: 0,
+ }
+
+ for _, p := range prefs {
+ if p.Theme != "" {
+ res.Theme = p.Theme
+ }
+ if p.Timezone != "" {
+ res.Timezone = p.Timezone
+ }
+ if p.HomeDashboardId != 0 {
+ res.HomeDashboardId = p.HomeDashboardId
+ }
+ }
+
+ query.Result = res
+ return nil
+}
+
func GetPreferences(query *m.GetPreferencesQuery) error {
var prefs m.Preferences
@@ -54,7 +89,7 @@ func SavePreferences(cmd *m.SavePreferencesCommand) error {
prefs.Theme = cmd.Theme
prefs.Updated = time.Now()
prefs.Version += 1
- _, err = sess.Id(prefs.Id).Update(&prefs)
+ _, err := sess.Id(prefs.Id).AllCols().Update(&prefs)
return err
}
})
diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go
index 96b8c24b8fc..623e85ec472 100644
--- a/pkg/services/sqlstore/user.go
+++ b/pkg/services/sqlstore/user.go
@@ -273,7 +273,6 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error {
u.email as email,
u.login as login,
u.name as name,
- u.theme as theme,
org.name as org_name,
org_user.role as org_role,
org.id as org_id
diff --git a/public/app/core/routes/routes.ts b/public/app/core/routes/routes.ts
index ddc0ac06250..c258fb1a611 100644
--- a/public/app/core/routes/routes.ts
+++ b/public/app/core/routes/routes.ts
@@ -88,17 +88,20 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
resolve: loadOrgBundle,
})
.when('/profile', {
- templateUrl: 'public/app/features/profile/partials/profile.html',
+ templateUrl: 'public/app/features/org/partials/profile.html',
controller : 'ProfileCtrl',
controllerAs: 'ctrl',
+ resolve: loadOrgBundle,
})
.when('/profile/password', {
- templateUrl: 'public/app/features/profile/partials/password.html',
+ templateUrl: 'public/app/features/org/partials/password.html',
controller : 'ChangePasswordCtrl',
+ resolve: loadOrgBundle,
})
.when('/profile/select-org', {
- templateUrl: 'public/app/features/profile/partials/select_org.html',
+ templateUrl: 'public/app/features/org/partials/select_org.html',
controller : 'SelectOrgCtrl',
+ resolve: loadOrgBundle,
})
// ADMIN
.when('/admin', {
diff --git a/public/app/features/all.js b/public/app/features/all.js
index 19ca8d7e2c9..43d9f33f190 100644
--- a/public/app/features/all.js
+++ b/public/app/features/all.js
@@ -7,8 +7,5 @@ define([
'./playlist/all',
'./snapshot/all',
'./panel/all',
- './profile/profile_ctrl',
- './profile/changePasswordCtrl',
- './profile/selectOrgCtrl',
'./styleguide/styleguide',
], function () {});
diff --git a/public/app/features/org/all.js b/public/app/features/org/all.js
index e04634d709a..b610a20e686 100644
--- a/public/app/features/org/all.js
+++ b/public/app/features/org/all.js
@@ -1,7 +1,11 @@
define([
'./org_users_ctrl',
+ './profile_ctrl',
+ './org_users_ctrl',
+ './select_org_ctrl',
'./newOrgCtrl',
'./userInviteCtrl',
'./orgApiKeysCtrl',
'./orgDetailsCtrl',
+ './prefs_control',
], function () {});
diff --git a/public/app/features/profile/changePasswordCtrl.js b/public/app/features/org/change_password_ctrl.js
similarity index 100%
rename from public/app/features/profile/changePasswordCtrl.js
rename to public/app/features/org/change_password_ctrl.js
diff --git a/public/app/features/profile/partials/password.html b/public/app/features/org/partials/change_password.html
similarity index 100%
rename from public/app/features/profile/partials/password.html
rename to public/app/features/org/partials/change_password.html
diff --git a/public/app/features/org/partials/orgDetails.html b/public/app/features/org/partials/orgDetails.html
index b3ba0f73d83..5f264517b0d 100644
--- a/public/app/features/org/partials/orgDetails.html
+++ b/public/app/features/org/partials/orgDetails.html
@@ -19,6 +19,8 @@
+