refactoring db; added email-verification

This commit is contained in:
$(pass /github/name)
2024-07-08 23:43:55 +02:00
parent 555d1be575
commit 87e9f71ceb
20 changed files with 890 additions and 255 deletions

View File

@@ -4,12 +4,18 @@ import (
"GoMembership/internal/models"
"GoMembership/pkg/errors"
"database/sql"
"fmt"
"strings"
"time"
)
type UserRepository interface {
CreateUser(user *models.User) (int64, error)
FindUserByID(id int) (*models.User, error)
FindUserByID(id int64) (*models.User, error)
FindUserByEmail(email string) (*models.User, error)
SetVerificationToken(user *models.User, token *string) (int64, error)
IsVerified(userID *int64) (bool, error)
VerifyUserOfToken(token *string) (int64, error)
}
type userRepository struct {
@@ -21,8 +27,24 @@ func NewUserRepository(db *sql.DB) UserRepository {
}
func (repo *userRepository) CreateUser(user *models.User) (int64, error) {
query := "INSERT INTO users (first_name, last_name, email, password, salt, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)"
result, err := repo.db.Exec(query, user.FirstName, user.LastName, user.Email, user.Password, user.Salt, user.CreatedAt, user.UpdatedAt)
query := "INSERT INTO users (first_name, last_name, email, phone, drivers_id_checked, role_id, payment_status, date_of_birth, address, profile_picture, notes, status, password, salt, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
result, err := repo.db.Exec(query,
user.FirstName,
user.LastName,
user.Email,
user.Phone,
user.DriversIDChecked,
user.RoleID,
user.PaymentStatus,
user.DateOfBirth,
user.Address,
user.ProfilePicture,
user.Notes,
user.Status,
user.Password,
user.Salt,
user.CreatedAt,
user.UpdatedAt)
if err != nil {
return -1, err
}
@@ -31,14 +53,50 @@ func (repo *userRepository) CreateUser(user *models.User) (int64, error) {
if err != nil {
return -1, err
}
return lastInsertID, err
}
func (repo *userRepository) FindUserByID(id int) (*models.User, error) {
func (repo *userRepository) UpdateUser(userID int64, updates map[string]interface{}) error {
if len(updates) == 0 {
return errors.ErrNoData
}
// Construct the query
setClauses := make([]string, 0, len(updates))
args := make([]interface{}, 0, len(updates)+1)
for column, value := range updates {
setClauses = append(setClauses, fmt.Sprintf("%s = ?", column))
args = append(args, value)
}
args = append(args, userID)
query := fmt.Sprintf("UPDATE users SET %s WHERE id = ?", strings.Join(setClauses, ", "))
// Execute the query
_, err := repo.db.Exec(query, args...)
if err != nil {
return err
}
return nil
}
func (repo *userRepository) FindUserByID(id int64) (*models.User, error) {
var user models.User
query := "SELECT id, first_name, last_name, email FROM users WHERE id = ?"
err := repo.db.QueryRow(query, id).Scan(&user.ID, &user.FirstName, &user.LastName, &user.Email)
query := "SELECT id, first_name, last_name, email, phone, drivers_id_checked, role_id, payment_status, date_of_birth, address, profile_picture, notes, status FROM users WHERE id = ?"
err := repo.db.QueryRow(query, id).Scan(&user.ID,
&user.FirstName,
&user.LastName,
&user.Email,
&user.Phone,
&user.DriversIDChecked,
&user.RoleID,
&user.PaymentStatus,
&user.DateOfBirth,
&user.Address,
&user.ProfilePicture,
&user.Notes,
&user.Status)
if err != nil {
if err == sql.ErrNoRows {
return nil, errors.ErrUserNotFound
@@ -60,3 +118,70 @@ func (repo *userRepository) FindUserByEmail(email string) (*models.User, error)
}
return &user, nil
}
func (repo *userRepository) IsVerified(userID *int64) (bool, error) {
var status string
query := "SELECT status FROM users where id = ?"
err := repo.db.QueryRow(query, userID).Scan(&status)
if err != nil {
if err == sql.ErrNoRows {
return false, errors.ErrUserNotFound
}
return false, err
}
return status != "unverified", nil
}
func (repo *userRepository) VerifyUserOfToken(token *string) (int64, error) {
var userID int64
err := repo.db.QueryRow("SELECT user_id FROM email_verifications WHERE verification_token = $1", token).Scan(&userID)
if err == sql.ErrNoRows {
return -1, errors.ErrTokenNotFound
} else if err != nil {
return -1, err
}
verified, err := repo.IsVerified(&userID)
if err != nil {
return -1, err
}
if verified {
return userID, errors.ErrAlreadyVerified
}
update := map[string]interface{}{
"status": "active",
}
err = repo.UpdateUser(userID, update)
if err != nil {
return -1, err
}
query := "UPDATE email_verifications SET verified_at = ? WHERE user_id = ?"
_, err = repo.db.Exec(query, time.Now(), userID)
if err != nil {
return -1, err
}
return userID, nil
}
func (repo *userRepository) SetVerificationToken(user *models.User, token *string) (int64, error) {
// check if user already verified
verified, err := repo.IsVerified(&user.ID)
if err != nil {
return -1, err
}
if verified {
return -1, errors.ErrAlreadyVerified
}
query := "INSERT OR REPLACE INTO email_verifications (user_id, verification_token, created_at) VALUES (?, ?, ?)"
result, err := repo.db.Exec(query, user.ID, token, time.Now())
if err != nil {
return -1, err
}
lastInsertID, err := result.LastInsertId()
if err != nil {
return -1, err
}
return lastInsertID, nil
}