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
+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 |