Skip to content

Commit bbef6f1

Browse files
authored
[Admin] Add admin event service layer (#286)
1 parent 25e9630 commit bbef6f1

File tree

7 files changed

+223
-19
lines changed

7 files changed

+223
-19
lines changed

src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs

+28-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using AzureOpenAIProxy.ApiApp.Models;
2+
using AzureOpenAIProxy.ApiApp.Services;
23

34
using Microsoft.AspNetCore.Mvc;
45

@@ -18,14 +19,38 @@ public static RouteHandlerBuilder AddNewAdminEvent(this WebApplication app)
1819
{
1920
var builder = app.MapPost(AdminEndpointUrls.AdminEvents, async (
2021
[FromBody] AdminEventDetails payload,
21-
HttpRequest request) =>
22+
IAdminEventService service,
23+
ILoggerFactory loggerFactory) =>
2224
{
25+
var logger = loggerFactory.CreateLogger(nameof(AdminEventEndpoints));
26+
logger.LogInformation("Received a new event request");
27+
28+
if (payload is null)
29+
{
30+
logger.LogError("No payload found");
31+
32+
return Results.BadRequest("Payload is null");
33+
}
34+
35+
//try
36+
//{
37+
// var result = await service.CreateEvent(payload);
38+
39+
// logger.LogInformation("Created a new event");
40+
41+
// return Results.Ok(result);
42+
//}
43+
//catch (Exception ex)
44+
//{
45+
// logger.LogError(ex, "Failed to create a new event");
46+
47+
// return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
48+
//}
49+
2350
return await Task.FromResult(Results.Ok());
2451
})
25-
// TODO: Check both request/response payloads
2652
.Accepts<AdminEventDetails>(contentType: "application/json")
2753
.Produces<AdminEventDetails>(statusCode: StatusCodes.Status200OK, contentType: "application/json")
28-
// TODO: Check both request/response payloads
2954
.Produces(statusCode: StatusCodes.Status400BadRequest)
3055
.Produces(statusCode: StatusCodes.Status401Unauthorized)
3156
.Produces<string>(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain")

src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace AzureOpenAIProxy.ApiApp.Models;
1+
using System.Text.Json.Serialization;
2+
3+
namespace AzureOpenAIProxy.ApiApp.Models;
24

35
/// <summary>
46
/// This represent the event detail data for response by admin event endpoint.
@@ -13,32 +15,38 @@ public class AdminEventDetails : EventDetails
1315
/// <summary>
1416
/// Gets or sets the event start date.
1517
/// </summary>
16-
public required DateTimeOffset? DateStart { get; set; }
18+
[JsonRequired]
19+
public DateTimeOffset DateStart { get; set; }
1720

1821
/// <summary>
1922
/// Gets or sets the event end date.
2023
/// </summary>
21-
public required DateTimeOffset? DateEnd { get; set; }
24+
[JsonRequired]
25+
public DateTimeOffset DateEnd { get; set; }
2226

2327
/// <summary>
2428
/// Gets or sets the event start to end date timezone.
2529
/// </summary>
26-
public required string? TimeZone { get; set; }
30+
[JsonRequired]
31+
public string TimeZone { get; set; } = string.Empty;
2732

2833
/// <summary>
2934
/// Gets or sets the event active status.
3035
/// </summary>
31-
public required bool? IsActive { get; set; }
36+
[JsonRequired]
37+
public bool IsActive { get; set; }
3238

3339
/// <summary>
3440
/// Gets or sets the event organizer name.
3541
/// </summary>
36-
public required string? OrganizerName { get; set; }
42+
[JsonRequired]
43+
public string OrganizerName { get; set; } = string.Empty;
3744

3845
/// <summary>
3946
/// Gets or sets the event organizer email.
4047
/// </summary>
41-
public required string? OrganizerEmail { get; set; }
48+
[JsonRequired]
49+
public string OrganizerEmail { get; set; } = string.Empty;
4250

4351
/// <summary>
4452
/// Gets or sets the event coorganizer name.
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
using System.ComponentModel.DataAnnotations;
21
using System.Text.Json.Serialization;
32

4-
using AzureOpenAIProxy.ApiApp.Models;
5-
63
/// <summary>
74
/// This represents the event's detailed data for response by EventEndpoint.
85
/// </summary>
@@ -11,25 +8,30 @@ public class EventDetails
118
/// <summary>
129
/// Gets or sets the event id.
1310
/// </summary>
14-
public required string? EventId { get; set; }
11+
[JsonRequired]
12+
public Guid EventId { get; set; }
1513

1614
/// <summary>
1715
/// Gets or sets the event title name.
1816
/// </summary>
19-
public required string? Title { get; set; }
17+
[JsonRequired]
18+
public string Title { get; set; } = string.Empty;
2019

2120
/// <summary>
2221
/// Gets or sets the event summary.
2322
/// </summary>
24-
public required string? Summary { get; set; }
23+
[JsonRequired]
24+
public string Summary { get; set; } = string.Empty;
2525

2626
/// <summary>
2727
/// Gets or sets the Azure OpenAI Service request max token capacity.
2828
/// </summary>
29-
public required int? MaxTokenCap { get; set; }
29+
[JsonRequired]
30+
public int MaxTokenCap { get; set; }
3031

3132
/// <summary>
3233
/// Gets or sets the Azure OpenAI Service daily request capacity.
3334
/// </summary>
34-
public required int? DailyRequestCap { get; set; }
35+
[JsonRequired]
36+
public int DailyRequestCap { get; set; }
3537
}

src/AzureOpenAIProxy.ApiApp/Program.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using AzureOpenAIProxy.ApiApp.Endpoints;
22
using AzureOpenAIProxy.ApiApp.Extensions;
3+
using AzureOpenAIProxy.ApiApp.Services;
34

45
var builder = WebApplication.CreateBuilder(args);
56

@@ -14,6 +15,9 @@
1415
// Add OpenAPI service
1516
builder.Services.AddOpenApiService();
1617

18+
// Add admin services
19+
builder.Services.AddAdminEventService();
20+
1721
var app = builder.Build();
1822

1923
app.MapDefaultEndpoints();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using AzureOpenAIProxy.ApiApp.Models;
2+
3+
namespace AzureOpenAIProxy.ApiApp.Services;
4+
5+
/// <summary>
6+
/// This provides interfaces to <see cref="AdminEventService"/> class.
7+
/// </summary>
8+
public interface IAdminEventService
9+
{
10+
/// <summary>
11+
/// Creates a new event.
12+
/// </summary>
13+
/// <param name="eventDetails">Event payload.</param>
14+
/// <returns>Returns the event payload created.</returns>
15+
Task<AdminEventDetails> CreateEvent(AdminEventDetails eventDetails);
16+
17+
/// <summary>
18+
/// Gets the list of events.
19+
/// </summary>
20+
/// <returns>Returns the list of events.</returns>
21+
Task<List<AdminEventDetails>> GetEvents();
22+
23+
/// <summary>
24+
/// Gets the event details.
25+
/// </summary>
26+
/// <param name="eventId">Event ID.</param>
27+
/// <returns>Returns the event details.</returns>
28+
Task<AdminEventDetails> GetEvent(Guid eventId);
29+
30+
/// <summary>
31+
/// Updates the event details.
32+
/// </summary>
33+
/// <param name="eventId">Event ID.</param>
34+
/// <param name="eventDetails">Event details to update.</param>
35+
/// <returns>Returns the updated event details.</returns>
36+
Task<AdminEventDetails> UpdateEvent(Guid eventId, AdminEventDetails eventDetails);
37+
}
38+
39+
/// <summary>
40+
/// This represents the service entity for admin event.
41+
/// </summary>
42+
public class AdminEventService : IAdminEventService
43+
{
44+
/// <inheritdoc />
45+
public async Task<AdminEventDetails> CreateEvent(AdminEventDetails eventDetails)
46+
{
47+
throw new NotImplementedException();
48+
}
49+
50+
/// <inheritdoc />
51+
public async Task<List<AdminEventDetails>> GetEvents()
52+
{
53+
throw new NotImplementedException();
54+
}
55+
56+
/// <inheritdoc />
57+
public async Task<AdminEventDetails> GetEvent(Guid eventId)
58+
{
59+
throw new NotImplementedException();
60+
}
61+
62+
/// <inheritdoc />
63+
public async Task<AdminEventDetails> UpdateEvent(Guid eventId, AdminEventDetails eventDetails)
64+
{
65+
throw new NotImplementedException();
66+
}
67+
}
68+
69+
/// <summary>
70+
/// This represents the extension class for <see cref="IServiceCollection"/>
71+
/// </summary>
72+
public static class AdminEventServiceExtensions
73+
{
74+
/// <summary>
75+
/// Adds the <see cref="AdminEventService"/> instance to the service collection.
76+
/// </summary>
77+
/// <param name="services"><see cref="IServiceCollection"/> instance.</param>
78+
/// <returns>Returns <see cref="IServiceCollection"/> instance.</returns>
79+
public static IServiceCollection AddAdminEventService(this IServiceCollection services)
80+
{
81+
services.AddScoped<IAdminEventService, AdminEventService>();
82+
83+
return services;
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using AzureOpenAIProxy.ApiApp.Models;
2+
using AzureOpenAIProxy.ApiApp.Services;
3+
4+
using FluentAssertions;
5+
6+
using Microsoft.Extensions.DependencyInjection;
7+
8+
namespace AzureOpenAIProxy.ApiApp.Tests.Services;
9+
10+
public class AdminEventServiceTests
11+
{
12+
[Fact]
13+
public void Given_ServiceCollection_When_AddAdminEventService_Invoked_Then_It_Should_Contain_AdminEventService()
14+
{
15+
// Arrange
16+
var services = new ServiceCollection();
17+
18+
// Act
19+
services.AddAdminEventService();
20+
21+
// Assert
22+
services.SingleOrDefault(p => p.ServiceType == typeof(IAdminEventService)).Should().NotBeNull();
23+
}
24+
25+
[Fact]
26+
public void Given_Instance_When_CreateEvent_Invoked_Then_It_Should_Throw_Exception()
27+
{
28+
// Arrange
29+
var eventDetails = new AdminEventDetails();
30+
var service = new AdminEventService();
31+
32+
// Act
33+
Func<Task> func = async () => await service.CreateEvent(eventDetails);
34+
35+
// Assert
36+
func.Should().ThrowAsync<NotImplementedException>();
37+
}
38+
39+
[Fact]
40+
public void Given_Instance_When_GetEvents_Invoked_Then_It_Should_Throw_Exception()
41+
{
42+
// Arrange
43+
var service = new AdminEventService();
44+
45+
// Act
46+
Func<Task> func = async () => await service.GetEvents();
47+
48+
// Assert
49+
func.Should().ThrowAsync<NotImplementedException>();
50+
}
51+
52+
[Fact]
53+
public void Given_Instance_When_GetEvent_Invoked_Then_It_Should_Throw_Exception()
54+
{
55+
// Arrange
56+
var eventId = Guid.NewGuid();
57+
var service = new AdminEventService();
58+
59+
// Act
60+
Func<Task> func = async () => await service.GetEvent(eventId);
61+
62+
// Assert
63+
func.Should().ThrowAsync<NotImplementedException>();
64+
}
65+
66+
[Fact]
67+
public void Given_Instance_When_UpdateEvent_Invoked_Then_It_Should_Throw_Exception()
68+
{
69+
// Arrange
70+
var eventId = Guid.NewGuid();
71+
var eventDetails = new AdminEventDetails();
72+
var service = new AdminEventService();
73+
74+
// Act
75+
Func<Task> func = async () => await service.UpdateEvent(eventId, eventDetails);
76+
77+
// Assert
78+
func.Should().ThrowAsync<NotImplementedException>();
79+
}
80+
}

test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
using FluentAssertions;
66

7-
namespace AzureOpenAIProxy.Tests;
7+
namespace AzureOpenAIProxy.AppHost.Tests;
88

99
public class AppHostProgramTests(AspireAppHostFixture host) : IClassFixture<AspireAppHostFixture>
1010
{

0 commit comments

Comments
 (0)