Skip to content

Commit 3312c81

Browse files
authored
feat: Workspace filters case insensitive (#2646)
1 parent 90815e5 commit 3312c81

File tree

7 files changed

+90
-37
lines changed

7 files changed

+90
-37
lines changed

coderd/database/databasefake/databasefake.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
289289
if len(params.Status) > 0 {
290290
usersFilteredByStatus := make([]database.User, 0, len(users))
291291
for i, user := range users {
292-
if slice.Contains(params.Status, user.Status) {
292+
if slice.ContainsCompare(params.Status, user.Status, func(a, b database.UserStatus) bool {
293+
return strings.EqualFold(string(a), string(b))
294+
}) {
293295
usersFilteredByStatus = append(usersFilteredByStatus, users[i])
294296
}
295297
}
@@ -299,7 +301,7 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
299301
if len(params.RbacRole) > 0 && !slice.Contains(params.RbacRole, rbac.RoleMember()) {
300302
usersFilteredByRole := make([]database.User, 0, len(users))
301303
for i, user := range users {
302-
if slice.Overlap(params.RbacRole, user.RBACRoles) {
304+
if slice.OverlapCompare(params.RbacRole, user.RBACRoles, strings.EqualFold) {
303305
usersFilteredByRole = append(usersFilteredByRole, users[i])
304306
}
305307
}
@@ -385,25 +387,21 @@ func (q *fakeQuerier) GetWorkspaces(_ context.Context, arg database.GetWorkspace
385387
}
386388
if arg.OwnerUsername != "" {
387389
owner, err := q.GetUserByID(context.Background(), workspace.OwnerID)
388-
if err == nil && arg.OwnerUsername != owner.Username {
390+
if err == nil && !strings.EqualFold(arg.OwnerUsername, owner.Username) {
389391
continue
390392
}
391393
}
392394
if arg.TemplateName != "" {
393-
templates, err := q.GetTemplatesWithFilter(context.Background(), database.GetTemplatesWithFilterParams{
394-
ExactName: arg.TemplateName,
395-
})
396-
// Add to later param
397-
if err == nil {
398-
for _, t := range templates {
399-
arg.TemplateIds = append(arg.TemplateIds, t.ID)
400-
}
395+
template, err := q.GetTemplateByID(context.Background(), workspace.TemplateID)
396+
if err == nil && !strings.EqualFold(arg.TemplateName, template.Name) {
397+
continue
401398
}
402399
}
403400
if !arg.Deleted && workspace.Deleted {
404401
continue
405402
}
406-
if arg.Name != "" && !strings.Contains(workspace.Name, arg.Name) {
403+
404+
if arg.Name != "" && !strings.Contains(strings.ToLower(workspace.Name), strings.ToLower(arg.Name)) {
407405
continue
408406
}
409407
if len(arg.TemplateIds) > 0 {

coderd/database/queries.sql.go

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

coderd/database/queries/workspaces.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ WHERE
2525
-- Filter by owner_name
2626
AND CASE
2727
WHEN @owner_username :: text != '' THEN
28-
owner_id = (SELECT id FROM users WHERE username = @owner_username)
28+
owner_id = (SELECT id FROM users WHERE lower(username) = lower(@owner_username))
2929
ELSE true
3030
END
3131
-- Filter by template_name
3232
-- There can be more than 1 template with the same name across organizations.
3333
-- Use the organization filter to restrict to 1 org if needed.
3434
AND CASE
3535
WHEN @template_name :: text != '' THEN
36-
template_id = ANY(SELECT id FROM templates WHERE name = @template_name)
36+
template_id = ANY(SELECT id FROM templates WHERE lower(name) = lower(@template_name))
3737
ELSE true
3838
END
3939
-- Filter by template_ids
@@ -45,7 +45,7 @@ WHERE
4545
-- Filter by name, matching on substring
4646
AND CASE
4747
WHEN @name :: text != '' THEN
48-
LOWER(name) LIKE '%' || LOWER(@name) || '%'
48+
name ILIKE '%' || @name || '%'
4949
ELSE true
5050
END
5151
;

coderd/util/slice/slice.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
package slice
22

3-
func Contains[T comparable](haystack []T, needle T) bool {
3+
func ContainsCompare[T any](haystack []T, needle T, equal func(a, b T) bool) bool {
44
for _, hay := range haystack {
5-
if needle == hay {
5+
if equal(needle, hay) {
66
return true
77
}
88
}
99
return false
1010
}
1111

12+
func Contains[T comparable](haystack []T, needle T) bool {
13+
return ContainsCompare(haystack, needle, func(a, b T) bool {
14+
return a == b
15+
})
16+
}
17+
1218
// Overlap returns if the 2 sets have any overlap (element(s) in common)
1319
func Overlap[T comparable](a []T, b []T) bool {
20+
return OverlapCompare(a, b, func(a, b T) bool {
21+
return a == b
22+
})
23+
}
24+
25+
func OverlapCompare[T any](a []T, b []T, equal func(a, b T) bool) bool {
1426
// For each element in b, if at least 1 is contained in 'a',
1527
// return true.
1628
for _, element := range b {
17-
if Contains(a, element) {
29+
if ContainsCompare(a, element, equal) {
1830
return true
1931
}
2032
}

coderd/workspaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,7 @@ func workspaceSearchQuery(query string) (database.GetWorkspacesParams, []httpapi
959959
// No filter
960960
return database.GetWorkspacesParams{}, nil
961961
}
962+
query = strings.ToLower(query)
962963
// Because we do this in 2 passes, we want to maintain quotes on the first
963964
// pass.Further splitting occurs on the second pass and quotes will be
964965
// dropped.

coderd/workspaces_internal_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func TestSearchWorkspace(t *testing.T) {
2727
Name: "Owner/Name",
2828
Query: "Foo/Bar",
2929
Expected: database.GetWorkspacesParams{
30-
OwnerUsername: "Foo",
31-
Name: "Bar",
30+
OwnerUsername: "foo",
31+
Name: "bar",
3232
},
3333
},
3434
{
@@ -40,15 +40,15 @@ func TestSearchWorkspace(t *testing.T) {
4040
},
4141
{
4242
Name: "Name+Param",
43-
Query: "workspace-name template:docker",
43+
Query: "workspace-name TEMPLATE:docker",
4444
Expected: database.GetWorkspacesParams{
4545
Name: "workspace-name",
4646
TemplateName: "docker",
4747
},
4848
},
4949
{
5050
Name: "OnlyParams",
51-
Query: "name:workspace-name template:docker owner:alice",
51+
Query: "name:workspace-name template:docker OWNER:Alice",
5252
Expected: database.GetWorkspacesParams{
5353
Name: "workspace-name",
5454
TemplateName: "docker",

coderd/workspaces_test.go

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,13 @@ func TestWorkspaceFilter(t *testing.T) {
358358
user, err := userClient.User(context.Background(), codersdk.Me)
359359
require.NoError(t, err, "fetch me")
360360

361+
if i%3 == 0 {
362+
user, err = client.UpdateUserProfile(context.Background(), user.ID.String(), codersdk.UpdateUserProfileRequest{
363+
Username: strings.ToUpper(user.Username),
364+
})
365+
require.NoError(t, err, "uppercase username")
366+
}
367+
361368
org, err := userClient.CreateOrganization(context.Background(), codersdk.CreateOrganizationRequest{
362369
Name: user.Username + "-org",
363370
})
@@ -378,16 +385,32 @@ func TestWorkspaceFilter(t *testing.T) {
378385

379386
availTemplates := make([]codersdk.Template, 0)
380387
allWorkspaces := make([]madeWorkspace, 0)
388+
upperTemplates := make([]string, 0)
381389

382390
// Create some random workspaces
383-
for _, user := range users {
391+
var count int
392+
for i, user := range users {
384393
version := coderdtest.CreateTemplateVersion(t, client, user.Org.ID, nil)
385394

386395
// Create a template & workspace in the user's org
387396
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
388-
template := coderdtest.CreateTemplate(t, client, user.Org.ID, version.ID)
397+
398+
var template codersdk.Template
399+
if i%3 == 0 {
400+
template = coderdtest.CreateTemplate(t, client, user.Org.ID, version.ID, func(request *codersdk.CreateTemplateRequest) {
401+
request.Name = strings.ToUpper(request.Name)
402+
})
403+
upperTemplates = append(upperTemplates, template.Name)
404+
} else {
405+
template = coderdtest.CreateTemplate(t, client, user.Org.ID, version.ID)
406+
}
407+
389408
availTemplates = append(availTemplates, template)
390-
workspace := coderdtest.CreateWorkspace(t, user.Client, template.OrganizationID, template.ID)
409+
workspace := coderdtest.CreateWorkspace(t, user.Client, template.OrganizationID, template.ID, func(request *codersdk.CreateWorkspaceRequest) {
410+
if count%3 == 0 {
411+
request.Name = strings.ToUpper(request.Name)
412+
}
413+
})
391414
allWorkspaces = append(allWorkspaces, madeWorkspace{
392415
Workspace: workspace,
393416
Template: template,
@@ -428,19 +451,28 @@ func TestWorkspaceFilter(t *testing.T) {
428451
{
429452
Name: "Owner",
430453
Filter: codersdk.WorkspaceFilter{
431-
Owner: users[2].User.Username,
454+
Owner: strings.ToUpper(users[2].User.Username),
432455
},
433456
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
434-
return workspace.Owner.Username == f.Owner
457+
return strings.EqualFold(workspace.Owner.Username, f.Owner)
435458
},
436459
},
437460
{
438461
Name: "TemplateName",
439462
Filter: codersdk.WorkspaceFilter{
440-
Template: allWorkspaces[5].Template.Name,
463+
Template: strings.ToUpper(allWorkspaces[5].Template.Name),
441464
},
442465
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
443-
return workspace.Template.Name == f.Template
466+
return strings.EqualFold(workspace.Template.Name, f.Template)
467+
},
468+
},
469+
{
470+
Name: "UpperTemplateName",
471+
Filter: codersdk.WorkspaceFilter{
472+
Template: upperTemplates[0],
473+
},
474+
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
475+
return strings.EqualFold(workspace.Template.Name, f.Template)
444476
},
445477
},
446478
{
@@ -450,16 +482,21 @@ func TestWorkspaceFilter(t *testing.T) {
450482
Name: "a",
451483
},
452484
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
453-
return strings.Contains(workspace.Workspace.Name, f.Name)
485+
return strings.ContainsAny(workspace.Workspace.Name, "Aa")
454486
},
455487
},
456488
{
457489
Name: "Q-Owner/Name",
458490
Filter: codersdk.WorkspaceFilter{
459-
FilterQuery: allWorkspaces[5].Owner.Username + "/" + allWorkspaces[5].Workspace.Name,
491+
FilterQuery: allWorkspaces[5].Owner.Username + "/" + strings.ToUpper(allWorkspaces[5].Workspace.Name),
460492
},
461-
FilterF: func(_ codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
462-
return workspace.Workspace.ID == allWorkspaces[5].Workspace.ID
493+
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
494+
if strings.EqualFold(workspace.Owner.Username, allWorkspaces[5].Owner.Username) &&
495+
strings.Contains(strings.ToLower(workspace.Workspace.Name), strings.ToLower(allWorkspaces[5].Workspace.Name)) {
496+
return true
497+
}
498+
499+
return false
463500
},
464501
},
465502
{
@@ -470,7 +507,12 @@ func TestWorkspaceFilter(t *testing.T) {
470507
Name: allWorkspaces[3].Workspace.Name,
471508
},
472509
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
473-
return workspace.Workspace.ID == allWorkspaces[3].Workspace.ID
510+
if strings.EqualFold(workspace.Owner.Username, f.Owner) &&
511+
strings.Contains(strings.ToLower(workspace.Workspace.Name), strings.ToLower(f.Name)) &&
512+
strings.EqualFold(workspace.Template.Name, f.Template) {
513+
return true
514+
}
515+
return false
474516
},
475517
},
476518
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy