Refactor messaging system to utilize LiteCqrs library
CI / Backend (build + test) (push) Failing after 1m28s
CI / Frontend (lint + typecheck + build) (push) Successful in 47s

- Replaced instances of the previous messaging system with LiteCqrs across various application components, enhancing the CQRS implementation.
- Updated dependency injection to register LiteCqrs services and behaviors, streamlining command and query handling.
- Adjusted multiple command and query handlers to align with the new messaging framework, ensuring consistent functionality and improved maintainability.
- Added LiteCqrs package reference in the project file for better dependency management.
This commit is contained in:
Leonid Pershin
2026-07-24 04:16:38 +03:00
parent 4e1b63645f
commit b05b76f32f
266 changed files with 577 additions and 641 deletions
+10 -5
View File
@@ -7,7 +7,10 @@
**PnvPanel** — self-service портал для VPN-конфигураций (VLESS/VMess/Trojan/Shadowsocks): пользователи
сами создают конфиги, админ управляет серверами и пользователями. Есть **Telegram-бот** (ссылка на
сайт, просмотр конфигов, passwordless-вход). Бэкенд оркестрирует панели **3x-ui** через
[`ThreeXui.Net`](https://github.com/mrleo1nid/ThreeXui.Net) и хранит проекцию домена в PostgreSQL.
[`ThreeXui.Net`](https://github.com/mrleo1nid/ThreeXui.Net), CQRS — через собственную библиотеку
[`LiteCqrs.Net`](https://github.com/mrleo1nid/LiteCqrs.Net) (на время разработки подключена как
`ProjectReference` из соседнего репозитория `D:\Github\LiteCqrs.Net`, ещё не опубликована в
NuGet/GitHub), и хранит проекцию домена в PostgreSQL.
Живые обновления — SignalR. Поставка — **единый Docker-образ** (фронт+бек+бот) + PostgreSQL в compose.
> Собрано и покрыто тестами, единый образ и compose-стек проверены живьём. Есть опциональный биллинг
@@ -25,8 +28,10 @@
## Стек
- **Backend**: C# / .NET 10, ASP.NET Core Web API, Clean Architecture, CQRS (**собственный тонкий
диспетчер**, без MediatR), EF Core 10 + Npgsql, ASP.NET Core Identity + JWT, SignalR, FluentValidation,
- **Backend**: C# / .NET 10, ASP.NET Core Web API, Clean Architecture, CQRS (через
[`LiteCqrs.Net`](https://github.com/mrleo1nid/LiteCqrs.Net) — собственная лёгкая
CQRS-библиотека, альтернатива MediatR с явным разделением Command/Query), EF Core 10 + Npgsql,
ASP.NET Core Identity + JWT, SignalR, FluentValidation,
Serilog. Маппинг DTO вручную (`FromDomain(...)`, без Mapster). OpenAPI — нативный
`Microsoft.AspNetCore.OpenApi` + Scalar UI (без Swashbuckle).
- **Frontend**: React 19 + Vite + TS, TanStack Query/Router, shadcn-стиль поверх Radix + Tailwind v4,
@@ -174,8 +179,8 @@ docker compose up -d # api + postgres (+ web)
## Ключевые решения
См. [tech-stack.md](docs/tech-stack.md#ключевые-решения-по-домену-и-поведению): CQRS — собственный
диспетчер (не MediatR); одна роль на пользователя; секреты нод — ASP.NET Data Protection; биллинг
См. [tech-stack.md](docs/tech-stack.md#ключевые-решения-по-домену-и-поведению): CQRS — через
LiteCqrs.Net (собственная библиотека, не MediatR); одна роль на пользователя; секреты нод — ASP.NET Data Protection; биллинг
опционален per-роль (недоступен для `admin`); i18n — RU+EN (react-i18next); Telegram — long polling,
только привязка (не signup); история трафика — простая таблица + TTL; логирование — Serilog.
+1
View File
@@ -29,6 +29,7 @@
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.21.0" />
<PackageVersion Include="Telegram.Bot" Version="22.10.2" />
<PackageVersion Include="ThreeXui.Net" Version="1.0.4" />
<PackageVersion Include="LiteCqrs.Net" Version="1.0.1" />
<!-- Тестирование (M8) -->
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
<PackageVersion Include="xunit" Version="2.9.3" />
@@ -1,7 +1,7 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Activation;
using PnvPanel.Application.Admin.Activation;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Activation;
using PnvPanel.Infrastructure.Identity;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Apps;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Domain.Apps;
using PnvPanel.Infrastructure.Identity;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Billing;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Billing;
using PnvPanel.Infrastructure.Identity;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Instructions;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Instructions;
using PnvPanel.Infrastructure.Identity;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Maintenance;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Infrastructure.Identity;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.News;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
using PnvPanel.Infrastructure.Identity;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Plans;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Infrastructure.Identity;
namespace PnvPanel.Api.Endpoints;
@@ -1,7 +1,7 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Pricing;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Infrastructure.Identity;
namespace PnvPanel.Api.Endpoints;
@@ -1,7 +1,7 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Audit;
using PnvPanel.Application.Admin.Stats;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Infrastructure.Identity;
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Support;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Support;
using PnvPanel.Application.Support.AddComment;
@@ -2,7 +2,7 @@ using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Configs;
using PnvPanel.Application.Admin.Users;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Configs;
using PnvPanel.Domain.Configs;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Apps;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Domain.Apps;
namespace PnvPanel.Api.Endpoints;
@@ -8,7 +8,7 @@ using PnvPanel.Application.Auth.Logout;
using PnvPanel.Application.Auth.Me;
using PnvPanel.Application.Auth.Refresh;
using PnvPanel.Application.Auth.Register;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
namespace PnvPanel.Api.Endpoints;
@@ -5,7 +5,7 @@ using PnvPanel.Application.Billing.CreatePaymentRequest;
using PnvPanel.Application.Billing.GetMyBillingStatus;
using PnvPanel.Application.Billing.MarkPaymentSent;
using PnvPanel.Application.Billing.SendRequisitesToTelegram;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Domain.Billing;
namespace PnvPanel.Api.Endpoints;
@@ -1,5 +1,5 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Configs;
using PnvPanel.Application.Configs.Create;
using PnvPanel.Application.Configs.Edit;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Inbounds;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Infrastructure.Identity;
namespace PnvPanel.Api.Endpoints;
@@ -1,5 +1,5 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Instructions;
namespace PnvPanel.Api.Endpoints;
@@ -1,5 +1,5 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
@@ -1,6 +1,6 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Nodes;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Infrastructure.Identity;
namespace PnvPanel.Api.Endpoints;
@@ -1,5 +1,5 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Plans;
namespace PnvPanel.Api.Endpoints;
@@ -2,7 +2,7 @@ using PnvPanel.Api.Common;
using PnvPanel.Application.Admin.Roles;
using PnvPanel.Application.Admin.Users;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Infrastructure.Identity;
namespace PnvPanel.Api.Endpoints;
@@ -1,6 +1,6 @@
using System.Text;
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Subscriptions;
namespace PnvPanel.Api.Endpoints;
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using PnvPanel.Api.Common;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Support;
using PnvPanel.Application.Support.AddComment;
@@ -1,7 +1,7 @@
using PnvPanel.Api.Common;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Telegram;
using PnvPanel.Domain.Telegram;
@@ -5,7 +5,7 @@ using PnvPanel.Application.Admin.Support;
using PnvPanel.Application.Billing;
using PnvPanel.Application.Billing.GetMyBillingStatus;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Configs.GetConfigLink;
using PnvPanel.Application.Configs.GetMyConfigs;
using PnvPanel.Application.Telegram;
@@ -354,246 +354,246 @@ public sealed class PnvBotUpdateHandler(
switch (parts[0])
{
case "login":
{
var result =
parts[1] == "approve"
? await sender.Send(
new ApproveTelegramLoginCommand(requestId, fromId),
cancellationToken
)
: await sender.Send(
new RejectTelegramLoginCommand(requestId, fromId),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
var statusText = result.IsSuccess
? (parts[1] == "approve" ? "✅ Вход подтверждён." : "❌ Вход отклонён.")
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
var result =
parts[1] == "approve"
? await sender.Send(
new ApproveTelegramLoginCommand(requestId, fromId),
cancellationToken
)
: await sender.Send(
new RejectTelegramLoginCommand(requestId, fromId),
cancellationToken
);
break;
}
case "act":
{
if (!await TrySetAdminCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Недостаточно прав.",
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
return;
}
var result =
parts[1] == "approve"
? await sender.Send(
new ApproveActivationCommand(requestId),
cancellationToken
)
: await sender.Send(
new RejectActivationCommand(requestId, Reason: null),
cancellationToken
if (callback.Message is not null)
{
var statusText = result.IsSuccess
? (parts[1] == "approve" ? "✅ Вход подтверждён." : "❌ Вход отклонён.")
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
// Редактируем исходное сообщение с запросом вместо отдельного — иначе кнопки
// «Активировать/Отклонить» остаются висеть под уже обработанным запросом (в т.ч.
// если его обработали в другом месте — на сайте или из другого чата).
var statusText = result.IsSuccess
? (
parts[1] == "approve"
? "✅ Пользователь активирован."
: "❌ Запрос отклонён."
)
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
break;
}
case "erq":
{
if (!await TrySetAdminCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Недостаточно прав.",
cancellationToken: cancellationToken
);
return;
}
var result =
parts[1] == "approve"
? await sender.Send(
new ApproveExtensionRequestCommand(requestId),
cancellationToken
)
: await sender.Send(
new RejectExtensionRequestCommand(requestId, Reason: null),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
var statusText = result.IsSuccess
? (
parts[1] == "approve"
? "✅ Заявка на продление одобрена."
: "❌ Заявка отклонена."
)
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
break;
}
case "pay":
{
if (!await TrySetAdminCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Недостаточно прав.",
cancellationToken: cancellationToken
);
return;
}
var result =
parts[1] == "approve"
? await sender.Send(
new ConfirmPaymentRequestCommand(requestId),
cancellationToken
)
: await sender.Send(
new RejectPaymentRequestCommand(requestId, Reason: null),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
var statusText = result.IsSuccess
? (
parts[1] == "approve"
? "✅ Оплата подтверждена."
: "❌ Оплата отклонена."
)
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
break;
}
case "cfg":
{
if (!await TrySetCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Telegram не привязан.",
cancellationToken: cancellationToken
);
return;
}
var linkResult = await sender.Send(
new GetConfigLinkQuery(requestId),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
cancellationToken: cancellationToken
);
if (!linkResult.IsSuccess)
{
await botClient.SendMessage(
chatId.Value,
$"Не удалось получить ссылку: {linkResult.Error.Message}",
cancellationToken: cancellationToken
);
return;
}
if (callback.Message is null)
break;
}
case "act":
{
if (!await TrySetAdminCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Недостаточно прав.",
cancellationToken: cancellationToken
);
return;
}
// Редактируем то же сообщение (не плодим отдельное с сырым URL) — ссылка моноширинным
// блоком, по нему в Telegram можно тапнуть и скопировать целиком одним движением.
// Убираем именно эту кнопку из клавиатуры — остальные конфиги и «В меню» остаются на месте.
var text =
$"{Escape(callback.Message.Text ?? "")}\n\n<code>{Escape(linkResult.Value.ConnectionString)}</code>";
var remainingRows = (callback.Message.ReplyMarkup?.InlineKeyboard ?? [])
.Where(row => row.All(b => b.CallbackData != data))
.ToArray();
var result =
parts[1] == "approve"
? await sender.Send(
new ApproveActivationCommand(requestId),
cancellationToken
)
: await sender.Send(
new RejectActivationCommand(requestId, Reason: null),
cancellationToken
);
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
replyMarkup: remainingRows.Length > 0
? new InlineKeyboardMarkup(remainingRows)
: null,
cancellationToken: cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
// Редактируем исходное сообщение с запросом вместо отдельного — иначе кнопки
// «Активировать/Отклонить» остаются висеть под уже обработанным запросом (в т.ч.
// если его обработали в другом месте — на сайте или из другого чата).
var statusText = result.IsSuccess
? (
parts[1] == "approve"
? "✅ Пользователь активирован."
: "❌ Запрос отклонён."
)
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
break;
}
break;
}
case "erq":
{
if (!await TrySetAdminCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Недостаточно прав.",
cancellationToken: cancellationToken
);
return;
}
var result =
parts[1] == "approve"
? await sender.Send(
new ApproveExtensionRequestCommand(requestId),
cancellationToken
)
: await sender.Send(
new RejectExtensionRequestCommand(requestId, Reason: null),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
var statusText = result.IsSuccess
? (
parts[1] == "approve"
? "✅ Заявка на продление одобрена."
: "❌ Заявка отклонена."
)
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
break;
}
case "pay":
{
if (!await TrySetAdminCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Недостаточно прав.",
cancellationToken: cancellationToken
);
return;
}
var result =
parts[1] == "approve"
? await sender.Send(
new ConfirmPaymentRequestCommand(requestId),
cancellationToken
)
: await sender.Send(
new RejectPaymentRequestCommand(requestId, Reason: null),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
result.IsSuccess ? "Готово" : result.Error.Message,
cancellationToken: cancellationToken
);
if (callback.Message is not null)
{
var statusText = result.IsSuccess
? (
parts[1] == "approve"
? "✅ Оплата подтверждена."
: "❌ Оплата отклонена."
)
: $"⚠️ {result.Error.Message}";
var text = $"{Escape(callback.Message.Text ?? "")}\n\n{statusText}";
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
cancellationToken: cancellationToken
);
}
break;
}
case "cfg":
{
if (!await TrySetCurrentUserAsync(services, fromId, cancellationToken))
{
await botClient.AnswerCallbackQuery(
callback.Id,
"Telegram не привязан.",
cancellationToken: cancellationToken
);
return;
}
var linkResult = await sender.Send(
new GetConfigLinkQuery(requestId),
cancellationToken
);
await botClient.AnswerCallbackQuery(
callback.Id,
cancellationToken: cancellationToken
);
if (!linkResult.IsSuccess)
{
await botClient.SendMessage(
chatId.Value,
$"Не удалось получить ссылку: {linkResult.Error.Message}",
cancellationToken: cancellationToken
);
return;
}
if (callback.Message is null)
break;
// Редактируем то же сообщение (не плодим отдельное с сырым URL) — ссылка моноширинным
// блоком, по нему в Telegram можно тапнуть и скопировать целиком одним движением.
// Убираем именно эту кнопку из клавиатуры — остальные конфиги и «В меню» остаются на месте.
var text =
$"{Escape(callback.Message.Text ?? "")}\n\n<code>{Escape(linkResult.Value.ConnectionString)}</code>";
var remainingRows = (callback.Message.ReplyMarkup?.InlineKeyboard ?? [])
.Where(row => row.All(b => b.CallbackData != data))
.ToArray();
await botClient.EditMessageText(
chatId.Value,
callback.Message.Id,
text,
parseMode: ParseMode.Html,
replyMarkup: remainingRows.Length > 0
? new InlineKeyboardMarkup(remainingRows)
: null,
cancellationToken: cancellationToken
);
break;
}
}
}
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Activation;
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Activation;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Activation;
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Activation;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Activation;
@@ -2,7 +2,7 @@ using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Activation;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Activation;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Activation;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Activation;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Activation;
@@ -2,7 +2,7 @@ using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Activation;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Activation;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Apps;
@@ -1,5 +1,5 @@
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Apps;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Apps;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Apps;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Apps;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Apps;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Apps;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Apps;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Billing;
@@ -4,7 +4,7 @@ using PnvPanel.Application.Auth;
using PnvPanel.Application.Billing;
using PnvPanel.Application.Common.Concurrency;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Billing;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Billing;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Billing;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Billing;
@@ -3,7 +3,7 @@ using PnvPanel.Application.Admin.Users;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Billing;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Billing;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Billing;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Billing;
@@ -4,7 +4,7 @@ using PnvPanel.Application.Auth;
using PnvPanel.Application.Billing;
using PnvPanel.Application.Common.Concurrency;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Billing;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Billing;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Billing;
@@ -1,5 +1,5 @@
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Configs;
using PnvPanel.Domain.Inbounds;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Configs;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Inbounds;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Configs;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Inbounds;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Inbounds;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Inbounds;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Instructions;
@@ -1,5 +1,5 @@
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Instructions;
using PnvPanel.Domain.Instructions;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Instructions;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Instructions;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Instructions;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Instructions;
using PnvPanel.Domain.Instructions;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Instructions;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Instructions;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Maintenance;
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Support;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Maintenance;
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Maintenance;
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Maintenance;
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Configs;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
@@ -1,5 +1,5 @@
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
using PnvPanel.Domain.News;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.News;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.News;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.News;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Nodes;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Nodes;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Nodes;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Nodes;
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Nodes;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Admin.Nodes;
@@ -1,5 +1,5 @@
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Nodes;
@@ -1,4 +1,4 @@
using PnvPanel.Application.Common.Messaging;
using LiteCqrs;
using PnvPanel.Application.Common.Models;
using PnvPanel.Domain.Nodes;

Some files were not shown because too many files have changed in this diff Show More