This required service and repo creation for the users. Logging out is not yet supported, but that is next.
144 lines
3.5 KiB
Go
144 lines
3.5 KiB
Go
package repository
|
|
|
|
import (
|
|
"database/sql"
|
|
|
|
domain "github.com/haydenhargreaves/Potion/internal/domain/user"
|
|
_ "github.com/lib/pq"
|
|
)
|
|
|
|
type UserRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// Compile-time check to ensure the UserRepository implements domain.UserRepository
|
|
var _ domain.UserRepository = (*UserRepository)(nil)
|
|
|
|
// NewUserRepository creates a user repository object which is used by the user service to access
|
|
// the database. Any user related database operations will take place in this repository.
|
|
func NewUserRepository(db *sql.DB) domain.UserRepository {
|
|
return &UserRepository{db: db}
|
|
}
|
|
|
|
// CreateGoogleUser creates a user entry in the users table. The refresh token is required along
|
|
// with the Google user info, in order to complete the database schema. Currently, Google login is
|
|
// the only support method of authentication, if this changes, this repository may need updates to
|
|
// match an updated table schema.
|
|
//
|
|
// This function will NOT check if the user already exists, if they do, it will return an error. For
|
|
// best results, pair this function with the GetGoogleUser which will return the user if it can find
|
|
// it.
|
|
func (r *UserRepository) CreateGoogleUser(googleUserInfo *domain.GoogleUserInfo, googleRefreshToken string) (domain.User, error) {
|
|
tx, err := r.db.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return domain.User{}, err
|
|
}
|
|
|
|
var user domain.User
|
|
query := `INSERT INTO users
|
|
(GoogleId, Name, Email, ImageUrl, GoogleRefreshToken)
|
|
VALUES ($1, $2, $3, $4, $5) RETURNING *;`
|
|
|
|
if err := tx.QueryRow(
|
|
query,
|
|
googleUserInfo.Id,
|
|
googleUserInfo.Name,
|
|
googleUserInfo.Email,
|
|
googleUserInfo.Picture,
|
|
googleRefreshToken,
|
|
).Scan(
|
|
&user.Id,
|
|
&user.GoogleId,
|
|
&user.Name,
|
|
&user.Email,
|
|
&user.ImageUrl,
|
|
&user.GoogleRefreshToken,
|
|
&user.Created,
|
|
); err != nil {
|
|
tx.Rollback()
|
|
return domain.User{}, err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
return domain.User{}, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// GetGoogleUser attempts to find a user in the database via its Google ID, not the database ID. This
|
|
// function is used when a user logs in with Google to prevent duplicate entries from being made. If
|
|
// no user is found, this function will return a null pointer but not an error.
|
|
func (r *UserRepository) GetGoogleUser(googleId string) (*domain.User, error) {
|
|
tx, err := r.db.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
var user domain.User
|
|
query := `SELECT * FROM users WHERE GoogleId = $1`
|
|
|
|
if err := tx.QueryRow(query, googleId).Scan(
|
|
&user.Id,
|
|
&user.GoogleId,
|
|
&user.Name,
|
|
&user.Email,
|
|
&user.ImageUrl,
|
|
&user.GoogleRefreshToken,
|
|
&user.Created,
|
|
); err != nil {
|
|
// If no user was found, don't error, just return
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
return &user, nil
|
|
}
|
|
|
|
func (r *UserRepository) GetUserById(id int) (*domain.User, error) {
|
|
tx, err := r.db.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
var user domain.User
|
|
query := `SELECT * FROM users WHERE id = $1`
|
|
|
|
if err := tx.QueryRow(query, id).Scan(
|
|
&user.Id,
|
|
&user.GoogleId,
|
|
&user.Name,
|
|
&user.Email,
|
|
&user.ImageUrl,
|
|
&user.GoogleRefreshToken,
|
|
&user.Created,
|
|
); err != nil {
|
|
// If no user was found, don't error, just return
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
return &user, nil
|
|
|
|
}
|