chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
77
platform/internal/userstore/tenant_slug.go
Normal file
77
platform/internal/userstore/tenant_slug.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package userstore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var tenantSlugRe = regexp.MustCompile(`^[a-z][a-z0-9-]{1,31}$`)
|
||||
|
||||
// 路径段保留字:不可用作公司 slug(与后续 /{slug}/ 路由冲突)
|
||||
var reservedTenantSlugs = map[string]struct{}{
|
||||
"api": {}, "ai": {}, "gateway": {}, "platform": {}, "_platform": {},
|
||||
"admin": {}, "assets": {}, "static": {}, "www": {}, "m": {}, "public": {},
|
||||
"health": {}, "ops": {}, "console": {}, "login": {}, "register": {},
|
||||
"favicon.ico": {}, "robots.txt": {},
|
||||
}
|
||||
|
||||
// NormalizeTenantSlug 规范化公司路径 slug(全局唯一,用于 www.yuxinda.com/{slug}/)。
|
||||
func NormalizeTenantSlug(raw string) (string, error) {
|
||||
s := strings.TrimSpace(strings.ToLower(raw))
|
||||
s = strings.ReplaceAll(s, "_", "-")
|
||||
s = strings.ReplaceAll(s, " ", "-")
|
||||
var b strings.Builder
|
||||
prevDash := false
|
||||
for _, r := range s {
|
||||
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') {
|
||||
b.WriteRune(r)
|
||||
prevDash = false
|
||||
continue
|
||||
}
|
||||
if r == '-' {
|
||||
if b.Len() == 0 || prevDash {
|
||||
continue
|
||||
}
|
||||
b.WriteByte('-')
|
||||
prevDash = true
|
||||
continue
|
||||
}
|
||||
// 跳过其它字符(含中文);中文名需用户另填 slug
|
||||
}
|
||||
s = strings.Trim(b.String(), "-")
|
||||
if s == "" {
|
||||
return "", fmt.Errorf("公司路径 slug 不能为空(请用英文/数字,如 aaa)")
|
||||
}
|
||||
if !tenantSlugRe.MatchString(s) {
|
||||
return "", fmt.Errorf("slug 须为 2–32 位,小写字母开头,仅含 a-z / 0-9 / -")
|
||||
}
|
||||
if _, bad := reservedTenantSlugs[s]; bad {
|
||||
return "", fmt.Errorf("slug %q 为系统保留字", s)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// SuggestTenantSlug 从公司名生成候选(中文名可能得不到可用 slug,需人工填写)。
|
||||
func SuggestTenantSlug(name string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
// 纯 ASCII 名:直接规范化
|
||||
ascii := true
|
||||
for _, r := range name {
|
||||
if r > unicode.MaxASCII {
|
||||
ascii = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ascii {
|
||||
s, err := NormalizeTenantSlug(name)
|
||||
if err == nil {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user