Add user that made the request to organization

Previously, when an org was created it had no users. Now when an
organization is created, the user that made the request is added to the
organization with the admin role.

If there are any errors when adding the user the organization, we make a
best effort attempt to delete the organization. However it is still
possilbe that an organization would be created, but have no users if our
best effort fails.
pull/2325/head
Michael Desa 2017-11-09 16:31:56 -05:00
parent 1832ecb4f7
commit fbff6cea76
2 changed files with 140 additions and 4 deletions

View File

@ -1,6 +1,7 @@
package server
import (
"context"
"encoding/json"
"fmt"
"net/http"
@ -8,6 +9,7 @@ import (
"github.com/bouk/httprouter"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/organizations"
"github.com/influxdata/chronograf/roles"
)
@ -123,6 +125,34 @@ func (s *Service) NewOrganization(w http.ResponseWriter, r *http.Request) {
return
}
// Now that the organization was created, add the user
// making the request to the organization
user, ok := hasUserContext(ctx)
if !ok {
// Best attempt at cleanup the organization if there were any errors
_ = s.Store.Organizations(ctx).Delete(ctx, res)
Error(w, http.StatusInternalServerError, "failed to retrieve user from context", s.Logger)
return
}
orgID := fmt.Sprintf("%d", res.ID)
user.Roles = []chronograf.Role{
{
Organization: orgID,
Name: roles.AdminRoleName,
},
}
orgCtx := context.WithValue(ctx, organizations.ContextKey, orgID)
_, err = s.Store.Users(orgCtx).Add(orgCtx, user)
if err != nil {
// Best attempt at cleanup the organization if there were any errors adding user to org
_ = s.Store.Organizations(ctx).Delete(ctx, res)
s.Logger.Error("failed to add user to organization", err.Error())
Error(w, http.StatusInternalServerError, "failed to add user to organization", s.Logger)
return
}
co := newOrganizationResponse(res)
location(w, co.Links.Self)
encodeJSON(w, http.StatusCreated, co, s.Logger)

View File

@ -352,12 +352,14 @@ func TestService_RemoveOrganization(t *testing.T) {
func TestService_NewOrganization(t *testing.T) {
type fields struct {
OrganizationsStore chronograf.OrganizationsStore
UsersStore chronograf.UsersStore
Logger chronograf.Logger
}
type args struct {
w *httptest.ResponseRecorder
r *http.Request
org *organizationRequest
w *httptest.ResponseRecorder
r *http.Request
org *organizationRequest
user *chronograf.User
}
tests := []struct {
name string
@ -377,12 +379,28 @@ func TestService_NewOrganization(t *testing.T) {
"http://any.url", // can be any valid URL as we are bypassing mux
nil,
),
user: &chronograf.User{
ID: 1,
Name: "bobetta",
Provider: "github",
Scheme: "oauth2",
},
org: &organizationRequest{
Name: "The Good Place",
},
},
fields: fields{
Logger: log.New(log.DebugLevel),
UsersStore: &mocks.UsersStore{
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
return &chronograf.User{
ID: 1,
Name: "bobetta",
Provider: "github",
Scheme: "oauth2",
}, nil
},
},
OrganizationsStore: &mocks.OrganizationsStore{
AddF: func(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
return &chronograf.Organization{
@ -396,17 +414,105 @@ func TestService_NewOrganization(t *testing.T) {
wantContentType: "application/json",
wantBody: `{"id":"1337","name":"The Good Place","links":{"self":"/chronograf/v1/organizations/1337"}}`,
},
{
name: "Create Organization - no user on context",
args: args{
w: httptest.NewRecorder(),
r: httptest.NewRequest(
"GET",
"http://any.url", // can be any valid URL as we are bypassing mux
nil,
),
org: &organizationRequest{
Name: "The Good Place",
},
},
fields: fields{
Logger: log.New(log.DebugLevel),
UsersStore: &mocks.UsersStore{
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
return &chronograf.User{
ID: 1,
Name: "bobetta",
Provider: "github",
Scheme: "oauth2",
}, nil
},
},
OrganizationsStore: &mocks.OrganizationsStore{
AddF: func(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 1337,
Name: "The Good Place",
}, nil
},
DeleteF: func(ctx context.Context, o *chronograf.Organization) error {
return nil
},
},
},
wantStatus: http.StatusInternalServerError,
wantContentType: "application/json",
wantBody: `{"code":500,"message":"failed to retrieve user from context"}`,
},
{
name: "Create Organization - failed to add user to organization",
args: args{
w: httptest.NewRecorder(),
r: httptest.NewRequest(
"GET",
"http://any.url", // can be any valid URL as we are bypassing mux
nil,
),
org: &organizationRequest{
Name: "The Good Place",
},
user: &chronograf.User{
ID: 1,
Name: "bobetta",
Provider: "github",
Scheme: "oauth2",
},
},
fields: fields{
Logger: log.New(log.DebugLevel),
UsersStore: &mocks.UsersStore{
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
return nil, fmt.Errorf("failed to add user to org")
},
},
OrganizationsStore: &mocks.OrganizationsStore{
AddF: func(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 1337,
Name: "The Good Place",
}, nil
},
DeleteF: func(ctx context.Context, o *chronograf.Organization) error {
return nil
},
},
},
wantStatus: http.StatusInternalServerError,
wantContentType: "application/json",
wantBody: `{"code":500,"message":"failed to add user to organization"}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Service{
Store: &Store{
Store: &mocks.Store{
OrganizationsStore: tt.fields.OrganizationsStore,
UsersStore: tt.fields.UsersStore,
},
Logger: tt.fields.Logger,
}
ctx := tt.args.r.Context()
ctx = context.WithValue(ctx, UserKey, tt.args.user)
tt.args.r = tt.args.r.WithContext(ctx)
buf, _ := json.Marshal(tt.args.org)
tt.args.r.Body = ioutil.NopCloser(bytes.NewReader(buf))
s.NewOrganization(tt.args.w, tt.args.r)