Add user management
This commit is contained in:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user