Refactor project files for improved readability and structure
- Cleaned up whitespace in Directory.Build.props and Directory.Packages.props for consistency. - Reformatted project file references in PnvPanel.Api.csproj for better clarity. - Enhanced code readability in various endpoint files by adjusting line breaks and indentation. - Standardized method signatures and improved formatting in ResultExtensions and multiple endpoint classes for better maintainability.
This commit is contained in:
@@ -4,24 +4,38 @@ namespace PnvPanel.Application.Auth;
|
||||
|
||||
public static class AuthErrors
|
||||
{
|
||||
public static readonly Error DuplicateUserName =
|
||||
Error.Conflict("Auth.DuplicateUserName", "Пользователь с таким именем уже существует.");
|
||||
public static readonly Error DuplicateUserName = Error.Conflict(
|
||||
"Auth.DuplicateUserName",
|
||||
"Пользователь с таким именем уже существует."
|
||||
);
|
||||
|
||||
public static readonly Error InvalidCredentials =
|
||||
Error.Unauthorized("Auth.InvalidCredentials", "Неверное имя пользователя или пароль.");
|
||||
public static readonly Error InvalidCredentials = Error.Unauthorized(
|
||||
"Auth.InvalidCredentials",
|
||||
"Неверное имя пользователя или пароль."
|
||||
);
|
||||
|
||||
public static readonly Error LockedOut =
|
||||
Error.Unauthorized("Auth.LockedOut", "Слишком много неудачных попыток входа. Попробуйте позже.");
|
||||
public static readonly Error LockedOut = Error.Unauthorized(
|
||||
"Auth.LockedOut",
|
||||
"Слишком много неудачных попыток входа. Попробуйте позже."
|
||||
);
|
||||
|
||||
public static readonly Error InvalidRefreshToken =
|
||||
Error.Unauthorized("Auth.InvalidRefreshToken", "Недействительный refresh-токен.");
|
||||
public static readonly Error InvalidRefreshToken = Error.Unauthorized(
|
||||
"Auth.InvalidRefreshToken",
|
||||
"Недействительный refresh-токен."
|
||||
);
|
||||
|
||||
public static readonly Error Unauthorized =
|
||||
Error.Unauthorized("Auth.Unauthorized", "Требуется аутентификация.");
|
||||
public static readonly Error Unauthorized = Error.Unauthorized(
|
||||
"Auth.Unauthorized",
|
||||
"Требуется аутентификация."
|
||||
);
|
||||
|
||||
public static readonly Error UserBlocked =
|
||||
Error.Forbidden("Auth.UserBlocked", "Аккаунт заблокирован администратором.");
|
||||
public static readonly Error UserBlocked = Error.Forbidden(
|
||||
"Auth.UserBlocked",
|
||||
"Аккаунт заблокирован администратором."
|
||||
);
|
||||
|
||||
public static readonly Error NotActivated =
|
||||
Error.Forbidden("Auth.NotActivated", "Аккаунт не активирован — обратитесь к администратору.");
|
||||
public static readonly Error NotActivated = Error.Forbidden(
|
||||
"Auth.NotActivated",
|
||||
"Аккаунт не активирован — обратитесь к администратору."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,4 +5,5 @@ public sealed record AuthResult(
|
||||
DateTimeOffset AccessTokenExpiresAt,
|
||||
string RefreshToken,
|
||||
DateTimeOffset RefreshTokenExpiresAt,
|
||||
CurrentUserDto User);
|
||||
CurrentUserDto User
|
||||
);
|
||||
|
||||
@@ -3,4 +3,5 @@ using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Auth.ChangePassword;
|
||||
|
||||
public sealed record ChangePasswordCommand(string CurrentPassword, string NewPassword) : ICommand<Result>;
|
||||
public sealed record ChangePasswordCommand(string CurrentPassword, string NewPassword)
|
||||
: ICommand<Result>;
|
||||
|
||||
+10
-3
@@ -4,14 +4,21 @@ using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Auth.ChangePassword;
|
||||
|
||||
public sealed class ChangePasswordCommandHandler(IIdentityService identityService, ICurrentUser currentUser)
|
||||
: ICommandHandler<ChangePasswordCommand, Result>
|
||||
public sealed class ChangePasswordCommandHandler(
|
||||
IIdentityService identityService,
|
||||
ICurrentUser currentUser
|
||||
) : ICommandHandler<ChangePasswordCommand, Result>
|
||||
{
|
||||
public Task<Result> Handle(ChangePasswordCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return Task.FromResult(Result.Failure(AuthErrors.Unauthorized));
|
||||
|
||||
return identityService.ChangePasswordAsync(userId, command.CurrentPassword, command.NewPassword, cancellationToken);
|
||||
return identityService.ChangePasswordAsync(
|
||||
userId,
|
||||
command.CurrentPassword,
|
||||
command.NewPassword,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -4,8 +4,10 @@ using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Auth.ChangeUserName;
|
||||
|
||||
public sealed class ChangeUserNameCommandHandler(IIdentityService identityService, ICurrentUser currentUser)
|
||||
: ICommandHandler<ChangeUserNameCommand, Result>
|
||||
public sealed class ChangeUserNameCommandHandler(
|
||||
IIdentityService identityService,
|
||||
ICurrentUser currentUser
|
||||
) : ICommandHandler<ChangeUserNameCommand, Result>
|
||||
{
|
||||
public Task<Result> Handle(ChangeUserNameCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
namespace PnvPanel.Application.Auth;
|
||||
|
||||
public sealed record CurrentUserDto(Guid Id, string UserName, string Role, bool IsActivated, bool TelegramLinked);
|
||||
public sealed record CurrentUserDto(
|
||||
Guid Id,
|
||||
string UserName,
|
||||
string Role,
|
||||
bool IsActivated,
|
||||
bool TelegramLinked
|
||||
);
|
||||
|
||||
+25
-8
@@ -6,27 +6,44 @@ using PnvPanel.Domain.Configs;
|
||||
|
||||
namespace PnvPanel.Application.Auth.DeleteMyAccount;
|
||||
|
||||
public sealed class DeleteMyAccountCommandHandler(IAppDbContext dbContext, IIdentityService identityService, IXuiPanelGateway gateway, ICurrentUser currentUser)
|
||||
: ICommandHandler<DeleteMyAccountCommand, Result>
|
||||
public sealed class DeleteMyAccountCommandHandler(
|
||||
IAppDbContext dbContext,
|
||||
IIdentityService identityService,
|
||||
IXuiPanelGateway gateway,
|
||||
ICurrentUser currentUser
|
||||
) : ICommandHandler<DeleteMyAccountCommand, Result>
|
||||
{
|
||||
public async Task<Result> Handle(DeleteMyAccountCommand command, CancellationToken cancellationToken)
|
||||
public async Task<Result> Handle(
|
||||
DeleteMyAccountCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return Result.Failure(AuthErrors.Unauthorized);
|
||||
|
||||
var configs = await dbContext.VpnConfigs
|
||||
.Where(c => c.UserId == userId && c.Status != ConfigStatus.Revoked)
|
||||
var configs = await dbContext
|
||||
.VpnConfigs.Where(c => c.UserId == userId && c.Status != ConfigStatus.Revoked)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
foreach (var config in configs)
|
||||
{
|
||||
var inbound = await dbContext.Inbounds.AsNoTracking().FirstOrDefaultAsync(i => i.Id == config.InboundId, cancellationToken);
|
||||
var inbound = await dbContext
|
||||
.Inbounds.AsNoTracking()
|
||||
.FirstOrDefaultAsync(i => i.Id == config.InboundId, cancellationToken);
|
||||
var node = inbound is null
|
||||
? null
|
||||
: await dbContext.Nodes.AsNoTracking().FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
|
||||
: await dbContext
|
||||
.Nodes.AsNoTracking()
|
||||
.FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
|
||||
|
||||
if (inbound is not null && node is not null)
|
||||
await gateway.RemoveClientAsync(node, inbound.RemoteInboundId, config.ClientExternalId, config.Protocol, cancellationToken);
|
||||
await gateway.RemoveClientAsync(
|
||||
node,
|
||||
inbound.RemoteInboundId,
|
||||
config.ClientExternalId,
|
||||
config.Protocol,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
config.Revoke();
|
||||
}
|
||||
|
||||
@@ -7,11 +7,19 @@ namespace PnvPanel.Application.Auth.Login;
|
||||
public sealed class LoginCommandHandler(
|
||||
IIdentityService identityService,
|
||||
IJwtTokenService jwtTokenService,
|
||||
IRefreshTokenService refreshTokenService) : ICommandHandler<LoginCommand, Result<AuthResult>>
|
||||
IRefreshTokenService refreshTokenService
|
||||
) : ICommandHandler<LoginCommand, Result<AuthResult>>
|
||||
{
|
||||
public async Task<Result<AuthResult>> Handle(LoginCommand command, CancellationToken cancellationToken)
|
||||
public async Task<Result<AuthResult>> Handle(
|
||||
LoginCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var credentialsResult = await identityService.ValidateCredentialsAsync(command.UserName, command.Password, cancellationToken);
|
||||
var credentialsResult = await identityService.ValidateCredentialsAsync(
|
||||
command.UserName,
|
||||
command.Password,
|
||||
cancellationToken
|
||||
);
|
||||
if (!credentialsResult.IsSuccess)
|
||||
return Result.Failure<AuthResult>(credentialsResult.Error);
|
||||
|
||||
@@ -23,14 +31,26 @@ public sealed class LoginCommandHandler(
|
||||
var (accessToken, accessExpiresAt) = jwtTokenService.GenerateAccessToken(user);
|
||||
var refreshToken = await refreshTokenService.IssueAsync(user.Id, cancellationToken);
|
||||
|
||||
var telegramInfo = await identityService.GetTelegramLinkInfoAsync(profile.Id, cancellationToken);
|
||||
var dto = new CurrentUserDto(profile.Id, profile.UserName, profile.Role, profile.IsActivated, telegramInfo.IsLinked);
|
||||
var telegramInfo = await identityService.GetTelegramLinkInfoAsync(
|
||||
profile.Id,
|
||||
cancellationToken
|
||||
);
|
||||
var dto = new CurrentUserDto(
|
||||
profile.Id,
|
||||
profile.UserName,
|
||||
profile.Role,
|
||||
profile.IsActivated,
|
||||
telegramInfo.IsLinked
|
||||
);
|
||||
|
||||
return Result.Success(new AuthResult(
|
||||
accessToken,
|
||||
accessExpiresAt,
|
||||
refreshToken.RawToken,
|
||||
refreshToken.ExpiresAt,
|
||||
dto));
|
||||
return Result.Success(
|
||||
new AuthResult(
|
||||
accessToken,
|
||||
accessExpiresAt,
|
||||
refreshToken.RawToken,
|
||||
refreshToken.ExpiresAt,
|
||||
dto
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,15 @@ using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Auth.Me;
|
||||
|
||||
public sealed class GetCurrentUserQueryHandler(IIdentityService identityService, ICurrentUser currentUser)
|
||||
: IQueryHandler<GetCurrentUserQuery, Result<CurrentUserDto>>
|
||||
public sealed class GetCurrentUserQueryHandler(
|
||||
IIdentityService identityService,
|
||||
ICurrentUser currentUser
|
||||
) : IQueryHandler<GetCurrentUserQuery, Result<CurrentUserDto>>
|
||||
{
|
||||
public async Task<Result<CurrentUserDto>> Handle(GetCurrentUserQuery query, CancellationToken cancellationToken)
|
||||
public async Task<Result<CurrentUserDto>> Handle(
|
||||
GetCurrentUserQuery query,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return Result.Failure<CurrentUserDto>(AuthErrors.Unauthorized);
|
||||
@@ -16,8 +21,19 @@ public sealed class GetCurrentUserQueryHandler(IIdentityService identityService,
|
||||
if (profile is null)
|
||||
return Result.Failure<CurrentUserDto>(AuthErrors.Unauthorized);
|
||||
|
||||
var telegramInfo = await identityService.GetTelegramLinkInfoAsync(userId, cancellationToken);
|
||||
var telegramInfo = await identityService.GetTelegramLinkInfoAsync(
|
||||
userId,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
return Result.Success(new CurrentUserDto(profile.Id, profile.UserName, profile.Role, profile.IsActivated, telegramInfo.IsLinked));
|
||||
return Result.Success(
|
||||
new CurrentUserDto(
|
||||
profile.Id,
|
||||
profile.UserName,
|
||||
profile.Role,
|
||||
profile.IsActivated,
|
||||
telegramInfo.IsLinked
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,29 +7,51 @@ namespace PnvPanel.Application.Auth.Refresh;
|
||||
public sealed class RefreshCommandHandler(
|
||||
IIdentityService identityService,
|
||||
IJwtTokenService jwtTokenService,
|
||||
IRefreshTokenService refreshTokenService) : ICommandHandler<RefreshCommand, Result<AuthResult>>
|
||||
IRefreshTokenService refreshTokenService
|
||||
) : ICommandHandler<RefreshCommand, Result<AuthResult>>
|
||||
{
|
||||
public async Task<Result<AuthResult>> Handle(RefreshCommand command, CancellationToken cancellationToken)
|
||||
public async Task<Result<AuthResult>> Handle(
|
||||
RefreshCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var rotated = await refreshTokenService.RotateAsync(command.RawRefreshToken, cancellationToken);
|
||||
var rotated = await refreshTokenService.RotateAsync(
|
||||
command.RawRefreshToken,
|
||||
cancellationToken
|
||||
);
|
||||
if (!rotated.IsSuccess)
|
||||
return Result.Failure<AuthResult>(rotated.Error);
|
||||
|
||||
var profile = await identityService.GetProfileAsync(rotated.Value.UserId, cancellationToken);
|
||||
var profile = await identityService.GetProfileAsync(
|
||||
rotated.Value.UserId,
|
||||
cancellationToken
|
||||
);
|
||||
if (profile is null)
|
||||
return Result.Failure<AuthResult>(AuthErrors.InvalidRefreshToken);
|
||||
|
||||
var authUser = new AuthenticatedUser(profile.Id, profile.UserName, profile.Role);
|
||||
var (accessToken, accessExpiresAt) = jwtTokenService.GenerateAccessToken(authUser);
|
||||
|
||||
var telegramInfo = await identityService.GetTelegramLinkInfoAsync(profile.Id, cancellationToken);
|
||||
var dto = new CurrentUserDto(profile.Id, profile.UserName, profile.Role, profile.IsActivated, telegramInfo.IsLinked);
|
||||
var telegramInfo = await identityService.GetTelegramLinkInfoAsync(
|
||||
profile.Id,
|
||||
cancellationToken
|
||||
);
|
||||
var dto = new CurrentUserDto(
|
||||
profile.Id,
|
||||
profile.UserName,
|
||||
profile.Role,
|
||||
profile.IsActivated,
|
||||
telegramInfo.IsLinked
|
||||
);
|
||||
|
||||
return Result.Success(new AuthResult(
|
||||
accessToken,
|
||||
accessExpiresAt,
|
||||
rotated.Value.RawToken,
|
||||
rotated.Value.ExpiresAt,
|
||||
dto));
|
||||
return Result.Success(
|
||||
new AuthResult(
|
||||
accessToken,
|
||||
accessExpiresAt,
|
||||
rotated.Value.RawToken,
|
||||
rotated.Value.ExpiresAt,
|
||||
dto
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Auth.Register;
|
||||
|
||||
public sealed record RegisterCommand(string UserName, string Password) : ICommand<Result<RegisterResult>>;
|
||||
public sealed record RegisterCommand(string UserName, string Password)
|
||||
: ICommand<Result<RegisterResult>>;
|
||||
|
||||
public sealed record RegisterResult(Guid Id, string UserName);
|
||||
|
||||
@@ -7,9 +7,16 @@ namespace PnvPanel.Application.Auth.Register;
|
||||
public sealed class RegisterCommandHandler(IIdentityService identityService)
|
||||
: ICommandHandler<RegisterCommand, Result<RegisterResult>>
|
||||
{
|
||||
public async Task<Result<RegisterResult>> Handle(RegisterCommand command, CancellationToken cancellationToken)
|
||||
public async Task<Result<RegisterResult>> Handle(
|
||||
RegisterCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var result = await identityService.CreateUserAsync(command.UserName, command.Password, cancellationToken);
|
||||
var result = await identityService.CreateUserAsync(
|
||||
command.UserName,
|
||||
command.Password,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
return result.IsSuccess
|
||||
? Result.Success(new RegisterResult(result.Value, command.UserName))
|
||||
|
||||
Reference in New Issue
Block a user