using HrynCo.NotificationService.DAL.Abstract.Providers; using HrynCo.NotificationService.Services.EmailChannels.Create; using HrynCo.NotificationService.Services.EmailChannels.Delete; using HrynCo.NotificationService.Services.EmailChannels.Get; using HrynCo.NotificationService.Services.EmailChannels.GetAll; using HrynCo.NotificationService.Services.EmailChannels.Update; using HrynCo.NotificationService.Web.Controllers.Admin.ViewModels; using MailKit.Net.Smtp; using MailKit.Security; using MediatR; using Microsoft.AspNetCore.Mvc; using MimeKit; namespace HrynCo.NotificationService.Web.Controllers.Admin; [Route("admin/channels")] public class AdminChannelsController : Controller { private readonly IMediator _mediator; public AdminChannelsController(IMediator mediator) { _mediator = mediator; } // GET /admin/channels [HttpGet("")] public async Task Index(CancellationToken ct) { var result = await _mediator.Send(new GetAllEmailChannelsQuery(), ct); if (!result.IsSuccess) { ModelState.AddModelError("", result.Error?.Message ?? "Failed to load channels."); return View(Array.Empty()); } return View(result.Result); } // GET /admin/channels/create [HttpGet("create")] public IActionResult Create() { return View("Edit", new EmailChannelEditViewModel()); } // GET /admin/channels/{id} [HttpGet("{id:guid}")] public async Task Edit(Guid id, CancellationToken ct) { var result = await _mediator.Send(new GetEmailChannelQuery(id), ct); if (!result.IsSuccess || result.Result is null) return NotFound(); var channel = result.Result; var smtp = channel.Settings as SmtpChannelSettings ?? new SmtpChannelSettings { Host = "", Username = "", Password = "", FromEmail = "", FromName = "" }; var vm = new EmailChannelEditViewModel { Id = channel.Id, ServiceName = channel.ServiceName, Priority = channel.Priority, EmailChannelType = channel.EmailChannelType, DailyLimit = channel.DailyLimit, MonthlyLimit = channel.MonthlyLimit, WarnThresholdPercent = channel.WarnThresholdPercent, IsActive = channel.IsActive, Host = smtp.Host, Port = smtp.Port, Username = smtp.Username, Password = smtp.Password, UseSsl = smtp.UseSsl, FromEmail = smtp.FromEmail, FromName = smtp.FromName }; return View(vm); } // POST /admin/channels/save [HttpPost("save")] [ValidateAntiForgeryToken] public async Task Save(EmailChannelEditViewModel model, CancellationToken ct) { if (!ModelState.IsValid) return View("Edit", model); var smtpSettings = new SmtpChannelSettings { Host = model.Host, Port = model.Port, Username = model.Username, Password = model.Password, UseSsl = model.UseSsl, FromEmail = model.FromEmail, FromName = model.FromName }; if (model.IsNew) { var command = new CreateEmailChannelCommand( model.ServiceName, model.Priority, EmailChannelType.Smtp, smtpSettings, model.DailyLimit, model.MonthlyLimit, model.WarnThresholdPercent, model.IsActive); var result = await _mediator.Send(command, ct); if (!result.IsSuccess) { ModelState.AddModelError("", result.Error?.Message ?? "Failed to create channel."); return View("Edit", model); } } else { var command = new UpdateEmailChannelCommand( model.Id, model.Priority, smtpSettings, model.DailyLimit, model.MonthlyLimit, model.WarnThresholdPercent, model.IsActive); var result = await _mediator.Send(command, ct); if (!result.IsSuccess) { ModelState.AddModelError("", result.Error?.Message ?? "Failed to update channel."); return View("Edit", model); } } return RedirectToAction(nameof(Index)); } // POST /admin/channels/{id}/test [HttpPost("{id:guid}/test")] public async Task Test(Guid id, [FromBody] TestChannelRequest request, CancellationToken ct) { var result = await _mediator.Send(new GetEmailChannelQuery(id), ct); if (!result.IsSuccess || result.Result is null) return NotFound(new { success = false, message = "Channel not found." }); if (result.Result.Settings is not SmtpChannelSettings smtp) return BadRequest(new { success = false, message = "Only SMTP channels are supported." }); try { var message = new MimeMessage(); message.From.Add(new MailboxAddress(smtp.FromName, smtp.FromEmail)); message.To.Add(MailboxAddress.Parse(request.ToEmail)); message.Subject = "✅ Test email from Notification Service"; message.Body = new TextPart("plain") { Text = $"This is a test email sent from the Notification Service admin panel.\n\nChannel: {result.Result.ServiceName}\nHost: {smtp.Host}:{smtp.Port}" }; using var client = new SmtpClient(); var secureSocket = smtp.Port == 465 ? SecureSocketOptions.SslOnConnect : smtp.UseSsl ? SecureSocketOptions.StartTls : SecureSocketOptions.None; await client.ConnectAsync(smtp.Host, smtp.Port, secureSocket, ct); if (!string.IsNullOrWhiteSpace(smtp.Username)) await client.AuthenticateAsync(smtp.Username, smtp.Password, ct); await client.SendAsync(message, ct); await client.DisconnectAsync(true, ct); return Ok(new { success = true, message = $"Test email sent to {request.ToEmail}." }); } catch (Exception ex) { return Ok(new { success = false, message = ex.Message }); } } // POST /admin/channels/{id}/delete [HttpPost("{id:guid}/delete")] [ValidateAntiForgeryToken] public async Task Delete(Guid id, CancellationToken ct) { await _mediator.Send(new DeleteEmailChannelCommand(id), ct); return RedirectToAction(nameof(Index)); } } public record TestChannelRequest(string ToEmail);