using Microsoft.EntityFrameworkCore; using ROLAC.API.Data; using ROLAC.API.DTOs.Settings; using ROLAC.API.Entities; using ROLAC.API.Services.Notifications; namespace ROLAC.API.Services; public class SettingsService : ISettingsService { private readonly AppDbContext _db; private readonly INotificationSettingsService _notificationSettings; public SettingsService(AppDbContext db, INotificationSettingsService notificationSettings) { _db = db; _notificationSettings = notificationSettings; } public async Task GetSiteAsync() { var s = await GetOrCreateSiteAsync(); return new SiteSettingDto { SiteTitle = s.SiteTitle, SiteTitleZh = s.SiteTitleZh, DefaultLanguage = s.DefaultLanguage, TimeZone = s.TimeZone, DateFormat = s.DateFormat, Currency = s.Currency, }; } public async Task UpdateSiteAsync(UpdateSiteSettingRequest r) { var s = await GetOrCreateSiteAsync(); s.SiteTitle = r.SiteTitle; s.SiteTitleZh = r.SiteTitleZh; s.DefaultLanguage = r.DefaultLanguage; s.TimeZone = r.TimeZone; s.DateFormat = r.DateFormat; s.Currency = r.Currency; await _db.SaveChangesAsync(); } public async Task GetNotificationAsync() { var n = await GetOrCreateNotificationAsync(); return new NotificationSettingDto { EnableEmail = n.EnableEmail, SmtpHost = n.SmtpHost, SmtpPort = n.SmtpPort, SmtpUseSsl = n.SmtpUseSsl, SmtpUser = n.SmtpUser, FromAddress = n.FromAddress, FromName = n.FromName, HasSmtpPassword = !string.IsNullOrEmpty(n.SmtpPassword), EnableLine = n.EnableLine, HasLineChannelAccessToken = !string.IsNullOrEmpty(n.LineChannelAccessToken), HasLineChannelSecret = !string.IsNullOrEmpty(n.LineChannelSecret), // WebhookUrl is filled by the controller (needs the request host). }; } public async Task UpdateNotificationAsync(UpdateNotificationSettingRequest r) { var n = await GetOrCreateNotificationAsync(); n.EnableEmail = r.EnableEmail; n.SmtpHost = r.SmtpHost; n.SmtpPort = r.SmtpPort; n.SmtpUseSsl = r.SmtpUseSsl; n.SmtpUser = r.SmtpUser; n.FromAddress = r.FromAddress ?? ""; n.FromName = r.FromName ?? ""; n.EnableLine = r.EnableLine; // Secrets are write-only: a blank value means "keep what's stored". if (!string.IsNullOrWhiteSpace(r.SmtpPassword)) n.SmtpPassword = r.SmtpPassword; if (!string.IsNullOrWhiteSpace(r.LineChannelAccessToken)) n.LineChannelAccessToken = r.LineChannelAccessToken; if (!string.IsNullOrWhiteSpace(r.LineChannelSecret)) n.LineChannelSecret = r.LineChannelSecret; await _db.SaveChangesAsync(); // Drop the cached snapshot so the new values are used on the next send — no restart needed. _notificationSettings.Reload(); } private async Task GetOrCreateSiteAsync() { var s = await _db.SiteSettings.OrderBy(x => x.Id).FirstOrDefaultAsync(); if (s is null) { s = new SiteSetting { SiteTitle = "Church" }; _db.SiteSettings.Add(s); await _db.SaveChangesAsync(); } return s; } private async Task GetOrCreateNotificationAsync() { var n = await _db.NotificationSettings.OrderBy(x => x.Id).FirstOrDefaultAsync(); if (n is null) { n = new NotificationSetting(); _db.NotificationSettings.Add(n); await _db.SaveChangesAsync(); } return n; } }