forked from baron/baron-sso
adminfront 조직 통계오류 보정. Kratos Projection용 통계테이블 구조 추가
This commit is contained in:
@@ -100,6 +100,7 @@ type AuthHandler struct {
|
||||
KetoService service.KetoService
|
||||
KetoOutboxRepo repository.KetoOutboxRepository
|
||||
UserRepo repository.UserRepository
|
||||
UserProjectionRepo repository.UserProjectionRepository
|
||||
ConsentRepo repository.ClientConsentRepository
|
||||
RPUserMetadataRepo repository.RPUserMetadataRepository
|
||||
RPUsageSink domain.RPUsageEventSink
|
||||
@@ -856,6 +857,7 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
|
||||
if err := h.UserRepo.Update(ctx, u); err != nil {
|
||||
slog.Error("[Signup] Failed to sync user to Read-Model (Local DB)", "email", u.Email, "error", err)
|
||||
markUserProjectionFailed(ctx, h.UserProjectionRepo, err)
|
||||
} else {
|
||||
slog.Debug("[Signup] Synced user to Read-Model", "email", u.Email)
|
||||
|
||||
@@ -865,6 +867,7 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
}
|
||||
if err := h.UserRepo.UpdateUserLoginIDs(ctx, u.ID, ids); err != nil {
|
||||
slog.Error("[Signup] Failed to update user login IDs", "userID", u.ID, "error", err)
|
||||
markUserProjectionFailed(ctx, h.UserProjectionRepo, err)
|
||||
}
|
||||
|
||||
// [Keto] Sync user-tenant relationship via Outbox
|
||||
@@ -7242,6 +7245,115 @@ func (h *AuthHandler) mapKratosIdentityToProfile(identityID string, traits map[s
|
||||
return profile
|
||||
}
|
||||
|
||||
func (h *AuthHandler) mapKratosTraitsToLocalUser(identityID string, traits map[string]interface{}, existing *domain.User) *domain.User {
|
||||
now := time.Now()
|
||||
localUser := &domain.User{
|
||||
ID: identityID,
|
||||
Status: domain.UserStatusActive,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Metadata: make(domain.JSONMap),
|
||||
}
|
||||
if existing != nil {
|
||||
copied := *existing
|
||||
localUser = &copied
|
||||
localUser.UpdatedAt = now
|
||||
if localUser.Metadata == nil {
|
||||
localUser.Metadata = make(domain.JSONMap)
|
||||
}
|
||||
}
|
||||
|
||||
if email := extractTraitString(traits, "email"); email != "" {
|
||||
localUser.Email = email
|
||||
}
|
||||
if name := extractTraitString(traits, "name"); name != "" {
|
||||
localUser.Name = name
|
||||
}
|
||||
if phone := extractTraitString(traits, "phone_number"); phone != "" {
|
||||
localUser.Phone = phone
|
||||
}
|
||||
if department := extractTraitString(traits, "department"); department != "" {
|
||||
localUser.Department = department
|
||||
}
|
||||
if position := extractTraitString(traits, "position"); position != "" {
|
||||
localUser.Position = position
|
||||
}
|
||||
if jobTitle := extractTraitString(traits, "jobTitle"); jobTitle != "" {
|
||||
localUser.JobTitle = jobTitle
|
||||
}
|
||||
if affType := extractTraitString(traits, "affiliationType"); affType != "" {
|
||||
localUser.AffiliationType = affType
|
||||
}
|
||||
|
||||
companyCode := extractTraitString(traits, "companyCode")
|
||||
if companyCode == "" {
|
||||
companyCode = extractTraitString(traits, "company_code")
|
||||
}
|
||||
if companyCode != "" {
|
||||
localUser.CompanyCode = companyCode
|
||||
}
|
||||
if companyCodes := extractTraitStringArray(traits, "companyCodes"); len(companyCodes) > 0 {
|
||||
localUser.CompanyCodes = pq.StringArray(companyCodes)
|
||||
}
|
||||
if tenantID := extractTraitString(traits, "tenant_id"); tenantID != "" {
|
||||
localUser.TenantID = &tenantID
|
||||
}
|
||||
if relyingPartyID := extractTraitString(traits, "relying_party_id"); relyingPartyID != "" {
|
||||
localUser.RelyingPartyID = &relyingPartyID
|
||||
}
|
||||
|
||||
role := extractTraitString(traits, "grade")
|
||||
if role == "" {
|
||||
role = extractTraitString(traits, "role")
|
||||
}
|
||||
role = domain.NormalizeRole(role)
|
||||
if role == "" {
|
||||
role = domain.RoleUser
|
||||
}
|
||||
localUser.Role = role
|
||||
if localUser.Status == "" {
|
||||
localUser.Status = domain.UserStatusActive
|
||||
}
|
||||
if localUser.CreatedAt.IsZero() {
|
||||
localUser.CreatedAt = now
|
||||
}
|
||||
|
||||
coreTraits := map[string]bool{
|
||||
"email": true, "name": true, "phone_number": true,
|
||||
"grade": true, "companyCode": true, "company_code": true,
|
||||
"companyCodes": true, "department": true,
|
||||
"position": true, "jobTitle": true,
|
||||
"affiliationType": true, "role": true,
|
||||
"tenant_id": true, "relying_party_id": true,
|
||||
"custom_login_ids": true, "id": true,
|
||||
}
|
||||
metadata := make(domain.JSONMap)
|
||||
for k, v := range traits {
|
||||
if !coreTraits[k] {
|
||||
metadata[k] = v
|
||||
}
|
||||
}
|
||||
localUser.Metadata = metadata
|
||||
|
||||
return localUser
|
||||
}
|
||||
|
||||
func (h *AuthHandler) syncUpdatedKratosUserReadModel(ctx context.Context, identityID string, traits map[string]interface{}) error {
|
||||
if h == nil || h.UserRepo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var existing *domain.User
|
||||
if current, err := h.UserRepo.FindByID(ctx, identityID); err == nil {
|
||||
existing = current
|
||||
} else {
|
||||
slog.Warn("[UpdateMe] Failed to load existing local user before read-model sync", "userID", identityID, "error", err)
|
||||
}
|
||||
|
||||
localUser := h.mapKratosTraitsToLocalUser(identityID, traits, existing)
|
||||
return h.UserRepo.Update(ctx, localUser)
|
||||
}
|
||||
|
||||
func (h *AuthHandler) applySessionInfoFromWhoami(profile *domain.UserProfileResponse, authenticatedAt, usedIdentifier string) *domain.UserProfileResponse {
|
||||
if profile == nil {
|
||||
return nil
|
||||
@@ -7374,9 +7486,10 @@ func (h *AuthHandler) UpdateMe(c *fiber.Ctx) error {
|
||||
// [New] Local DB Sync - Sync synchronously to ensure immediate consistency
|
||||
if h.UserRepo != nil {
|
||||
ctx := context.Background()
|
||||
// Also update local User record (read-model)
|
||||
// We can fetch updated identity or just map current traits
|
||||
// Since mapKratosIdentityToProfile is for UI, let's just use UpdateUserLoginIDs first
|
||||
if err := h.syncUpdatedKratosUserReadModel(ctx, identityID, traits); err != nil {
|
||||
slog.Error("[UpdateMe] Failed to sync local user read-model", "userID", identityID, "error", err)
|
||||
markUserProjectionFailed(ctx, h.UserProjectionRepo, err)
|
||||
}
|
||||
if err := h.UserRepo.UpdateUserLoginIDs(ctx, identityID, loginIDRecords); err != nil {
|
||||
slog.Error("[UpdateMe] Failed to update user login IDs", "userID", identityID, "error", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user