Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small changes #33

Merged
merged 18 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -108,26 +108,27 @@
.ThenByDescending(log => log.TimeStamp)
.FirstOrDefault()
})
.OrderBy(p => p.WorstMood.Mood)

Check warning on line 111 in Infrastructure/Repositories/PlantRepository.cs

View workflow job for this annotation

GitHub Actions / tests

Dereference of a possibly null reference.
.ThenByDescending(p => p.WorstMood.TimeStamp)

Check warning on line 112 in Infrastructure/Repositories/PlantRepository.cs

View workflow job for this annotation

GitHub Actions / tests

Dereference of a possibly null reference.
.Take(3)
.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
Loading