0
0
mirror of https://github.com/alex289/CleanArchitecture.git synced 2025-07-01 11:02:57 +00:00

feat: Check for tenant when updating users tenant

This commit is contained in:
alex289 2023-08-31 11:46:01 +02:00
parent 61bcab6d77
commit 3969db2bba
No known key found for this signature in database
GPG Key ID: 573F77CD2D87F863
9 changed files with 126 additions and 13 deletions

View File

@ -17,7 +17,7 @@ public sealed class CreateTenantCommandHandlerTests
Guid.NewGuid(), Guid.NewGuid(),
"Test Tenant"); "Test Tenant");
_fixture.CommandHandler.Handle(command, default!).Wait(); _fixture.CommandHandler.Handle(command, default).Wait();
_fixture _fixture
.VerifyNoDomainNotification() .VerifyNoDomainNotification()
@ -36,7 +36,7 @@ public sealed class CreateTenantCommandHandlerTests
Guid.NewGuid(), Guid.NewGuid(),
"Test Tenant"); "Test Tenant");
_fixture.CommandHandler.Handle(command, default!).Wait(); _fixture.CommandHandler.Handle(command, default).Wait();
_fixture _fixture
.VerifyNoCommit() .VerifyNoCommit()
@ -56,7 +56,7 @@ public sealed class CreateTenantCommandHandlerTests
_fixture.SetupExistingTenant(command.AggregateId); _fixture.SetupExistingTenant(command.AggregateId);
_fixture.CommandHandler.Handle(command, default!).Wait(); _fixture.CommandHandler.Handle(command, default).Wait();
_fixture _fixture
.VerifyNoCommit() .VerifyNoCommit()

View File

@ -42,4 +42,23 @@ public sealed class DeleteTenantCommandHandlerTests
ErrorCodes.ObjectNotFound, ErrorCodes.ObjectNotFound,
$"There is no tenant with Id {command.AggregateId}"); $"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<TenantDeletedEvent>()
.VerifyAnyDomainNotification()
.VerifyExistingNotification(
ErrorCodes.InsufficientPermissions,
$"No permission to delete tenant {command.AggregateId}");
}
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using CleanArchitecture.Domain.Commands.Tenants.DeleteTenant; using CleanArchitecture.Domain.Commands.Tenants.DeleteTenant;
using CleanArchitecture.Domain.Enums;
using CleanArchitecture.Domain.Interfaces.Repositories; using CleanArchitecture.Domain.Interfaces.Repositories;
using NSubstitute; using NSubstitute;
@ -36,4 +37,9 @@ public sealed class DeleteTenantCommandTestFixture : CommandHandlerFixtureBase
return tenant; return tenant;
} }
public void SetupUser()
{
User.GetUserRole().Returns(UserRole.User);
}
} }

View File

@ -19,7 +19,7 @@ public sealed class UpdateTenantCommandHandlerTests
_fixture.SetupExistingTenant(command.AggregateId); _fixture.SetupExistingTenant(command.AggregateId);
_fixture.CommandHandler.Handle(command, default!).Wait(); _fixture.CommandHandler.Handle(command, default).Wait();
_fixture _fixture
.VerifyCommit() .VerifyCommit()
@ -38,7 +38,7 @@ public sealed class UpdateTenantCommandHandlerTests
_fixture.SetupUser(); _fixture.SetupUser();
_fixture.CommandHandler.Handle(command, default!).Wait(); _fixture.CommandHandler.Handle(command, default).Wait();
_fixture _fixture
.VerifyNoCommit() .VerifyNoCommit()
@ -56,7 +56,7 @@ public sealed class UpdateTenantCommandHandlerTests
Guid.NewGuid(), Guid.NewGuid(),
"Tenant Name"); "Tenant Name");
_fixture.CommandHandler.Handle(command, default!).Wait(); _fixture.CommandHandler.Handle(command, default).Wait();
_fixture _fixture
.VerifyNoCommit() .VerifyNoCommit()

View File

@ -26,6 +26,8 @@ public sealed class UpdateUserCommandHandlerTests
UserRole.User, UserRole.User,
Guid.NewGuid()); Guid.NewGuid());
_fixture.SetupTenant(command.TenantId);
await _fixture.CommandHandler.Handle(command, default); await _fixture.CommandHandler.Handle(command, default);
_fixture _fixture
@ -46,6 +48,8 @@ public sealed class UpdateUserCommandHandlerTests
"Email", "Email",
UserRole.User, UserRole.User,
Guid.NewGuid()); Guid.NewGuid());
_fixture.SetupTenant(command.TenantId);
await _fixture.CommandHandler.Handle(command, default); await _fixture.CommandHandler.Handle(command, default);
@ -70,6 +74,8 @@ public sealed class UpdateUserCommandHandlerTests
"Email", "Email",
UserRole.User, UserRole.User,
Guid.NewGuid()); Guid.NewGuid());
_fixture.SetupTenant(command.TenantId);
_fixture.UserRepository _fixture.UserRepository
.GetByEmailAsync(command.Email) .GetByEmailAsync(command.Email)
@ -92,4 +98,59 @@ public sealed class UpdateUserCommandHandlerTests
DomainErrorCodes.User.UserAlreadyExists, DomainErrorCodes.User.UserAlreadyExists,
$"There is already a user with email {command.Email}"); $"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<UserUpdatedEvent>()
.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<Entities.User>(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<UserUpdatedEvent>(x => x.AggregateId == command.UserId);
}
} }

View File

@ -11,17 +11,20 @@ public sealed class UpdateUserCommandTestFixture : CommandHandlerFixtureBase
public UpdateUserCommandTestFixture() public UpdateUserCommandTestFixture()
{ {
UserRepository = Substitute.For<IUserRepository>(); UserRepository = Substitute.For<IUserRepository>();
TenantRepository = Substitute.For<ITenantRepository>();
CommandHandler = new UpdateUserCommandHandler( CommandHandler = new UpdateUserCommandHandler(
Bus, Bus,
UnitOfWork, UnitOfWork,
NotificationHandler, NotificationHandler,
UserRepository, UserRepository,
User); User,
TenantRepository);
} }
public UpdateUserCommandHandler CommandHandler { get; } public UpdateUserCommandHandler CommandHandler { get; }
public IUserRepository UserRepository { get; } public IUserRepository UserRepository { get; }
private ITenantRepository TenantRepository { get; }
public Entities.User SetupUser() public Entities.User SetupUser()
{ {
@ -40,4 +43,21 @@ public sealed class UpdateUserCommandTestFixture : CommandHandlerFixtureBase
return user; return user;
} }
public Entities.Tenant SetupTenant(Guid tenantId)
{
var tenant = new Entities.Tenant(tenantId, "Name");
TenantRepository
.ExistsAsync(Arg.Is<Guid>(y => y == tenant.Id))
.Returns(true);
return tenant;
}
public void SetupCurrentUser(Guid userId)
{
User.GetUserId().Returns(userId);
User.GetUserRole().Returns(UserRole.User);
}
} }

View File

@ -38,8 +38,6 @@ public sealed class DeleteTenantCommandHandler : CommandHandlerBase,
return; return;
} }
// Todo: Test following
if (_user.GetUserRole() != UserRole.Admin) if (_user.GetUserRole() != UserRole.Admin)
{ {
await NotifyAsync( await NotifyAsync(

View File

@ -15,16 +15,19 @@ public sealed class UpdateUserCommandHandler : CommandHandlerBase,
{ {
private readonly IUser _user; private readonly IUser _user;
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly ITenantRepository _tenantRepository;
public UpdateUserCommandHandler( public UpdateUserCommandHandler(
IMediatorHandler bus, IMediatorHandler bus,
IUnitOfWork unitOfWork, IUnitOfWork unitOfWork,
INotificationHandler<DomainNotification> notifications, INotificationHandler<DomainNotification> notifications,
IUserRepository userRepository, IUserRepository userRepository,
IUser user) : base(bus, unitOfWork, notifications) IUser user,
ITenantRepository tenantRepository) : base(bus, unitOfWork, notifications)
{ {
_userRepository = userRepository; _userRepository = userRepository;
_user = user; _user = user;
_tenantRepository = tenantRepository;
} }
public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken) public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken)
@ -76,8 +79,15 @@ public sealed class UpdateUserCommandHandler : CommandHandlerBase,
{ {
user.SetRole(request.Role); user.SetRole(request.Role);
// Todo: Test if (!await _tenantRepository.ExistsAsync(request.TenantId))
// Todo: Check if tenant exists first {
await NotifyAsync(
new DomainNotification(
request.MessageType,
$"There is no tenant with Id {request.TenantId}",
ErrorCodes.ObjectNotFound));
return;
}
user.SetTenant(request.TenantId); user.SetTenant(request.TenantId);
} }

View File

@ -40,7 +40,6 @@ public sealed class GetUsersByIdsTests : IClassFixture<UserTestFixture>
ids.Add(nonExistingId); ids.Add(nonExistingId);
// Todo: Use default instead of null everywhere
var result = await _fixture.UsersApiImplementation.GetByIds( var result = await _fixture.UsersApiImplementation.GetByIds(
SetupRequest(ids), SetupRequest(ids),
default!); default!);