- Fixed song add form (3 HTMX bugs: reset on typeahead, wrong query param, artist-only find-or-create) - Added Played checkbox to add form; inline edit (✎/Save/Cancel) for setlist rows - View fixes: date format, location name instead of ID in jam list, notes on location detail, song count column, location name links to detail - Title typeahead + cross-filtering (artist↔title filter each other) - Fixed datalist accumulation bug: HTMX 2.0 inherits hx-swap from parent; added explicit hx-swap="innerHTML" on both inputs - Setlist sort by id (ULID = insertion order); created rejected by PocketBase - Location delete guard: OnRecordDelete hook blocks if jams exist; FK enforcement is app-level not SQLite-level Loose ends to pick up: - Focus-after-add not user-confirmed yet (setTimeout approach) - jams.participants and setlist.position still in DB schema but unused in UI (optional migration to clean up) - Logout flow and dashboard ranking not browser-tested
69 lines
1.9 KiB
Go
69 lines
1.9 KiB
Go
package web
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/pocketbase/pocketbase/core"
|
|
|
|
"code.osinet.fr/fgm/jamtrack/views"
|
|
)
|
|
|
|
const cookieName = "pb_auth"
|
|
|
|
// LoginGet renders the login form.
|
|
func LoginGet(e *core.RequestEvent) error {
|
|
return views.Login("").Render(e.Request.Context(), e.Response)
|
|
}
|
|
|
|
// LoginPost handles username/password authentication and sets the session cookie.
|
|
func LoginPost(e *core.RequestEvent) error {
|
|
username := e.Request.FormValue("username")
|
|
password := e.Request.FormValue("password")
|
|
|
|
record, err := e.App.FindFirstRecordByData("users", "username", username)
|
|
if err != nil || !record.ValidatePassword(password) {
|
|
return views.Login("Invalid username or password.").Render(e.Request.Context(), e.Response)
|
|
}
|
|
|
|
token, err := record.NewAuthToken()
|
|
if err != nil {
|
|
return views.Login("Authentication error. Please try again.").Render(e.Request.Context(), e.Response)
|
|
}
|
|
|
|
e.SetCookie(&http.Cookie{
|
|
Name: cookieName,
|
|
Value: token,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
return e.Redirect(http.StatusFound, "/")
|
|
}
|
|
|
|
// Logout clears the session cookie and redirects to the login page.
|
|
func Logout(e *core.RequestEvent) error {
|
|
e.SetCookie(&http.Cookie{
|
|
Name: cookieName,
|
|
Value: "",
|
|
Path: "/",
|
|
MaxAge: -1,
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
return e.Redirect(http.StatusFound, "/login")
|
|
}
|
|
|
|
// RequireAuth is a middleware that validates the session cookie and populates
|
|
// e.Auth. Unauthenticated requests are redirected to /login.
|
|
func RequireAuth(e *core.RequestEvent) error {
|
|
cookie, err := e.Request.Cookie(cookieName)
|
|
if err != nil || cookie.Value == "" {
|
|
return e.Redirect(http.StatusFound, "/login")
|
|
}
|
|
record, err := e.App.FindAuthRecordByToken(cookie.Value, core.TokenTypeAuth)
|
|
if err != nil {
|
|
return e.Redirect(http.StatusFound, "/login")
|
|
}
|
|
e.Auth = record
|
|
return e.Next()
|
|
}
|