using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using ROLAC.API.Authorization; using ROLAC.API.DTOs.Settings; using ROLAC.API.Services; using ROLAC.API.Services.Logging; using ROLAC.API.Services.Notifications; namespace ROLAC.API.Controllers; /// /// Site-wide and notification (SMTP/Line) settings, surfaced by the Church Profile → Site / /// Notification tabs. Gated by the Settings permission module (super_admin bypasses). /// [ApiController] [Route("api/settings")] [Authorize] public class SettingsController : ControllerBase { private readonly ISettingsService _settings; private readonly IEmailService _email; private readonly ILineNotificationService _line; private readonly CurrentUserAccessor _currentUser; public SettingsController( ISettingsService settings, IEmailService email, ILineNotificationService line, CurrentUserAccessor currentUser) { _settings = settings; _email = email; _line = line; _currentUser = currentUser; } // ── Site settings ──────────────────────────────────────────────────────── [HttpGet("site")] [HasPermission(Modules.Settings, PermissionActions.Read)] public async Task GetSite() => Ok(await _settings.GetSiteAsync()); [HttpPut("site")] [HasPermission(Modules.Settings, PermissionActions.Write)] public async Task UpdateSite([FromBody] UpdateSiteSettingRequest request) { await _settings.UpdateSiteAsync(request); return NoContent(); } // ── Notification settings ────────────────────────────────────────────────── [HttpGet("notification")] [HasPermission(Modules.Settings, PermissionActions.Read)] public async Task GetNotification() { var dto = await _settings.GetNotificationAsync(); dto.WebhookUrl = $"{Request.Scheme}://{Request.Host}/api/line/webhook"; return Ok(dto); } [HttpPut("notification")] [HasPermission(Modules.Settings, PermissionActions.Write)] public async Task UpdateNotification([FromBody] UpdateNotificationSettingRequest request) { await _settings.UpdateNotificationAsync(request); return NoContent(); } [HttpPost("notification/test-email")] [HasPermission(Modules.Settings, PermissionActions.Write)] public async Task TestEmail([FromBody] TestEmailRequest request, CancellationToken ct) { var to = string.IsNullOrWhiteSpace(request.ToAddress) ? _currentUser.Email : request.ToAddress; if (string.IsNullOrWhiteSpace(to)) return BadRequest(new { message = "No recipient — provide an address or set an email on your account." }); var result = await _email.SendAsync(new EmailMessage( MemberIds: Array.Empty(), Addresses: new[] { to }, Subject: "ROLAC test email / 測試郵件", HtmlBody: "

This is a test email from ROLAC notification settings.

" + "

這是來自 ROLAC 通知設定的測試郵件。

", SentByUserId: _currentUser.UserIdOrSystem), ct); return Ok(result); } [HttpPost("notification/test-line")] [HasPermission(Modules.Settings, PermissionActions.Write)] public async Task TestLine([FromBody] TestLineRequest request, CancellationToken ct) { if (request.MemberId is null && request.GroupId is null) return BadRequest(new { message = "Choose a bound member or group to receive the test." }); var result = await _line.SendLineAsync( body: "ROLAC 測試訊息 / This is a test Line message from ROLAC.", memberIds: request.MemberId is { } m ? new[] { m } : Array.Empty(), groupIds: request.GroupId is { } g ? new[] { g } : Array.Empty(), sentByUserId: _currentUser.UserIdOrSystem, ct); return Ok(result); } }