From c470ec532bf7cbc607c95a0f23071495010c78c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesko=20Ansch=C3=BCtz?= Date: Mon, 23 Mar 2026 23:41:16 +0100 Subject: [PATCH] fix(backend): Error-Logging in Screen-User-Handlern + Tenant-Lookup-Refactoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- server/backend/internal/httpapi/manage/ui.go | 9 +++++ server/backend/internal/store/auth.go | 38 ++++++++++++-------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/server/backend/internal/httpapi/manage/ui.go b/server/backend/internal/httpapi/manage/ui.go index cee10fd..5233e0f 100644 --- a/server/backend/internal/httpapi/manage/ui.go +++ b/server/backend/internal/httpapi/manage/ui.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "html/template" + "log/slog" "net/http" "os" "path/filepath" @@ -202,6 +203,8 @@ func HandleCreateScreenUser(auth *store.AuthStore) http.HandlerFunc { _, err := auth.CreateScreenUser(r.Context(), tenantSlug, username, password) 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) return } @@ -214,6 +217,8 @@ func HandleDeleteScreenUser(auth *store.AuthStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { userID := r.PathValue("userID") 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) return } @@ -235,6 +240,8 @@ func HandleAddUserToScreen(screens *store.ScreenStore) http.HandlerFunc { return } 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) return } @@ -248,6 +255,8 @@ func HandleRemoveUserFromScreen(screens *store.ScreenStore) http.HandlerFunc { screenID := r.PathValue("screenID") userID := r.PathValue("userID") 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) return } diff --git a/server/backend/internal/store/auth.go b/server/backend/internal/store/auth.go index 49f260e..f076b95 100644 --- a/server/backend/internal/store/auth.go +++ b/server/backend/internal/store/auth.go @@ -136,15 +136,19 @@ func (s *AuthStore) EnsureAdminUser(ctx context.Context, tenantSlug, password st 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, `insert into users(tenant_id, username, password_hash, role) - values( - (select id from tenants where slug = $1), - 'admin', - $2, - 'admin' - )`, - tenantSlug, string(hash)) + values($1, 'admin', $2, 'admin')`, + tenantID, string(hash)) if err != nil { 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 // the username is already taken (unique constraint violation). 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) if err != nil { 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, `insert into users(tenant_id, username, password_hash, role) - values( - (select id from tenants where slug = $1), - $2, $3, 'screen_user' - ) - returning id, tenant_id, coalesce( - (select slug from tenants where id = tenant_id), '' - ), username, password_hash, role, created_at`, - tenantSlug, username, string(hash)) + values($1, $2, $3, 'screen_user') + returning id, tenant_id, $4::text, username, password_hash, role, created_at`, + tenantID, username, string(hash), tenantSlug) u, err := scanUserWithSlug(row) if err != nil { return nil, fmt.Errorf("auth: create screen user: %w", err)