From 4258bf68304c8e6d85cdfebf5fff6d81016deb61 Mon Sep 17 00:00:00 2001 From: Inseo Lee Date: Wed, 21 Aug 2024 07:08:39 +0000 Subject: [PATCH 01/26] Add EventListEntity --- .../Models/EventListEntity.cs | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs new file mode 100644 index 00000000..560b45b8 --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs @@ -0,0 +1,89 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +using AzureOpenAIProxy.ApiApp.Models; + +/// +/// Data transfer model for showing all events +/// +public class EventListEntity +{ + /// + /// Event Id + /// + [JsonPropertyName("eventId")] + public required string EventId { get; set; } + + /// + /// Event name + /// + [JsonPropertyName("eventName")] + public required string EventName { get; set; } + + /// + /// Event start time + /// + [JsonPropertyName("startTime")] + public required DateTimeOffset? StartTime { get; set; } + + /// + /// Event end time + /// + [JsonPropertyName("endTime")] + public required DateTimeOffset? EndTime { get; set; } + + /// + /// Event's time zone. It could be serialized to string + /// + [JsonPropertyName("tz")] + public required TimeZoneInfo? TimeZone { get; set; } + + /// + /// Organizer's name + /// + [JsonPropertyName("organizerName")] + public required string OrganizerName { get; set; } + + /// + /// Organizer's email address. + /// + [EmailAddress] + [JsonPropertyName("OrganizerEmail")] + public required string OrganizerEmail { get; set; } + + /// + /// The number of registered users + /// + [JsonPropertyName("registered")] + public required int Registered { get; set; } + + /// + /// List of resources that the organizer deploys + /// + [JsonPropertyName("resources")] + public required virtual IList Resources { get; set; } + + /// + /// Shows whether the event is active or not + /// + [JsonPropertyName("isActive")] + public required bool IsActive { get; set; } + + /// + /// Define the list entity of Resources + /// + public class ResourceEntity + { + /// + /// Resource's Id + /// + [JsonPropertyName("id")] + public required string ResourceId {get; set; } + + /// + /// Resource's name. e.g. gpt4o + /// + [JsonPropertyName("name")] + public required string ResourceName {get; set; } + } +} \ No newline at end of file From 6a2d022476705f04fdcc350779139ec5e4befbd8 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Thu, 22 Aug 2024 14:43:26 +0900 Subject: [PATCH 02/26] Implement EventEndpoint --- .../Endpoints/EndpointUrls.cs | 7 ++- .../Endpoints/EventEndpoint.cs | 58 +++++++++++++++++++ .../Models/EventListEntity.cs | 6 +- src/AzureOpenAIProxy.ApiApp/Program.cs | 1 + 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs index be5b3e79..b69068eb 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs @@ -1,4 +1,4 @@ -namespace AzureOpenAIProxy.ApiApp.Endpoints; +namespace AzureOpenAIProxy.ApiApp.Endpoints; /// /// This represents the collection of the endpoint URLs. @@ -14,4 +14,9 @@ public static class EndpointUrls /// Declares the chat completions endpoint. /// public const string ChatCompletions = "/openai/deployments/{deploymentName}/chat/completions"; + + /// + /// Declares the event endpoint. + /// + public const string Events = "/events"; } diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs new file mode 100644 index 00000000..6447bcd3 --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -0,0 +1,58 @@ +using System.Text.Json; +using AzureOpenAIProxy.ApiApp.Models; + +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; + +namespace AzureOpenAIProxy.ApiApp.Endpoints +{ + public static class EventEndpoint + { + public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) + { + // TODO: Authorization process with bearer token (JWT) with endpoint filter + var rt = app.MapGet(EndpointUrls.Events, + ( + HttpRequest request + ) => + { + // These events are mock for now. + var sampleEvents = new List + { + new EventListEntity { EventName = "Opening Hackathon", + EventId = Guid.NewGuid().ToString(), + StartTime = DateTimeOffset.Now, + EndTime = DateTimeOffset.Now.AddDays(1), + IsActive = true, + OrganizerName = "John Doe", + OrganizerEmail = "me@example.com", + TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Seoul").Id, + Registered = 10, + Resources = new List + { + new EventListEntity.ResourceEntity { ResourceId = "1", ResourceName = "gpt4o" } + } + } + }; + // TODO: Should add 404 logic if the server failed to retrieve data with TypedResult + return TypedResults.Ok(sampleEvents); + }) + // Note: RouteHandlerBuilder does not have ProducesProblem extension method yet, but it will be added on .NET 9 + // Source: https://github.com/dotnet/aspnetcore/issues/56178 + .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") + .Produces(statusCode: StatusCodes.Status401Unauthorized, contentType: "application/problem+json") + .Produces(statusCode: StatusCodes.Status404NotFound, contentType: "application/problem+json") + .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "application/problem+json") + .WithTags("events") + .WithName("GetEvents") + .WithOpenApi(operations => + { + operations.Description = "Show all events in Azure OpenAI Proxy services."; + operations.Summary = "Get all events"; + return operations; + }); + + return rt; + } + } +} diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs index 560b45b8..28ed8bf1 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs @@ -4,7 +4,7 @@ using AzureOpenAIProxy.ApiApp.Models; /// -/// Data transfer model for showing all events +/// Data transfer model for showing all events /// public class EventListEntity { @@ -36,7 +36,7 @@ public class EventListEntity /// Event's time zone. It could be serialized to string /// [JsonPropertyName("tz")] - public required TimeZoneInfo? TimeZone { get; set; } + public required string? TimeZone { get; set; } /// /// Organizer's name @@ -61,7 +61,7 @@ public class EventListEntity /// List of resources that the organizer deploys /// [JsonPropertyName("resources")] - public required virtual IList Resources { get; set; } + public virtual IEnumerable? Resources { get; set; } /// /// Shows whether the event is active or not diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 5a68a0be..06e68066 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -35,5 +35,6 @@ app.AddWeatherForecast(); app.AddChatCompletions(); +app.AddEventEndpoint(); await app.RunAsync(); From c8947ea5aa3c5b4a04fe4a5c4b0aa40f2b3abec0 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Thu, 22 Aug 2024 16:54:30 +0900 Subject: [PATCH 03/26] Add comments and set class properties as nullable --- .../Endpoints/EventEndpoint.cs | 11 ++++++++++- .../Models/EventListEntity.cs | 16 ++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 6447bcd3..3cc0faec 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -6,11 +6,19 @@ namespace AzureOpenAIProxy.ApiApp.Endpoints { + /// + /// Defines an endpoint for events + /// public static class EventEndpoint { + /// + /// Adds EventEndpoint to WebApplication. + /// + /// + /// public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) { - // TODO: Authorization process with bearer token (JWT) with endpoint filter + // TODO: Parameter validation var rt = app.MapGet(EndpointUrls.Events, ( HttpRequest request @@ -36,6 +44,7 @@ HttpRequest request }; // TODO: Should add 404 logic if the server failed to retrieve data with TypedResult return TypedResults.Ok(sampleEvents); + // return TypedResults.Problem(statusCode: StatusCodes.Status404NotFound); }) // Note: RouteHandlerBuilder does not have ProducesProblem extension method yet, but it will be added on .NET 9 // Source: https://github.com/dotnet/aspnetcore/issues/56178 diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs index 28ed8bf1..e3f72329 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs @@ -12,13 +12,13 @@ public class EventListEntity /// Event Id /// [JsonPropertyName("eventId")] - public required string EventId { get; set; } + public required string? EventId { get; set; } /// /// Event name /// [JsonPropertyName("eventName")] - public required string EventName { get; set; } + public required string? EventName { get; set; } /// /// Event start time @@ -42,20 +42,20 @@ public class EventListEntity /// Organizer's name /// [JsonPropertyName("organizerName")] - public required string OrganizerName { get; set; } + public required string? OrganizerName { get; set; } /// /// Organizer's email address. /// [EmailAddress] [JsonPropertyName("OrganizerEmail")] - public required string OrganizerEmail { get; set; } + public required string? OrganizerEmail { get; set; } /// /// The number of registered users /// [JsonPropertyName("registered")] - public required int Registered { get; set; } + public required int? Registered { get; set; } /// /// List of resources that the organizer deploys @@ -67,7 +67,7 @@ public class EventListEntity /// Shows whether the event is active or not /// [JsonPropertyName("isActive")] - public required bool IsActive { get; set; } + public required bool? IsActive { get; set; } /// /// Define the list entity of Resources @@ -78,12 +78,12 @@ public class ResourceEntity /// Resource's Id /// [JsonPropertyName("id")] - public required string ResourceId {get; set; } + public required string? ResourceId {get; set; } /// /// Resource's name. e.g. gpt4o /// [JsonPropertyName("name")] - public required string ResourceName {get; set; } + public required string? ResourceName {get; set; } } } \ No newline at end of file From 70134ac81f7668fab76b30f9e355c613ffe64ed2 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 00:41:52 +0900 Subject: [PATCH 04/26] Add XML comment description support in Swagger --- src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj | 3 ++- .../Extensions/ServiceCollectionExtensions.cs | 5 ++++- src/AzureOpenAIProxy.ApiApp/Program.cs | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj b/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj index 4657650c..53da571b 100644 --- a/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj +++ b/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj @@ -4,7 +4,8 @@ net8.0 enable enable - + true + $(NoWarn);1591 AzureOpenAIProxy.ApiApp AzureOpenAIProxy.ApiApp diff --git a/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs b/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs index d39a1712..df5e39ba 100644 --- a/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs +++ b/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs @@ -1,4 +1,6 @@ -using AzureOpenAIProxy.ApiApp.Builders; +using System.Reflection; + +using AzureOpenAIProxy.ApiApp.Builders; using AzureOpenAIProxy.ApiApp.Configurations; using AzureOpenAIProxy.ApiApp.Filters; using AzureOpenAIProxy.ApiApp.Services; @@ -68,6 +70,7 @@ public static IServiceCollection AddOpenApiService(this IServiceCollection servi Url = new Uri("https://aka.ms/aoai-proxy.net") }, }; + options.IncludeXmlComments(Assembly.GetExecutingAssembly()); options.SwaggerDoc(Constants.Version, info); options.AddSecurityDefinition( diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 06e68066..383ff3a4 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -1,5 +1,9 @@ +using System.Reflection; + using AzureOpenAIProxy.ApiApp.Endpoints; using AzureOpenAIProxy.ApiApp.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); @@ -23,6 +27,7 @@ // Configure the HTTP request pipeline. // Use Swagger UI app.UseSwaggerUI(basePath); +app.UseSwagger(); // Enable buffering app.Use(async (context, next) => From 8e1e71a865cdfac0d2d928e15f2ad6a9d94ad5df Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 14:46:39 +0900 Subject: [PATCH 05/26] Remove duplicate configurations from ApiApp --- src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj b/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj index 09700974..92c1aae3 100644 --- a/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj +++ b/src/AzureOpenAIProxy.ApiApp/AzureOpenAIProxy.ApiApp.csproj @@ -1,11 +1,6 @@ - net8.0 - enable - enable - true - $(NoWarn);1591 AzureOpenAIProxy.ApiApp AzureOpenAIProxy.ApiApp From bf5c99956d66c8d6c70665487da8308074240086 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:14:43 +0900 Subject: [PATCH 06/26] Fix comments to standard in EventEndpoint --- src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 3cc0faec..0e1814ad 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -7,15 +7,15 @@ namespace AzureOpenAIProxy.ApiApp.Endpoints { /// - /// Defines an endpoint for events + /// This represents the endpoint entity for events. /// public static class EventEndpoint { /// - /// Adds EventEndpoint to WebApplication. + /// Adds the event endpoint. /// - /// - /// + /// instance. + /// Returns instance. public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) { // TODO: Parameter validation From 78927ac64a1822b121477a453d37e8448367bfe2 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:22:59 +0900 Subject: [PATCH 07/26] Remove HttpRequest from EventEndpoint handler parameter --- src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 0e1814ad..fcd9a29a 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -18,11 +18,7 @@ public static class EventEndpoint /// Returns instance. public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) { - // TODO: Parameter validation - var rt = app.MapGet(EndpointUrls.Events, - ( - HttpRequest request - ) => + var rt = app.MapGet(EndpointUrls.Events, () => { // These events are mock for now. var sampleEvents = new List From 2326d7ed84907c5d78946a7559165b39cdd678e0 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:26:34 +0900 Subject: [PATCH 08/26] Clean GET implementation in EventEndpoint --- .../Endpoints/EventEndpoint.cs | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index fcd9a29a..9a257653 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -20,30 +20,10 @@ public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) { var rt = app.MapGet(EndpointUrls.Events, () => { - // These events are mock for now. - var sampleEvents = new List - { - new EventListEntity { EventName = "Opening Hackathon", - EventId = Guid.NewGuid().ToString(), - StartTime = DateTimeOffset.Now, - EndTime = DateTimeOffset.Now.AddDays(1), - IsActive = true, - OrganizerName = "John Doe", - OrganizerEmail = "me@example.com", - TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Seoul").Id, - Registered = 10, - Resources = new List - { - new EventListEntity.ResourceEntity { ResourceId = "1", ResourceName = "gpt4o" } - } - } - }; - // TODO: Should add 404 logic if the server failed to retrieve data with TypedResult - return TypedResults.Ok(sampleEvents); - // return TypedResults.Problem(statusCode: StatusCodes.Status404NotFound); + // TODO: Implement logic of endpoints + // Need authorization + return Results.Ok(); }) - // Note: RouteHandlerBuilder does not have ProducesProblem extension method yet, but it will be added on .NET 9 - // Source: https://github.com/dotnet/aspnetcore/issues/56178 .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") .Produces(statusCode: StatusCodes.Status401Unauthorized, contentType: "application/problem+json") .Produces(statusCode: StatusCodes.Status404NotFound, contentType: "application/problem+json") From 86ed5ec77f6e2600a049f76f0ad05fc81c3ca5d2 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:31:09 +0900 Subject: [PATCH 09/26] Update OpenAPI response annotations on EventEndpoint handler --- src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 9a257653..19b067f2 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -25,9 +25,8 @@ public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) return Results.Ok(); }) .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") - .Produces(statusCode: StatusCodes.Status401Unauthorized, contentType: "application/problem+json") - .Produces(statusCode: StatusCodes.Status404NotFound, contentType: "application/problem+json") - .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "application/problem+json") + .Produces(statusCode: StatusCodes.Status401Unauthorized) + .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") .WithTags("events") .WithName("GetEvents") .WithOpenApi(operations => From 343db20a9b8876ef0d5914f1490c5d3f65b972db Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:32:58 +0900 Subject: [PATCH 10/26] Update OpenAPI description and summary of EventEndpoint This endpoint is for logged users --- .../Endpoints/EventEndpoint.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 19b067f2..cdbd2dcb 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -1,4 +1,5 @@ using System.Text.Json; + using AzureOpenAIProxy.ApiApp.Models; using Microsoft.AspNetCore.Http.HttpResults; @@ -7,7 +8,7 @@ namespace AzureOpenAIProxy.ApiApp.Endpoints { /// - /// This represents the endpoint entity for events. + /// This represents the endpoint entity for events that the logged user joined. /// public static class EventEndpoint { @@ -19,22 +20,22 @@ public static class EventEndpoint public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) { var rt = app.MapGet(EndpointUrls.Events, () => - { + { // TODO: Implement logic of endpoints // Need authorization return Results.Ok(); - }) - .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") + }) + .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") .Produces(statusCode: StatusCodes.Status401Unauthorized) .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") - .WithTags("events") - .WithName("GetEvents") - .WithOpenApi(operations => - { - operations.Description = "Show all events in Azure OpenAI Proxy services."; - operations.Summary = "Get all events"; - return operations; - }); + .WithTags("events") + .WithName("GetEvents") + .WithOpenApi(operations => + { + operations.Description = "Show all events in Azure OpenAI Proxy services that the logged user joined."; + operations.Summary = "Show the logged user's joined events."; + return operations; + }); return rt; } From 946c381ca2f6da92761a86ac045b70c35c7d5f4c Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:57:17 +0900 Subject: [PATCH 11/26] Rename EventListEntity to EventDetails --- .../Endpoints/EventEndpoint.cs | 2 +- .../Models/EventDetails.cs | 95 +++++++++++++++++++ .../Models/EventListEntity.cs | 89 ----------------- 3 files changed, 96 insertions(+), 90 deletions(-) create mode 100644 src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs delete mode 100644 src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index cdbd2dcb..c6c72703 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -25,7 +25,7 @@ public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) // Need authorization return Results.Ok(); }) - .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") + .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") .Produces(statusCode: StatusCodes.Status401Unauthorized) .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") .WithTags("events") diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs new file mode 100644 index 00000000..ed72a825 --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs @@ -0,0 +1,95 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +using AzureOpenAIProxy.ApiApp.Models; + +/// +/// This represents the event's detailed data for response by EventEndpoint. +/// +public class EventDetails +{ + /// + /// Gets or sets the event id. + /// + [JsonPropertyName("eventId")] + public required string? EventId { get; set; } + + /// + /// Gets or sets the event title. + /// + [JsonPropertyName("title")] + public required string? Title { get; set; } + + /// + /// Gets or sets the event summary. + /// + [JsonPropertyName("summary")] + public required string? Summary { get; set; } + + /// + /// Gets or sets the event description. + /// + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// + /// Gets or sets the event's start time. + /// + [JsonPropertyName("dateStart")] + public required DateTimeOffset? DateStart { get; set; } + + /// + /// Gets or sets the event's end time. + /// + [JsonPropertyName("dateEnd")] + public required DateTimeOffset? DateEnd { get; set; } + + /// + /// Gets or sets the event's time zone. + /// + [JsonPropertyName("tz")] + public required string? TimeZone { get; set; } + + /// + /// Gets or sets the event's active status. + /// + [JsonPropertyName("isActive")] + public required bool? IsActive { get; set; } + + /// + /// Gets or sets the organizer's name. + /// + [JsonPropertyName("organizerName")] + public required string? OrganizerName { get; set; } + + /// + /// Gets or sets the organizer's email address. + /// + [EmailAddress] + [JsonPropertyName("OrganizerEmail")] + public required string? OrganizerEmail { get; set; } + + /// + /// Gets or sets the co-organizer's name. + /// + [JsonPropertyName("CoorganizerName")] + public string? CoorganizerName { get; set; } + + /// + /// Gets or sets the co-organizer's email address. + /// + [JsonPropertyName("CoorganizerEmail")] + public string? CoorganizerEmail { get; set; } + + /// + /// Gets or sets the event's maximum token capacity. + /// + [JsonPropertyName("maxTokenCap")] + public required int? MaxTokenCap { get; set; } + + /// + /// Gets or sets the event's daily request capacity. + /// + [JsonPropertyName("dailyRequestCap")] + public required int? DailyRequestCap { get; set; } +} \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs deleted file mode 100644 index e3f72329..00000000 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventListEntity.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; - -using AzureOpenAIProxy.ApiApp.Models; - -/// -/// Data transfer model for showing all events -/// -public class EventListEntity -{ - /// - /// Event Id - /// - [JsonPropertyName("eventId")] - public required string? EventId { get; set; } - - /// - /// Event name - /// - [JsonPropertyName("eventName")] - public required string? EventName { get; set; } - - /// - /// Event start time - /// - [JsonPropertyName("startTime")] - public required DateTimeOffset? StartTime { get; set; } - - /// - /// Event end time - /// - [JsonPropertyName("endTime")] - public required DateTimeOffset? EndTime { get; set; } - - /// - /// Event's time zone. It could be serialized to string - /// - [JsonPropertyName("tz")] - public required string? TimeZone { get; set; } - - /// - /// Organizer's name - /// - [JsonPropertyName("organizerName")] - public required string? OrganizerName { get; set; } - - /// - /// Organizer's email address. - /// - [EmailAddress] - [JsonPropertyName("OrganizerEmail")] - public required string? OrganizerEmail { get; set; } - - /// - /// The number of registered users - /// - [JsonPropertyName("registered")] - public required int? Registered { get; set; } - - /// - /// List of resources that the organizer deploys - /// - [JsonPropertyName("resources")] - public virtual IEnumerable? Resources { get; set; } - - /// - /// Shows whether the event is active or not - /// - [JsonPropertyName("isActive")] - public required bool? IsActive { get; set; } - - /// - /// Define the list entity of Resources - /// - public class ResourceEntity - { - /// - /// Resource's Id - /// - [JsonPropertyName("id")] - public required string? ResourceId {get; set; } - - /// - /// Resource's name. e.g. gpt4o - /// - [JsonPropertyName("name")] - public required string? ResourceName {get; set; } - } -} \ No newline at end of file From 99616eb4a0ba50499d99a20fca1cba575835a09c Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:58:12 +0900 Subject: [PATCH 12/26] Remove redundant UseSwagger() --- src/AzureOpenAIProxy.ApiApp/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 7f9ee34e..afb3566b 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -30,7 +30,6 @@ // Configure the HTTP request pipeline. // Use Swagger UI app.UseSwaggerUI(basePath); -app.UseSwagger(); // Enable buffering app.Use(async (context, next) => From c03c5d17485ee88959d350e0bd5cd0f8b43cb972 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 15:58:50 +0900 Subject: [PATCH 13/26] Remove XML comment configuration for Swagger --- .../Extensions/ServiceCollectionExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs b/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs index ec5b1f27..c3d6ec78 100644 --- a/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs +++ b/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs @@ -103,7 +103,6 @@ public static IServiceCollection AddOpenApiService(this IServiceCollection servi Url = new Uri("https://aka.ms/aoai-proxy.net") }, }; - options.IncludeXmlComments(Assembly.GetExecutingAssembly()); options.SwaggerDoc(Constants.Version, info); options.AddSecurityDefinition( From fb3e867579ef53a03ef6e2bba6b221bd82d4fed8 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Fri, 23 Aug 2024 16:11:45 +0900 Subject: [PATCH 14/26] Fix Azure namespace problem in ServiceCollectionExtensions --- .../Extensions/ServiceCollectionExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs b/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs index c3d6ec78..c5ad44fe 100644 --- a/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs +++ b/src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using Azure.Identity; +using Azure.Security.KeyVault.Secrets; using AzureOpenAIProxy.ApiApp.Builders; using AzureOpenAIProxy.ApiApp.Configurations; @@ -131,4 +132,4 @@ public static IServiceCollection AddOpenApiService(this IServiceCollection servi return services; } -} +} \ No newline at end of file From 28764474fadce750ecee2298e5549c8d0dbecbf3 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 14:05:26 +0900 Subject: [PATCH 15/26] Rename AddEventEndpoint to AddEvents --- .../Endpoints/EventEndpoint.cs | 57 +++++++++---------- src/AzureOpenAIProxy.ApiApp/Program.cs | 4 +- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index c6c72703..7742d727 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -5,39 +5,38 @@ using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; -namespace AzureOpenAIProxy.ApiApp.Endpoints +namespace AzureOpenAIProxy.ApiApp.Endpoints; + +/// +/// This represents the endpoint entity for events that the logged user joined. +/// +public static class EventEndpoint { /// - /// This represents the endpoint entity for events that the logged user joined. + /// Adds the event endpoint. /// - public static class EventEndpoint + /// instance. + /// Returns instance. + public static RouteHandlerBuilder AddEvents(this WebApplication app) { - /// - /// Adds the event endpoint. - /// - /// instance. - /// Returns instance. - public static RouteHandlerBuilder AddEventEndpoint(this WebApplication app) + var builder = app.MapGet(EndpointUrls.Events, () => + { + // TODO: Issue #179 https://github.com/aliencube/azure-openai-sdk-proxy/issues/179 + return Results.Ok(); + }) + .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") + .Produces(statusCode: StatusCodes.Status401Unauthorized) + .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") + .WithTags("events") + .WithName("GetEvents") + .WithOpenApi(operation => { - var rt = app.MapGet(EndpointUrls.Events, () => - { - // TODO: Implement logic of endpoints - // Need authorization - return Results.Ok(); - }) - .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") - .Produces(statusCode: StatusCodes.Status401Unauthorized) - .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") - .WithTags("events") - .WithName("GetEvents") - .WithOpenApi(operations => - { - operations.Description = "Show all events in Azure OpenAI Proxy services that the logged user joined."; - operations.Summary = "Show the logged user's joined events."; - return operations; - }); + operation.Description = "Gets all events' details that the user joined."; + operation.Summary = "This endpoint gets all events' details that the user joined."; + + return operation; + }); - return rt; - } + return builder; } -} +} \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index afb3566b..22e28df3 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -42,7 +42,9 @@ app.AddWeatherForecast(); app.AddChatCompletions(); -app.AddEventEndpoint(); + +// Events Endpoints +app.AddEvents(); // Admin Endpoints app.AddAdminEvents(); From f598197c23147af7491ff35629ba0d02a4a8fedd Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 14:06:34 +0900 Subject: [PATCH 16/26] Remove JSON attributes from EventDetails --- .../Models/EventDetails.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs index ed72a825..36762ad5 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs @@ -11,85 +11,70 @@ public class EventDetails /// /// Gets or sets the event id. /// - [JsonPropertyName("eventId")] public required string? EventId { get; set; } /// /// Gets or sets the event title. /// - [JsonPropertyName("title")] public required string? Title { get; set; } /// /// Gets or sets the event summary. /// - [JsonPropertyName("summary")] public required string? Summary { get; set; } /// /// Gets or sets the event description. /// - [JsonPropertyName("description")] public string? Description { get; set; } /// /// Gets or sets the event's start time. /// - [JsonPropertyName("dateStart")] public required DateTimeOffset? DateStart { get; set; } /// /// Gets or sets the event's end time. /// - [JsonPropertyName("dateEnd")] public required DateTimeOffset? DateEnd { get; set; } /// /// Gets or sets the event's time zone. /// - [JsonPropertyName("tz")] public required string? TimeZone { get; set; } /// /// Gets or sets the event's active status. /// - [JsonPropertyName("isActive")] public required bool? IsActive { get; set; } /// /// Gets or sets the organizer's name. /// - [JsonPropertyName("organizerName")] public required string? OrganizerName { get; set; } /// /// Gets or sets the organizer's email address. /// - [EmailAddress] - [JsonPropertyName("OrganizerEmail")] public required string? OrganizerEmail { get; set; } /// /// Gets or sets the co-organizer's name. /// - [JsonPropertyName("CoorganizerName")] public string? CoorganizerName { get; set; } /// /// Gets or sets the co-organizer's email address. /// - [JsonPropertyName("CoorganizerEmail")] public string? CoorganizerEmail { get; set; } /// /// Gets or sets the event's maximum token capacity. /// - [JsonPropertyName("maxTokenCap")] public required int? MaxTokenCap { get; set; } /// /// Gets or sets the event's daily request capacity. /// - [JsonPropertyName("dailyRequestCap")] public required int? DailyRequestCap { get; set; } } \ No newline at end of file From f46d9963b1db8b326c868bee9e69f4218b6a3706 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 16:05:02 +0900 Subject: [PATCH 17/26] Remove redundant namespaces Remove unused using directives in EventEndpoint.cs, Program.cs Removed the following unused using directives: - In EventEndpoint.cs: - Microsoft.AspNetCore.Http.HttpResults - Microsoft.AspNetCore.Mvc - In Program.cs: - System.Reflection - Microsoft.Extensions.DependencyInjection - Microsoft.OpenApi.Models --- src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs | 3 --- src/AzureOpenAIProxy.ApiApp/Program.cs | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 7742d727..677cb238 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -2,9 +2,6 @@ using AzureOpenAIProxy.ApiApp.Models; -using Microsoft.AspNetCore.Http.HttpResults; -using Microsoft.AspNetCore.Mvc; - namespace AzureOpenAIProxy.ApiApp.Endpoints; /// diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 22e28df3..8f447d53 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -1,9 +1,5 @@ -using System.Reflection; - using AzureOpenAIProxy.ApiApp.Endpoints; using AzureOpenAIProxy.ApiApp.Extensions; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); From e4c985977af5f0d42bffd78008e420dd67dd0f1e Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 16:07:21 +0900 Subject: [PATCH 18/26] Refactor AdminEventDetails to inherit from EventDetails --- .../Models/AdminEventDetails.cs | 62 +------------------ .../Models/EventDetails.cs | 10 --- 2 files changed, 1 insertion(+), 71 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index 19a20eed..b9aeb14a 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -3,58 +3,8 @@ /// /// This represent the event detail data for response by admin event endpoint. /// -public class AdminEventDetails +public class AdminEventDetails : EventDetails { - /// - /// Gets or sets the event id. - /// - public required string? EventId { get; set; } - - /// - /// Gets or sets the event title name. - /// - public required string? Title { get; set; } - - /// - /// Gets or sets the event summary. - /// - public required string? Summary { get; set; } - - /// - /// Gets or sets the event description. - /// - public string? Description { get; set; } - - /// - /// Gets or sets the event start date. - /// - public required DateTimeOffset? DateStart { get; set; } - - /// - /// Gets or sets the event end date. - /// - public required DateTimeOffset? DateEnd { get; set; } - - /// - /// Gets or sets the event start to end date timezone. - /// - public required string? TimeZone { get; set; } - - /// - /// Gets or sets the event active status. - /// - public required bool? IsActive { get; set; } - - /// - /// Gets or sets the event organizer name. - /// - public required string? OrganizerName { get; set; } - - /// - /// Gets or sets the event organizer email. - /// - public required string? OrganizerEmail { get; set; } - /// /// Gets or sets the event coorganizer name. /// @@ -64,14 +14,4 @@ public class AdminEventDetails /// Gets or sets the event coorganizer email. /// public string? CoorganizerEmail { get; set; } - - /// - /// Gets or sets the Azure OpenAI Service request max token capacity. - /// - public required int? MaxTokenCap { get; set; } - - /// - /// Gets or sets the Azure OpenAI Service daily request capacity. - /// - public required int? DailyRequestCap { get; set; } } \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs index 36762ad5..31c43bb6 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs @@ -58,16 +58,6 @@ public class EventDetails /// public required string? OrganizerEmail { get; set; } - /// - /// Gets or sets the co-organizer's name. - /// - public string? CoorganizerName { get; set; } - - /// - /// Gets or sets the co-organizer's email address. - /// - public string? CoorganizerEmail { get; set; } - /// /// Gets or sets the event's maximum token capacity. /// From dc5ef5120ca099390c8f434b6c55452709be9d76 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 16:42:59 +0900 Subject: [PATCH 19/26] Move less important properties from EventDetails to AdminEventDetails --- .../Models/AdminEventDetails.cs | 35 +++++++++++++++++++ .../Models/EventDetails.cs | 35 ------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index b9aeb14a..e78a4af4 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -14,4 +14,39 @@ public class AdminEventDetails : EventDetails /// Gets or sets the event coorganizer email. /// public string? CoorganizerEmail { get; set; } + + /// + /// Gets or sets the event description. + /// + public string? Description { get; set; } + + /// + /// Gets or sets the event's start time. + /// + public required DateTimeOffset? DateStart { get; set; } + + /// + /// Gets or sets the event's end time. + /// + public required DateTimeOffset? DateEnd { get; set; } + + /// + /// Gets or sets the event's time zone. + /// + public required string? TimeZone { get; set; } + + /// + /// Gets or sets the event's active status. + /// + public required bool? IsActive { get; set; } + + /// + /// Gets or sets the organizer's name. + /// + public required string? OrganizerName { get; set; } + + /// + /// Gets or sets the organizer's email address. + /// + public required string? OrganizerEmail { get; set; } } \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs index 31c43bb6..997065a0 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs @@ -23,41 +23,6 @@ public class EventDetails /// public required string? Summary { get; set; } - /// - /// Gets or sets the event description. - /// - public string? Description { get; set; } - - /// - /// Gets or sets the event's start time. - /// - public required DateTimeOffset? DateStart { get; set; } - - /// - /// Gets or sets the event's end time. - /// - public required DateTimeOffset? DateEnd { get; set; } - - /// - /// Gets or sets the event's time zone. - /// - public required string? TimeZone { get; set; } - - /// - /// Gets or sets the event's active status. - /// - public required bool? IsActive { get; set; } - - /// - /// Gets or sets the organizer's name. - /// - public required string? OrganizerName { get; set; } - - /// - /// Gets or sets the organizer's email address. - /// - public required string? OrganizerEmail { get; set; } - /// /// Gets or sets the event's maximum token capacity. /// From 49225413ecc02a0ad09f8a123bb0e11c893e97bd Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 17:00:00 +0900 Subject: [PATCH 20/26] Change to AddEventList() in EventEndpoint --- src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs | 2 +- src/AzureOpenAIProxy.ApiApp/Program.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index 677cb238..e8533f88 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -14,7 +14,7 @@ public static class EventEndpoint /// /// instance. /// Returns instance. - public static RouteHandlerBuilder AddEvents(this WebApplication app) + public static RouteHandlerBuilder AddEventList(this WebApplication app) { var builder = app.MapGet(EndpointUrls.Events, () => { diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 36e6c86f..9e7da34b 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -40,7 +40,7 @@ app.AddChatCompletions(); // Event Endpoints -app.AddEvents(); +app.AddEventList(); // Admin Endpoints app.AddAdminEvents(); From 3ef176ab01b7f53e04729c598bc8718c7000ae56 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 17:02:58 +0900 Subject: [PATCH 21/26] Rearrange AdminEventDetails --- .../Models/AdminEventDetails.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index e78a4af4..bdfb1b9f 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -5,16 +5,6 @@ /// public class AdminEventDetails : EventDetails { - /// - /// Gets or sets the event coorganizer name. - /// - public string? CoorganizerName { get; set; } - - /// - /// Gets or sets the event coorganizer email. - /// - public string? CoorganizerEmail { get; set; } - /// /// Gets or sets the event description. /// @@ -49,4 +39,14 @@ public class AdminEventDetails : EventDetails /// Gets or sets the organizer's email address. /// public required string? OrganizerEmail { get; set; } + + /// + /// Gets or sets the event coorganizer name. + /// + public string? CoorganizerName { get; set; } + + /// + /// Gets or sets the event coorganizer email. + /// + public string? CoorganizerEmail { get; set; } } \ No newline at end of file From 00d1401253baa4664f5c60ee4b5e0eccf620beb4 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 17:32:08 +0900 Subject: [PATCH 22/26] Revert property comments --- .../Models/AdminEventDetails.cs | 12 ++++++------ src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index bdfb1b9f..4f587217 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -11,32 +11,32 @@ public class AdminEventDetails : EventDetails public string? Description { get; set; } /// - /// Gets or sets the event's start time. + /// Gets or sets the event start date. /// public required DateTimeOffset? DateStart { get; set; } /// - /// Gets or sets the event's end time. + /// Gets or sets the event end date. /// public required DateTimeOffset? DateEnd { get; set; } /// - /// Gets or sets the event's time zone. + /// Gets or sets the event start to end date timezone. /// public required string? TimeZone { get; set; } /// - /// Gets or sets the event's active status. + /// Gets or sets the event active status. /// public required bool? IsActive { get; set; } /// - /// Gets or sets the organizer's name. + /// Gets or sets the event organizer name. /// public required string? OrganizerName { get; set; } /// - /// Gets or sets the organizer's email address. + /// Gets or sets the event organizer email. /// public required string? OrganizerEmail { get; set; } diff --git a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs index 997065a0..5c33fafb 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/EventDetails.cs @@ -14,7 +14,7 @@ public class EventDetails public required string? EventId { get; set; } /// - /// Gets or sets the event title. + /// Gets or sets the event title name. /// public required string? Title { get; set; } @@ -24,12 +24,12 @@ public class EventDetails public required string? Summary { get; set; } /// - /// Gets or sets the event's maximum token capacity. + /// Gets or sets the Azure OpenAI Service request max token capacity. /// public required int? MaxTokenCap { get; set; } /// - /// Gets or sets the event's daily request capacity. + /// Gets or sets the Azure OpenAI Service daily request capacity. /// public required int? DailyRequestCap { get; set; } } \ No newline at end of file From 3509aa7593b93d318aadeb20bcfa94c27b0d744d Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 17:33:27 +0900 Subject: [PATCH 23/26] Update OpenAPI metadata for AddEventList --- src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs index e8533f88..a82efb31 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EventEndpoint.cs @@ -21,7 +21,7 @@ public static RouteHandlerBuilder AddEventList(this WebApplication app) // TODO: Issue #179 https://github.com/aliencube/azure-openai-sdk-proxy/issues/179 return Results.Ok(); }) - .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") + .Produces>(statusCode: StatusCodes.Status200OK, contentType: "application/json") .Produces(statusCode: StatusCodes.Status401Unauthorized) .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") .WithTags("events") From 9cf17484122c4c135b2d0deba1e1ac1d66106434 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sat, 24 Aug 2024 17:33:50 +0900 Subject: [PATCH 24/26] Add events OpenAPI tag --- src/AzureOpenAIProxy.ApiApp/Filters/OpenApiTagFilter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Filters/OpenApiTagFilter.cs b/src/AzureOpenAIProxy.ApiApp/Filters/OpenApiTagFilter.cs index 196c87fb..9ed10fa3 100644 --- a/src/AzureOpenAIProxy.ApiApp/Filters/OpenApiTagFilter.cs +++ b/src/AzureOpenAIProxy.ApiApp/Filters/OpenApiTagFilter.cs @@ -16,7 +16,8 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) [ new OpenApiTag { Name = "weather", Description = "Weather forecast operations" }, new OpenApiTag { Name = "openai", Description = "Azure OpenAI operations" }, - new OpenApiTag { Name = "admin", Description = "Admin for organizing events" } + new OpenApiTag { Name = "admin", Description = "Admin for organizing events" }, + new OpenApiTag { Name = "events", Description = "User events" } ]; } } From 0baa71682020a23556f910d2fb81be36cf8cf952 Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sun, 25 Aug 2024 13:54:52 +0900 Subject: [PATCH 25/26] Add 4 tests for EventEndpoint in GetEventsOpenApiTests.cs --- .../ApiApp/Endpoints/GetEventsOpenApiTests.cs | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs new file mode 100644 index 00000000..1e108ea4 --- /dev/null +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs @@ -0,0 +1,82 @@ +using System.Text.Json; + +using AzureOpenAIProxy.AppHost.Tests.Fixtures; + +using FluentAssertions; + +using IdentityModel.Client; + +namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; + +public class GetEventsOpenApiTests(AspireAppHostFixture host) : IClassFixture +{ + [Fact] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .TryGetProperty("/events", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Fact] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Verb() + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/events") + .TryGetProperty("get", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Theory] + [InlineData("events")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tags(string tag) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/events") + .GetProperty("get") + .TryGetProperty("tags", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Array); + result.EnumerateArray().Select(p => p.GetString()).Should().Contain(tag); + } + + [Theory] + [InlineData("summary")] + [InlineData("operationId")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Value(string attribute) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert = + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/events") + .GetProperty("get") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.String); + } +} \ No newline at end of file From 4a421511616d675327c133f9a86f25e475838a2b Mon Sep 17 00:00:00 2001 From: Capella87 Date: Sun, 25 Aug 2024 15:08:44 +0900 Subject: [PATCH 26/26] Add object, response tests in GetEventsOpenApiTests.cs --- .../ApiApp/Endpoints/GetEventsOpenApiTests.cs | 80 ++++++++++++++----- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs index 1e108ea4..8aad2350 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/GetEventsOpenApiTests.cs @@ -15,12 +15,14 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Pat { // Arrange using var httpClient = host.App!.CreateHttpClient("apiapp"); + // Act var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); - var openapi = JsonSerializer.Deserialize(json); + var apiDocument = JsonSerializer.Deserialize(json); + // Assert - var result = openapi!.RootElement.GetProperty("paths") - .TryGetProperty("/events", out var property) ? property : default; + var result = apiDocument!.RootElement.GetProperty("paths") + .TryGetProperty("/events", out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.Object); } @@ -29,14 +31,15 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Ver { // Arrange using var httpClient = host.App!.CreateHttpClient("apiapp"); + // Act var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); - var openapi = JsonSerializer.Deserialize(json); + var apiDocument = JsonSerializer.Deserialize(json); // Assert - var result = openapi!.RootElement.GetProperty("paths") - .GetProperty("/events") - .TryGetProperty("get", out var property) ? property : default; + var result = apiDocument!.RootElement.GetProperty("paths") + .GetProperty("/events") + .TryGetProperty("get", out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.Object); } @@ -49,13 +52,13 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tag // Act var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); - var openapi = JsonSerializer.Deserialize(json); + var apiDocument = JsonSerializer.Deserialize(json); // Assert - var result = openapi!.RootElement.GetProperty("paths") - .GetProperty("/events") - .GetProperty("get") - .TryGetProperty("tags", out var property) ? property : default; + var result = apiDocument!.RootElement.GetProperty("paths") + .GetProperty("/events") + .GetProperty("get") + .TryGetProperty("tags", out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.Array); result.EnumerateArray().Select(p => p.GetString()).Should().Contain(tag); } @@ -70,13 +73,54 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Val // Act var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); - var openapi = JsonSerializer.Deserialize(json); + var apiDocument = JsonSerializer.Deserialize(json); - // Assert = - var result = openapi!.RootElement.GetProperty("paths") - .GetProperty("/events") - .GetProperty("get") - .TryGetProperty(attribute, out var property) ? property : default; + // Assert + var result = apiDocument!.RootElement.GetProperty("paths") + .GetProperty("/events") + .GetProperty("get") + .TryGetProperty(attribute, out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.String); } + + [Theory] + [InlineData("responses")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Object(string attribute) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var apiDocument = JsonSerializer.Deserialize(json); + + // Assert + var result = apiDocument!.RootElement.GetProperty("paths") + .GetProperty("/events") + .GetProperty("get") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Theory] + [InlineData("200")] + [InlineData("401")] + [InlineData("500")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response(string attribute) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var apiDocument = JsonSerializer.Deserialize(json); + + // Assert + var result = apiDocument!.RootElement.GetProperty("paths") + .GetProperty("/events") + .GetProperty("get") + .GetProperty("responses") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } } \ No newline at end of file