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

Refactor User Type, Add Additional User Endpoints #2

Merged
merged 4 commits into from
Aug 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ func (c *Client) DeleteUser(id int64) error {
return c.request("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil, nil, nil)
}

// UpdateUserPassword updates a user password.
func (c *Client) UpdateUserPassword(id int64, password string) error {
body := map[string]string{"password": password}
data, err := json.Marshal(body)
if err != nil {
return err
}
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/password", id), nil, bytes.NewBuffer(data), nil)
}

// UpdateUserPermissions sets a user's admin status.
func (c *Client) UpdateUserPermissions(id int64, isAdmin bool) error {
body := map[string]bool{"isGrafanaAdmin": isAdmin}
data, err := json.Marshal(body)
if err != nil {
return err
}
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/permissions", id), nil, bytes.NewBuffer(data), nil)
}

// PauseAllAlerts pauses all Grafana alerts.
func (c *Client) PauseAllAlerts() (PauseAllAlertsResponse, error) {
result := PauseAllAlertsResponse{}
Expand Down
26 changes: 24 additions & 2 deletions admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
)

const (
createUserJSON = `{"id":1,"message":"User created"}`
deleteUserJSON = `{"message":"User deleted"}`
createUserJSON = `{"id":1,"message":"User created"}`
deleteUserJSON = `{"message":"User deleted"}`
updateUserPasswordJSON = `{"message":"User password updated"}`
updateUserPermissionsJSON = `{"message":"User permissions updated"}`

pauseAllAlertsJSON = `{
"alertsAffected": 1,
Expand Down Expand Up @@ -47,6 +49,26 @@ func TestDeleteUser(t *testing.T) {
}
}

func TestUpdateUserPassword(t *testing.T) {
server, client := gapiTestTools(200, updateUserPasswordJSON)
defer server.Close()

err := client.UpdateUserPassword(int64(1), "new-password")
if err != nil {
t.Error(err)
}
}

func TestUpdateUserPermissions(t *testing.T) {
server, client := gapiTestTools(200, updateUserPermissionsJSON)
defer server.Close()

err := client.UpdateUserPermissions(int64(1), false)
if err != nil {
t.Error(err)
}
}

func TestPauseAllAlerts(t *testing.T) {
server, client := gapiTestTools(200, pauseAllAlertsJSON)
defer server.Close()
Expand Down
86 changes: 55 additions & 31 deletions user.go
Original file line number Diff line number Diff line change
@@ -1,50 +1,74 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"time"
)

// User represents a Grafana user.
// User represents a Grafana user. It is structured after the UserProfileDTO
// struct in the Grafana codebase.
type User struct {
Id int64 `json:"id,omitempty"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Login string `json:"login,omitempty"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"isAdmin,omitempty"`
Id int64 `json:"id,omitempty"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Login string `json:"login,omitempty"`
Theme string `json:"theme,omitempty"`
OrgId int64 `json:"orgId,omitempty"`
IsAdmin bool `json:"isGrafanaAdmin,omitempty"`
IsDisabled bool `json:"isDisabled,omitempty"`
IsExternal bool `json:"isExternal,omitempty"`
UpdatedAt time.Time `json:"updatedAt,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty"`
AuthLabels []string `json:"authLabels,omitempty"`
AvatarUrl string `json:"avatarUrl,omitempty"`
Password string `json:"password,omitempty"`
}

// UserSearch represents a Grafana user as returned by API endpoints that
// return a collection of Grafana users. This representation of user has
// reduced and differing fields. It is structured after the UserSearchHitDTO
// struct in the Grafana codebase.
type UserSearch struct {
Id int64 `json:"id,omitempty"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Login string `json:"login,omitempty"`
IsAdmin bool `json:"isAdmin,omitempty"`
IsDisabled bool `json:"isDisabled,omitempty"`
LastSeenAt time.Time `json:"lastSeenAt,omitempty"`
LastSeenAtAge string `json:"lastSeenAtAge,omitempty"`
AuthLabels []string `json:"authLabels,omitempty"`
AvatarUrl string `json:"avatarUrl,omitempty"`
}

// Users fetches and returns Grafana users.
func (c *Client) Users() ([]User, error) {
users := make([]User, 0)
err := c.request("GET", "/api/users", nil, nil, &users)
if err != nil {
return users, err
}
func (c *Client) Users() (users []UserSearch, err error) {
err = c.request("GET", "/api/users", nil, nil, &users)
return
}

return users, err
// User fetches a user by ID.
func (c *Client) User(id int64) (user User, err error) {
err = c.request("GET", fmt.Sprintf("/api/users/%d", id), nil, nil, &user)
return
}

// UserByEmail fetches and returns the user whose email matches that passed.
func (c *Client) UserByEmail(email string) (User, error) {
user := User{}
// UserByEmail fetches a user by email address.
func (c *Client) UserByEmail(email string) (user User, err error) {
query := url.Values{}
query.Add("loginOrEmail", email)
tmp := struct {
Id int64 `json:"id,omitempty"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Login string `json:"login,omitempty"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"isGrafanaAdmin,omitempty"`
}{}
err = c.request("GET", "/api/users/lookup", query, nil, &user)
return
}

err := c.request("GET", "/api/users/lookup", query, nil, &tmp)
// UserUpdate updates a user by ID.
func (c *Client) UserUpdate(u User) error {
data, err := json.Marshal(u)
if err != nil {
return user, err
return err
}

user = User(tmp)

return user, err
return c.request("PUT", fmt.Sprintf("/api/users/%d", u.Id), nil, bytes.NewBuffer(data), nil)
}
68 changes: 49 additions & 19 deletions user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
)

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

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

t.Log(pretty.PrettyFormat(resp))

user := User{
Id: 1,
Email: "admin@localhost",
Name: "",
Login: "admin",
IsAdmin: true,
if len(resp) != 1 {
t.Fatal("No users were returned.")
}

if len(resp) != 1 || resp[0] != user {
user := resp[0]

if user.Email != "users@localhost" ||
user.Id != 1 ||
user.IsAdmin != true {
t.Error("Not correctly parsing returned users.")
}
}

func TestUser(t *testing.T) {
server, client := gapiTestTools(200, getUserJSON)
defer server.Close()

user, err := client.User(1)
if err != nil {
t.Error(err)
}

t.Log(pretty.PrettyFormat(user))

if user.Email != "user@localhost" ||
user.Id != 2 ||
user.IsAdmin != false {
t.Error("Not correctly parsing returned user.")
}
}

func TestUserByEmail(t *testing.T) {
server, client := gapiTestTools(200, getUserByEmailJSON)
defer server.Close()

resp, err := client.UserByEmail("admin@localhost")
user, err := client.UserByEmail("admin@localhost")
if err != nil {
t.Error(err)
}

t.Log(pretty.PrettyFormat(resp))
t.Log(pretty.PrettyFormat(user))

user := User{
Id: 1,
Email: "admin@localhost",
Name: "",
Login: "admin",
IsAdmin: true,
}
if resp != user {
if user.Email != "userByEmail@localhost" ||
user.Id != 3 ||
user.IsAdmin != true {
t.Error("Not correctly parsing returned user.")
}
}

func TestUserUpdate(t *testing.T) {
server, client := gapiTestTools(200, getUserUpdateJSON)
defer server.Close()

user, err := client.User(4)
if err != nil {
t.Error(err)
}
user.IsAdmin = true
err = client.UserUpdate(user)
if err != nil {
t.Error(err)
}
}