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
parent
1832ecb4f7
commit
fbff6cea76
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue