web-ui: добавлена страница группового удаления загрузок

- выбор → поимённое подтверждение → отчёт: пачка до 20 загрузок, гарды входа
  на обеих границах, потолок времени и остановка после трёх подряд отказов
  внешнего сервиса
- допуск полного удаления сведён в единую точку store.State.CanDelete() —
  worker, страница загрузки и Telegram больше не держат своих перечней
This commit is contained in:
av
2026-08-10 17:43:36 +03:00
parent a7c1efd8eb
commit 288be8ec34
35 changed files with 3185 additions and 31 deletions
+36
View File
@@ -333,3 +333,39 @@ func TestCreateDownloadPersistsDisplayName(t *testing.T) {
t.Fatalf("display_name = %q", d.DisplayName)
}
}
// Выборка для страницы группового удаления отдаёт ровно те состояния, где домен
// допускает полное удаление, — и ничего сверх них. Перебираем все состояния:
// разъезд запроса с предикатом иначе виден только на проде.
func TestListDeletableDownloads(t *testing.T) {
st := newTestStore(t)
ctx := context.Background()
all := []State{
StateCatched, StateDownloading, StateCompleted, StateRecognizing,
StateReview, StateLinking, StateDone, StateDeferred, StateStuck,
StateFailed, StateCancelled, StateReverted,
StateTargetMissing, StateOrphaned, StateDeleted,
}
byID := map[string]State{}
for i, s := range all {
byID[mkDownload(t, st, i+1, s, "задача "+string(s))] = s
}
got, err := st.ListDeletableDownloads(ctx)
if err != nil {
t.Fatal(err)
}
seen := map[State]bool{}
for _, d := range got {
if !d.State.CanDelete() {
t.Errorf("в выборке состояние %s, удаление из которого недоступно", d.State)
}
seen[d.State] = true
}
for _, s := range all {
if s.CanDelete() && !seen[s] {
t.Errorf("состояние %s допускает удаление, но в выборку не попало", s)
}
}
}