- Updated the CreateRobot API to auto-generate the member_id if not provided, enhancing usability and ensuring unique identifiers. - Revised CreateRobotRequest structure to make member_id optional, aligning with the new auto-generation logic. - Added a new function for generating unique member IDs with collision detection, ensuring compliance with existing ID patterns. - Enhanced unit tests to validate the new behavior, ensuring robust error handling and proper ID generation. - Updated related OpenAPI documentation to reflect changes in request structure and behavior.
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package robot
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
gonanoid "github.com/matoous/go-nanoid/v2"
|
|
"github.com/yaoapp/gou/model"
|
|
)
|
|
|
|
// GetLocale extracts locale from request
|
|
// Priority: query param > Accept-Language header > default
|
|
func GetLocale(c *gin.Context) string {
|
|
// Check query param first
|
|
if locale := c.Query("locale"); locale != "" {
|
|
return strings.ToLower(strings.TrimSpace(locale))
|
|
}
|
|
|
|
// Check Accept-Language header
|
|
if acceptLang := c.GetHeader("Accept-Language"); acceptLang != "" {
|
|
// Parse first language from header (e.g., "en-US,en;q=0.9" -> "en-us")
|
|
parts := strings.Split(acceptLang, ",")
|
|
if len(parts) > 0 {
|
|
lang := strings.Split(parts[0], ";")[0]
|
|
return strings.ToLower(strings.TrimSpace(lang))
|
|
}
|
|
}
|
|
|
|
// Default locale
|
|
return "en-us"
|
|
}
|
|
|
|
// ParseBoolValue parses various string formats into a boolean pointer
|
|
func ParseBoolValue(value string) *bool {
|
|
value = strings.ToLower(strings.TrimSpace(value))
|
|
switch value {
|
|
case "1", "true", "yes", "on":
|
|
v := true
|
|
return &v
|
|
case "0", "false", "no", "off":
|
|
v := false
|
|
return &v
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ==================== Member ID Generation ====================
|
|
// Follows the same pattern as openapi/oauth/providers/user/utils.go
|
|
|
|
const memberModel = "__yao.member"
|
|
|
|
// GenerateMemberID generates a new unique member_id for robot creation
|
|
// Uses numeric ID (12 characters) with collision detection
|
|
func GenerateMemberID(ctx context.Context) (string, error) {
|
|
const maxRetries = 10
|
|
|
|
for i := 0; i < maxRetries; i++ {
|
|
// Generate 12-digit numeric ID (matches existing pattern)
|
|
id, err := gonanoid.Generate("0123456789", 12)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate member_id: %w", err)
|
|
}
|
|
|
|
// Check if ID already exists
|
|
exists, err := memberIDExists(ctx, id)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to check member_id existence: %w", err)
|
|
}
|
|
|
|
if !exists {
|
|
return id, nil
|
|
}
|
|
// ID exists, retry
|
|
}
|
|
|
|
return "", fmt.Errorf("failed to generate unique member_id after %d retries", maxRetries)
|
|
}
|
|
|
|
// memberIDExists checks if a member_id already exists in the database
|
|
func memberIDExists(ctx context.Context, memberID string) (bool, error) {
|
|
m := model.Select(memberModel)
|
|
if m == nil {
|
|
return false, fmt.Errorf("model %s not found", memberModel)
|
|
}
|
|
|
|
members, err := m.Get(model.QueryParam{
|
|
Select: []interface{}{"id"},
|
|
Wheres: []model.QueryWhere{
|
|
{Column: "member_id", Value: memberID},
|
|
},
|
|
Limit: 1,
|
|
})
|
|
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return len(members) > 0, nil
|
|
}
|