fix(backend): Error-Logging in Screen-User-Handlern + Tenant-Lookup-Refactoring

Fehlende slog.Error-Aufrufe in HandleAddUserToScreen, HandleCreateScreenUser,
HandleDeleteScreenUser und HandleRemoveUserFromScreen ergänzt — DB-Fehler
wurden bisher komplett geschluckt und waren nicht diagnostizierbar.

Tenant-Lookup in EnsureAdminUser und CreateScreenUser aus SQL-Subqueries
in eigene Queries extrahiert für bessere Fehlermeldungen bei fehlendem Tenant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jesko Anschütz 2026-03-23 23:41:16 +01:00
parent 73c3d74098
commit c470ec532b
2 changed files with 32 additions and 15 deletions

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"html/template" "html/template"
"log/slog"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -202,6 +203,8 @@ func HandleCreateScreenUser(auth *store.AuthStore) http.HandlerFunc {
_, err := auth.CreateScreenUser(r.Context(), tenantSlug, username, password) _, err := auth.CreateScreenUser(r.Context(), tenantSlug, username, password)
if err != nil { if err != nil {
slog.Error("create screen user failed", "event", "create_screen_user_failed",
"tenant_slug", tenantSlug, "username", username, "err", err)
http.Redirect(w, r, "/admin?tab=users&msg=error_exists", http.StatusSeeOther) http.Redirect(w, r, "/admin?tab=users&msg=error_exists", http.StatusSeeOther)
return return
} }
@ -214,6 +217,8 @@ func HandleDeleteScreenUser(auth *store.AuthStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
userID := r.PathValue("userID") userID := r.PathValue("userID")
if err := auth.DeleteUser(r.Context(), userID); err != nil { if err := auth.DeleteUser(r.Context(), userID); err != nil {
slog.Error("delete screen user failed", "event", "delete_screen_user_failed",
"user_id", userID, "err", err)
http.Error(w, "Fehler beim Löschen", http.StatusInternalServerError) http.Error(w, "Fehler beim Löschen", http.StatusInternalServerError)
return return
} }
@ -235,6 +240,8 @@ func HandleAddUserToScreen(screens *store.ScreenStore) http.HandlerFunc {
return return
} }
if err := screens.AddUserToScreen(r.Context(), userID, screenID); err != nil { if err := screens.AddUserToScreen(r.Context(), userID, screenID); err != nil {
slog.Error("add user to screen failed", "event", "add_user_to_screen_failed",
"screen_id", screenID, "user_id", userID, "err", err)
http.Redirect(w, r, "/admin?msg=error_db", http.StatusSeeOther) http.Redirect(w, r, "/admin?msg=error_db", http.StatusSeeOther)
return return
} }
@ -248,6 +255,8 @@ func HandleRemoveUserFromScreen(screens *store.ScreenStore) http.HandlerFunc {
screenID := r.PathValue("screenID") screenID := r.PathValue("screenID")
userID := r.PathValue("userID") userID := r.PathValue("userID")
if err := screens.RemoveUserFromScreen(r.Context(), userID, screenID); err != nil { if err := screens.RemoveUserFromScreen(r.Context(), userID, screenID); err != nil {
slog.Error("remove user from screen failed", "event", "remove_user_from_screen_failed",
"screen_id", screenID, "user_id", userID, "err", err)
http.Error(w, "db error", http.StatusInternalServerError) http.Error(w, "db error", http.StatusInternalServerError)
return return
} }

View file

@ -136,15 +136,19 @@ func (s *AuthStore) EnsureAdminUser(ctx context.Context, tenantSlug, password st
return fmt.Errorf("auth: hash password: %w", err) return fmt.Errorf("auth: hash password: %w", err)
} }
var tenantID string
err = s.pool.QueryRow(ctx, `select id from tenants where slug = $1`, tenantSlug).Scan(&tenantID)
if err != nil {
if err == pgx.ErrNoRows {
return fmt.Errorf("auth: tenant not found: %s", tenantSlug)
}
return fmt.Errorf("auth: resolve tenant: %w", err)
}
_, err = s.pool.Exec(ctx, _, err = s.pool.Exec(ctx,
`insert into users(tenant_id, username, password_hash, role) `insert into users(tenant_id, username, password_hash, role)
values( values($1, 'admin', $2, 'admin')`,
(select id from tenants where slug = $1), tenantID, string(hash))
'admin',
$2,
'admin'
)`,
tenantSlug, string(hash))
if err != nil { if err != nil {
return fmt.Errorf("auth: create admin user: %w", err) return fmt.Errorf("auth: create admin user: %w", err)
} }
@ -156,6 +160,15 @@ func (s *AuthStore) EnsureAdminUser(ctx context.Context, tenantSlug, password st
// Returns pgx.ErrNoRows if the tenant does not exist, or a wrapped error if // Returns pgx.ErrNoRows if the tenant does not exist, or a wrapped error if
// the username is already taken (unique constraint violation). // the username is already taken (unique constraint violation).
func (s *AuthStore) CreateScreenUser(ctx context.Context, tenantSlug, username, password string) (*User, error) { func (s *AuthStore) CreateScreenUser(ctx context.Context, tenantSlug, username, password string) (*User, error) {
var tenantID string
err := s.pool.QueryRow(ctx, `select id from tenants where slug = $1`, tenantSlug).Scan(&tenantID)
if err != nil {
if err == pgx.ErrNoRows {
return nil, fmt.Errorf("auth: tenant not found: %s", tenantSlug)
}
return nil, fmt.Errorf("auth: resolve tenant: %w", err)
}
hash, err := bcrypt.GenerateFromPassword([]byte(password), 12) hash, err := bcrypt.GenerateFromPassword([]byte(password), 12)
if err != nil { if err != nil {
return nil, fmt.Errorf("auth: hash password: %w", err) return nil, fmt.Errorf("auth: hash password: %w", err)
@ -163,14 +176,9 @@ func (s *AuthStore) CreateScreenUser(ctx context.Context, tenantSlug, username,
row := s.pool.QueryRow(ctx, row := s.pool.QueryRow(ctx,
`insert into users(tenant_id, username, password_hash, role) `insert into users(tenant_id, username, password_hash, role)
values( values($1, $2, $3, 'screen_user')
(select id from tenants where slug = $1), returning id, tenant_id, $4::text, username, password_hash, role, created_at`,
$2, $3, 'screen_user' tenantID, username, string(hash), tenantSlug)
)
returning id, tenant_id, coalesce(
(select slug from tenants where id = tenant_id), ''
), username, password_hash, role, created_at`,
tenantSlug, username, string(hash))
u, err := scanUserWithSlug(row) u, err := scanUserWithSlug(row)
if err != nil { if err != nil {
return nil, fmt.Errorf("auth: create screen user: %w", err) return nil, fmt.Errorf("auth: create screen user: %w", err)