diff --git a/src/common/dao/quota.go b/src/common/dao/quota.go index c86c53797..31449b624 100644 --- a/src/common/dao/quota.go +++ b/src/common/dao/quota.go @@ -220,12 +220,15 @@ func quotaOrderBy(query ...*models.QuotaQuery) string { sort = sort[1:] } - prefix := []string{"hard.", "used."} - for _, p := range prefix { - if strings.HasPrefix(sort, p) { - field := fmt.Sprintf("%s->>'%s'", strings.TrimSuffix(p, "."), strings.TrimPrefix(sort, p)) - orderBy = fmt.Sprintf("(%s) %s", castQuantity(field), order) - break + prefixes := []string{"hard.", "used."} + for _, prefix := range prefixes { + if strings.HasPrefix(sort, prefix) { + resource := strings.TrimPrefix(sort, prefix) + if types.IsValidResource(types.ResourceName(resource)) { + field := fmt.Sprintf("%s->>'%s'", strings.TrimSuffix(prefix, "."), resource) + orderBy = fmt.Sprintf("(%s) %s", castQuantity(field), order) + break + } } } } diff --git a/src/common/dao/quota_test.go b/src/common/dao/quota_test.go index 21daf10b9..c6cba2ac0 100644 --- a/src/common/dao/quota_test.go +++ b/src/common/dao/quota_test.go @@ -141,3 +141,36 @@ func (suite *QuotaDaoSuite) TestListQuotas() { func TestRunQuotaDaoSuite(t *testing.T) { suite.Run(t, new(QuotaDaoSuite)) } + +func Test_quotaOrderBy(t *testing.T) { + query := func(sort string) []*models.QuotaQuery { + return []*models.QuotaQuery{ + {Sorting: models.Sorting{Sort: sort}}, + } + } + + type args struct { + query []*models.QuotaQuery + } + tests := []struct { + name string + args args + want string + }{ + {"no query", args{nil}, "b.creation_time DESC"}, + {"order by unsupport field", args{query("unknow")}, "b.creation_time DESC"}, + {"order by count of hard", args{query("hard.count")}, "(CAST( (CASE WHEN (hard->>'count') IS NULL THEN '0' WHEN (hard->>'count') = '-1' THEN '9223372036854775807' ELSE (hard->>'count') END) AS BIGINT )) ASC"}, + {"order by storage of hard", args{query("hard.storage")}, "(CAST( (CASE WHEN (hard->>'storage') IS NULL THEN '0' WHEN (hard->>'storage') = '-1' THEN '9223372036854775807' ELSE (hard->>'storage') END) AS BIGINT )) ASC"}, + {"order by unsupport hard resource", args{query("hard.unknow")}, "b.creation_time DESC"}, + {"order by count of used", args{query("used.count")}, "(CAST( (CASE WHEN (used->>'count') IS NULL THEN '0' WHEN (used->>'count') = '-1' THEN '9223372036854775807' ELSE (used->>'count') END) AS BIGINT )) ASC"}, + {"order by storage of used", args{query("used.storage")}, "(CAST( (CASE WHEN (used->>'storage') IS NULL THEN '0' WHEN (used->>'storage') = '-1' THEN '9223372036854775807' ELSE (used->>'storage') END) AS BIGINT )) ASC"}, + {"order by unsupport used resource", args{query("used.unknow")}, "b.creation_time DESC"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := quotaOrderBy(tt.args.query...); got != tt.want { + t.Errorf("quotaOrderBy() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/src/common/dao/quota_usage.go b/src/common/dao/quota_usage.go index d8b55db9b..2879ef609 100644 --- a/src/common/dao/quota_usage.go +++ b/src/common/dao/quota_usage.go @@ -21,6 +21,7 @@ import ( "github.com/astaxie/beego/orm" "github.com/goharbor/harbor/src/common/models" + "github.com/goharbor/harbor/src/pkg/types" ) var ( @@ -127,15 +128,19 @@ func quotaUsageOrderBy(query ...*models.QuotaUsageQuery) string { } else { sort := query[0].Sort - order := "asc" + order := "ASC" if sort[0] == '-' { - order = "desc" + order = "DESC" sort = sort[1:] } prefix := "used." if strings.HasPrefix(sort, prefix) { - orderBy = fmt.Sprintf("used->>'%s' %s", strings.TrimPrefix(sort, prefix), order) + resource := strings.TrimPrefix(sort, prefix) + if types.IsValidResource(types.ResourceName(resource)) { + field := fmt.Sprintf("%s->>'%s'", strings.TrimSuffix(prefix, "."), resource) + orderBy = fmt.Sprintf("(%s) %s", castQuantity(field), order) + } } } } diff --git a/src/common/dao/quota_usage_test.go b/src/common/dao/quota_usage_test.go index 40ff14124..81e51aa2d 100644 --- a/src/common/dao/quota_usage_test.go +++ b/src/common/dao/quota_usage_test.go @@ -133,3 +133,33 @@ func (suite *QuotaUsageDaoSuite) TestListQuotaUsages() { func TestRunQuotaUsageDaoSuite(t *testing.T) { suite.Run(t, new(QuotaUsageDaoSuite)) } + +func Test_quotaUsageOrderBy(t *testing.T) { + query := func(sort string) []*models.QuotaUsageQuery { + return []*models.QuotaUsageQuery{ + {Sorting: models.Sorting{Sort: sort}}, + } + } + + type args struct { + query []*models.QuotaUsageQuery + } + tests := []struct { + name string + args args + want string + }{ + {"no query", args{nil}, ""}, + {"order by unsupport field", args{query("unknow")}, ""}, + {"order by count of used", args{query("used.count")}, "(CAST( (CASE WHEN (used->>'count') IS NULL THEN '0' WHEN (used->>'count') = '-1' THEN '9223372036854775807' ELSE (used->>'count') END) AS BIGINT )) ASC"}, + {"order by storage of used", args{query("used.storage")}, "(CAST( (CASE WHEN (used->>'storage') IS NULL THEN '0' WHEN (used->>'storage') = '-1' THEN '9223372036854775807' ELSE (used->>'storage') END) AS BIGINT )) ASC"}, + {"order by unsupport used resource", args{query("used.unknow")}, ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := quotaUsageOrderBy(tt.args.query...); got != tt.want { + t.Errorf("quotaUsageOrderBy() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/src/pkg/types/resources.go b/src/pkg/types/resources.go index 95a98fdff..d6a7f65e0 100644 --- a/src/pkg/types/resources.go +++ b/src/pkg/types/resources.go @@ -135,3 +135,13 @@ func IsNegative(a ResourceList) []ResourceName { } return results } + +// IsValidResource returns true when resource was supported +func IsValidResource(resource ResourceName) bool { + switch resource { + case ResourceCount, ResourceStorage: + return true + default: + return false + } +}