This commit is contained in:
2026-08-16 22:38:44 +08:00
parent 1945d34894
commit 560ae46b82
19 changed files with 345 additions and 112 deletions
+23
View File
@@ -40,6 +40,7 @@ type SecurityConfig struct {
type SecurityRepo interface {
SecurityConfig(context.Context) (*SecurityConfig, error)
SaveSecurityConfig(context.Context, *SecurityConfig) error
BackfillPasswordUpdatedAt(context.Context, time.Time) error
}
type SecurityUsecase struct {
@@ -63,6 +64,13 @@ func NewSecurityUsecase(repo SecurityRepo, cache Cache, settings RuntimeSettings
}
func (uc *SecurityUsecase) UpdateSecurity(ctx context.Context, value *SecurityConfig) error {
previous, err := uc.repo.SecurityConfig(ctx)
if err != nil {
return err
}
value.ID = previous.ID
value.CreatedAt = previous.CreatedAt
value.UpdatedAt = previous.UpdatedAt
if err := uc.repo.SaveSecurityConfig(ctx, value); err != nil {
return err
}
@@ -70,6 +78,14 @@ func (uc *SecurityUsecase) UpdateSecurity(ctx context.Context, value *SecurityCo
copy := *value
uc.cachedConfig = &copy
uc.mu.Unlock()
// Keep the same observable ordering as the administration backend:
// persist and activate the new configuration first, then backfill legacy
// users when password expiration changes from disabled to enabled. A
// backfill failure is returned to the caller without rolling back the
// already effective configuration.
if value.PwdExpireEnable && !previous.PwdExpireEnable {
return uc.repo.BackfillPasswordUpdatedAt(ctx, time.Now())
}
return nil
}
@@ -83,6 +99,13 @@ func (uc *SecurityUsecase) Current(ctx context.Context) (*SecurityConfig, error)
uc.mu.RUnlock()
value, err := uc.repo.SecurityConfig(ctx)
if err != nil {
// GVA returns its default value together with the database-not-ready
// error. Callers such as login/runtime policy consumers intentionally
// ignore the error and continue with that default, while the HTTP
// settings endpoint still reports the failure.
if value != nil {
return value, err
}
return nil, err
}
uc.mu.Lock()