Skip to content

Commit

Permalink
Add GetUser and UpdateUser to shoreline Client to allow all clients t…
Browse files Browse the repository at this point in the history
…o work
  • Loading branch information
darinkrauss committed Dec 17, 2015
1 parent 37ac6f3 commit 6ea9c99
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 16 deletions.
22 changes: 12 additions & 10 deletions clients/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ import (
)

type (
GatekeeperMock struct{}
SeagullMock struct{}
GatekeeperMock struct {
expectedPermissions map[string]Permissions
expectedError error
}
SeagullMock struct{}
)

//A mock of the Gatekeeper interface
func NewGatekeeperMock() *GatekeeperMock {
return &GatekeeperMock{}
func NewGatekeeperMock(expectedPermissions map[string]Permissions, expectedError error) *GatekeeperMock {
return &GatekeeperMock{expectedPermissions, expectedError}
}

func (mock *GatekeeperMock) UserInGroup(userID, groupID string) (map[string]Permissions, error) {
perms := make(map[string]Permissions)
p := make(Permissions)
p["userid"] = userID
perms["root"] = p

return perms, nil
if mock.expectedPermissions != nil || mock.expectedError != nil {
return mock.expectedPermissions, mock.expectedError
} else {
return map[string]Permissions{"root": Permissions{"userid": userID}}, nil
}
}

func (mock *GatekeeperMock) SetPermissions(userID, groupID string, permissions Permissions) (map[string]Permissions, error) {
Expand Down
4 changes: 2 additions & 2 deletions clients/mocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestGatekeeperMock_UserInGroup(t *testing.T) {

expected := makeExpectedPermissons()

gkc := NewGatekeeperMock()
gkc := NewGatekeeperMock(nil, nil)

if perms, err := gkc.UserInGroup(USERID, GROUPID); err != nil {
t.Fatal("No error should be returned")
Expand All @@ -30,7 +30,7 @@ func TestGatekeeperMock_UserInGroup(t *testing.T) {
}
func TestGatekeeperMock_SetPermissions(t *testing.T) {

gkc := NewGatekeeperMock()
gkc := NewGatekeeperMock(nil, nil)

expected := makeExpectedPermissons()

Expand Down
90 changes: 86 additions & 4 deletions clients/shoreline/shoreline.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/tidepool-org/go-common/clients/disc"
"github.com/tidepool-org/go-common/clients/status"
"github.com/tidepool-org/go-common/errors"
"github.com/tidepool-org/go-common/jepson"
"io"
"log"
"net/http"
"net/url"
"sync"
"time"

"github.com/tidepool-org/go-common/clients/disc"
"github.com/tidepool-org/go-common/clients/status"
"github.com/tidepool-org/go-common/errors"
"github.com/tidepool-org/go-common/jepson"
)

//Generic client interface that we will implement and mock
Expand All @@ -26,6 +27,8 @@ type Client interface {
Signup(username, password, email string) (*UserData, error)
CheckToken(token string) *TokenData
TokenProvide() string
GetUser(userID, token string) (*UserData, error)
UpdateUser(user UserUpdate, token string) error
}

// UserApiClient manages the local data for a client. A client is intended to be shared among multiple
Expand Down Expand Up @@ -53,6 +56,13 @@ type UserData struct {
Emails []string // the array of email addresses associated with this account
}

// UserUpdate is the data structure for updating of a users details
type UserUpdate struct {
UserData
Password string
Authenticated bool //the user has verified the email used as part of signup
}

// TokenData is the data structure returned from a successful CheckToken query.
type TokenData struct {
UserID string // the UserID stored in the token
Expand Down Expand Up @@ -311,6 +321,78 @@ func (client *ShorelineClient) TokenProvide() string {
return client.serverToken
}

// Get user details for the given user
// In this case the userID could be the actual ID or an email address
func (client *ShorelineClient) GetUser(userID, token string) (*UserData, error) {
host := client.getHost()
if host == nil {
return nil, errors.New("No known user-api hosts.")
}

host.Path += fmt.Sprintf("user/%s", userID)

req, _ := http.NewRequest("GET", host.String(), nil)
req.Header.Add("x-tidepool-session-token", token)

res, err := client.httpClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "Failure to get a user")
}
defer res.Body.Close()

switch res.StatusCode {
case http.StatusOK:
ud, err := extractUserData(res.Body)
if err != nil {
return nil, err
}
return ud, nil
case http.StatusNoContent:
return &UserData{}, nil
default:
return nil, &status.StatusError{
status.NewStatusf(res.StatusCode, "Unknown response code from service[%s]", req.URL)}
}
}

// Get user details for the given user
// In this case the userID could be the actual ID or an email address
func (client *ShorelineClient) UpdateUser(user UserUpdate, token string) error {
host := client.getHost()
if host == nil {
return errors.New("No known user-api hosts.")
}

//structure that the update are given to us in
type updatesToApply struct {
Updates UserUpdate `json:"updates"`
}

host.Path += "/user/" + user.UserID

if jsonUser, err := json.Marshal(updatesToApply{Updates: user}); err != nil {
return &status.StatusError{
status.NewStatusf(http.StatusInternalServerError, "Error getting user updates [%s]", err.Error())}
} else {

req, _ := http.NewRequest("PUT", host.String(), bytes.NewBuffer(jsonUser))
req.Header.Add("x-tidepool-session-token", token)

res, err := client.httpClient.Do(req)
if err != nil {
return errors.Wrap(err, "Failure to get a user")
}

switch res.StatusCode {
case http.StatusOK:
return nil
default:
return &status.StatusError{
status.NewStatusf(res.StatusCode, "Unknown response code from service[%s]", req.URL)}
}
}
}

func (client *ShorelineClient) getHost() *url.URL {
if hostArr := client.hostGetter.HostGet(); len(hostArr) > 0 {
cpy := new(url.URL)
Expand Down
8 changes: 8 additions & 0 deletions clients/shoreline/shorelineMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,11 @@ func (client *ShorelineMockClient) CheckToken(token string) *TokenData {
func (client *ShorelineMockClient) TokenProvide() string {
return client.ServerToken
}

func (client *ShorelineMockClient) GetUser(userID, token string) (*UserData, error) {
return &UserData{UserID: userID, UserName: "From Mock", Emails: []string{userID}}, nil
}

func (client *ShorelineMockClient) UpdateUser(user UserUpdate, token string) error {
return nil
}
10 changes: 10 additions & 0 deletions clients/shoreline/shorelineMock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ func TestMock(t *testing.T) {
t.Error("Should give us token data")
}

if usr, _ := client.GetUser("[email protected]", TOKEN_MOCK); usr == nil {
t.Error("Should give us a mock user")
}

user := UserUpdate{UserData: UserData{UserID: "123", UserName: "name", Emails: []string{"[email protected]"}}, Password: "myN3wPw"}

if err := client.UpdateUser(user, TOKEN_MOCK); err != nil {
t.Error("Should return no error on success")
}

if sd, se := client.Signup("username", "password", "[email protected]"); sd == nil || se != nil {
t.Errorf("Signup not return err[%s]", se.Error())
}
Expand Down

0 comments on commit 6ea9c99

Please sign in to comment.