diff --git a/cmd/membership/main.go b/cmd/membership/main.go new file mode 100644 index 0000000..83ee34f --- /dev/null +++ b/cmd/membership/main.go @@ -0,0 +1,8 @@ +package main + +import "GoMembership/internal/server" + +func main() { + server.Run() +} + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3ea80f2 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module GoMembership + +go 1.18 + +require ( + github.com/gorilla/mux v1.8.0 + golang.org/x/crypto v0.0.0-20220411214040-896ed404bb0e +) + +replace golang.org/x/crypto => golang.org/x/crypto v0.0.0-20220411214040-896ed404bb0e + diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2be86d7 --- /dev/null +++ b/go.sum @@ -0,0 +1,5 @@ +github.com/gorilla/mux v1.8.0 h1:vGHr6G7CRByRCFwUmpxP8Cj8ljy1OV8ZrRH6qrOEzXM= +github.com/gorilla/mux v1.8.0/go.mod h1:vGHr6G7CRByRCFwUmpxP8Cj8ljy1OV8ZrRH6qrOEzXM= +golang.org/x/crypto v0.0.0-20220411214040-896ed404bb0e h1:aIjQLr9igSCqCxL1cOsTSG91TtOGStlwrPvHxGpQuWk= +golang.org/x/crypto v0.0.0 + diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..82a131d --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,20 @@ +package config + +import ( + "os" +) + +type Config struct { + DBUser string + DBPassword string + DBName string +} + +func LoadConfig() *Config { + return &Config{ + DBUser: os.Getenv("DB_USER"), + DBPassword: os.Getenv("DB_PASSWORD"), + DBName: os.Getenv("DB_NAME"), + } +} + diff --git a/internal/controllers/user_controller.go b/internal/controllers/user_controller.go new file mode 100644 index 0000000..fdf937b --- /dev/null +++ b/internal/controllers/user_controller.go @@ -0,0 +1,31 @@ + +package controllers + +import ( + "encoding/json" + "net/http" + "GoMembership/internal/models" + "GoMembership/internal/services" +) + +type UserController struct { + service services.UserService +} + +func NewUserController(service services.UserService) *UserController { + return &UserController{service} +} + +func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) { + var user models.User + if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if err := uc.service.RegisterUser(&user); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusCreated) +} + diff --git a/internal/database/db.go b/internal/database/db.go new file mode 100644 index 0000000..253b271 --- /dev/null +++ b/internal/database/db.go @@ -0,0 +1,23 @@ +package database + +import ( + "database/sql" + "log" + "GoMembership/internal/config" + + _ "github.com/go-sql-driver/mysql" +) + +func Connect() *sql.DB { + cfg := config.LoadConfig() + dsn := cfg.DBUser + ":" + cfg.DBPassword + "@/" + cfg.DBName + db, err := sql.Open("mysql", dsn) + if err != nil { + log.Fatal(err) + } + if err := db.Ping(); err != nil { + log.Fatal(err) + } + return db +} + diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go new file mode 100644 index 0000000..0a45e89 --- /dev/null +++ b/internal/handlers/user_handler.go @@ -0,0 +1,11 @@ +package handlers + +import ( + "net/http" + "GoMembership/internal/controllers" +) + +func RegisterUserHandler(controller *controllers.UserController) http.Handler { + return http.HandlerFunc(controller.RegisterUser) +} + diff --git a/internal/middlewares/auth_middleware.go b/internal/middlewares/auth_middleware.go new file mode 100644 index 0000000..bbcffa7 --- /dev/null +++ b/internal/middlewares/auth_middleware.go @@ -0,0 +1,13 @@ +package middlewares + +import ( + "net/http" +) + +func AuthMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Authentication logic here + next.ServeHTTP(w, r) + }) +} + diff --git a/internal/models/user.go b/internal/models/user.go new file mode 100644 index 0000000..09df5b5 --- /dev/null +++ b/internal/models/user.go @@ -0,0 +1,14 @@ +package models + +import "time" + +type User struct { + ID int `json:"id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Email string `json:"email"` + Password string `json:"password"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go new file mode 100644 index 0000000..8264106 --- /dev/null +++ b/internal/repositories/user_repository.go @@ -0,0 +1,25 @@ +package repositories + +import ( + "database/sql" + "GoMembership/internal/models" +) + +type UserRepository interface { + CreateUser(user *models.User) error +} + +type userRepository struct { + db *sql.DB +} + +func NewUserRepository(db *sql.DB) UserRepository { + return &userRepository{db} +} + +func (r *userRepository) CreateUser(user *models.User) error { + query := "INSERT INTO users (first_name, last_name, email, password, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)" + _, err := r.db.Exec(query, user.FirstName, user.LastName, user.Email, user.Password, user.CreatedAt, user.UpdatedAt) + return err +} + diff --git a/internal/routes/routes.go b/internal/routes/routes.go new file mode 100644 index 0000000..ffbb3c1 --- /dev/null +++ b/internal/routes/routes.go @@ -0,0 +1,13 @@ +package routes + +import ( + "net/http" + "GoMembership/internal/controllers" + + "github.com/gorilla/mux" +) + +func RegisterRoutes(router *mux.Router, userController *controllers.UserController) { + router.HandleFunc("/register", userController.RegisterUser).Methods("POST") +} + diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..4e16c63 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,32 @@ +package server + +import ( + "database/sql" + "log" + "GoMembership/internal/controllers" + "GoMembership/internal/repositories" + "GoMembership/internal/routes" + "GoMembership/internal/services" + "net/http" + + "github.com/gorilla/mux" + _ "github.com/go-sql-driver/mysql" +) + +func Run() { + db, err := sql.Open("mysql", "user:password@/dbname") + if err != nil { + log.Fatal(err) + } + defer db.Close() + + userRepo := repositories.NewUserRepository(db) + userService := services.NewUserService(userRepo) + userController := controllers.NewUserController(userService) + + router := mux.NewRouter() + routes.RegisterRoutes(router, userController) + + log.Fatal(http.ListenAndServe(":8080", router)) +} + diff --git a/internal/services/user_service.go b/internal/services/user_service.go new file mode 100644 index 0000000..556e51f --- /dev/null +++ b/internal/services/user_service.go @@ -0,0 +1,29 @@ +package services + +import ( + "GoMembership/internal/models" + "GoMembership/internal/repositories" + "golang.org/x/crypto/bcrypt" +) + +type UserService interface { + RegisterUser(user *models.User) error +} + +type userService struct { + repo repositories.UserRepository +} + +func NewUserService(repo repositories.UserRepository) UserService { + return &userService{repo} +} + +func (s *userService) RegisterUser(user *models.User) error { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost) + if err != nil { + return err + } + user.Password = string(hashedPassword) + return s.repo.CreateUser(user) +} + diff --git a/internal/utils/validators.go b/internal/utils/validators.go new file mode 100644 index 0000000..71ca830 --- /dev/null +++ b/internal/utils/validators.go @@ -0,0 +1,10 @@ +package utils + +import "regexp" + +func IsEmailValid(email string) bool { + regex := `^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$` + re := regexp.MustCompile(regex) + return re.MatchString(email) +} + diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go new file mode 100644 index 0000000..ef9e07c --- /dev/null +++ b/pkg/errors/errors.go @@ -0,0 +1,10 @@ +package errors + +import "errors" + +var ( + ErrUserNotFound = errors.New("user not found") + ErrInvalidEmail = errors.New("invalid email") + // Add other custom errors here +) + diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 0000000..4b7b1c8 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,24 @@ +package logger + +import ( + "log" + "os" +) + +var ( + Info *log.Logger + Warning *log.Logger + Error *log.Logger +) + +func init() { + file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + log.Fatal(err) + } + + Info = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + Warning = log.New(file, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) + Error = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) +} +