Skip to content

Commit

Permalink
Merge pull request #33 from Team-Wilhelm/final-tweaks
Browse files Browse the repository at this point in the history
Small changes
  • Loading branch information
juuwel authored May 28, 2024
2 parents 25ea313 + 935ebb2 commit 8bd1d9b
Show file tree
Hide file tree
Showing 27 changed files with 234 additions and 111 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 0 additions & 7 deletions Infrastructure/Repositories/CollectionsRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,4 @@ public async Task RemovePlantFromCollection(Collection collection, Plant plant)
collection.Plants.Remove(plant);
await applicationDbContext.SaveChangesAsync();
}

public async Task<int> GetTotalCollectionsCount(string email)
{
await using var applicationDbContext = await dbContextFactory.CreateDbContextAsync();
return await applicationDbContext.Collections
.CountAsync(collection => collection.UserEmail == email);
}
}
19 changes: 10 additions & 9 deletions Infrastructure/Repositories/PlantRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,21 @@ public async Task<List<Plant>> GetCriticalPlants(string requesterEmail)
.Select(p => p.Plant)
.ToListAsync();
}

public async Task<int> GetHappyPlantsCount(string userEmail)
public async Task<Stats> 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<int> 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
};
}
}
8 changes: 8 additions & 0 deletions Shared/Models/Stats.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
17 changes: 12 additions & 5 deletions Tests/PlantTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using api.Events.Collections.Server;
using api.Events.PlantEvents.Client;
using api.Events.PlantEvents.Server;
using lib;
Expand All @@ -15,16 +14,24 @@ 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();

await webSocketTestClient.DoAndAssert(new ClientWantsToCreatePlantDto { CreatePlantDto = createPlantDto, Jwt = jwt }, receivedMessages =>
{
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,
Expand All @@ -36,7 +43,7 @@ await webSocketTestClient.DoAndAssert(new ClientWantsAllPlantsDto
});
}

private CreatePlantDto GenerateRandomCreatePlantDto(string email)
private CreatePlantDto GenerateRandomCreatePlantDto()
{
var createPlantDto = new CreatePlantDto
{
Expand Down
4 changes: 3 additions & 1 deletion Tests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ await webSocketTestClient.DoAndAssert(new ClientWantsToSignUpDto { RegisterUserD

var jwtSubscription = webSocketTestClient.Client.MessageReceived.Subscribe(msg =>
{
var eventType = JsonSerializer.Deserialize<BaseDto>(msg.Text).eventType;
if (eventType != nameof(ServerAuthenticatesUser)) return;
var serverAuthenticates = JsonSerializer.Deserialize<ServerAuthenticatesUser>(msg.Text, options: new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
jwt = serverAuthenticates.Jwt;
jwt = serverAuthenticates!.Jwt;
});
webSocketTestClient.Send(new ClientWantsToLogInDto { LoginDto = loginDto });

Expand Down
69 changes: 69 additions & 0 deletions Tests/WebSocketTestClient.cs
Original file line number Diff line number Diff line change
@@ -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<BaseDto> 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<BaseDto>(msg.Text, JsonSerializerOptions);

if (baseDto.eventType == "ServerSendsErrorMessage" || baseDto.eventType.Contains("ServerResponds") ||
baseDto.eventType.Contains("ServerRejects"))
{
var error = JsonSerializer.Deserialize<ServerSendsErrorMessage>(msg.Text, JsonSerializerOptions);
Console.WriteLine("Error: " + error!.Error);
}

lock (ReceivedMessages)
ReceivedMessages.Add(baseDto);
});
}

public async Task<WebSocketTestClient> ConnectAsync()
{
await Client.Start();
if (!Client.IsRunning)
throw new Exception("Could not start client!");
return this;
}

public void Send<T>(T dto) where T : BaseDto
{
Client.Send(JsonSerializer.Serialize(dto));
}

public async Task DoAndAssert<T>(T? action = null, Func<List<BaseDto>, 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: ");
}
}
}
}
5 changes: 0 additions & 5 deletions api/Core/Services/CollectionsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,4 @@ private async Task<Collection> VerifyCollectionExistsAndUserHasAccess(Guid colle
if (collection.UserEmail != loggedInUser) throw new NoAccessException("You don't have access to this collection");
return collection;
}

public async Task<int> GetTotalCollectionsCount(string email)
{
return await collectionsRepository.GetTotalCollectionsCount(email);
}
}
10 changes: 0 additions & 10 deletions api/Core/Services/PlantService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,6 @@ public async Task<List<GetCriticalPlantDto>> GetCriticalPlants(string requesterE

return criticalPlants;
}

public async Task<int> GetHappyPlantsCount(string userEmail)
{
return await plantRepository.GetHappyPlantsCount(userEmail);
}

public async Task<int> GetTotalPlantsCount(string userEmail)
{
return await plantRepository.GetTotalPlantsCount(userEmail);
}

private string GenerateRandomNickname()
{
Expand Down
13 changes: 13 additions & 0 deletions api/Core/Services/StatsService.cs
Original file line number Diff line number Diff line change
@@ -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<Stats> GetStats(string email)
{
return await plantRepository.GetStats(email);
}
}
26 changes: 26 additions & 0 deletions api/EnvironmentHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace api;

public static class EnvironmentHelper
{
private static readonly List<string?> 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";
}
}
3 changes: 2 additions & 1 deletion api/Events/Auth/Client/ClientWantsToLogIn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public override async Task Handle(ClientWantsToLogInDto dto, IWebSocketConnectio
Jwt = jwt,

});
socket.SendDto(new ServerSendsUserInfo

socket.SendDto(new ServerSendsUserInfo
{
GetUserDto = getUserDto
});
Expand Down
2 changes: 1 addition & 1 deletion api/Events/Auth/Client/ClientWantsToLogOut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using api.Core.Services;
using api.Events.Collections.Server;
using api.Events.Statistics;
using api.Extensions;
using Fleck;
using lib;
Expand All @@ -13,16 +14,20 @@ public class ClientWantsToCreateCollectionDto : BaseDtoWithJwt
public required CreateCollectionDto CreateCollectionDto { get; set; }
}

public class ClientWantsToCreateCollection(CollectionsService collectionsService, JwtService jwtService) : BaseEventHandler<ClientWantsToCreateCollectionDto>
public class ClientWantsToCreateCollection(CollectionsService collectionsService, JwtService jwtService, StatsService statsService) : BaseEventHandler<ClientWantsToCreateCollectionDto>
{
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});
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using api.Core.Services;
using api.Events.Collections.Server;
using api.Events.Statistics;
using api.Extensions;
using Fleck;
using lib;
Expand All @@ -13,16 +14,20 @@ public class ClientWantsToDeleteCollectionDto : BaseDtoWithJwt
public Guid CollectionId { get; set; }
}

public class ClientWantsToDeleteCollection(CollectionsService collectionsService, JwtService jwtService) : BaseEventHandler<ClientWantsToDeleteCollectionDto>
public class ClientWantsToDeleteCollection(CollectionsService collectionsService, JwtService jwtService, StatsService statsService) : BaseEventHandler<ClientWantsToDeleteCollectionDto>
{
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});
}
}
9 changes: 6 additions & 3 deletions api/Events/PlantEvents/Client/ClientWantsToCreatePlant.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<ClientWantsToCreatePlantDto>
public class ClientWantsToCreatePlant(PlantService plantService, JwtService jwtService, StatsService statsService): BaseEventHandler<ClientWantsToCreatePlantDto>
{
public override async Task Handle(ClientWantsToCreatePlantDto dto, IWebSocketConnection socket)
{
Expand All @@ -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});
}
}
7 changes: 6 additions & 1 deletion api/Events/PlantEvents/Client/ClientWantsToDeletePlant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,13 +17,17 @@ public class ClientWantsToDeletePlantDto: BaseDtoWithJwt
}

[ValidateDataAnnotations]
public class ClientWantsToDeletePlant(PlantService plantService, JwtService jwtService): BaseEventHandler<ClientWantsToDeletePlantDto>
public class ClientWantsToDeletePlant(PlantService plantService, JwtService jwtService, StatsService statsService): BaseEventHandler<ClientWantsToDeletePlantDto>
{
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});
}
}

Loading

0 comments on commit 8bd1d9b

Please sign in to comment.