Правки админки, вход
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
using BCrypt.Net;
|
||||
using Knot.Contracts.Auth.Application.Abstractions;
|
||||
using Knot.Contracts.Auth.Domain;
|
||||
using Knot.Modules.Admin.Application.Admin.DTOs;
|
||||
using Knot.Shared.Kernel;
|
||||
using MediatR;
|
||||
|
||||
namespace Knot.Modules.Admin.Application.Admin.Commands.CreateUser;
|
||||
|
||||
public record CreateUserCommand(
|
||||
string Username,
|
||||
string Password,
|
||||
string DisplayName,
|
||||
string? Email = null,
|
||||
string? Bio = null
|
||||
) : ICommand<AdminUserDto>;
|
||||
|
||||
internal sealed class CreateUserCommandHandler : ICommandHandler<CreateUserCommand, AdminUserDto>
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IAuthUnitOfWork _unitOfWork;
|
||||
|
||||
public CreateUserCommandHandler(IUserRepository userRepository, IAuthUnitOfWork unitOfWork)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public async Task<Result<AdminUserDto>> Handle(CreateUserCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Проверка уникальности username
|
||||
if (!await _userRepository.IsUsernameUniqueAsync(request.Username, cancellationToken))
|
||||
{
|
||||
return Result.Failure<AdminUserDto>(new Error("Admin.CreateUser.UsernameNotUnique", "Username is already taken"));
|
||||
}
|
||||
|
||||
// Хеширование пароля
|
||||
string passwordHash = BCrypt.Net.BCrypt.HashPassword(request.Password);
|
||||
|
||||
// Создание контракта пользователя
|
||||
var userContract = new UserContract
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Username = request.Username,
|
||||
PasswordHash = passwordHash,
|
||||
DisplayName = request.DisplayName,
|
||||
Email = request.Email,
|
||||
Bio = request.Bio,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
IsBanned = false,
|
||||
IsOnline = false
|
||||
};
|
||||
|
||||
_unitOfWork.Add(userContract);
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Result.Success(new AdminUserDto(
|
||||
userContract.Id,
|
||||
userContract.Username,
|
||||
userContract.DisplayName,
|
||||
userContract.Email,
|
||||
userContract.Avatar,
|
||||
userContract.CreatedAt,
|
||||
userContract.IsOnline,
|
||||
userContract.LastSeen ?? DateTime.UtcNow,
|
||||
userContract.IsBanned));
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Knot.Contracts.Conversations.Abstractions;
|
||||
using Knot.Contracts.Settings.Application.Abstractions;
|
||||
using Knot.Contracts.Settings.Application.DTOs;
|
||||
using Knot.Modules.Admin.Application.Admin.Commands;
|
||||
using Knot.Modules.Admin.Application.Admin.Commands.CreateUser;
|
||||
using Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
|
||||
using Knot.Modules.Admin.Application.Admin.Queries;
|
||||
using MediatR;
|
||||
@@ -56,6 +58,12 @@ public static class AdminEndpoints
|
||||
return Results.Ok(result.Value);
|
||||
});
|
||||
|
||||
group.MapPost("users", async ([FromBody] CreateUserCommand command, ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(command, ct);
|
||||
return result.IsSuccess ? Results.Created($"/api/admin/users/{result.Value.Id}", result.Value) : Results.BadRequest(new { error = result.Error.Description });
|
||||
});
|
||||
|
||||
group.MapPost("users/{userId:guid}/reset-password", async ([FromRoute] Guid userId, [FromBody] ResetPasswordRequest dto, ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new ResetUserPasswordCommand(userId, dto.NewPassword), ct);
|
||||
@@ -106,6 +114,12 @@ public static class AdminEndpoints
|
||||
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound("User not found");
|
||||
});
|
||||
|
||||
group.MapDelete("users/{userId:guid}", async ([FromRoute] Guid userId, IUserDeleterService userDeleter, CancellationToken ct) =>
|
||||
{
|
||||
var result = await userDeleter.DeleteUserAsync(userId, ct);
|
||||
return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
|
||||
});
|
||||
|
||||
group.MapGet("clean/dry-run", async (ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new CleanDryRunQuery(), ct);
|
||||
|
||||
@@ -43,6 +43,7 @@ public static class DependencyInjection
|
||||
services.AddScoped<Knot.Contracts.Messaging.Application.Abstractions.IMessageNotifier, Knot.Modules.Conversations.Infrastructure.SignalR.MessageNotifier>();
|
||||
services.AddScoped<ConversationsAbstractions.IUserStatusService, Knot.Modules.Conversations.Infrastructure.Services.UserStatusService>();
|
||||
services.AddScoped<Knot.Contracts.Conversations.Abstractions.IUserStatusService, Knot.Modules.Conversations.Infrastructure.Services.UserStatusService>();
|
||||
services.AddScoped<Knot.Contracts.Conversations.Abstractions.IUserDeleterService, Knot.Modules.Conversations.Infrastructure.Services.UserDeleterService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Knot.Modules.Conversations.Infrastructure.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
namespace Knot.Modules.Conversations.Infrastructure;
|
||||
|
||||
[DbContext(typeof(ChatsDbContext))]
|
||||
public class ChatsDbContextFactory : IDesignTimeDbContextFactory<ChatsDbContext>
|
||||
{
|
||||
public ChatsDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
var optionsBuilder = new DbContextOptionsBuilder<ChatsDbContext>();
|
||||
optionsBuilder.UseNpgsql("Host=localhost;Database=knot_db;Username=knot;Password=knot_pass");
|
||||
return new ChatsDbContext(optionsBuilder.Options);
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,16 @@ namespace Knot.Modules.Conversations.Infrastructure.Persistence;
|
||||
|
||||
public sealed class ChatsDbContext : DbContext, Knot.Modules.Conversations.Application.Abstractions.IChatsUnitOfWork, Knot.Contracts.Conversations.Infrastructure.Persistence.IChatsDbContext
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IEncryptionService _encryptionService;
|
||||
private readonly IMediator? _mediator;
|
||||
private readonly IEncryptionService? _encryptionService;
|
||||
|
||||
public ChatsDbContext(DbContextOptions<ChatsDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public ChatsDbContext(DbContextOptions<ChatsDbContext> options, IMediator mediator, IEncryptionService encryptionService)
|
||||
: base(options)
|
||||
: this(options)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_encryptionService = encryptionService;
|
||||
@@ -99,9 +104,12 @@ public sealed class ChatsDbContext : DbContext, Knot.Modules.Conversations.Appli
|
||||
|
||||
int result = await base.SaveChangesAsync(cancellationToken);
|
||||
|
||||
foreach (var domainEvent in domainEvents)
|
||||
if (_mediator != null)
|
||||
{
|
||||
await _mediator.Publish(domainEvent, cancellationToken);
|
||||
foreach (var domainEvent in domainEvents)
|
||||
{
|
||||
await _mediator.Publish(domainEvent, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Knot.Contracts.Conversations.Abstractions;
|
||||
using Knot.Modules.Conversations.Application.Users.Commands.DeleteUser;
|
||||
using Knot.Shared.Kernel;
|
||||
using MediatR;
|
||||
|
||||
namespace Knot.Modules.Conversations.Infrastructure.Services;
|
||||
|
||||
public sealed class UserDeleterService : IUserDeleterService
|
||||
{
|
||||
private readonly ISender _sender;
|
||||
|
||||
public UserDeleterService(ISender sender)
|
||||
{
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
public async Task<Result> DeleteUserAsync(Guid userId, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _sender.Send(new DeleteUserCommand(userId), cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,10 @@
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.4" />
|
||||
<PackageReference Include="MediatR" Version="12.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.4" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// <auto-generated />
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Knot.Modules.Conversations.Infrastructure.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
Reference in New Issue
Block a user