Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Chystik committed Oct 27, 2023
1 parent 65d42fa commit 29d0de1
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 96 deletions.
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Logs
*log

# Binaries
/cmd/gophermart/main
/cmd/gophermart/gophermart
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# Binaries
cmd/gophermart/main
cmd/gophermart/gophermart
.tools/

# Dependency directories (remove the comment below to include it)
vendor/
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#SHELL = /bin/bash
.PHONY: autotest dep test race lint gen cover statictest dev-up dev-down accrual dev-test
.PHONY: autotest dep test race lint gen cover statictest dev-up dev-down accrual dev-autotest

dep:
go mod download
Expand All @@ -23,11 +23,11 @@ autotest:
-gophermart-binary-path=$(gophermart-bin) \
-gophermart-host=localhost \
-gophermart-port=8080 \
-gophermart-database-uri="postgresql://postgres:postgres@localhost:5432/praktikum?sslmode=disable" \
-gophermart-database-uri="postgresql://postgres:postgres@localhost/praktikum?sslmode=disable" \
-accrual-binary-path=./cmd/accrual/accrual_linux_amd64 \
-accrual-host=localhost \
-accrual-port=$(accrual-port) \
-accrual-database-uri="postgresql://postgres:postgres@localhost:5432/praktikum?sslmode=disable"
-accrual-database-uri="postgresql://postgres:postgres@localhost/praktikum?sslmode=disable"
rm $(gophermart-bin)

gen:
Expand All @@ -47,7 +47,7 @@ dev-up:
dev-down:
docker-compose -f=docker-compose.dev.yml --env-file=.env.dev down --rmi local

dev-test:
dev-autotest:
docker-compose -f=docker-compose.dev-test.yml --env-file=.env.dev up -d
docker-compose -f=docker-compose.dev-test.yml --env-file=.env.dev logs -f tests
docker-compose -f=docker-compose.dev-test.yml --env-file=.env.dev down --rmi local
Expand Down
57 changes: 18 additions & 39 deletions internal/controller/rest_api_handlers/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"io"
"net/http"
"strconv"

"github.com/Chystik/gophermart/internal/infrastructure/repository"
"github.com/Chystik/gophermart/internal/models"
Expand All @@ -31,37 +30,32 @@ func newOrderRoutes(oi usecase.OrderInteractor, l logger.AppLogger) *orderRoutes

func (or *orderRoutes) uploadOrders(w http.ResponseWriter, r *http.Request) {
var order models.Order
var numberRaw []byte
var number int
var user models.User
var orderNumberRaw []byte
var ctx = context.Background()
var err error

numberRaw, err = io.ReadAll(r.Body)
orderNumberRaw, err = io.ReadAll(r.Body)
if err != nil {
errorJSON(w, err, http.StatusInternalServerError, or.logger)
return
}

// check number
number, err = strconv.Atoi(string(numberRaw))
if err != nil {
errorJSON(w, err, http.StatusUnprocessableEntity, or.logger)
return
}
order.Number = string(orderNumberRaw)

// validate
if !valid(number) {
if !order.ValidLuhnNumber() {
errorJSON(w, errNotValidLuhn, http.StatusUnprocessableEntity, or.logger)
return
}

order.Number = string(numberRaw)
order.User, err = getUserLogin(r.Context()) //claims.Login
user.Login, err = user.GetLoginFromContext(r.Context())
if err != nil {
errorJSON(w, err, http.StatusUnauthorized, or.logger)
return
}

order.User = user.Login

err = or.orderInteractor.Create(ctx, order)
if err != nil {
if err == repository.ErrUploadedByUser {
Expand All @@ -79,7 +73,16 @@ func (or *orderRoutes) uploadOrders(w http.ResponseWriter, r *http.Request) {
}

func (or *orderRoutes) downloadOrders(w http.ResponseWriter, r *http.Request) {
orders, err := or.orderInteractor.GetAll(r.Context())
var login models.User
var err error

login.Login, err = login.GetLoginFromContext(r.Context())
if err != nil {
errorJSON(w, err, http.StatusUnauthorized, or.logger)
return
}

orders, err := or.orderInteractor.GetList(r.Context(), login)
if err != nil {
errorJSON(w, err, http.StatusInternalServerError, or.logger)
return
Expand All @@ -92,27 +95,3 @@ func (or *orderRoutes) downloadOrders(w http.ResponseWriter, r *http.Request) {

writeJSON(w, http.StatusOK, "application/json", orders, or.logger)
}

// Valid checks the order number using the Luhn algorithm
func valid(number int) bool {
var luhn int

checksum := func(n int) int {
for i := 0; n > 0; i++ {
cur := n % 10

if i%2 == 0 {
cur = cur * 2
if cur > 9 {
cur = cur%10 + cur/10
}
}

luhn += cur
n = n / 10
}
return luhn % 10
}

return (number%10+checksum(number/10))%10 == 0
}
50 changes: 11 additions & 39 deletions internal/controller/rest_api_handlers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package restapihandlers
import (
"context"
"encoding/json"
"errors"
"net/http"
"strconv"
"time"

"github.com/Chystik/gophermart/internal/infrastructure/repository"
Expand All @@ -15,16 +13,6 @@ import (
"github.com/golang-jwt/jwt/v5"
)

const (
cookieName = "token"
claimsKey models.ClaimsKey = "props"
tokenExpiration = 5 * time.Minute
)

var (
errWrongAuthClaims = errors.New("wrong auth claims")
)

type userRoutes struct {
userInteractor usecase.UserInteractor
logger logger.AppLogger
Expand Down Expand Up @@ -109,17 +97,15 @@ func (ur *userRoutes) login(w http.ResponseWriter, r *http.Request) {

func (ur *userRoutes) getBalance(w http.ResponseWriter, r *http.Request) {
var ctx = context.Background()
var user models.User
var err error

login, err := getUserLogin(r.Context())
user.Login, err = user.GetLoginFromContext(r.Context())
if err != nil {
errorJSON(w, err, http.StatusUnauthorized, ur.logger)
return
}

user := models.User{
Login: login,
}

user, err = ur.userInteractor.Get(ctx, user)
if err != nil {
errorJSON(w, err, http.StatusInternalServerError, ur.logger)
Expand All @@ -133,36 +119,31 @@ func (ur *userRoutes) getBalance(w http.ResponseWriter, r *http.Request) {

func (ur *userRoutes) withdraw(w http.ResponseWriter, r *http.Request) {
var wth models.Withdrawal
var order models.Order
var user models.User
var ctx = context.Background()
var order int
var err error
var login string

err = json.NewDecoder(r.Body).Decode(&wth)
if err != nil {
errorJSON(w, err, http.StatusUnprocessableEntity, ur.logger)
return
}

order, err = strconv.Atoi(wth.Order)
if err != nil {
errorJSON(w, errNotValidLuhn, http.StatusUnprocessableEntity, ur.logger)
return
}
order.Number = wth.Order

// Validate order number
if !valid(order) {
if !order.ValidLuhnNumber() {
errorJSON(w, errNotValidLuhn, http.StatusUnprocessableEntity, ur.logger)
return
}

login, err = getUserLogin(r.Context())
user.Login, err = user.GetLoginFromContext(r.Context())
if err != nil {
errorJSON(w, errNotValidLuhn, http.StatusUnauthorized, ur.logger)
return
}

err = ur.userInteractor.Withdraw(ctx, wth, models.User{Login: login})
err = ur.userInteractor.Withdraw(ctx, wth, user)
if err != nil {
var stat int
if err == usecase.ErrNotEnoughMoney {
Expand Down Expand Up @@ -195,7 +176,7 @@ func (ur *userRoutes) getWithdrawals(w http.ResponseWriter, r *http.Request) {
}

func (ur *userRoutes) authorize(w http.ResponseWriter, user models.User) {
expirationTime := time.Now().Add(tokenExpiration)
expirationTime := time.Now().Add(models.TokenExpiration)

// Create the JWT claims, which includes the username and expiry time
claims := &models.AuthClaims{
Expand All @@ -216,17 +197,8 @@ func (ur *userRoutes) authorize(w http.ResponseWriter, user models.User) {

// Set cookie
http.SetCookie(w, &http.Cookie{
Name: cookieName,
Name: models.CookieName,
Value: tokenStr,
Expires: expirationTime,
})
}

func getUserLogin(ctx context.Context) (string, error) {
claims, ok := ctx.Value(claimsKey).(*models.AuthClaims)
if !ok {
return "", errWrongAuthClaims
}

return claims.Login, nil
}
10 changes: 2 additions & 8 deletions internal/infrastructure/repository/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,16 @@ func (or *orderRepository) Get(ctx context.Context, order models.Order) (models.
return order, nil
}

func (or *orderRepository) GetAll(ctx context.Context) ([]models.Order, error) {
func (or *orderRepository) GetList(ctx context.Context, login models.User) ([]models.Order, error) {
var orders []models.Order
var claimsKey models.ClaimsKey = "props"

claims, ok := ctx.Value(claimsKey).(*models.AuthClaims)
if !ok {
return orders, errors.New("bad login")
}

query := `
SELECT number, user_id, status, accrual, uploaded_at
FROM praktikum.order
WHERE user_id = $1
ORDER BY uploaded_at ASC`

err := or.SelectContext(ctx, &orders, query, claims.Login)
err := or.SelectContext(ctx, &orders, query, login.Login)
if err != nil {
return nil, err
}
Expand Down
17 changes: 16 additions & 1 deletion internal/models/auth.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
package models

import "github.com/golang-jwt/jwt/v5"
import (
"errors"
"time"

"github.com/golang-jwt/jwt/v5"
)

type ClaimsKey string

const (
CookieName = "token"
ClaimsKeyName ClaimsKey = "props"
TokenExpiration = 5 * time.Minute
)

var (
errWrongAuthClaims = errors.New("wrong auth claims")
)

type AuthClaims struct {
Login string `json:"login"`
jwt.RegisteredClaims
Expand Down
28 changes: 28 additions & 0 deletions internal/models/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package models

import (
"fmt"
"strconv"
"strings"
"time"
)
Expand Down Expand Up @@ -45,3 +46,30 @@ func (f RFC3339Time) MarshalJSON() ([]byte, error) {
}
return []byte(fmt.Sprintf("\"%s\"", f.Time.Format(time.RFC3339))), nil
}

// Valid checks the order number using the Luhn algorithm
func (o Order) ValidLuhnNumber() bool {
luhn, err := strconv.Atoi(o.Number)
if err != nil {
return false
}

checksum := func(n int) int {
for i := 0; n > 0; i++ {
cur := n % 10

if i%2 == 0 {
cur = cur * 2
if cur > 9 {
cur = cur%10 + cur/10
}
}

luhn += cur
n = n / 10
}
return luhn % 10
}

return (luhn%10+checksum(luhn/10))%10 == 0
}
12 changes: 11 additions & 1 deletion internal/models/user.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package models

import (
"context"
"errors"

"golang.org/x/crypto/bcrypt"
Expand Down Expand Up @@ -33,7 +34,7 @@ func (u *User) SetPassword() error {
return nil
}

func (u *User) Authenticate(actual User) error {
func (u User) Authenticate(actual User) error {
err := bcrypt.CompareHashAndPassword([]byte(actual.Password), []byte(u.Password))
if err != nil {
if err == bcrypt.ErrMismatchedHashAndPassword {
Expand All @@ -44,3 +45,12 @@ func (u *User) Authenticate(actual User) error {

return nil
}

func (u User) GetLoginFromContext(ctx context.Context) (string, error) {
claims, ok := ctx.Value(ClaimsKeyName).(*AuthClaims)
if !ok {
return "", errWrongAuthClaims
}

return claims.Login, nil
}
Loading

0 comments on commit 29d0de1

Please sign in to comment.