Files
ai_site/platform/internal/userstore/tenant_slug.go
2026-07-31 10:31:17 +08:00

78 lines
2.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 须为 232 位,小写字母开头,仅含 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 ""
}