package db import ( "me-fit/types" "me-fit/utils" "database/sql" "errors" "strings" "time" "github.com/google/uuid" ) var ( ErrUserNotFound = errors.New("User not found") ErrUserExists = errors.New("User already exists") ) type User struct { Id uuid.UUID Email string EmailVerified bool EmailVerifiedAt *time.Time IsAdmin bool Password []byte Salt []byte CreateAt time.Time } func NewUser(id uuid.UUID, email string, emailVerified bool, emailVerifiedAt *time.Time, isAdmin bool, password []byte, salt []byte, createAt time.Time) *User { return &User{ Id: id, Email: email, EmailVerified: emailVerified, EmailVerifiedAt: emailVerifiedAt, IsAdmin: isAdmin, Password: password, Salt: salt, CreateAt: createAt, } } type DbAuth interface { GetUser(email string) (*User, error) InsertUser(user *User) error GetEmailVerificationToken(userId uuid.UUID) (string, error) InsertEmailVerificationToken(userId uuid.UUID, token string) error } type DbAuthSqlite struct { db *sql.DB } func NewDbAuthSqlite(db *sql.DB) *DbAuthSqlite { return &DbAuthSqlite{db: db} } func (db DbAuthSqlite) GetUser(email string) (*User, error) { var ( userId uuid.UUID emailVerified bool emailVerifiedAt *time.Time isAdmin bool password []byte salt []byte createdAt time.Time ) err := db.db.QueryRow(` SELECT user_uuid, email_verified, email_verified_at, password, salt, created_at FROM user WHERE email = ?`, email).Scan(&userId, &emailVerified, &emailVerifiedAt, &password, &salt, &createdAt) if err != nil { if err == sql.ErrNoRows { return nil, ErrUserNotFound } else { utils.LogError("SQL error GetUser", err) return nil, types.ErrInternal } } return NewUser(userId, email, emailVerified, emailVerifiedAt, isAdmin, password, salt, createdAt), nil } func (db DbAuthSqlite) InsertUser(user *User) error { _, err := db.db.Exec(` INSERT INTO user (user_uuid, email, email_verified, email_verified_at, is_admin, password, salt, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, user.Id, user.Email, user.EmailVerified, user.EmailVerifiedAt, user.IsAdmin, user.Password, user.Salt, user.CreateAt) if err != nil { if strings.Contains(err.Error(), "email") { return ErrUserExists } utils.LogError("SQL error InsertUser", err) return types.ErrInternal } return nil } func (db DbAuthSqlite) GetEmailVerificationToken(userId uuid.UUID) (string, error) { var token string err := db.db.QueryRow(` SELECT token FROM user_token WHERE user_uuid = ? AND type = 'email_verify'`, userId).Scan(&token) if err != nil && err != sql.ErrNoRows { utils.LogError("Could not get token", err) return "", types.ErrInternal } return token, nil } func (db DbAuthSqlite) InsertEmailVerificationToken(userId uuid.UUID, token string) error { _, err := db.db.Exec(` INSERT INTO user_token (user_uuid, type, token, created_at) VALUES (?, 'email_verify', ?, datetime())`, userId, token) if err != nil { utils.LogError("Could not insert token", err) return types.ErrInternal } return nil }