Skip to content

Commit

Permalink
fix review part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Пешков Дмитрий committed Sep 23, 2024
1 parent 38b6b3b commit 736760f
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 70 deletions.
8 changes: 7 additions & 1 deletion cmd/gophermart/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"errors"
"github.com/spqrcor/gofermart/internal/authenticate"
"github.com/spqrcor/gofermart/internal/client"
"github.com/spqrcor/gofermart/internal/config"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/spqrcor/gofermart/internal/services"
"github.com/spqrcor/gofermart/internal/workers"
"log"
"net/http"
)

func main() {
Expand Down Expand Up @@ -42,7 +44,11 @@ func main() {
orderWorker.Run()

appServer := server.NewServer(userService, orderService, withdrawalService, loggerRes, conf.RunAddr, authService)
if err := appServer.Start(); err != nil {
err = appServer.Start()
if errors.Is(err, http.ErrServerClosed) {
loggerRes.Error("Server stop")
}
if err != nil {
loggerRes.Error(err.Error())
}
}
60 changes: 32 additions & 28 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"sync"
"time"
)

Expand All @@ -20,36 +21,39 @@ type Config struct {
TokenExp time.Duration `env:"TOKEN_EXP"`
}

func NewConfig() Config {
var cfg = Config{
RunAddr: "localhost:8080",
LogLevel: zap.InfoLevel,
AccrualSystemAddress: "",
DatabaseURI: "",
QueryTimeOut: 3,
WorkerCount: 3,
RetryStartWorkerCount: 10,
SecretKey: "KLJ-fo3Fksd3fl!=",
TokenExp: time.Hour * 3,
}
var cfg = Config{
RunAddr: "localhost:8080",
LogLevel: zap.InfoLevel,
AccrualSystemAddress: "",
DatabaseURI: "",
QueryTimeOut: 3,
WorkerCount: 3,
RetryStartWorkerCount: 10,
SecretKey: "KLJ-fo3Fksd3fl!=",
TokenExp: time.Hour * 3,
}
var once sync.Once

flag.StringVar(&cfg.RunAddr, "a", cfg.RunAddr, "address and port to run server")
flag.StringVar(&cfg.AccrualSystemAddress, "r", cfg.AccrualSystemAddress, "accrual system address")
flag.StringVar(&cfg.DatabaseURI, "d", cfg.DatabaseURI, "database uri")
flag.Parse()
func NewConfig() Config {
once.Do(func() {
flag.StringVar(&cfg.RunAddr, "a", cfg.RunAddr, "address and port to run server")
flag.StringVar(&cfg.AccrualSystemAddress, "r", cfg.AccrualSystemAddress, "accrual system address")
flag.StringVar(&cfg.DatabaseURI, "d", cfg.DatabaseURI, "database uri")
flag.Parse()

serverAddressEnv, findAddress := os.LookupEnv("RUN_ADDRESS")
serverDatabaseURI, findDatabaseURI := os.LookupEnv("DATABASE_URI")
serverAccrualSystemAddress, findAccrualSystemAddress := os.LookupEnv("ACCRUAL_SYSTEM_ADDRESS")
serverAddressEnv, findAddress := os.LookupEnv("RUN_ADDRESS")
serverDatabaseURI, findDatabaseURI := os.LookupEnv("DATABASE_URI")
serverAccrualSystemAddress, findAccrualSystemAddress := os.LookupEnv("ACCRUAL_SYSTEM_ADDRESS")

if findAddress {
cfg.RunAddr = serverAddressEnv
}
if findDatabaseURI {
cfg.DatabaseURI = serverDatabaseURI
}
if findAccrualSystemAddress {
cfg.AccrualSystemAddress = serverAccrualSystemAddress
}
if findAddress {
cfg.RunAddr = serverAddressEnv
}
if findDatabaseURI {
cfg.DatabaseURI = serverDatabaseURI
}
if findAccrualSystemAddress {
cfg.AccrualSystemAddress = serverAccrualSystemAddress
}
})
return cfg
}
3 changes: 2 additions & 1 deletion internal/handlers/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ func RegisterHandler(u *services.UserService, a *authenticate.Authenticate) http
if errors.Is(err, services.ErrValidation) {
http.Error(res, err.Error(), http.StatusBadRequest)
return
} else if errors.Is(err, services.ErrLoginExists) {
}
if errors.Is(err, services.ErrLoginExists) {
res.WriteHeader(http.StatusConflict)
return
}
Expand Down
17 changes: 8 additions & 9 deletions internal/server/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ func authenticateMiddleware(logger *zap.Logger, auth *authenticate.Authenticate)
if err != nil {
http.Error(rw, err.Error(), http.StatusUnauthorized)
return
} else {
UserID, err := auth.GetUserIDFromCookie(cookie.Value)
if err != nil {
logger.Error(err.Error())
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
ctx := context.WithValue(r.Context(), authenticate.ContextUserID, UserID)
next.ServeHTTP(rw, r.WithContext(ctx))
}
UserID, err := auth.GetUserIDFromCookie(cookie.Value)
if err != nil {
logger.Error(err.Error())
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
ctx := context.WithValue(r.Context(), authenticate.ContextUserID, UserID)
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
}
22 changes: 12 additions & 10 deletions internal/server/gzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ import (
func getBodyMiddleware(logger *zap.Logger) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if r.Header.Get(`Content-Encoding`) == `gzip` {
gz, err := gzip.NewReader(r.Body)
if err != nil {
logger.Error(err.Error())
} else {
r.Body = gz
}
if err = gz.Close(); err != nil {
logger.Error(err.Error())
}
if r.Header.Get(`Content-Encoding`) != `gzip` {
next.ServeHTTP(rw, r)
return
}
gz, err := gzip.NewReader(r.Body)
if err != nil {
logger.Error(err.Error())
} else {
r.Body = gz
}
if err = gz.Close(); err != nil {
logger.Error(err.Error())
}
next.ServeHTTP(rw, r)
})
Expand Down
18 changes: 12 additions & 6 deletions internal/services/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import (
"time"
)

const (
addOrderQuery = "INSERT INTO orders (id, user_id, number) VALUES ($1, $2, $3) ON CONFLICT(number) DO UPDATE SET number = EXCLUDED.number RETURNING id, user_id"
getAllOrdersQuery = "SELECT number, status, accrual, created_at FROM orders WHERE user_id = $1 ORDER BY created_at DESC"
getUnCompleteOrdersQuery = "SELECT number FROM orders WHERE status IN ('NEW', 'PROCESSING') ORDER BY created_at"
updateOrderByNumberQuery = "UPDATE orders SET status = $1, accrual =$2 WHERE number = $3"
)

type Order struct {
Number string `json:"number"`
Status string `json:"status"`
Expand Down Expand Up @@ -49,8 +56,7 @@ func (o *OrderService) Add(ctx context.Context, orderNum string) error {

childCtx, cancel := context.WithTimeout(ctx, time.Second*o.queryTimeOut)
defer cancel()
err := o.db.QueryRowContext(childCtx, `INSERT INTO orders (id, user_id, number) VALUES ($1, $2, $3)
ON CONFLICT(number) DO UPDATE SET number = EXCLUDED.number RETURNING id, user_id`, orderID, ctx.Value(authenticate.ContextUserID), orderNum).Scan(&baseOrderID, &baseUserID)
err := o.db.QueryRowContext(childCtx, addOrderQuery, orderID, ctx.Value(authenticate.ContextUserID), orderNum).Scan(&baseOrderID, &baseUserID)
if err != nil {
return err
}
Expand All @@ -68,7 +74,7 @@ func (o *OrderService) GetAll(ctx context.Context) ([]Order, error) {
childCtx, cancel := context.WithTimeout(ctx, time.Second*o.queryTimeOut)
defer cancel()

rows, err := o.db.QueryContext(childCtx, "SELECT number, status, accrual, created_at FROM orders WHERE user_id = $1 ORDER BY created_at DESC", ctx.Value(authenticate.ContextUserID))
rows, err := o.db.QueryContext(childCtx, getAllOrdersQuery, ctx.Value(authenticate.ContextUserID))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -103,7 +109,7 @@ func (o *OrderService) GetUnComplete(ctx context.Context) ([]string, error) {
childCtx, cancel := context.WithTimeout(ctx, time.Second*o.queryTimeOut)
defer cancel()

rows, err := o.db.QueryContext(childCtx, "SELECT number FROM orders WHERE status IN ('NEW', 'PROCESSING') ORDER BY created_at")
rows, err := o.db.QueryContext(childCtx, getUnCompleteOrdersQuery)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -134,13 +140,13 @@ func (o *OrderService) ChangeStatus(ctx context.Context, data OrderFromAccrual)
if err != nil {
return err
}
_, err = tx.ExecContext(childCtx, "UPDATE orders SET status = $1, accrual =$2 WHERE number = $3", data.Status, data.Accrual, data.Order)
_, err = tx.ExecContext(childCtx, updateOrderByNumberQuery, data.Status, data.Accrual, data.Order)
if err != nil {
_ = tx.Rollback()
return err
}
if data.Accrual > 0 {
_, err = tx.ExecContext(childCtx, "UPDATE users SET balance = balance + $1 WHERE id = (SELECT user_id FROM orders WHERE number = $2)", data.Accrual, data.Order)
_, err = tx.ExecContext(childCtx, updateBalanceByOrderQuery, data.Accrual, data.Order)
if err != nil {
_ = tx.Rollback()
return err
Expand Down
22 changes: 15 additions & 7 deletions internal/services/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,19 @@ var ErrLoginExists = fmt.Errorf("login exists")
var ErrValidation = fmt.Errorf("validation error")
var ErrGeneratePassword = fmt.Errorf("generate password error")

const minPasswordLength = 6
const maxPasswordLength = 72
const minLoginLength = 3
const maxLoginLength = 255
const (
minPasswordLength = 6
maxPasswordLength = 72
minLoginLength = 3
maxLoginLength = 255
)

const (
addUserQuery = "INSERT INTO users (id, login, password) VALUES ($1, $2, $3) ON CONFLICT(login) DO UPDATE SET login = EXCLUDED.login RETURNING id"
getUserByLoginQuery = "SELECT id, password FROM users WHERE login = $1"
updateBalanceByOrderQuery = "UPDATE users SET balance = balance + $1 WHERE id = (SELECT user_id FROM orders WHERE number = $2)"
updateBalanceByIdQuery = "UPDATE users SET balance = balance - $2 WHERE id = $1"
)

type InputDataUser struct {
Login string `json:"login"`
Expand Down Expand Up @@ -47,8 +56,7 @@ func (u *UserService) Add(ctx context.Context, input InputDataUser) (uuid.UUID,
userID := uuid.NewString()
childCtx, cancel := context.WithTimeout(ctx, time.Second*u.queryTimeOut)
defer cancel()
err = u.db.QueryRowContext(childCtx, "INSERT INTO users (id, login, password) VALUES ($1, $2, $3) ON CONFLICT(login) DO UPDATE SET login = EXCLUDED.login RETURNING id",
userID, input.Login, string(bytes)).Scan(&baseUserID)
err = u.db.QueryRowContext(childCtx, addUserQuery, userID, input.Login, string(bytes)).Scan(&baseUserID)
if err != nil {
return uuid.Nil, err
}
Expand All @@ -61,7 +69,7 @@ func (u *UserService) Add(ctx context.Context, input InputDataUser) (uuid.UUID,
func (u *UserService) Login(ctx context.Context, input InputDataUser) (uuid.UUID, error) {
childCtx, cancel := context.WithTimeout(ctx, time.Second*u.queryTimeOut)
defer cancel()
row := u.db.QueryRowContext(childCtx, "SELECT id, password FROM users WHERE login = $1", input.Login)
row := u.db.QueryRowContext(childCtx, getUserByLoginQuery, input.Login)

var userID, password string
err := row.Scan(&userID, &password)
Expand Down
16 changes: 10 additions & 6 deletions internal/services/withdrawal.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import (
"time"
)

const (
addWithdrawalQuery = "INSERT INTO withdrawals (user_id, number, sum) VALUES ($1, $2, $3) RETURNING id"
getAllWithdrawalsQuery = "SELECT number, sum, created_at FROM withdrawals WHERE user_id = $1 ORDER BY created_at DESC"
getBalanceQuery = "SELECT balance, (SELECT COALESCE(SUM(w.sum), 0) FROM withdrawals w WHERE w.user_id = u.id) FROM users u WHERE id = $1"
)

type InputWithdrawal struct {
OrderNum string `json:"order"`
Sum float64 `json:"sum"`
Expand Down Expand Up @@ -54,7 +60,7 @@ func (w *WithdrawalService) Add(ctx context.Context, input InputWithdrawal) erro
if err != nil {
return err
}
_, err = tx.ExecContext(childCtx, "UPDATE users SET balance = balance - $2 WHERE id = $1", userID, input.Sum)
_, err = tx.ExecContext(childCtx, updateBalanceByIdQuery, userID, input.Sum)
if err != nil {
_ = tx.Rollback()
var pgError *pgconn.PgError
Expand All @@ -65,7 +71,7 @@ func (w *WithdrawalService) Add(ctx context.Context, input InputWithdrawal) erro
}

var withdrawID string
err = tx.QueryRowContext(childCtx, "INSERT INTO withdrawals (user_id, number, sum) VALUES ($1, $2, $3) RETURNING id", userID, input.OrderNum, input.Sum).Scan(&withdrawID)
err = tx.QueryRowContext(childCtx, addWithdrawalQuery, userID, input.OrderNum, input.Sum).Scan(&withdrawID)
if err != nil {
_ = tx.Rollback()
if errors.Is(err, sql.ErrNoRows) {
Expand All @@ -81,8 +87,7 @@ func (w *WithdrawalService) GetAll(ctx context.Context) ([]Withdrawal, error) {
childCtx, cancel := context.WithTimeout(ctx, time.Second*w.queryTimeOut)
defer cancel()

rows, err := w.db.QueryContext(childCtx, "SELECT number, sum, created_at FROM withdrawals WHERE user_id = $1 ORDER BY created_at DESC",
ctx.Value(authenticate.ContextUserID))
rows, err := w.db.QueryContext(childCtx, getAllWithdrawalsQuery, ctx.Value(authenticate.ContextUserID))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -113,8 +118,7 @@ func (w *WithdrawalService) GetBalance(ctx context.Context) (BalanceInfo, error)
childCtx, cancel := context.WithTimeout(ctx, time.Second*w.queryTimeOut)
defer cancel()

row := w.db.QueryRowContext(childCtx, "SELECT balance, (SELECT COALESCE(SUM(w.sum), 0) FROM withdrawals w WHERE w.user_id = u.id) FROM users u WHERE id = $1",
ctx.Value(authenticate.ContextUserID))
row := w.db.QueryRowContext(childCtx, getBalanceQuery, ctx.Value(authenticate.ContextUserID))
if err := row.Scan(&balanceInfo.Current, &balanceInfo.Withdrawn); err != nil {
return balanceInfo, errors.New("user not found")
}
Expand Down
3 changes: 1 addition & 2 deletions internal/workers/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ func (w *OrderWorker) Run() {
errorCh := w.worker()

go func() {
for {
err := <-errorCh
for err := range errorCh {
if err != nil && retryCount < w.conf.RetryStartWorkerCount {
w.worker()
retryCount++
Expand Down

0 comments on commit 736760f

Please sign in to comment.