diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index fb5236fe610a2..6bb45c4fb3c23 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -1330,24 +1330,21 @@ const docTemplate = `{ } } }, - "/organizations/{organization}/templateversions": { - "post": { + "/organizations/{organization}/templates/{templatename}/versions/{templateversionname}": { + "get": { "security": [ { "CoderSessionToken": [] } ], - "consumes": [ - "application/json" - ], "produces": [ "application/json" ], "tags": [ "Templates" ], - "summary": "Create template version by organization", - "operationId": "create-template-version-by-organization", + "summary": "Get template version by organization, template, and name", + "operationId": "get-template-version-by-organization-template-and-name", "parameters": [ { "type": "string", @@ -1358,18 +1355,23 @@ const docTemplate = `{ "required": true }, { - "description": "Create template version request", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/codersdk.CreateTemplateVersionDryRunRequest" - } + "type": "string", + "description": "Template name", + "name": "templatename", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Template version name", + "name": "templateversionname", + "in": "path", + "required": true } ], "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "schema": { "$ref": "#/definitions/codersdk.TemplateVersion" } @@ -1377,7 +1379,7 @@ const docTemplate = `{ } } }, - "/organizations/{organization}/templateversions/{templateversionname}": { + "/organizations/{organization}/templates/{templatename}/versions/{templateversionname}/previous": { "get": { "security": [ { @@ -1390,8 +1392,8 @@ const docTemplate = `{ "tags": [ "Templates" ], - "summary": "Get template version by organization and name", - "operationId": "get-template-version-by-organization-and-name", + "summary": "Get previous template version by organization, template, and name", + "operationId": "get-previous-template-version-by-organization-template-and-name", "parameters": [ { "type": "string", @@ -1401,6 +1403,13 @@ const docTemplate = `{ "in": "path", "required": true }, + { + "type": "string", + "description": "Template name", + "name": "templatename", + "in": "path", + "required": true + }, { "type": "string", "description": "Template version name", @@ -1419,21 +1428,24 @@ const docTemplate = `{ } } }, - "/organizations/{organization}/templateversions/{templateversionname}/previous": { - "get": { + "/organizations/{organization}/templateversions": { + "post": { "security": [ { "CoderSessionToken": [] } ], + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "Templates" ], - "summary": "Get previous template version by organization and name", - "operationId": "get-previous-template-version-by-organization-and-name", + "summary": "Create template version by organization", + "operationId": "create-template-version-by-organization", "parameters": [ { "type": "string", @@ -1444,16 +1456,18 @@ const docTemplate = `{ "required": true }, { - "type": "string", - "description": "Template version name", - "name": "templateversionname", - "in": "path", - "required": true + "description": "Create template version request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateTemplateVersionDryRunRequest" + } } ], "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "schema": { "$ref": "#/definitions/codersdk.TemplateVersion" } diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 0d6c224dbc1a6..91c1d15ff255a 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -1160,18 +1160,17 @@ } } }, - "/organizations/{organization}/templateversions": { - "post": { + "/organizations/{organization}/templates/{templatename}/versions/{templateversionname}": { + "get": { "security": [ { "CoderSessionToken": [] } ], - "consumes": ["application/json"], "produces": ["application/json"], "tags": ["Templates"], - "summary": "Create template version by organization", - "operationId": "create-template-version-by-organization", + "summary": "Get template version by organization, template, and name", + "operationId": "get-template-version-by-organization-template-and-name", "parameters": [ { "type": "string", @@ -1182,18 +1181,23 @@ "required": true }, { - "description": "Create template version request", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/codersdk.CreateTemplateVersionDryRunRequest" - } + "type": "string", + "description": "Template name", + "name": "templatename", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Template version name", + "name": "templateversionname", + "in": "path", + "required": true } ], "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "schema": { "$ref": "#/definitions/codersdk.TemplateVersion" } @@ -1201,7 +1205,7 @@ } } }, - "/organizations/{organization}/templateversions/{templateversionname}": { + "/organizations/{organization}/templates/{templatename}/versions/{templateversionname}/previous": { "get": { "security": [ { @@ -1210,8 +1214,8 @@ ], "produces": ["application/json"], "tags": ["Templates"], - "summary": "Get template version by organization and name", - "operationId": "get-template-version-by-organization-and-name", + "summary": "Get previous template version by organization, template, and name", + "operationId": "get-previous-template-version-by-organization-template-and-name", "parameters": [ { "type": "string", @@ -1221,6 +1225,13 @@ "in": "path", "required": true }, + { + "type": "string", + "description": "Template name", + "name": "templatename", + "in": "path", + "required": true + }, { "type": "string", "description": "Template version name", @@ -1239,17 +1250,18 @@ } } }, - "/organizations/{organization}/templateversions/{templateversionname}/previous": { - "get": { + "/organizations/{organization}/templateversions": { + "post": { "security": [ { "CoderSessionToken": [] } ], + "consumes": ["application/json"], "produces": ["application/json"], "tags": ["Templates"], - "summary": "Get previous template version by organization and name", - "operationId": "get-previous-template-version-by-organization-and-name", + "summary": "Create template version by organization", + "operationId": "create-template-version-by-organization", "parameters": [ { "type": "string", @@ -1260,16 +1272,18 @@ "required": true }, { - "type": "string", - "description": "Template version name", - "name": "templateversionname", - "in": "path", - "required": true + "description": "Create template version request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateTemplateVersionDryRunRequest" + } } ], "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "schema": { "$ref": "#/definitions/codersdk.TemplateVersion" } diff --git a/coderd/coderd.go b/coderd/coderd.go index 179d10498b478..46630aae8e4f8 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -394,16 +394,18 @@ func New(options *Options) *API { httpmw.ExtractOrganizationParam(options.Database), ) r.Get("/", api.organization) - r.Route("/templateversions", func(r chi.Router) { - r.Post("/", api.postTemplateVersionsByOrganization) - r.Get("/{templateversionname}", api.templateVersionByOrganizationAndName) - r.Get("/{templateversionname}/previous", api.previousTemplateVersionByOrganizationAndName) - }) + r.Post("/templateversions", api.postTemplateVersionsByOrganization) r.Route("/templates", func(r chi.Router) { r.Post("/", api.postTemplateByOrganization) r.Get("/", api.templatesByOrganization) - r.Get("/{templatename}", api.templateByOrganizationAndName) r.Get("/examples", api.templateExamples) + r.Route("/{templatename}", func(r chi.Router) { + r.Get("/", api.templateByOrganizationAndName) + r.Route("/versions/{templateversionname}", func(r chi.Router) { + r.Get("/", api.templateVersionByOrganizationTemplateAndName) + r.Get("/previous", api.previousTemplateVersionByOrganizationTemplateAndName) + }) + }) }) r.Route("/members", func(r chi.Router) { r.Get("/roles", api.assignableOrgRoles) diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index 14019815d2a43..0a95e8bb522a3 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -239,6 +239,14 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { AssertAction: rbac.ActionRead, AssertObject: templateObj, }, + "GET:/api/v2/organizations/{organization}/templates/{templatename}/versions/{templateversionname}": { + AssertAction: rbac.ActionRead, + AssertObject: templateObj, + }, + "GET:/api/v2/organizations/{organization}/templates/{templatename}/versions/{templateversionname}/previous": { + AssertAction: rbac.ActionRead, + AssertObject: templateObj, + }, "POST:/api/v2/organizations/{organization}/members/{user}/workspaces": { AssertAction: rbac.ActionCreate, // No ID when creating @@ -252,12 +260,10 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { "GET:/api/v2/applications/auth-redirect": {AssertAction: rbac.ActionCreate, AssertObject: rbac.ResourceAPIKey}, // These endpoints need payloads to get to the auth part. Payloads will be required - "PUT:/api/v2/users/{user}/roles": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, - "PUT:/api/v2/organizations/{organization}/members/{user}/roles": {NoAuthorize: true}, - "POST:/api/v2/workspaces/{workspace}/builds": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, - "POST:/api/v2/organizations/{organization}/templateversions": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, - "GET:/api/v2/organizations/{organization}/templateversions/{templateversionname}": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, - "GET:/api/v2/organizations/{organization}/templateversions/{templateversionname}/previous": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, + "PUT:/api/v2/users/{user}/roles": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, + "PUT:/api/v2/organizations/{organization}/members/{user}/roles": {NoAuthorize: true}, + "POST:/api/v2/workspaces/{workspace}/builds": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, + "POST:/api/v2/organizations/{organization}/templateversions": {StatusCode: http.StatusBadRequest, NoAuthorize: true}, // Endpoints that use the SQLQuery filter. "GET:/api/v2/workspaces/": { diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 800bf3d48ba88..502b3c83447b9 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -1797,26 +1797,6 @@ func (q *fakeQuerier) GetTemplateVersionParameters(_ context.Context, templateVe return parameters, nil } -func (q *fakeQuerier) GetTemplateVersionByOrganizationAndName(_ context.Context, arg database.GetTemplateVersionByOrganizationAndNameParams) (database.TemplateVersion, error) { - if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersion{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, templateVersion := range q.templateVersions { - if templateVersion.OrganizationID != arg.OrganizationID { - continue - } - if !strings.EqualFold(templateVersion.Name, arg.Name) { - continue - } - return templateVersion, nil - } - return database.TemplateVersion{}, sql.ErrNoRows -} - func (q *fakeQuerier) GetTemplateVersionByID(_ context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) { q.mutex.RLock() defer q.mutex.RUnlock() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index f930af0a941e6..a9ea854bcc6d0 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -83,7 +83,6 @@ type sqlcQuerier interface { GetTemplateDAUs(ctx context.Context, templateID uuid.UUID) ([]GetTemplateDAUsRow, error) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (TemplateVersion, error) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.UUID) (TemplateVersion, error) - GetTemplateVersionByOrganizationAndName(ctx context.Context, arg GetTemplateVersionByOrganizationAndNameParams) (TemplateVersion, error) GetTemplateVersionByTemplateIDAndName(ctx context.Context, arg GetTemplateVersionByTemplateIDAndNameParams) (TemplateVersion, error) GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionParameter, error) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UUID) ([]TemplateVersion, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 0844e2dd48331..f0897b3ed17b6 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3677,38 +3677,6 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U return i, err } -const getTemplateVersionByOrganizationAndName = `-- name: GetTemplateVersionByOrganizationAndName :one -SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by -FROM - template_versions -WHERE - organization_id = $1 - AND "name" = $2 -` - -type GetTemplateVersionByOrganizationAndNameParams struct { - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - Name string `db:"name" json:"name"` -} - -func (q *sqlQuerier) GetTemplateVersionByOrganizationAndName(ctx context.Context, arg GetTemplateVersionByOrganizationAndNameParams) (TemplateVersion, error) { - row := q.db.QueryRowContext(ctx, getTemplateVersionByOrganizationAndName, arg.OrganizationID, arg.Name) - var i TemplateVersion - err := row.Scan( - &i.ID, - &i.TemplateID, - &i.OrganizationID, - &i.CreatedAt, - &i.UpdatedAt, - &i.Name, - &i.Readme, - &i.JobID, - &i.CreatedBy, - ) - return i, err -} - const getTemplateVersionByTemplateIDAndName = `-- name: GetTemplateVersionByTemplateIDAndName :one SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by diff --git a/coderd/database/queries/templateversions.sql b/coderd/database/queries/templateversions.sql index d49d86bf562ea..78dcff44e2d30 100644 --- a/coderd/database/queries/templateversions.sql +++ b/coderd/database/queries/templateversions.sql @@ -52,15 +52,6 @@ WHERE template_id = $1 AND "name" = $2; --- name: GetTemplateVersionByOrganizationAndName :one -SELECT - * -FROM - template_versions -WHERE - organization_id = $1 - AND "name" = $2; - -- name: GetTemplateVersionByID :one SELECT * diff --git a/coderd/templateversions.go b/coderd/templateversions.go index abcf87ce1ee3c..f013912521b35 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -763,22 +763,50 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user)) } -// @Summary Get template version by organization and name -// @ID get-template-version-by-organization-and-name +// @Summary Get template version by organization, template, and name +// @ID get-template-version-by-organization-template-and-name // @Security CoderSessionToken // @Produce json // @Tags Templates // @Param organization path string true "Organization ID" format(uuid) +// @Param templatename path string true "Template name" // @Param templateversionname path string true "Template version name" // @Success 200 {object} codersdk.TemplateVersion -// @Router /organizations/{organization}/templateversions/{templateversionname} [get] -func (api *API) templateVersionByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { +// @Router /organizations/{organization}/templates/{templatename}/versions/{templateversionname} [get] +func (api *API) templateVersionByOrganizationTemplateAndName(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() organization := httpmw.OrganizationParam(r) - templateVersionName := chi.URLParam(r, "templateversionname") - templateVersion, err := api.Database.GetTemplateVersionByOrganizationAndName(ctx, database.GetTemplateVersionByOrganizationAndNameParams{ + templateName := chi.URLParam(r, "templatename") + + template, err := api.Database.GetTemplateByOrganizationAndName(ctx, database.GetTemplateByOrganizationAndNameParams{ OrganizationID: organization.ID, - Name: templateVersionName, + Name: templateName, + }) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + httpapi.ResourceNotFound(rw) + return + } + + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching template.", + Detail: err.Error(), + }) + return + } + + if !api.Authorize(r, rbac.ActionRead, template) { + httpapi.ResourceNotFound(rw) + return + } + + templateVersionName := chi.URLParam(r, "templateversionname") + templateVersion, err := api.Database.GetTemplateVersionByTemplateIDAndName(ctx, database.GetTemplateVersionByTemplateIDAndNameParams{ + TemplateID: uuid.NullUUID{ + UUID: template.ID, + Valid: true, + }, + Name: templateVersionName, }) if errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{ @@ -814,22 +842,49 @@ func (api *API) templateVersionByOrganizationAndName(rw http.ResponseWriter, r * httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user)) } -// @Summary Get previous template version by organization and name -// @ID get-previous-template-version-by-organization-and-name +// @Summary Get previous template version by organization, template, and name +// @ID get-previous-template-version-by-organization-template-and-name // @Security CoderSessionToken // @Produce json // @Tags Templates // @Param organization path string true "Organization ID" format(uuid) +// @Param templatename path string true "Template name" // @Param templateversionname path string true "Template version name" // @Success 200 {object} codersdk.TemplateVersion -// @Router /organizations/{organization}/templateversions/{templateversionname}/previous [get] -func (api *API) previousTemplateVersionByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { +// @Router /organizations/{organization}/templates/{templatename}/versions/{templateversionname}/previous [get] +func (api *API) previousTemplateVersionByOrganizationTemplateAndName(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() organization := httpmw.OrganizationParam(r) - templateVersionName := chi.URLParam(r, "templateversionname") - templateVersion, err := api.Database.GetTemplateVersionByOrganizationAndName(ctx, database.GetTemplateVersionByOrganizationAndNameParams{ + templateName := chi.URLParam(r, "templatename") + template, err := api.Database.GetTemplateByOrganizationAndName(ctx, database.GetTemplateByOrganizationAndNameParams{ OrganizationID: organization.ID, - Name: templateVersionName, + Name: templateName, + }) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + httpapi.ResourceNotFound(rw) + return + } + + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching template.", + Detail: err.Error(), + }) + return + } + + if !api.Authorize(r, rbac.ActionRead, template) { + httpapi.ResourceNotFound(rw) + return + } + + templateVersionName := chi.URLParam(r, "templateversionname") + templateVersion, err := api.Database.GetTemplateVersionByTemplateIDAndName(ctx, database.GetTemplateVersionByTemplateIDAndNameParams{ + TemplateID: uuid.NullUUID{ + UUID: template.ID, + Valid: true, + }, + Name: templateVersionName, }) if err != nil { if xerrors.Is(err, sql.ErrNoRows) { diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index adf35aeb1c21b..f178c613ce9dc 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -992,19 +992,19 @@ func TestPaginatedTemplateVersions(t *testing.T) { } } -func TestTemplateVersionByOrganizationAndName(t *testing.T) { +func TestTemplateVersionByOrganizationTemplateAndName(t *testing.T) { t.Parallel() t.Run("NotFound", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - _, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, "nothing") + _, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, template.Name, "nothing") var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusNotFound, apiErr.StatusCode()) @@ -1015,12 +1015,12 @@ func TestTemplateVersionByOrganizationAndName(t *testing.T) { client := coderdtest.New(t, nil) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - _, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, version.Name) + _, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, template.Name, version.Name) require.NoError(t, err) }) } @@ -1048,7 +1048,7 @@ func TestPreviousTemplateVersion(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - _, err := client.PreviousTemplateVersion(ctx, user.OrganizationID, templateBVersion1.Name) + _, err := client.PreviousTemplateVersion(ctx, user.OrganizationID, templateB.Name, templateBVersion1.Name) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusNotFound, apiErr.StatusCode()) @@ -1075,7 +1075,7 @@ func TestPreviousTemplateVersion(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - result, err := client.PreviousTemplateVersion(ctx, user.OrganizationID, templateBVersion2.Name) + result, err := client.PreviousTemplateVersion(ctx, user.OrganizationID, templateB.Name, templateBVersion2.Name) require.NoError(t, err) require.Equal(t, templateBVersion1.ID, result.ID) }) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index e4a07f6990619..e7d1689240be1 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -153,9 +153,9 @@ func (c *Client) CreateTemplateVersion(ctx context.Context, organizationID uuid. return templateVersion, json.NewDecoder(res.Body).Decode(&templateVersion) } -func (c *Client) TemplateVersionByOrganizationAndName(ctx context.Context, organizationID uuid.UUID, name string) (TemplateVersion, error) { +func (c *Client) TemplateVersionByOrganizationAndName(ctx context.Context, organizationID uuid.UUID, templateName, versionName string) (TemplateVersion, error) { res, err := c.Request(ctx, http.MethodGet, - fmt.Sprintf("/api/v2/organizations/%s/templateversions/%s", organizationID.String(), name), + fmt.Sprintf("/api/v2/organizations/%s/templates/%s/versions/%s", organizationID.String(), templateName, versionName), nil, ) diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index f7b456779c9e8..55feefca30a8d 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -221,8 +221,8 @@ func (c *Client) CancelTemplateVersionDryRun(ctx context.Context, version, job u return nil } -func (c *Client) PreviousTemplateVersion(ctx context.Context, organization uuid.UUID, versionName string) (TemplateVersion, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/templateversions/%s/previous", organization, versionName), nil) +func (c *Client) PreviousTemplateVersion(ctx context.Context, organization uuid.UUID, templateName, versionName string) (TemplateVersion, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/templates/%s/versions/%s/previous", organization, templateName, versionName), nil) if err != nil { return TemplateVersion{}, err } diff --git a/docs/api/templates.md b/docs/api/templates.md index 2d62e30f5cd4d..859618198a4a7 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -375,53 +375,30 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Create template version by organization +## Get template version by organization, template, and name ### Code samples ```shell # Example request using curl -curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templateversions \ - -H 'Content-Type: application/json' \ +curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templates/{templatename}/versions/{templateversionname} \ -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`POST /organizations/{organization}/templateversions` - -> Body parameter - -```json -{ - "parameter_values": [ - { - "copy_from_parameter": "000e07d6-021d-446c-be14-48a9c20bca0b", - "destination_scheme": "none", - "name": "string", - "source_scheme": "none", - "source_value": "string" - } - ], - "rich_parameter_values": [ - { - "name": "string", - "value": "string" - } - ], - "workspace_name": "string" -} -``` +`GET /organizations/{organization}/templates/{templatename}/versions/{templateversionname}` ### Parameters -| Name | In | Type | Required | Description | -| -------------- | ---- | ---------------------------------------------------------------------------------------------------- | -------- | ------------------------------- | -| `organization` | path | string(uuid) | true | Organization ID | -| `body` | body | [codersdk.CreateTemplateVersionDryRunRequest](schemas.md#codersdkcreatetemplateversiondryrunrequest) | true | Create template version request | +| Name | In | Type | Required | Description | +| --------------------- | ---- | ------------ | -------- | --------------------- | +| `organization` | path | string(uuid) | true | Organization ID | +| `templatename` | path | string | true | Template name | +| `templateversionname` | path | string | true | Template version name | ### Example responses -> 201 Response +> 200 Response ```json { @@ -468,30 +445,31 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa ### Responses -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------------ | ----------- | -------------------------------------------------------------- | -| 201 | [Created](https://tools.ietf.org/html/rfc7231#section-6.3.2) | Created | [codersdk.TemplateVersion](schemas.md#codersdktemplateversion) | +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.TemplateVersion](schemas.md#codersdktemplateversion) | To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Get template version by organization and name +## Get previous template version by organization, template, and name ### Code samples ```shell # Example request using curl -curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templateversions/{templateversionname} \ +curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templates/{templatename}/versions/{templateversionname}/previous \ -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`GET /organizations/{organization}/templateversions/{templateversionname}` +`GET /organizations/{organization}/templates/{templatename}/versions/{templateversionname}/previous` ### Parameters | Name | In | Type | Required | Description | | --------------------- | ---- | ------------ | -------- | --------------------- | | `organization` | path | string(uuid) | true | Organization ID | +| `templatename` | path | string | true | Template name | | `templateversionname` | path | string | true | Template version name | ### Example responses @@ -549,29 +527,53 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Get previous template version by organization and name +## Create template version by organization ### Code samples ```shell # Example request using curl -curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templateversions/{templateversionname}/previous \ +curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templateversions \ + -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`GET /organizations/{organization}/templateversions/{templateversionname}/previous` +`POST /organizations/{organization}/templateversions` + +> Body parameter + +```json +{ + "parameter_values": [ + { + "copy_from_parameter": "000e07d6-021d-446c-be14-48a9c20bca0b", + "destination_scheme": "none", + "name": "string", + "source_scheme": "none", + "source_value": "string" + } + ], + "rich_parameter_values": [ + { + "name": "string", + "value": "string" + } + ], + "workspace_name": "string" +} +``` ### Parameters -| Name | In | Type | Required | Description | -| --------------------- | ---- | ------------ | -------- | --------------------- | -| `organization` | path | string(uuid) | true | Organization ID | -| `templateversionname` | path | string | true | Template version name | +| Name | In | Type | Required | Description | +| -------------- | ---- | ---------------------------------------------------------------------------------------------------- | -------- | ------------------------------- | +| `organization` | path | string(uuid) | true | Organization ID | +| `body` | body | [codersdk.CreateTemplateVersionDryRunRequest](schemas.md#codersdkcreatetemplateversiondryrunrequest) | true | Create template version request | ### Example responses -> 200 Response +> 201 Response ```json { @@ -618,9 +620,9 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat ### Responses -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.TemplateVersion](schemas.md#codersdktemplateversion) | +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------------ | ----------- | -------------------------------------------------------------- | +| 201 | [Created](https://tools.ietf.org/html/rfc7231#section-6.3.2) | Created | [codersdk.TemplateVersion](schemas.md#codersdktemplateversion) | To perform this operation, you must be authenticated. [Learn more](authentication.md). diff --git a/site/src/api/api.ts b/site/src/api/api.ts index dd651a54aeb1b..2007b40a360fa 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -231,10 +231,11 @@ export const getTemplateVersions = async ( export const getTemplateVersionByName = async ( organizationId: string, + templateName: string, versionName: string, ): Promise => { const response = await axios.get( - `/api/v2/organizations/${organizationId}/templateversions/${versionName}`, + `/api/v2/organizations/${organizationId}/templates/${templateName}/versions/${versionName}`, ) return response.data } @@ -245,11 +246,12 @@ export type GetPreviousTemplateVersionByNameResponse = export const getPreviousTemplateVersionByName = async ( organizationId: string, + templateName: string, versionName: string, ): Promise => { try { const response = await axios.get( - `/api/v2/organizations/${organizationId}/templateversions/${versionName}/previous`, + `/api/v2/organizations/${organizationId}/templates/${templateName}/versions/${versionName}/previous`, ) return response.data } catch (error) { diff --git a/site/src/pages/TemplateVersionPage/TemplateVersionPage.tsx b/site/src/pages/TemplateVersionPage/TemplateVersionPage.tsx index 0f2b40d37cf93..ed836d58fd79b 100644 --- a/site/src/pages/TemplateVersionPage/TemplateVersionPage.tsx +++ b/site/src/pages/TemplateVersionPage/TemplateVersionPage.tsx @@ -18,7 +18,7 @@ export const TemplateVersionPage: FC = () => { const { version: versionName, template: templateName } = useParams() as Params const orgId = useOrganizationId() const [state] = useMachine(templateVersionMachine, { - context: { versionName, orgId }, + context: { templateName, versionName, orgId }, }) const tab = useTab("file", "0") const { t } = useTranslation("templateVersionPage") diff --git a/site/src/testHelpers/handlers.ts b/site/src/testHelpers/handlers.ts index 9b11058004279..0dd0f2d0fe848 100644 --- a/site/src/testHelpers/handlers.ts +++ b/site/src/testHelpers/handlers.ts @@ -90,13 +90,13 @@ export const handlers = [ }, ), rest.get( - "api/v2/organizations/:organizationId/templateversions/:templateVersionName", + "api/v2/organizations/:organizationId/templates/:templateName/versions/:templateVersionName", async (req, res, ctx) => { return res(ctx.status(200), ctx.json(M.MockTemplateVersion)) }, ), rest.get( - "api/v2/organizations/:organizationId/templateversions/:templateVersionName/previous", + "api/v2/organizations/:organizationId/templates/:templateName/versions/:templateVersionName/previous", async (req, res, ctx) => { return res(ctx.status(200), ctx.json(M.MockTemplateVersion2)) }, diff --git a/site/src/xServices/templateVersion/templateVersionXService.ts b/site/src/xServices/templateVersion/templateVersionXService.ts index 73cd0989bfc09..1c59f792e246d 100644 --- a/site/src/xServices/templateVersion/templateVersionXService.ts +++ b/site/src/xServices/templateVersion/templateVersionXService.ts @@ -12,6 +12,7 @@ import { assign, createMachine } from "xstate" export interface TemplateVersionMachineContext { orgId: string + templateName: string versionName: string currentVersion?: TemplateVersion currentFiles?: TemplateVersionFiles @@ -94,10 +95,10 @@ export const templateVersionMachine = createMachine( }), }, services: { - loadVersions: async ({ orgId, versionName }) => { + loadVersions: async ({ orgId, templateName, versionName }) => { const [currentVersion, previousVersion] = await Promise.all([ - getTemplateVersionByName(orgId, versionName), - getPreviousTemplateVersionByName(orgId, versionName), + getTemplateVersionByName(orgId, templateName, versionName), + getPreviousTemplateVersionByName(orgId, templateName, versionName), ]) return {