mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user