From 1ce2f5aa477da06a8f028e7ecf2857954c128ed8 Mon Sep 17 00:00:00 2001 From: "Christoph K." Date: Thu, 9 Apr 2026 22:17:25 +0200 Subject: [PATCH] admin benutzer wird intial angelegt --- .gitea/workflows/deploy.yml | 7 ++++++- backend/cmd/server/main.go | 21 +++++++++++++++++++++ backend/internal/db/users.go | 21 +++++++++++++++++++++ docker-compose.yml | 2 ++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 417b3e3..30e9d3a 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -23,7 +23,12 @@ jobs: fi - name: Write .env - run: printf 'DB_PASSWORD=%s\n' '${{ secrets.DB_PASSWORD }}' > ${{ vars.DEPLOY_DIR }}/.env + run: | + printf 'DB_PASSWORD=%s\nADMIN_USER=%s\nADMIN_PASSWORD=%s\n' \ + '${{ secrets.DB_PASSWORD }}' \ + '${{ vars.ADMIN_USER }}' \ + '${{ secrets.ADMIN_PASSWORD }}' \ + > ${{ vars.DEPLOY_DIR }}/.env - name: Build & Deploy run: docker compose -f ${{ vars.DEPLOY_DIR }}/docker-compose.yml up --build -d diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 42f2ae5..09a0884 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -39,6 +39,27 @@ func main() { } slog.Info("schema ready") + if adminUser := os.Getenv("ADMIN_USER"); adminUser != "" { + adminPass := os.Getenv("ADMIN_PASSWORD") + if adminPass == "" { + slog.Error("ADMIN_USER set but ADMIN_PASSWORD is empty") + os.Exit(1) + } + hash, err := auth.HashPassword(adminPass) + if err != nil { + slog.Error("hash admin password", "err", err) + os.Exit(1) + } + created, err := db.SeedAdminUser(ctx, pool, adminUser, hash) + if err != nil { + slog.Error("seed admin user", "err", err) + os.Exit(1) + } + if created { + slog.Info("admin user created", "username", adminUser) + } + } + if err := os.MkdirAll(uploadDir, 0o755); err != nil { slog.Error("create upload dir", "err", err) os.Exit(1) diff --git a/backend/internal/db/users.go b/backend/internal/db/users.go index 3a19908..731e962 100644 --- a/backend/internal/db/users.go +++ b/backend/internal/db/users.go @@ -2,6 +2,7 @@ package db import ( "context" + "fmt" "github.com/jackc/pgx/v5/pgxpool" @@ -16,6 +17,26 @@ func NewUserStore(pool *pgxpool.Pool) *UserStore { return &UserStore{pool: pool} } +// SeedAdminUser creates an admin user if no users exist yet. +// Returns (true, nil) if the user was created, (false, nil) if users already exist. +func SeedAdminUser(ctx context.Context, pool *pgxpool.Pool, username, passwordHash string) (bool, error) { + var count int + if err := pool.QueryRow(ctx, `SELECT COUNT(*) FROM users`).Scan(&count); err != nil { + return false, fmt.Errorf("count users: %w", err) + } + if count > 0 { + return false, nil + } + _, err := pool.Exec(ctx, + `INSERT INTO users (username, password_hash, is_admin) VALUES ($1, $2, true)`, + username, passwordHash, + ) + if err != nil { + return false, fmt.Errorf("insert admin: %w", err) + } + return true, nil +} + // ListUsers returns all users ordered by created_at. func (s *UserStore) ListUsers(ctx context.Context) ([]domain.User, error) { rows, err := s.pool.Query(ctx, diff --git a/docker-compose.yml b/docker-compose.yml index da3dea6..2ba4787 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,8 @@ services: DATABASE_URL: postgres://${DB_USER:-pamietnik}:${DB_PASSWORD:?DB_PASSWORD is required}@host-gateway:5433/${DB_NAME:-pamietnik}?sslmode=disable LISTEN_ADDR: :8080 UPLOAD_DIR: /uploads + ADMIN_USER: ${ADMIN_USER:-} + ADMIN_PASSWORD: ${ADMIN_PASSWORD:-} volumes: - /volume2/docker/pamietnik/uploads:/uploads restart: unless-stopped