using Knot.Modules.Conversations.Application.DTOs; using Knot.Modules.Conversations.Application.Messages.GetMessages; using Knot.Modules.Conversations.Application.Messages.GetSharedMedia; using Knot.Modules.Conversations.Application.Messages.SearchMessages; using Knot.Modules.Conversations.Application.Messages.Send; using Knot.Modules.Conversations.Application.Messages.UploadFile; using Knot.Shared.Kernel; using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace Knot.Modules.Conversations.Presentation.Endpoints; public static class MessagesEndpoints { public static void MapMessagesEndpoints(this WebApplication app) { var group = app.MapGroup("api/messages").RequireAuthorization(); group.MapGet("chat/{chatId:guid}", async ( [FromRoute] Guid chatId, [FromQuery] string? cursor, [FromQuery] long? afterSequenceId, [FromQuery] long? pivot, [FromQuery] int? limit, ISender sender, IUserContext userContext, CancellationToken ct) => { var result = await sender.Send(new GetMessagesQuery(userContext.UserId, chatId, cursor, pivot, afterSequenceId, limit), ct); return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description); }); group.MapGet("search", async ([FromQuery] string q, [FromQuery] Guid? chatId, ISender sender, IUserContext userContext, CancellationToken ct) => { var result = await sender.Send(new SearchMessagesQuery(userContext.UserId, q, chatId), ct); return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description); }); group.MapPost("upload", async (HttpRequest req, ISender sender, CancellationToken ct) => { if (!req.HasFormContentType) return Results.BadRequest("No file uploaded"); var form = await req.ReadFormAsync(ct); var file = form.Files.FirstOrDefault(); if (file == null || file.Length == 0) return Results.BadRequest("No file uploaded"); using var stream = file.OpenReadStream(); var result = await sender.Send(new UploadFileCommand(file.FileName, file.ContentType, file.Length, stream), ct); if (result.IsFailure) { if (result.Error.Code == "File.TooLarge") return Results.StatusCode(413); return Results.BadRequest(result.Error.Description); } return Results.Ok(result.Value); }).DisableAntiforgery(); group.MapGet("chat/{chatId:guid}/shared", async ([FromRoute] Guid chatId, [FromQuery] string? type, ISender sender, IUserContext userContext, CancellationToken ct) => { var result = await sender.Send(new GetSharedMediaQuery(userContext.UserId, chatId, type), ct); return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description); }); group.MapPost("chat/{chatId:guid}", async ([FromRoute] Guid chatId, [FromBody] SendMessageRequest request, ISender sender, IUserContext userContext, CancellationToken ct) => { var attachments = request.Attachments?.Select(a => new AttachmentRequest(a.Type, a.Url, a.FileName, a.FileSize)).ToList(); var command = new SendMessageCommand( chatId, userContext.UserId, request.Content, request.Type, attachments, request.ReplyToId, request.Quote, request.ForwardedFromId); var result = await sender.Send(command, ct); return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description); }); } }