From 142ad4eeb8b188577c2dde35cd2ae78734f59c93 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 13:01:47 +0000 Subject: [PATCH 1/9] feat: added include_deleted relates to #1955 --- coderd/workspaces.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 25fd67d581cba..6e90e56c94e72 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -165,10 +165,37 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) owner := httpmw.UserParam(r) workspaceName := chi.URLParam(r, "workspacename") + var ( + includeDeletedStr = r.URL.Query().Get("include_deleted") + includeDeleted = false + ) + if includeDeletedStr != "" { + var err error + includeDeleted, err = strconv.ParseBool(includeDeletedStr) + if err != nil { + httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ + Message: fmt.Sprintf("Invalid boolean value %q for \"include_deleted\" query param.", includeDeletedStr), + Validations: []httpapi.Error{ + {Field: "include_deleted", Detail: "Must be a valid boolean"}, + }, + }) + return + } + } + workspace, err := api.Database.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{ OwnerID: owner.ID, Name: workspaceName, }) + + if includeDeleted && errors.Is(err, sql.ErrNoRows) { + workspace, err = api.Database.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{ + OwnerID: owner.ID, + Name: workspaceName, + Deleted: includeDeleted, + }) + } + if errors.Is(err, sql.ErrNoRows) { // Do not leak information if the workspace exists or not httpapi.Forbidden(rw) From 5c77ea41104c1c0be625697e1efe66bd99a082ac Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 10:25:04 -0400 Subject: [PATCH 2/9] Update coderd/workspaces.go defining vars in the scope of conditional Co-authored-by: Mathias Fredriksson --- coderd/workspaces.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 6e90e56c94e72..0885053df90ca 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -165,13 +165,10 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) owner := httpmw.UserParam(r) workspaceName := chi.URLParam(r, "workspacename") - var ( - includeDeletedStr = r.URL.Query().Get("include_deleted") - includeDeleted = false - ) - if includeDeletedStr != "" { + includeDeleted := false + if s := r.URL.Query().Get("include_deleted"); s != "" { var err error - includeDeleted, err = strconv.ParseBool(includeDeletedStr) + includeDeleted, err = strconv.ParseBool(s) if err != nil { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ Message: fmt.Sprintf("Invalid boolean value %q for \"include_deleted\" query param.", includeDeletedStr), From 31f40136cb27dfca966874cd3cb810105df4d17a Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 10:26:02 -0400 Subject: [PATCH 3/9] Update coderd/workspaces.go avoid newline Co-authored-by: Mathias Fredriksson --- coderd/workspaces.go | 1 - 1 file changed, 1 deletion(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 0885053df90ca..5744d192c20df 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -184,7 +184,6 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) OwnerID: owner.ID, Name: workspaceName, }) - if includeDeleted && errors.Is(err, sql.ErrNoRows) { workspace, err = api.Database.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{ OwnerID: owner.ID, From 9389df38dfface97e2c04cbea516337035b10583 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 10:26:11 -0400 Subject: [PATCH 4/9] Update coderd/workspaces.go Co-authored-by: Mathias Fredriksson --- coderd/workspaces.go | 1 - 1 file changed, 1 deletion(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 5744d192c20df..020fd78d37456 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -191,7 +191,6 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) Deleted: includeDeleted, }) } - if errors.Is(err, sql.ErrNoRows) { // Do not leak information if the workspace exists or not httpapi.Forbidden(rw) From 769ea99882eb7ef96efb23e2f08cce2e687b53dc Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 15:13:48 +0000 Subject: [PATCH 5/9] PR feedback --- .vscode/settings.json | 1 + coderd/workspaces.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 396b551029288..a7c4e8086ffdc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -83,6 +83,7 @@ "workspaceapp", "workspaceapps", "workspacebuilds", + "workspacename", "wsconncache", "xerrors", "xstate", diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 020fd78d37456..079f880ed44f3 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -171,7 +171,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) includeDeleted, err = strconv.ParseBool(s) if err != nil { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ - Message: fmt.Sprintf("Invalid boolean value %q for \"include_deleted\" query param.", includeDeletedStr), + Message: fmt.Sprintf("Invalid boolean value %q for \"include_deleted\" query param.", s), Validations: []httpapi.Error{ {Field: "include_deleted", Detail: "Must be a valid boolean"}, }, From f8a844ce1965584c7490c5106f53e9161d15286d Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 16:36:26 +0000 Subject: [PATCH 6/9] wrote test, added type --- cli/create.go | 4 ++-- cli/root.go | 2 +- coderd/workspaces_test.go | 33 +++++++++++++++++++++++++++++++-- codersdk/workspaces.go | 12 ++++++++++-- site/src/api/api.ts | 4 +++- site/src/api/typesGenerated.ts | 5 +++++ 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/cli/create.go b/cli/create.go index 4a178bf1f5a2c..0b4f042a959fe 100644 --- a/cli/create.go +++ b/cli/create.go @@ -49,7 +49,7 @@ func create() *cobra.Command { workspaceName, err = cliui.Prompt(cmd, cliui.PromptOptions{ Text: "Specify a name for your workspace:", Validate: func(workspaceName string) error { - _, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName) + _, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceByOwnerAndNameParams{}) if err == nil { return xerrors.Errorf("A workspace already exists named %q!", workspaceName) } @@ -61,7 +61,7 @@ func create() *cobra.Command { } } - _, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName) + _, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceByOwnerAndNameParams{}) if err == nil { return xerrors.Errorf("A workspace already exists named %q!", workspaceName) } diff --git a/cli/root.go b/cli/root.go index abf69c84f54cd..2e56ab280d880 100644 --- a/cli/root.go +++ b/cli/root.go @@ -214,7 +214,7 @@ func namedWorkspace(cmd *cobra.Command, client *codersdk.Client, identifier stri return codersdk.Workspace{}, xerrors.Errorf("invalid workspace name: %q", identifier) } - return client.WorkspaceByOwnerAndName(cmd.Context(), owner, name) + return client.WorkspaceByOwnerAndName(cmd.Context(), owner, name, codersdk.WorkspaceByOwnerAndNameParams{}) } // createConfig consumes the global configuration flag to produce a config root. diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 665c2d0a49d88..58b705ea27916 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -258,7 +258,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) - _, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, "something") + _, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, "something", codersdk.WorkspaceByOwnerAndNameParams{}) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode()) @@ -271,9 +271,38 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - _, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, workspace.Name) + _, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{}) require.NoError(t, err) }) + t.Run("deletedGetWorkspaceByOwnerAndName", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + + // Given: + // We delete the workspace + build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionDelete, + }) + require.NoError(t, err, "delete the workspace") + coderdtest.AwaitWorkspaceBuildJob(t, client, build.ID) + + // Then: + // when we call without includes_deleted, we don't expect to get the workspace back + _, err = client.WorkspaceByOwnerAndName(context.Background(), workspace.OwnerName, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{}) + require.ErrorContains(t, err, "403") + + // Then: + // When we call with includes_deleted, we should get the workspace back + workspaceNew, err := client.WorkspaceByOwnerAndName(context.Background(), workspace.OwnerName, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{IncludeDeleted: true}) + require.NoError(t, err) + require.Equal(t, workspace.ID, workspaceNew.ID) + }) } func TestWorkspaceFilter(t *testing.T) { diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index 3e81645957314..67db13a422459 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -258,9 +258,17 @@ func (c *Client) Workspaces(ctx context.Context, filter WorkspaceFilter) ([]Work return workspaces, json.NewDecoder(res.Body).Decode(&workspaces) } +type WorkspaceByOwnerAndNameParams struct { + IncludeDeleted bool `json:"include_deleted,omitempty"` +} + // WorkspaceByOwnerAndName returns a workspace by the owner's UUID and the workspace's name. -func (c *Client) WorkspaceByOwnerAndName(ctx context.Context, owner string, name string) (Workspace, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/workspace/%s", owner, name), nil) +func (c *Client) WorkspaceByOwnerAndName(ctx context.Context, owner string, name string, params WorkspaceByOwnerAndNameParams) (Workspace, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/workspace/%s", owner, name), nil, func(r *http.Request) { + q := r.URL.Query() + q.Set("include_deleted", fmt.Sprintf("%t", params.IncludeDeleted)) + r.URL.RawQuery = q.Encode() + }) if err != nil { return Workspace{}, err } diff --git a/site/src/api/api.ts b/site/src/api/api.ts index c86748b2b64cd..c2186f8dc4cad 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -142,7 +142,9 @@ export const getWorkspaceByOwnerAndName = async ( username = "me", workspaceName: string, ): Promise => { - const response = await axios.get(`/api/v2/users/${username}/workspace/${workspaceName}`) + const response = await axios.get(`/api/v2/users/${username}/workspace/${workspaceName}`, { + params: { include_deleted: true }, + }) return response.data } diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index e403fe80fddff..61395af7c6d55 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -456,6 +456,11 @@ export interface WorkspaceBuildsRequest extends Pagination { readonly WorkspaceID: string } +// From codersdk/workspaces.go:261:6 +export interface WorkspaceByOwnerAndNameParams { + readonly include_deleted?: boolean +} + // From codersdk/workspaces.go:219:6 export interface WorkspaceFilter { readonly organization_id?: string From 56bceb614a62535167f9cd3ce5bca2202f12b6cb Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 13:23:35 -0400 Subject: [PATCH 7/9] Update coderd/workspaces_test.go shortening test name Co-authored-by: Cian Johnston --- coderd/workspaces_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 58b705ea27916..e28a0b77f9c9e 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -274,7 +274,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { _, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{}) require.NoError(t, err) }) - t.Run("deletedGetWorkspaceByOwnerAndName", func(t *testing.T) { + t.Run("Deleted", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) user := coderdtest.CreateFirstUser(t, client) From ee1f417fdadf0d6a7f353beb36e439c3ea258be0 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 17:38:37 +0000 Subject: [PATCH 8/9] taking out api.ts change for now --- site/src/api/api.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/site/src/api/api.ts b/site/src/api/api.ts index c2186f8dc4cad..c86748b2b64cd 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -142,9 +142,7 @@ export const getWorkspaceByOwnerAndName = async ( username = "me", workspaceName: string, ): Promise => { - const response = await axios.get(`/api/v2/users/${username}/workspace/${workspaceName}`, { - params: { include_deleted: true }, - }) + const response = await axios.get(`/api/v2/users/${username}/workspace/${workspaceName}`) return response.data } From 538155464921571e46709deae63cd2717295718f Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 8 Jun 2022 17:40:21 +0000 Subject: [PATCH 9/9] casing --- coderd/workspaces_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index e28a0b77f9c9e..73fed89c80c79 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -293,7 +293,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { coderdtest.AwaitWorkspaceBuildJob(t, client, build.ID) // Then: - // when we call without includes_deleted, we don't expect to get the workspace back + // When we call without includes_deleted, we don't expect to get the workspace back _, err = client.WorkspaceByOwnerAndName(context.Background(), workspace.OwnerName, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{}) require.ErrorContains(t, err, "403") pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy