send all files

This commit is contained in:
2024-07-21 00:15:14 -03:00
parent 1e8cda0139
commit c9464c4a6f
72 changed files with 6335 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
PORT=
JWT_KEY=
DATABASE_URL=
+21
View File
@@ -0,0 +1,21 @@
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
.env
+16
View File
@@ -0,0 +1,16 @@
FROM golang:latest
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY .env ./
COPY . .
RUN go build -o main
EXPOSE 3003
CMD ["./main"]
+1
View File
@@ -0,0 +1 @@
# api
+24
View File
@@ -0,0 +1,24 @@
package authmodule
import (
authdto "api/application/auth/dto"
"api/models/api"
)
type Controller interface {
Authorization(data *authdto.AuthDto) (*api.Response, int, error)
}
type controller struct {
AuthService
}
func newController(service AuthService) Controller {
return &controller{
AuthService: service,
}
}
func (c *controller) Authorization(data *authdto.AuthDto) (*api.Response, int, error) {
return c.AuthService.Authorization(data)
}
+34
View File
@@ -0,0 +1,34 @@
package authdto
import (
"api/libs/logger"
"errors"
"github.com/go-playground/validator/v10"
)
type AuthDto struct {
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
}
func (d *AuthDto) Validate() error {
validate := validator.New()
err := validate.Struct(d)
if err != nil {
// this check is only needed when your code could produce
// an invalid value for validation such as interface with nil
// value most including myself do not usually have code like this.
if _, ok := err.(*validator.InvalidValidationError); ok {
logger.Development.Info(err.Error())
}
for _, e := range err.(validator.ValidationErrors) {
err = errors.New(e.Field() + " " + e.Tag())
}
}
return err
}
+10
View File
@@ -0,0 +1,10 @@
package authmodule
import "github.com/gofiber/fiber/v2"
// apply routes in app fiber, with controllers and services defined
func AuthModuleDecorator(app *fiber.App) {
s := newService()
c := newController(s)
newRoutes(c, app)
}
+51
View File
@@ -0,0 +1,51 @@
package authmodule
import (
authdto "api/application/auth/dto"
"api/libs/logger"
"api/models/api"
"github.com/gofiber/fiber/v2"
)
func newRoutes(c Controller, app *fiber.App) {
app.Post("/authorization", authorization(c))
}
func authorization(controller Controller) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
auth := &authdto.AuthDto{}
err := c.BodyParser(auth)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
err = auth.Validate()
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
response, statusCode, err := controller.Authorization(auth)
if err != nil {
logger.Production.Info(err.Error())
c.Status(statusCode)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
return c.Status(statusCode).JSON(response)
}
}
+69
View File
@@ -0,0 +1,69 @@
package authmodule
import (
authdto "api/application/auth/dto"
"api/libs/jwt"
"api/libs/postgres"
"api/models/api"
"api/models/users"
"context"
"github.com/alexedwards/argon2id"
"github.com/gofiber/fiber/v2"
)
type AuthService interface {
Authorization(data *authdto.AuthDto) (*api.Response, int, error)
}
type authService struct {
userRepository *users.Queries
ctx context.Context
}
func newService() AuthService {
return &authService{
userRepository: users.New(postgres.Pool),
ctx: context.Background(),
}
}
func (a *authService) Authorization(data *authdto.AuthDto) (*api.Response, int, error) {
userL, err := a.userRepository.GetUser(a.ctx, data.Username)
if err != nil {
return &api.Response{Error: true, ErrorMessage: err.Error()}, fiber.StatusUnauthorized, err
}
match, err := argon2id.ComparePasswordAndHash(data.Password, userL.Password)
if err != nil {
return &api.Response{Error: true, ErrorMessage: err.Error()}, fiber.StatusUnauthorized, err
}
if match {
dic := map[string]interface{}{
"id": userL.User,
}
token, err := jwt.EncodeJwt(dic)
if err != nil {
return &api.Response{Error: true, ErrorMessage: err.Error()}, fiber.StatusInternalServerError, err
}
payload := struct {
User struct {
Id string `json:"id"`
Username string `json:"username"`
} `json:"user"`
Token string `json:"token"`
}{}
payload.User.Username = userL.Username
payload.User.Id = userL.User
payload.Token = token
return &api.Response{Error: false, Payload: payload}, fiber.StatusOK, err
}
return nil, fiber.StatusUnauthorized, nil
}
+45
View File
@@ -0,0 +1,45 @@
package productsmodule
import (
productdto "api/application/products/dto"
"api/models/api"
)
// Controller defines the methods to be exposed in Controller layer
type Controller interface {
CreateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error)
UpdateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error)
VerifyCode(data *productdto.ValidateCodeDto) (*api.Response, int, error)
GetProducts() (*api.Response, int, error)
DeleteProduct(data *productdto.DeleteProductDto) (*api.Response, int, error)
}
type controller struct {
ProductsService
}
func newController(service ProductsService) Controller {
return &controller{
ProductsService: service,
}
}
func (c *controller) CreateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error) {
return c.ProductsService.CreateProduct(userId, data)
}
func (c *controller) UpdateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error) {
return c.ProductsService.UpdateProduct(userId, data)
}
func (c *controller) VerifyCode(data *productdto.ValidateCodeDto) (*api.Response, int, error) {
return c.ProductsService.VerifyCode(data)
}
func (c *controller) GetProducts() (*api.Response, int, error) {
return c.ProductsService.GetProducts()
}
func (c *controller) DeleteProduct(data *productdto.DeleteProductDto) (*api.Response, int, error) {
return c.ProductsService.DeleteProduct(data)
}
@@ -0,0 +1,28 @@
package productdto
import (
"api/libs/logger"
"errors"
"github.com/go-playground/validator/v10"
)
type DeleteProductDto struct {
Codigo string `json:"codigo" validate:"required"`
}
func (d *DeleteProductDto) Validate() error {
validate := validator.New()
err := validate.Struct(d)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
logger.Development.Info(err.Error())
}
for _, e := range err.(validator.ValidationErrors) {
err = errors.New(e.Field() + " " + e.Tag())
}
}
return err
}
@@ -0,0 +1,38 @@
package productdto
import (
"api/libs/logger"
"errors"
"github.com/go-playground/validator/v10"
)
type ProductDto struct {
Nome string `json:"nome" validate:"required"`
Codigo string `json:"codigo" validate:"required"`
EstoqueTotal int64 `json:"estoqueTotal" validate:"required"`
EstoqueCorte int64 `json:"estoqueCorte" validate:"required"`
PrecoDe float32 `json:"precoDe" validate:"required"`
PrecoPor float32 `json:"precoPor" validate:"required"`
}
func (d *ProductDto) Validate() error {
validate := validator.New()
err := validate.Struct(d)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
logger.Development.Info(err.Error())
}
for _, e := range err.(validator.ValidationErrors) {
err = errors.New(e.Field() + " " + e.Tag())
}
}
if d.PrecoPor > d.PrecoDe {
err = errors.New(`o "preço de" não pode ser inferior ao "preço por"`)
}
return err
}
@@ -0,0 +1,28 @@
package productdto
import (
"api/libs/logger"
"errors"
"github.com/go-playground/validator/v10"
)
type ValidateCodeDto struct {
Codigo string `json:"codigo" validate:"required"`
}
func (d *ValidateCodeDto) Validate() error {
validate := validator.New()
err := validate.Struct(d)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
logger.Development.Info(err.Error())
}
for _, e := range err.(validator.ValidationErrors) {
err = errors.New(e.Field() + " " + e.Tag())
}
}
return err
}
+10
View File
@@ -0,0 +1,10 @@
package productsmodule
import "github.com/gofiber/fiber/v2"
// apply routes in app fiber, with controllers and services defined
func ProductstModuleDecorator(app *fiber.App) {
s := newService()
c := newController(s)
newRoutes(c, app)
}
+193
View File
@@ -0,0 +1,193 @@
package productsmodule
import (
productdto "api/application/products/dto"
"api/libs/jwt"
"api/libs/logger"
"api/models/api"
"github.com/gofiber/fiber/v2"
)
func newRoutes(c Controller, app *fiber.App) {
app.Post("/product", jwt.JwtProtected(), createProduct(c))
app.Put("/product", jwt.JwtProtected(), updateProduct(c))
app.Post("/product/validate", jwt.JwtProtected(), validateCode(c))
app.Get("/products", jwt.JwtProtected(), getProducts(c))
app.Delete("/product", jwt.JwtProtected(), deleteProduct(c))
}
func getProducts(controller Controller) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
response, statusCode, err := controller.GetProducts()
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusInternalServerError)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
return c.Status(statusCode).JSON(response)
}
}
func createProduct(controller Controller) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
userId := jwt.DecodeJwtSingleKey(c, "id").(string)
product := &productdto.ProductDto{}
err := c.BodyParser(product)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
err = product.Validate()
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
response, statusCode, err := controller.CreateProduct(userId, product)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusInternalServerError)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
return c.Status(statusCode).JSON(response)
}
}
func updateProduct(controller Controller) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
userId := jwt.DecodeJwtSingleKey(c, "id").(string)
product := &productdto.ProductDto{}
err := c.BodyParser(product)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
err = product.Validate()
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
response, statusCode, err := controller.UpdateProduct(userId, product)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusInternalServerError)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
return c.Status(statusCode).JSON(response)
}
}
func validateCode(controller Controller) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
codeValidate := &productdto.ValidateCodeDto{}
err := c.BodyParser(codeValidate)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
err = codeValidate.Validate()
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
response, statusCode, err := controller.VerifyCode(codeValidate)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusInternalServerError)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
return c.Status(statusCode).JSON(response)
}
}
func deleteProduct(controller Controller) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
delete := &productdto.DeleteProductDto{}
err := c.BodyParser(delete)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
err = delete.Validate()
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusBadRequest)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
response, statusCode, err := controller.DeleteProduct(delete)
if err != nil {
logger.Production.Info(err.Error())
c.Status(fiber.StatusInternalServerError)
return c.JSON(api.Response{
Error: true,
ErrorMessage: err.Error(),
})
}
return c.Status(statusCode).JSON(response)
}
}
+112
View File
@@ -0,0 +1,112 @@
package productsmodule
import (
productdto "api/application/products/dto"
"api/libs/logger"
"api/libs/postgres"
"api/models/api"
"api/models/products"
"context"
"github.com/gofiber/fiber/v2"
"github.com/jackc/pgx/v5"
)
type ProductsService interface {
CreateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error)
UpdateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error)
VerifyCode(data *productdto.ValidateCodeDto) (*api.Response, int, error)
GetProducts() (*api.Response, int, error)
DeleteProduct(data *productdto.DeleteProductDto) (*api.Response, int, error)
}
type productsService struct {
productsRepository *products.Queries
ctx context.Context
}
func newService() ProductsService {
return &productsService{
productsRepository: products.New(postgres.Pool),
ctx: context.Background(),
}
}
func (p *productsService) CreateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error) {
estoqueDisponivel := data.EstoqueTotal - data.EstoqueCorte
newProduct, err := p.productsRepository.CreateProduct(p.ctx, userId, products.CreateProductParams{
Nome: data.Nome,
Codigo: data.Codigo,
EstoqueTotal: data.EstoqueTotal,
EstoqueCorte: data.EstoqueCorte,
EstoqueDisponivel: estoqueDisponivel,
PrecoDe: data.PrecoDe,
PrecoPor: data.PrecoPor,
})
if err != nil {
logger.Production.Info(err.Error())
return &api.Response{Error: true, ErrorMessage: err.Error(), Payload: "error insert product"}, fiber.StatusInternalServerError, err
}
return &api.Response{Error: false, Payload: newProduct}, fiber.StatusOK, nil
}
func (p *productsService) VerifyCode(data *productdto.ValidateCodeDto) (*api.Response, int, error) {
_, err := p.productsRepository.GetProduct(p.ctx, data.Codigo)
if err != nil {
if err == pgx.ErrNoRows {
return &api.Response{Error: false, Payload: false}, fiber.StatusOK, nil
}
logger.Production.Info(err.Error())
return &api.Response{Error: true, ErrorMessage: err.Error(), Payload: "error verify code product"}, fiber.StatusInternalServerError, err
}
return &api.Response{Error: false, Payload: true}, fiber.StatusOK, nil
}
func (p *productsService) UpdateProduct(userId string, data *productdto.ProductDto) (*api.Response, int, error) {
estoqueDisponivel := data.EstoqueTotal - data.EstoqueCorte
err := p.productsRepository.UpdateProduct(p.ctx, userId, products.UpdateProductParams{
Nome: data.Nome,
Codigo: data.Codigo,
EstoqueTotal: data.EstoqueTotal,
EstoqueCorte: data.EstoqueCorte,
EstoqueDisponivel: estoqueDisponivel,
PrecoDe: data.PrecoDe,
PrecoPor: data.PrecoPor,
})
if err != nil {
logger.Production.Info(err.Error())
return &api.Response{Error: true, ErrorMessage: err.Error(), Payload: "error update product"}, fiber.StatusInternalServerError, err
}
return &api.Response{Error: false, Payload: nil}, fiber.StatusOK, nil
}
func (p *productsService) GetProducts() (*api.Response, int, error) {
products, err := p.productsRepository.ListProducts(p.ctx)
if err != nil {
logger.Production.Info(err.Error())
return &api.Response{Error: true, ErrorMessage: err.Error(), Payload: "error get products"}, fiber.StatusInternalServerError, err
}
return &api.Response{Error: false, Payload: products}, fiber.StatusOK, nil
}
func (p *productsService) DeleteProduct(data *productdto.DeleteProductDto) (*api.Response, int, error) {
err := p.productsRepository.DeleteProduct(p.ctx, data.Codigo)
if err != nil {
logger.Production.Info(err.Error())
return &api.Response{Error: true, ErrorMessage: err.Error(), Payload: "error delete product"}, fiber.StatusInternalServerError, err
}
return &api.Response{Error: false, Payload: nil}, fiber.StatusOK, nil
}
+55
View File
@@ -0,0 +1,55 @@
module api
go 1.21.0
require (
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
github.com/go-playground/validator/v10 v10.15.3
github.com/gofiber/fiber/v2 v2.49.1
github.com/jackc/pgx/v5 v5.6.0
go.mongodb.org/mongo-driver v1.12.1
go.uber.org/zap v1.25.0
)
require (
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx v3.6.2+incompatible // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
require (
github.com/gofiber/jwt/v3 v3.3.10
github.com/golang-jwt/jwt/v4 v4.5.0
)
require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/joho/godotenv v1.5.1
github.com/klauspost/compress v1.16.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.49.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.15.0 // indirect
)
+175
View File
@@ -0,0 +1,175 @@
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736 h1:qZaEtLxnqY5mJ0fVKbk31NVhlgi0yrKm51Pq/I5wcz4=
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736/go.mod h1:mTeFRcTdnpzOlRjMoFYC/80HwVUreupyAiqPkCZQOXc=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.15.3 h1:S+sSpunYjNPDuXkWbK+x+bA7iXiW296KG4dL3X7xUZo=
github.com/go-playground/validator/v10 v10.15.3/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/gofiber/fiber/v2 v2.45.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc=
github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk=
github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU=
github.com/gofiber/jwt/v3 v3.3.10 h1:0bpWtFKaGepjwYTU4efHfy0o+matSqZwTxGMo5a+uuc=
github.com/gofiber/jwt/v3 v3.3.10/go.mod h1:GJorFVaDyfMPSK9RB8RG4NQ3s1oXKTmYaoL/ny08O1A=
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/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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 v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
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/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
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/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.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE=
github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE=
go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
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.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+62
View File
@@ -0,0 +1,62 @@
package database
import (
"api/libs/logger"
"api/libs/postgres"
"api/models/users"
"context"
"os"
"time"
"github.com/alexedwards/argon2id"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
func Init() {
ensureTableUsers()
ensureTableProducts()
usersRepository := users.New(postgres.Pool)
var ctx = context.Background()
hash, err := argon2id.CreateHash("admin", argon2id.DefaultParams)
if err != nil {
logger.Production.Error("error generate password hash")
}
_, err = usersRepository.GetUser(ctx, "admin")
if err != nil {
if err.Error() == pgx.ErrNoRows.Error() {
usersRepository.CreateUser(ctx, users.CreateUserParams{
User: uuid.New().String(),
CreatedAt: uint64(time.Now().Unix()),
Username: "admin",
Password: hash,
})
logger.Production.Info("Create user admin into database")
} else {
logger.Production.Error(err.Error())
os.Exit(1)
}
}
}
func ensureTableUsers() {
if _, err := postgres.Pool.Exec(context.Background(), CreateUsersTableIfNotExists); err != nil {
logger.Production.Error(err.Error())
os.Exit(1)
}
logger.Production.Info("users exists")
}
func ensureTableProducts() {
if _, err := postgres.Pool.Exec(context.Background(), CreateProductsTableIfNotExists); err != nil {
logger.Production.Error(err.Error())
os.Exit(1)
}
logger.Production.Info("products exists")
}
+29
View File
@@ -0,0 +1,29 @@
package database
var CreateUsersTableIfNotExists = `
CREATE TABLE IF NOT EXISTS users (
"user" UUID NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT,
username text NOT NULL,
"password" text NOT NULL,
PRIMARY KEY ("user")
)`
var CreateProductsTableIfNotExists = `
CREATE TABLE IF NOT EXISTS products (
created_by UUID NOT NULL,
created_at BIGINT NOT NULL,
updated_by UUID,
updated_at BIGINT,
nome text NOT NULL,
codigo text NOT NULL,
estoque_total BIGINT NOT NULL,
estoque_corte BIGINT NOT NULL,
estoque_disponivel BIGINT NOT NULL,
preco_de NUMERIC NOT NULL,
preco_por NUMERIC NOT NULL,
PRIMARY KEY (codigo)
)`
+22
View File
@@ -0,0 +1,22 @@
package variable
import (
"log"
"os"
"github.com/joho/godotenv"
)
// use godot package to load/read the .env file and
// return the value of the key
func GetEnvVariable(key string) string {
// load .env file
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
}
return os.Getenv(key)
}
+74
View File
@@ -0,0 +1,74 @@
package jwt
import (
"api/helpers/variable"
"time"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v4"
jwtMiddleware "github.com/gofiber/jwt/v3"
)
func jwtError(c *fiber.Ctx, err error) error {
// Return status 401 and failed authentication error.
if err.Error() == "Missing or malformed JWT" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"err": true,
"msg": err.Error(),
})
}
// Return status 401 and failed authentication error.
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"err": true,
"msg": err.Error(),
})
}
func JwtProtected() func(*fiber.Ctx) error {
config := jwtMiddleware.Config{
SigningKey: []byte(variable.GetEnvVariable("JWT_KEY")),
ContextKey: "authorization",
ErrorHandler: jwtError,
}
return jwtMiddleware.New(config)
}
func GetClaims(c *fiber.Ctx) jwt.MapClaims {
// Parses the JWT used to secure authorized access to private routes
token := c.Locals("authorization").(*jwt.Token)
claims := token.Claims.(jwt.MapClaims)
// Forwards the claims further to the function that is using them
return claims
}
func DecodeJwtSingleKey(c *fiber.Ctx, k string) interface{} {
claims := GetClaims(c)
return claims[k]
}
func EncodeJwt(dictionary map[string]interface{}) (string, error) {
// Create token
token := jwt.New(jwt.SigningMethodHS256)
// Set claims
claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(time.Hour * 12).Unix()
// Basic claims are merged with the dictionary provided
for key, value := range dictionary {
claims[key] = value
}
// Generate encoded token and send it as response
encodedToken, err := token.SignedString([]byte(variable.GetEnvVariable("JWT_KEY")))
return encodedToken, err
}
+24
View File
@@ -0,0 +1,24 @@
package logger
import "go.uber.org/zap"
var (
Development *zap.Logger
Production *zap.Logger
)
func InitializeLogger() {
var err interface{}
Development, err = zap.NewDevelopment()
if err != nil {
panic(0)
}
Production, err = zap.NewProduction()
if err != nil {
panic(0)
}
}
+25
View File
@@ -0,0 +1,25 @@
package postgres
import (
"api/helpers/variable"
"api/libs/logger"
"context"
"os"
"github.com/jackc/pgx/v5/pgxpool"
)
var Pool *pgxpool.Pool
func InitializeDatabaseConnection() {
poolConfig, err := pgxpool.ParseConfig(variable.GetEnvVariable("DATABASE_URL"))
Pool, err = pgxpool.NewWithConfig(context.Background(), poolConfig)
if err != nil {
logger.Development.Info(err.Error())
os.Exit(1)
}
logger.Development.Info("Connected to Postgres database")
}
+41
View File
@@ -0,0 +1,41 @@
package main
import (
authmodule "api/application/auth"
productsmodule "api/application/products"
"api/helpers/database"
"api/helpers/variable"
"api/libs/logger"
"api/libs/postgres"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/helmet"
loggerFiber "github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
)
func main() {
logger.InitializeLogger()
postgres.InitializeDatabaseConnection()
database.Init()
app := fiber.New()
app.Use(recover.New())
app.Use(helmet.New())
app.Use(cors.New(cors.ConfigDefault))
app.Use(loggerFiber.New())
authmodule.AuthModuleDecorator(app)
productsmodule.ProductstModuleDecorator(app)
app.Listen(":" + variable.GetEnvVariable("PORT"))
}
+7
View File
@@ -0,0 +1,7 @@
package api
type Response struct {
Error bool `json:"error"`
ErrorMessage string `json:"errorMessage"`
Payload interface{} `json:"payload"`
}
+32
View File
@@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package products
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}
+15
View File
@@ -0,0 +1,15 @@
package products
type Product struct {
CreatedBy string `json:"createdBy"`
CreatedAt uint64 `json:"createdAt"`
UpdatedBy *string `json:"updatedBy"`
UpdatedAt *uint64 `json:"updatedAt"`
Nome string `json:"nome"`
Codigo string `json:"codigo"`
EstoqueTotal int64 `json:"estoqueTotal"`
EstoqueCorte int64 `json:"estoqueCorte"`
EstoqueDisponivel int64 `json:"estoqueDisponivel"`
PrecoDe float32 `json:"precoDe"`
PrecoPor float32 `json:"precoPor"`
}
+174
View File
@@ -0,0 +1,174 @@
package products
import (
"context"
"time"
)
const createProduct = `-- name: CreateProduct :one
INSERT INTO products (
created_at, created_by, updated_at, updated_by, nome, codigo, estoque_total, estoque_corte, estoque_disponivel, preco_de, preco_por
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11
)
RETURNING created_by, created_at, updated_by, updated_at, nome, codigo, estoque_total, estoque_corte, estoque_disponivel, preco_de, preco_por
`
type CreateProductParams struct {
CreatedAt uint64
CreatedBy string
UpdatedAt uint64
UpdatedBy string
Nome string
Codigo string
EstoqueTotal int64
EstoqueCorte int64
EstoqueDisponivel int64
PrecoDe float32
PrecoPor float32
}
func (q *Queries) CreateProduct(ctx context.Context, userId string, arg CreateProductParams) (Product, error) {
t := time.Now().Unix()
row := q.db.QueryRow(ctx, createProduct,
t,
userId,
nil,
nil,
arg.Nome,
arg.Codigo,
arg.EstoqueTotal,
arg.EstoqueCorte,
arg.EstoqueDisponivel,
arg.PrecoDe,
arg.PrecoPor,
)
var i Product
err := row.Scan(
&i.CreatedBy,
&i.CreatedAt,
&i.UpdatedBy,
&i.UpdatedAt,
&i.Nome,
&i.Codigo,
&i.EstoqueTotal,
&i.EstoqueCorte,
&i.EstoqueDisponivel,
&i.PrecoDe,
&i.PrecoPor,
)
return i, err
}
const getProduct = `-- name: GetProduct :one
SELECT created_by, created_at, updated_by, updated_at, nome, codigo, estoque_total, estoque_corte, estoque_disponivel, preco_de, preco_por FROM products
WHERE codigo = $1 LIMIT 1
`
func (q *Queries) GetProduct(ctx context.Context, codigo string) (Product, error) {
row := q.db.QueryRow(ctx, getProduct, codigo)
var i Product
err := row.Scan(
&i.CreatedBy,
&i.CreatedAt,
&i.UpdatedBy,
&i.UpdatedAt,
&i.Nome,
&i.Codigo,
&i.EstoqueTotal,
&i.EstoqueCorte,
&i.EstoqueDisponivel,
&i.PrecoDe,
&i.PrecoPor,
)
return i, err
}
const listProducts = `-- name: ListProducts :many
SELECT created_by, created_at, updated_by, updated_at, nome, codigo, estoque_total, estoque_corte, estoque_disponivel, preco_de, preco_por FROM products
ORDER BY created_at
`
func (q *Queries) ListProducts(ctx context.Context) ([]Product, error) {
rows, err := q.db.Query(ctx, listProducts)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Product
for rows.Next() {
var i Product
if err := rows.Scan(
&i.CreatedBy,
&i.CreatedAt,
&i.UpdatedBy,
&i.UpdatedAt,
&i.Nome,
&i.Codigo,
&i.EstoqueTotal,
&i.EstoqueCorte,
&i.EstoqueDisponivel,
&i.PrecoDe,
&i.PrecoPor,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateProduct = `-- name: UpdateProduct :exec
UPDATE products
SET
updated_at = $2,
updated_by = $3,
nome = $4,
estoque_total = $5,
estoque_corte = $6,
estoque_disponivel = $7,
preco_de = $8,
preco_por = $9
WHERE codigo = $1
`
type UpdateProductParams struct {
UpdatedAt uint64
UpdatedBy string
Nome string
Codigo string
EstoqueTotal int64
EstoqueCorte int64
EstoqueDisponivel int64
PrecoDe float32
PrecoPor float32
}
func (q *Queries) UpdateProduct(ctx context.Context, userId string, arg UpdateProductParams) error {
t := time.Now().Unix()
_, err := q.db.Exec(ctx, updateProduct,
arg.Codigo,
t,
userId,
arg.Nome,
arg.EstoqueTotal,
arg.EstoqueCorte,
arg.EstoqueDisponivel,
arg.PrecoDe,
arg.PrecoPor,
)
return err
}
const deleteProduct = `-- name: DeleteProduct :exec
DELETE FROM products
WHERE codigo = $1
`
func (q *Queries) DeleteProduct(ctx context.Context, codigo string) error {
_, err := q.db.Exec(ctx, deleteProduct, codigo)
return err
}
+32
View File
@@ -0,0 +1,32 @@
-- name: GetProduct :one
SELECT * FROM products
WHERE codigo = $1 LIMIT 1;
-- name: ListProducts :many
SELECT * FROM products
ORDER BY created_at;
-- name: CreateProduct :one
INSERT INTO products (
created_at, created_by, updated_at, updated_by, nome, codigo, estoque_total, estoque_corte, estoque_disponivel, preco_de, preco_por
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11
)
RETURNING *;
-- name: UpdateProduct :exec
UPDATE products
SET
updated_at = $2,
updated_by = $3,
nome = $4,
estoque_total = $5,
estoque_corte = $6,
estoque_disponivel = $7,
preco_de = $8,
preco_por = $9
WHERE codigo = $1;
-- name: DeleteProduct :exec
DELETE FROM products
WHERE codigo = $1;
+15
View File
@@ -0,0 +1,15 @@
CREATE TABLE products (
product UUID NOT NULL,
created_by UUID NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_by UUID,
updated_at TIMESTAMP,
nome text NOT NULL,
codigo text NOT NULL,
estoque_total BIGINT NOT NULL,
estoque_corte BIGINT NOT NULL,
estoque_disponivel BIGINT NOT NULL,
preco_de NUMERIC NOT NULL,
preco_por NUMERIC NOT NULL
)
+11
View File
@@ -0,0 +1,11 @@
version: "2
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
gen:
go:
package: "products"
out: "./"
sql_package: "pgx/v5"
+20
View File
@@ -0,0 +1,20 @@
-- name: GetUser :one
SELECT * FROM users
WHERE username = $1 LIMIT 1;
-- name: CreateUser :one
INSERT INTO users (
"user", created_at, updated_at, username, "password"
) VALUES (
$1, $2, $3, $4, $5
)
RETURNING *;
-- name: UpdateUser :exec
UPDATE users
SET
updated_at = $2,
username = $3,
"password" = $4
WHERE "user" = $1;
+7
View File
@@ -0,0 +1,7 @@
CREATE TABLE users (
"user" UUID NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP,
username text NOT NULL,
"password" text NOT NULL
)
+10
View File
@@ -0,0 +1,10 @@
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
gen:
go:
package: "users"
out: "./"
sql_package: "pgx/v5"
+32
View File
@@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package users
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}
+9
View File
@@ -0,0 +1,9 @@
package users
type User struct {
User string
CreatedAt uint64
UpdatedAt *uint64
Username string
Password string
}
+86
View File
@@ -0,0 +1,86 @@
package users
import (
"context"
)
const createUser = `-- name: CreateUser :one
INSERT INTO users (
"user", created_at, updated_at, username, "password"
) VALUES (
$1, $2, $3, $4, $5
)
RETURNING "user", created_at, updated_at, username, password
`
type CreateUserParams struct {
User string
CreatedAt uint64
UpdatedAt *uint64
Username string
Password string
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
row := q.db.QueryRow(ctx, createUser,
arg.User,
arg.CreatedAt,
arg.UpdatedAt,
arg.Username,
arg.Password,
)
var i User
err := row.Scan(
&i.User,
&i.CreatedAt,
i.UpdatedAt,
&i.Username,
&i.Password,
)
return i, err
}
const getUser = `-- name: GetUser :one
SELECT "user", created_at, updated_at, username, password FROM users
WHERE username = $1 LIMIT 1
`
func (q *Queries) GetUser(ctx context.Context, username string) (User, error) {
row := q.db.QueryRow(ctx, getUser, username)
var i User
err := row.Scan(
&i.User,
&i.CreatedAt,
&i.UpdatedAt,
&i.Username,
&i.Password,
)
return i, err
}
const updateUser = `-- name: UpdateUser :exec
UPDATE users
SET
updated_at = $2,
username = $3,
"password" = $4
WHERE "user" = $1
`
type UpdateUserParams struct {
User string
UpdatedAt uint64
Username string
Password string
}
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
_, err := q.db.Exec(ctx, updateUser,
arg.User,
arg.UpdatedAt,
arg.Username,
arg.Password,
)
return err
}