Enhance user plan management and update related endpoints
CI / Backend (build + test) (push) Failing after 1m23s
CI / Frontend (lint + typecheck + build) (push) Successful in 34s

- Added new configuration options for user plans in `.env.example`, including `Plans__MaxCustomConfigCount` and `Plans__MinCustomConfigCount`.
- Introduced `MapPlanEndpoints` in `Program.cs` to handle plan-related API routes.
- Implemented `SetUserPlan` endpoint in `RoleEndpoints` to allow admins to assign plans to users.
- Removed deprecated role request approval endpoints from `AdminSupportEndpoints`.
- Updated `ITelegramNotifier` and related classes to reflect changes in role request handling and payment notifications.
- Refactored role management commands to remove `MaxConfigs` and focus on `MaxIpLimit` and billing settings.
- Enhanced billing request handling to accommodate plan changes instead of role changes.
- Updated various interfaces and command handlers to support new plan management features.
This commit is contained in:
Leonid Pershin
2026-07-23 22:52:20 +03:00
parent 2c5b730500
commit fad03c2834
152 changed files with 4060 additions and 2240 deletions
+12 -27
View File
@@ -33,12 +33,12 @@ Telegram-бот — **второй канал доставки** (presentation-
Зарегистрироваться»; плюс кнопка «🌐 Сайт панели» со ссылкой на сайт, если задан `Telegram__PublicSiteUrl`
(пусто — кнопки нет). Слэш-команды `/configs`/`/unlink` продолжают работать как раньше — кнопки лишь
вызывают те же обработчики через callback (`menu:configs`/`menu:unlink`/`menu:back`).
8. **Админ: обработка заявок на роль поддержки** — при новой заявке (`SupportTicket.Type ==
RoleRequest`) админ получает сообщение с описанием (существующая роль либо параметры новой) и
обоснованием, жмёт «✅ Одобрить / ❌ Отклонить» **прямо в Telegram, без захода на сайт** — одобрение
создаёт роль (если новая) и назначает её пользователю той же командой, что и на сайте. Баг-репорты/
предложения — только уведомление с кнопкой-ссылкой на сайт, без инлайн-действий (переписка и
вложения удобнее там).
8. **Админ: обработка заявок на продление поддержки** — при новой заявке
(`SupportTicket.Type == ExtensionRequest`, только для billing-ролей) админ получает сообщение с
числом запрошенных дней и обоснованием, жмёт «✅ Одобрить / ❌ Отклонить» **прямо в Telegram, без
захода на сайт** — одобрение продлевает `BillingPaidUntil` той же командой, что и на сайте.
Баг-репорты/предложения — только уведомление с кнопкой-ссылкой на сайт, без инлайн-действий
(переписка и вложения удобнее там).
**Не реализовано:**
- QR-картинкой и агрегированная подписка в самом боте (только текстовая ссылка на конфиг по кнопке).
@@ -49,6 +49,7 @@ Telegram-бот — **второй канал доставки** (presentation-
просмотр списка и показ существующей ссылки по кнопке).
- Баг-репорты/предложения тикетов поддержки **не решаются из бота** (только уведомление-ссылка) —
ответы, вложения, resolve/close только на сайте.
- Смена тарифа (`ChangePlanCommand`) — только на сайте (`/plan`), в боте не решается.
## Размещение в архитектуре
@@ -182,23 +183,8 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
(`InlineKeyboardButton.WithUrl`, не callback) — тап открывает страницу тикета в браузере.
3. Дальше — только на сайте: переписка, вложения, resolve/close.
**Заявка на роль** — полностью решается в Telegram:
1. `CreateRoleRequestTicketCommandHandler` вызывает
`ITelegramNotifier.NotifyAdminsRoleRequestCreatedAsync(ticketId, userName, roleDescription, justification, ct)`
— `roleDescription` уже готовая строка (имя существующей роли либо «новая роль «X» (конфигов: N, IP: M)»).
2. Сообщение с кнопками **«✅ Одобрить» / «❌ Отклонить»** (callback `rrq:approve:{id}`/`rrq:reject:{id}`
— тот же 3-частный формат `prefix:action:guid`, что и `act:*` для активации).
3. Нажатие → проверка прав (`TrySetAdminCurrentUserAsync`, тот же, что для активации) →
`ApproveRoleRequestCommand`/`RejectRoleRequestCommand` (те же команды, что дёргает
`POST /api/admin/support/tickets/{id}/approve|reject` на сайте). При одобрении — если роль новая,
сперва создаётся `AppRole`, затем в любом случае назначается пользователю; тикет переходит в
`Resolved`/`Closed`. Нажавшему админу — короткое подтверждение, исходное сообщение редактируется
(дописывается статус), как и у `act:*`.
4. Пользователю (если Telegram привязан) — DM «✅ Ваша заявка на роль одобрена.» / «❌ Ваша заявка на
роль отклонена.».
**Заявка на продление** (`ExtensionRequest`, только для billing-ролей) — тот же паттерн, что и заявка
на роль, инлайн-кнопки с префиксом `erq:`:
**Заявка на продление** (`ExtensionRequest`, только для billing-ролей) — полностью решается в
Telegram, инлайн-кнопки с префиксом `erq:`:
1. `CreateExtensionRequestTicketCommandHandler` вызывает
`ITelegramNotifier.NotifyAdminsExtensionRequestCreatedAsync(ticketId, userName, requestedDays, justification, ct)`.
2. Кнопки **«✅ Одобрить» / «❌ Отклонить»** (callback `erq:approve:{id}`/`erq:reject:{id}`).
@@ -213,7 +199,7 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
Только для ролей с `AppRole.BillingEnabled` (см. [domain-model.md](domain-model.md#billing--подписка-по-сроку)).
Заявка (`PaymentRequest`) заводится и решается частично на сайте, частично в Telegram — симметрично
заявке на роль:
заявке на продление:
1. Пользователь создаёт заявку и жмёт «Я оплатил» на сайте (`/billing`) — бот в это не вовлечён,
кроме опциональной кнопки «Отправить реквизиты в Telegram» (DM самому себе для удобства, статус
@@ -221,11 +207,11 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
2. `MarkPaymentSentCommandHandler` вызывает
`ITelegramNotifier.NotifyAdminsPaymentRequestedAsync(requestId, userName, period, amount, ct)`.
3. Сообщение с кнопками **«✅ Подтвердить» / «❌ Отклонить»** (callback `pay:approve:{id}`/`pay:reject:{id}`
— тот же 3-частный формат, что и `rrq:*`/`act:*`).
— тот же 3-частный формат, что и `erq:*`/`act:*`).
4. Нажатие → проверка прав (`TrySetAdminCurrentUserAsync`) → `ConfirmPaymentRequestCommand`/
`RejectPaymentRequestCommand` (те же команды, что дёргает `POST /api/admin/billing/requests/{id}/confirm|reject`
на сайте). Подтверждение продлевает `AppUser.BillingPaidUntil` и возвращает приостановленные
конфиги в `Active`. Исходное сообщение редактируется (дописывается статус), как у `rrq:*`/`act:*`.
конфиги в `Active`. Исходное сообщение редактируется (дописывается статус), как у `erq:*`/`act:*`.
5. Пользователю (если Telegram привязан) — DM «✅ Оплата подтверждена. Доступ продлён до {дата}.» /
«❌ Заявка на оплату отклонена.».
@@ -261,7 +247,6 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
| «📝 Зарегистрироваться» (`reg:new`) | Регистрация нового аккаунта прямо из бота (Флоу 3) | нет (нужно, чтобы **не** был привязан) |
| «✅ Активировать»/«❌ Отклонить» | (admin) решение по конкретному запросу активации | админ по env |
| `/requests` | (admin) список ожидающих запросов активации (до 10) | админ по env |
| «✅ Одобрить»/«❌ Отклонить» (`rrq:*`) | (admin) решение по заявке на роль — создаёт/назначает роль | админ по env |
| «✅ Одобрить»/«❌ Отклонить» (`erq:*`) | (admin) решение по заявке на продление — продлевает `BillingPaidUntil` | админ по env |
| «✅ Подтвердить»/«❌ Отклонить» (`pay:*`) | (admin) решение по заявке на оплату — продлевает `BillingPaidUntil` | админ по env |
| «🌐 Открыть на сайте» | Ссылка на баг-репорт на сайте (только если задан `Telegram__PublicSiteUrl`) | админ по env |