@@ -406,30 +406,46 @@ func (api *API) postUserWorkspaces(rw http.ResponseWriter, r *http.Request) {
406
406
ctx = r .Context ()
407
407
apiKey = httpmw .APIKey (r )
408
408
auditor = api .Auditor .Load ()
409
- user = httpmw .UserParam (r )
410
409
)
411
410
411
+ var req codersdk.CreateWorkspaceRequest
412
+ if ! httpapi .Read (ctx ,rw ,r ,& req ) {
413
+ return
414
+ }
415
+
416
+ // No middleware exists to fetch the user from. This endpoint needs to fetch
417
+ // the organization member, which requires the organization. Which can be
418
+ // sourced from the template.
419
+ //
420
+ // TODO: This code gets called twice for each workspace build request.
421
+ // This is inefficient and costs at most 2 extra RTTs to the DB.
422
+ // This can be optimized. It exists as it is now for code simplicity.
423
+ template ,ok := requestTemplate (ctx ,rw ,req ,api .Database )
424
+ if ! ok {
425
+ return
426
+ }
427
+
428
+ member ,ok := httpmw .ExtractOrganizationMemberContext (rw ,r ,api .Database ,template .OrganizationID )
429
+ if ! ok {
430
+ return
431
+ }
432
+
412
433
aReq ,commitAudit := audit .InitRequest [database.WorkspaceTable ](rw ,& audit.RequestParams {
413
434
Audit :* auditor ,
414
435
Log :api .Logger ,
415
436
Request :r ,
416
437
Action :database .AuditActionCreate ,
417
438
AdditionalFields : audit.AdditionalFields {
418
- WorkspaceOwner :user .Username ,
439
+ WorkspaceOwner :member .Username ,
419
440
},
420
441
})
421
442
422
443
defer commitAudit ()
423
444
424
- var req codersdk.CreateWorkspaceRequest
425
- if ! httpapi .Read (ctx ,rw ,r ,& req ) {
426
- return
427
- }
428
-
429
445
owner := workspaceOwner {
430
- ID :user . ID ,
431
- Username :user .Username ,
432
- AvatarURL :user .AvatarURL ,
446
+ ID :member . UserID ,
447
+ Username :member .Username ,
448
+ AvatarURL :member .AvatarURL ,
433
449
}
434
450
createWorkspace (ctx ,aReq ,apiKey .UserID ,api ,owner ,req ,rw ,r )
435
451
}
@@ -450,65 +466,8 @@ func createWorkspace(
450
466
rw http.ResponseWriter ,
451
467
r * http.Request ,
452
468
) {
453
- // If we were given a `TemplateVersionID`, we need to determine the `TemplateID` from it.
454
- templateID := req .TemplateID
455
- if templateID == uuid .Nil {
456
- templateVersion ,err := api .Database .GetTemplateVersionByID (ctx ,req .TemplateVersionID )
457
- if httpapi .Is404Error (err ) {
458
- httpapi .Write (ctx ,rw ,http .StatusBadRequest , codersdk.Response {
459
- Message :fmt .Sprintf ("Template version %q doesn't exist." ,templateID .String ()),
460
- Validations : []codersdk.ValidationError {{
461
- Field :"template_version_id" ,
462
- Detail :"template not found" ,
463
- }},
464
- })
465
- return
466
- }
467
- if err != nil {
468
- httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
469
- Message :"Internal error fetching template version." ,
470
- Detail :err .Error (),
471
- })
472
- return
473
- }
474
- if templateVersion .Archived {
475
- httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
476
- Message :"Archived template versions cannot be used to make a workspace." ,
477
- Validations : []codersdk.ValidationError {
478
- {
479
- Field :"template_version_id" ,
480
- Detail :"template version archived" ,
481
- },
482
- },
483
- })
484
- return
485
- }
486
-
487
- templateID = templateVersion .TemplateID .UUID
488
- }
489
-
490
- template ,err := api .Database .GetTemplateByID (ctx ,templateID )
491
- if httpapi .Is404Error (err ) {
492
- httpapi .Write (ctx ,rw ,http .StatusBadRequest , codersdk.Response {
493
- Message :fmt .Sprintf ("Template %q doesn't exist." ,templateID .String ()),
494
- Validations : []codersdk.ValidationError {{
495
- Field :"template_id" ,
496
- Detail :"template not found" ,
497
- }},
498
- })
499
- return
500
- }
501
- if err != nil {
502
- httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
503
- Message :"Internal error fetching template." ,
504
- Detail :err .Error (),
505
- })
506
- return
507
- }
508
- if template .Deleted {
509
- httpapi .Write (ctx ,rw ,http .StatusNotFound , codersdk.Response {
510
- Message :fmt .Sprintf ("Template %q has been deleted!" ,template .Name ),
511
- })
469
+ template ,ok := requestTemplate (ctx ,rw ,req ,api .Database )
470
+ if ! ok {
512
471
return
513
472
}
514
473
@@ -776,6 +735,72 @@ func createWorkspace(
776
735
httpapi .Write (ctx ,rw ,http .StatusCreated ,w )
777
736
}
778
737
738
+ func requestTemplate (ctx context.Context ,rw http.ResponseWriter ,req codersdk.CreateWorkspaceRequest ,db database.Store ) (database.Template ,bool ) {
739
+ // If we were given a `TemplateVersionID`, we need to determine the `TemplateID` from it.
740
+ templateID := req .TemplateID
741
+
742
+ if templateID == uuid .Nil {
743
+ templateVersion ,err := db .GetTemplateVersionByID (ctx ,req .TemplateVersionID )
744
+ if httpapi .Is404Error (err ) {
745
+ httpapi .Write (ctx ,rw ,http .StatusBadRequest , codersdk.Response {
746
+ Message :fmt .Sprintf ("Template version %q doesn't exist." ,req .TemplateVersionID ),
747
+ Validations : []codersdk.ValidationError {{
748
+ Field :"template_version_id" ,
749
+ Detail :"template not found" ,
750
+ }},
751
+ })
752
+ return database.Template {},false
753
+ }
754
+ if err != nil {
755
+ httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
756
+ Message :"Internal error fetching template version." ,
757
+ Detail :err .Error (),
758
+ })
759
+ return database.Template {},false
760
+ }
761
+ if templateVersion .Archived {
762
+ httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
763
+ Message :"Archived template versions cannot be used to make a workspace." ,
764
+ Validations : []codersdk.ValidationError {
765
+ {
766
+ Field :"template_version_id" ,
767
+ Detail :"template version archived" ,
768
+ },
769
+ },
770
+ })
771
+ return database.Template {},false
772
+ }
773
+
774
+ templateID = templateVersion .TemplateID .UUID
775
+ }
776
+
777
+ template ,err := db .GetTemplateByID (ctx ,templateID )
778
+ if httpapi .Is404Error (err ) {
779
+ httpapi .Write (ctx ,rw ,http .StatusBadRequest , codersdk.Response {
780
+ Message :fmt .Sprintf ("Template %q doesn't exist." ,templateID ),
781
+ Validations : []codersdk.ValidationError {{
782
+ Field :"template_id" ,
783
+ Detail :"template not found" ,
784
+ }},
785
+ })
786
+ return database.Template {},false
787
+ }
788
+ if err != nil {
789
+ httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
790
+ Message :"Internal error fetching template." ,
791
+ Detail :err .Error (),
792
+ })
793
+ return database.Template {},false
794
+ }
795
+ if template .Deleted {
796
+ httpapi .Write (ctx ,rw ,http .StatusNotFound , codersdk.Response {
797
+ Message :fmt .Sprintf ("Template %q has been deleted!" ,template .Name ),
798
+ })
799
+ return database.Template {},false
800
+ }
801
+ return template ,true
802
+ }
803
+
779
804
func (api * API )notifyWorkspaceCreated (
780
805
ctx context.Context ,
781
806
receiverID uuid.UUID ,