feat: Add template version page (#5071)

This commit is contained in:
Bruno Quaresma
2022-11-15 13:24:13 -03:00
committed by GitHub
parent 773fc73280
commit f262fb4811
34 changed files with 1750 additions and 824 deletions

View File

@ -340,7 +340,10 @@ func New(options *Options) *API {
httpmw.ExtractOrganizationParam(options.Database),
)
r.Get("/", api.organization)
r.Post("/templateversions", api.postTemplateVersionsByOrganization)
r.Route("/templateversions", func(r chi.Router) {
r.Post("/", api.postTemplateVersionsByOrganization)
r.Get("/{templateversionname}", api.templateVersionByOrganizationAndName)
})
r.Route("/templates", func(r chi.Router) {
r.Post("/", api.postTemplateByOrganization)
r.Get("/", api.templatesByOrganization)

View File

@ -238,10 +238,11 @@ 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},
"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},
// Endpoints that use the SQLQuery filter.
"GET:/api/v2/workspaces/": {StatusCode: http.StatusOK, NoAuthorize: true},

View File

@ -1471,6 +1471,22 @@ func (q *fakeQuerier) GetTemplateVersionByTemplateIDAndName(_ context.Context, a
return database.TemplateVersion{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetTemplateVersionByOrganizationAndName(_ context.Context, arg database.GetTemplateVersionByOrganizationAndNameParams) (database.TemplateVersion, error) {
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()

View File

@ -81,6 +81,7 @@ 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)
GetTemplateVersionsByTemplateID(ctx context.Context, arg GetTemplateVersionsByTemplateIDParams) ([]TemplateVersion, error)
GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error)

View File

@ -3550,6 +3550,38 @@ 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

View File

@ -52,6 +52,15 @@ 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
*

View File

@ -596,6 +596,48 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user))
}
func (api *API) templateVersionByOrganizationAndName(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{
OrganizationID: organization.ID,
Name: templateVersionName,
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
Message: fmt.Sprintf("No template version found by name %q.", templateVersionName),
})
return
}
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return
}
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
}
user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error on fetching user.",
Detail: err.Error(),
})
return
}
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user))
}
func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()

View File

@ -928,3 +928,36 @@ func TestPaginatedTemplateVersions(t *testing.T) {
})
}
}
func TestTemplateVersionByOrganizationAndName(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)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
_, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, "nothing")
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
})
t.Run("Found", 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)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
_, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, version.Name)
require.NoError(t, err)
})
}