diff --git a/cli/create.go b/cli/create.go index e43aa898f358e..793f4d99b4839 100644 --- a/cli/create.go +++ b/cli/create.go @@ -140,7 +140,7 @@ func create() *cobra.Command { } after := time.Now() - workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{ + workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: workspaceName, AutostartSchedule: schedSpec, diff --git a/coderd/coderd.go b/coderd/coderd.go index d4a61da2c18f3..0ac4a7c68dc5f 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -292,7 +292,6 @@ func New(options *Options) *API { r.Get("/", api.templatesByOrganization) r.Get("/{templatename}", api.templateByOrganizationAndName) }) - r.Post("/workspaces", api.postWorkspacesByOrganization) r.Route("/members", func(r chi.Router) { r.Get("/roles", api.assignableOrgRoles) r.Route("/{user}", func(r chi.Router) { @@ -301,6 +300,7 @@ func New(options *Options) *API { httpmw.ExtractOrganizationMemberParam(options.Database), ) r.Put("/roles", api.putMemberRoles) + r.Post("/workspaces", api.postWorkspacesByOrganization) }) }) }) diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index 667e068e27961..60fca71cd0062 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -233,7 +233,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { AssertAction: rbac.ActionRead, AssertObject: rbac.ResourceTemplate.InOrg(a.Template.OrganizationID), }, - "POST:/api/v2/organizations/{organization}/workspaces": { + "POST:/api/v2/organizations/{organization}/members/{user}/workspaces": { AssertAction: rbac.ActionCreate, // No ID when creating AssertObject: workspaceRBACObj, diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index d1c3e390a3c93..1f3589ad51b26 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -523,7 +523,7 @@ func CreateWorkspace(t *testing.T, client *codersdk.Client, organization uuid.UU for _, mutator := range mutators { mutator(&req) } - workspace, err := client.CreateWorkspace(context.Background(), organization, req) + workspace, err := client.CreateWorkspace(context.Background(), organization, codersdk.Me, req) require.NoError(t, err) return workspace } diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 1f32c797599d6..c809242d8fed5 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -222,6 +222,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req organization = httpmw.OrganizationParam(r) apiKey = httpmw.APIKey(r) auditor = api.Auditor.Load() + user = httpmw.UserParam(r) aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, @@ -232,7 +233,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req defer commitAudit() if !api.Authorize(r, rbac.ActionCreate, - rbac.ResourceWorkspace.InOrg(organization.ID).WithOwner(apiKey.UserID.String())) { + rbac.ResourceWorkspace.InOrg(organization.ID).WithOwner(user.ID.String())) { httpapi.ResourceNotFound(rw) return } @@ -292,7 +293,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } workspace, err := api.Database.GetWorkspaceByOwnerIDAndName(ctx, database.GetWorkspaceByOwnerIDAndNameParams{ - OwnerID: apiKey.UserID, + OwnerID: user.ID, Name: createWorkspace.Name, }) if err == nil { @@ -359,7 +360,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req ID: uuid.New(), CreatedAt: now, UpdatedAt: now, - OwnerID: apiKey.UserID, + OwnerID: user.ID, OrganizationID: template.OrganizationID, TemplateID: template.ID, Name: createWorkspace.Name, @@ -441,7 +442,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req aReq.New = workspace users, err := api.Database.GetUsersByIDs(ctx, database.GetUsersByIDsParams{ - IDs: []uuid.UUID{apiKey.UserID, workspaceBuild.InitiatorID}, + IDs: []uuid.UUID{user.ID, workspaceBuild.InitiatorID}, }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ @@ -478,7 +479,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req workspace, apiBuild, template, - findUser(apiKey.UserID, users), + findUser(user.ID, users), )) } diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 11e23ea341c60..c94c4dd277bfb 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -156,7 +156,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - _, err := client.CreateWorkspace(ctx, user.OrganizationID, codersdk.CreateWorkspaceRequest{ + _, err := client.CreateWorkspace(ctx, user.OrganizationID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: uuid.New(), Name: "workspace", }) @@ -183,7 +183,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, other, org.ID, nil) template := coderdtest.CreateTemplate(t, other, org.ID, version.ID) - _, err = client.CreateWorkspace(ctx, first.OrganizationID, codersdk.CreateWorkspaceRequest{ + _, err = client.CreateWorkspace(ctx, first.OrganizationID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: "workspace", }) @@ -205,7 +205,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - _, err := client.CreateWorkspace(ctx, user.OrganizationID, codersdk.CreateWorkspaceRequest{ + _, err := client.CreateWorkspace(ctx, user.OrganizationID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: workspace.Name, }) @@ -285,7 +285,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { Name: "testing", TTLMillis: ptr.Ref((59 * time.Second).Milliseconds()), } - _, err := client.CreateWorkspace(ctx, template.OrganizationID, req) + _, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) require.Error(t, err) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -311,7 +311,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { Name: "testing", TTLMillis: ptr.Ref(template.MaxTTLMillis + time.Minute.Milliseconds()), } - _, err := client.CreateWorkspace(ctx, template.OrganizationID, req) + _, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) require.Error(t, err) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -338,7 +338,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { Name: "testing", AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"), } - _, err := client.CreateWorkspace(ctx, template.OrganizationID, req) + _, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) require.Error(t, err) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -412,7 +412,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { // Given: // We recreate the workspace with the same name - workspace, err = client.CreateWorkspace(ctx, user.OrganizationID, codersdk.CreateWorkspaceRequest{ + workspace, err = client.CreateWorkspace(ctx, user.OrganizationID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: workspace.TemplateID, Name: workspace.Name, AutostartSchedule: workspace.AutostartSchedule, @@ -772,7 +772,7 @@ func TestPostWorkspaceBuild(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - _, err := client.CreateWorkspace(ctx, user.OrganizationID, codersdk.CreateWorkspaceRequest{ + _, err := client.CreateWorkspace(ctx, user.OrganizationID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: "workspace", }) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index a3ef0a7a000e3..90af0cc257f64 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -198,8 +198,8 @@ func (c *Client) TemplateByName(ctx context.Context, organizationID uuid.UUID, n } // CreateWorkspace creates a new workspace for the template specified. -func (c *Client) CreateWorkspace(ctx context.Context, organizationID uuid.UUID, request CreateWorkspaceRequest) (Workspace, error) { - res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/organizations/%s/workspaces", organizationID), request) +func (c *Client) CreateWorkspace(ctx context.Context, organizationID uuid.UUID, user string, request CreateWorkspaceRequest) (Workspace, error) { + res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/organizations/%s/members/%s/workspaces", organizationID, user), request) if err != nil { return Workspace{}, err } diff --git a/site/src/api/api.ts b/site/src/api/api.ts index c907ecccca10d..225137dc486c6 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -302,10 +302,11 @@ export const createUser = async (user: TypesGen.CreateUserRequest): Promise => { const response = await axios.post( - `/api/v2/organizations/${organizationId}/workspaces`, + `/api/v2/organizations/${organizationId}/members/${userId}/workspaces`, workspace, ) return response.data diff --git a/site/src/xServices/createWorkspace/createWorkspaceXService.ts b/site/src/xServices/createWorkspace/createWorkspaceXService.ts index e30751cb58429..2b81709ceb3e4 100644 --- a/site/src/xServices/createWorkspace/createWorkspaceXService.ts +++ b/site/src/xServices/createWorkspace/createWorkspaceXService.ts @@ -128,7 +128,7 @@ export const createWorkspaceMachine = createMachine( throw new Error("No create workspace request") } - return createWorkspace(organizationId, createWorkspaceRequest) + return createWorkspace(organizationId, "me", createWorkspaceRequest) }, }, guards: {