feat: add author filter command to template filtering (#19202)

Can do `author:username` to filter templates created by a certain
author. Adding to help clean out some templates that I created on our
dev instance. This makes sorting a bit easier.
This commit is contained in:
Steven Masley
2025-08-06 10:41:01 -05:00
committed by GitHub
parent 408e19fd98
commit 5b80c47e8c
6 changed files with 81 additions and 1 deletions
+2
View File
@@ -82,6 +82,8 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
pq.Array(arg.IDs),
arg.Deprecated,
arg.HasAITask,
arg.AuthorID,
arg.AuthorUsername,
)
if err != nil {
return nil, err
+17
View File
@@ -12059,6 +12059,19 @@ WHERE
tv.has_ai_task = $7 :: boolean
ELSE true
END
-- Filter by author_id
AND CASE
WHEN $8 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
t.created_by = $8
ELSE true
END
-- Filter by author_username
AND CASE
WHEN $9 :: text != '' THEN
t.created_by = (SELECT id FROM users WHERE lower(users.username) = lower($9) AND deleted = false)
ELSE true
END
-- Authorize Filter clause will be injected below in GetAuthorizedTemplates
-- @authorize_filter
ORDER BY (t.name, t.id) ASC
@@ -12072,6 +12085,8 @@ type GetTemplatesWithFilterParams struct {
IDs []uuid.UUID `db:"ids" json:"ids"`
Deprecated sql.NullBool `db:"deprecated" json:"deprecated"`
HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
AuthorID uuid.UUID `db:"author_id" json:"author_id"`
AuthorUsername string `db:"author_username" json:"author_username"`
}
func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplatesWithFilterParams) ([]Template, error) {
@@ -12083,6 +12098,8 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
pq.Array(arg.IDs),
arg.Deprecated,
arg.HasAITask,
arg.AuthorID,
arg.AuthorUsername,
)
if err != nil {
return nil, err
+13
View File
@@ -59,6 +59,19 @@ WHERE
tv.has_ai_task = sqlc.narg('has_ai_task') :: boolean
ELSE true
END
-- Filter by author_id
AND CASE
WHEN @author_id :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
t.created_by = @author_id
ELSE true
END
-- Filter by author_username
AND CASE
WHEN @author_username :: text != '' THEN
t.created_by = (SELECT id FROM users WHERE lower(users.username) = lower(@author_username) AND deleted = false)
ELSE true
END
-- Authorize Filter clause will be injected below in GetAuthorizedTemplates
-- @authorize_filter
ORDER BY (t.name, t.id) ASC
+3 -1
View File
@@ -278,12 +278,14 @@ func Templates(ctx context.Context, db database.Store, query string) (database.G
parser := httpapi.NewQueryParamParser()
filter := database.GetTemplatesWithFilterParams{
Deleted: parser.Boolean(values, false, "deleted"),
OrganizationID: parseOrganization(ctx, db, parser, values, "organization"),
ExactName: parser.String(values, "", "exact_name"),
FuzzyName: parser.String(values, "", "name"),
IDs: parser.UUIDs(values, []uuid.UUID{}, "ids"),
Deprecated: parser.NullableBoolean(values, sql.NullBool{}, "deprecated"),
OrganizationID: parseOrganization(ctx, db, parser, values, "organization"),
HasAITask: parser.NullableBoolean(values, sql.NullBool{}, "has-ai-task"),
AuthorID: parser.UUID(values, uuid.Nil, "author_id"),
AuthorUsername: parser.String(values, "", "author"),
}
parser.ErrorExcessParams(values)
+40
View File
@@ -814,6 +814,46 @@ func TestTemplatesByOrganization(t *testing.T) {
require.False(t, templates[0].Deprecated)
require.Empty(t, templates[0].DeprecationMessage)
})
t.Run("ListByAuthor", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
owner := coderdtest.CreateFirstUser(t, client)
adminAlpha, adminAlphaData := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
adminBravo, adminBravoData := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
adminCharlie, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
versionA := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
versionB := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
versionC := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
foo := coderdtest.CreateTemplate(t, adminAlpha, owner.OrganizationID, versionA.ID, func(request *codersdk.CreateTemplateRequest) {
request.Name = "foo"
})
bar := coderdtest.CreateTemplate(t, adminBravo, owner.OrganizationID, versionB.ID, func(request *codersdk.CreateTemplateRequest) {
request.Name = "bar"
})
_ = coderdtest.CreateTemplate(t, adminCharlie, owner.OrganizationID, versionC.ID, func(request *codersdk.CreateTemplateRequest) {
request.Name = "baz"
})
ctx := testutil.Context(t, testutil.WaitLong)
// List alpha
alpha, err := client.Templates(ctx, codersdk.TemplateFilter{
AuthorUsername: adminAlphaData.Username,
})
require.NoError(t, err)
require.Len(t, alpha, 1)
require.Equal(t, foo.ID, alpha[0].ID)
// List bravo
bravo, err := client.Templates(ctx, codersdk.TemplateFilter{
AuthorUsername: adminBravoData.Username,
})
require.NoError(t, err)
require.Len(t, bravo, 1)
require.Equal(t, bar.ID, bravo[0].ID)
})
}
func TestTemplateByOrganizationAndName(t *testing.T) {
+6
View File
@@ -541,6 +541,7 @@ type TemplateFilter struct {
OrganizationID uuid.UUID `typescript:"-"`
ExactName string `typescript:"-"`
FuzzyName string `typescript:"-"`
AuthorUsername string `typescript:"-"`
SearchQuery string `json:"q,omitempty"`
}
@@ -562,6 +563,11 @@ func (f TemplateFilter) asRequestOption() RequestOption {
if f.FuzzyName != "" {
params = append(params, fmt.Sprintf("name:%q", f.FuzzyName))
}
if f.AuthorUsername != "" {
params = append(params, fmt.Sprintf("author:%q", f.AuthorUsername))
}
if f.SearchQuery != "" {
params = append(params, f.SearchQuery)
}