package platformsettings import ( "context" "strings" ) // mailPublicFromSMTP maps SMTPPublic into the flat admin UI shape. func mailPublicFromSMTP(smtp SMTPPublic) MailPublic { return MailPublic{ Configured: smtp.Configured || smtp.HasResendAPIKey, SMTPEnabled: smtp.Enabled, SMTPHost: smtp.Host, SMTPPort: smtp.Port, SMTPUser: smtp.User, SMTPFrom: smtp.From, HasSMTPPassword: smtp.HasPassword, SMTPPasswordMasked: smtp.PasswordMasked, HasResendAPIKey: smtp.HasResendAPIKey, ResendAPIKeyMasked: smtp.ResendAPIKeyMasked, EmailDryRun: smtp.EmailDryRun, Source: smtp.Source, } } // mailUpdateToSMTP converts the flat admin UI patch into SMTPUpdate. func mailUpdateToSMTP(in MailUpdate) SMTPUpdate { return SMTPUpdate{ Enabled: in.SMTPEnabled, Host: in.SMTPHost, Port: in.SMTPPort, User: in.SMTPUser, From: in.SMTPFrom, Password: in.SMTPPassword, ClearPassword: in.ClearSMTPPassword, ResendAPIKey: in.ResendAPIKey, ClearResendAPIKey: in.ClearResendAPIKey, EmailDryRun: in.EmailDryRun, } } // ResolveResend returns the platform Resend API key (DB preferred, then env). func (s *Service) ResolveResend(ctx context.Context) (ResolvedResend, error) { doc, _, err := s.loadDoc(ctx) if err != nil { return ResolvedResend{}, err } st := doc.SMTP if strings.TrimSpace(st.ResendAPIKeyEnc) != "" { plain, err := DecryptSecret(s.Key, st.ResendAPIKeyEnc) if err != nil { return ResolvedResend{}, err } return ResolvedResend{APIKey: plain, Source: SourceDB}, nil } // Legacy Values bag (Agent 3/6 may have written mail.resend_api_key). if v, ok := doc.Values[ValueKeyResendAPIKey]; ok && strings.TrimSpace(v) != "" { plain := v if strings.HasPrefix(v, encPrefix) || isSecretValueKey(ValueKeyResendAPIKey) { dec, err := DecryptSecret(s.Key, v) if err != nil { return ResolvedResend{}, err } plain = dec } if strings.TrimSpace(plain) != "" { return ResolvedResend{APIKey: plain, Source: SourceDB}, nil } } if strings.TrimSpace(s.Env.ResendAPIKey) != "" { return ResolvedResend{APIKey: strings.TrimSpace(s.Env.ResendAPIKey), Source: SourceEnv}, nil } return ResolvedResend{Source: SourceNone}, nil } // ResolveEmailDryRun returns whether platform email should force dry-run. // Default is true (safe) when neither settings nor env set the flag. func (s *Service) ResolveEmailDryRun(ctx context.Context) (ResolvedEmailDryRun, error) { doc, _, err := s.loadDoc(ctx) if err != nil { return ResolvedEmailDryRun{}, err } st := doc.SMTP if st.EmailDryRun != nil { return ResolvedEmailDryRun{DryRun: *st.EmailDryRun, Source: SourceDB}, nil } if v, ok := doc.Values[ValueKeyEmailDryRun]; ok && strings.TrimSpace(v) != "" { return ResolvedEmailDryRun{DryRun: parseTruthy(v), Source: SourceDB}, nil } if s.Env.EmailDryRunSet { return ResolvedEmailDryRun{DryRun: s.Env.EmailDryRun, Source: SourceEnv}, nil } // Safe default: dry-run on until admin configures live delivery. return ResolvedEmailDryRun{DryRun: true, Source: SourceNone}, nil }