m's 2026-05-21 14:20 report: dashboard "Diese Woche" card linked to /deadlines?status=this_week but the 301 to /events?type=deadline dropped the query string, landing on the default Pending filter instead of the This-Week bucket. Two-part fix: 1. handleDeadlinesListRedirect now appends r.URL.RawQuery to the target so any filter (status, project_id, event_type, …) survives the redirect. Regression test pins all three shapes (no query, single param, multi param). 2. Dashboard summary cards point at the canonical /events?type=deadline&status=… URL directly — saves the 301 bounce and matches the URL the events page itself reads on load. The five card values (overdue/today/this_week/next_week/later) are all in STATUS_OPTIONS_DEADLINE in frontend/src/client/events.ts, so the events page filter chip picks them up natively.
86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
// Ensures the /projects/{id}/sub-projects alias from F-48 lands on the
|
|
// canonical /projects/{id}/children URL. The redirect is wired on the OUTER
|
|
// mux so it fires before auth middleware.
|
|
func TestRegisterLegacyRedirects_SubProjectsAlias(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
registerLegacyRedirects(mux)
|
|
|
|
cases := []struct {
|
|
path string
|
|
want string
|
|
}{
|
|
{"/projects/abc-123/sub-projects", "/projects/abc-123/children"},
|
|
{"/projects/abc-123/sub-projects?foo=bar", "/projects/abc-123/children?foo=bar"},
|
|
}
|
|
for _, tc := range cases {
|
|
req := httptest.NewRequest(http.MethodGet, tc.path, nil)
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusMovedPermanently {
|
|
t.Fatalf("%s: status = %d, want %d", tc.path, w.Code, http.StatusMovedPermanently)
|
|
}
|
|
if got := w.Header().Get("Location"); got != tc.want {
|
|
t.Fatalf("%s: Location = %q, want %q", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// t-paliad-224: /deadlines/calendar and /appointments/calendar 301 to
|
|
// the canonical /events Kalender tab. Pins the redirect target so a
|
|
// future refactor doesn't silently break the bookmark contract.
|
|
func TestStandaloneCalendarHandlers_RedirectToEventsKalender(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
handler http.HandlerFunc
|
|
want string
|
|
}{
|
|
{"deadlines", handleDeadlinesCalendarPage, "/events?type=deadline&view=calendar"},
|
|
{"appointments", handleAppointmentsCalendarPage, "/events?type=appointment&view=calendar"},
|
|
}
|
|
for _, tc := range cases {
|
|
req := httptest.NewRequest(http.MethodGet, "/x", nil) // path ignored — handler is direct
|
|
w := httptest.NewRecorder()
|
|
tc.handler(w, req)
|
|
if w.Code != http.StatusMovedPermanently {
|
|
t.Fatalf("%s: status = %d, want %d", tc.name, w.Code, http.StatusMovedPermanently)
|
|
}
|
|
if got := w.Header().Get("Location"); got != tc.want {
|
|
t.Fatalf("%s: Location = %q, want %q", tc.name, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// /deadlines list redirect must forward the incoming query string so legacy
|
|
// dashboard cards and external bookmarks like /deadlines?status=this_week
|
|
// land at /events?type=deadline&status=this_week instead of losing the
|
|
// filter. Regression for m's 2026-05-21 14:20 report.
|
|
func TestDeadlinesListRedirect_PreservesQueryString(t *testing.T) {
|
|
cases := []struct {
|
|
path string
|
|
want string
|
|
}{
|
|
{"/deadlines", "/events?type=deadline"},
|
|
{"/deadlines?status=this_week", "/events?type=deadline&status=this_week"},
|
|
{"/deadlines?status=overdue&project_id=abc", "/events?type=deadline&status=overdue&project_id=abc"},
|
|
}
|
|
for _, tc := range cases {
|
|
req := httptest.NewRequest(http.MethodGet, tc.path, nil)
|
|
w := httptest.NewRecorder()
|
|
handleDeadlinesListRedirect(w, req)
|
|
if w.Code != http.StatusMovedPermanently {
|
|
t.Fatalf("%s: status = %d, want 301", tc.path, w.Code)
|
|
}
|
|
if got := w.Header().Get("Location"); got != tc.want {
|
|
t.Fatalf("%s: Location = %q, want %q", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|