Skip to content

Commit

Permalink
Feat 46 sso system (#156)
Browse files Browse the repository at this point in the history
* feat: Controller Google Login

* chore: Adding Google oAuth2 Package

* feat: Adding Cors Middleware

* feat: Cors Middleware

* feat: WIP Google Login

* chore: refactor Login and Access Token

* feat: Google Login Finished

* chore: Refactoring DB and ENV initialization

* feat: Facebook Implementation + Better implementation.

* feat: provider error

* feat: Provider Tests

* feat: Provider tests

* fix: Fixing something wrong

* foix: Google Struct name

* fix: Compose api Port

* Fix: Errors and variables names

* fix: adding error check

* Issue 36 (#150)

* feat: add migration push notification settings

* feat: push notification endpoint

* fix: adjust user repo to update push notification

* Padronizar testes usando Mockery (#147) (#152)

*refactor tests: breed and pet.

* foix: Google Struct name

* fix: Compose api Port

* Fix: Errors and variables names

* fix: adding error check

* feat: Controller Google Login

* chore: Adding Google oAuth2 Package

* feat: Adding Cors Middleware

* feat: Cors Middleware

* feat: WIP Google Login

* chore: refactor Login and Access Token

* feat: Google Login Finished

* chore: Refactoring DB and ENV initialization

* feat: Facebook Implementation + Better implementation.

* feat: provider error

* feat: Provider Tests

* feat: Provider tests

* Issue 36 (#150)

* feat: add migration push notification settings

* feat: push notification endpoint

* fix: adjust user repo to update push notification

* Padronizar testes usando Mockery (#147) (#152)

*refactor tests: breed and pet.

* foix: Google Struct name

* fix: Compose api Port

* Fix: Errors and variables names

* fix: adding error check

* fix: ajust docker compose

* fix: resolve lint errors

---------

Co-authored-by: Thiago Calazans <98334306+thiagoCalazans-dev@users.noreply.github.com>
Co-authored-by: Edilton Oliveira <86030948+EdiltonOliveira@users.noreply.github.com>
Co-authored-by: Paulo Victor T Silva <pilutechinformatica@gmail.com>
  • Loading branch information
4 people committed Jul 24, 2024
1 parent 63e713c commit 69b94a3
Show file tree
Hide file tree
Showing 26 changed files with 821 additions and 108 deletions.
15 changes: 12 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
DATABASE_URL="maria:123@tcp(db:3306)/petdex?multiStatements=true"
MIGRATION_DATABASE_URL=maria:123@tcp(localhost:3306)/petdex?multiStatements=true
PORT="3000"
API_PORT="3000"
ENVIRONMENT="DEVELOPMENT"
MIGRATIONS_PATH="migrations"

Expand All @@ -11,9 +9,20 @@ DB_DATABASE="petdex"
DB_HOST="db"
DB_PORT="3306"

MIGRATION_HOST="localhost"

REDIS_HOST="pet-dex-cache"
REDIS_PORT="6379"
REDIS_PASSWORD="123"

JWT_SECRET=MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHQ5BWxB9NlRB89pOVY320IISVsSCOLKtGy0nVybrHNdzIhQW64XN8af66SvAN4CG9ZuzH73iGOFUXoMTwy1bDKsoxrRgybEoHA8wZxw0yOItYoQ8HY6fzLJTEmHtMTPLKCqhZe70vEBK/N69dJhZWL0MH4UeQwLgibIrCoPQuhbAgMBAAE

# Get at https://console.cloud.google.com/apis/credentials follow https://developers.google.com/identity/sign-in/web/sign-in instructions
GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
# The redirect URL should be in the Authorized redirect URIs at https://console.cloud.google.com/apis/credentials and this URL should be the login page that will call the fetch to google login
GOOGLE_REDIRECT_URL=

# Get at https://developers.facebook.com/ creating an app.
FACEBOOK_APP_ID=
FACEBOOK_APP_SECRET=
5 changes: 5 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ packages:
PetRepository:
UserRepository:
OngRepository:
SingleSignOnProvider:
SingleSignOnGateway:
BreedRepository:
AdressRepo:
SingleSignOnProvider:
SingleSignOnGateway:
BreedRepository:
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dev:
docker compose --profile development --env-file .env up --build

prod:
docker compose --profile integration-tests up --build
docker compose --profile integration-tests --env-file .env up --build

run:
go run ./api/main.go
Expand Down
62 changes: 60 additions & 2 deletions api/controllers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (uc *UserController) Insert(w http.ResponseWriter, r *http.Request) {

w.WriteHeader(http.StatusCreated)
}
func (uc *UserController) GenerateToken(w http.ResponseWriter, r *http.Request) {
func (uc *UserController) Login(w http.ResponseWriter, r *http.Request) {
var userLoginDto dto.UserLoginDto
err := json.NewDecoder(r.Body).Decode(&userLoginDto)

Expand All @@ -65,7 +65,7 @@ func (uc *UserController) GenerateToken(w http.ResponseWriter, r *http.Request)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
token, err := uc.usecase.GenerateToken(&userLoginDto)
token, err := uc.usecase.Login(&userLoginDto)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
Expand Down Expand Up @@ -238,3 +238,61 @@ func (uc *UserController) ChangePassword(w http.ResponseWriter, r *http.Request)

w.WriteHeader(http.StatusOK)
}

func (uc *UserController) ProviderLogin(w http.ResponseWriter, r *http.Request) {
provider := chi.URLParam(r, "provider")

userId := r.Header.Get("UserId")
if userId != "" {
w.WriteHeader(http.StatusOK)
return
}

var body struct {
AccessToken string `json:"accessToken"`
}

err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
uc.logger.Error("error decoding request: ", err)
http.Error(w, "Error decoding request ", http.StatusBadRequest)
return
}

if body.AccessToken == "" {
uc.logger.Error("empty access token: ", err)
http.Error(w, "error empty access token ", http.StatusBadRequest)
return
}

user, isNew, err := uc.usecase.ProviderLogin(body.AccessToken, provider)
if err != nil {
uc.logger.Error("error logging in with provider: ", provider, err)
w.WriteHeader(http.StatusInternalServerError)
return
}

if isNew {
// Return name, lastname and email to create the new user in the frontend
err := json.NewEncoder(w).Encode(struct {
Name string `json:"name"`
Email string `json:"email"`
}{
Name: user.Name,
Email: user.Email,
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
return
}

//Generate Token for the user
token, _ := uc.usecase.NewAccessToken(user.ID.String(), user.Name, user.Email)

w.Header().Add("Authorization", token)
w.WriteHeader(http.StatusOK)
}
30 changes: 14 additions & 16 deletions api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,36 @@ import (
"pet-dex-backend/v2/infra/db"
"pet-dex-backend/v2/pkg/encoder"
"pet-dex-backend/v2/pkg/hasher"
"pet-dex-backend/v2/pkg/sso"
"pet-dex-backend/v2/usecase"

"github.com/jmoiron/sqlx"
)

func main() {
env, err := config.LoadEnv(".")
if err != nil {
panic(err)
}

err = config.InitConfigs()
if err != nil {
panic(err)
}

sqlxDb, err := sqlx.Open("mysql", env.DBUrl)

envVariables, err := config.LoadEnv(".")
if err != nil {
panic(err)
}

// config.InitConfigs()
databaseUrl := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?multiStatements=true", envVariables.DB_USER, envVariables.DB_PASSWORD, envVariables.DB_HOST, envVariables.DB_PORT, envVariables.DB_DATABASE)
sqlxDb := sqlx.MustConnect("mysql", databaseUrl)
dbPetRepo := db.NewPetRepository(sqlxDb)
dbUserRepo := db.NewUserRepository(sqlxDb)
dbOngRepo := db.NewOngRepository(sqlxDb)
hash := hasher.NewHasher()
bdBreedRepo := db.NewBreedRepository(sqlxDb)

encoder := encoder.NewEncoderAdapter(config.GetEnvConfig().JWT_SECRET)
encoder := encoder.NewEncoderAdapter(envVariables.JWT_SECRET)

googleSsoGt := sso.NewGoogleGateway(envVariables)
facebookSsoGt := sso.NewFacebookGateway(envVariables)

ssoProvider := sso.NewProvider(googleSsoGt, facebookSsoGt)

breedUsecase := usecase.NewBreedUseCase(bdBreedRepo)
uusercase := usecase.NewUserUsecase(dbUserRepo, hash, encoder)
uusercase := usecase.NewUserUsecase(dbUserRepo, hash, encoder, ssoProvider)
petUsecase := usecase.NewPetUseCase(dbPetRepo)
ongUsecase := usecase.NewOngUseCase(dbOngRepo, dbUserRepo, hash)
breedController := controllers.NewBreedController(breedUsecase)
Expand All @@ -56,6 +54,6 @@ func main() {
}
router := routes.InitializeRouter(controllers)

fmt.Printf("running on port %v \n", env.PORT)
log.Fatal(http.ListenAndServe(":"+env.PORT, router))
fmt.Printf("running on port %v \n", envVariables.API_PORT)
log.Fatal(http.ListenAndServe(":"+envVariables.API_PORT, router))
}
18 changes: 18 additions & 0 deletions api/middlewares/cors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package middlewares

import (
"net/http"

"github.com/go-chi/cors"
)

func CorsMiddleware() func(http.Handler) http.Handler {
return cors.Handler(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 300, // Maximum value not ignored by any of major browsers
})
}
6 changes: 4 additions & 2 deletions api/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Controllers struct {
func InitRoutes(controllers Controllers, c *chi.Mux) {

c.Route("/api", func(r chi.Router) {
r.Use(middlewares.CorsMiddleware())
r.Use(middleware.AllowContentType("application/json"))

r.Group(func(private chi.Router) {
Expand Down Expand Up @@ -51,8 +52,9 @@ func InitRoutes(controllers Controllers, c *chi.Mux) {
})

r.Group(func(public chi.Router) {
public.Post("/user", controllers.UserController.Insert)
public.Post("/user/token", controllers.UserController.GenerateToken)
public.Post("/user/create-account", controllers.UserController.Insert)
public.Post("/user/{provider}/login", controllers.UserController.ProviderLogin)
public.Post("/user/login", controllers.UserController.Login)
public.Get("/pets/", controllers.PetController.ListAllPets)
})

Expand Down
32 changes: 20 additions & 12 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ services:
hostname: api
working_dir: /app
environment:
- DATABASE_URL=${DATABASE_URL}
- PORT=${PORT}
- PORT=${API_PORT}
- ENVIRONMENT=${ENVIRONMENT}
- MIGRATIONS_PATH=${MIGRATIONS_PATH}
ports:
- "${PORT}:${PORT}"
- "${API_PORT}:${API_PORT}"
volumes:
- ./:/app
depends_on:
cache:
condition: service_started
db:
condition: service_started
condition: service_healthy
env_file:
- .env.example
- .env
networks:
- pet-dex-dev

db: &db
db: &db # TODO: Quando subir dev se não tiver migration tem q rodar
image: mariadb:11.4.1-rc-jammy
profiles:
- development
hostname: db
environment:
- MARIADB_DATABASE=${DB_DATABASE}
- MARIADB_USER=${DB_USER}
Expand All @@ -50,9 +50,16 @@ services:
depends_on:
cache:
condition: service_started
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 20s
interval: 20s
timeout: 10s
retries: 3
volumes:
- ./data:/var/lib/mysql
env_file:
- .env.example
- .env
networks:
- pet-dex-dev
Expand All @@ -71,6 +78,7 @@ services:
volumes:
- ./cache:/data
env_file:
- .env.example
- .env
networks:
- pet-dex-dev
Expand All @@ -83,20 +91,20 @@ services:
- integration-tests
hostname: api-tests
environment:
DATABASE_URL: ${DATABASE_URL}
PORT: ${PORT}
PORT: ${API_PORT}
ENVIRONMENT: ${ENVIRONMENT}
MIGRATIONS_PATH: ${MIGRATIONS_PATH}
INTEGRATION: true
ports:
- "${PORT}:${PORT}"
- "${API_PORT}:${API_PORT}"
depends_on:
cache-test:
condition: service_healthy
db-test:
condition: service_healthy
env_file:
- .env.example
- .env
networks:
- pet-dex-integration-tests

Expand Down Expand Up @@ -125,16 +133,16 @@ services:
condition: service_healthy
profiles:
- integration-tests
hostname: db-test
volumes:
- ./data-teste:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 1m
interval: 1m
timeout: 10s
retries: 3
volumes:
- ./data-teste:/var/lib/mysql
env_file:
- .env.example
- .env
networks:
- pet-dex-integration-tests
2 changes: 1 addition & 1 deletion entity/dto/user_login.dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dto
import "errors"

type UserLoginDto struct {
Email string `json:"Email"`
Email string `json:"email"`
Password string `json:"password"`
}

Expand Down
6 changes: 6 additions & 0 deletions entity/dto/user_sso.dto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dto

type UserSSODto struct {
Name string `json:"name"`
Email string `json:"email"`
}
2 changes: 1 addition & 1 deletion entity/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func NewUser(name, uType, document, avatar_url, email, phone, pass, city, state
}
}

func UserToUpdate(dtoUpdate *dto.UserUpdateDto) User {
func UserToUpdate(dtoUpdate dto.UserUpdateDto) User {
user := User{
Name: dtoUpdate.Name,
Document: dtoUpdate.Document,
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ require (
)

require (
cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-chi/cors v1.2.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/facebook/v2 v2.7.3 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/markbates/goth v1.80.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
Expand All @@ -41,6 +45,7 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
Expand Down
Loading

0 comments on commit 69b94a3

Please sign in to comment.