diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 828f1cf..06377de 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -35,7 +35,4 @@ jobs: MQTT_CLIENT_ID: ${{ secrets.MQTT_CLIENT_ID }} MQTT_SUBSCRIBE_TOPIC: ${{ secrets.MQTT_SUBSCRIBE_TOPIC }} MQTT_PUBLISH_TOPIC: ${{ secrets.MQTT_PUBLISH_TOPIC }} - - AZURE_VISION_KEY: ${{ secrets.AZURE_VISION_KEY }} - AZURE_VISION_ENDPOINT: ${{ secrets.AZURE_VISION_ENDPOINT }} run: cd Tests && dotnet test \ No newline at end of file diff --git a/Infrastructure/Repositories/CollectionsRepository.cs b/Infrastructure/Repositories/CollectionsRepository.cs index bdac8c3..f434f85 100644 --- a/Infrastructure/Repositories/CollectionsRepository.cs +++ b/Infrastructure/Repositories/CollectionsRepository.cs @@ -67,11 +67,4 @@ public async Task RemovePlantFromCollection(Collection collection, Plant plant) collection.Plants.Remove(plant); await applicationDbContext.SaveChangesAsync(); } - - public async Task GetTotalCollectionsCount(string email) - { - await using var applicationDbContext = await dbContextFactory.CreateDbContextAsync(); - return await applicationDbContext.Collections - .CountAsync(collection => collection.UserEmail == email); - } } \ No newline at end of file diff --git a/Infrastructure/Repositories/PlantRepository.cs b/Infrastructure/Repositories/PlantRepository.cs index 3f21e69..0727ce1 100644 --- a/Infrastructure/Repositories/PlantRepository.cs +++ b/Infrastructure/Repositories/PlantRepository.cs @@ -114,20 +114,21 @@ public async Task> GetCriticalPlants(string requesterEmail) .Select(p => p.Plant) .ToListAsync(); } - - public async Task GetHappyPlantsCount(string userEmail) + public async Task GetStats(string userEmail) { await using var context = await dbContextFactory.CreateDbContextAsync(); - return await context.Plants + var totalPlants = await context.Plants.CountAsync(p => p.UserEmail == userEmail); + var happyPlants = await context.Plants .Include(plant => plant.ConditionsLogs) .Where(p => p.UserEmail == userEmail && p.ConditionsLogs.Count != 0) .CountAsync(p => p.ConditionsLogs.OrderByDescending(log => log.TimeStamp).FirstOrDefault()!.Mood > 2); - } + var collections = await context.Collections.CountAsync(c => c.UserEmail == userEmail); - public async Task GetTotalPlantsCount(string userEmail) - { - await using var context = await dbContextFactory.CreateDbContextAsync(); - return await context.Plants - .CountAsync(p => p.UserEmail == userEmail); + return new Stats + { + TotalPlants = totalPlants, + HappyPlants = happyPlants, + Collections = collections + }; } } \ No newline at end of file diff --git a/Shared/Models/Stats.cs b/Shared/Models/Stats.cs new file mode 100644 index 0000000..163c91b --- /dev/null +++ b/Shared/Models/Stats.cs @@ -0,0 +1,8 @@ +namespace Shared.Models; + +public class Stats +{ + public int TotalPlants { get; set; } + public int HappyPlants { get; set; } + public int Collections { get; set; } +} \ No newline at end of file diff --git a/Tests/PlantTests.cs b/Tests/PlantTests.cs index 88de0fb..5de8a3e 100644 --- a/Tests/PlantTests.cs +++ b/Tests/PlantTests.cs @@ -1,4 +1,3 @@ -using api.Events.Collections.Server; using api.Events.PlantEvents.Client; using api.Events.PlantEvents.Server; using lib; @@ -15,8 +14,7 @@ public async Task CreatePlant() { var jwtAndEmail = await SignUpAndLogIn(); var jwt = jwtAndEmail[DictionaryKeys.Jwt]; - var email = jwtAndEmail[DictionaryKeys.Email]; - var createPlantDto = GenerateRandomCreatePlantDto(email); + var createPlantDto = GenerateRandomCreatePlantDto(); var webSocketTestClient = await new WebSocketTestClient().ConnectAsync(); @@ -24,7 +22,16 @@ await webSocketTestClient.DoAndAssert(new ClientWantsToCreatePlantDto { CreatePl { return receivedMessages.Count(e => e.eventType == nameof(ServerSavesPlant)) == 1; }); - + } + + [Test] + public async Task GetAllPlants() + { + var jwtAndEmail = await SignUpAndLogIn(); + var jwt = jwtAndEmail[DictionaryKeys.Jwt]; + + var webSocketTestClient = await new WebSocketTestClient().ConnectAsync(); + await webSocketTestClient.DoAndAssert(new ClientWantsAllPlantsDto { Jwt = jwt, @@ -36,7 +43,7 @@ await webSocketTestClient.DoAndAssert(new ClientWantsAllPlantsDto }); } - private CreatePlantDto GenerateRandomCreatePlantDto(string email) + private CreatePlantDto GenerateRandomCreatePlantDto() { var createPlantDto = new CreatePlantDto { diff --git a/Tests/TestBase.cs b/Tests/TestBase.cs index 9260a42..a0e31da 100644 --- a/Tests/TestBase.cs +++ b/Tests/TestBase.cs @@ -35,8 +35,10 @@ await webSocketTestClient.DoAndAssert(new ClientWantsToSignUpDto { RegisterUserD var jwtSubscription = webSocketTestClient.Client.MessageReceived.Subscribe(msg => { + var eventType = JsonSerializer.Deserialize(msg.Text).eventType; + if (eventType != nameof(ServerAuthenticatesUser)) return; var serverAuthenticates = JsonSerializer.Deserialize(msg.Text, options: new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); - jwt = serverAuthenticates.Jwt; + jwt = serverAuthenticates!.Jwt; }); webSocketTestClient.Send(new ClientWantsToLogInDto { LoginDto = loginDto }); diff --git a/Tests/WebSocketTestClient.cs b/Tests/WebSocketTestClient.cs new file mode 100644 index 0000000..4e863d1 --- /dev/null +++ b/Tests/WebSocketTestClient.cs @@ -0,0 +1,69 @@ +using System.Text.Json; +using api.Events.Global; +using lib; +using Websocket.Client; + +namespace Tests +{ + public class WebSocketTestClient + { + public readonly WebsocketClient Client; + public readonly List ReceivedMessages = []; + private static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + PropertyNameCaseInsensitive = true + }; + + public WebSocketTestClient(string? url = null) + { + Client = url == null ? new WebsocketClient(new Uri("ws://localhost:" + (Environment.GetEnvironmentVariable("FULLSTACK_API_PORT") ?? "8181"))) : new WebsocketClient(new Uri(url)); + Client.MessageReceived.Subscribe(msg => + { + BaseDto baseDto = JsonSerializer.Deserialize(msg.Text, JsonSerializerOptions); + + if (baseDto.eventType == "ServerSendsErrorMessage" || baseDto.eventType.Contains("ServerResponds") || + baseDto.eventType.Contains("ServerRejects")) + { + var error = JsonSerializer.Deserialize(msg.Text, JsonSerializerOptions); + Console.WriteLine("Error: " + error!.Error); + } + + lock (ReceivedMessages) + ReceivedMessages.Add(baseDto); + }); + } + + public async Task ConnectAsync() + { + await Client.Start(); + if (!Client.IsRunning) + throw new Exception("Could not start client!"); + return this; + } + + public void Send(T dto) where T : BaseDto + { + Client.Send(JsonSerializer.Serialize(dto)); + } + + public async Task DoAndAssert(T? action = null, Func, bool>? condition = null) where T : BaseDto + { + if ((object) (T) action != null) + Send(action); + if (condition != null) + { + DateTime startTime = DateTime.UtcNow; + while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(5.0)) + { + lock (ReceivedMessages) + { + if (condition(ReceivedMessages)) + return; + } + await Task.Delay(100); + } + throw new TimeoutException("Condition not met: "); + } + } + } +} \ No newline at end of file diff --git a/api/Core/Services/CollectionsService.cs b/api/Core/Services/CollectionsService.cs index 7ac6a66..eb4a888 100644 --- a/api/Core/Services/CollectionsService.cs +++ b/api/Core/Services/CollectionsService.cs @@ -74,9 +74,4 @@ private async Task VerifyCollectionExistsAndUserHasAccess(Guid colle if (collection.UserEmail != loggedInUser) throw new NoAccessException("You don't have access to this collection"); return collection; } - - public async Task GetTotalCollectionsCount(string email) - { - return await collectionsRepository.GetTotalCollectionsCount(email); - } } \ No newline at end of file diff --git a/api/Core/Services/PlantService.cs b/api/Core/Services/PlantService.cs index 5a271d7..3922459 100644 --- a/api/Core/Services/PlantService.cs +++ b/api/Core/Services/PlantService.cs @@ -134,16 +134,6 @@ public async Task> GetCriticalPlants(string requesterE return criticalPlants; } - - public async Task GetHappyPlantsCount(string userEmail) - { - return await plantRepository.GetHappyPlantsCount(userEmail); - } - - public async Task GetTotalPlantsCount(string userEmail) - { - return await plantRepository.GetTotalPlantsCount(userEmail); - } private string GenerateRandomNickname() { diff --git a/api/Core/Services/StatsService.cs b/api/Core/Services/StatsService.cs new file mode 100644 index 0000000..3722478 --- /dev/null +++ b/api/Core/Services/StatsService.cs @@ -0,0 +1,13 @@ +using Infrastructure.Repositories; +using Shared.Dtos; +using Shared.Models; + +namespace api.Core.Services; + +public class StatsService(PlantRepository plantRepository) +{ + public async Task GetStats(string email) + { + return await plantRepository.GetStats(email); + } +} diff --git a/api/EnvironmentHelper.cs b/api/EnvironmentHelper.cs new file mode 100644 index 0000000..8546b43 --- /dev/null +++ b/api/EnvironmentHelper.cs @@ -0,0 +1,26 @@ +namespace api; + +public static class EnvironmentHelper +{ + private static readonly List NonProdEnvironments = ["Development", "Testing"]; + + public static bool IsTesting() + { + return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Testing"; + } + + public static bool IsDevelopment() + { + return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development"; + } + + public static bool IsNonProd() + { + return NonProdEnvironments.Contains(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); + } + + public static bool IsCi() + { + return Environment.GetEnvironmentVariable("CI") == "true"; + } +} \ No newline at end of file diff --git a/api/Events/Auth/Client/ClientWantsToLogIn.cs b/api/Events/Auth/Client/ClientWantsToLogIn.cs index 2477d41..a4ff964 100644 --- a/api/Events/Auth/Client/ClientWantsToLogIn.cs +++ b/api/Events/Auth/Client/ClientWantsToLogIn.cs @@ -44,7 +44,8 @@ public override async Task Handle(ClientWantsToLogInDto dto, IWebSocketConnectio Jwt = jwt, }); - socket.SendDto(new ServerSendsUserInfo + + socket.SendDto(new ServerSendsUserInfo { GetUserDto = getUserDto }); diff --git a/api/Events/Auth/Client/ClientWantsToLogOut.cs b/api/Events/Auth/Client/ClientWantsToLogOut.cs index dd514a4..a361ecd 100644 --- a/api/Events/Auth/Client/ClientWantsToLogOut.cs +++ b/api/Events/Auth/Client/ClientWantsToLogOut.cs @@ -12,7 +12,7 @@ public class ClientWantsToLogOut(WebSocketConnectionService connectionService) { public override Task Handle(ClientWantsToLogOutDto dto, IWebSocketConnection socket) { - connectionService.RemoveConnection(socket); + connectionService.RemoveEmailFromConnection(socket); socket.SendDto(new ServerLogsOutUser()); return Task.CompletedTask; } diff --git a/api/Events/Collections/Client/ClientWantsToCreateCollection.cs b/api/Events/Collections/Client/ClientWantsToCreateCollection.cs index 7298b0e..4553efd 100644 --- a/api/Events/Collections/Client/ClientWantsToCreateCollection.cs +++ b/api/Events/Collections/Client/ClientWantsToCreateCollection.cs @@ -1,5 +1,6 @@ using api.Core.Services; using api.Events.Collections.Server; +using api.Events.Statistics; using api.Extensions; using Fleck; using lib; @@ -13,16 +14,20 @@ public class ClientWantsToCreateCollectionDto : BaseDtoWithJwt public required CreateCollectionDto CreateCollectionDto { get; set; } } -public class ClientWantsToCreateCollection(CollectionsService collectionsService, JwtService jwtService) : BaseEventHandler +public class ClientWantsToCreateCollection(CollectionsService collectionsService, JwtService jwtService, StatsService statsService) : BaseEventHandler { public override async Task Handle(ClientWantsToCreateCollectionDto dto, IWebSocketConnection socket) { var email = jwtService.GetEmailFromJwt(dto.Jwt!); await collectionsService.CreateCollection(dto.CreateCollectionDto, email); var allCollections = await collectionsService.GetCollectionsForUser(email); + var stats = await statsService.GetStats(email); + socket.SendDto(new ServerSendsAllCollections() { Collections = allCollections.ToList() }); + + socket.SendDto(new ServerSendsStats{Stats = stats}); } } \ No newline at end of file diff --git a/api/Events/Collections/Client/ClientWantsToDeleteCollection.cs b/api/Events/Collections/Client/ClientWantsToDeleteCollection.cs index 08bc019..69966f9 100644 --- a/api/Events/Collections/Client/ClientWantsToDeleteCollection.cs +++ b/api/Events/Collections/Client/ClientWantsToDeleteCollection.cs @@ -1,5 +1,6 @@ using api.Core.Services; using api.Events.Collections.Server; +using api.Events.Statistics; using api.Extensions; using Fleck; using lib; @@ -13,16 +14,20 @@ public class ClientWantsToDeleteCollectionDto : BaseDtoWithJwt public Guid CollectionId { get; set; } } -public class ClientWantsToDeleteCollection(CollectionsService collectionsService, JwtService jwtService) : BaseEventHandler +public class ClientWantsToDeleteCollection(CollectionsService collectionsService, JwtService jwtService, StatsService statsService) : BaseEventHandler { public override async Task Handle(ClientWantsToDeleteCollectionDto dto, IWebSocketConnection socket) { var email = jwtService.GetEmailFromJwt(dto.Jwt!); await collectionsService.DeleteCollection(dto.CollectionId, email); var allCollections = await collectionsService.GetCollectionsForUser(email); + + var stats = await statsService.GetStats(email); socket.SendDto(new ServerSendsAllCollections() { Collections = allCollections.ToList() }); + + socket.SendDto(new ServerSendsStats{Stats = stats}); } } \ No newline at end of file diff --git a/api/Events/PlantEvents/Client/ClientWantsToCreatePlant.cs b/api/Events/PlantEvents/Client/ClientWantsToCreatePlant.cs index eaf2632..ff059e9 100644 --- a/api/Events/PlantEvents/Client/ClientWantsToCreatePlant.cs +++ b/api/Events/PlantEvents/Client/ClientWantsToCreatePlant.cs @@ -1,6 +1,7 @@ using api.Core.Services; using api.EventFilters; using api.Events.PlantEvents.Server; +using api.Events.Statistics; using api.Extensions; using Fleck; using lib; @@ -11,11 +12,11 @@ namespace api.Events.PlantEvents.Client; public class ClientWantsToCreatePlantDto: BaseDtoWithJwt { - public CreatePlantDto CreatePlantDto { get; set; } + public required CreatePlantDto CreatePlantDto { get; set; } } [ValidateDataAnnotations] -public class ClientWantsToCreatePlant(PlantService plantService, JwtService jwtService): BaseEventHandler +public class ClientWantsToCreatePlant(PlantService plantService, JwtService jwtService, StatsService statsService): BaseEventHandler { public override async Task Handle(ClientWantsToCreatePlantDto dto, IWebSocketConnection socket) { @@ -26,7 +27,9 @@ public override async Task Handle(ClientWantsToCreatePlantDto dto, IWebSocketCon { Plant = plant }; - socket.SendDto(serverCreatesNewPlant); + + var stats = await statsService.GetStats(email); + socket.SendDto(new ServerSendsStats{Stats = stats}); } } \ No newline at end of file diff --git a/api/Events/PlantEvents/Client/ClientWantsToDeletePlant.cs b/api/Events/PlantEvents/Client/ClientWantsToDeletePlant.cs index bb4068f..76319a3 100644 --- a/api/Events/PlantEvents/Client/ClientWantsToDeletePlant.cs +++ b/api/Events/PlantEvents/Client/ClientWantsToDeletePlant.cs @@ -3,6 +3,7 @@ using api.EventFilters; using api.Events.Global; using api.Events.PlantEvents.Server; +using api.Events.Statistics; using api.Extensions; using Fleck; using lib; @@ -16,13 +17,17 @@ public class ClientWantsToDeletePlantDto: BaseDtoWithJwt } [ValidateDataAnnotations] -public class ClientWantsToDeletePlant(PlantService plantService, JwtService jwtService): BaseEventHandler +public class ClientWantsToDeletePlant(PlantService plantService, JwtService jwtService, StatsService statsService): BaseEventHandler { public override async Task Handle(ClientWantsToDeletePlantDto dto, IWebSocketConnection socket) { var email = jwtService.GetEmailFromJwt(dto.Jwt!); + var stats = await statsService.GetStats(email); + await plantService.DeletePlant(dto.PlantId, email); socket.SendDto( new ServerConfirmsDelete()); + + socket.SendDto(new ServerSendsStats{Stats = stats}); } } diff --git a/api/Events/PlantEvents/Client/ClientWantsToGetCriticalPlants.cs b/api/Events/PlantEvents/Client/ClientWantsToGetCriticalPlants.cs index 01b27f3..5b92e63 100644 --- a/api/Events/PlantEvents/Client/ClientWantsToGetCriticalPlants.cs +++ b/api/Events/PlantEvents/Client/ClientWantsToGetCriticalPlants.cs @@ -1,5 +1,6 @@ using api.Core.Services; using api.Events.PlantEvents.Server; +using api.Events.Statistics; using api.Extensions; using Fleck; using lib; @@ -9,16 +10,20 @@ namespace api.Events.PlantEvents.Client; public class ClientWantsToGetCriticalPlantsDto : BaseDtoWithJwt; -public class ClientWantsToGetCriticalPlants(JwtService jwtService, PlantService plantService) : BaseEventHandler +public class ClientWantsToGetCriticalPlants(JwtService jwtService, PlantService plantService, StatsService statsService) : BaseEventHandler { public override async Task Handle(ClientWantsToGetCriticalPlantsDto dto, IWebSocketConnection socket) { var email = jwtService.GetEmailFromJwt(dto.Jwt!); var plants = await plantService.GetCriticalPlants(email); + var stats = await statsService.GetStats(email); + var serverResponse = new ServerSendsCriticalPlants { Plants = plants }; socket.SendDto(serverResponse); + + socket.SendDto(new ServerSendsStats{Stats = stats}); } } \ No newline at end of file diff --git a/api/Events/PlantEvents/Client/ClientWantsToUpdatePlant.cs b/api/Events/PlantEvents/Client/ClientWantsToUpdatePlant.cs index 9f2b8ce..1dc8348 100644 --- a/api/Events/PlantEvents/Client/ClientWantsToUpdatePlant.cs +++ b/api/Events/PlantEvents/Client/ClientWantsToUpdatePlant.cs @@ -1,5 +1,6 @@ using api.Core.Services; using api.Events.PlantEvents.Server; +using api.Events.Statistics; using api.Extensions; using Fleck; using lib; @@ -13,15 +14,19 @@ public class ClientWantsToUpdatePlantDto: BaseDtoWithJwt public required UpdatePlantDto UpdatePlantDto { get; set; } } -public class ClientWantsToUpdatePlant(PlantService plantService, JwtService jwtService): BaseEventHandler +public class ClientWantsToUpdatePlant(PlantService plantService, JwtService jwtService, StatsService statsService): BaseEventHandler { public override async Task Handle(ClientWantsToUpdatePlantDto dto, IWebSocketConnection socket) { var email = jwtService.GetEmailFromJwt(dto.Jwt!); var plant = await plantService.UpdatePlant(dto.UpdatePlantDto, email); + var stats = await statsService.GetStats(email); + socket.SendDto(new ServerSavesPlant { Plant = plant }); + + socket.SendDto(new ServerSendsStats{Stats = stats}); } } \ No newline at end of file diff --git a/api/Events/Statistics/ClientWantsStats.cs b/api/Events/Statistics/ClientWantsStats.cs new file mode 100644 index 0000000..0220931 --- /dev/null +++ b/api/Events/Statistics/ClientWantsStats.cs @@ -0,0 +1,28 @@ +using api.Core.Services; +using api.Extensions; +using Fleck; +using lib; +using Shared.Models; + +namespace api.Events.Statistics; + +public class ClientWantsStatsDto : BaseDtoWithJwt +{ + +} + +public class ClientWantsStats(StatsService statsService, JwtService jwtService) : BaseEventHandler +{ + public override async Task Handle(ClientWantsStatsDto dto, IWebSocketConnection socket) + { + var email = jwtService.GetEmailFromJwt(dto.Jwt!); + + var stats = await statsService.GetStats(email); + socket.SendDto(new ServerSendsStats{Stats = stats}); + } +} + +public class ServerSendsStats : BaseDto +{ + public Stats Stats { get; set; } = null!; +} diff --git a/api/Events/Stats/ClientWantsStats.cs b/api/Events/Stats/ClientWantsStats.cs deleted file mode 100644 index b581887..0000000 --- a/api/Events/Stats/ClientWantsStats.cs +++ /dev/null @@ -1,48 +0,0 @@ -using api.Core.Services; -using api.Extensions; -using Fleck; -using lib; -using Shared.Models; - -namespace api.Events.Stats; - -public class ClientWantsStatsDto : BaseDtoWithJwt -{ - -} - -public class ClientWantsStats(PlantService plantService, CollectionsService collectionsService, JwtService jwtService) : BaseEventHandler -{ - public override async Task Handle(ClientWantsStatsDto dto, IWebSocketConnection socket) - { - var email = jwtService.GetEmailFromJwt(dto.Jwt!); - - var totalPlants = await plantService.GetTotalPlantsCount(email); - var happyPlants = await plantService.GetHappyPlantsCount(email); - var collections = await collectionsService.GetTotalCollectionsCount(email); - - var statsDto = new ServerSendsStats - { - Stats = new Stats - { - TotalPlants = totalPlants, - HappyPlants = happyPlants, - Collections = collections - } - }; - - socket.SendDto(statsDto); - } -} - -public class ServerSendsStats : BaseDto -{ - public Stats Stats { get; set; } -} - -public class Stats -{ - public int TotalPlants { get; set; } - public int HappyPlants { get; set; } - public int Collections { get; set; } -} \ No newline at end of file diff --git a/api/Extensions/AddServicesAndRepositoriesExtension.cs b/api/Extensions/AddServicesAndRepositoriesExtension.cs index 35b8d38..3206523 100644 --- a/api/Extensions/AddServicesAndRepositoriesExtension.cs +++ b/api/Extensions/AddServicesAndRepositoriesExtension.cs @@ -26,9 +26,10 @@ public static void AddServicesAndRepositories(this IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // External services - if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Testing") + if (EnvironmentHelper.IsTesting()) { services.AddSingleton(); services.AddSingleton(); diff --git a/api/Extensions/ConfigureExtensions.cs b/api/Extensions/ConfigureExtensions.cs index e3c2ee4..43bfcd2 100644 --- a/api/Extensions/ConfigureExtensions.cs +++ b/api/Extensions/ConfigureExtensions.cs @@ -6,7 +6,7 @@ public static class ConfigureExtensions { public static void ConfigureOptions(this WebApplicationBuilder builder) { - if (Environment.GetEnvironmentVariable("CI") is not null) + if (EnvironmentHelper.IsCi()) { builder.Services.Configure(options => { @@ -25,7 +25,9 @@ public static void ConfigureOptions(this WebApplicationBuilder builder) options.SubscribeTopic = Environment.GetEnvironmentVariable("MQTT_SUBSCRIBE_TOPIC") ?? throw new Exception("MQTT subscribe topic is missing"); options.PublishTopic = Environment.GetEnvironmentVariable("MQTT_PUBLISH_TOPIC") ?? throw new Exception("MQTT publish topic is missing"); }); - + + if (EnvironmentHelper.IsTesting()) return; + builder.Services.Configure(options => { options.RemoveBackgroundEndpoint = Environment.GetEnvironmentVariable("AZURE_VISION_REMOVE_BACKGROUND_ENDPOINT") ?? throw new Exception("Azure Vision endpoint is missing"); diff --git a/api/GlobalExceptionHandler.cs b/api/GlobalExceptionHandler.cs index 511ca11..2d878c0 100644 --- a/api/GlobalExceptionHandler.cs +++ b/api/GlobalExceptionHandler.cs @@ -28,10 +28,11 @@ public static void Handle(this Exception ex, IWebSocketConnection socket, string _ => new ServerSendsErrorMessage { Error = message ?? ex.Message } }; else - serverResponse = new ServerSendsErrorMessage - { - Error = "Something went wrong. Please try again later." - }; + { + serverResponse = EnvironmentHelper.IsTesting() + ? new ServerSendsErrorMessage { Error = ex.Message } + : new ServerSendsErrorMessage { Error = "Something went wrong. Please try again later." }; + } socket.SendDto(serverResponse); } diff --git a/api/Program.cs b/api/Program.cs index c833a96..d3df78d 100644 --- a/api/Program.cs +++ b/api/Program.cs @@ -1,6 +1,5 @@ using System.Reflection; using System.Text.Json; -using api.Core.Options; using api.Core.Services; using api.Events.Auth.Client; using api.Extensions; @@ -9,7 +8,6 @@ using lib; using Microsoft.EntityFrameworkCore; using Serilog; -using Shared.Dtos; using Shared.Exceptions; using Shared.Models; using Testcontainers.PostgreSql; @@ -26,6 +24,11 @@ public static class Startup nameof(ClientWantsToSignUp) ]; + private static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + PropertyNameCaseInsensitive = true + }; + public static async Task Main(string[] args) { var app = await StartApi(args); @@ -46,7 +49,7 @@ public static async Task StartApi(string[] args) var builder = WebApplication.CreateBuilder(args); - if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Testing") + if (EnvironmentHelper.IsTesting()) { var dbContainer = new PostgreSqlBuilder() @@ -86,7 +89,7 @@ public static async Task StartApi(string[] args) var scope = app.Services.CreateScope(); var db = await app.Services.GetRequiredService>().CreateDbContextAsync(); - if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development") + if (EnvironmentHelper.IsNonProd()) { await db.Database.EnsureDeletedAsync(); } @@ -94,7 +97,7 @@ public static async Task StartApi(string[] args) await db.Database.EnsureCreatedAsync(); await db.Database.MigrateAsync(); - if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development") + if (EnvironmentHelper.IsNonProd()) { await db.SeedDevelopmentDataAsync(scope, app.Configuration["AzureBlob:DefaultPlantImageUrl"] ?? "https://example.com"); } @@ -135,7 +138,7 @@ public static async Task StartApi(string[] args) try { // Check if the message contains a JWT token and if it is valid - var dto = JsonSerializer.Deserialize(message, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + var dto = JsonSerializer.Deserialize(message, JsonSerializerOptions); if (dto is not null && PublicEvents.Contains(dto.eventType) == false) { if (dto.Jwt is null) diff --git a/api/WebSocketConnectionService.cs b/api/WebSocketConnectionService.cs index 6b57682..a7c1cde 100644 --- a/api/WebSocketConnectionService.cs +++ b/api/WebSocketConnectionService.cs @@ -19,6 +19,12 @@ public void UpdateConnectionEmail(IWebSocketConnection connection, string email) var clientId = connection.ConnectionInfo.Id; _connectedClients[clientId].Email = email; } + + public void RemoveEmailFromConnection(IWebSocketConnection connection) + { + var clientId = connection.ConnectionInfo.Id; + _connectedClients[clientId].Email = null; + } public void RemoveConnection(IWebSocketConnection connection) { diff --git a/api/logo.png b/api/logo.png deleted file mode 100644 index 0ac63e4..0000000 Binary files a/api/logo.png and /dev/null differ