diff --git a/console/serve.go b/console/serve.go index 19502fe..928c600 100644 --- a/console/serve.go +++ b/console/serve.go @@ -34,15 +34,15 @@ func (s *ServeCommand) Run() framework.CommandRunner { logger.Info(`+-----------------------+`) // Using time zone as specified in env file - loc, _ := time.LoadLocation(env.TimeZone) + loc, _ := time.LoadLocation(env.Server.TimeZone) time.Local = loc middleware.Setup() //seeds.Setup() - if env.Environment != "local" && env.SentryDSN != "" { + if env.Server.Environment != "local" && env.Sentry.DSN != "" { err := sentry.Init(sentry.ClientOptions{ - Dsn: env.SentryDSN, + Dsn: env.Sentry.DSN, Environment: env.Environment, AttachStacktrace: true, }) @@ -52,13 +52,13 @@ func (s *ServeCommand) Run() framework.CommandRunner { } } logger.Info("Running server") - if env.ServerPort == "" { + if env.Server.Port == "" { if err := router.Run(); err != nil { logger.Fatal(err) return } } else { - if err := router.Run(":" + env.ServerPort); err != nil { + if err := router.Run(":" + env.Server.Port); err != nil { logger.Fatal(err) return } diff --git a/pkg/framework/env.go b/pkg/framework/env.go index 8774625..9f4fe70 100644 --- a/pkg/framework/env.go +++ b/pkg/framework/env.go @@ -4,32 +4,52 @@ import ( "github.com/spf13/viper" ) -type Env struct { - LogLevel string `mapstructure:"LOG_LEVEL"` - ServerPort string `mapstructure:"SERVER_PORT"` +type AdminConfig struct { + Email string `mapstructure:"ADMIN_EMAIL"` + Password string `mapstructure:"ADMIN_PASSWORD"` +} + +type AWSConfig struct { + Region string `mapstructure:"AWS_REGION"` + AccessKey string `mapstructure:"AWS_ACCESS_KEY_ID"` + SecretAccessKey string `mapstructure:"AWS_SECRET_ACCESS_KEY"` + StorageBucketName string `mapstructure:"STORAGE_BUCKET_NAME"` + CognitoClientID string `mapstructure:"COGNITO_CLIENT_ID"` + CognitoUserPoolID string `mapstructure:"COGNITO_USER_POOL_ID"` +} + +type SentryConfig struct { + DSN string `mapstructure:"SENTRY_DSN"` +} + +type ServerConfig struct { + Port string `mapstructure:"SERVER_PORT"` Environment string `mapstructure:"ENVIRONMENT"` + LogLevel string `mapstructure:"LOG_LEVEL"` + TimeZone string `mapstructure:"TIMEZONE"` +} + +type DatabaseConfig struct { + Username string `mapstructure:"DB_USER"` + Password string `mapstructure:"DB_PASS"` + Host string `mapstructure:"DB_HOST"` + Port string `mapstructure:"DB_PORT"` + Name string `mapstructure:"DB_NAME"` + Type string `mapstructure:"DB_TYPE"` + ForwardPort string `mapstructure:"DB_FORWARD_PORT"` +} + +type Env struct { + Server ServerConfig `mapstructure:",squash"` + + Database DatabaseConfig `mapstructure:",squash"` + + Sentry SentryConfig `mapstructure:",squash"` + MaxMultipartMemory int64 `mapstructure:"MAX_MULTIPART_MEMORY"` + + Admin AdminConfig `mapstructure:",squash"` - DBUsername string `mapstructure:"DB_USER"` - DBPassword string `mapstructure:"DB_PASS"` - DBHost string `mapstructure:"DB_HOST"` - DBPort string `mapstructure:"DB_PORT"` - DBName string `mapstructure:"DB_NAME"` - DBType string `mapstructure:"DB_TYPE"` - - SentryDSN string `mapstructure:"SENTRY_DSN"` - MaxMultipartMemory int64 `mapstructure:"MAX_MULTIPART_MEMORY"` - StorageBucketName string `mapstructure:"STORAGE_BUCKET_NAME"` - - TimeZone string `mapstructure:"TIMEZONE"` - AdminEmail string `mapstructure:"ADMIN_EMAIL"` - AdminPassword string `mapstructure:"ADMIN_PASSWORD"` - - AWSRegion string `mapstructure:"AWS_REGION"` - AWSAccessKey string `mapstructure:"AWS_ACCESS_KEY_ID"` - ClientID string `mapstructure:"COGNITO_CLIENT_ID"` - UserPoolID string `mapstructure:"COGNITO_USER_POOL_ID"` - AWSSecretAccessKey string `mapstructure:"AWS_SECRET_ACCESS_KEY"` - DBFORWARDPORT string `mapstructure:"DB_FORWARD_PORT"` + AWS AWSConfig `mapstructure:",squash"` } var globalEnv = Env{ diff --git a/pkg/infrastructure/aws.go b/pkg/infrastructure/aws.go index 26b0a83..7acd050 100644 --- a/pkg/infrastructure/aws.go +++ b/pkg/infrastructure/aws.go @@ -19,11 +19,11 @@ func NewAWSConfig( env *framework.Env, ) aws.Config { c := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider( - env.AWSAccessKey, env.AWSSecretAccessKey, ""), + env.AWS.AccessKey, env.AWS.SecretAccessKey, ""), ) conf, _ := config.LoadDefaultConfig( context.Background(), - config.WithRegion(env.AWSRegion), + config.WithRegion(env.AWS.Region), config.WithCredentialsProvider(c), config.WithClientLogMode(aws.LogRetries), ) diff --git a/pkg/infrastructure/db.go b/pkg/infrastructure/db.go index 2b56593..6aa07de 100644 --- a/pkg/infrastructure/db.go +++ b/pkg/infrastructure/db.go @@ -16,7 +16,7 @@ type Database struct { // NewDatabase creates a new database instance func NewDatabase(logger framework.Logger, env *framework.Env) Database { - url := fmt.Sprintf("%s:%s@tcp(%s:%s)/?charset=utf8mb4&parseTime=True&loc=Local", env.DBUsername, env.DBPassword, env.DBHost, env.DBPort) + url := fmt.Sprintf("%s:%s@tcp(%s:%s)/?charset=utf8mb4&parseTime=True&loc=Local", env.Database.Username, env.Database.Password, env.Database.Host, env.Database.Port) logger.Info("opening db connection") db, err := gorm.Open(mysql.Open(url), &gorm.Config{Logger: logger.GetGormLogger()}) @@ -25,7 +25,7 @@ func NewDatabase(logger framework.Logger, env *framework.Env) Database { } logger.Info("creating database if it doesn't exist") - if err = db.Exec("CREATE DATABASE IF NOT EXISTS " + env.DBName).Error; err != nil { + if err = db.Exec("CREATE DATABASE IF NOT EXISTS " + env.Database.Name).Error; err != nil { logger.Info("couldn't create database") logger.Panic(err) } @@ -41,7 +41,7 @@ func NewDatabase(logger framework.Logger, env *framework.Env) Database { // reopen connection with the given database, after creating or checking if the database exists logger.Info("using given database") - urlWithDB := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", env.DBUsername, env.DBPassword, env.DBHost, env.DBPort, env.DBName) + urlWithDB := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", env.Database.Username, env.Database.Password, env.Database.Host, env.Database.Port, env.Database.Name) db, err = gorm.Open(mysql.Open(urlWithDB), &gorm.Config{Logger: logger.GetGormLogger()}) if err != nil { logger.Panic(err) diff --git a/pkg/infrastructure/router.go b/pkg/infrastructure/router.go index 035c62f..235b7bc 100644 --- a/pkg/infrastructure/router.go +++ b/pkg/infrastructure/router.go @@ -20,8 +20,17 @@ func NewRouter( logger framework.Logger, ) Router { + if env.Server.Environment != "local" && env.Sentry.DSN != "" { + if err := sentry.Init(sentry.ClientOptions{ + Dsn: env.Sentry.DSN, + Environment: `clean-backend-` + env.Server.Environment, + }); err != nil { + logger.Infof("Sentry initialization failed: %v\n", err) + } + } + gin.DefaultWriter = logger.GetGinLogger() - appEnv := env.Environment + appEnv := env.Server.Environment if appEnv == "production" { gin.SetMode(gin.ReleaseMode) } else { diff --git a/pkg/services/cognito.go b/pkg/services/cognito.go index 97ecc18..3979eb1 100644 --- a/pkg/services/cognito.go +++ b/pkg/services/cognito.go @@ -31,7 +31,7 @@ func NewCognitoAuthService( logger framework.Logger, ) CognitoAuthService { - issuer = "https://cognito-idp." + env.AWSRegion + ".amazonaws.com/" + env.UserPoolID + issuer = "https://cognito-idp." + env.AWS.Region + ".amazonaws.com/" + env.AWS.CognitoUserPoolID jwkURL = issuer + "/.well-known/jwks.json" keySet, _ = jwk.Fetch(context.Background(), jwkURL) @@ -59,7 +59,7 @@ func (cg *CognitoAuthService) VerifyToken(tokenString string) (jwt.Token, error) func (cg *CognitoAuthService) CreateUser(email, password, role string) (string, error) { _, err := cg.client.AdminCreateUser(context.Background(), &cognitoidentityprovider.AdminCreateUserInput{ - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: &email, MessageAction: types.MessageActionTypeSuppress, UserAttributes: []types.AttributeType{ @@ -86,10 +86,10 @@ func (cg *CognitoAuthService) CreateUser(email, password, role string) (string, Username: &email, Password: &password, Permanent: true, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, }) if err != nil { - _, delErr := cg.client.AdminDeleteUser(context.Background(), &cognitoidentityprovider.AdminDeleteUserInput{Username: &email, UserPoolId: &cg.env.UserPoolID}) + _, delErr := cg.client.AdminDeleteUser(context.Background(), &cognitoidentityprovider.AdminDeleteUserInput{Username: &email, UserPoolId: &cg.env.AWS.CognitoUserPoolID}) awsErr := utils.MapAWSError(cg.logger, delErr) if awsErr != nil { return "", awsErr @@ -155,12 +155,12 @@ func (cg *CognitoAuthService) setCustomClaimToOneUser(user string, c map[string] _, _ = cg.client.AddCustomAttributes(context.Background(), &cognitoidentityprovider.AddCustomAttributesInput{ CustomAttributes: create, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, }) _, err := cg.client.AdminUpdateUserAttributes(context.Background(), &cognitoidentityprovider.AdminUpdateUserAttributesInput{ UserAttributes: claim, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: &user, }) if err != nil { @@ -176,7 +176,7 @@ func (cg *CognitoAuthService) setCustomClaimToOneUser(user string, c map[string] func (cg *CognitoAuthService) GetUserByUsername(username string) (*cognitoidentityprovider.AdminGetUserOutput, error) { user, err := cg.client.AdminGetUser(context.Background(), &cognitoidentityprovider.AdminGetUserInput{ Username: &username, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, }) if err != nil { if awsErr := utils.MapAWSError(cg.logger, err); awsErr != nil { @@ -191,7 +191,7 @@ func (cg *CognitoAuthService) GetUserByUsername(username string) (*cognitoidenti func (cg *CognitoAuthService) GetUserByEmail(email string) (*cognitoidentityprovider.AdminGetUserOutput, error) { user, err := cg.client.AdminGetUser(context.Background(), &cognitoidentityprovider.AdminGetUserInput{ Username: &email, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, }) if err != nil { if awsErr := utils.MapAWSError(cg.logger, err); awsErr != nil { @@ -205,7 +205,7 @@ func (cg *CognitoAuthService) GetUserByEmail(email string) (*cognitoidentityprov func (cg *CognitoAuthService) CreateAdminUser(email, password string, isPermanent bool) (string, error) { _, err := cg.client.AdminCreateUser(context.Background(), &cognitoidentityprovider.AdminCreateUserInput{ - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: &email, MessageAction: types.MessageActionTypeSuppress, UserAttributes: []types.AttributeType{ @@ -231,11 +231,11 @@ func (cg *CognitoAuthService) CreateAdminUser(email, password string, isPermanen Username: &email, Password: &password, Permanent: true, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, }) if err != nil { - _, err = cg.client.AdminDeleteUser(context.Background(), &cognitoidentityprovider.AdminDeleteUserInput{Username: &email, UserPoolId: &cg.env.UserPoolID}) + _, err = cg.client.AdminDeleteUser(context.Background(), &cognitoidentityprovider.AdminDeleteUserInput{Username: &email, UserPoolId: &cg.env.AWS.CognitoUserPoolID}) awsErr := utils.MapAWSError(cg.logger, err) if awsErr != nil { return "", awsErr @@ -291,7 +291,7 @@ func (cg *CognitoAuthService) DeleteCognitoUser(token *string) error { func (cg *CognitoAuthService) UpdateUserAttribute(username *string, attr []types.AttributeType) (*cognitoidentityprovider.AdminUpdateUserAttributesOutput, error) { op, err := cg.client.AdminUpdateUserAttributes(context.Background(), &cognitoidentityprovider.AdminUpdateUserAttributesInput{ - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: username, UserAttributes: attr, }, @@ -335,7 +335,7 @@ func (cg *CognitoAuthService) SetUserPassword(email, password string) error { Password: &password, Username: &email, Permanent: true, - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, }) if err != nil { if awsErr := utils.MapAWSError(cg.logger, err); awsErr != nil { @@ -349,7 +349,7 @@ func (cg *CognitoAuthService) SetUserPassword(email, password string) error { func (cg *CognitoAuthService) DeleteUserAsAdmin(username string) error { _, err := cg.client.AdminDeleteUser(context.Background(), &cognitoidentityprovider.AdminDeleteUserInput{ - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: &username, }, ) @@ -378,7 +378,7 @@ func (cg *CognitoAuthService) UpdateUserRole(email, newRole string) error { func (cg *CognitoAuthService) DisableUser(username string) error { _, err := cg.client.AdminDisableUser(context.Background(), &cognitoidentityprovider.AdminDisableUserInput{ - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: &username, }, ) @@ -394,7 +394,7 @@ func (cg *CognitoAuthService) DisableUser(username string) error { func (cg *CognitoAuthService) EnableUser(username string) error { _, err := cg.client.AdminEnableUser(context.Background(), &cognitoidentityprovider.AdminEnableUserInput{ - UserPoolId: &cg.env.UserPoolID, + UserPoolId: &cg.env.AWS.CognitoUserPoolID, Username: &username, }, ) diff --git a/pkg/services/s3.go b/pkg/services/s3.go index 2be8563..af16c44 100644 --- a/pkg/services/s3.go +++ b/pkg/services/s3.go @@ -34,7 +34,7 @@ func (s *S3Service) UploadFile( fileName string, ) (string, error) { - bucketName := s.env.StorageBucketName + bucketName := s.env.AWS.StorageBucketName if bucketName == "" { s.logger.Fatal("Bucket name missing.") @@ -63,7 +63,7 @@ func (s *S3Service) UploadFile( } func (s *S3Service) GetSignedURL(key string) (string, error) { - bucketName := s.env.StorageBucketName + bucketName := s.env.AWS.StorageBucketName if bucketName == "" { s.logger.Fatal("Bucket name missing.") diff --git a/seeds/admin_seed.go b/seeds/admin_seed.go index eee7370..06422e8 100644 --- a/seeds/admin_seed.go +++ b/seeds/admin_seed.go @@ -34,8 +34,8 @@ func NewAdminSeed( // Run the admin seed func (s AdminSeed) Setup() { - email := s.env.AdminEmail - password := s.env.AdminPassword + email := s.env.Admin.Email + password := s.env.Admin.Password s.logger.Info("🌱 seeding admin data...")