From 98f0da8f467ffb45363c327fd62c8f125123aa84 Mon Sep 17 00:00:00 2001 From: ktutak1337 Date: Sat, 30 Mar 2024 16:04:50 +0100 Subject: [PATCH] Code(API::GetChatSession): Implement GetChatSession feature --- .../Chat/ChatSessionNotFoundException.cs | 21 +++++++++++++++ .../Repositories/IChatSessionRepository.cs | 2 +- .../StellarChat.Server.Api/Extensions.cs | 5 ++++ .../Chat/GetChatSession/GetChatSession.cs | 9 +++++++ .../GetChatSession/GetChatSessionEndpoint.cs | 26 +++++++++++++++++++ .../GetChatSession/GetChatSessionHandler.cs | 19 ++++++++++++++ .../StellarChat.Server.Api.csproj | 5 ++++ .../Contracts/Chat/ChatSessionResponse.cs | 3 +++ .../Extensions.cs | 7 +++-- .../StellarChat.Shared.Infrastructure.csproj | 5 ---- 10 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 src/Server/StellarChat.Server.Api/DAL/Mongo/Exceptions/Chat/ChatSessionNotFoundException.cs create mode 100644 src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSession.cs create mode 100644 src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionEndpoint.cs create mode 100644 src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionHandler.cs create mode 100644 src/Shared/StellarChat.Shared.Abstractions/Contracts/Chat/ChatSessionResponse.cs diff --git a/src/Server/StellarChat.Server.Api/DAL/Mongo/Exceptions/Chat/ChatSessionNotFoundException.cs b/src/Server/StellarChat.Server.Api/DAL/Mongo/Exceptions/Chat/ChatSessionNotFoundException.cs new file mode 100644 index 0000000..8428940 --- /dev/null +++ b/src/Server/StellarChat.Server.Api/DAL/Mongo/Exceptions/Chat/ChatSessionNotFoundException.cs @@ -0,0 +1,21 @@ +using StellarChat.Shared.Abstractions.Exceptions; + +namespace StellarChat.Server.Api.DAL.Mongo.Exceptions.Chat; + +internal sealed class ChatSessionNotFoundException : StellarChatException +{ + public Guid Id { get; } + public string? Title { get; } + + public ChatSessionNotFoundException(Guid id) + : base( + message: $"Chat session with ID: {id} not found.", + userMessage: $"The requested chat session could not be found.") + => Id = id; + + public ChatSessionNotFoundException(string title) + : base( + message: $"Chat session with title: {title} not found.", + userMessage: $"The chat session with the title '{title}' could not be found.") + => Title = title; +} diff --git a/src/Server/StellarChat.Server.Api/Domain/Chat/Repositories/IChatSessionRepository.cs b/src/Server/StellarChat.Server.Api/Domain/Chat/Repositories/IChatSessionRepository.cs index f07ab1d..c14143b 100644 --- a/src/Server/StellarChat.Server.Api/Domain/Chat/Repositories/IChatSessionRepository.cs +++ b/src/Server/StellarChat.Server.Api/Domain/Chat/Repositories/IChatSessionRepository.cs @@ -2,7 +2,7 @@ namespace StellarChat.Server.Api.Domain.Chat.Repositories; -internal interface IChatSessionRepository +public interface IChatSessionRepository { ValueTask GetAsync(Guid id); ValueTask GetByTitleAsync(string title); diff --git a/src/Server/StellarChat.Server.Api/Extensions.cs b/src/Server/StellarChat.Server.Api/Extensions.cs index 92f5a77..bcffef2 100644 --- a/src/Server/StellarChat.Server.Api/Extensions.cs +++ b/src/Server/StellarChat.Server.Api/Extensions.cs @@ -21,6 +21,11 @@ public static void AddInfrastructure(this WebApplicationBuilder builder) .AddScoped() .AddMongoRepository("messages") .AddMongoRepository("chat-sessions"); + + builder.Services.AddMediator(options => + { + options.ServiceLifetime = ServiceLifetime.Scoped; + }); } public static WebApplication UseInfrastructure(this WebApplication app) diff --git a/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSession.cs b/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSession.cs new file mode 100644 index 0000000..6b08584 --- /dev/null +++ b/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSession.cs @@ -0,0 +1,9 @@ +using Mediator; +using StellarChat.Shared.Abstractions.Contracts.Chat; + +namespace StellarChat.Server.Api.Features.Chat.GetChatSession; + +internal sealed record GetChatSession : IQuery +{ + public Guid Id { get; set; } +} diff --git a/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionEndpoint.cs b/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionEndpoint.cs new file mode 100644 index 0000000..7d11bc3 --- /dev/null +++ b/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionEndpoint.cs @@ -0,0 +1,26 @@ +using Mediator; +using StellarChat.Shared.Abstractions.API.Endpoints; +using StellarChat.Shared.Abstractions.Contracts.Chat; + +namespace StellarChat.Server.Api.Features.Chat.GetChatSession; + +internal sealed class GetChatSessionEndpoint : IEndpoint +{ + public void Expose(IEndpointRouteBuilder endpoints) + { + var chatHistory = endpoints.MapGroup("/chat-history").WithTags("Chat history"); + + chatHistory.MapGet("/sessions/{chatId:guid}", async (Guid chatId, IMediator mediator) => IEndpoint.Select(await mediator.Send(new GetChatSession { Id = chatId }))) + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status404NotFound) + .WithName("GetChatSession") + .WithOpenApi(operation => new(operation) + { + Summary = "Retrieves a single chat session by 'chatId'." + }); + } + + public void Register(IServiceCollection services, IConfiguration configuration) { } + + public void Use(IApplicationBuilder app) { } +} diff --git a/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionHandler.cs b/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionHandler.cs new file mode 100644 index 0000000..51b3a61 --- /dev/null +++ b/src/Server/StellarChat.Server.Api/Features/Chat/GetChatSession/GetChatSessionHandler.cs @@ -0,0 +1,19 @@ +using Mapster; +using Mediator; +using StellarChat.Server.Api.DAL.Mongo.Exceptions.Chat; +using StellarChat.Server.Api.Domain.Chat.Repositories; +using StellarChat.Shared.Abstractions.Contracts.Chat; + +namespace StellarChat.Server.Api.Features.Chat.GetChatSession; + +internal sealed class GetChatSessionHandler : IQueryHandler +{ + private readonly IChatSessionRepository _chatSessionRepository; + + public GetChatSessionHandler(IChatSessionRepository chatSessionRepository) + => _chatSessionRepository = chatSessionRepository; + + public async ValueTask Handle(GetChatSession query, CancellationToken cancellationToken) + => (await _chatSessionRepository.GetAsync(query.Id)) + .Adapt() ?? throw new ChatSessionNotFoundException(query.Id); +} diff --git a/src/Server/StellarChat.Server.Api/StellarChat.Server.Api.csproj b/src/Server/StellarChat.Server.Api/StellarChat.Server.Api.csproj index 256f610..1afb5b5 100644 --- a/src/Server/StellarChat.Server.Api/StellarChat.Server.Api.csproj +++ b/src/Server/StellarChat.Server.Api/StellarChat.Server.Api.csproj @@ -11,6 +11,11 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Shared/StellarChat.Shared.Abstractions/Contracts/Chat/ChatSessionResponse.cs b/src/Shared/StellarChat.Shared.Abstractions/Contracts/Chat/ChatSessionResponse.cs new file mode 100644 index 0000000..4d7114d --- /dev/null +++ b/src/Shared/StellarChat.Shared.Abstractions/Contracts/Chat/ChatSessionResponse.cs @@ -0,0 +1,3 @@ +namespace StellarChat.Shared.Abstractions.Contracts.Chat; + +public record ChatSessionResponse(Guid Id, string Title, string Metaprompt, HashSet ActivePlugins, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); diff --git a/src/Shared/StellarChat.Shared.Infrastructure/Extensions.cs b/src/Shared/StellarChat.Shared.Infrastructure/Extensions.cs index 6c295e0..8d2cbe5 100644 --- a/src/Shared/StellarChat.Shared.Infrastructure/Extensions.cs +++ b/src/Shared/StellarChat.Shared.Infrastructure/Extensions.cs @@ -31,8 +31,7 @@ public static WebApplicationBuilder AddSharedInfrastructure(this WebApplicationB .AddCorsPolicy(builder.Configuration) .AddMongo(builder.Configuration) .RegisterEndpoints(builder.Configuration) - .AddSemanticKernel(builder.Configuration) - .AddMediator(); + .AddSemanticKernel(builder.Configuration); return builder; } @@ -62,7 +61,7 @@ public static string ToSnakeCase(this string input) Regex.Replace( Regex.Replace(input, @"([\p{Lu}]+)([\p{Lu}][\p{Ll}])", "$1_$2"), @"([\p{Ll}\d])([\p{Lu}])", "$1_$2"), @"[-\s]", "_").ToLower(); - public static bool IsEmpty(this string value) + public static bool IsEmpty(this string value) => string.IsNullOrWhiteSpace(value); public static bool IsNotEmpty(this string value) @@ -99,7 +98,7 @@ public static string GetUserIpAddress(this HttpContext context) if (context.Request.Headers.TryGetValue("x-forwarded-for", out var forwardedFor)) { var ipAddresses = forwardedFor.ToString().Split(",", StringSplitOptions.RemoveEmptyEntries); - + if (ipAddresses.Any()) { ipAddress = ipAddresses[0]; diff --git a/src/Shared/StellarChat.Shared.Infrastructure/StellarChat.Shared.Infrastructure.csproj b/src/Shared/StellarChat.Shared.Infrastructure/StellarChat.Shared.Infrastructure.csproj index b6ace02..0182cb6 100644 --- a/src/Shared/StellarChat.Shared.Infrastructure/StellarChat.Shared.Infrastructure.csproj +++ b/src/Shared/StellarChat.Shared.Infrastructure/StellarChat.Shared.Infrastructure.csproj @@ -11,11 +11,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive -