diff --git a/config/connection.go b/config/connection.go index 736f67e..d8f9888 100644 --- a/config/connection.go +++ b/config/connection.go @@ -51,6 +51,7 @@ func InitDatabase() { } err = DB.AutoMigrate( + &domain.Point{}, &domain.User{}, &domain.UserRole{}, &domain.UserPin{}, diff --git a/domain/initialcoint.go b/domain/initialcoint.go new file mode 100644 index 0000000..02e142d --- /dev/null +++ b/domain/initialcoint.go @@ -0,0 +1,11 @@ +package domain + +import "time" + +type Point struct { + ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` + CoinName string `gorm:"not null" json:"coin_name"` + ValuePerUnit float64 `gorm:"not null" json:"value_perunit"` + CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` + UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` +} diff --git a/dto/initialcoint.go b/dto/initialcoint.go new file mode 100644 index 0000000..7c2c0ef --- /dev/null +++ b/dto/initialcoint.go @@ -0,0 +1,48 @@ +package dto + +import "github.com/go-playground/validator/v10" + +type PointResponse struct { + ID string `json:"id"` + CoinName string `json:"coin_name"` + ValuePerUnit float64 `json:"value_perunit"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` +} + +func NewPointResponse(id, coinName string, valuePerUnit float64, createdAt, updatedAt string) PointResponse { + return PointResponse{ + ID: id, + CoinName: coinName, + ValuePerUnit: valuePerUnit, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } +} + +type PointRequest struct { + CoinName string `json:"coin_name" validate:"required"` + ValuePerUnit float64 `json:"value_perunit" validate:"required,gt=0"` +} + +func NewPointRequest(coinName string, valuePerUnit float64) PointRequest { + return PointRequest{ + CoinName: coinName, + ValuePerUnit: valuePerUnit, + } +} + +func (p *PointRequest) Validate() error { + validate := validator.New() + return validate.Struct(p) +} + +type PointUpdateDTO struct { + CoinName string `json:"coin_name" validate:"required"` + ValuePerUnit float64 `json:"value_perunit" validate:"required,gt=0"` +} + +func (p *PointUpdateDTO) Validate() error { + validate := validator.New() + return validate.Struct(p) +} \ No newline at end of file diff --git a/internal/api/routes.go b/internal/api/routes.go index 05a8985..eb1377f 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -10,6 +10,13 @@ func AppRouter(app *fiber.App) { // # API Secure app.Use(middleware.APIKeyMiddleware) + // # user initial coint + app.Get("/apirijikid/user/initial-coint", controllers.GetUserInitialCoint) + app.Get("/apirijikid/user/initial-coint/:id", controllers.GetUserInitialCointById) + app.Post("/apirijikid/user/initial-coint", controllers.CreatePoint) + app.Put("/apirijikid/user/initial-coint/:id", controllers.UpdatePoint) + app.Delete("/apirijikid/user/initial-coint/:id", controllers.DeletePoint) + // # role app.Get("/apirijikid/roles", controllers.GetAllUserRoles) app.Get("/apirijikid/role/:id", controllers.GetUserRoleByID) diff --git a/internal/controllers/initialcoint.go b/internal/controllers/initialcoint.go new file mode 100644 index 0000000..03a13f3 --- /dev/null +++ b/internal/controllers/initialcoint.go @@ -0,0 +1,199 @@ +package controllers + +import ( + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/services" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func GetUserInitialCoint(c *fiber.Ctx) error { + points, err := services.GetPoints() + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to fetch points", + nil, + )) + } + + var pointResponses []dto.PointResponse + for _, point := range points { + pointResponses = append(pointResponses, dto.PointResponse{ + ID: point.ID, + CoinName: point.CoinName, + ValuePerUnit: point.ValuePerUnit, + CreatedAt: utils.FormatDateToIndonesianFormat(point.CreatedAt), + UpdatedAt: utils.FormatDateToIndonesianFormat(point.UpdatedAt), + }) + } + + if len(pointResponses) == 0 { + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Points successfully displayed but no data", + nil, + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Points fetched successfully", + struct { + Points []dto.PointResponse `json:"points"` + }{ + Points: pointResponses, + }, + )) + +} + +func GetUserInitialCointById(c *fiber.Ctx) error { + id := c.Params("id") + + point, err := services.GetPointByID(id) + if err != nil { + if err.Error() == "point not found" { + return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( + fiber.StatusNotFound, + "Point not found", + nil, + )) + } + + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to fetch point", + nil, + )) + } + + pointResponse := dto.PointResponse{ + ID: point.ID, + CoinName: point.CoinName, + ValuePerUnit: point.ValuePerUnit, + CreatedAt: utils.FormatDateToIndonesianFormat(point.CreatedAt), + UpdatedAt: utils.FormatDateToIndonesianFormat(point.UpdatedAt), + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Point fetched successfully", + pointResponse, + )) +} + +func CreatePoint(c *fiber.Ctx) error { + var pointInput dto.PointRequest + + if err := c.BodyParser(&pointInput); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid input data", + nil, + )) + } + + if err := pointInput.Validate(); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Validation failed: "+err.Error(), + nil, + )) + } + + newPoint, err := services.CreatePoint(pointInput.CoinName, pointInput.ValuePerUnit) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to create point", + nil, + )) + } + + pointResponse := dto.NewPointResponse( + newPoint.ID, + newPoint.CoinName, + newPoint.ValuePerUnit, + utils.FormatDateToIndonesianFormat(newPoint.CreatedAt), + utils.FormatDateToIndonesianFormat(newPoint.UpdatedAt), + ) + + return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( + fiber.StatusCreated, + "Point created successfully", + struct { + Point dto.PointResponse `json:"point"` + }{ + Point: pointResponse, + }, + )) +} + +func UpdatePoint(c *fiber.Ctx) error { + id := c.Params("id") + + var pointInput dto.PointUpdateDTO + + if err := c.BodyParser(&pointInput); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid input data", + nil, + )) + } + + if err := pointInput.Validate(); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Validation failed: "+err.Error(), + nil, + )) + } + + updatedPoint, err := services.UpdatePoint(id, pointInput.CoinName, pointInput.ValuePerUnit) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to update point", + nil, + )) + } + + pointResponse := dto.NewPointResponse( + updatedPoint.ID, + updatedPoint.CoinName, + updatedPoint.ValuePerUnit, + utils.FormatDateToIndonesianFormat(updatedPoint.CreatedAt), + utils.FormatDateToIndonesianFormat(updatedPoint.UpdatedAt), + ) + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Point updated successfully", + struct { + Point dto.PointResponse `json:"point"` + }{ + Point: pointResponse, + }, + )) +} + +func DeletePoint(c *fiber.Ctx) error { + id := c.Params("id") + + err := services.DeletePoint(id) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to delete point", + nil, + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Point deleted successfully", + nil, + )) +} diff --git a/internal/repositories/initialcoint.go b/internal/repositories/initialcoint.go new file mode 100644 index 0000000..cbf308a --- /dev/null +++ b/internal/repositories/initialcoint.go @@ -0,0 +1,44 @@ +package repositories + +import ( + "github.com/pahmiudahgede/senggoldong/config" + "github.com/pahmiudahgede/senggoldong/domain" +) + +func GetPoints() ([]domain.Point, error) { + var points []domain.Point + if err := config.DB.Find(&points).Error; err != nil { + return nil, err + } + return points, nil +} + +func GetPointByID(id string) (domain.Point, error) { + var point domain.Point + if err := config.DB.Where("id = ?", id).First(&point).Error; err != nil { + return point, err + } + return point, nil +} + +func CreatePoint(point *domain.Point) error { + + if err := config.DB.Create(point).Error; err != nil { + return err + } + return nil +} + +func UpdatePoint(point *domain.Point) error { + if err := config.DB.Save(point).Error; err != nil { + return err + } + return nil +} + +func DeletePoint(id string) error { + if err := config.DB.Where("id = ?", id).Delete(&domain.Point{}).Error; err != nil { + return err + } + return nil +} \ No newline at end of file diff --git a/internal/services/initialcoint.go b/internal/services/initialcoint.go new file mode 100644 index 0000000..ccfe59e --- /dev/null +++ b/internal/services/initialcoint.go @@ -0,0 +1,65 @@ +package services + +import ( + "errors" + + "github.com/pahmiudahgede/senggoldong/domain" + "github.com/pahmiudahgede/senggoldong/internal/repositories" +) + +func GetPoints() ([]domain.Point, error) { + return repositories.GetPoints() +} + +func GetPointByID(id string) (domain.Point, error) { + point, err := repositories.GetPointByID(id) + if err != nil { + return domain.Point{}, errors.New("point not found") + } + return point, nil +} + +func CreatePoint(coinName string, valuePerUnit float64) (domain.Point, error) { + + newPoint := domain.Point{ + CoinName: coinName, + ValuePerUnit: valuePerUnit, + } + + if err := repositories.CreatePoint(&newPoint); err != nil { + return domain.Point{}, err + } + + return newPoint, nil +} + +func UpdatePoint(id, coinName string, valuePerUnit float64) (domain.Point, error) { + + point, err := repositories.GetPointByID(id) + if err != nil { + return domain.Point{}, errors.New("point not found") + } + + point.CoinName = coinName + point.ValuePerUnit = valuePerUnit + + if err := repositories.UpdatePoint(&point); err != nil { + return domain.Point{}, err + } + + return point, nil +} + +func DeletePoint(id string) error { + + _, err := repositories.GetPointByID(id) + if err != nil { + return errors.New("point not found") + } + + if err := repositories.DeletePoint(id); err != nil { + return err + } + + return nil +}