diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs index 0cde354b..beb5371f 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs @@ -1,4 +1,5 @@ using AzureOpenAIProxy.ApiApp.Models; +using AzureOpenAIProxy.ApiApp.Services; using Microsoft.AspNetCore.Mvc; @@ -18,14 +19,38 @@ public static RouteHandlerBuilder AddNewAdminEvent(this WebApplication app) { var builder = app.MapPost(AdminEndpointUrls.AdminEvents, async ( [FromBody] AdminEventDetails payload, - HttpRequest request) => + IAdminEventService service, + ILoggerFactory loggerFactory) => { + var logger = loggerFactory.CreateLogger(nameof(AdminEventEndpoints)); + logger.LogInformation("Received a new event request"); + + if (payload is null) + { + logger.LogError("No payload found"); + + return Results.BadRequest("Payload is null"); + } + + //try + //{ + // var result = await service.CreateEvent(payload); + + // logger.LogInformation("Created a new event"); + + // return Results.Ok(result); + //} + //catch (Exception ex) + //{ + // logger.LogError(ex, "Failed to create a new event"); + + // return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError); + //} + return await Task.FromResult(Results.Ok()); }) - // TODO: Check both request/response payloads .Accepts(contentType: "application/json") .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") - // TODO: Check both request/response payloads .Produces(statusCode: StatusCodes.Status400BadRequest) .Produces(statusCode: StatusCodes.Status401Unauthorized) .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index 4f587217..a3ccdf25 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -1,4 +1,6 @@ -namespace AzureOpenAIProxy.ApiApp.Models; +using System.Text.Json.Serialization; + +namespace AzureOpenAIProxy.ApiApp.Models; /// /// This represent the event detail data for response by admin event endpoint. @@ -13,32 +15,38 @@ public class AdminEventDetails : EventDetails /// /// Gets or sets the event start date. /// - public required DateTimeOffset? DateStart { get; set; } + [JsonRequired] + public DateTimeOffset DateStart { get; set; } /// /// Gets or sets the event end date. /// - public required DateTimeOffset? DateEnd { get; set; } + [JsonRequired] + public DateTimeOffset DateEnd { get; set; } /// /// Gets or sets the event start to end date timezone. /// - public required string? TimeZone { get; set; } + [JsonRequired] + public string TimeZone { get; set; } = string.Empty; /// /// Gets or sets the event active status. /// - public required bool? IsActive { get; set; } + [JsonRequired] + public bool IsActive { get; set; } /// /// Gets or sets the event organizer name. /// - public required string? OrganizerName { get; set; } + [JsonRequired] + public string OrganizerName { get; set; } = string.Empty; /// /// Gets or sets the event organizer email. /// - public required string? OrganizerEmail { get; set; } + [JsonRequired] + public string OrganizerEmail { get; set; } = string.Empty; /// /// Gets or sets the event coorganizer name. diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs index 5c33fafb..ae3594f2 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs @@ -1,8 +1,5 @@ -using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; -using AzureOpenAIProxy.ApiApp.Models; - /// /// This represents the event's detailed data for response by EventEndpoint. /// @@ -11,25 +8,30 @@ public class EventDetails /// /// Gets or sets the event id. /// - public required string? EventId { get; set; } + [JsonRequired] + public Guid EventId { get; set; } /// /// Gets or sets the event title name. /// - public required string? Title { get; set; } + [JsonRequired] + public string Title { get; set; } = string.Empty; /// /// Gets or sets the event summary. /// - public required string? Summary { get; set; } + [JsonRequired] + public string Summary { get; set; } = string.Empty; /// /// Gets or sets the Azure OpenAI Service request max token capacity. /// - public required int? MaxTokenCap { get; set; } + [JsonRequired] + public int MaxTokenCap { get; set; } /// /// Gets or sets the Azure OpenAI Service daily request capacity. /// - public required int? DailyRequestCap { get; set; } + [JsonRequired] + public int DailyRequestCap { get; set; } } \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 5ce6fbe0..1ef3a28c 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -1,5 +1,6 @@ using AzureOpenAIProxy.ApiApp.Endpoints; using AzureOpenAIProxy.ApiApp.Extensions; +using AzureOpenAIProxy.ApiApp.Services; var builder = WebApplication.CreateBuilder(args); @@ -14,6 +15,9 @@ // Add OpenAPI service builder.Services.AddOpenApiService(); +// Add admin services +builder.Services.AddAdminEventService(); + var app = builder.Build(); app.MapDefaultEndpoints(); diff --git a/src/AzureOpenAIProxy.ApiApp/Services/AdminEventService.cs b/src/AzureOpenAIProxy.ApiApp/Services/AdminEventService.cs new file mode 100644 index 00000000..d3e0533f --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Services/AdminEventService.cs @@ -0,0 +1,85 @@ +using AzureOpenAIProxy.ApiApp.Models; + +namespace AzureOpenAIProxy.ApiApp.Services; + +/// +/// This provides interfaces to class. +/// +public interface IAdminEventService +{ + /// + /// Creates a new event. + /// + /// Event payload. + /// Returns the event payload created. + Task CreateEvent(AdminEventDetails eventDetails); + + /// + /// Gets the list of events. + /// + /// Returns the list of events. + Task> GetEvents(); + + /// + /// Gets the event details. + /// + /// Event ID. + /// Returns the event details. + Task GetEvent(Guid eventId); + + /// + /// Updates the event details. + /// + /// Event ID. + /// Event details to update. + /// Returns the updated event details. + Task UpdateEvent(Guid eventId, AdminEventDetails eventDetails); +} + +/// +/// This represents the service entity for admin event. +/// +public class AdminEventService : IAdminEventService +{ + /// + public async Task CreateEvent(AdminEventDetails eventDetails) + { + throw new NotImplementedException(); + } + + /// + public async Task> GetEvents() + { + throw new NotImplementedException(); + } + + /// + public async Task GetEvent(Guid eventId) + { + throw new NotImplementedException(); + } + + /// + public async Task UpdateEvent(Guid eventId, AdminEventDetails eventDetails) + { + throw new NotImplementedException(); + } +} + +/// +/// This represents the extension class for +/// +public static class AdminEventServiceExtensions +{ + /// + /// Adds the instance to the service collection. + /// + /// instance. + /// Returns instance. + public static IServiceCollection AddAdminEventService(this IServiceCollection services) + { + services.AddScoped(); + + return services; + } +} diff --git a/test/AzureOpenAIProxy.ApiApp.Tests/Services/AdminEventServiceTests.cs b/test/AzureOpenAIProxy.ApiApp.Tests/Services/AdminEventServiceTests.cs new file mode 100644 index 00000000..e459e4d0 --- /dev/null +++ b/test/AzureOpenAIProxy.ApiApp.Tests/Services/AdminEventServiceTests.cs @@ -0,0 +1,80 @@ +using AzureOpenAIProxy.ApiApp.Models; +using AzureOpenAIProxy.ApiApp.Services; + +using FluentAssertions; + +using Microsoft.Extensions.DependencyInjection; + +namespace AzureOpenAIProxy.ApiApp.Tests.Services; + +public class AdminEventServiceTests +{ + [Fact] + public void Given_ServiceCollection_When_AddAdminEventService_Invoked_Then_It_Should_Contain_AdminEventService() + { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddAdminEventService(); + + // Assert + services.SingleOrDefault(p => p.ServiceType == typeof(IAdminEventService)).Should().NotBeNull(); + } + + [Fact] + public void Given_Instance_When_CreateEvent_Invoked_Then_It_Should_Throw_Exception() + { + // Arrange + var eventDetails = new AdminEventDetails(); + var service = new AdminEventService(); + + // Act + Func func = async () => await service.CreateEvent(eventDetails); + + // Assert + func.Should().ThrowAsync(); + } + + [Fact] + public void Given_Instance_When_GetEvents_Invoked_Then_It_Should_Throw_Exception() + { + // Arrange + var service = new AdminEventService(); + + // Act + Func func = async () => await service.GetEvents(); + + // Assert + func.Should().ThrowAsync(); + } + + [Fact] + public void Given_Instance_When_GetEvent_Invoked_Then_It_Should_Throw_Exception() + { + // Arrange + var eventId = Guid.NewGuid(); + var service = new AdminEventService(); + + // Act + Func func = async () => await service.GetEvent(eventId); + + // Assert + func.Should().ThrowAsync(); + } + + [Fact] + public void Given_Instance_When_UpdateEvent_Invoked_Then_It_Should_Throw_Exception() + { + // Arrange + var eventId = Guid.NewGuid(); + var eventDetails = new AdminEventDetails(); + var service = new AdminEventService(); + + // Act + Func func = async () => await service.UpdateEvent(eventId, eventDetails); + + // Assert + func.Should().ThrowAsync(); + } +} diff --git a/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs index 22adb326..4af8e386 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs @@ -4,7 +4,7 @@ using FluentAssertions; -namespace AzureOpenAIProxy.Tests; +namespace AzureOpenAIProxy.AppHost.Tests; public class AppHostProgramTests(AspireAppHostFixture host) : IClassFixture {