Skip to content

Commit 1a14a8c

Browse files
committed
feat: add support for template in workspace filter
1 parent 42c6b08 commit 1a14a8c

File tree

7 files changed

+134
-29
lines changed

7 files changed

+134
-29
lines changed

coderd/database/databasefake/databasefake.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,26 @@ func (q *fakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd
761761
return sql.ErrNoRows
762762
}
763763

764+
func (q *fakeQuerier) GetTemplatesByName(_ context.Context, arg database.GetTemplatesByNameParams) ([]database.Template, error) {
765+
q.mutex.RLock()
766+
defer q.mutex.RUnlock()
767+
var templates []database.Template
768+
for _, template := range q.templates {
769+
if !strings.EqualFold(template.Name, arg.Name) {
770+
continue
771+
}
772+
if template.Deleted != arg.Deleted {
773+
continue
774+
}
775+
templates = append(templates, template)
776+
}
777+
if len(templates) > 0 {
778+
return templates, nil
779+
}
780+
781+
return nil, sql.ErrNoRows
782+
}
783+
764784
func (q *fakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg database.GetTemplateVersionsByTemplateIDParams) (version []database.TemplateVersion, err error) {
765785
q.mutex.RLock()
766786
defer q.mutex.RUnlock()

coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 60 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/templates.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ WHERE
2828
LIMIT
2929
1;
3030

31+
-- name: GetTemplatesByName :many
32+
SELECT
33+
*
34+
FROM
35+
templates
36+
WHERE
37+
deleted = @deleted
38+
AND LOWER("name") = LOWER(@name);
39+
3140
-- name: GetTemplatesByOrganization :many
3241
SELECT
3342
*

coderd/database/queries/workspaces.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ WHERE
2828
owner_id = @owner_id
2929
ELSE true
3030
END
31+
-- Filter by template_id
32+
AND CASE
33+
WHEN @template_id :: uuid != '00000000-00000000-00000000-00000000' THEN
34+
template_id = @template_id
35+
ELSE true
36+
END
3137
-- Filter by name, matching on substring
3238
AND CASE
3339
WHEN @name :: text != '' THEN

coderd/workspaces.go

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -103,48 +103,56 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
103103
// Optional filters with query params
104104
func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
105105
apiKey := httpmw.APIKey(r)
106+
filter := database.GetWorkspacesWithFilterParams{Deleted: false}
106107

107-
// Empty strings mean no filter
108108
orgFilter := r.URL.Query().Get("organization_id")
109-
ownerFilter := r.URL.Query().Get("owner")
110-
nameFilter := r.URL.Query().Get("name")
111-
112-
filter := database.GetWorkspacesWithFilterParams{Deleted: false}
113109
if orgFilter != "" {
114110
orgID, err := uuid.Parse(orgFilter)
115111
if err == nil {
116112
filter.OrganizationID = orgID
117113
}
118114
}
115+
116+
ownerFilter := r.URL.Query().Get("owner")
119117
if ownerFilter == "me" {
120118
filter.OwnerID = apiKey.UserID
121119
} else if ownerFilter != "" {
122-
userID, err := uuid.Parse(ownerFilter)
123-
if err != nil {
124-
// Maybe it's a username
125-
user, err := api.Database.GetUserByEmailOrUsername(r.Context(), database.GetUserByEmailOrUsernameParams{
126-
// Why not just accept 1 arg and use it for both in the sql?
127-
Username: ownerFilter,
128-
Email: ownerFilter,
129-
})
130-
if err == nil {
131-
filter.OwnerID = user.ID
132-
}
133-
} else {
134-
filter.OwnerID = userID
120+
user, err := api.Database.GetUserByEmailOrUsername(r.Context(), database.GetUserByEmailOrUsernameParams{
121+
Username: ownerFilter,
122+
})
123+
if err == nil {
124+
filter.OwnerID = user.ID
135125
}
136126
}
127+
128+
templateFilter := r.URL.Query().Get("template")
129+
var templates []database.Template
130+
if templateFilter != "" {
131+
ts, err := api.Database.GetTemplatesByName(r.Context(), database.GetTemplatesByNameParams{
132+
Name: templateFilter,
133+
})
134+
if err == nil {
135+
templates = ts
136+
}
137+
}
138+
139+
nameFilter := r.URL.Query().Get("name")
137140
if nameFilter != "" {
138141
filter.Name = nameFilter
139142
}
140143

141-
workspaces, err := api.Database.GetWorkspacesWithFilter(r.Context(), filter)
142-
if err != nil {
143-
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
144-
Message: "Internal error fetching workspaces.",
145-
Detail: err.Error(),
146-
})
147-
return
144+
var workspaces []database.Workspace
145+
for _, template := range templates {
146+
filter.TemplateID = template.ID
147+
ws, err := api.Database.GetWorkspacesWithFilter(r.Context(), filter)
148+
if err != nil {
149+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
150+
Message: "Internal error fetching workspaces.",
151+
Detail: err.Error(),
152+
})
153+
return
154+
}
155+
workspaces = append(workspaces, ws...)
148156
}
149157

150158
// Only return workspaces the user can read

codersdk/workspaces.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,12 @@ func (c *Client) PutExtendWorkspace(ctx context.Context, id uuid.UUID, req PutEx
218218

219219
type WorkspaceFilter struct {
220220
OrganizationID uuid.UUID `json:"organization_id,omitempty"`
221-
// Owner can be a user_id (uuid), "me", or a username
221+
// Owner can be "me" or a username
222222
Owner string `json:"owner,omitempty"`
223-
Name string `json:"name,omitempty"`
223+
// Template is a template name
224+
Template string `json:"template,omitempty"`
225+
// Name will return partial matches
226+
Name string `json:"name,omitempty"`
224227
}
225228

226229
// asRequestOption returns a function that can be used in (*Client).Request.

0 commit comments

Comments
 (0)