Add users
This commit is contained in:
50
pkg/db/db.go
Normal file
50
pkg/db/db.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewClient(l *zap.Logger) *Client {
|
||||
l.Info("Setting up database connection")
|
||||
|
||||
dbPool := setupPool()
|
||||
testConnection(dbPool)
|
||||
|
||||
l.Info("Database successfully connected")
|
||||
|
||||
return &Client{pool: dbPool}
|
||||
}
|
||||
|
||||
func setupPool() *pgxpool.Pool {
|
||||
dbUrl := os.Getenv("DATABASE_URL")
|
||||
if dbUrl == "" {
|
||||
panic(errors.New("DATABASE_URL is not set"))
|
||||
}
|
||||
dbPool, err := pgxpool.Connect(context.Background(), dbUrl)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return dbPool
|
||||
}
|
||||
|
||||
func testConnection(dbPool *pgxpool.Pool) {
|
||||
var greeting string
|
||||
err := dbPool.QueryRow(context.Background(), "select 'Hello, world!'").Scan(&greeting)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) GetConn(ctx context.Context) *pgxpool.Conn {
|
||||
conn, _ := c.pool.Acquire(ctx)
|
||||
return conn
|
||||
}
|
49
pkg/db/postgres/usersRepository.go
Normal file
49
pkg/db/postgres/usersRepository.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"serverctl/pkg/db"
|
||||
"serverctl/pkg/users"
|
||||
)
|
||||
|
||||
var _ users.Repository = &usersRepository{}
|
||||
|
||||
type usersRepository struct {
|
||||
databasePool *db.Client
|
||||
}
|
||||
|
||||
func NewUsersRepository(db *db.Client) users.Repository {
|
||||
return &usersRepository{db}
|
||||
}
|
||||
|
||||
func (u *usersRepository) Create(ctx context.Context, user *users.CreateUser) (int, error) {
|
||||
var userId int
|
||||
conn := u.databasePool.GetConn(ctx)
|
||||
defer conn.Release()
|
||||
|
||||
conn.QueryRow(ctx, "INSERT INTO users(email, password_hash) values ($1, $2) RETURNING id", user.Email, user.PasswordHash).Scan(&userId)
|
||||
|
||||
if userId == 0 {
|
||||
return -1, errors.New("could not insert data into users table")
|
||||
}
|
||||
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
func (u *usersRepository) GetByEmail(ctx context.Context, email string, passwordHash string) (*users.User, error) {
|
||||
conn := u.databasePool.GetConn(ctx)
|
||||
defer conn.Release()
|
||||
|
||||
var id int
|
||||
err := conn.QueryRow(ctx, "select id from users where email = $1 and password_hash = $2", email, passwordHash).Scan(&id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if id <= 0 {
|
||||
return nil, errors.New("user with that password doesn't exist")
|
||||
}
|
||||
|
||||
return users.NewUser(id, email), nil
|
||||
}
|
10
pkg/users/model.go
Normal file
10
pkg/users/model.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package users
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
Email string
|
||||
}
|
||||
|
||||
func NewUser(id int, email string) *User {
|
||||
return &User{id, email}
|
||||
}
|
8
pkg/users/repository.go
Normal file
8
pkg/users/repository.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package users
|
||||
|
||||
import "context"
|
||||
|
||||
type Repository interface {
|
||||
Create(ctx context.Context, user *CreateUser) (int, error)
|
||||
GetByEmail(ctx context.Context, email string, passwordHash string) (*User, error)
|
||||
}
|
44
pkg/users/service.go
Normal file
44
pkg/users/service.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/eko/gocache/cache"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
logger *zap.Logger
|
||||
cache *cache.Cache
|
||||
repository Repository
|
||||
passwordHasher PasswordHasher
|
||||
}
|
||||
|
||||
func NewService(l *zap.Logger, ur Repository, c *cache.Cache) *Service {
|
||||
return &Service{
|
||||
logger: l,
|
||||
repository: ur,
|
||||
cache: c,
|
||||
passwordHasher: NewPlainTextPasswordHasher(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) Create(email string, password string) (int, error) {
|
||||
createUser, err := NewCreateUser(email, password, s.passwordHasher)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
var userId int
|
||||
userId, err = s.repository.Create(context.Background(), createUser)
|
||||
if err != nil {
|
||||
s.logger.Warn("Could not create user in service")
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
func (s *Service) Authenticate(ctx context.Context, email string, password string) (*User, error) {
|
||||
user, err := s.repository.GetByEmail(ctx, email, s.passwordHasher.HashPassword(password))
|
||||
return user, err
|
||||
}
|
49
pkg/users/user.go
Normal file
49
pkg/users/user.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package users
|
||||
|
||||
import "errors"
|
||||
|
||||
type PasswordHasher interface {
|
||||
HashPassword(password string) string
|
||||
}
|
||||
|
||||
type CreateUser struct {
|
||||
Email string
|
||||
PasswordHash string
|
||||
}
|
||||
|
||||
func NewCreateUser(email string, password string, hasher PasswordHasher) (*CreateUser, error) {
|
||||
if email == "" {
|
||||
return nil, errors.New("Email cannot be empty for user")
|
||||
}
|
||||
if password == "" || len(password) < 8 {
|
||||
return nil, errors.New("password is doesn't fit requirements")
|
||||
}
|
||||
|
||||
return &CreateUser{
|
||||
Email: email,
|
||||
PasswordHash: hasher.HashPassword(password),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type bCryptPasswordHasher struct {
|
||||
}
|
||||
|
||||
func NewBCryptPasswordHasher() PasswordHasher {
|
||||
return &bCryptPasswordHasher{}
|
||||
}
|
||||
|
||||
func (b bCryptPasswordHasher) HashPassword(password string) string {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
type plainTextPasswordHasher struct {
|
||||
}
|
||||
|
||||
func NewPlainTextPasswordHasher() PasswordHasher {
|
||||
return &plainTextPasswordHasher{}
|
||||
}
|
||||
|
||||
func (p plainTextPasswordHasher) HashPassword(password string) string {
|
||||
return password
|
||||
}
|
Reference in New Issue
Block a user