Skip to content
This repository was archived by the owner on Jan 15, 2024. It is now read-only.

Commit ebe004c

Browse files
Merge pull request #2 from grafana/refactor-user
Refactor User Type, Add Additional User Endpoints
2 parents 85cb393 + 8a2ef07 commit ebe004c

File tree

4 files changed

+148
-52
lines changed

4 files changed

+148
-52
lines changed

admin.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@ func (c *Client) DeleteUser(id int64) error {
3838
return c.request("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil, nil, nil)
3939
}
4040

41+
// UpdateUserPassword updates a user password.
42+
func (c *Client) UpdateUserPassword(id int64, password string) error {
43+
body := map[string]string{"password": password}
44+
data, err := json.Marshal(body)
45+
if err != nil {
46+
return err
47+
}
48+
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/password", id), nil, bytes.NewBuffer(data), nil)
49+
}
50+
51+
// UpdateUserPermissions sets a user's admin status.
52+
func (c *Client) UpdateUserPermissions(id int64, isAdmin bool) error {
53+
body := map[string]bool{"isGrafanaAdmin": isAdmin}
54+
data, err := json.Marshal(body)
55+
if err != nil {
56+
return err
57+
}
58+
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/permissions", id), nil, bytes.NewBuffer(data), nil)
59+
}
60+
4161
// PauseAllAlerts pauses all Grafana alerts.
4262
func (c *Client) PauseAllAlerts() (PauseAllAlertsResponse, error) {
4363
result := PauseAllAlertsResponse{}

admin_test.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
)
99

1010
const (
11-
createUserJSON = `{"id":1,"message":"User created"}`
12-
deleteUserJSON = `{"message":"User deleted"}`
11+
createUserJSON = `{"id":1,"message":"User created"}`
12+
deleteUserJSON = `{"message":"User deleted"}`
13+
updateUserPasswordJSON = `{"message":"User password updated"}`
14+
updateUserPermissionsJSON = `{"message":"User permissions updated"}`
1315

1416
pauseAllAlertsJSON = `{
1517
"alertsAffected": 1,
@@ -47,6 +49,26 @@ func TestDeleteUser(t *testing.T) {
4749
}
4850
}
4951

52+
func TestUpdateUserPassword(t *testing.T) {
53+
server, client := gapiTestTools(200, updateUserPasswordJSON)
54+
defer server.Close()
55+
56+
err := client.UpdateUserPassword(int64(1), "new-password")
57+
if err != nil {
58+
t.Error(err)
59+
}
60+
}
61+
62+
func TestUpdateUserPermissions(t *testing.T) {
63+
server, client := gapiTestTools(200, updateUserPermissionsJSON)
64+
defer server.Close()
65+
66+
err := client.UpdateUserPermissions(int64(1), false)
67+
if err != nil {
68+
t.Error(err)
69+
}
70+
}
71+
5072
func TestPauseAllAlerts(t *testing.T) {
5173
server, client := gapiTestTools(200, pauseAllAlertsJSON)
5274
defer server.Close()

user.go

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,74 @@
11
package gapi
22

33
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
47
"net/url"
8+
"time"
59
)
610

7-
// User represents a Grafana user.
11+
// User represents a Grafana user. It is structured after the UserProfileDTO
12+
// struct in the Grafana codebase.
813
type User struct {
9-
Id int64 `json:"id,omitempty"`
10-
Email string `json:"email,omitempty"`
11-
Name string `json:"name,omitempty"`
12-
Login string `json:"login,omitempty"`
13-
Password string `json:"password,omitempty"`
14-
IsAdmin bool `json:"isAdmin,omitempty"`
14+
Id int64 `json:"id,omitempty"`
15+
Email string `json:"email,omitempty"`
16+
Name string `json:"name,omitempty"`
17+
Login string `json:"login,omitempty"`
18+
Theme string `json:"theme,omitempty"`
19+
OrgId int64 `json:"orgId,omitempty"`
20+
IsAdmin bool `json:"isGrafanaAdmin,omitempty"`
21+
IsDisabled bool `json:"isDisabled,omitempty"`
22+
IsExternal bool `json:"isExternal,omitempty"`
23+
UpdatedAt time.Time `json:"updatedAt,omitempty"`
24+
CreatedAt time.Time `json:"createdAt,omitempty"`
25+
AuthLabels []string `json:"authLabels,omitempty"`
26+
AvatarUrl string `json:"avatarUrl,omitempty"`
27+
Password string `json:"password,omitempty"`
28+
}
29+
30+
// UserSearch represents a Grafana user as returned by API endpoints that
31+
// return a collection of Grafana users. This representation of user has
32+
// reduced and differing fields. It is structured after the UserSearchHitDTO
33+
// struct in the Grafana codebase.
34+
type UserSearch struct {
35+
Id int64 `json:"id,omitempty"`
36+
Email string `json:"email,omitempty"`
37+
Name string `json:"name,omitempty"`
38+
Login string `json:"login,omitempty"`
39+
IsAdmin bool `json:"isAdmin,omitempty"`
40+
IsDisabled bool `json:"isDisabled,omitempty"`
41+
LastSeenAt time.Time `json:"lastSeenAt,omitempty"`
42+
LastSeenAtAge string `json:"lastSeenAtAge,omitempty"`
43+
AuthLabels []string `json:"authLabels,omitempty"`
44+
AvatarUrl string `json:"avatarUrl,omitempty"`
1545
}
1646

1747
// Users fetches and returns Grafana users.
18-
func (c *Client) Users() ([]User, error) {
19-
users := make([]User, 0)
20-
err := c.request("GET", "/api/users", nil, nil, &users)
21-
if err != nil {
22-
return users, err
23-
}
48+
func (c *Client) Users() (users []UserSearch, err error) {
49+
err = c.request("GET", "/api/users", nil, nil, &users)
50+
return
51+
}
2452

25-
return users, err
53+
// User fetches a user by ID.
54+
func (c *Client) User(id int64) (user User, err error) {
55+
err = c.request("GET", fmt.Sprintf("/api/users/%d", id), nil, nil, &user)
56+
return
2657
}
2758

28-
// UserByEmail fetches and returns the user whose email matches that passed.
29-
func (c *Client) UserByEmail(email string) (User, error) {
30-
user := User{}
59+
// UserByEmail fetches a user by email address.
60+
func (c *Client) UserByEmail(email string) (user User, err error) {
3161
query := url.Values{}
3262
query.Add("loginOrEmail", email)
33-
tmp := struct {
34-
Id int64 `json:"id,omitempty"`
35-
Email string `json:"email,omitempty"`
36-
Name string `json:"name,omitempty"`
37-
Login string `json:"login,omitempty"`
38-
Password string `json:"password,omitempty"`
39-
IsAdmin bool `json:"isGrafanaAdmin,omitempty"`
40-
}{}
63+
err = c.request("GET", "/api/users/lookup", query, nil, &user)
64+
return
65+
}
4166

42-
err := c.request("GET", "/api/users/lookup", query, nil, &tmp)
67+
// UserUpdate updates a user by ID.
68+
func (c *Client) UserUpdate(u User) error {
69+
data, err := json.Marshal(u)
4370
if err != nil {
44-
return user, err
71+
return err
4572
}
46-
47-
user = User(tmp)
48-
49-
return user, err
73+
return c.request("PUT", fmt.Sprintf("/api/users/%d", u.Id), nil, bytes.NewBuffer(data), nil)
5074
}

user_test.go

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
)
88

99
const (
10-
getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]`
11-
getUserByEmailJSON = `{"id":1,"email":"admin@localhost","name":"","login":"admin","theme":"","orgId":1,"isGrafanaAdmin":true}`
10+
getUsersJSON = `[{"id":1,"email":"users@localhost","isAdmin":true}]`
11+
getUserJSON = `{"id":2,"email":"user@localhost","isGrafanaAdmin":false}`
12+
getUserByEmailJSON = `{"id":3,"email":"userByEmail@localhost","isGrafanaAdmin":true}`
13+
getUserUpdateJSON = `{"id":4,"email":"userUpdate@localhost","isGrafanaAdmin":false}`
1214
)
1315

1416
func TestUsers(t *testing.T) {
@@ -22,38 +24,66 @@ func TestUsers(t *testing.T) {
2224

2325
t.Log(pretty.PrettyFormat(resp))
2426

25-
user := User{
26-
Id: 1,
27-
Email: "admin@localhost",
28-
Name: "",
29-
Login: "admin",
30-
IsAdmin: true,
27+
if len(resp) != 1 {
28+
t.Fatal("No users were returned.")
3129
}
3230

33-
if len(resp) != 1 || resp[0] != user {
31+
user := resp[0]
32+
33+
if user.Email != "users@localhost" ||
34+
user.Id != 1 ||
35+
user.IsAdmin != true {
3436
t.Error("Not correctly parsing returned users.")
3537
}
3638
}
3739

40+
func TestUser(t *testing.T) {
41+
server, client := gapiTestTools(200, getUserJSON)
42+
defer server.Close()
43+
44+
user, err := client.User(1)
45+
if err != nil {
46+
t.Error(err)
47+
}
48+
49+
t.Log(pretty.PrettyFormat(user))
50+
51+
if user.Email != "user@localhost" ||
52+
user.Id != 2 ||
53+
user.IsAdmin != false {
54+
t.Error("Not correctly parsing returned user.")
55+
}
56+
}
57+
3858
func TestUserByEmail(t *testing.T) {
3959
server, client := gapiTestTools(200, getUserByEmailJSON)
4060
defer server.Close()
4161

42-
resp, err := client.UserByEmail("admin@localhost")
62+
user, err := client.UserByEmail("admin@localhost")
4363
if err != nil {
4464
t.Error(err)
4565
}
4666

47-
t.Log(pretty.PrettyFormat(resp))
67+
t.Log(pretty.PrettyFormat(user))
4868

49-
user := User{
50-
Id: 1,
51-
Email: "admin@localhost",
52-
Name: "",
53-
Login: "admin",
54-
IsAdmin: true,
55-
}
56-
if resp != user {
69+
if user.Email != "userByEmail@localhost" ||
70+
user.Id != 3 ||
71+
user.IsAdmin != true {
5772
t.Error("Not correctly parsing returned user.")
5873
}
5974
}
75+
76+
func TestUserUpdate(t *testing.T) {
77+
server, client := gapiTestTools(200, getUserUpdateJSON)
78+
defer server.Close()
79+
80+
user, err := client.User(4)
81+
if err != nil {
82+
t.Error(err)
83+
}
84+
user.IsAdmin = true
85+
err = client.UserUpdate(user)
86+
if err != nil {
87+
t.Error(err)
88+
}
89+
}

0 commit comments

Comments
 (0)