tgbot: выбор кандидата метабазы inline-кнопками в карточке ревью
Когда для распознавания сохранены кандидаты метабазы, карточка подтверждения бота показывает кнопку «🗂 База (N)». По ней двухшагово (как delete/dismiss) разворачивается список кандидатов inline-кнопками; выбор пиннит источник через worker.ChooseCandidate (ручной матч, без авто-раскладки) и обновляет карточку. Веб остаётся точкой точных правок (ручной ввод id/URL, «без базы»). Безопасность границы: id кандидата из callback_data валидируется как ULID (ident.Parse) до доменного вызова, как в вебе. Текст inline-кнопок Telegram не парсится как HTML — название кандидата в подписи не экранируется. SDD: change telegram-vybor-nahodok — дельта notifications (ADDED «Выбор кандидата метабазы из карточки подтверждения бота») + review (MODIFIED «Разделение труда транспортов»: быстрый выбор кандидата — Telegram-действие). Влито в specs, change заархивирован. Миграций БД нет (кандидаты уже в БД). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,7 @@ type Reviewer interface {
|
||||
ReviewData(ctx context.Context, id string) (*worker.ReviewData, error)
|
||||
Apply(ctx context.Context, id string) error
|
||||
Refine(ctx context.Context, id string, hint string) error
|
||||
ChooseCandidate(ctx context.Context, id, candidateID string) error
|
||||
SetType(ctx context.Context, id string, mediaType string) error
|
||||
Defer(ctx context.Context, id string) error
|
||||
Cancel(ctx context.Context, id string) error
|
||||
@@ -362,6 +363,33 @@ func (b *Bot) handleCallback(ctx context.Context, cq *tgbotapi.CallbackQuery) {
|
||||
b.answer(cq.ID, "Жду подсказку")
|
||||
b.send(chatID, "Ответьте сообщением с подсказкой для #"+idCode(id)+".", nil)
|
||||
return
|
||||
case "sources":
|
||||
// Первый шаг выбора базы: перечитываем задачу ради свежего списка
|
||||
// кандидатов и разворачиваем клавиатуру списка. Домен не трогаем.
|
||||
rd, rerr := b.reviewer.ReviewData(ctx, id)
|
||||
if rerr != nil {
|
||||
b.log.Warn("telegram sources review data failed", "download_id", id, "error", rerr)
|
||||
b.answer(cq.ID, "Ошибка")
|
||||
return
|
||||
}
|
||||
b.answer(cq.ID, "")
|
||||
b.editMarkup(chatID, msgID, b.candidatesKeyboard(rd))
|
||||
return
|
||||
case "srcback":
|
||||
// Возврат из списка кандидатов к обычной карточке (домен не трогаем).
|
||||
b.answer(cq.ID, "Отменено")
|
||||
b.refreshCard(ctx, chatID, msgID, id)
|
||||
return
|
||||
case "pick":
|
||||
// Выбор кандидата: val — id кандидата из callback_data (недоверенный
|
||||
// вход), валидируем как ULID на границе до доменного вызова.
|
||||
candidateID, perr := ident.Parse(val)
|
||||
if perr != nil {
|
||||
b.answer(cq.ID, "Кнопка устарела — откройте задачу в вебе")
|
||||
return
|
||||
}
|
||||
err = b.reviewer.ChooseCandidate(ctx, id, candidateID)
|
||||
note = "Источник выбран"
|
||||
default:
|
||||
b.answer(cq.ID, "")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user