Add Telegram bot integration and enhance user management features
- Introduced Telegram.Bot package for bot functionality. - Updated user management to include Telegram linking and blocking features. - Enhanced activation request handling with notifications via Telegram. - Added new database entities for Telegram link tokens and login requests. - Implemented traffic synchronization for client stats in the XuiPanelGateway. - Updated application structure to support new test projects and improved dependency injection for Telegram services.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
using PnvPanel.Domain.Apps;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed record AdminAppDto(
|
||||
Guid Id, string Name, string DownloadUrl, OsPlatform OperatingSystem, string? Description,
|
||||
string? IconUrl, int SortOrder, bool IsEnabled)
|
||||
{
|
||||
public static AdminAppDto FromDomain(ClientApp app) => new(
|
||||
app.Id, app.Name, app.DownloadUrl.ToString(), app.OperatingSystem, app.Description,
|
||||
app.IconUrl, app.SortOrder, app.IsEnabled);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public static class AppErrors
|
||||
{
|
||||
public static readonly Error NotFound = Error.NotFound("Apps.NotFound", "Приложение не найдено.");
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
using PnvPanel.Domain.Apps;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed record CreateAppCommand(
|
||||
string Name, string DownloadUrl, OsPlatform OperatingSystem, string? Description, string? IconUrl, int SortOrder)
|
||||
: ICommand<Result<AdminAppDto>>;
|
||||
@@ -0,0 +1,20 @@
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
using PnvPanel.Domain.Apps;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed class CreateAppCommandHandler(IAppDbContext dbContext) : ICommandHandler<CreateAppCommand, Result<AdminAppDto>>
|
||||
{
|
||||
public Task<Result<AdminAppDto>> Handle(CreateAppCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var app = ClientApp.Create(
|
||||
command.Name, new Uri(command.DownloadUrl, UriKind.Absolute), command.OperatingSystem,
|
||||
command.Description, command.IconUrl, command.SortOrder);
|
||||
|
||||
dbContext.ClientApps.Add(app);
|
||||
|
||||
return Task.FromResult(Result.Success(AdminAppDto.FromDomain(app)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed class CreateAppCommandValidator : AbstractValidator<CreateAppCommand>
|
||||
{
|
||||
public CreateAppCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
|
||||
RuleFor(x => x.DownloadUrl).NotEmpty().MaximumLength(500);
|
||||
RuleFor(x => x.OperatingSystem).IsInEnum();
|
||||
RuleFor(x => x.Description).MaximumLength(300);
|
||||
RuleFor(x => x.SortOrder).GreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed record DeleteAppCommand(Guid AppId) : ICommand<Result>;
|
||||
@@ -0,0 +1,19 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed class DeleteAppCommandHandler(IAppDbContext dbContext) : ICommandHandler<DeleteAppCommand, Result>
|
||||
{
|
||||
public async Task<Result> Handle(DeleteAppCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var app = await dbContext.ClientApps.FirstOrDefaultAsync(a => a.Id == command.AppId, cancellationToken);
|
||||
if (app is null)
|
||||
return Result.Failure(AppErrors.NotFound);
|
||||
|
||||
dbContext.ClientApps.Remove(app);
|
||||
return Result.Success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed record ListAdminAppsQuery : IQuery<Result<IReadOnlyList<AdminAppDto>>>;
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed class ListAdminAppsQueryHandler(IAppDbContext dbContext) : IQueryHandler<ListAdminAppsQuery, Result<IReadOnlyList<AdminAppDto>>>
|
||||
{
|
||||
public async Task<Result<IReadOnlyList<AdminAppDto>>> Handle(ListAdminAppsQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
var apps = await dbContext.ClientApps.AsNoTracking()
|
||||
.OrderBy(a => a.OperatingSystem).ThenBy(a => a.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Success<IReadOnlyList<AdminAppDto>>(apps.Select(AdminAppDto.FromDomain).ToList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
using PnvPanel.Domain.Apps;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed record UpdateAppCommand(
|
||||
Guid AppId, string Name, string DownloadUrl, OsPlatform OperatingSystem, string? Description,
|
||||
string? IconUrl, int SortOrder, bool IsEnabled)
|
||||
: ICommand<Result<AdminAppDto>>;
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed class UpdateAppCommandHandler(IAppDbContext dbContext) : ICommandHandler<UpdateAppCommand, Result<AdminAppDto>>
|
||||
{
|
||||
public async Task<Result<AdminAppDto>> Handle(UpdateAppCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var app = await dbContext.ClientApps.FirstOrDefaultAsync(a => a.Id == command.AppId, cancellationToken);
|
||||
if (app is null)
|
||||
return Result.Failure<AdminAppDto>(AppErrors.NotFound);
|
||||
|
||||
app.Update(
|
||||
command.Name, new Uri(command.DownloadUrl, UriKind.Absolute), command.OperatingSystem,
|
||||
command.Description, command.IconUrl, command.SortOrder, command.IsEnabled);
|
||||
|
||||
return Result.Success(AdminAppDto.FromDomain(app));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Apps;
|
||||
|
||||
public sealed class UpdateAppCommandValidator : AbstractValidator<UpdateAppCommand>
|
||||
{
|
||||
public UpdateAppCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
|
||||
RuleFor(x => x.DownloadUrl).NotEmpty().MaximumLength(500);
|
||||
RuleFor(x => x.OperatingSystem).IsInEnum();
|
||||
RuleFor(x => x.Description).MaximumLength(300);
|
||||
RuleFor(x => x.SortOrder).GreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user