Implement username change functionality and enhance Telegram bot registration flow
CI / Backend (build + test) (push) Successful in 1m22s
CI / Frontend (lint + typecheck + build) (push) Successful in 32s

- Added a new endpoint for changing usernames, allowing users to update their login credentials via the API.
- Integrated username change functionality into the settings page, providing a user-friendly interface for this action.
- Enhanced the Telegram bot to support user registration directly through the bot, including username generation and password delivery.
- Updated documentation to reflect the new username change endpoint and registration flow through the Telegram bot.
This commit is contained in:
Leonid Pershin
2026-07-02 18:57:36 +03:00
parent 1452e5c4af
commit cf3d8fcad8
19 changed files with 346 additions and 22 deletions
+1
View File
@@ -19,6 +19,7 @@ REST поверх HTTP/JSON, авторизация — `Authorization: Bearer <
| POST | `/api/auth/refresh` | — | — (refresh из cookie) | то же, что login; ротация cookie |
| POST | `/api/auth/logout` | user | — | `204 No Content` |
| POST | `/api/auth/change-password` | user | `{ currentPassword, newPassword }` | `204 No Content` |
| POST | `/api/auth/change-username` | user | `{ newUserName }` | `204 No Content` |
| GET | `/api/auth/me` | user | — | `{ id, userName, role, isActivated, telegramLinked }` |
| DELETE| `/api/auth/me` | user | — | `204 No Content` |
+9 -1
View File
@@ -90,6 +90,13 @@
- Библиотека Telegram.Bot, `TelegramBotHostedService` (long polling) в процессе Api, `IOptions<TelegramOptions>`.
- Домен: поля Telegram у `AppUser`, `TelegramLinkToken`, `TelegramLoginRequest`.
- Флоу привязки (`LinkTelegramCommand`) + эндпоинт `link-token`/`unlink`.
- Регистрация прямо из бота (`RegisterViaTelegramCommand`, кнопка «📝 Зарегистрироваться» при `/start`
и в местах, где боту нужен привязанный аккаунт): логин — `@username` из Telegram, при отсутствии
или занятости — Telegram id; пароль генерируется (`RandomNumberGenerator`, гарантированы заглавная
буква/строчная/цифра под текущую политику пароля) и присылается в чат один раз. Новый аккаунт —
роль `user`, `IsActivated = false`, активация как у обычной регистрации. Логин можно сменить в
Настройках (`ChangeUserNameCommand`, `POST /api/auth/change-username`) — актуально, если логин
получился числовым (Telegram id).
- Passwordless-вход: `login-request` + подтверждение в боте (`ApproveTelegramLoginCommand`) → выпуск JWT; поллинг завершения на фронте (`GET /api/auth/telegram/login-request/{id}`).
- Команды бота: `/start` (+ `link_<token>`/`login_<requestId>` deep-link payload), «Мои конфиги»
(`/configs` — по сообщению на конфиг, с inline-кнопкой «🔗 Показать ссылку», раскрывающей connection
@@ -119,7 +126,8 @@
## Backlog (после MVP)
- Полное самообслуживание в боте (создание/ротация/отзыв конфигов) — в MVP бот read-only.
- Полная регистрация аккаунта через Telegram (в MVP — только привязка); Telegram Login Widget как альтернатива.
- Telegram Login Widget как альтернатива кнопке-боту (сама регистрация/вход через бота уже реализованы —
см. M7 и [telegram-bot.md](telegram-bot.md)).
- Тарифы/биллинг/платежи, автопродление, промокоды.
- Реферальная программа; расширенные уведомления (через Telegram/веб — email в проекте не используется).
- Балансировка/выбор оптимальной ноды, автоскейл.
+35 -7
View File
@@ -18,13 +18,18 @@ Telegram-бот — **второй канал доставки** (presentation-
4. **DM-уведомления пользователю** (если Telegram привязан): активация аккаунта, блокировка,
принудительный отзыв конфига админом.
5. **Отвязка**`/unlink`.
6. **Регистрация прямо из бота** — кнопка «📝 Зарегистрироваться» показывается там, где боту нужен
привязанный аккаунт, а Telegram ещё не привязан (`/start`, `/help`, `/configs`, запрос passwordless-
входа). Логин — `@username` из Telegram; если его нет или он уже занят на сайте — используется
Telegram id (гарантированно уникален). Пароль генерируется и присылается в чат один раз — сохраните
его сразу, при желании логин и пароль можно сменить в Настройках на сайте. Новый аккаунт получает
роль `user` и `IsActivated = false` — активация нужна как для обычной регистрации на сайте.
**Не реализовано / backlog:**
- QR-картинкой и агрегированная подписка в самом боте (только текстовая ссылка на конфиг по кнопке).
- Отдельная команда `/resetpassword` с одноразовой ссылкой — восстановление пароля сейчас идёт
только через обычный passwordless-вход (`/start login_<n>`) + смену пароля в настройках на сайте.
- Webhook-транспорт — только long polling, конфигурации режима/URL в коде нет.
- Регистрация нового аккаунта из бота (только привязка существующего).
- Полное самообслуживание (создание/ротация/отзыв конфигов) — бот **read-only** по конфигам (только
просмотр списка и показ существующей ссылки по кнопке).
@@ -92,10 +97,30 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
`refresh` уже пришёл в httpOnly cookie (та же логика cookie, что и обычный логин, включая
`Secure = request.IsHttps`). Запрос помечается `Consumed`.
Если Telegram **не привязан**бот сразу сообщает «Сначала привяжите Telegram к аккаунту на сайте»,
подтвердить вход невозможно. Регистрация целиком через Telegram — вне MVP.
Если Telegram **не привязан**подтвердить вход невозможно; бот присылает `NotLinkedMessage`
(«Сначала зарегистрируйтесь и войдите на сайте, затем привяжите Telegram...») с кнопкой
«📝 Зарегистрироваться» — см. Флоу 3.
## Флоу 3 — Просмотр конфигов в боте
## Флоу 3 — Регистрация прямо из бота
Показывается кнопкой «📝 Зарегистрироваться» везде, где боту нужен привязанный аккаунт, а его нет
(`/start`, `/help`, `/configs`, запрос passwordless-входа для непривязанного Telegram).
1. Нажатие → callback `reg:new``RegisterViaTelegramCommand(telegramUserId, telegramUsername)`.
2. Если `TelegramUserId` уже привязан к какому-то аккаунту — `TelegramErrors.AlreadyLinked`, регистрация
не создаёт второй аккаунт.
3. Логин: пробуем `@username` из Telegram (`identityService.CreateUserAsync`); если username пуст или
занят на сайте — используем `TelegramUserId.ToString()` (гарантированно уникален). Пароль генерируется
(`RandomNumberGenerator`, 12 символов, гарантированы заглавная/строчная буква и цифра под текущую
политику пароля) и присылается в чат **один раз**, отдельным HTML-сообщением (`<code>`).
4. Сразу после создания — `identityService.LinkTelegramAsync(...)`, аккаунт уже привязан, без
отдельного шага как во Флоу 1.
5. Новый аккаунт — роль `user`, `IsActivated = false`: активация нужна как для обычной регистрации на
сайте, `/configs` будет недоступен до неё.
6. Логин можно сменить в Настройках на сайте (`ChangeUserNameCommand`, `POST /api/auth/change-username`)
— актуально, если логином стал Telegram id.
## Флоу 4 — Просмотр конфигов в боте
1. Привязанный пользователь: `/configs`.
2. Бот вызывает `GetMyConfigsQuery` (тот же, что и веб) от пользователя, найденного по `TelegramUserId`.
@@ -103,10 +128,12 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
inline-кнопка «🔗 Показать ссылку» (кроме отозванных — там кнопки нет). Если конфигов нет —
«У вас пока нет конфигов.»
4. Нажатие кнопки → callback `cfg:link:{configId}` → бот вызывает `GetConfigLinkQuery` (тот же, что
эндпоинт `/api/configs/{id}/link`) от текущего пользователя и присылает connection string отдельным
сообщением. Ссылка не дублируется никуда до явного нажатия. QR-картинки нет — только текст.
эндпоинт `/api/configs/{id}/link`) от текущего пользователя и **редактирует то же сообщение**
(`EditMessageText`), дописывая ссылку моноширинным блоком (`<code>`, тап = копирование целиком) и
убирая кнопку — не плодит отдельное сообщение с сырым URL. Ссылка не раскрывается нигде до явного
нажатия. QR-картинки нет — только текст.
## Флоу 4 — Обработка активации админом в боте
## Флоу 5 — Обработка активации админом в боте
1. Пользователь отправляет запрос активации (сайт: `POST /api/activation/request { comment }`) →
`RequestActivationCommandHandler` шлёт SignalR `activationRequested` группе `admins` **и** вызывает
@@ -133,6 +160,7 @@ Telegram ──updates──► TelegramBotHostedService → PnvBotUpdateHandl
| `/configs` | Список конфигов с кнопкой «Показать ссылку» на каждом | да |
| `/unlink` | Отвязать Telegram от аккаунта | да |
| `/help` | Справка (то же сообщение, что `/start`) | нет |
| «📝 Зарегистрироваться» (`reg:new`) | Регистрация нового аккаунта прямо из бота (Флоу 3) | нет (нужно, чтобы **не** был привязан) |
| «✅ Активировать»/«❌ Отклонить» | (admin) решение по конкретному запросу активации | админ по env |
| `/requests` | (admin) список ожидающих запросов активации (до 10) | админ по env |
+1 -2
View File
@@ -107,13 +107,12 @@ PnvPanel **не заменяет** Xray/3x-ui — он оркестрирует
- Создание/просмотр/отзыв конфигов пользователем (проверки активации, квоты, доступа роли к инбаунду); ссылка-подписка + QR.
- Синхронизация трафика (фоновая) + realtime-обновления по SignalR.
- Базовая статистика для админа.
- Telegram-бот: ссылка на сайт, просмотр конфигов, привязка Telegram и passwordless-вход.
- Telegram-бот: ссылка на сайт, просмотр конфигов, привязка/регистрация через Telegram и passwordless-вход.
- Светлая/тёмная тема сайта.
- Страница инструкций по подключению + каталог приложений по ОС (админ ведёт, юзер видит сгруппировано).
- Единый Docker-образ (фронт+бек) + PostgreSQL в docker-compose.
**За рамками MVP (backlog):**
- Полная регистрация аккаунта через Telegram (в MVP — только привязка существующего).
- Тарифы/биллинг/платежи.
- Многоуровневые квоты, автопродление, промокоды.
- Балансировка нагрузки между нодами, автоскейл.