F-6 from t-paliad-074 architecture audit. The Gitea repo was renamed m/patholo → mAi/paliad → m/paliad, but go.mod still declared `mgit.msbls.de/m/patholo` and every internal import echoed the pre-rebrand name. Sweep: - go.mod: module path → mgit.msbls.de/m/paliad - All *.go files: imports rewritten via sed - README.md, docs/design-kanzlai-integration.md: mAi/paliad → m/paliad - Frontend issue-reference comments (mAi/paliad#N → m/paliad#N) in i18n.ts, theme.ts, sidebar.ts, app.ts, Sidebar.tsx, PWAHead.tsx, global.css Verified: go build/vet/test ./... clean, bun run build clean, no remaining mgit.msbls.de/m/patholo or mAi/paliad references outside docs that intentionally describe the rename history.
71 lines
2.2 KiB
Go
71 lines
2.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
|
|
"mgit.msbls.de/m/paliad/internal/auth"
|
|
"mgit.msbls.de/m/paliad/internal/services"
|
|
)
|
|
|
|
// GET /onboarding — first-login profile capture. The page is authenticated
|
|
// (user must have logged in), but it is NOT behind the onboarding gate — it
|
|
// is the one place a user without a paliad.users row is allowed to land.
|
|
func handleOnboardingPage(w http.ResponseWriter, r *http.Request) {
|
|
// If the user is already onboarded, send them to the dashboard so the
|
|
// page doesn't become a dead end after a refresh.
|
|
if dbSvc != nil {
|
|
if uid, ok := auth.UserIDFromContext(r.Context()); ok {
|
|
if u, err := dbSvc.users.GetByID(r.Context(), uid); err == nil && u != nil {
|
|
http.Redirect(w, r, "/dashboard", http.StatusFound)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
http.ServeFile(w, r, "dist/onboarding.html")
|
|
}
|
|
|
|
// POST /api/onboarding — creates the caller's paliad.users row. The id and
|
|
// email are pulled from the verified JWT claims so a user can't onboard as
|
|
// someone else.
|
|
func handleCreateOnboarding(w http.ResponseWriter, r *http.Request) {
|
|
if !requireDB(w) {
|
|
return
|
|
}
|
|
uid, ok := requireUser(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
claims, ok := auth.ClaimsFromContext(r.Context())
|
|
if !ok || claims.Email == "" {
|
|
writeJSON(w, http.StatusUnauthorized, map[string]string{
|
|
"error": "missing email claim — please sign out and back in",
|
|
})
|
|
return
|
|
}
|
|
|
|
var input services.CreateUserInput
|
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
|
|
return
|
|
}
|
|
|
|
u, err := dbSvc.users.Create(r.Context(), uid, claims.Email, input)
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, services.ErrUserAlreadyOnboarded):
|
|
writeJSON(w, http.StatusConflict, map[string]string{
|
|
"error": "onboarding already completed",
|
|
})
|
|
default:
|
|
// Validation errors from the service (bad office, missing
|
|
// job_title, empty display_name) come through as generic errors;
|
|
// surface them so the form can show a precise message.
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
}
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusCreated, u)
|
|
}
|