This commit is contained in:
koh
2025-04-12 15:25:34 +07:00
commit d83f6c1145
38 changed files with 2131 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
package controllers
// Controllers chứa tất cả các controller của ứng dụng
type Controllers struct {
UserController IUserController
ProductController IProductController
}
// NewControllers tạo một instance mới của Controllers
func NewControllers(userController IUserController, productController IProductController) *Controllers {
return &Controllers{
UserController: userController,
ProductController: productController,
}
}

View File

@@ -0,0 +1,22 @@
package controllers
import "github.com/gin-gonic/gin"
// IUserController định nghĩa interface cho UserController
type IUserController interface {
Register(c *gin.Context)
Login(c *gin.Context)
GetProfile(c *gin.Context)
UpdateProfile(c *gin.Context)
}
// IProductController định nghĩa interface cho ProductController
type IProductController interface {
CreateProduct(c *gin.Context)
GetProduct(c *gin.Context)
GetAllProducts(c *gin.Context)
UpdateProduct(c *gin.Context)
DeleteProduct(c *gin.Context)
}
// Các interface khác có thể được thêm vào đây khi cần thiết

View File

@@ -0,0 +1,125 @@
package controllers
import (
"strconv"
"github.com/dungnt11/todoms_golang/internal/services"
"github.com/gin-gonic/gin"
)
// ProductController triển khai IProductController
type ProductController struct {
productService services.IProductService
}
// NewProductController tạo một instance mới của ProductController
func NewProductController(productService services.IProductService) *ProductController {
return &ProductController{
productService: productService,
}
}
// CreateProduct xử lý tạo sản phẩm mới
func (pc *ProductController) CreateProduct(c *gin.Context) {
// Gọi service để thực hiện logic tạo sản phẩm
result, err := pc.productService.CreateProduct(c)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(201, result)
}
// GetProduct xử lý lấy thông tin sản phẩm theo ID
func (pc *ProductController) GetProduct(c *gin.Context) {
// Lấy ID từ param
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(400, gin.H{
"error": "ID không hợp lệ",
})
return
}
// Gọi service để lấy thông tin sản phẩm
result, err := pc.productService.GetProduct(uint(id))
if err != nil {
c.JSON(404, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}
// GetAllProducts xử lý lấy tất cả sản phẩm
func (pc *ProductController) GetAllProducts(c *gin.Context) {
// Gọi service để lấy tất cả sản phẩm
result, err := pc.productService.GetAllProducts()
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}
// UpdateProduct xử lý cập nhật thông tin sản phẩm
func (pc *ProductController) UpdateProduct(c *gin.Context) {
// Lấy ID từ param
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(400, gin.H{
"error": "ID không hợp lệ",
})
return
}
// Gọi service để cập nhật thông tin sản phẩm
result, err := pc.productService.UpdateProduct(uint(id), c)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}
// DeleteProduct xử lý xóa sản phẩm
func (pc *ProductController) DeleteProduct(c *gin.Context) {
// Lấy ID từ param
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(400, gin.H{
"error": "ID không hợp lệ",
})
return
}
// Gọi service để xóa sản phẩm
result, err := pc.productService.DeleteProduct(uint(id))
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}

View File

@@ -0,0 +1,93 @@
package controllers
import (
"github.com/dungnt11/todoms_golang/internal/services"
"github.com/gin-gonic/gin"
)
// UserController triển khai IUserController
type UserController struct {
userService services.IUserService
}
// NewUserController tạo một instance mới của UserController
func NewUserController(userService services.IUserService) *UserController {
return &UserController{
userService: userService,
}
}
// Register xử lý đăng ký người dùng
func (uc *UserController) Register(c *gin.Context) {
// Gọi service để thực hiện logic đăng ký
result, err := uc.userService.Register(c)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}
// Login xử lý đăng nhập
func (uc *UserController) Login(c *gin.Context) {
// Gọi service để thực hiện logic đăng nhập
result, err := uc.userService.Login(c)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}
// GetProfile xử lý lấy thông tin profile
func (uc *UserController) GetProfile(c *gin.Context) {
// Lấy user ID từ token hoặc param (giả định)
userID := uint(1) // Trong thực tế, bạn sẽ lấy từ JWT token hoặc param
// Gọi service để lấy thông tin profile
result, err := uc.userService.GetProfile(userID)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}
// UpdateProfile xử lý cập nhật profile
func (uc *UserController) UpdateProfile(c *gin.Context) {
// Lấy user ID từ token hoặc param (giả định)
userID := uint(1) // Trong thực tế, bạn sẽ lấy từ JWT token hoặc param
// Đọc dữ liệu từ request
var data map[string]interface{}
if err := c.ShouldBindJSON(&data); err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
// Gọi service để cập nhật profile
result, err := uc.userService.UpdateProfile(userID, data)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, result)
}

View File

@@ -0,0 +1,65 @@
package initialize
import (
"fmt"
"os"
"strings"
"github.com/dungnt11/todoms_golang/global"
"github.com/joho/godotenv"
)
func LoadConfig() error {
err := godotenv.Load()
if err != nil {
return err
}
// Cấu hình server
global.Config.Server.Port = os.Getenv("PORT")
global.Config.Server.AppEnv = os.Getenv("APP_ENV")
// Cấu hình database
global.Config.Database.Host = os.Getenv("BLUEPRINT_DB_HOST")
global.Config.Database.Port = os.Getenv("BLUEPRINT_DB_PORT")
global.Config.Database.Database = os.Getenv("BLUEPRINT_DB_DATABASE")
global.Config.Database.Username = os.Getenv("BLUEPRINT_DB_USERNAME")
global.Config.Database.Password = os.Getenv("BLUEPRINT_DB_PASSWORD")
global.Config.Database.RootPassword = os.Getenv("BLUEPRINT_DB_ROOT_PASSWORD")
// Chuyển đổi các giá trị cấu hình database từ string sang int
if maxIdleConns := os.Getenv("BLUEPRINT_DB_MAX_IDLE_CONNS"); maxIdleConns != "" {
fmt.Sscanf(maxIdleConns, "%d", &global.Config.Database.MaxIdleConns)
}
if maxOpenConns := os.Getenv("BLUEPRINT_DB_MAX_OPEN_CONNS"); maxOpenConns != "" {
fmt.Sscanf(maxOpenConns, "%d", &global.Config.Database.MaxOpenConns)
}
if connMaxLifetime := os.Getenv("BLUEPRINT_DB_CONN_MAX_LIFETIME"); connMaxLifetime != "" {
fmt.Sscanf(connMaxLifetime, "%d", &global.Config.Database.ConnMaxLifetime)
}
// Cấu hình logger
global.Config.Logger.LogLevel = os.Getenv("LOGGER_LOG_LEVEL")
global.Config.Logger.FileLogName = os.Getenv("LOGGER_FILE_LOG_NAME")
// Chuyển đổi từ string sang int và bool
if maxSize := os.Getenv("LOGGER_MAX_SIZE"); maxSize != "" {
fmt.Sscanf(maxSize, "%d", &global.Config.Logger.MaxSize)
}
if maxBackups := os.Getenv("LOGGER_MAX_BACKUPS"); maxBackups != "" {
fmt.Sscanf(maxBackups, "%d", &global.Config.Logger.MaxBackups)
}
if maxAge := os.Getenv("LOGGER_MAX_AGE"); maxAge != "" {
fmt.Sscanf(maxAge, "%d", &global.Config.Logger.MaxAge)
}
if compress := os.Getenv("LOGGER_COMPRESS"); compress != "" {
global.Config.Logger.Compress = strings.ToLower(compress) == "true"
}
return nil
}

View File

@@ -0,0 +1,103 @@
package initialize
import (
"os"
"github.com/dungnt11/todoms_golang/global"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// InitLogger khởi tạo logger
func InitLogger() *zap.Logger {
// Đảm bảo thư mục logs tồn tại
ensureLogDir(global.Config.Logger.FileLogName)
// Khởi tạo logger
return newLogger(global.Config.Logger)
}
// ensureLogDir đảm bảo thư mục logs tồn tại
func ensureLogDir(logPath string) {
// Tìm vị trí thư mục cuối cùng trong đường dẫn
lastSlash := 0
for i := len(logPath) - 1; i >= 0; i-- {
if logPath[i] == '/' {
lastSlash = i
break
}
}
// Nếu không có thư mục, không cần tạo
if lastSlash == 0 {
return
}
// Tạo thư mục nếu chưa tồn tại
dirPath := logPath[:lastSlash]
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
os.MkdirAll(dirPath, 0755)
}
}
// newLogger tạo một logger mới
func newLogger(config global.LoggerConfig) *zap.Logger {
// Xác định level log
var level zapcore.Level
switch config.LogLevel {
case "debug":
level = zapcore.DebugLevel
case "info":
level = zapcore.InfoLevel
case "warn":
level = zapcore.WarnLevel
case "error":
level = zapcore.ErrorLevel
default:
level = zapcore.InfoLevel
}
// Cấu hình encoder
encoder := getEncoder()
// Cấu hình lumberjack để xoay vòng file log
hook := lumberjack.Logger{
Filename: config.FileLogName,
MaxSize: config.MaxSize, // megabytes
MaxBackups: config.MaxBackups,
MaxAge: config.MaxAge, // days
Compress: config.Compress,
}
// Tạo core cho zap
core := zapcore.NewCore(
encoder,
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)),
level,
)
// Tạo logger với các tùy chọn
return zap.New(core,
zap.AddCaller(),
zap.AddStacktrace(zapcore.ErrorLevel),
)
}
// getEncoder trả về encoder cho zap
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
// Cấu hình thời gian
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.TimeKey = "time"
// Cấu hình level
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
// Cấu hình caller
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
// Trả về encoder JSON
return zapcore.NewJSONEncoder(encoderConfig)
}

View File

@@ -0,0 +1,47 @@
package initialize
import (
"fmt"
"time"
"github.com/dungnt11/todoms_golang/global"
"go.uber.org/zap"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// checkErrorPanic kiểm tra lỗi và gọi panic nếu có lỗi, đồng thời ghi log chi tiết.
func checkErrorPanic(err error, errString string) {
if err != nil {
global.Logger.Error(errString, zap.Error(err))
panic(err)
}
}
// InitMysql khởi tạo kết nối đến cơ sở dữ liệu MySQL và trả về đối tượng *gorm.DB.
func InitMysql() *gorm.DB {
m := global.Config.Database
dsn := "%s:%s@tcp(%s:%v)/%s?charset=utf8mb4&parseTime=True&loc=Local"
s := fmt.Sprintf(dsn, m.Username, m.Password, m.Host, m.Port, m.Database)
db, err := gorm.Open(mysql.Open(s), &gorm.Config{
SkipDefaultTransaction: false,
})
checkErrorPanic(err, "InitMysql initialization error")
global.Logger.Info("Initializing MySQL Successfully")
setPool(db)
return db
}
// setPool thiết lập các thông số cho connection pool của cơ sở dữ liệu.
func setPool(db *gorm.DB) {
m := global.Config.Database
sqlDb, err := db.DB()
if err != nil {
global.Logger.Error("Failed to get sql.DB from gorm.DB", zap.Error(err))
return
}
sqlDb.SetMaxIdleConns(m.MaxIdleConns)
sqlDb.SetMaxOpenConns(m.MaxOpenConns)
sqlDb.SetConnMaxLifetime(time.Duration(m.ConnMaxLifetime) * time.Second)
}

View File

@@ -0,0 +1,93 @@
package initialize
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/dungnt11/todoms_golang/global"
"github.com/dungnt11/todoms_golang/internal/routers"
"github.com/dungnt11/todoms_golang/internal/wire"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// Run khởi động ứng dụng
func Run() {
// Tải cấu hình từ file .env
if err := LoadConfig(); err != nil {
fmt.Printf("Không thể tải cấu hình: %s\n", err.Error())
return
}
// Khởi tạo logger
global.Logger = InitLogger()
if global.Logger == nil {
fmt.Println("Khởi tạo logger thất bại")
return
}
// Khởi tạo database
global.Mdb = InitMysql()
if global.Mdb == nil {
global.Logger.Error("Khởi tạo MySQL thất bại")
return
}
// Khởi tạo router
r := provideRouter()
// Khởi tạo controllers thông qua wire
controllers, err := wire.InitializeControllers()
if err != nil {
global.Logger.Error("Khởi tạo controllers thất bại", zap.Error(err))
return
}
// Khởi tạo routers
routers.InitRouters(r, controllers)
// Khởi động server
port := global.Config.Server.Port
server := &http.Server{
Addr: fmt.Sprintf(":%s", port),
Handler: r,
}
// Khởi động server trong goroutine riêng
go func() {
global.Logger.Info(fmt.Sprintf("Server đang chạy trên cổng %s", port))
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
global.Logger.Error("Server gặp lỗi", zap.Error(err))
}
}()
// Graceful shutdown
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
global.Logger.Info("Đang tắt server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
global.Logger.Error("Server shutdown gặp lỗi", zap.Error(err))
}
global.Logger.Info("Server đã tắt thành công.")
}
func provideRouter() *gin.Engine {
if global.Config.Server.AppEnv == "local" {
gin.SetMode(gin.DebugMode)
gin.ForceConsoleColor()
return gin.Default()
} else {
gin.SetMode(gin.ReleaseMode)
return gin.New()
}
}

View File

@@ -0,0 +1,16 @@
package models
import (
"time"
)
// Product đại diện cho thông tin sản phẩm
type Product struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:255;not null" json:"name"`
Description string `gorm:"type:text" json:"description"`
Price float64 `gorm:"not null" json:"price"`
Quantity int `gorm:"not null" json:"quantity"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

18
internal/models/user.go Normal file
View File

@@ -0,0 +1,18 @@
package models
import (
"time"
"gorm.io/gorm"
)
// User đại diện cho người dùng trong hệ thống
type User struct {
ID uint `json:"id" gorm:"primaryKey"`
Username string `json:"username" gorm:"uniqueIndex;not null"`
Password string `json:"-" gorm:"not null"` // Không trả về password trong JSON
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
}

View File

@@ -0,0 +1,23 @@
package repositories
import "github.com/dungnt11/todoms_golang/internal/models"
// IUserRepository định nghĩa interface cho UserRepository
type IUserRepository interface {
Create(user *models.User) error
FindByID(id uint) (*models.User, error)
FindByUsername(username string) (*models.User, error)
Update(user *models.User) error
Delete(id uint) error
}
// IProductRepository định nghĩa interface cho ProductRepository
type IProductRepository interface {
Create(product *models.Product) error
FindByID(id uint) (*models.Product, error)
FindAll() ([]*models.Product, error)
Update(product *models.Product) error
Delete(id uint) error
}
// Các interface khác có thể được thêm vào đây khi cần thiết

View File

@@ -0,0 +1,53 @@
package repositories
import (
"github.com/dungnt11/todoms_golang/internal/models"
"gorm.io/gorm"
)
// ProductRepository triển khai IProductRepository
type ProductRepository struct {
db *gorm.DB
}
// NewProductRepository tạo một instance mới của ProductRepository
func NewProductRepository(db *gorm.DB) *ProductRepository {
return &ProductRepository{
db: db,
}
}
// Create tạo một sản phẩm mới
func (r *ProductRepository) Create(product *models.Product) error {
return r.db.Create(product).Error
}
// FindByID tìm sản phẩm theo ID
func (r *ProductRepository) FindByID(id uint) (*models.Product, error) {
var product models.Product
err := r.db.First(&product, id).Error
if err != nil {
return nil, err
}
return &product, nil
}
// FindAll lấy tất cả sản phẩm
func (r *ProductRepository) FindAll() ([]*models.Product, error) {
var products []*models.Product
err := r.db.Find(&products).Error
if err != nil {
return nil, err
}
return products, nil
}
// Update cập nhật thông tin sản phẩm
func (r *ProductRepository) Update(product *models.Product) error {
return r.db.Save(product).Error
}
// Delete xóa sản phẩm theo ID
func (r *ProductRepository) Delete(id uint) error {
return r.db.Delete(&models.Product{}, id).Error
}

View File

@@ -0,0 +1,53 @@
package repositories
import (
"github.com/dungnt11/todoms_golang/internal/models"
"gorm.io/gorm"
)
// UserRepository triển khai IUserRepository
type UserRepository struct {
db *gorm.DB
}
// NewUserRepository tạo một instance mới của UserRepository
func NewUserRepository(db *gorm.DB) *UserRepository {
return &UserRepository{
db: db,
}
}
// Create tạo một user mới trong database
func (ur *UserRepository) Create(user *models.User) error {
return ur.db.Create(user).Error
}
// FindByID tìm user theo ID
func (ur *UserRepository) FindByID(id uint) (*models.User, error) {
var user models.User
err := ur.db.First(&user, id).Error
if err != nil {
return nil, err
}
return &user, nil
}
// FindByUsername tìm user theo username
func (ur *UserRepository) FindByUsername(username string) (*models.User, error) {
var user models.User
err := ur.db.Where("username = ?", username).First(&user).Error
if err != nil {
return nil, err
}
return &user, nil
}
// Update cập nhật thông tin user
func (ur *UserRepository) Update(user *models.User) error {
return ur.db.Save(user).Error
}
// Delete xóa user theo ID
func (ur *UserRepository) Delete(id uint) error {
return ur.db.Delete(&models.User{}, id).Error
}

View File

@@ -0,0 +1,18 @@
package product
import (
"github.com/dungnt11/todoms_golang/internal/controllers"
"github.com/gin-gonic/gin"
)
// InitProductRoutes khởi tạo các routes cho product
func InitProductRoutes(router *gin.RouterGroup, productController controllers.IProductController) {
productRoutes := router.Group("/products")
{
productRoutes.POST("", productController.CreateProduct)
productRoutes.GET("", productController.GetAllProducts)
productRoutes.GET("/:id", productController.GetProduct)
productRoutes.PUT("/:id", productController.UpdateProduct)
productRoutes.DELETE("/:id", productController.DeleteProduct)
}
}

View File

@@ -0,0 +1,20 @@
package routers
import (
"github.com/dungnt11/todoms_golang/internal/controllers"
"github.com/dungnt11/todoms_golang/internal/routers/product"
"github.com/dungnt11/todoms_golang/internal/routers/user"
"github.com/gin-gonic/gin"
)
// InitRouters khởi tạo tất cả các routers
func InitRouters(r *gin.Engine, controllers *controllers.Controllers) {
// API v1
apiV1 := r.Group("/api/v1")
// Khởi tạo các routes
user.InitUserRoutes(apiV1, controllers.UserController)
product.InitProductRoutes(apiV1, controllers.ProductController)
// Các routes khác có thể được thêm vào đây
}

View File

@@ -0,0 +1,17 @@
package user
import (
"github.com/dungnt11/todoms_golang/internal/controllers"
"github.com/gin-gonic/gin"
)
// InitUserRoutes khởi tạo các routes liên quan đến user
func InitUserRoutes(router *gin.RouterGroup, userController controllers.IUserController) {
userGroup := router.Group("/users")
{
userGroup.POST("/register", userController.Register)
userGroup.POST("/login", userController.Login)
userGroup.GET("/profile", userController.GetProfile)
userGroup.PUT("/profile", userController.UpdateProfile)
}
}

View File

@@ -0,0 +1,22 @@
package services
import "github.com/gin-gonic/gin"
// IUserService định nghĩa interface cho UserService
type IUserService interface {
Register(c *gin.Context) (map[string]interface{}, error)
Login(c *gin.Context) (map[string]interface{}, error)
GetProfile(userID uint) (map[string]interface{}, error)
UpdateProfile(userID uint, data map[string]interface{}) (map[string]interface{}, error)
}
// IProductService định nghĩa interface cho ProductService
type IProductService interface {
CreateProduct(c *gin.Context) (map[string]interface{}, error)
GetProduct(id uint) (map[string]interface{}, error)
GetAllProducts() (map[string]interface{}, error)
UpdateProduct(id uint, c *gin.Context) (map[string]interface{}, error)
DeleteProduct(id uint) (map[string]interface{}, error)
}
// Các interface khác có thể được thêm vào đây khi cần thiết

View File

@@ -0,0 +1,123 @@
package services
import (
"errors"
"github.com/dungnt11/todoms_golang/internal/models"
"github.com/dungnt11/todoms_golang/internal/repositories"
"github.com/gin-gonic/gin"
)
// ProductService triển khai IProductService
type ProductService struct {
productRepo repositories.IProductRepository
}
// NewProductService tạo một instance mới của ProductService
func NewProductService(productRepo repositories.IProductRepository) *ProductService {
return &ProductService{
productRepo: productRepo,
}
}
// CreateProduct tạo một sản phẩm mới
func (s *ProductService) CreateProduct(c *gin.Context) (map[string]interface{}, error) {
var product models.Product
if err := c.ShouldBindJSON(&product); err != nil {
return nil, err
}
if product.Name == "" {
return nil, errors.New("tên sản phẩm không được để trống")
}
if product.Price <= 0 {
return nil, errors.New("giá sản phẩm phải lớn hơn 0")
}
if err := s.productRepo.Create(&product); err != nil {
return nil, err
}
return map[string]interface{}{
"message": "tạo sản phẩm thành công",
"product": product,
}, nil
}
// GetProduct lấy thông tin sản phẩm theo ID
func (s *ProductService) GetProduct(id uint) (map[string]interface{}, error) {
product, err := s.productRepo.FindByID(id)
if err != nil {
return nil, errors.New("không tìm thấy sản phẩm")
}
return map[string]interface{}{
"product": product,
}, nil
}
// GetAllProducts lấy tất cả sản phẩm
func (s *ProductService) GetAllProducts() (map[string]interface{}, error) {
products, err := s.productRepo.FindAll()
if err != nil {
return nil, err
}
return map[string]interface{}{
"products": products,
}, nil
}
// UpdateProduct cập nhật thông tin sản phẩm
func (s *ProductService) UpdateProduct(id uint, c *gin.Context) (map[string]interface{}, error) {
product, err := s.productRepo.FindByID(id)
if err != nil {
return nil, errors.New("không tìm thấy sản phẩm")
}
var updatedProduct models.Product
if err := c.ShouldBindJSON(&updatedProduct); err != nil {
return nil, err
}
// Cập nhật thông tin
if updatedProduct.Name != "" {
product.Name = updatedProduct.Name
}
if updatedProduct.Description != "" {
product.Description = updatedProduct.Description
}
if updatedProduct.Price > 0 {
product.Price = updatedProduct.Price
}
if updatedProduct.Quantity >= 0 {
product.Quantity = updatedProduct.Quantity
}
if err := s.productRepo.Update(product); err != nil {
return nil, err
}
return map[string]interface{}{
"message": "cập nhật sản phẩm thành công",
"product": product,
}, nil
}
// DeleteProduct xóa sản phẩm theo ID
func (s *ProductService) DeleteProduct(id uint) (map[string]interface{}, error) {
// Kiểm tra sản phẩm tồn tại
_, err := s.productRepo.FindByID(id)
if err != nil {
return nil, errors.New("không tìm thấy sản phẩm")
}
if err := s.productRepo.Delete(id); err != nil {
return nil, err
}
return map[string]interface{}{
"message": "xóa sản phẩm thành công",
}, nil
}

View File

@@ -0,0 +1,118 @@
package services
import (
"errors"
"github.com/dungnt11/todoms_golang/internal/models"
"github.com/dungnt11/todoms_golang/internal/repositories"
"github.com/gin-gonic/gin"
)
// UserService triển khai IUserService
type UserService struct {
userRepo repositories.IUserRepository
}
// NewUserService tạo một instance mới của UserService
func NewUserService(userRepo repositories.IUserRepository) *UserService {
return &UserService{
userRepo: userRepo,
}
}
// Register xử lý logic đăng ký người dùng
func (us *UserService) Register(c *gin.Context) (map[string]interface{}, error) {
// Đọc dữ liệu từ request
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
return nil, err
}
// Kiểm tra username đã tồn tại chưa
existingUser, _ := us.userRepo.FindByUsername(user.Username)
if existingUser != nil {
return nil, errors.New("username đã được sử dụng")
}
// Lưu vào database thông qua repository
err := us.userRepo.Create(&user)
if err != nil {
return nil, err
}
// Trả về kết quả
return map[string]interface{}{
"message": "Đăng ký thành công",
"user_id": user.ID,
}, nil
}
// Login xử lý logic đăng nhập
func (us *UserService) Login(c *gin.Context) (map[string]interface{}, error) {
// Đọc dữ liệu từ request
var loginData struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&loginData); err != nil {
return nil, err
}
// Tìm user theo username
user, err := us.userRepo.FindByUsername(loginData.Username)
if err != nil {
return nil, errors.New("username hoặc mật khẩu không đúng")
}
// Kiểm tra mật khẩu (giả định)
if user.Password != loginData.Password {
return nil, errors.New("username hoặc mật khẩu không đúng")
}
// Trả về kết quả
return map[string]interface{}{
"message": "Đăng nhập thành công",
"user_id": user.ID,
"token": "jwt_token_here", // Trong thực tế, bạn sẽ tạo JWT token
}, nil
}
// GetProfile lấy thông tin profile của người dùng
func (us *UserService) GetProfile(userID uint) (map[string]interface{}, error) {
// Tìm user theo ID
user, err := us.userRepo.FindByID(userID)
if err != nil {
return nil, errors.New("không tìm thấy người dùng")
}
// Trả về kết quả
return map[string]interface{}{
"user": user,
}, nil
}
// UpdateProfile cập nhật thông tin profile của người dùng
func (us *UserService) UpdateProfile(userID uint, data map[string]interface{}) (map[string]interface{}, error) {
// Tìm user theo ID
user, err := us.userRepo.FindByID(userID)
if err != nil {
return nil, errors.New("không tìm thấy người dùng")
}
// Cập nhật thông tin (giả định)
if name, ok := data["name"].(string); ok {
user.Name = name
}
// Lưu vào database
err = us.userRepo.Update(user)
if err != nil {
return nil, err
}
// Trả về kết quả
return map[string]interface{}{
"message": "Cập nhật thành công",
"user": user,
}, nil
}

17
internal/wire/injector.go Normal file
View File

@@ -0,0 +1,17 @@
//go:build wireinject
// +build wireinject
package wire
import (
"github.com/dungnt11/todoms_golang/internal/controllers"
"github.com/google/wire"
)
// InitializeControllers khởi tạo tất cả các controllers
func InitializeControllers() (*controllers.Controllers, error) {
wire.Build(
AppSet,
)
return nil, nil
}

49
internal/wire/wire.go Normal file
View File

@@ -0,0 +1,49 @@
// Package wire chứa các định nghĩa cho dependency injection sử dụng Google Wire
package wire
import (
"github.com/dungnt11/todoms_golang/global"
"github.com/dungnt11/todoms_golang/internal/controllers"
"github.com/dungnt11/todoms_golang/internal/repositories"
"github.com/dungnt11/todoms_golang/internal/services"
"github.com/google/wire"
"gorm.io/gorm"
)
// RepositorySet là tập hợp các provider cho repositories
var RepositorySet = wire.NewSet(
repositories.NewUserRepository,
wire.Bind(new(repositories.IUserRepository), new(*repositories.UserRepository)),
repositories.NewProductRepository,
wire.Bind(new(repositories.IProductRepository), new(*repositories.ProductRepository)),
)
// ServiceSet là tập hợp các provider cho services
var ServiceSet = wire.NewSet(
services.NewUserService,
wire.Bind(new(services.IUserService), new(*services.UserService)),
services.NewProductService,
wire.Bind(new(services.IProductService), new(*services.ProductService)),
)
// ControllerSet là tập hợp các provider cho controllers
var ControllerSet = wire.NewSet(
controllers.NewUserController,
wire.Bind(new(controllers.IUserController), new(*controllers.UserController)),
controllers.NewProductController,
wire.Bind(new(controllers.IProductController), new(*controllers.ProductController)),
controllers.NewControllers,
)
// ProvideDB cung cấp instance của *gorm.DB
func ProvideDB() *gorm.DB {
return global.Mdb
}
// AppSet là tập hợp tất cả các provider
var AppSet = wire.NewSet(
RepositorySet,
ServiceSet,
ControllerSet,
ProvideDB,
)

28
internal/wire/wire_gen.go Normal file
View File

@@ -0,0 +1,28 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package wire
import (
"github.com/dungnt11/todoms_golang/internal/controllers"
"github.com/dungnt11/todoms_golang/internal/repositories"
"github.com/dungnt11/todoms_golang/internal/services"
)
// Injectors from injector.go:
// InitializeControllers khởi tạo tất cả các controllers
func InitializeControllers() (*controllers.Controllers, error) {
db := ProvideDB()
userRepository := repositories.NewUserRepository(db)
userService := services.NewUserService(userRepository)
userController := controllers.NewUserController(userService)
productRepository := repositories.NewProductRepository(db)
productService := services.NewProductService(productRepository)
productController := controllers.NewProductController(productService)
controllersControllers := controllers.NewControllers(userController, productController)
return controllersControllers, nil
}