Files
MotoresArgentinosV2/Backend/MotoresArgentinosV2.API/Controllers/ChatController.cs

149 lines
5.6 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MotoresArgentinosV2.Infrastructure.Data;
using MotoresArgentinosV2.Core.Entities;
using MotoresArgentinosV2.Core.Interfaces;
using Microsoft.AspNetCore.Authorization;
namespace MotoresArgentinosV2.API.Controllers;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class ChatController : ControllerBase
{
private readonly MotoresV2DbContext _context;
private readonly INotificationService _notificationService;
private readonly INotificationPreferenceService _prefService;
private readonly string _frontendUrl;
public ChatController(
MotoresV2DbContext context,
INotificationService notificationService,
INotificationPreferenceService prefService,
IConfiguration config)
{
_context = context;
_notificationService = notificationService;
_prefService = prefService;
_frontendUrl = config["AppSettings:FrontendUrl"]?.Split(',')[0].Trim() ?? "http://localhost:5173";
}
[HttpPost("send")]
public async Task<IActionResult> SendMessage([FromBody] ChatMessage msg)
{
// 1. Guardar Mensaje
msg.SentAt = DateTime.UtcNow;
msg.IsRead = false;
_context.ChatMessages.Add(msg);
await _context.SaveChangesAsync();
// 2. Notificar por Email (Con manejo de errores silencioso)
try
{
var receiver = await _context.Users.FindAsync(msg.ReceiverID);
var sender = await _context.Users.FindAsync(msg.SenderID);
if (receiver != null && !string.IsNullOrEmpty(receiver.Email))
{
// Solo enviar correo si la preferencia "mensajes" está habilitada
if (await _prefService.IsEnabledAsync(receiver.UserID, NotificationCategory.Mensajes))
{
// LÓGICA DE NOMBRE DE REMITENTE
string senderDisplayName;
if (sender != null && sender.UserType == 3) // 3 = ADMIN
{
// Caso: Moderador escribe a Usuario
senderDisplayName = "Un moderador de Motores Argentinos";
}
else
{
// Caso: Usuario responde a Moderador
string name = sender?.UserName ?? "Un usuario";
senderDisplayName = $"El usuario {name}";
}
// Generamos el token de baja para la categoría "mensajes"
var rawToken = await _prefService.GetOrCreateUnsubscribeTokenAsync(receiver.UserID, NotificationCategory.Mensajes);
var unsubscribeUrl = $"{_frontendUrl}/baja/procesar?token={Uri.EscapeDataString(rawToken)}";
await _notificationService.SendChatNotificationEmailAsync(
receiver.Email,
senderDisplayName, // Pasamos el nombre formateado
msg.MessageText,
msg.AdID,
unsubscribeUrl); // Se incluye URL de baja en el footer
}
}
}
catch (Exception ex)
{
// Loguear error sin romper el flujo del chat
Console.WriteLine($"Error enviando notificación de chat: {ex.Message}");
}
return Ok(msg);
}
[HttpGet("inbox/{userId}")]
public async Task<IActionResult> GetInbox(int userId)
{
// Obtener todas las conversaciones donde el usuario es remitente o destinatario
// Pero filtramos los que pertenecen a avisos eliminados (StatusID != 9)
var messages = await _context.ChatMessages
.Where(m => m.SenderID == userId || m.ReceiverID == userId)
.Join(_context.Ads, m => m.AdID, a => a.AdID, (m, a) => new { m, a })
.Where(x => x.a.StatusID != (int)AdStatusEnum.Deleted)
.Select(x => x.m)
.OrderByDescending(m => m.SentAt)
.ToListAsync();
return Ok(messages);
}
[HttpGet("conversation/{adId}/{user1Id}/{user2Id}")]
public async Task<IActionResult> GetConversation(int adId, int user1Id, int user2Id)
{
var messages = await _context.ChatMessages
.Where(m => m.AdID == adId &&
((m.SenderID == user1Id && m.ReceiverID == user2Id) ||
(m.SenderID == user2Id && m.ReceiverID == user1Id)))
.OrderBy(m => m.SentAt)
.ToListAsync();
return Ok(messages);
}
[HttpPost("mark-read/{messageId}")]
public async Task<IActionResult> MarkRead(int messageId)
{
var msg = await _context.ChatMessages.FindAsync(messageId);
if (msg == null) return NotFound();
msg.IsRead = true;
await _context.SaveChangesAsync();
return Ok();
}
[HttpGet("unread-count/{userId}")]
public async Task<IActionResult> GetUnreadCount(int userId)
{
// Seguridad: Asegurarse de que el usuario que consulta es el dueño de los mensajes o un admin.
var currentUserId = int.Parse(User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "0");
var isAdmin = User.IsInRole("Admin");
if (currentUserId != userId && !isAdmin)
{
return Forbid();
}
var count = await _context.ChatMessages
.Join(_context.Ads, m => m.AdID, a => a.AdID, (m, a) => new { m, a })
.CountAsync(x => x.m.ReceiverID == userId && !x.m.IsRead && x.a.StatusID != (int)AdStatusEnum.Deleted);
return Ok(new { count });
}
}