Fix stale Regular grounding and enforce three Regulars for onboarding
A background grounding result now applies only while the dinner is still pending under the normalized name the job searched: GroundPendingDinner and FailPendingDinnerGrounding match normalized_name, so a rename makes the old job's success or failure a no-op. Renaming a dinner still pending enqueues a fresh grounding job for the new name; if that cannot be enqueued, the dinner's grounding is failed so it is not left pending with no job. Completing onboarding (PATCH /api/v1/settings/household with onboarding_completed true) is refused with 400 invalid_settings until the household has at least three Regulars (status regular; archived and Quest log dinners do not count), and onboarding_completed_at is set only then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/auth"
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/db"
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/household"
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/store"
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/migrations"
|
||||
@@ -115,10 +117,30 @@ func TestPatchHouseholdSettings(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// newOnboardingRouter returns a router whose settings store holds regulars
|
||||
// Regulars.
|
||||
func newOnboardingRouter(t *testing.T, regulars int) http.Handler {
|
||||
t.Helper()
|
||||
st := newTestStore(t)
|
||||
if err := household.SeedSettings(context.Background(), st, "America/New_York"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := range regulars {
|
||||
now := store.Now().String()
|
||||
if _, err := db.New(st.Writer).CreateDinner(context.Background(), db.CreateDinnerParams{
|
||||
ID: store.NewID(), Name: fmt.Sprintf("Dinner %d", i), NormalizedName: fmt.Sprintf("dinner %d", i),
|
||||
Status: "regular", Origin: "regular", GroundingStatus: "pending", CreatedAt: now, UpdatedAt: now,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return newTestRouterWith(t, "dev", household.NewSettingsService(st), newTestRunner(t))
|
||||
}
|
||||
|
||||
func TestPatchHouseholdSettingsCompletesOnboarding(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, body := serve(t, newTestRouter(t, "dev"), signedIn(http.MethodPatch, settingsPath,
|
||||
rec, body := serve(t, newOnboardingRouter(t, household.MinRegulars), signedIn(http.MethodPatch, settingsPath,
|
||||
strings.NewReader(`{"onboarding_completed":true}`)))
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body)
|
||||
@@ -128,6 +150,30 @@ func TestPatchHouseholdSettingsCompletesOnboarding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPatchHouseholdSettingsOnboardingNeedsRegulars: completing onboarding
|
||||
// with fewer than three Regulars is refused and leaves it incomplete.
|
||||
func TestPatchHouseholdSettingsOnboardingNeedsRegulars(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for regulars := range household.MinRegulars {
|
||||
t.Run(fmt.Sprintf("%d Regulars", regulars), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
router := newOnboardingRouter(t, regulars)
|
||||
rec, _ := serve(t, router, signedIn(http.MethodPatch, settingsPath,
|
||||
strings.NewReader(`{"onboarding_completed":true}`)))
|
||||
if rec.Code != http.StatusBadRequest ||
|
||||
!strings.Contains(rec.Body.String(), `"code":"invalid_settings"`) ||
|
||||
!strings.Contains(rec.Body.String(), "onboarding_completed: add at least 3 Regulars first") {
|
||||
t.Fatalf("PATCH = %d %s, want 400 invalid_settings on onboarding_completed", rec.Code, rec.Body)
|
||||
}
|
||||
_, body := serve(t, router, signedIn(http.MethodGet, settingsPath, nil))
|
||||
if body["onboarding_completed_at"] != nil {
|
||||
t.Errorf("onboarding_completed_at = %#v after a refused completion, want null", body["onboarding_completed_at"])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchHouseholdSettingsRejected(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user