Add user management

This commit is contained in:
2026-05-02 14:31:19 +02:00
parent 24ade563db
commit 5997a29d92
20 changed files with 983 additions and 2 deletions
+158
View File
@@ -0,0 +1,158 @@
package database
import (
"database/sql"
"errors"
"fmt"
"quay/app/models"
"quay/app/repository"
"github.com/google/uuid"
"github.com/mattn/go-sqlite3"
)
type SQLiteUserRepository struct {
db *sql.DB
}
func NewSQLiteUserRepository(db *sql.DB) *SQLiteUserRepository {
return &SQLiteUserRepository{db: db}
}
var _ repository.UserRepository = (*SQLiteUserRepository)(nil)
func (r *SQLiteUserRepository) GetAllUsers() ([]models.User, error) {
rows, err := r.db.Query(`
SELECT id, name, role, hashed_password, created_at
FROM users`)
if err != nil {
return nil, fmt.Errorf("list users: %w", err)
}
var users []models.User
for rows.Next() {
s, err := scanUser(rows)
if err != nil {
rows.Close()
return nil, fmt.Errorf("list users scan: %w", err)
}
users = append(users, *s)
}
rows.Close()
if err := rows.Err(); err != nil {
return nil, err
}
return users, nil
}
func (r *SQLiteUserRepository) GetUserById(id string) (*models.User, error) {
row := r.db.QueryRow(`
SELECT id, name, role, hashed_password, created_at
FROM users WHERE id = ?`, id)
u, err := scanUser(row)
if err != nil {
return nil, fmt.Errorf("get user by id: %w", err)
}
return u, nil
}
func (r *SQLiteUserRepository) GetUserByName(name string) (*models.User, error) {
row := r.db.QueryRow(`
SELECT id, name, role, hashed_password, created_at
FROM users WHERE name = ?`, name)
u, err := scanUser(row)
if err != nil {
return nil, fmt.Errorf("get user by name: %w", err)
}
return u, nil
}
func (r *SQLiteUserRepository) CreateUser(user *models.User) error {
tx, err := r.db.Begin()
if err != nil {
return fmt.Errorf("create user begin tx: %w", err)
}
defer tx.Rollback()
user.ID = uuid.NewString()
_, err = tx.Exec(`
INSERT INTO users (id, name, role, hashed_password, created_at)
VALUES (?, ?, ?, ?, ?)`,
user.ID, user.Name, user.Role, user.HashedPassword, user.CreatedAt,
)
if err != nil {
if isSQLiteUniqueConstraintError(err) {
return fmt.Errorf("create user insert: %w", repository.ErrUserAlreadyExists)
}
return fmt.Errorf("create user insert: %w", err)
}
return tx.Commit()
}
func (r *SQLiteUserRepository) UpdateUser(user *models.User) error {
tx, err := r.db.Begin()
if err != nil {
return fmt.Errorf("update user begin tx: %w", err)
}
defer tx.Rollback()
_, err = tx.Exec(`
UPDATE users SET name=?, role=? WHERE id=?`,
user.Name, user.Role, user.ID,
)
if err != nil {
if isSQLiteUniqueConstraintError(err) {
return fmt.Errorf("update user: %w", repository.ErrUserAlreadyExists)
}
return fmt.Errorf("update user: %w", err)
}
return tx.Commit()
}
func (r *SQLiteUserRepository) DeleteUser(id string) error {
_, err := r.db.Exec(`DELETE FROM users WHERE id = ?`, id)
if err != nil {
return fmt.Errorf("delete user: %w", err)
}
return nil
}
func scanUser(s scanner) (*models.User, error) {
u := new(models.User)
err := s.Scan(
&u.ID,
&u.Name,
&u.Role,
&u.HashedPassword,
&u.CreatedAt,
)
if err != nil {
return nil, err
}
return u, nil
}
func (r *SQLiteUserRepository) AdminUserExists() (bool, error) {
var count int
err := r.db.QueryRow(`SELECT COUNT(*) FROM users WHERE role = 'admin'`).Scan(&count)
if err != nil {
return false, fmt.Errorf("admin user exists: %w", err)
}
return count > 0, nil
}
func isSQLiteUniqueConstraintError(err error) bool {
var sqliteErr sqlite3.Error
if !errors.As(err, &sqliteErr) {
return false
}
return sqliteErr.Code == sqlite3.ErrConstraint && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique
}