diff --git a/Dockerfile b/Dockerfile index 6b3663d..d3c697b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,10 @@ RUN go mod download COPY . . # Build the Go app -RUN go build -o ./out/app ./cmd/app/main.go +RUN go build -o ./out/app ./main.go +RUN go get -d github.com/swaggo/swag/cmd/swag +RUN go install github.com/swaggo/swag/cmd/swag@latest +RUN make docs # Start fresh from a smaller image FROM alpine:3.9 diff --git a/Makefile b/Makefile index 657b800..86e6185 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,14 @@ run: - ENV_FILE=.env go run cmd/app/main.go + ENV_FILE=.env go run main.go build: - go build -o bin/vanir cmd/app/main.go + go build -o bin/vanir main.go dependencies: go mod download tests: - ENV_FILE=$(shell pwd)/.env.test go test -v ./... -race -coverpkg=./... -coverprofile=coverage.txt -covermode=atomic \ No newline at end of file + ENV_FILE=$(shell pwd)/.env.test go test -v ./... -race -coverpkg=./... -coverprofile=coverage.txt -covermode=atomic + +docs: + swag init --parseInternal --parseDependency --output internal/app/docs \ No newline at end of file diff --git a/go.mod b/go.mod index 5bf3767..032c4c2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module vanir -go 1.21 +go 1.22.0 toolchain go1.22.1 @@ -11,23 +11,32 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 github.com/imroc/req/v3 v3.43.1 github.com/joho/godotenv v1.5.1 - github.com/labstack/echo/v4 v4.11.4 + github.com/labstack/echo/v4 v4.13.0 github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.21.0 + golang.org/x/crypto v0.30.0 gorm.io/driver/postgres v1.5.7 gorm.io/driver/sqlite v1.5.5 gorm.io/gorm v1.25.8 ) require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.2.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/ghodss/yaml v1.0.0 // indirect github.com/go-logr/logr v1.4.1 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect @@ -43,10 +52,12 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect @@ -60,23 +71,31 @@ require ( github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/quic-go/quic-go v0.42.0 // indirect github.com/refraction-networking/utls v1.6.3 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/swaggo/echo-swagger v1.4.1 // indirect + github.com/swaggo/files/v2 v2.0.1 // indirect + github.com/swaggo/swag v1.16.4 // indirect + github.com/urfave/cli/v2 v2.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect go.uber.org/mock v0.4.0 // indirect golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.19.0 // indirect + golang.org/x/tools v0.27.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 1ebaf20..d577cd2 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,14 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= +github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -54,6 +62,8 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= @@ -72,11 +82,31 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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= @@ -194,6 +224,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -212,6 +244,8 @@ github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/echo/v4 v4.13.0 h1:8DjSi4H/k+RqoOmwXkxW14A2H1pdPdS95+qmdJ4q1Tg= +github.com/labstack/echo/v4 v4.13.0/go.mod h1:61j7WN2+bp8V21qerqRs4yVlVTGyOagMBpF0vE7VcmM= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= @@ -222,6 +256,11 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -238,6 +277,7 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= github.com/onsi/ginkgo/v2 v2.17.0 h1:kdnunFXpBjbzN56hcJHrXZ8M+LOkenKA7NnBzTNigTI= @@ -271,6 +311,10 @@ github.com/refraction-networking/utls v1.6.3 h1:MFOfRN35sSx6K5AZNIoESsBuBxS2LCgR github.com/refraction-networking/utls v1.6.3/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -309,6 +353,14 @@ github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk= +github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc= +github.com/swaggo/files/v2 v2.0.1 h1:XCVJO/i/VosCDsJu1YLpdejGsGnBE9deRMpjN4pJLHk= +github.com/swaggo/files/v2 v2.0.1/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= +github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 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/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -342,6 +394,8 @@ 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.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -385,6 +439,8 @@ golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -417,6 +473,7 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= @@ -425,6 +482,10 @@ 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.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -449,6 +510,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -482,6 +545,7 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -499,6 +563,8 @@ golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -508,6 +574,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/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.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -515,6 +582,8 @@ 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/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -575,6 +644,8 @@ golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= +golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= 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= @@ -669,12 +740,17 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= @@ -703,3 +779,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/app/app.go b/internal/app/app.go index b860a04..78ff24b 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -7,15 +7,30 @@ import ( "os" "os/signal" "time" + _ "vanir/internal/app/docs" "vanir/internal/app/router" "vanir/internal/pkg/config" "vanir/internal/pkg/data/db" "vanir/internal/pkg/helpers" + echoSwagger "github.com/swaggo/echo-swagger" // echo-swagger middleware + "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) +// @title Vanir +// @version 1.2.0 +// @description This is an API used to track crypto currencies prices and manage your favorites + +// @contact.name Bruno Lombardi +// @contact.url https://github.com/bruno-lombardi + +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html + +// @host localhost:3333 +// @BasePath /api/v1 func Run() { config.Setup() db.SetupDB() @@ -37,6 +52,7 @@ func Run() { } apiV1 := e.Group("/v1") router.SetupRootRouter(apiV1) + e.GET("/swagger/*", echoSwagger.WrapHandler) go func() { if err := e.Start(":" + conf.Server.Port); err != nil && err != http.ErrServerClosed { @@ -47,6 +63,8 @@ func Run() { quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt) <-quit + e.Logger.Infof("gracefully shutting down") + close(quit) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := e.Shutdown(ctx); err != nil { diff --git a/internal/app/docs/docs.go b/internal/app/docs/docs.go new file mode 100644 index 0000000..0e63074 --- /dev/null +++ b/internal/app/docs/docs.go @@ -0,0 +1,163 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/v1/users": { + "post": { + "description": "Creates a new user with the provided information.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Create new user", + "parameters": [ + { + "description": "create user params", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.CreateUserParams" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.User" + } + } + } + } + }, + "/v1/users/{id}": { + "get": { + "description": "Gets an existent user by its ID", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get a user by its ID", + "parameters": [ + { + "type": "string", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.User" + } + } + } + } + } + }, + "definitions": { + "models.CreateUserParams": { + "description": "Create user params information with email, name and password with confirmation", + "type": "object", + "required": [ + "email", + "name", + "password", + "password_confirmation" + ], + "properties": { + "email": { + "type": "string", + "maxLength": 255, + "example": "bruno.lombardi@email.com" + }, + "name": { + "type": "string", + "maxLength": 100, + "minLength": 2, + "example": "Bruno Lombardi" + }, + "password": { + "type": "string", + "maxLength": 64, + "minLength": 6, + "example": "123456" + }, + "password_confirmation": { + "type": "string", + "maxLength": 64, + "minLength": 6, + "example": "123456" + } + } + }, + "models.User": { + "description": "User account information with user id and email", + "type": "object", + "properties": { + "created_at": { + "type": "integer", + "example": 1733583441703 + }, + "email": { + "type": "string", + "example": "bruno.lombardi@email.com" + }, + "id": { + "type": "string", + "example": "u_AksOKxc12a" + }, + "name": { + "type": "string", + "example": "Bruno Lombardi" + }, + "updated_at": { + "type": "integer", + "example": 1733583441710 + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/internal/app/docs/swagger.json b/internal/app/docs/swagger.json new file mode 100644 index 0000000..75d1a87 --- /dev/null +++ b/internal/app/docs/swagger.json @@ -0,0 +1,134 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": { + "/v1/users": { + "post": { + "description": "Creates a new user with the provided information.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Create new user", + "parameters": [ + { + "description": "create user params", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.CreateUserParams" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.User" + } + } + } + } + }, + "/v1/users/{id}": { + "get": { + "description": "Gets an existent user by its ID", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get a user by its ID", + "parameters": [ + { + "type": "string", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.User" + } + } + } + } + } + }, + "definitions": { + "models.CreateUserParams": { + "description": "Create user params information with email, name and password with confirmation", + "type": "object", + "required": [ + "email", + "name", + "password", + "password_confirmation" + ], + "properties": { + "email": { + "type": "string", + "maxLength": 255, + "example": "bruno.lombardi@email.com" + }, + "name": { + "type": "string", + "maxLength": 100, + "minLength": 2, + "example": "Bruno Lombardi" + }, + "password": { + "type": "string", + "maxLength": 64, + "minLength": 6, + "example": "123456" + }, + "password_confirmation": { + "type": "string", + "maxLength": 64, + "minLength": 6, + "example": "123456" + } + } + }, + "models.User": { + "description": "User account information with user id and email", + "type": "object", + "properties": { + "created_at": { + "type": "integer", + "example": 1733583441703 + }, + "email": { + "type": "string", + "example": "bruno.lombardi@email.com" + }, + "id": { + "type": "string", + "example": "u_AksOKxc12a" + }, + "name": { + "type": "string", + "example": "Bruno Lombardi" + }, + "updated_at": { + "type": "integer", + "example": 1733583441710 + } + } + } + } +} \ No newline at end of file diff --git a/internal/app/docs/swagger.yaml b/internal/app/docs/swagger.yaml new file mode 100644 index 0000000..3a4614b --- /dev/null +++ b/internal/app/docs/swagger.yaml @@ -0,0 +1,94 @@ +definitions: + models.CreateUserParams: + description: Create user params information with email, name and password with + confirmation + properties: + email: + example: bruno.lombardi@email.com + maxLength: 255 + type: string + name: + example: Bruno Lombardi + maxLength: 100 + minLength: 2 + type: string + password: + example: "123456" + maxLength: 64 + minLength: 6 + type: string + password_confirmation: + example: "123456" + maxLength: 64 + minLength: 6 + type: string + required: + - email + - name + - password + - password_confirmation + type: object + models.User: + description: User account information with user id and email + properties: + created_at: + example: 1733583441703 + type: integer + email: + example: bruno.lombardi@email.com + type: string + id: + example: u_AksOKxc12a + type: string + name: + example: Bruno Lombardi + type: string + updated_at: + example: 1733583441710 + type: integer + type: object +info: + contact: {} +paths: + /v1/users: + post: + consumes: + - application/json + description: Creates a new user with the provided information. + parameters: + - description: create user params + in: body + name: request + required: true + schema: + $ref: '#/definitions/models.CreateUserParams' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.User' + summary: Create new user + tags: + - users + /v1/users/{id}: + get: + description: Gets an existent user by its ID + parameters: + - description: User ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.User' + summary: Get a user by its ID + tags: + - users +swagger: "2.0" diff --git a/internal/app/presentation/controllers/auth/auth_controller.go b/internal/app/presentation/controller/auth/auth_controller.go similarity index 100% rename from internal/app/presentation/controllers/auth/auth_controller.go rename to internal/app/presentation/controller/auth/auth_controller.go diff --git a/internal/app/presentation/controllers/cryptos/list_top_cryptos_controller.go b/internal/app/presentation/controller/cryptos/list_top_cryptos_controller.go similarity index 100% rename from internal/app/presentation/controllers/cryptos/list_top_cryptos_controller.go rename to internal/app/presentation/controller/cryptos/list_top_cryptos_controller.go diff --git a/internal/app/presentation/controllers/cryptos/list_user_favorite_cryptos_controller.go b/internal/app/presentation/controller/cryptos/list_user_favorite_cryptos_controller.go similarity index 100% rename from internal/app/presentation/controllers/cryptos/list_user_favorite_cryptos_controller.go rename to internal/app/presentation/controller/cryptos/list_user_favorite_cryptos_controller.go diff --git a/internal/app/presentation/controllers/favorite/add_favorite_controller.go b/internal/app/presentation/controller/favorite/add_favorite_controller.go similarity index 100% rename from internal/app/presentation/controllers/favorite/add_favorite_controller.go rename to internal/app/presentation/controller/favorite/add_favorite_controller.go diff --git a/internal/app/presentation/controllers/favorite/remove_favorite_controller.go b/internal/app/presentation/controller/favorite/remove_favorite_controller.go similarity index 100% rename from internal/app/presentation/controllers/favorite/remove_favorite_controller.go rename to internal/app/presentation/controller/favorite/remove_favorite_controller.go diff --git a/internal/app/presentation/controllers/users/create_user_controller.go b/internal/app/presentation/controller/users/create_user_controller.go similarity index 70% rename from internal/app/presentation/controllers/users/create_user_controller.go rename to internal/app/presentation/controller/users/create_user_controller.go index a7aaed8..98d30ae 100644 --- a/internal/app/presentation/controllers/users/create_user_controller.go +++ b/internal/app/presentation/controller/users/create_user_controller.go @@ -1,4 +1,4 @@ -package controllers +package controller import ( "net/http" @@ -17,6 +17,15 @@ func NewCreateUserController(userService services.UserService) *CreateUserContro } } +// CreateUserController godoc +// @Summary Create new user +// @Description Creates a new user with the provided information. +// @Tags users +// @Accept application/json +// @Produce json +// @Param request body models.CreateUserParams true "create user params" +// @Success 200 {object} models.User +// @Router /v1/users [POST] func (c *CreateUserController) Handle(req *protocols.HttpRequest) (*protocols.HttpResponse, error) { createUserParams := req.Body.(*models.CreateUserParams) diff --git a/test/app/presentation/controllers/users/create_user_controller_test.go b/internal/app/presentation/controller/users/create_user_controller_test.go similarity index 79% rename from test/app/presentation/controllers/users/create_user_controller_test.go rename to internal/app/presentation/controller/users/create_user_controller_test.go index 8cb04b1..04c9b44 100644 --- a/test/app/presentation/controllers/users/create_user_controller_test.go +++ b/internal/app/presentation/controller/users/create_user_controller_test.go @@ -1,20 +1,26 @@ -package user_controllers_test +package controller import ( "fmt" "net/http" "testing" - controllers "vanir/internal/app/presentation/controllers/users" + "vanir/internal/pkg/config" + "vanir/internal/pkg/data/db" "vanir/internal/pkg/data/models" "vanir/internal/pkg/helpers" "vanir/internal/pkg/protocols" - _ "vanir/test" + mocks "vanir/test/mocks" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" ) func TestRunCreateUserControllerTestCases(t *testing.T) { + config.Setup() + db.SetupDB() + + userServiceMock := &mocks.UserServiceMock{} + controllerTestCases := []ControllerTestCase{ { Name: "Should create user with valid data", @@ -33,10 +39,10 @@ func TestRunCreateUserControllerTestCases(t *testing.T) { }, ExpectResponse: func(t *testing.T, response *protocols.HttpResponse) error { user, ok := response.Body.(*models.User) - assert.True(t, ok) - assert.NotNil(t, user.ID) - assert.Equal(t, http.StatusCreated, response.StatusCode) - assert.Equal(t, "bruno@email.com", user.Email) + require.True(t, ok) + require.NotNil(t, user.ID) + require.Equal(t, http.StatusCreated, response.StatusCode) + require.Equal(t, "bruno@email.com", user.Email) return nil }, AfterTest: func() error { @@ -66,7 +72,7 @@ func TestRunCreateUserControllerTestCases(t *testing.T) { return nil }, ExpectResponse: func(t *testing.T, response *protocols.HttpResponse) error { - assert.Equal(t, http.StatusInternalServerError, response.StatusCode) + require.Equal(t, http.StatusInternalServerError, response.StatusCode) return nil }, AfterTest: func() error { @@ -85,18 +91,18 @@ func TestRunCreateUserControllerTestCases(t *testing.T) { for _, testCase := range controllerTestCases { t.Run(testCase.Name, func(t *testing.T) { - assert.NoError(t, testCase.BeforeTest()) + require.NoError(t, testCase.BeforeTest()) - createUserController := controllers.NewCreateUserController( + createUserController := NewCreateUserController( userServiceMock, ) request, ok := testCase.WhenRequest.(*protocols.HttpRequest) - assert.True(t, ok) + require.True(t, ok) response, _ := createUserController.Handle(request) - assert.NoError(t, testCase.ExpectResponse(t, response)) - assert.NoError(t, testCase.AfterTest()) + require.NoError(t, testCase.ExpectResponse(t, response)) + require.NoError(t, testCase.AfterTest()) }) } } diff --git a/internal/app/presentation/controllers/users/get_user_controller.go b/internal/app/presentation/controller/users/get_user_controller.go similarity index 72% rename from internal/app/presentation/controllers/users/get_user_controller.go rename to internal/app/presentation/controller/users/get_user_controller.go index 02dd646..9b118a9 100644 --- a/internal/app/presentation/controllers/users/get_user_controller.go +++ b/internal/app/presentation/controller/users/get_user_controller.go @@ -1,4 +1,4 @@ -package controllers +package controller import ( "net/http" @@ -16,6 +16,14 @@ func NewGetUserController(userService services.UserService) *GetUserController { } } +// GetUserController godoc +// @Summary Get a user by its ID +// @Description Gets an existent user by its ID +// @Tags users +// @Produce json +// @Param id path string true "User ID" +// @Success 200 {object} models.User +// @Router /v1/users/{id} [GET] func (c *GetUserController) Handle(req *protocols.HttpRequest) (*protocols.HttpResponse, error) { id := req.PathParams["id"] diff --git a/test/app/presentation/controllers/users/get_user_controller_test.go b/internal/app/presentation/controller/users/get_user_controller_test.go similarity index 69% rename from test/app/presentation/controllers/users/get_user_controller_test.go rename to internal/app/presentation/controller/users/get_user_controller_test.go index c6ca113..6135e1a 100644 --- a/test/app/presentation/controllers/users/get_user_controller_test.go +++ b/internal/app/presentation/controller/users/get_user_controller_test.go @@ -1,19 +1,29 @@ -package user_controllers_test +package controller import ( "fmt" "net/http" "testing" - controllers "vanir/internal/app/presentation/controllers/users" + "vanir/internal/pkg/config" + "vanir/internal/pkg/data/db" "vanir/internal/pkg/data/models" "vanir/internal/pkg/helpers" "vanir/internal/pkg/protocols" + data_test "vanir/test/data" + mocks "vanir/test/mocks" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" ) -func TestRunGetUserControllerTestCases(t *testing.T) { +type ControllerTestCase data_test.ControllerTestCase + +func TestGetUserControllerTestCases(t *testing.T) { + config.Setup() + db.SetupDB() + + userServiceMock := &mocks.UserServiceMock{} + controllerTestCases := []ControllerTestCase{ { Name: "Should return user when service returns the user with valid id", @@ -29,10 +39,10 @@ func TestRunGetUserControllerTestCases(t *testing.T) { }, ExpectResponse: func(t *testing.T, response *protocols.HttpResponse) error { user, ok := response.Body.(*models.User) - assert.True(t, ok) - assert.NotNil(t, user.ID) - assert.Equal(t, http.StatusOK, response.StatusCode) - assert.Equal(t, "bruno@email.com", user.Email) + require.True(t, ok) + require.NotNil(t, user.ID) + require.Equal(t, http.StatusOK, response.StatusCode) + require.Equal(t, "bruno@email.com", user.Email) return nil }, AfterTest: func() error { @@ -54,7 +64,7 @@ func TestRunGetUserControllerTestCases(t *testing.T) { return nil }, ExpectResponse: func(t *testing.T, response *protocols.HttpResponse) error { - assert.Equal(t, http.StatusInternalServerError, response.StatusCode) + require.Equal(t, http.StatusInternalServerError, response.StatusCode) return nil }, AfterTest: func() error { @@ -68,18 +78,18 @@ func TestRunGetUserControllerTestCases(t *testing.T) { for _, testCase := range controllerTestCases { t.Run(testCase.Name, func(t *testing.T) { - assert.NoError(t, testCase.BeforeTest()) + require.NoError(t, testCase.BeforeTest()) - updateUserController := controllers.NewGetUserController( + updateUserController := NewGetUserController( userServiceMock, ) request, ok := testCase.WhenRequest.(*protocols.HttpRequest) - assert.True(t, ok) + require.True(t, ok) response, _ := updateUserController.Handle(request) - assert.NoError(t, testCase.ExpectResponse(t, response)) - assert.NoError(t, testCase.AfterTest()) + require.NoError(t, testCase.ExpectResponse(t, response)) + require.NoError(t, testCase.AfterTest()) }) } } diff --git a/internal/app/presentation/controllers/users/update_user_controller.go b/internal/app/presentation/controller/users/update_user_controller.go similarity index 97% rename from internal/app/presentation/controllers/users/update_user_controller.go rename to internal/app/presentation/controller/users/update_user_controller.go index 364ed48..23bdc06 100644 --- a/internal/app/presentation/controllers/users/update_user_controller.go +++ b/internal/app/presentation/controller/users/update_user_controller.go @@ -1,4 +1,4 @@ -package controllers +package controller import ( "net/http" diff --git a/test/app/presentation/controllers/users/update_user_controller_test.go b/internal/app/presentation/controller/users/update_user_controller_test.go similarity index 77% rename from test/app/presentation/controllers/users/update_user_controller_test.go rename to internal/app/presentation/controller/users/update_user_controller_test.go index 26d2613..fcb2168 100644 --- a/test/app/presentation/controllers/users/update_user_controller_test.go +++ b/internal/app/presentation/controller/users/update_user_controller_test.go @@ -1,19 +1,26 @@ -package user_controllers_test +package controller import ( "fmt" "net/http" "testing" - controllers "vanir/internal/app/presentation/controllers/users" + "vanir/internal/pkg/config" + "vanir/internal/pkg/data/db" "vanir/internal/pkg/data/models" "vanir/internal/pkg/helpers" "vanir/internal/pkg/protocols" + mocks "vanir/test/mocks" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" ) func TestRunUpdateUserControllerTestCases(t *testing.T) { + config.Setup() + db.SetupDB() + + userServiceMock := &mocks.UserServiceMock{} + controllerTestCases := []ControllerTestCase{ { Name: "Should update user with valid data", @@ -33,10 +40,10 @@ func TestRunUpdateUserControllerTestCases(t *testing.T) { }, ExpectResponse: func(t *testing.T, response *protocols.HttpResponse) error { user, ok := response.Body.(*models.User) - assert.True(t, ok) - assert.NotNil(t, user.ID) - assert.Equal(t, http.StatusOK, response.StatusCode) - assert.Equal(t, "bruno@email.com", user.Email) + require.True(t, ok) + require.NotNil(t, user.ID) + require.Equal(t, http.StatusOK, response.StatusCode) + require.Equal(t, "bruno@email.com", user.Email) return nil }, AfterTest: func() error { @@ -62,7 +69,7 @@ func TestRunUpdateUserControllerTestCases(t *testing.T) { return nil }, ExpectResponse: func(t *testing.T, response *protocols.HttpResponse) error { - assert.Equal(t, http.StatusInternalServerError, response.StatusCode) + require.Equal(t, http.StatusInternalServerError, response.StatusCode) return nil }, AfterTest: func() error { @@ -76,18 +83,18 @@ func TestRunUpdateUserControllerTestCases(t *testing.T) { for _, testCase := range controllerTestCases { t.Run(testCase.Name, func(t *testing.T) { - assert.NoError(t, testCase.BeforeTest()) + require.NoError(t, testCase.BeforeTest()) - updateUserController := controllers.NewUpdateUserController( + updateUserController := NewUpdateUserController( userServiceMock, ) request, ok := testCase.WhenRequest.(*protocols.HttpRequest) - assert.True(t, ok) + require.True(t, ok) response, _ := updateUserController.Handle(request) - assert.NoError(t, testCase.ExpectResponse(t, response)) - assert.NoError(t, testCase.AfterTest()) + require.NoError(t, testCase.ExpectResponse(t, response)) + require.NoError(t, testCase.AfterTest()) }) } } diff --git a/test/app/presentation/middlewares/authenticated_middleware_test.go b/internal/app/presentation/middlewares/authenticated_middleware_test.go similarity index 92% rename from test/app/presentation/middlewares/authenticated_middleware_test.go rename to internal/app/presentation/middlewares/authenticated_middleware_test.go index 54de223..a94f8ab 100644 --- a/test/app/presentation/middlewares/authenticated_middleware_test.go +++ b/internal/app/presentation/middlewares/authenticated_middleware_test.go @@ -1,10 +1,9 @@ -package middlewares_test +package middlewares import ( "fmt" "net/http" "testing" - "vanir/internal/app/presentation/middlewares" "vanir/internal/pkg/data/models" "vanir/internal/pkg/protocols" "vanir/test/mocks" @@ -15,7 +14,7 @@ import ( type AuthMiddlewareSuite struct { suite.Suite - authMiddleware *middlewares.AuthenticatedMiddleware + authMiddleware *AuthenticatedMiddleware encrypter *mocks.EncrypterMock userService *mocks.UserServiceMock } @@ -24,7 +23,7 @@ func (sut *AuthMiddlewareSuite) BeforeTest(_, _ string) { sut.userService = &mocks.UserServiceMock{} sut.encrypter = &mocks.EncrypterMock{} - sut.authMiddleware = middlewares.NewAuthenticatedMiddleware(sut.encrypter, sut.userService) + sut.authMiddleware = NewAuthenticatedMiddleware(sut.encrypter, sut.userService) } func (sut *AuthMiddlewareSuite) AfterTest(_, _ string) { @@ -33,7 +32,7 @@ func (sut *AuthMiddlewareSuite) AfterTest(_, _ string) { } func (sut *AuthMiddlewareSuite) TestSmokeTest() { - sut.NotNil(middlewares.GetAuthenticatedMiddleware(&mocks.EncrypterMock{}, &mocks.UserServiceMock{})) + sut.NotNil(GetAuthenticatedMiddleware(&mocks.EncrypterMock{}, &mocks.UserServiceMock{})) } func (sut *AuthMiddlewareSuite) TestShouldNotReturnErrorIfAuthorizationTokenIsValid() { diff --git a/internal/app/router/auth.go b/internal/app/router/auth.go index 2285719..e4110ce 100644 --- a/internal/app/router/auth.go +++ b/internal/app/router/auth.go @@ -2,7 +2,7 @@ package router import ( "vanir/internal/app/presentation/adapters" - controllers "vanir/internal/app/presentation/controllers/auth" + controllers "vanir/internal/app/presentation/controller/auth" "vanir/internal/pkg/crypto" "vanir/internal/pkg/data/models" "vanir/internal/pkg/data/repositories" diff --git a/internal/app/router/cryptos.go b/internal/app/router/cryptos.go index 11240b3..c43a41d 100644 --- a/internal/app/router/cryptos.go +++ b/internal/app/router/cryptos.go @@ -2,7 +2,7 @@ package router import ( "vanir/internal/app/presentation/adapters" - controllers "vanir/internal/app/presentation/controllers/cryptos" + controllers "vanir/internal/app/presentation/controller/cryptos" "vanir/internal/app/presentation/middlewares" "vanir/internal/pkg/crypto" "vanir/internal/pkg/data/http/clients" diff --git a/internal/app/router/favorites.go b/internal/app/router/favorites.go index d8fee99..1664d95 100644 --- a/internal/app/router/favorites.go +++ b/internal/app/router/favorites.go @@ -2,7 +2,7 @@ package router import ( "vanir/internal/app/presentation/adapters" - controllers "vanir/internal/app/presentation/controllers/favorite" + controllers "vanir/internal/app/presentation/controller/favorite" "vanir/internal/app/presentation/middlewares" "vanir/internal/pkg/crypto" "vanir/internal/pkg/data/models" diff --git a/internal/app/router/users.go b/internal/app/router/users.go index 0cbbeb0..7df9946 100644 --- a/internal/app/router/users.go +++ b/internal/app/router/users.go @@ -2,7 +2,7 @@ package router import ( "vanir/internal/app/presentation/adapters" - controllers "vanir/internal/app/presentation/controllers/users" + controller "vanir/internal/app/presentation/controller/users" "vanir/internal/app/presentation/middlewares" "vanir/internal/pkg/crypto" "vanir/internal/pkg/data/models" @@ -14,9 +14,9 @@ import ( func SetupUserRoutes(r *echo.Group) { userService := services.GetUserService(repositories.GetUserRepository(), crypto.GetHasher()) - getUserController := controllers.NewGetUserController(userService) - updateUserController := controllers.NewUpdateUserController(userService) - createUserController := controllers.NewCreateUserController(userService) + getUserController := controller.NewGetUserController(userService) + updateUserController := controller.NewUpdateUserController(userService) + createUserController := controller.NewCreateUserController(userService) authenticatedMiddleware := middlewares.GetAuthenticatedMiddleware(crypto.GetEncrypter(), userService) r.POST("", adapters.AdaptControllerToEchoJSON( diff --git a/internal/pkg/data/models/favorites.go b/internal/pkg/data/models/favorites.go index 43649c9..1917136 100644 --- a/internal/pkg/data/models/favorites.go +++ b/internal/pkg/data/models/favorites.go @@ -21,3 +21,14 @@ type DeleteFavoriteParams struct { Reference string UserID string } + +type ListUserFavoritesQueryParams struct { + UserID string `validate:"required"` + Page int `query:"page" validate:"required,numeric,min=1"` + Limit int `query:"limit" validate:"required,max=100,min=1"` +} + +type ListFavoritesResponse struct { + Paginated + Data []Favorite `json:"data"` +} diff --git a/internal/pkg/data/models/user.go b/internal/pkg/data/models/user.go index 8487327..bb11fd1 100644 --- a/internal/pkg/data/models/user.go +++ b/internal/pkg/data/models/user.go @@ -1,21 +1,23 @@ package models -import "time" - +// @Description User account information +// @Description with user id and email type User struct { - ID string `json:"id"` - Email string `json:"email"` - Name string `json:"name"` - Password string `json:"-"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID string `json:"id" example:"u_AksOKxc12a"` + Email string `json:"email" example:"bruno.lombardi@email.com"` + Name string `json:"name" example:"Bruno Lombardi"` + Password string `json:"-"` + CreatedAt int64 `json:"created_at" example:"1733583441703"` + UpdatedAt int64 `json:"updated_at" example:"1733583441710"` } +// @Description Create user params information +// @Description with email, name and password with confirmation type CreateUserParams struct { - Email string `json:"email" validate:"email,required,max=255"` - Name string `json:"name" validate:"required,max=100,min=2"` - Password string `json:"password" validate:"required,max=64,min=6"` - PasswordConfirmation string `json:"password_confirmation" validate:"required,max=64,min=6,eqcsfield=Password"` + Email string `json:"email" validate:"email,required,max=255" example:"bruno.lombardi@email.com"` + Name string `json:"name" validate:"required,max=100,min=2" example:"Bruno Lombardi"` + Password string `json:"password" validate:"required,max=64,min=6" example:"123456"` + PasswordConfirmation string `json:"password_confirmation" validate:"required,max=64,min=6,eqcsfield=Password" example:"123456"` } type UpdateUserParams struct { diff --git a/test/pkg/services/auth_service_test.go b/internal/pkg/services/auth_service_test.go similarity index 94% rename from test/pkg/services/auth_service_test.go rename to internal/pkg/services/auth_service_test.go index de4ce5c..a2299b1 100644 --- a/test/pkg/services/auth_service_test.go +++ b/internal/pkg/services/auth_service_test.go @@ -1,4 +1,4 @@ -package services_test +package services import ( "fmt" @@ -7,7 +7,6 @@ import ( "vanir/internal/pkg/data/repositories" "vanir/internal/pkg/helpers" "vanir/internal/pkg/protocols" - "vanir/internal/pkg/services" "vanir/test/mocks" "github.com/stretchr/testify/mock" @@ -16,7 +15,7 @@ import ( type AuthServiceSuite struct { suite.Suite - authService *services.AuthServiceImpl + authService *AuthServiceImpl userRepository *mocks.UserRepositoryMock hasher *mocks.HasherMock encrypter *mocks.EncrypterMock @@ -27,7 +26,7 @@ func (sut *AuthServiceSuite) BeforeTest(_, _ string) { sut.hasher = &mocks.HasherMock{} sut.encrypter = &mocks.EncrypterMock{} - sut.authService = services.NewAuthServiceImpl(sut.userRepository, sut.hasher, sut.encrypter) + sut.authService = NewAuthServiceImpl(sut.userRepository, sut.hasher, sut.encrypter) } func (sut *AuthServiceSuite) AfterTest(_, _ string) { @@ -37,7 +36,7 @@ func (sut *AuthServiceSuite) AfterTest(_, _ string) { } func (sut *AuthServiceSuite) TestSmokeAuthService() { - sut.NotNil(services.GetAuthService(&mocks.UserRepositoryMock{}, &mocks.HasherMock{}, &mocks.EncrypterMock{})) + sut.NotNil(GetAuthService(&mocks.UserRepositoryMock{}, &mocks.HasherMock{}, &mocks.EncrypterMock{})) } func (sut *AuthServiceSuite) TestShouldReturnTokenWhenValidCredentials() { diff --git a/internal/pkg/services/favorite_service.go b/internal/pkg/services/favorite_service.go index 323d002..784018d 100644 --- a/internal/pkg/services/favorite_service.go +++ b/internal/pkg/services/favorite_service.go @@ -1,12 +1,14 @@ package services import ( + "math" "sync" "vanir/internal/pkg/data/models" "vanir/internal/pkg/data/repositories" ) type FavoriteService interface { + Paginate(params *models.ListUserFavoritesQueryParams) (*models.ListFavoritesResponse, error) Create(params *models.CreateFavoriteParams) (*models.Favorite, error) Get(ID string) (*models.Favorite, error) Delete(params *models.DeleteFavoriteParams) error @@ -66,3 +68,36 @@ func (s *FavoriteServiceImpl) Delete(params *models.DeleteFavoriteParams) error err := s.favoritesRepository.DeleteByUserIDAndReference(params.UserID, params.Reference) return err } + +func (s *FavoriteServiceImpl) Paginate(params *models.ListUserFavoritesQueryParams) (*models.ListFavoritesResponse, error) { + favorites, count, err := s.favoritesRepository.FindAllByUserID(params.UserID, params.Page, params.Limit) + + return &models.ListFavoritesResponse{ + Data: mapListToModel(favorites), + Paginated: models.Paginated{ + TotalPages: int(math.Ceil(float64(count) / float64(params.Limit))), + Count: int(count), + Page: params.Page, + Limit: params.Limit, + }, + }, err +} + +func mapEntityToModel(favorite repositories.FavoriteEntity) models.Favorite { + return models.Favorite{ + ID: favorite.ID, + Type: string(favorite.Type), + Reference: favorite.Reference, + UserID: favorite.UserID, + CreatedAt: favorite.CreatedAt, + UpdatedAt: favorite.UpdatedAt, + } +} + +func mapListToModel(favorites []repositories.FavoriteEntity) []models.Favorite { + mappedFavorites := []models.Favorite{} + for _, item := range favorites { + mappedFavorites = append(mappedFavorites, mapEntityToModel(item)) + } + return mappedFavorites +} diff --git a/internal/pkg/services/user_service.go b/internal/pkg/services/user_service.go index 7bb532e..3d57233 100644 --- a/internal/pkg/services/user_service.go +++ b/internal/pkg/services/user_service.go @@ -42,14 +42,7 @@ func (u *UserServiceImpl) Create(createUserParams *models.CreateUserParams) (*mo if err != nil { return nil, err } else { - return &models.User{ - ID: user.ID, - Email: user.Email, - Name: user.Name, - Password: user.Password, - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - }, nil + return mapUserToModel(user), nil } } @@ -75,26 +68,23 @@ func (u *UserServiceImpl) Update(updateUserParams *models.UpdateUserParams) (*mo return nil, err } - return &models.User{ - ID: user.ID, - Email: user.Email, - Name: user.Name, - Password: user.Password, - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - }, nil + return mapUserToModel(user), nil } func (u *UserServiceImpl) Get(ID string) (*models.User, error) { user, err := u.userRepository.Get(ID) + return mapUserToModel(user), err +} + +func mapUserToModel(user *repositories.UserEntity) *models.User { return &models.User{ ID: user.ID, Email: user.Email, Name: user.Name, Password: user.Password, - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - }, err + CreatedAt: user.CreatedAt.Unix(), + UpdatedAt: user.UpdatedAt.Unix(), + } } diff --git a/test/pkg/services/user_service_test.go b/internal/pkg/services/user_service_test.go similarity index 96% rename from test/pkg/services/user_service_test.go rename to internal/pkg/services/user_service_test.go index 7ef35b9..a62dc1e 100644 --- a/test/pkg/services/user_service_test.go +++ b/internal/pkg/services/user_service_test.go @@ -1,4 +1,4 @@ -package services_test +package services import ( "fmt" @@ -6,7 +6,6 @@ import ( "vanir/internal/pkg/data/models" "vanir/internal/pkg/data/repositories" "vanir/internal/pkg/helpers" - "vanir/internal/pkg/services" "vanir/test/mocks" "github.com/stretchr/testify/mock" @@ -15,7 +14,7 @@ import ( type UserServiceSuite struct { suite.Suite - userService *services.UserServiceImpl + userService *UserServiceImpl userRepository *mocks.UserRepositoryMock hasher *mocks.HasherMock } @@ -24,7 +23,7 @@ func (sut *UserServiceSuite) BeforeTest(_, _ string) { sut.userRepository = &mocks.UserRepositoryMock{} sut.hasher = &mocks.HasherMock{} - sut.userService = services.NewUserServiceImpl(sut.userRepository, sut.hasher) + sut.userService = NewUserServiceImpl(sut.userRepository, sut.hasher) } func (sut *UserServiceSuite) AfterTest(_, _ string) { @@ -35,7 +34,7 @@ func (sut *UserServiceSuite) AfterTest(_, _ string) { } func (sut *UserServiceSuite) TestSmokeTest() { - sut.NotNil(services.GetUserService(&mocks.UserRepositoryMock{}, &mocks.HasherMock{})) + sut.NotNil(GetUserService(&mocks.UserRepositoryMock{}, &mocks.HasherMock{})) } func (sut *UserServiceSuite) TestShouldCreateUserWhenValidData() { diff --git a/cmd/app/main.go b/main.go similarity index 100% rename from cmd/app/main.go rename to main.go diff --git a/test/app/presentation/controllers/users/setup_test.go b/test/app/presentation/controllers/users/setup_test.go deleted file mode 100644 index f7801b5..0000000 --- a/test/app/presentation/controllers/users/setup_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package user_controllers_test - -import ( - "os" - "testing" - "vanir/internal/pkg/config" - "vanir/internal/pkg/data/db" - data_test "vanir/test/data" - "vanir/test/mocks" -) - -type ControllerTestCase = data_test.ControllerTestCase - -var userServiceMock *mocks.UserServiceMock - -func TestMain(m *testing.M) { - config.Setup() - db.SetupDB() - userServiceMock = &mocks.UserServiceMock{} - - code := m.Run() - - os.Exit(code) -}