Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d412cb8
Запуск сервера. Получение конфига
nessai1 Nov 12, 2023
fcb6029
Загрузка конфигурации из .env
nessai1 Nov 12, 2023
7707498
Сделал логгирование сервиса
nessai1 Nov 14, 2023
642f87a
Сделал работу с БД в сервисе
nessai1 Nov 14, 2023
ba6e84a
Пользователь, контроллер юзеров, тесты под него
nessai1 Nov 15, 2023
a95957f
Метод добавления юзера
nessai1 Nov 15, 2023
a1854fe
Репозиторий пользователей под postgres
nessai1 Nov 16, 2023
34a8405
Добавил контекст к операциям чтения/записи пользователя; Конкретизиро…
nessai1 Nov 18, 2023
135c09e
Обработчики авторизации/регистрации. Начало
nessai1 Nov 18, 2023
05d6b12
Вынес репозиторий работающий с картой для переиспользования в тестиро…
nessai1 Nov 19, 2023
d21935f
Обработчики авторизации/регистрации
nessai1 Nov 19, 2023
76fb86a
Схема БД в первом приближении
nessai1 Nov 19, 2023
05dd878
Алгоритм Луна для проверки номеров заказов
nessai1 Nov 20, 2023
a2f93b5
Поправил схему БД. Написал миграцию для заказов типа enrollment
nessai1 Nov 20, 2023
ada2987
Добавил сущность enrollment. Первая часть реализации работы с сущност…
nessai1 Nov 21, 2023
9d6f143
Fix auth context
nessai1 Nov 25, 2023
38b7969
Добавил ID для пользователей
nessai1 Nov 25, 2023
a7d7fee
Загрузка заказа. Часть обработчика
nessai1 Nov 26, 2023
eecfc2e
Правки по ревью
nessai1 Nov 27, 2023
cefbff1
Обработка добавления заказа
nessai1 Nov 30, 2023
9b7812c
Пофиксил запись accrual в заказ
nessai1 Dec 3, 2023
131c00a
Убрал филд accrual в списке заказов если стоит дефолтное значение
nessai1 Dec 3, 2023
c05d093
История заказов (withdrawals)
nessai1 Dec 3, 2023
88098bf
Переделана работа регистрации на воркеров; Работа с транзакциями
nessai1 Dec 4, 2023
2298989
Add gzip middleware
nessai1 Dec 4, 2023
768699a
Merge branch 'master' into loyalty-service
nessai1 Dec 4, 2023
96fe85c
Add content type to handlers
nessai1 Dec 4, 2023
75ac086
Fix vet testes
nessai1 Dec 4, 2023
1c9b6d7
Правки по ревью, ч.1
nessai1 Dec 10, 2023
af99b07
tests fixes
nessai1 Dec 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SECRET_KEY=yoursecretkey
RUN_ADDRESS=http://localhost:8080
DATABASE_URI='host=localhost user=admin password=123123 dbname=gophermat sslmode=disable'
ACCRUAL_SYSTEM_ADDRESS=http://localhost:8081
ENV_TYPE=development
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ vendor/
# IDEs directories
.idea
.vscode

.env
11 changes: 10 additions & 1 deletion cmd/gophermart/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
package main

func main() {}
import (
"github.com/nessai1/gophermat/internal/gophermart"
"log"
)

func main() {
if err := gophermart.Start(); err != nil {
log.Fatalf("error while listening application: %s", err.Error())
}
}
1 change: 1 addition & 0 deletions dev/sql_scheme.drawio

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module github.com/nessai1/gophermat

go 1.21.3

require (
github.com/go-chi/chi v1.5.4
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-migrate/migrate/v4 v4.16.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
55 changes: 55 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-migrate/migrate/v4 v4.16.2 h1:8coYbMKUyInrFk1lfGfRovTLAW7PhWp8qQDT2iKfuoA=
github.com/golang-migrate/migrate/v4 v4.16.2/go.mod h1:pfcJX4nPHaVdc5nmdCikFBWtm+UBpiZjRNNsyBbp0/o=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw=
github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
72 changes: 72 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package config

import (
"flag"
"github.com/joho/godotenv"
"os"
)

type EnvType string

const (
EnvTypeDevelopment EnvType = "development"
EnvTypeStage EnvType = "stage"
EnvTypeProduction EnvType = "production"
)

const defaultSecretKey = "default_secret_key"

type Config struct {
ServiceAddr string
AccrualServiceAddr string
DBConnectionStr string
SecretKey string
EnvType EnvType
}

func GetConfig() *Config {
return fetchConfig()
}

func fetchConfig() *Config {

serviceAddr := flag.String("a", "", "Address of service")
databaseConnection := flag.String("d", "", "Database connection uri")
accrualServiceAddr := flag.String("r", "", "Accrual service url")

flag.Parse()
godotenv.Load() // May not have .env

if serviceAddrEnv := os.Getenv("RUN_ADDRESS"); serviceAddrEnv != "" {
*serviceAddr = serviceAddrEnv
}

if databaseConnectionEnv := os.Getenv("DATABASE_URI"); databaseConnectionEnv != "" {
*databaseConnection = databaseConnectionEnv
}

if accrualServiceAddrEnv := os.Getenv("ACCRUAL_SYSTEM_ADDRESS"); accrualServiceAddrEnv != "" {
*accrualServiceAddr = accrualServiceAddrEnv
}

var envType EnvType
envTypeStr := os.Getenv("ENV_TYPE")
if envTypeStr == "" {
envType = EnvTypeProduction
} else {
envType = EnvType(envTypeStr)
}

secretKey := os.Getenv("ACCRUAL_SYSTEM_ADDRESS")
if secretKey == "" {
secretKey = defaultSecretKey
}

return &Config{
ServiceAddr: *serviceAddr,
AccrualServiceAddr: *accrualServiceAddr,
DBConnectionStr: *databaseConnection,
SecretKey: secretKey,
EnvType: envType,
}
}
51 changes: 51 additions & 0 deletions internal/database/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package database

import (
"database/sql"
"errors"
"fmt"

"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"

_ "github.com/jackc/pgx/v5/stdlib"

_ "github.com/golang-migrate/migrate/v4/source/file"
)

func InitSQLDriverByConnectionURI(connectionURI string) (*sql.DB, error) {
db, err := sql.Open("pgx", connectionURI)
if err != nil {
return nil, fmt.Errorf("cannot open sql connection: %w", err)
}

err = db.Ping()
if err != nil {
return nil, fmt.Errorf("cannot ping database: %w", err)
}

err = initMigrations(db)
if err != nil && !errors.Is(err, migrate.ErrNoChange) {
return nil, fmt.Errorf("cannot init migrations for sql connection: %w", err)
}

return db, nil
}

func initMigrations(db *sql.DB) error {
driver, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
return fmt.Errorf("error while create driver with instance: %w", err)
}

migrations, err := migrate.NewWithDatabaseInstance("file:migrations", "postgres", driver)
if err != nil {
return fmt.Errorf("error while create migrations: %w", err)
}

if err = migrations.Up(); err != nil {
return err
}

return nil
}
86 changes: 86 additions & 0 deletions internal/gophermart/gophermart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package gophermart

import (
"fmt"
"github.com/go-chi/chi"
"github.com/nessai1/gophermat/internal/config"
"github.com/nessai1/gophermat/internal/database"
"github.com/nessai1/gophermat/internal/handler"
"github.com/nessai1/gophermat/internal/intransaction"
"github.com/nessai1/gophermat/internal/logger"
"github.com/nessai1/gophermat/internal/order"
"github.com/nessai1/gophermat/internal/user"
"github.com/nessai1/gophermat/internal/zip"
"go.uber.org/zap"
"net/http"
)

func Start() error {
router := chi.NewRouter()
cfg := config.GetConfig()

log, err := logger.NewLogger(cfg.EnvType)
if err != nil {
return fmt.Errorf("cannot initialize logger on start service: %w", err)
}

db, err := database.InitSQLDriverByConnectionURI(cfg.DBConnectionStr)
if err != nil {
return fmt.Errorf("cannot initialize database on start service: %w", err)
}

userController := user.NewController(user.CreatePGXRepository(db))
authHandler := handler.NewAuthHandler(log, cfg.SecretKey, userController)

router.Use(zip.GetZipMiddleware(log))

authMux := chi.NewMux()
authMux.Post("/api/user/register", authHandler.HandleRegisterUser)
authMux.Post("/api/user/login", authHandler.HandleAuthUser)

transaction := intransaction.NewPGXTransaction(db)

enrollmentController := order.NewEnrollmentController(cfg.AccrualServiceAddr, order.CreatePGXEnrollmentRepository(db), userController)
ch, err := order.StartEnrollmentWorker(userController, enrollmentController, log, cfg.AccrualServiceAddr, transaction)
if err != nil {
return fmt.Errorf("error while starting enrollment worker: %w", err)
}

enrollmentController.EnrollmentCh = ch

enrollmentHandler := handler.EnrollmentOrderHandler{
Logger: log,
EnrollmentController: enrollmentController,
}
enrollmentMux := chi.NewMux()
enrollmentMux.Use(authHandler.MiddlewareAuthorizeRequest())
enrollmentMux.Post("/", enrollmentHandler.HandleLoadOrders)
enrollmentMux.Get("/", enrollmentHandler.HandleGetOrders)

balanceHandler := handler.BalanceHandler{
Logger: log,
WithdrawController: order.NewWithdrawController(order.NewPGXWithdrawRepository(db), userController, transaction),
}

balanceMux := chi.NewMux()
balanceMux.Use(authHandler.MiddlewareAuthorizeRequest())
balanceMux.Get("/", balanceHandler.HandleGetBalance)
balanceMux.Post("/withdraw", balanceHandler.HandleAddWithdraw)

withdrawInfoMux := chi.NewMux()
withdrawInfoMux.Use(authHandler.MiddlewareAuthorizeRequest())
withdrawInfoMux.Get("/", balanceHandler.HandleGetListWithdraw)

router.Mount("/", authMux)
router.Mount("/api/user/orders", enrollmentMux)
router.Mount("/api/user/balance", balanceMux)
router.Mount("/api/user/withdrawals", withdrawInfoMux)

log.Info("starting service", zap.String("service address", cfg.ServiceAddr))

if err := http.ListenAndServe(cfg.ServiceAddr, router); err != nil {
return err
}

return nil
}
Loading