Skip to content

Commit dbd5b4a

Browse files
authored
feat: Add workspace owner name to response (#1448)
This will be rendered in the workspace page!
1 parent 4cfc9af commit dbd5b4a

File tree

11 files changed

+116
-20
lines changed

11 files changed

+116
-20
lines changed

cli/templatedelete_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/stretchr/testify/require"
8+
79
"github.com/coder/coder/cli/clitest"
810
"github.com/coder/coder/coderd/coderdtest"
911
"github.com/coder/coder/codersdk"
1012
"github.com/coder/coder/pty/ptytest"
11-
"github.com/stretchr/testify/require"
1213
)
1314

1415
func TestTemplateDelete(t *testing.T) {

coderd/database/databasefake/databasefake.go

+16
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,22 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
242242
return users, nil
243243
}
244244

245+
func (q *fakeQuerier) GetUsersByIDs(_ context.Context, ids []uuid.UUID) ([]database.User, error) {
246+
q.mutex.RLock()
247+
defer q.mutex.RUnlock()
248+
249+
users := make([]database.User, 0)
250+
for _, user := range q.users {
251+
for _, id := range ids {
252+
if user.ID.String() != id.String() {
253+
continue
254+
}
255+
users = append(users, user)
256+
}
257+
}
258+
return users, nil
259+
}
260+
245261
func (q *fakeQuerier) GetAllUserRoles(_ context.Context, userID uuid.UUID) (database.GetAllUserRolesRow, error) {
246262
q.mutex.RLock()
247263
defer q.mutex.RUnlock()

coderd/database/querier.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

+36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/organizationmembers.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ SET
4949
WHERE
5050
user_id = @user_id
5151
AND organization_id = @org_id
52-
RETURNING *;
52+
RETURNING *;

coderd/database/queries/users.sql

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ WHERE
88
LIMIT
99
1;
1010

11+
-- name: GetUsersByIDs :many
12+
SELECT * FROM users WHERE id = ANY(@ids :: uuid [ ]);
13+
1114
-- name: GetUserByEmailOrUsername :one
1215
SELECT
1316
*

coderd/organizations.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ func (api *api) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
426426
}
427427

428428
httpapi.Write(rw, http.StatusOK, convertWorkspace(workspace,
429-
convertWorkspaceBuild(build, convertProvisionerJob(job)), template))
429+
convertWorkspaceBuild(build, convertProvisionerJob(job)), template, owner))
430430
}
431431

432432
// Create a new workspace for the currently authenticated user.
@@ -617,9 +617,16 @@ func (api *api) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
617617
})
618618
return
619619
}
620+
user, err := api.Database.GetUserByID(r.Context(), apiKey.UserID)
621+
if err != nil {
622+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
623+
Message: fmt.Sprintf("get user: %s", err),
624+
})
625+
return
626+
}
620627

621628
httpapi.Write(rw, http.StatusCreated, convertWorkspace(workspace,
622-
convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(templateVersionJob)), template))
629+
convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(templateVersionJob)), template, user))
623630
}
624631

625632
// convertOrganization consumes the database representation and outputs an API friendly representation.

coderd/workspaces.go

+42-13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/go-chi/chi/v5"
1212
"github.com/google/uuid"
1313
"github.com/moby/moby/pkg/namesgenerator"
14+
"golang.org/x/sync/errgroup"
1415
"golang.org/x/xerrors"
1516

1617
"github.com/coder/coder/coderd/autobuild/schedule"
@@ -30,21 +31,34 @@ func (api *api) workspace(rw http.ResponseWriter, r *http.Request) {
3031
})
3132
return
3233
}
33-
job, err := api.Database.GetProvisionerJobByID(r.Context(), build.JobID)
34+
var (
35+
group errgroup.Group
36+
job database.ProvisionerJob
37+
template database.Template
38+
owner database.User
39+
)
40+
group.Go(func() (err error) {
41+
job, err = api.Database.GetProvisionerJobByID(r.Context(), build.JobID)
42+
return err
43+
})
44+
group.Go(func() (err error) {
45+
template, err = api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
46+
return err
47+
})
48+
group.Go(func() (err error) {
49+
owner, err = api.Database.GetUserByID(r.Context(), workspace.OwnerID)
50+
return err
51+
})
52+
err = group.Wait()
3453
if err != nil {
3554
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
36-
Message: fmt.Sprintf("get workspace build job: %s", err),
55+
Message: fmt.Sprintf("fetch resource: %s", err),
3756
})
3857
return
3958
}
40-
template, err := api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
41-
if err != nil {
42-
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
43-
Message: fmt.Sprintf("get template: %s", err),
44-
})
45-
return
46-
}
47-
httpapi.Write(rw, http.StatusOK, convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template))
59+
60+
httpapi.Write(rw, http.StatusOK,
61+
convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template, owner))
4862
}
4963

5064
func (api *api) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
@@ -359,9 +373,11 @@ func (api *api) putWorkspaceAutostop(rw http.ResponseWriter, r *http.Request) {
359373
func convertWorkspaces(ctx context.Context, db database.Store, workspaces []database.Workspace) ([]codersdk.Workspace, error) {
360374
workspaceIDs := make([]uuid.UUID, 0, len(workspaces))
361375
templateIDs := make([]uuid.UUID, 0, len(workspaces))
376+
ownerIDs := make([]uuid.UUID, 0, len(workspaces))
362377
for _, workspace := range workspaces {
363378
workspaceIDs = append(workspaceIDs, workspace.ID)
364379
templateIDs = append(templateIDs, workspace.TemplateID)
380+
ownerIDs = append(ownerIDs, workspace.OwnerID)
365381
}
366382
workspaceBuilds, err := db.GetWorkspaceBuildsByWorkspaceIDsWithoutAfter(ctx, workspaceIDs)
367383
if errors.Is(err, sql.ErrNoRows) {
@@ -377,6 +393,10 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data
377393
if err != nil {
378394
return nil, xerrors.Errorf("get templates: %w", err)
379395
}
396+
users, err := db.GetUsersByIDs(ctx, ownerIDs)
397+
if err != nil {
398+
return nil, xerrors.Errorf("get users: %w", err)
399+
}
380400
jobIDs := make([]uuid.UUID, 0, len(workspaceBuilds))
381401
for _, build := range workspaceBuilds {
382402
jobIDs = append(jobIDs, build.JobID)
@@ -397,6 +417,10 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data
397417
for _, template := range templates {
398418
templateByID[template.ID] = template
399419
}
420+
userByID := map[uuid.UUID]database.User{}
421+
for _, user := range users {
422+
userByID[user.ID] = user
423+
}
400424
jobByID := map[uuid.UUID]database.ProvisionerJob{}
401425
for _, job := range jobs {
402426
jobByID[job.ID] = job
@@ -413,20 +437,25 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data
413437
}
414438
job, exists := jobByID[build.JobID]
415439
if !exists {
416-
return nil, xerrors.Errorf("build job not found for workspace: %q", err)
440+
return nil, xerrors.Errorf("build job not found for workspace: %w", err)
441+
}
442+
user, exists := userByID[workspace.OwnerID]
443+
if !exists {
444+
return nil, xerrors.Errorf("owner not found for workspace: %q", workspace.Name)
417445
}
418446
apiWorkspaces = append(apiWorkspaces,
419-
convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template))
447+
convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template, user))
420448
}
421449
return apiWorkspaces, nil
422450
}
423451

424-
func convertWorkspace(workspace database.Workspace, workspaceBuild codersdk.WorkspaceBuild, template database.Template) codersdk.Workspace {
452+
func convertWorkspace(workspace database.Workspace, workspaceBuild codersdk.WorkspaceBuild, template database.Template, owner database.User) codersdk.Workspace {
425453
return codersdk.Workspace{
426454
ID: workspace.ID,
427455
CreatedAt: workspace.CreatedAt,
428456
UpdatedAt: workspace.UpdatedAt,
429457
OwnerID: workspace.OwnerID,
458+
OwnerName: owner.Username,
430459
TemplateID: workspace.TemplateID,
431460
LatestBuild: workspaceBuild,
432461
TemplateName: template.Name,

codersdk/workspaces.go

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Workspace struct {
2020
CreatedAt time.Time `json:"created_at"`
2121
UpdatedAt time.Time `json:"updated_at"`
2222
OwnerID uuid.UUID `json:"owner_id"`
23+
OwnerName string `json:"owner_name"`
2324
TemplateID uuid.UUID `json:"template_id"`
2425
TemplateName string `json:"template_name"`
2526
LatestBuild WorkspaceBuild `json:"latest_build"`

site/src/api/typesGenerated.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export interface CreateUserRequest {
8585
readonly organization_id: string
8686
}
8787

88-
// From codersdk/workspaces.go:33:6
88+
// From codersdk/workspaces.go:34:6
8989
export interface CreateWorkspaceBuildRequest {
9090
readonly template_version_id?: string
9191
// This is likely an enum in an external package ("github.com/coder/coder/coderd/database.WorkspaceTransition")
@@ -289,12 +289,12 @@ export interface UpdateUserProfileRequest {
289289
readonly username: string
290290
}
291291

292-
// From codersdk/workspaces.go:95:6
292+
// From codersdk/workspaces.go:96:6
293293
export interface UpdateWorkspaceAutostartRequest {
294294
readonly schedule: string
295295
}
296296

297-
// From codersdk/workspaces.go:115:6
297+
// From codersdk/workspaces.go:116:6
298298
export interface UpdateWorkspaceAutostopRequest {
299299
readonly schedule: string
300300
}
@@ -355,6 +355,7 @@ export interface Workspace {
355355
readonly created_at: string
356356
readonly updated_at: string
357357
readonly owner_id: string
358+
readonly owner_name: string
358359
readonly template_id: string
359360
readonly template_name: string
360361
readonly latest_build: WorkspaceBuild

site/src/testHelpers/entities.ts

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export const MockWorkspace: TypesGen.Workspace = {
124124
template_name: MockTemplate.name,
125125
outdated: false,
126126
owner_id: MockUser.id,
127+
owner_name: MockUser.username,
127128
autostart_schedule: MockWorkspaceAutostartEnabled.schedule,
128129
autostop_schedule: MockWorkspaceAutostopEnabled.schedule,
129130
latest_build: MockWorkspaceBuild,

0 commit comments

Comments
 (0)