From fa007423e331ab92d2d5489fd0f721afe59a3b7a Mon Sep 17 00:00:00 2001 From: gotjosh Date: Wed, 11 Sep 2019 13:43:05 +0100 Subject: [PATCH] API: Add `updatedAt` to api/users/:id (#19004) * API: Add `updatedAt` to api/users/:id This adds the timestamp of when a particular user was last updated to the `api/users/:id` endpoint. This helps our administrators understand when was the user information last updated. Particularly when it comes from external systems e.g. LDAP --- pkg/api/user_test.go | 55 +++++++++++++++++++++++++++++++++-- pkg/models/user.go | 21 ++++++------- pkg/services/sqlstore/user.go | 1 + 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/pkg/api/user_test.go b/pkg/api/user_test.go index 6aa9dd9adbf..c38bb498c9d 100644 --- a/pkg/api/user_test.go +++ b/pkg/api/user_test.go @@ -1,13 +1,15 @@ package api import ( + "net/http" "testing" - - "github.com/grafana/grafana/pkg/models" + "time" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/require" ) func TestUserApiEndpoint(t *testing.T) { @@ -20,6 +22,55 @@ func TestUserApiEndpoint(t *testing.T) { TotalCount: 2, } + loggedInUserScenario("When calling GET on", "api/users/:id", func(sc *scenarioContext) { + fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC) + bus.AddHandler("test", func(query *models.GetUserProfileQuery) error { + query.Result = models.UserProfileDTO{ + Id: int64(1), + Email: "daniel@grafana.com", + Name: "Daniel", + Login: "danlee", + OrgId: int64(2), + IsGrafanaAdmin: true, + IsDisabled: false, + IsExternal: false, + UpdatedAt: fakeNow, + } + return nil + }) + + bus.AddHandler("test", func(query *models.GetAuthInfoQuery) error { + query.Result = &models.UserAuth{ + AuthModule: models.AuthModuleLDAP, + } + return nil + }) + + sc.handlerFunc = GetUserByID + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() + + expected := ` + { + "id": 1, + "email": "daniel@grafana.com", + "name": "Daniel", + "login": "danlee", + "theme": "", + "orgId": 2, + "isGrafanaAdmin": true, + "isDisabled": false, + "isExternal": true, + "authLabels": [ + "LDAP" + ], + "updatedAt": "2019-02-11T17:30:40Z" + } + ` + + require.Equal(t, http.StatusOK, sc.resp.Code) + require.JSONEq(t, expected, sc.resp.Body.String()) + }) + loggedInUserScenario("When calling GET on", "/api/users", func(sc *scenarioContext) { var sentLimit int var sendPage int diff --git a/pkg/models/user.go b/pkg/models/user.go index 491d5e32d5c..c2d10b74778 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -215,16 +215,17 @@ func (user *SignedInUser) IsRealUser() bool { } type UserProfileDTO struct { - Id int64 `json:"id"` - Email string `json:"email"` - Name string `json:"name"` - Login string `json:"login"` - Theme string `json:"theme"` - OrgId int64 `json:"orgId"` - IsGrafanaAdmin bool `json:"isGrafanaAdmin"` - IsDisabled bool `json:"isDisabled"` - IsExternal bool `json:"isExternal"` - AuthLabels []string `json:"authLabels"` + Id int64 `json:"id"` + Email string `json:"email"` + Name string `json:"name"` + Login string `json:"login"` + Theme string `json:"theme"` + OrgId int64 `json:"orgId"` + IsGrafanaAdmin bool `json:"isGrafanaAdmin"` + IsDisabled bool `json:"isDisabled"` + IsExternal bool `json:"isExternal"` + AuthLabels []string `json:"authLabels"` + UpdatedAt time.Time `json:"updatedAt"` } type UserSearchHitDTO struct { diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index 659c2dd864d..f7c665b9c27 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -331,6 +331,7 @@ func GetUserProfile(query *models.GetUserProfileQuery) error { IsGrafanaAdmin: user.IsAdmin, IsDisabled: user.IsDisabled, OrgId: user.OrgId, + UpdatedAt: user.Updated, } return err