All checks were successful
check / check (push) Successful in 1m54s
Closes #51 The root path `/` now checks for an authenticated session and redirects accordingly: - **Authenticated users** → `303 See Other` redirect to `/sources` (the webhook dashboard) - **Unauthenticated users** → `303 See Other` redirect to `/pages/login` ### Changes - **`internal/handlers/index.go`** — Replaced the template-rendering `HandleIndex()` with a session-checking redirect handler. Removed `formatUptime` helper (dead code after this change). - **`internal/handlers/handlers.go`** — Removed `index.html` from the template map (no longer rendered). - **`internal/handlers/handlers_test.go`** — Replaced the old "handler is not nil" test with two proper redirect tests: - `unauthenticated redirects to login` — verifies 303 to `/pages/login` - `authenticated redirects to sources` — sets up an authenticated session cookie, verifies 303 to `/sources` - Removed `TestFormatUptime` (tested dead code). - **`README.md`** — Updated the API endpoints table to describe the new redirect behavior. ### How it works The handler calls `session.Get(r)` and `session.IsAuthenticated(sess)` — the same pattern used by the `RequireAuth` middleware and `HandleLoginPage`. No new dependencies or session logic introduced. The login flow is unaffected: `HandleLoginSubmit` redirects to `/` after successful login, which now forwards to `/sources` (one extra redirect hop, but correct and clean). Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de> Co-authored-by: clawbot <clawbot@eeqj.de> Reviewed-on: #52 Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
130 lines
3.1 KiB
Go
130 lines
3.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"go.uber.org/fx"
|
|
"go.uber.org/fx/fxtest"
|
|
"sneak.berlin/go/webhooker/internal/config"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
"sneak.berlin/go/webhooker/internal/delivery"
|
|
"sneak.berlin/go/webhooker/internal/globals"
|
|
"sneak.berlin/go/webhooker/internal/healthcheck"
|
|
"sneak.berlin/go/webhooker/internal/logger"
|
|
"sneak.berlin/go/webhooker/internal/session"
|
|
)
|
|
|
|
// noopNotifier is a no-op delivery.Notifier for tests.
|
|
type noopNotifier struct{}
|
|
|
|
func (n *noopNotifier) Notify([]delivery.DeliveryTask) {}
|
|
|
|
func TestHandleIndex(t *testing.T) {
|
|
var h *Handlers
|
|
var sess *session.Session
|
|
|
|
app := fxtest.New(
|
|
t,
|
|
fx.Provide(
|
|
globals.New,
|
|
logger.New,
|
|
func() *config.Config {
|
|
return &config.Config{
|
|
DataDir: t.TempDir(),
|
|
}
|
|
},
|
|
database.New,
|
|
database.NewWebhookDBManager,
|
|
healthcheck.New,
|
|
session.New,
|
|
func() delivery.Notifier { return &noopNotifier{} },
|
|
New,
|
|
),
|
|
fx.Populate(&h, &sess),
|
|
)
|
|
app.RequireStart()
|
|
defer app.RequireStop()
|
|
|
|
t.Run("unauthenticated redirects to login", func(t *testing.T) {
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
handler := h.HandleIndex()
|
|
handler.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusSeeOther, w.Code)
|
|
assert.Equal(t, "/pages/login", w.Header().Get("Location"))
|
|
})
|
|
|
|
t.Run("authenticated redirects to sources", func(t *testing.T) {
|
|
// Create a request, set up an authenticated session, then test
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Get a session and mark it as authenticated
|
|
s, err := sess.Get(req)
|
|
assert.NoError(t, err)
|
|
sess.SetUser(s, "test-user-id", "testuser")
|
|
err = sess.Save(req, w, s)
|
|
assert.NoError(t, err)
|
|
|
|
// Build a new request with the session cookie from the response
|
|
req2 := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
for _, cookie := range w.Result().Cookies() {
|
|
req2.AddCookie(cookie)
|
|
}
|
|
w2 := httptest.NewRecorder()
|
|
|
|
handler := h.HandleIndex()
|
|
handler.ServeHTTP(w2, req2)
|
|
|
|
assert.Equal(t, http.StatusSeeOther, w2.Code)
|
|
assert.Equal(t, "/sources", w2.Header().Get("Location"))
|
|
})
|
|
}
|
|
|
|
func TestRenderTemplate(t *testing.T) {
|
|
var h *Handlers
|
|
|
|
app := fxtest.New(
|
|
t,
|
|
fx.Provide(
|
|
globals.New,
|
|
logger.New,
|
|
func() *config.Config {
|
|
return &config.Config{
|
|
DataDir: t.TempDir(),
|
|
}
|
|
},
|
|
database.New,
|
|
database.NewWebhookDBManager,
|
|
healthcheck.New,
|
|
session.New,
|
|
func() delivery.Notifier { return &noopNotifier{} },
|
|
New,
|
|
),
|
|
fx.Populate(&h),
|
|
)
|
|
app.RequireStart()
|
|
defer app.RequireStop()
|
|
|
|
t.Run("handles missing templates gracefully", func(t *testing.T) {
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
data := map[string]interface{}{
|
|
"Version": "1.0.0",
|
|
}
|
|
|
|
// When a non-existent template name is requested, renderTemplate
|
|
// should return an internal server error
|
|
h.renderTemplate(w, req, "nonexistent.html", data)
|
|
|
|
// Should return internal server error when template is not found
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
})
|
|
}
|