Добавил ручную перепривязку

This commit is contained in:
2026-06-15 07:42:50 +03:00
parent 093211c9c7
commit 16a82572e7
10 changed files with 206 additions and 10 deletions
+3
View File
@@ -92,6 +92,7 @@ func NewRouter(d Deps) (http.Handler, error) {
r.Post("/ui/downloads/{id}/nobase", s.handleNoBase)
r.Post("/ui/downloads/{id}/defer", s.handleDefer)
r.Post("/ui/downloads/{id}/undo", s.handleUndo)
r.Post("/ui/downloads/{id}/relink", s.handleRelink)
// REST API.
r.Route("/api", func(r chi.Router) {
@@ -126,6 +127,7 @@ type downloadView struct {
Terminal bool
Reviewable bool // review/deferred — есть экран ревью
Undoable bool // done — можно откатить раскладку
Relinkable bool // reverted — можно перепривязать заново
}
func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) {
@@ -304,6 +306,7 @@ func toView(d store.Download) downloadView {
Terminal: d.State.IsTerminal(),
Reviewable: d.State == store.StateReview || d.State == store.StateDeferred,
Undoable: d.State == store.StateDone,
Relinkable: d.State == store.StateReverted,
}
}
+19
View File
@@ -193,6 +193,7 @@ type fakeReviewer struct {
applied []int64
deferred []int64
undone []int64
relinked []int64
cleared []int64
}
@@ -235,6 +236,10 @@ func (f *fakeReviewer) Undo(_ context.Context, id int64) error {
f.undone = append(f.undone, id)
return nil
}
func (f *fakeReviewer) Relink(_ context.Context, id int64) error {
f.relinked = append(f.relinked, id)
return nil
}
func (f *fakeReviewer) ChooseCandidate(_ context.Context, id, candidateID int64) error {
if f.chosen == nil {
f.chosen = map[int64]int64{}
@@ -444,3 +449,17 @@ func TestUndoAndDefer(t *testing.T) {
t.Errorf("undo=%v defer=%v", rv.undone, rv.deferred)
}
}
func TestRelink(t *testing.T) {
rv := &fakeReviewer{data: seriesReviewData()}
srv := newServer(t, httpapi.Deps{Ingestor: &fakeIngestor{}, Commander: &fakeCommander{},
Reader: &fakeReader{}, Reviewer: rv})
cl := noRedirectClient()
if _, err := cl.Post(srv.URL+"/ui/downloads/1/relink", "", nil); err != nil {
t.Fatal(err)
}
if len(rv.relinked) != 1 || rv.relinked[0] != 1 {
t.Errorf("relinked = %v, want [1]", rv.relinked)
}
}
+17
View File
@@ -20,6 +20,7 @@ type Reviewer interface {
IgnoreFile(ctx context.Context, id int64, src string) error
Defer(ctx context.Context, id int64) error
Undo(ctx context.Context, id int64) error
Relink(ctx context.Context, id int64) error
ChooseCandidate(ctx context.Context, id, candidateID int64) error
SetProviderID(ctx context.Context, id int64, provider, providerID string) error
ClearProvider(ctx context.Context, id int64) error
@@ -233,6 +234,22 @@ func (s *server) handleUndo(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusSeeOther)
}
// handleRelink повторно привязывает откатанную задачу: перезапускает
// распознавание, задача пройдёт recognizing → review для подтверждения.
func (s *server) handleRelink(w http.ResponseWriter, r *http.Request) {
id, err := pathID(r)
if err != nil {
redirectErr(w, r, "некорректный id")
return
}
if err := s.deps.Reviewer.Relink(r.Context(), id); err != nil {
s.deps.Logger.Warn("review action failed", "action", "relink", "id", id, "err", err)
redirectErr(w, r, err.Error())
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
// reviewAction — общий помощник: выполнить действие и вернуться на страницу
// ревью (с ошибкой в ?err при неудаче).
func (s *server) reviewAction(w http.ResponseWriter, r *http.Request, fn func(context.Context, int64) error) {