1
0
forked from baron/baron-sso

slug 명칭 한글 수정

This commit is contained in:
2026-02-25 14:17:45 +09:00
parent bc07619452
commit 600961f33d
10 changed files with 406 additions and 15 deletions

View File

@@ -1,6 +1,7 @@
package utils
import (
"fmt"
"regexp"
"strings"
)
@@ -75,3 +76,46 @@ func ValidateSlug(slug string) (bool, string) {
return true, ""
}
// GenerateSlug generates a base slug from a given string.
// It removes special characters, replaces spaces with hyphens, and converts to lowercase.
func GenerateSlug(name string) string {
// Convert to lowercase
s := strings.ToLower(strings.TrimSpace(name))
// Replace non-alphanumeric characters (including spaces) with a hyphen
re := regexp.MustCompile(`[^a-z0-9]+`)
s = re.ReplaceAllString(s, "-")
// Remove leading and trailing hyphens
s = strings.Trim(s, "-")
// Handle empty slug
if s == "" {
s = "tenant"
}
// Truncate to maximum length of 32 (reserving space for suffixes)
if len(s) > 25 {
s = s[:25]
s = strings.TrimSuffix(s, "-")
}
return s
}
// GenerateUniqueSlug generates a unique slug by appending a suffix if the base slug exists.
// It takes the base name and a checker function that returns true if the slug already exists.
func GenerateUniqueSlug(name string, exists func(string) bool) string {
baseSlug := GenerateSlug(name)
slug := baseSlug
counter := 1
for reservedSlugs[slug] || exists(slug) {
slug = fmt.Sprintf("%s-%d", baseSlug, counter)
counter++
}
return slug
}

View File

@@ -54,3 +54,62 @@ func TestValidateSlug_Format(t *testing.T) {
})
}
}
func TestGenerateSlug(t *testing.T) {
tests := []struct {
name string
expected string
}{
{"Hello World", "hello-world"},
{"My Company!@#", "my-company"},
{"---Test---", "test"},
{" Spaces ", "spaces"},
{"A VERY LONG NAME THAT EXCEEDS THIRTY TWO CHARACTERS", "a-very-long-name-that-exc"},
{"한글 테스트", "tenant"}, // Non-ascii characters will be replaced by hyphens and trimmed to empty, then fallback to "tenant"
{"Test 한글 Mix", "test-mix"},
{"", "tenant"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
slug := GenerateSlug(tt.name)
assert.Equal(t, tt.expected, slug)
// Ensure generated slug is valid (unless it's reserved like "slug" wasn't reserved, but let's check format)
if !reservedSlugs[slug] {
valid, _ := ValidateSlug(slug)
assert.True(t, valid, "Generated slug should be valid format")
}
})
}
}
func TestGenerateUniqueSlug(t *testing.T) {
existingSlugs := map[string]bool{
"my-company": true,
"my-company-1": true,
"test": true,
}
existsFunc := func(slug string) bool {
return existingSlugs[slug]
}
tests := []struct {
name string
expected string
}{
{"My Company", "my-company-2"},
{"Test", "test-1"},
{"New Company", "new-company"},
{"admin", "admin-1"}, // "admin" is reserved, so it should append suffix
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
slug := GenerateUniqueSlug(tt.name, existsFunc)
assert.Equal(t, tt.expected, slug)
valid, _ := ValidateSlug(slug)
assert.True(t, valid, "Generated unique slug should be valid")
})
}
}