using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Nexus.Api.Data; using Nexus.Api.Models; using Nexus.Api.Services; namespace Nexus.Api.Controllers; [Authorize] [ApiController] [Route("api/dashboard/notifications")] public class NotificationsController(INotificationService notificationService) : ControllerBase { [HttpGet] public async Task>> GetNotifications( [FromQuery] string forUser = "bao", [FromQuery] int limit = 50, [FromQuery] bool unreadOnly = false, CancellationToken ct = default) { var notifications = await notificationService.GetForUserAsync(forUser, limit, unreadOnly, ct); return Ok(notifications.Select(notification => MapToDto(notification)).ToList()); } [HttpGet("unread-count")] public async Task> GetUnreadCount( [FromQuery] string forUser = "bao", CancellationToken ct = default) { var count = await notificationService.GetUnreadCountAsync(forUser, ct); return Ok(new UnreadCountDto(count)); } [HttpGet("snapshot")] public async Task> GetSnapshot( [FromQuery] string forUser = "bao", [FromQuery] int limit = 50, [FromQuery] bool unreadOnly = false, CancellationToken ct = default) { return Ok(await notificationService.GetSnapshotAsync(forUser, limit, unreadOnly, ct)); } [HttpPatch("{id:guid}/read")] [ProducesResponseType(typeof(NotificationDto), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task> MarkAsRead( Guid id, CancellationToken ct = default) { var readResult = await notificationService.MarkAsReadAsync(id, ct); var notification = readResult.Notification; if (notification is null) return NotFound(new ProblemDetails { Title = "Notification not found", Detail = $"Notification '{id}' does not exist.", Status = StatusCodes.Status404NotFound }); var primary = new EntityRefDto( "notification", notification.Id.ToString(), notification.Title); var affected = notification.TaskId is { } taskId ? new[] { new EntityRefDto("task", taskId.ToString()) } : []; var operation = OperationResultFactory.FromHttpContext( HttpContext, readResult.Changed ? "completed" : "noop", primary, revision: readResult.Changed ? 1 : 0, affectedRefs: affected); return Ok(MapToDto(notification, operation)); } [HttpPatch("read-all")] [ProducesResponseType(typeof(NotificationReadAllResultDto), StatusCodes.Status200OK)] public async Task> MarkAllAsRead( [FromQuery] string forUser = "bao", CancellationToken ct = default) { var count = await notificationService.MarkAllAsReadAsync(forUser, ct); var operation = OperationResultFactory.FromHttpContext( HttpContext, count > 0 ? "completed" : "noop", new EntityRefDto("notification", "*", "Benachrichtigungen")); return Ok(new NotificationReadAllResultDto(count, operation)); } private static NotificationDto MapToDto( Notification n, OperationResultDto? operation = null) => new( n.Id, n.Type, n.Title, n.Message, n.ForUser, n.TaskId, n.IsRead, n.CreatedAt, operation); }