Initial commit: base slice (auth, roles, users, admin) scaffold

Backend: .NET 10 Clean Architecture + LiteCqrs.Net + EF Core/PostgreSQL +
Identity/JWT. Frontend: React 19 + Vite + TanStack Query/Router + Tailwind v4
with a retro CRT theme. Docker/compose deployment mirroring PnvPanel's
conventions, scoped down to the current base feature set.
This commit is contained in:
Leonid Pershin
2026-07-24 05:40:34 +03:00
commit 8a3eebc48f
156 changed files with 9335 additions and 0 deletions
@@ -0,0 +1,28 @@
using NSubstitute;
using TeleWave.Application.Admin.Roles.ChangeUserRole;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using Xunit;
namespace TeleWave.Application.Tests.Admin.Roles;
public class ChangeUserRoleCommandHandlerTests
{
private readonly IRoleService _roleService = Substitute.For<IRoleService>();
[Fact]
public async Task Handle_DelegatesToRoleService()
{
var userId = Guid.NewGuid();
var roleId = Guid.NewGuid();
_roleService
.ChangeUserRoleAsync(userId, roleId, Arg.Any<CancellationToken>())
.Returns(Result.Success());
var handler = new ChangeUserRoleCommandHandler(_roleService);
var result = await handler.Handle(new ChangeUserRoleCommand(userId, roleId), CancellationToken.None);
Assert.True(result.IsSuccess);
await _roleService.Received(1).ChangeUserRoleAsync(userId, roleId, Arg.Any<CancellationToken>());
}
}
@@ -0,0 +1,45 @@
using NSubstitute;
using TeleWave.Application.Admin.Users;
using TeleWave.Application.Admin.Users.BlockUser;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using Xunit;
namespace TeleWave.Application.Tests.Admin.Users;
public class BlockUserCommandHandlerTests
{
private readonly IIdentityService _identityService = Substitute.For<IIdentityService>();
private readonly ICurrentUser _currentUser = Substitute.For<ICurrentUser>();
private BlockUserCommandHandler CreateHandler() => new(_identityService, _currentUser);
[Fact]
public async Task Handle_WhenTargetingSelf_ReturnsFailureWithoutCallingIdentityService()
{
var userId = Guid.NewGuid();
_currentUser.UserId.Returns(userId);
var result = await CreateHandler().Handle(new BlockUserCommand(userId), CancellationToken.None);
Assert.False(result.IsSuccess);
Assert.Equal(UserErrors.CannotBlockSelf, result.Error);
await _identityService.DidNotReceive().BlockUserAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_WhenTargetingAnotherUser_DelegatesToIdentityService()
{
var adminId = Guid.NewGuid();
var targetId = Guid.NewGuid();
_currentUser.UserId.Returns(adminId);
_identityService
.BlockUserAsync(targetId, Arg.Any<CancellationToken>())
.Returns(Result.Success());
var result = await CreateHandler().Handle(new BlockUserCommand(targetId), CancellationToken.None);
Assert.True(result.IsSuccess);
await _identityService.Received(1).BlockUserAsync(targetId, Arg.Any<CancellationToken>());
}
}