Enhance user type management with locale support
- Added 'locale' field to user type structure for language localization. - Updated API methods to include locale in pricing and published types retrieval. - Enhanced tests to validate locale handling in user type operations, ensuring robust support for multiple languages.
This commit is contained in:
parent
15f0750253
commit
87465379be
6 changed files with 264 additions and 147 deletions
282
data/bindata.go
282
data/bindata.go
File diff suppressed because one or more lines are too long
|
|
@ -116,7 +116,7 @@ var (
|
|||
|
||||
// DefaultTypeFields contains basic type fields
|
||||
DefaultTypeFields = []interface{}{
|
||||
"id", "type_id", "name", "description", "is_active", "is_default", "sort_order", "status",
|
||||
"id", "type_id", "name", "description", "is_active", "is_default", "sort_order", "status", "locale",
|
||||
"default_role_id", "max_sessions", "session_timeout", "price_daily", "price_monthly",
|
||||
"price_yearly", "credits_monthly", "created_at", "updated_at",
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ var (
|
|||
// DefaultTypeDetailFields contains all type fields including configuration and metadata
|
||||
DefaultTypeDetailFields = []interface{}{
|
||||
"id", "type_id", "name", "description", "default_role_id", "schema", "metadata",
|
||||
"is_active", "is_default", "sort_order", "status", "max_sessions", "session_timeout",
|
||||
"is_active", "is_default", "sort_order", "status", "locale", "max_sessions", "session_timeout",
|
||||
"password_policy", "features", "limits", "price_daily", "price_monthly", "price_yearly",
|
||||
"credits_monthly", "introduction", "sale_type", "sale_link", "sale_price_label",
|
||||
"sale_description", "created_at", "updated_at",
|
||||
|
|
|
|||
|
|
@ -294,11 +294,12 @@ func (u *DefaultUser) SetTypeConfiguration(ctx context.Context, typeID string, c
|
|||
// GetTypePricing retrieves pricing information for a type
|
||||
func (u *DefaultUser) GetTypePricing(ctx context.Context, typeID string) (maps.MapStrAny, error) {
|
||||
m := model.Select(u.typeModel)
|
||||
|
||||
types, err := m.Get(model.QueryParam{
|
||||
Select: []interface{}{
|
||||
"type_id", "name", "price_daily", "price_monthly", "price_yearly",
|
||||
"credits_monthly", "introduction", "sale_type", "sale_link",
|
||||
"sale_price_label", "sale_description", "status",
|
||||
"sale_price_label", "sale_description", "status", "locale",
|
||||
},
|
||||
Wheres: []model.QueryWhere{
|
||||
{Column: "type_id", Value: typeID},
|
||||
|
|
@ -317,8 +318,8 @@ func (u *DefaultUser) GetTypePricing(ctx context.Context, typeID string) (maps.M
|
|||
return types[0], nil
|
||||
}
|
||||
|
||||
// GetPublishedTypes retrieves all published types with pricing information
|
||||
func (u *DefaultUser) GetPublishedTypes(ctx context.Context, param model.QueryParam) ([]maps.MapStr, error) {
|
||||
// GetPublishedTypes retrieves all published types with pricing information, optionally filtered by locale
|
||||
func (u *DefaultUser) GetPublishedTypes(ctx context.Context, param model.QueryParam, locale ...string) ([]maps.MapStr, error) {
|
||||
// Add published status filter
|
||||
param.Wheres = append(param.Wheres, model.QueryWhere{
|
||||
Column: "status",
|
||||
|
|
@ -331,12 +332,20 @@ func (u *DefaultUser) GetPublishedTypes(ctx context.Context, param model.QueryPa
|
|||
Value: true,
|
||||
})
|
||||
|
||||
// Add locale filter if provided
|
||||
if len(locale) > 0 && locale[0] != "" {
|
||||
param.Wheres = append(param.Wheres, model.QueryWhere{
|
||||
Column: "locale",
|
||||
Value: locale[0],
|
||||
})
|
||||
}
|
||||
|
||||
// Set default select fields if not provided
|
||||
if param.Select == nil {
|
||||
param.Select = []interface{}{
|
||||
"type_id", "name", "description", "price_daily", "price_monthly", "price_yearly",
|
||||
"credits_monthly", "introduction", "sale_type", "sale_link",
|
||||
"sale_price_label", "sale_description", "sort_order", "status", "is_active", "features", "limits",
|
||||
"sale_price_label", "sale_description", "sort_order", "status", "locale", "is_active", "features", "limits",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type TestTypeData struct {
|
|||
IsDefault bool `json:"is_default"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Status string `json:"status"`
|
||||
Locale string `json:"locale"`
|
||||
DefaultRoleID string `json:"default_role_id"`
|
||||
MaxSessions *int `json:"max_sessions"`
|
||||
SessionTimeout int `json:"session_timeout"`
|
||||
|
|
@ -832,6 +833,7 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
testTypes := []struct {
|
||||
TypeID string
|
||||
Name string
|
||||
Locale string
|
||||
PriceDaily int
|
||||
PriceMonthly int
|
||||
PriceYearly int
|
||||
|
|
@ -846,6 +848,7 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
{
|
||||
TypeID: "free_" + testUUID,
|
||||
Name: "Free Plan",
|
||||
Locale: "en-us",
|
||||
PriceDaily: 0,
|
||||
PriceMonthly: 0,
|
||||
PriceYearly: 0,
|
||||
|
|
@ -858,6 +861,7 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
{
|
||||
TypeID: "pro_" + testUUID,
|
||||
Name: "Pro Plan",
|
||||
Locale: "en-us",
|
||||
PriceDaily: 100,
|
||||
PriceMonthly: 2900,
|
||||
PriceYearly: 29900,
|
||||
|
|
@ -870,6 +874,7 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
{
|
||||
TypeID: "enterprise_" + testUUID,
|
||||
Name: "Enterprise Plan",
|
||||
Locale: "en-us",
|
||||
PriceDaily: 0,
|
||||
PriceMonthly: 0,
|
||||
PriceYearly: 0,
|
||||
|
|
@ -884,6 +889,7 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
{
|
||||
TypeID: "beta_" + testUUID,
|
||||
Name: "Beta Plan",
|
||||
Locale: "en-us",
|
||||
PriceDaily: 50,
|
||||
PriceMonthly: 1500,
|
||||
PriceYearly: 15000,
|
||||
|
|
@ -899,6 +905,7 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
typeData := maps.MapStrAny{
|
||||
"type_id": testType.TypeID,
|
||||
"name": testType.Name,
|
||||
"locale": testType.Locale,
|
||||
"price_daily": testType.PriceDaily,
|
||||
"price_monthly": testType.PriceMonthly,
|
||||
"price_yearly": testType.PriceYearly,
|
||||
|
|
@ -1123,4 +1130,90 @@ func TestTypePricingOperations(t *testing.T) {
|
|||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "type not found")
|
||||
})
|
||||
|
||||
// Test locale support
|
||||
t.Run("GetTypePricing_WithLocale", func(t *testing.T) {
|
||||
// Create a zh-cn version of pro plan with unique type_id
|
||||
zhCNTypeData := maps.MapStrAny{
|
||||
"type_id": "pro_zh_" + testUUID,
|
||||
"name": "专业版",
|
||||
"locale": "zh-cn",
|
||||
"price_daily": 7,
|
||||
"price_monthly": 199,
|
||||
"price_yearly": 1990,
|
||||
"credits_monthly": 10000,
|
||||
"introduction": "适合专业用户和团队协作",
|
||||
"sale_type": "online",
|
||||
"status": "published",
|
||||
"is_active": true,
|
||||
}
|
||||
_, err := testProvider.CreateType(ctx, zhCNTypeData)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get pricing for English version
|
||||
pricingEN, err := testProvider.GetTypePricing(ctx, "pro_"+testUUID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Pro Plan", pricingEN["name"])
|
||||
assert.Equal(t, "en-us", pricingEN["locale"])
|
||||
|
||||
// Get pricing for Chinese version
|
||||
pricingCN, err := testProvider.GetTypePricing(ctx, "pro_zh_"+testUUID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "专业版", pricingCN["name"])
|
||||
assert.Equal(t, "zh-cn", pricingCN["locale"])
|
||||
|
||||
// Verify different prices (Note: EN price was updated to 3900 in SetTypePricing test)
|
||||
priceMonthlyEN := pricingEN["price_monthly"]
|
||||
switch v := priceMonthlyEN.(type) {
|
||||
case int:
|
||||
assert.Equal(t, 3900, v) // Updated price from SetTypePricing test
|
||||
case int32:
|
||||
assert.Equal(t, int32(3900), v)
|
||||
case int64:
|
||||
assert.Equal(t, int64(3900), v)
|
||||
}
|
||||
|
||||
priceMonthlyCN := pricingCN["price_monthly"]
|
||||
switch v := priceMonthlyCN.(type) {
|
||||
case int:
|
||||
assert.Equal(t, 199, v)
|
||||
case int32:
|
||||
assert.Equal(t, int32(199), v)
|
||||
case int64:
|
||||
assert.Equal(t, int64(199), v)
|
||||
}
|
||||
})
|
||||
|
||||
// Test GetPublishedTypes with locale filter
|
||||
t.Run("GetPublishedTypes_WithLocale", func(t *testing.T) {
|
||||
param := model.QueryParam{}
|
||||
|
||||
// Get English versions
|
||||
typesEN, err := testProvider.GetPublishedTypes(ctx, param, "en-us")
|
||||
assert.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, len(typesEN), 3) // At least free, pro, enterprise
|
||||
|
||||
enCount := 0
|
||||
for _, typeRecord := range typesEN {
|
||||
if strings.Contains(typeRecord["type_id"].(string), testUUID) {
|
||||
assert.Equal(t, "en-us", typeRecord["locale"])
|
||||
enCount++
|
||||
}
|
||||
}
|
||||
assert.GreaterOrEqual(t, enCount, 3) // free, pro, enterprise
|
||||
|
||||
// Get Chinese version
|
||||
typesCN, err := testProvider.GetPublishedTypes(ctx, param, "zh-cn")
|
||||
assert.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, len(typesCN), 1) // At least pro_zh
|
||||
|
||||
cnCount := 0
|
||||
for _, typeRecord := range typesCN {
|
||||
if strings.Contains(typeRecord["type_id"].(string), testUUID) {
|
||||
assert.Equal(t, "zh-cn", typeRecord["locale"])
|
||||
cnCount++
|
||||
}
|
||||
}
|
||||
assert.GreaterOrEqual(t, cnCount, 1) // pro_zh
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,6 +247,12 @@ type UserProvider interface {
|
|||
GetTypeConfiguration(ctx context.Context, typeID string) (maps.MapStrAny, error)
|
||||
SetTypeConfiguration(ctx context.Context, typeID string, config maps.MapStrAny) error
|
||||
|
||||
// Type Pricing and Status Management
|
||||
GetTypePricing(ctx context.Context, typeID string) (maps.MapStrAny, error)
|
||||
SetTypePricing(ctx context.Context, typeID string, pricing maps.MapStrAny) error
|
||||
GetPublishedTypes(ctx context.Context, param model.QueryParam, locale ...string) ([]maps.MapStr, error)
|
||||
UpdateTypeStatus(ctx context.Context, typeID string, status string) error
|
||||
|
||||
// ============================================================================
|
||||
// Team Resource
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -107,6 +107,15 @@
|
|||
"default": "draft",
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "locale",
|
||||
"type": "string",
|
||||
"label": "Locale",
|
||||
"comment": "Language locale (e.g., en-us, zh-cn)",
|
||||
"length": 10,
|
||||
"default": "en-us",
|
||||
"index": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Pricing & Subscription Fields
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue