You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.3 KiB
Go
100 lines
2.3 KiB
Go
package model
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/mattn/go-sqlite3"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type User struct {
|
|
ID int
|
|
Name string
|
|
Email string
|
|
HashedPassword []byte
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
type UserServiceInterface interface {
|
|
Insert(name, email, password string) (int, error)
|
|
Authenticate(email, password string) (int, error)
|
|
Exists(id int) (bool, error)
|
|
}
|
|
|
|
// TODD add logger to service
|
|
type UserService struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
func (u *UserService) Insert(name, email, password string) (int, error) {
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 12)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
stmt := `INSERT INTO users (name, email, hashed_password)
|
|
VALUES (?,?,?)`
|
|
|
|
result, err := u.DB.Exec(stmt, name, email, string(hashedPassword))
|
|
if err != nil {
|
|
slog.Debug(fmt.Sprintf("Error encounters on insert: %s", err.Error()))
|
|
// This is a assertion that err is of type sqlite3.Error. If it is ok is true.
|
|
if serr, ok := err.(sqlite3.Error); ok {
|
|
slog.Debug("Error is sqlite3.Error type.")
|
|
if serr.ExtendedCode == sqlite3.ErrConstraintUnique {
|
|
slog.Debug("Error is a unique contraint violation.")
|
|
return 0, ErrDuplicateEmail
|
|
}
|
|
}
|
|
return 0, err
|
|
}
|
|
|
|
lastId, err := result.LastInsertId()
|
|
if err != nil {
|
|
slog.Debug("An error occured when retrieving insert result id.")
|
|
return 0, err
|
|
}
|
|
slog.Debug(fmt.Sprintf("Inserted new user. User pk: %d", int(lastId)))
|
|
return int(lastId), nil
|
|
}
|
|
|
|
func (u *UserService) Authenticate(email, password string) (int, error) {
|
|
var id int
|
|
var hashedPassword []byte
|
|
stmt := `SELECT id, hashed_password FROM users WHERE email == ?`
|
|
|
|
err := u.DB.QueryRow(stmt, email).Scan(&id, &hashedPassword)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return 0, ErrInvalidCredentials
|
|
} else {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
err = bcrypt.CompareHashAndPassword(hashedPassword, []byte(password))
|
|
if err != nil {
|
|
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
|
|
return 0, ErrInvalidCredentials
|
|
} else {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
return id, nil
|
|
}
|
|
|
|
func (u *UserService) Exists(id int) (bool, error) {
|
|
var exists bool
|
|
|
|
stmt := "SELECT EXISTS(SELECT true FROM users WHERE id = ?)"
|
|
|
|
err := u.DB.QueryRow(stmt, id).Scan(&exists)
|
|
return exists, err
|
|
}
|