From 3969db2bba88bc53c2754c2178afce8e7be590d8 Mon Sep 17 00:00:00 2001 From: alex289 Date: Thu, 31 Aug 2023 11:46:01 +0200 Subject: [PATCH] feat: Check for tenant when updating users tenant --- .../CreateTenantCommandHandlerTests.cs | 6 +- .../DeleteTenantCommandHandlerTests.cs | 19 ++++++ .../DeleteTenantCommandTestFixture.cs | 6 ++ .../UpdateTenantCommandHandlerTests.cs | 6 +- .../UpdateUserCommandHandlerTests.cs | 61 +++++++++++++++++++ .../UpdateUserCommandTestFixture.cs | 22 ++++++- .../DeleteTenantCommandHandler.cs | 2 - .../UpdateUser/UpdateUserCommandHandler.cs | 16 ++++- .../Users/GetUsersByIdsTests.cs | 1 - 9 files changed, 126 insertions(+), 13 deletions(-) diff --git a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/CreateTenant/CreateTenantCommandHandlerTests.cs b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/CreateTenant/CreateTenantCommandHandlerTests.cs index eb8d848..2dce689 100644 --- a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/CreateTenant/CreateTenantCommandHandlerTests.cs +++ b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/CreateTenant/CreateTenantCommandHandlerTests.cs @@ -17,7 +17,7 @@ public sealed class CreateTenantCommandHandlerTests Guid.NewGuid(), "Test Tenant"); - _fixture.CommandHandler.Handle(command, default!).Wait(); + _fixture.CommandHandler.Handle(command, default).Wait(); _fixture .VerifyNoDomainNotification() @@ -36,7 +36,7 @@ public sealed class CreateTenantCommandHandlerTests Guid.NewGuid(), "Test Tenant"); - _fixture.CommandHandler.Handle(command, default!).Wait(); + _fixture.CommandHandler.Handle(command, default).Wait(); _fixture .VerifyNoCommit() @@ -56,7 +56,7 @@ public sealed class CreateTenantCommandHandlerTests _fixture.SetupExistingTenant(command.AggregateId); - _fixture.CommandHandler.Handle(command, default!).Wait(); + _fixture.CommandHandler.Handle(command, default).Wait(); _fixture .VerifyNoCommit() diff --git a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandHandlerTests.cs b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandHandlerTests.cs index cfd6851..8f0d378 100644 --- a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandHandlerTests.cs +++ b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandHandlerTests.cs @@ -42,4 +42,23 @@ public sealed class DeleteTenantCommandHandlerTests ErrorCodes.ObjectNotFound, $"There is no tenant with Id {command.AggregateId}"); } + + [Fact] + public void Should_Not_Delete_Tenant_Insufficient_Permissions() + { + var tenant = _fixture.SetupTenant(); + _fixture.SetupUser(); + + var command = new DeleteTenantCommand(tenant.Id); + + _fixture.CommandHandler.Handle(command, default).Wait(); + + _fixture + .VerifyNoCommit() + .VerifyNoRaisedEvent() + .VerifyAnyDomainNotification() + .VerifyExistingNotification( + ErrorCodes.InsufficientPermissions, + $"No permission to delete tenant {command.AggregateId}"); + } } \ No newline at end of file diff --git a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandTestFixture.cs b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandTestFixture.cs index 1b8367a..b929df9 100644 --- a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandTestFixture.cs +++ b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/DeleteTenant/DeleteTenantCommandTestFixture.cs @@ -1,5 +1,6 @@ using System; using CleanArchitecture.Domain.Commands.Tenants.DeleteTenant; +using CleanArchitecture.Domain.Enums; using CleanArchitecture.Domain.Interfaces.Repositories; using NSubstitute; @@ -36,4 +37,9 @@ public sealed class DeleteTenantCommandTestFixture : CommandHandlerFixtureBase return tenant; } + + public void SetupUser() + { + User.GetUserRole().Returns(UserRole.User); + } } \ No newline at end of file diff --git a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/UpdateTenant/UpdateTenantCommandHandlerTests.cs b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/UpdateTenant/UpdateTenantCommandHandlerTests.cs index e391a89..77a186a 100644 --- a/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/UpdateTenant/UpdateTenantCommandHandlerTests.cs +++ b/CleanArchitecture.Domain.Tests/CommandHandler/Tenant/UpdateTenant/UpdateTenantCommandHandlerTests.cs @@ -19,7 +19,7 @@ public sealed class UpdateTenantCommandHandlerTests _fixture.SetupExistingTenant(command.AggregateId); - _fixture.CommandHandler.Handle(command, default!).Wait(); + _fixture.CommandHandler.Handle(command, default).Wait(); _fixture .VerifyCommit() @@ -38,7 +38,7 @@ public sealed class UpdateTenantCommandHandlerTests _fixture.SetupUser(); - _fixture.CommandHandler.Handle(command, default!).Wait(); + _fixture.CommandHandler.Handle(command, default).Wait(); _fixture .VerifyNoCommit() @@ -56,7 +56,7 @@ public sealed class UpdateTenantCommandHandlerTests Guid.NewGuid(), "Tenant Name"); - _fixture.CommandHandler.Handle(command, default!).Wait(); + _fixture.CommandHandler.Handle(command, default).Wait(); _fixture .VerifyNoCommit() diff --git a/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandHandlerTests.cs b/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandHandlerTests.cs index 683d677..7542c97 100644 --- a/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandHandlerTests.cs +++ b/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandHandlerTests.cs @@ -26,6 +26,8 @@ public sealed class UpdateUserCommandHandlerTests UserRole.User, Guid.NewGuid()); + _fixture.SetupTenant(command.TenantId); + await _fixture.CommandHandler.Handle(command, default); _fixture @@ -46,6 +48,8 @@ public sealed class UpdateUserCommandHandlerTests "Email", UserRole.User, Guid.NewGuid()); + + _fixture.SetupTenant(command.TenantId); await _fixture.CommandHandler.Handle(command, default); @@ -70,6 +74,8 @@ public sealed class UpdateUserCommandHandlerTests "Email", UserRole.User, Guid.NewGuid()); + + _fixture.SetupTenant(command.TenantId); _fixture.UserRepository .GetByEmailAsync(command.Email) @@ -92,4 +98,59 @@ public sealed class UpdateUserCommandHandlerTests DomainErrorCodes.User.UserAlreadyExists, $"There is already a user with email {command.Email}"); } + + [Fact] + public async Task Should_Not_Update_Non_Existing_Tenant() + { + var user = _fixture.SetupUser(); + + var command = new UpdateUserCommand( + user.Id, + "test@email.com", + "Test", + "Email", + UserRole.User, + Guid.NewGuid()); + + await _fixture.CommandHandler.Handle(command, default); + + _fixture + .VerifyNoCommit() + .VerifyNoRaisedEvent() + .VerifyAnyDomainNotification() + .VerifyExistingNotification( + ErrorCodes.ObjectNotFound, + $"There is no tenant with Id {command.TenantId}"); + } + + [Fact] + public async Task Should_Not_Update_Admin_Properties() + { + var user = _fixture.SetupUser(); + _fixture.SetupCurrentUser(user.Id); + + var command = new UpdateUserCommand( + user.Id, + "test@email.com", + "Test", + "Email", + UserRole.Admin, + Guid.NewGuid()); + + _fixture.SetupTenant(command.TenantId); + + await _fixture.CommandHandler.Handle(command, default); + + _fixture.UserRepository.Received(1).Update(Arg.Is(u => + u.TenantId == user.TenantId && + u.Role == user.Role && + u.Id == command.UserId && + u.Email == command.Email && + u.FirstName == command.FirstName)); + + _fixture + .VerifyNoDomainNotification() + .VerifyCommit() + .VerifyRaisedEvent(x => x.AggregateId == command.UserId); + } } \ No newline at end of file diff --git a/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandTestFixture.cs b/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandTestFixture.cs index aaf9faf..6f144a0 100644 --- a/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandTestFixture.cs +++ b/CleanArchitecture.Domain.Tests/CommandHandler/User/UpdateUser/UpdateUserCommandTestFixture.cs @@ -11,17 +11,20 @@ public sealed class UpdateUserCommandTestFixture : CommandHandlerFixtureBase public UpdateUserCommandTestFixture() { UserRepository = Substitute.For(); + TenantRepository = Substitute.For(); CommandHandler = new UpdateUserCommandHandler( Bus, UnitOfWork, NotificationHandler, UserRepository, - User); + User, + TenantRepository); } public UpdateUserCommandHandler CommandHandler { get; } public IUserRepository UserRepository { get; } + private ITenantRepository TenantRepository { get; } public Entities.User SetupUser() { @@ -40,4 +43,21 @@ public sealed class UpdateUserCommandTestFixture : CommandHandlerFixtureBase return user; } + + public Entities.Tenant SetupTenant(Guid tenantId) + { + var tenant = new Entities.Tenant(tenantId, "Name"); + + TenantRepository + .ExistsAsync(Arg.Is(y => y == tenant.Id)) + .Returns(true); + + return tenant; + } + + public void SetupCurrentUser(Guid userId) + { + User.GetUserId().Returns(userId); + User.GetUserRole().Returns(UserRole.User); + } } \ No newline at end of file diff --git a/CleanArchitecture.Domain/Commands/Tenants/DeleteTenant/DeleteTenantCommandHandler.cs b/CleanArchitecture.Domain/Commands/Tenants/DeleteTenant/DeleteTenantCommandHandler.cs index 3a57bed..1303d7b 100644 --- a/CleanArchitecture.Domain/Commands/Tenants/DeleteTenant/DeleteTenantCommandHandler.cs +++ b/CleanArchitecture.Domain/Commands/Tenants/DeleteTenant/DeleteTenantCommandHandler.cs @@ -38,8 +38,6 @@ public sealed class DeleteTenantCommandHandler : CommandHandlerBase, return; } - // Todo: Test following - if (_user.GetUserRole() != UserRole.Admin) { await NotifyAsync( diff --git a/CleanArchitecture.Domain/Commands/Users/UpdateUser/UpdateUserCommandHandler.cs b/CleanArchitecture.Domain/Commands/Users/UpdateUser/UpdateUserCommandHandler.cs index 74b86fc..cbfec13 100644 --- a/CleanArchitecture.Domain/Commands/Users/UpdateUser/UpdateUserCommandHandler.cs +++ b/CleanArchitecture.Domain/Commands/Users/UpdateUser/UpdateUserCommandHandler.cs @@ -15,16 +15,19 @@ public sealed class UpdateUserCommandHandler : CommandHandlerBase, { private readonly IUser _user; private readonly IUserRepository _userRepository; + private readonly ITenantRepository _tenantRepository; public UpdateUserCommandHandler( IMediatorHandler bus, IUnitOfWork unitOfWork, INotificationHandler notifications, IUserRepository userRepository, - IUser user) : base(bus, unitOfWork, notifications) + IUser user, + ITenantRepository tenantRepository) : base(bus, unitOfWork, notifications) { _userRepository = userRepository; _user = user; + _tenantRepository = tenantRepository; } public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken) @@ -76,8 +79,15 @@ public sealed class UpdateUserCommandHandler : CommandHandlerBase, { user.SetRole(request.Role); - // Todo: Test - // Todo: Check if tenant exists first + if (!await _tenantRepository.ExistsAsync(request.TenantId)) + { + await NotifyAsync( + new DomainNotification( + request.MessageType, + $"There is no tenant with Id {request.TenantId}", + ErrorCodes.ObjectNotFound)); + return; + } user.SetTenant(request.TenantId); } diff --git a/CleanArchitecture.gRPC.Tests/Users/GetUsersByIdsTests.cs b/CleanArchitecture.gRPC.Tests/Users/GetUsersByIdsTests.cs index 4744376..dbac281 100644 --- a/CleanArchitecture.gRPC.Tests/Users/GetUsersByIdsTests.cs +++ b/CleanArchitecture.gRPC.Tests/Users/GetUsersByIdsTests.cs @@ -40,7 +40,6 @@ public sealed class GetUsersByIdsTests : IClassFixture ids.Add(nonExistingId); -// Todo: Use default instead of null everywhere var result = await _fixture.UsersApiImplementation.GetByIds( SetupRequest(ids), default!);