From 7186bc4f62d26dc939950e44b4f83c4860c1eeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D1=88=D0=BA=D0=BE=D0=B2=20=D0=94=D0=BC=D0=B8?= =?UTF-8?q?=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 17 Sep 2024 23:41:58 +0300 Subject: [PATCH] fix review part 3 --- cmd/gophermart/main.go | 4 +++- internal/authenticate/authenticate.go | 30 ++++++++++++++++----------- internal/config/config.go | 4 ++++ internal/handlers/add_orders.go | 2 +- internal/handlers/add_withdrawals.go | 2 +- internal/handlers/get_balance.go | 2 +- internal/handlers/get_orders.go | 2 +- internal/handlers/get_withdrawals.go | 2 +- internal/handlers/login.go | 4 ++-- internal/handlers/register.go | 4 ++-- internal/server/authenticate.go | 4 ++-- internal/server/server.go | 18 +++++++++------- internal/services/order.go | 11 ++-------- internal/services/user.go | 5 ----- internal/services/withdrawal.go | 6 ------ internal/workers/order.go | 4 ++-- 16 files changed, 50 insertions(+), 54 deletions(-) diff --git a/cmd/gophermart/main.go b/cmd/gophermart/main.go index a179b34..bceb5fe 100644 --- a/cmd/gophermart/main.go +++ b/cmd/gophermart/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "github.com/spqrcor/gofermart/internal/authenticate" "github.com/spqrcor/gofermart/internal/client" "github.com/spqrcor/gofermart/internal/config" "github.com/spqrcor/gofermart/internal/db" @@ -28,6 +29,7 @@ func main() { orderQueue := make(chan string) defer close(orderQueue) + authService := authenticate.NewAuthenticateService(conf.SecretKey, conf.TokenExp) userService := services.NewUserService(dbRes, conf.QueryTimeOut) orderService := services.NewOrderService(orderQueue, dbRes, loggerRes, conf.QueryTimeOut) withdrawalService := services.NewWithdrawalService(dbRes, loggerRes, conf.QueryTimeOut) @@ -36,7 +38,7 @@ func main() { orderWorker := workers.NewOrderWorker(mainCtx, orderService, orderQueue, loggerRes, conf.WorkerCount, orderClient) orderWorker.Run() - appServer := server.NewServer(userService, orderService, withdrawalService, loggerRes, conf.RunAddr) + appServer := server.NewServer(userService, orderService, withdrawalService, loggerRes, conf.RunAddr, authService) if err := appServer.Start(); err != nil { loggerRes.Error(err.Error()) } diff --git a/internal/authenticate/authenticate.go b/internal/authenticate/authenticate.go index 92dc66a..4a3d69a 100644 --- a/internal/authenticate/authenticate.go +++ b/internal/authenticate/authenticate.go @@ -17,37 +17,43 @@ type ContextKey string var ContextUserID ContextKey = "UserID" -const tokenExp = time.Hour * 3 -const secretKey = "KLJ-fo3Fksd3fl!=" +type Authenticate struct { + secretKey string + tokenExp time.Duration +} + +func NewAuthenticateService(secretKey string, tokenExp time.Duration) *Authenticate { + return &Authenticate{secretKey: secretKey, tokenExp: tokenExp} +} -func CreateCookie(UserID uuid.UUID) (http.Cookie, error) { - token, err := createToken(UserID) +func (a *Authenticate) createCookie(UserID uuid.UUID) (http.Cookie, error) { + token, err := a.createToken(UserID) if err != nil { return http.Cookie{}, err } - return http.Cookie{Name: "Authorization", Value: token, Expires: time.Now().Add(tokenExp), HttpOnly: true, Path: "/"}, nil + return http.Cookie{Name: "Authorization", Value: token, Expires: time.Now().Add(a.tokenExp), HttpOnly: true, Path: "/"}, nil } -func createToken(UserID uuid.UUID) (string, error) { +func (a *Authenticate) createToken(UserID uuid.UUID) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{ RegisteredClaims: jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(time.Now().Add(tokenExp)), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(a.tokenExp)), }, UserID: UserID, }) - tokenString, err := token.SignedString([]byte(secretKey)) + tokenString, err := token.SignedString([]byte(a.secretKey)) if err != nil { return "", err } return "Bearer " + tokenString, nil } -func GetUserIDFromCookie(tokenString string) (uuid.UUID, error) { +func (a *Authenticate) GetUserIDFromCookie(tokenString string) (uuid.UUID, error) { claims := &Claims{} token, err := jwt.ParseWithClaims(strings.TrimPrefix(tokenString, "Bearer "), claims, func(t *jwt.Token) (interface{}, error) { - return []byte(secretKey), nil + return []byte(a.secretKey), nil }) if err != nil { return uuid.Nil, err @@ -59,8 +65,8 @@ func GetUserIDFromCookie(tokenString string) (uuid.UUID, error) { return claims.UserID, nil } -func SetCookie(rw http.ResponseWriter, UserID uuid.UUID) { - cookie, err := CreateCookie(UserID) +func (a *Authenticate) SetCookie(rw http.ResponseWriter, UserID uuid.UUID) { + cookie, err := a.createCookie(UserID) if err == nil { http.SetCookie(rw, &cookie) } diff --git a/internal/config/config.go b/internal/config/config.go index 65a6dbf..ed4858d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,6 +15,8 @@ type Config struct { DatabaseURI string `env:"DATABASE_URI"` QueryTimeOut time.Duration `env:"QUERY_TIME_OUT"` WorkerCount int `env:"WORKER_COUNT"` + SecretKey string `env:"SECRET_KEY"` + TokenExp time.Duration `env:"TOKEN_EXP"` } func NewConfig() Config { @@ -25,6 +27,8 @@ func NewConfig() Config { DatabaseURI: "", QueryTimeOut: 3, WorkerCount: 3, + SecretKey: "KLJ-fo3Fksd3fl!=", + TokenExp: time.Hour * 3, } flag.StringVar(&cfg.RunAddr, "a", cfg.RunAddr, "address and port to run server") diff --git a/internal/handlers/add_orders.go b/internal/handlers/add_orders.go index 7510195..331e4ba 100644 --- a/internal/handlers/add_orders.go +++ b/internal/handlers/add_orders.go @@ -7,7 +7,7 @@ import ( "net/http" ) -func AddOrdersHandler(o services.OrderRepository) http.HandlerFunc { +func AddOrdersHandler(o *services.OrderService) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { orderNum, err := utils.FromPostPlain(req) if err != nil { diff --git a/internal/handlers/add_withdrawals.go b/internal/handlers/add_withdrawals.go index 7938163..c0add23 100644 --- a/internal/handlers/add_withdrawals.go +++ b/internal/handlers/add_withdrawals.go @@ -7,7 +7,7 @@ import ( "net/http" ) -func AddWithdrawalHandler(w services.WithdrawalRepository) http.HandlerFunc { +func AddWithdrawalHandler(w *services.WithdrawalService) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { var input services.InputWithdrawal if err := utils.FromPostJSON(req, &input); err != nil { diff --git a/internal/handlers/get_balance.go b/internal/handlers/get_balance.go index e140090..7bd94b1 100644 --- a/internal/handlers/get_balance.go +++ b/internal/handlers/get_balance.go @@ -6,7 +6,7 @@ import ( "net/http" ) -func GetBalanceHandler(w services.WithdrawalRepository) http.HandlerFunc { +func GetBalanceHandler(w *services.WithdrawalService) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { balance, err := w.GetBalance(req.Context()) if err != nil { diff --git a/internal/handlers/get_orders.go b/internal/handlers/get_orders.go index 71f9d7f..646d921 100644 --- a/internal/handlers/get_orders.go +++ b/internal/handlers/get_orders.go @@ -7,7 +7,7 @@ import ( "net/http" ) -func GetOrdersHandler(o services.OrderRepository) http.HandlerFunc { +func GetOrdersHandler(o *services.OrderService) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { orders, err := o.GetAll(req.Context()) if errors.Is(err, services.ErrOrdersNotFound) { diff --git a/internal/handlers/get_withdrawals.go b/internal/handlers/get_withdrawals.go index 017f0b3..16a6c00 100644 --- a/internal/handlers/get_withdrawals.go +++ b/internal/handlers/get_withdrawals.go @@ -7,7 +7,7 @@ import ( "net/http" ) -func GetWithdrawalsHandler(w services.WithdrawalRepository) http.HandlerFunc { +func GetWithdrawalsHandler(w *services.WithdrawalService) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { withdrawals, err := w.GetAll(req.Context()) if errors.Is(err, services.ErrWithdrawNotFound) { diff --git a/internal/handlers/login.go b/internal/handlers/login.go index b65aabf..dc945c9 100644 --- a/internal/handlers/login.go +++ b/internal/handlers/login.go @@ -8,7 +8,7 @@ import ( "net/http" ) -func LoginHandler(u services.UserRepository) http.HandlerFunc { +func LoginHandler(u *services.UserService, a *authenticate.Authenticate) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { var input services.InputDataUser if err := utils.FromPostJSON(req, &input); err != nil { @@ -25,7 +25,7 @@ func LoginHandler(u services.UserRepository) http.HandlerFunc { return } - authenticate.SetCookie(res, UserID) + a.SetCookie(res, UserID) res.WriteHeader(http.StatusOK) } } diff --git a/internal/handlers/register.go b/internal/handlers/register.go index 5843620..122a059 100644 --- a/internal/handlers/register.go +++ b/internal/handlers/register.go @@ -8,7 +8,7 @@ import ( "net/http" ) -func RegisterHandler(u services.UserRepository) http.HandlerFunc { +func RegisterHandler(u *services.UserService, a *authenticate.Authenticate) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { var input services.InputDataUser if err := utils.FromPostJSON(req, &input); err != nil { @@ -28,7 +28,7 @@ func RegisterHandler(u services.UserRepository) http.HandlerFunc { return } - authenticate.SetCookie(res, UserID) + a.SetCookie(res, UserID) res.WriteHeader(http.StatusOK) } } diff --git a/internal/server/authenticate.go b/internal/server/authenticate.go index 11482ca..5a8ddfa 100644 --- a/internal/server/authenticate.go +++ b/internal/server/authenticate.go @@ -7,7 +7,7 @@ import ( "net/http" ) -func authenticateMiddleware(logger *zap.Logger) func(next http.Handler) http.Handler { +func authenticateMiddleware(logger *zap.Logger, auth *authenticate.Authenticate) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("Authorization") @@ -15,7 +15,7 @@ func authenticateMiddleware(logger *zap.Logger) func(next http.Handler) http.Han http.Error(rw, err.Error(), http.StatusUnauthorized) return } else { - UserID, err := authenticate.GetUserIDFromCookie(cookie.Value) + UserID, err := auth.GetUserIDFromCookie(cookie.Value) if err != nil { logger.Error(err.Error()) http.Error(rw, err.Error(), http.StatusInternalServerError) diff --git a/internal/server/server.go b/internal/server/server.go index b2653a2..da728fb 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -3,6 +3,7 @@ package server import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" + "github.com/spqrcor/gofermart/internal/authenticate" "github.com/spqrcor/gofermart/internal/handlers" "github.com/spqrcor/gofermart/internal/services" "go.uber.org/zap" @@ -10,16 +11,17 @@ import ( ) type HTTPServer struct { - userService services.UserRepository - orderService services.OrderRepository - withdrawalService services.WithdrawalRepository + userService *services.UserService + orderService *services.OrderService + withdrawalService *services.WithdrawalService logger *zap.Logger runAddress string + authService *authenticate.Authenticate } -func NewServer(userService services.UserRepository, orderService services.OrderRepository, withdrawalService services.WithdrawalRepository, logger *zap.Logger, runAddress string) *HTTPServer { +func NewServer(userService *services.UserService, orderService *services.OrderService, withdrawalService *services.WithdrawalService, logger *zap.Logger, runAddress string, authService *authenticate.Authenticate) *HTTPServer { return &HTTPServer{ - userService: userService, orderService: orderService, withdrawalService: withdrawalService, logger: logger, runAddress: runAddress, + userService: userService, orderService: orderService, withdrawalService: withdrawalService, logger: logger, runAddress: runAddress, authService: authService, } } @@ -30,12 +32,12 @@ func (s *HTTPServer) Start() error { r.Use(getBodyMiddleware(s.logger)) r.Group(func(r chi.Router) { - r.Post("/api/user/register", handlers.RegisterHandler(s.userService)) - r.Post("/api/user/login", handlers.LoginHandler(s.userService)) + r.Post("/api/user/register", handlers.RegisterHandler(s.userService, s.authService)) + r.Post("/api/user/login", handlers.LoginHandler(s.userService, s.authService)) }) r.Group(func(r chi.Router) { - r.Use(authenticateMiddleware(s.logger)) + r.Use(authenticateMiddleware(s.logger, s.authService)) r.Post("/api/user/orders", handlers.AddOrdersHandler(s.orderService)) r.Get("/api/user/orders", handlers.GetOrdersHandler(s.orderService)) r.Get("/api/user/balance", handlers.GetBalanceHandler(s.withdrawalService)) diff --git a/internal/services/order.go b/internal/services/order.go index 2e50f54..29f6801 100644 --- a/internal/services/order.go +++ b/internal/services/order.go @@ -29,13 +29,6 @@ var ErrOrderUserExists = fmt.Errorf("order user exists") var ErrOrderInvalidFormat = fmt.Errorf("order invalid format") var ErrOrdersNotFound = fmt.Errorf("orders not found") -type OrderRepository interface { - Add(ctx context.Context, orderNum string) error - GetAll(ctx context.Context) ([]Order, error) - GetUnComplete(ctx context.Context) ([]string, error) - ChangeStatus(ctx context.Context, data OrderFromAccrual) error -} - type OrderService struct { orderQueue chan string db *sql.DB @@ -56,8 +49,8 @@ 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, `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) if err != nil { return err } else if ctx.Value(authenticate.ContextUserID) != uuid.MustParse(baseUserID) { diff --git a/internal/services/user.go b/internal/services/user.go index a47c311..4a9db20 100644 --- a/internal/services/user.go +++ b/internal/services/user.go @@ -25,11 +25,6 @@ type InputDataUser struct { Password string `json:"password"` } -type UserRepository interface { - Add(ctx context.Context, input InputDataUser) (uuid.UUID, error) - Login(ctx context.Context, input InputDataUser) (uuid.UUID, error) -} - type UserService struct { db *sql.DB queryTimeOut time.Duration diff --git a/internal/services/withdrawal.go b/internal/services/withdrawal.go index a3bfa02..6c2d75b 100644 --- a/internal/services/withdrawal.go +++ b/internal/services/withdrawal.go @@ -31,12 +31,6 @@ type BalanceInfo struct { var ErrBalance = fmt.Errorf("balance error") var ErrWithdrawNotFound = fmt.Errorf("withdraw not found") -type WithdrawalRepository interface { - Add(ctx context.Context, input InputWithdrawal) error - GetAll(ctx context.Context) ([]Withdrawal, error) - GetBalance(ctx context.Context) (BalanceInfo, error) -} - type WithdrawalService struct { db *sql.DB logger *zap.Logger diff --git a/internal/workers/order.go b/internal/workers/order.go index 08a0532..694dd94 100644 --- a/internal/workers/order.go +++ b/internal/workers/order.go @@ -10,14 +10,14 @@ import ( type OrderWorker struct { ctx context.Context - orderService services.OrderRepository + orderService *services.OrderService orderQueue chan string logger *zap.Logger workerCount int orderClient *client.OrderClient } -func NewOrderWorker(ctx context.Context, orderService services.OrderRepository, orderQueue chan string, logger *zap.Logger, workerCount int, orderClient *client.OrderClient) *OrderWorker { +func NewOrderWorker(ctx context.Context, orderService *services.OrderService, orderQueue chan string, logger *zap.Logger, workerCount int, orderClient *client.OrderClient) *OrderWorker { return &OrderWorker{ctx: ctx, orderService: orderService, orderQueue: orderQueue, logger: logger, workerCount: workerCount, orderClient: orderClient} }