Create a new workspace for the currently authenticated user. @Summary Create user workspace @Description Create a new workspace using a template. The request must @Description specify either the Template ID or the Template Version ID, @Description not both. If the Template ID is specified, the acti
(rw http.ResponseWriter, r *http.Request)
| 435 | // @Success 200 {object} codersdk.Workspace |
| 436 | // @Router /api/v2/users/{user}/workspaces [post] |
| 437 | func (api *API) postUserWorkspaces(rw http.ResponseWriter, r *http.Request) { |
| 438 | var ( |
| 439 | ctx = r.Context() |
| 440 | apiKey = httpmw.APIKey(r) |
| 441 | auditor = api.Auditor.Load() |
| 442 | mems = httpmw.OrganizationMembersParam(r) |
| 443 | ) |
| 444 | |
| 445 | var req codersdk.CreateWorkspaceRequest |
| 446 | if !httpapi.Read(ctx, rw, r, &req) { |
| 447 | return |
| 448 | } |
| 449 | |
| 450 | var owner workspaceOwner |
| 451 | if mems.User != nil { |
| 452 | // This user fetch is an optimization path for the most common case of creating a |
| 453 | // workspace for 'Me'. |
| 454 | // |
| 455 | // This is also required to allow `owners` to create workspaces for users |
| 456 | // that are not in an organization. |
| 457 | owner = workspaceOwner{ |
| 458 | ID: mems.User.ID, |
| 459 | Username: mems.User.Username, |
| 460 | AvatarURL: mems.User.AvatarURL, |
| 461 | } |
| 462 | } else { |
| 463 | // A workspace can still be created if the caller can read the organization |
| 464 | // member. The organization is required, which can be sourced from the |
| 465 | // template. |
| 466 | // |
| 467 | // TODO: This code gets called twice for each workspace build request. |
| 468 | // This is inefficient and costs at most 2 extra RTTs to the DB. |
| 469 | // This can be optimized. It exists as it is now for code simplicity. |
| 470 | // The most common case is to create a workspace for 'Me'. Which does |
| 471 | // not enter this code branch. |
| 472 | template, err := requestTemplate(ctx, req, api.Database) |
| 473 | if err != nil { |
| 474 | httperror.WriteResponseError(ctx, rw, err) |
| 475 | return |
| 476 | } |
| 477 | |
| 478 | // If the caller can find the organization membership in the same org |
| 479 | // as the template, then they can continue. |
| 480 | orgIndex := slices.IndexFunc(mems.Memberships, func(mem httpmw.OrganizationMember) bool { |
| 481 | return mem.OrganizationID == template.OrganizationID |
| 482 | }) |
| 483 | if orgIndex == -1 { |
| 484 | httpapi.ResourceNotFound(rw) |
| 485 | return |
| 486 | } |
| 487 | |
| 488 | member := mems.Memberships[orgIndex] |
| 489 | owner = workspaceOwner{ |
| 490 | ID: member.UserID, |
| 491 | Username: member.Username, |
| 492 | AvatarURL: member.AvatarURL, |
| 493 | } |
| 494 | } |
nothing calls this directly
no test coverage detected