73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
app "haixun-backend/internal/library/errors"
|
|
"haixun-backend/internal/library/errors/code"
|
|
"haixun-backend/internal/model/member/domain/entity"
|
|
domrepo "haixun-backend/internal/model/member/domain/repository"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type AdminOptions struct {
|
|
TenantID string
|
|
Email string
|
|
Password string
|
|
DisplayName string
|
|
}
|
|
|
|
func EnsureAdminMember(ctx context.Context, repo domrepo.Repository, opts AdminOptions) (*entity.Member, bool, error) {
|
|
tenantID := strings.TrimSpace(opts.TenantID)
|
|
email := normalizeEmail(opts.Email)
|
|
if tenantID == "" || email == "" || opts.Password == "" {
|
|
return nil, false, app.For(code.Member).InputMissingRequired("tenant_id, email, and password are required")
|
|
}
|
|
if len(opts.Password) < 8 {
|
|
return nil, false, app.For(code.Member).InputInvalidFormat("password must be at least 8 characters")
|
|
}
|
|
|
|
existing, err := repo.FindByEmail(ctx, tenantID, email)
|
|
if err == nil {
|
|
if err := repo.SetRoles(ctx, tenantID, existing.UID, []string{"admin"}); err != nil {
|
|
return nil, false, err
|
|
}
|
|
existing.Roles = []string{"admin"}
|
|
return existing, false, nil
|
|
}
|
|
if e := app.FromError(err); e == nil || e.Category() != code.ResNotFound {
|
|
return nil, false, err
|
|
}
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(opts.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, false, app.For(code.Member).SysInternal("hash password failed").WithCause(err)
|
|
}
|
|
displayName := strings.TrimSpace(opts.DisplayName)
|
|
if displayName == "" {
|
|
displayName = "Admin"
|
|
}
|
|
member, err := repo.Create(ctx, &entity.Member{
|
|
TenantID: tenantID,
|
|
UID: uuid.NewString(),
|
|
Email: email,
|
|
DisplayName: displayName,
|
|
Language: "zh-TW",
|
|
Status: entity.StatusOpen,
|
|
Origin: entity.OriginNative,
|
|
PasswordHash: string(hash),
|
|
Roles: []string{"admin"},
|
|
})
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
return member, true, nil
|
|
}
|
|
|
|
func normalizeEmail(email string) string {
|
|
return strings.ToLower(strings.TrimSpace(email))
|
|
}
|