feat: implement communications module with SMTP settings, email logging, and frontend UI
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Zentral.API.Apps.Communications.Dtos;
|
||||
using Zentral.Domain.Entities;
|
||||
using Zentral.Domain.Interfaces;
|
||||
using Zentral.Infrastructure.Data;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace Zentral.API.Apps.Communications.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/communications")]
|
||||
public class CommunicationsController : ControllerBase
|
||||
{
|
||||
private readonly ZentralDbContext _context;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public CommunicationsController(ZentralDbContext context, IEmailSender emailSender)
|
||||
{
|
||||
_context = context;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
[HttpGet("config")]
|
||||
public async Task<ActionResult<SmtpConfigDto>> GetConfig()
|
||||
{
|
||||
var configs = await _context.Configurazioni
|
||||
.Where(c => c.Chiave.StartsWith("SMTP_"))
|
||||
.ToDictionaryAsync(c => c.Chiave, c => c.Valore);
|
||||
|
||||
var dto = new SmtpConfigDto
|
||||
{
|
||||
Host = GetValue(configs, "SMTP_HOST"),
|
||||
Port = int.Parse(GetValue(configs, "SMTP_PORT", "587")),
|
||||
User = GetValue(configs, "SMTP_USER"),
|
||||
Password = GetValue(configs, "SMTP_PASS"),
|
||||
EnableSsl = bool.Parse(GetValue(configs, "SMTP_SSL", "false")),
|
||||
FromEmail = GetValue(configs, "SMTP_FROM_EMAIL"),
|
||||
FromName = GetValue(configs, "SMTP_FROM_NAME")
|
||||
};
|
||||
|
||||
return Ok(dto);
|
||||
}
|
||||
|
||||
[HttpPost("config")]
|
||||
public async Task<ActionResult> SaveConfig(SmtpConfigDto dto)
|
||||
{
|
||||
await SetConfig("SMTP_HOST", dto.Host);
|
||||
await SetConfig("SMTP_PORT", dto.Port.ToString());
|
||||
await SetConfig("SMTP_USER", dto.User);
|
||||
await SetConfig("SMTP_PASS", dto.Password);
|
||||
await SetConfig("SMTP_SSL", dto.EnableSsl.ToString().ToLower());
|
||||
await SetConfig("SMTP_FROM_EMAIL", dto.FromEmail);
|
||||
await SetConfig("SMTP_FROM_NAME", dto.FromName);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("send-test")]
|
||||
public async Task<ActionResult> SendTestEmail(TestEmailDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _emailSender.SendEmailAsync(dto.To, dto.Subject, dto.Body);
|
||||
return Ok(new { message = "Email send process initiated. Check logs for status." });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("logs")]
|
||||
public async Task<ActionResult<List<EmailLogDto>>> GetLogs([FromQuery] int limit = 50)
|
||||
{
|
||||
var logs = await _context.EmailLogs
|
||||
.OrderByDescending(l => l.SentDate)
|
||||
.Take(limit)
|
||||
.Select(l => new EmailLogDto
|
||||
{
|
||||
Id = l.Id,
|
||||
SentDate = l.SentDate,
|
||||
Sender = l.Sender,
|
||||
Recipient = l.Recipient,
|
||||
Subject = l.Subject,
|
||||
Status = l.Status,
|
||||
ErrorMessage = l.ErrorMessage
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(logs);
|
||||
}
|
||||
|
||||
private string GetValue(Dictionary<string, string?> dict, string key, string def = "")
|
||||
{
|
||||
return dict.ContainsKey(key) && dict[key] != null ? dict[key]! : def;
|
||||
}
|
||||
|
||||
private async Task SetConfig(string key, string? value)
|
||||
{
|
||||
var config = await _context.Configurazioni.FirstOrDefaultAsync(c => c.Chiave == key);
|
||||
if (config == null)
|
||||
{
|
||||
config = new Configurazione { Chiave = key, CreatedAt = DateTime.UtcNow, CreatedBy = User.FindFirstValue(ClaimTypes.Name) ?? "System" };
|
||||
_context.Configurazioni.Add(config);
|
||||
}
|
||||
config.Valore = value;
|
||||
config.UpdatedAt = DateTime.UtcNow;
|
||||
config.UpdatedBy = User.FindFirstValue(ClaimTypes.Name) ?? "System";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Zentral.API.Apps.Communications.Dtos;
|
||||
|
||||
public class EmailLogDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public DateTime SentDate { get; set; }
|
||||
public string Sender { get; set; } = string.Empty;
|
||||
public string Recipient { get; set; } = string.Empty;
|
||||
public string Subject { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Zentral.API.Apps.Communications.Dtos;
|
||||
|
||||
public class SmtpConfigDto
|
||||
{
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public int Port { get; set; } = 587;
|
||||
public string User { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public bool EnableSsl { get; set; } = false;
|
||||
public string FromEmail { get; set; } = string.Empty;
|
||||
public string FromName { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Zentral.API.Apps.Communications.Dtos;
|
||||
|
||||
public class TestEmailDto
|
||||
{
|
||||
public string To { get; set; } = string.Empty;
|
||||
public string Subject { get; set; } = "Test Email from Zentral";
|
||||
public string Body { get; set; } = "This is a test email sent from Zentral Communications Module.";
|
||||
}
|
||||
@@ -6,7 +6,10 @@ using Zentral.API.Apps.Warehouse.Services;
|
||||
using Zentral.API.Apps.Purchases.Services;
|
||||
using Zentral.API.Apps.Sales.Services;
|
||||
using Zentral.API.Apps.Production.Services;
|
||||
using Zentral.API.Apps.Production.Services;
|
||||
using Zentral.Infrastructure.Data;
|
||||
using Zentral.Infrastructure.Services;
|
||||
using Zentral.Domain.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
@@ -28,6 +31,9 @@ builder.Services.AddScoped<AutoCodeService>();
|
||||
builder.Services.AddScoped<CustomFieldService>();
|
||||
builder.Services.AddSingleton<DataNotificationService>();
|
||||
|
||||
// Communications Module Services
|
||||
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();
|
||||
|
||||
// Warehouse Module Services
|
||||
builder.Services.AddScoped<IWarehouseService, WarehouseService>();
|
||||
|
||||
|
||||
@@ -521,6 +521,20 @@ public class AppService
|
||||
RoutePath = "/report-designer",
|
||||
IsAvailable = true,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
},
|
||||
new App
|
||||
{
|
||||
Code = "communications",
|
||||
Name = "Comunicazioni",
|
||||
Description = "Gestione invio mail, chat interna e condivisione risorse",
|
||||
Icon = "Email",
|
||||
BasePrice = 1000m,
|
||||
MonthlyMultiplier = 1.2m,
|
||||
SortOrder = 90,
|
||||
IsCore = false,
|
||||
RoutePath = "/communications",
|
||||
IsAvailable = true,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user