refact: refact code for optimization
This commit is contained in:
parent
dd7fca697d
commit
83d6a09600
|
@ -1,112 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/pahmiudahgede/senggoldong/domain"
|
|
||||||
"gorm.io/driver/postgres"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DB *gorm.DB
|
|
||||||
DBHost string
|
|
||||||
DBPort string
|
|
||||||
DBName string
|
|
||||||
DBUser string
|
|
||||||
DBPassword string
|
|
||||||
|
|
||||||
APIKey string
|
|
||||||
ServerHost string
|
|
||||||
ServerPort string
|
|
||||||
|
|
||||||
RedisClient *redis.Client
|
|
||||||
RedisHost string
|
|
||||||
RedisPort string
|
|
||||||
RedisPassword string
|
|
||||||
RedisDB int
|
|
||||||
)
|
|
||||||
|
|
||||||
func Context() context.Context {
|
|
||||||
return context.Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitConfig() {
|
|
||||||
ServerHost = os.Getenv("SERVER_HOST")
|
|
||||||
ServerPort = os.Getenv("SERVER_PORT")
|
|
||||||
DBHost = os.Getenv("DB_HOST")
|
|
||||||
DBPort = os.Getenv("DB_PORT")
|
|
||||||
DBName = os.Getenv("DB_NAME")
|
|
||||||
DBUser = os.Getenv("DB_USER")
|
|
||||||
DBPassword = os.Getenv("DB_PASSWORD")
|
|
||||||
APIKey = os.Getenv("API_KEY")
|
|
||||||
RedisHost = os.Getenv("REDIS_HOST")
|
|
||||||
RedisPort = os.Getenv("REDIS_PORT")
|
|
||||||
RedisPassword = os.Getenv("REDIS_PASSWORD")
|
|
||||||
RedisDB = 0
|
|
||||||
|
|
||||||
if ServerHost == "" || ServerPort == "" || DBHost == "" || DBPort == "" || DBName == "" || DBUser == "" || DBPassword == "" || APIKey == "" {
|
|
||||||
log.Fatal("Error: environment variables yang dibutuhkan tidak ada")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitDatabase() {
|
|
||||||
InitConfig()
|
|
||||||
|
|
||||||
dsn := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=disable",
|
|
||||||
DBHost, DBPort, DBUser, DBName, DBPassword)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("gagal terhubung ke database: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = DB.AutoMigrate(
|
|
||||||
&domain.Point{},
|
|
||||||
&domain.User{},
|
|
||||||
&domain.UserRole{},
|
|
||||||
&domain.UserPin{},
|
|
||||||
&domain.MenuAccess{},
|
|
||||||
&domain.PlatformHandle{},
|
|
||||||
&domain.Address{},
|
|
||||||
&domain.Article{},
|
|
||||||
&domain.TrashCategory{},
|
|
||||||
&domain.TrashDetail{},
|
|
||||||
&domain.Banner{},
|
|
||||||
&domain.CoverageArea{},
|
|
||||||
&domain.CoverageDistric{},
|
|
||||||
&domain.CoverageSubdistrict{},
|
|
||||||
&domain.RequestPickup{},
|
|
||||||
&domain.RequestItem{},
|
|
||||||
&domain.Product{},
|
|
||||||
&domain.ProductImage{},
|
|
||||||
&domain.Store{},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error: Failed to auto migrate domain:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Koneksi ke database berhasil dan migrasi dilakukan")
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitRedis() {
|
|
||||||
InitConfig()
|
|
||||||
|
|
||||||
RedisClient = redis.NewClient(&redis.Options{
|
|
||||||
Addr: fmt.Sprintf("%s:%s", RedisHost, RedisPort),
|
|
||||||
Password: RedisPassword,
|
|
||||||
DB: RedisDB,
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := RedisClient.Ping(context.Background()).Result()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Gagal terhubung ke Redis:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Koneksi ke Redis berhasil")
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/pahmiudahgede/senggoldong/domain"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DB *gorm.DB
|
||||||
|
|
||||||
|
func InitDatabase() {
|
||||||
|
|
||||||
|
InitConfig()
|
||||||
|
|
||||||
|
dsn := fmt.Sprintf(
|
||||||
|
"host=%s port=%s user=%s dbname=%s password=%s sslmode=disable",
|
||||||
|
DBHost, DBPort, DBUser, DBName, DBPassword,
|
||||||
|
)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: Gagal terhubung ke database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DB.AutoMigrate(
|
||||||
|
&domain.Point{},
|
||||||
|
&domain.User{},
|
||||||
|
&domain.UserRole{},
|
||||||
|
&domain.UserPin{},
|
||||||
|
&domain.MenuAccess{},
|
||||||
|
&domain.PlatformHandle{},
|
||||||
|
&domain.Address{},
|
||||||
|
&domain.Article{},
|
||||||
|
&domain.TrashCategory{},
|
||||||
|
&domain.TrashDetail{},
|
||||||
|
&domain.Banner{},
|
||||||
|
&domain.CoverageArea{},
|
||||||
|
&domain.CoverageDistric{},
|
||||||
|
&domain.CoverageSubdistrict{},
|
||||||
|
&domain.RequestPickup{},
|
||||||
|
&domain.RequestItem{},
|
||||||
|
&domain.Product{},
|
||||||
|
&domain.ProductImage{},
|
||||||
|
&domain.Store{},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: Gagal melakukan migrasi schema: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Koneksi ke database berhasil dan migrasi schema juga berhasil")
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DBHost string
|
||||||
|
DBPort string
|
||||||
|
DBName string
|
||||||
|
DBUser string
|
||||||
|
DBPassword string
|
||||||
|
|
||||||
|
RedisHost string
|
||||||
|
RedisPort string
|
||||||
|
RedisPassword string
|
||||||
|
RedisDB int
|
||||||
|
|
||||||
|
ServerHost string
|
||||||
|
ServerPort string
|
||||||
|
APIKey string
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitConfig() {
|
||||||
|
|
||||||
|
ServerHost = os.Getenv("SERVER_HOST")
|
||||||
|
ServerPort = os.Getenv("SERVER_PORT")
|
||||||
|
DBHost = os.Getenv("DB_HOST")
|
||||||
|
DBPort = os.Getenv("DB_PORT")
|
||||||
|
DBName = os.Getenv("DB_NAME")
|
||||||
|
DBUser = os.Getenv("DB_USER")
|
||||||
|
DBPassword = os.Getenv("DB_PASSWORD")
|
||||||
|
APIKey = os.Getenv("API_KEY")
|
||||||
|
|
||||||
|
RedisHost = os.Getenv("REDIS_HOST")
|
||||||
|
RedisPort = os.Getenv("REDIS_PORT")
|
||||||
|
RedisPassword = os.Getenv("REDIS_PASSWORD")
|
||||||
|
RedisDB = 0
|
||||||
|
|
||||||
|
if ServerHost == "" || ServerPort == "" || DBHost == "" || DBPort == "" || DBName == "" || DBUser == "" || DBPassword == "" || APIKey == "" {
|
||||||
|
log.Fatal("Error: Beberapa environment variables tidak ditemukan.")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var RedisClient *redis.Client
|
||||||
|
|
||||||
|
func Context() context.Context {
|
||||||
|
return context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitRedis() {
|
||||||
|
|
||||||
|
InitConfig()
|
||||||
|
|
||||||
|
RedisClient = redis.NewClient(&redis.Options{
|
||||||
|
Addr: fmt.Sprintf("%s:%s", RedisHost, RedisPort),
|
||||||
|
Password: RedisPassword,
|
||||||
|
DB: RedisDB,
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := RedisClient.Ping(context.Background()).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: Gagal terhubung ke Redis: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Koneksi ke Redis berhasil.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFromCache(key string) (string, error) {
|
||||||
|
val, err := RedisClient.Get(Context(), key).Result()
|
||||||
|
if err == redis.Nil {
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
} else if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetToCache(key string, value string, ttl time.Duration) error {
|
||||||
|
err := RedisClient.Set(Context(), key, value, ttl).Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFromCache(key string) error {
|
||||||
|
err := RedisClient.Del(Context(), key).Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
package dto
|
package dto
|
||||||
|
|
||||||
import "github.com/go-playground/validator/v10"
|
|
||||||
|
|
||||||
type PointResponse struct {
|
type PointResponse struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
CoinName string `json:"coin_name"`
|
CoinName string `json:"coin_name"`
|
||||||
|
@ -10,39 +8,12 @@ type PointResponse struct {
|
||||||
UpdatedAt string `json:"updatedAt"`
|
UpdatedAt string `json:"updatedAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPointResponse(id, coinName string, valuePerUnit float64, createdAt, updatedAt string) PointResponse {
|
type PointCreateRequest struct {
|
||||||
return PointResponse{
|
|
||||||
ID: id,
|
|
||||||
CoinName: coinName,
|
|
||||||
ValuePerUnit: valuePerUnit,
|
|
||||||
CreatedAt: createdAt,
|
|
||||||
UpdatedAt: updatedAt,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PointRequest struct {
|
|
||||||
CoinName string `json:"coin_name" validate:"required"`
|
CoinName string `json:"coin_name" validate:"required"`
|
||||||
ValuePerUnit float64 `json:"value_perunit" validate:"required,gt=0"`
|
ValuePerUnit float64 `json:"value_perunit" validate:"required,gt=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPointRequest(coinName string, valuePerUnit float64) PointRequest {
|
type PointUpdateRequest struct {
|
||||||
return PointRequest{
|
CoinName string `json:"coin_name,omitempty"`
|
||||||
CoinName: coinName,
|
ValuePerUnit float64 `json:"value_perunit,omitempty"`
|
||||||
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)
|
|
||||||
}
|
}
|
|
@ -4,22 +4,30 @@ import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/pahmiudahgede/senggoldong/internal/controllers"
|
"github.com/pahmiudahgede/senggoldong/internal/controllers"
|
||||||
"github.com/pahmiudahgede/senggoldong/internal/middleware"
|
"github.com/pahmiudahgede/senggoldong/internal/middleware"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/internal/services"
|
||||||
"github.com/pahmiudahgede/senggoldong/utils"
|
"github.com/pahmiudahgede/senggoldong/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AppRouter(app *fiber.App) {
|
func AppRouter(app *fiber.App) {
|
||||||
|
// # init
|
||||||
|
pointRepo := repositories.NewPointRepository()
|
||||||
|
pointService := services.NewPointService(pointRepo)
|
||||||
|
pointController := controllers.NewPointController(pointService)
|
||||||
|
|
||||||
// # api group domain endpoint #
|
// # api group domain endpoint #
|
||||||
api := app.Group("/apirijikid")
|
api := app.Group("/apirijikid")
|
||||||
|
|
||||||
// # API Secure #
|
// # API Secure #
|
||||||
api.Use(middleware.APIKeyMiddleware)
|
api.Use(middleware.APIKeyMiddleware)
|
||||||
|
api.Use(middleware.RateLimitMiddleware)
|
||||||
|
|
||||||
// # user initial coint #
|
// # user initial coint #
|
||||||
api.Get("/user/initial-coint", controllers.GetUserInitialCoint)
|
api.Get("/user/initial-coint", pointController.GetAllPoints)
|
||||||
api.Get("/user/initial-coint/:id", controllers.GetUserInitialCointById)
|
api.Get("/user/initial-coint/:id", pointController.GetPointByID)
|
||||||
api.Post("/user/initial-coint", middleware.RoleRequired(utils.RoleAdministrator), controllers.CreatePoint)
|
api.Post("/user/initial-coint", middleware.RoleRequired(utils.RoleAdministrator), pointController.CreatePoint)
|
||||||
api.Put("/user/initial-coint/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.UpdatePoint)
|
api.Put("/user/initial-coint/:id", middleware.RoleRequired(utils.RoleAdministrator), pointController.UpdatePoint)
|
||||||
api.Delete("/user/initial-coint/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.DeletePoint)
|
api.Delete("/user/initial-coint/:id", middleware.RoleRequired(utils.RoleAdministrator), pointController.DeletePoint)
|
||||||
|
|
||||||
//# coverage area #
|
//# coverage area #
|
||||||
api.Get("/coverage-areas", controllers.GetCoverageAreas)
|
api.Get("/coverage-areas", controllers.GetCoverageAreas)
|
||||||
|
|
|
@ -7,183 +7,116 @@ import (
|
||||||
"github.com/pahmiudahgede/senggoldong/utils"
|
"github.com/pahmiudahgede/senggoldong/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetUserInitialCoint(c *fiber.Ctx) error {
|
type PointController struct {
|
||||||
points, err := services.GetPoints()
|
service *services.PointService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPointController(service *services.PointService) *PointController {
|
||||||
|
return &PointController{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *PointController) GetAllPoints(c *fiber.Ctx) error {
|
||||||
|
points, err := pc.service.GetAllPoints()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse(
|
||||||
fiber.StatusInternalServerError,
|
fiber.StatusInternalServerError,
|
||||||
"Failed to fetch points",
|
"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(
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
fiber.StatusOK,
|
fiber.StatusOK,
|
||||||
"Points fetched successfully",
|
"Points fetched successfully",
|
||||||
pointResponses,
|
points,
|
||||||
))
|
))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserInitialCointById(c *fiber.Ctx) error {
|
func (pc *PointController) GetPointByID(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
|
point, err := pc.service.GetPointByID(id)
|
||||||
point, err := services.GetPointByID(id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "point not found" {
|
return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse(
|
||||||
return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse(
|
fiber.StatusNotFound,
|
||||||
fiber.StatusNotFound,
|
"Point not found",
|
||||||
"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(
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
fiber.StatusOK,
|
fiber.StatusOK,
|
||||||
"Point fetched successfully",
|
"Point fetched successfully",
|
||||||
pointResponse,
|
point,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePoint(c *fiber.Ctx) error {
|
func (pc *PointController) CreatePoint(c *fiber.Ctx) error {
|
||||||
var pointInput dto.PointRequest
|
var request dto.PointCreateRequest
|
||||||
|
|
||||||
if err := c.BodyParser(&pointInput); err != nil {
|
if err := c.BodyParser(&request); err != nil {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
|
return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse(
|
||||||
fiber.StatusBadRequest,
|
fiber.StatusBadRequest,
|
||||||
"Invalid input data",
|
"Invalid request body",
|
||||||
nil,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pointInput.Validate(); err != nil {
|
point, err := pc.service.CreatePoint(&request)
|
||||||
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 {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse(
|
||||||
fiber.StatusInternalServerError,
|
fiber.StatusInternalServerError,
|
||||||
"Failed to create point",
|
err.Error(),
|
||||||
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(
|
return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse(
|
||||||
fiber.StatusCreated,
|
fiber.StatusCreated,
|
||||||
"Point created successfully",
|
"Point created successfully",
|
||||||
struct {
|
point,
|
||||||
Point dto.PointResponse `json:"point"`
|
|
||||||
}{
|
|
||||||
Point: pointResponse,
|
|
||||||
},
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdatePoint(c *fiber.Ctx) error {
|
func (pc *PointController) UpdatePoint(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
|
var request dto.PointUpdateRequest
|
||||||
|
|
||||||
var pointInput dto.PointUpdateDTO
|
if err := c.BodyParser(&request); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse(
|
||||||
if err := c.BodyParser(&pointInput); err != nil {
|
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
|
|
||||||
fiber.StatusBadRequest,
|
fiber.StatusBadRequest,
|
||||||
"Invalid input data",
|
"Invalid request body",
|
||||||
nil,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pointInput.Validate(); err != nil {
|
point, err := pc.service.UpdatePoint(id, &request)
|
||||||
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 {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
if err.Error() == "point not found" {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse(
|
||||||
|
fiber.StatusNotFound,
|
||||||
|
"Point not found",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse(
|
||||||
fiber.StatusInternalServerError,
|
fiber.StatusInternalServerError,
|
||||||
"Failed to update point",
|
err.Error(),
|
||||||
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(
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
fiber.StatusOK,
|
fiber.StatusOK,
|
||||||
"Point updated successfully",
|
"Point updated successfully",
|
||||||
struct {
|
point,
|
||||||
Point dto.PointResponse `json:"point"`
|
|
||||||
}{
|
|
||||||
Point: pointResponse,
|
|
||||||
},
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePoint(c *fiber.Ctx) error {
|
func (pc *PointController) DeletePoint(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
|
|
||||||
err := services.DeletePoint(id)
|
err := pc.service.DeletePoint(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
if err.Error() == "point not found" {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse(
|
||||||
|
fiber.StatusNotFound,
|
||||||
|
"Point not found",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse(
|
||||||
fiber.StatusInternalServerError,
|
fiber.StatusInternalServerError,
|
||||||
"Failed to delete point",
|
err.Error(),
|
||||||
nil,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,4 +125,4 @@ func DeletePoint(c *fiber.Ctx) error {
|
||||||
"Point deleted successfully",
|
"Point deleted successfully",
|
||||||
nil,
|
nil,
|
||||||
))
|
))
|
||||||
}
|
}
|
|
@ -1,28 +1,54 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/config"
|
||||||
"github.com/pahmiudahgede/senggoldong/utils"
|
"github.com/pahmiudahgede/senggoldong/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func APIKeyMiddleware(c *fiber.Ctx) error {
|
func APIKeyMiddleware(c *fiber.Ctx) error {
|
||||||
|
|
||||||
apiKey := c.Get("x-api-key")
|
apiKey := c.Get("x-api-key")
|
||||||
|
|
||||||
expectedAPIKey := os.Getenv("API_KEY")
|
expectedAPIKey := os.Getenv("API_KEY")
|
||||||
|
|
||||||
if apiKey != expectedAPIKey {
|
if apiKey != expectedAPIKey {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
response := utils.FormatResponse(
|
|
||||||
fiber.StatusUnauthorized,
|
fiber.StatusUnauthorized,
|
||||||
"Invalid API Key",
|
"Invalid API Key",
|
||||||
nil,
|
nil,
|
||||||
)
|
))
|
||||||
|
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RateLimitMiddleware(c *fiber.Ctx) error {
|
||||||
|
apiKey := c.Get("x-api-key")
|
||||||
|
if apiKey == "" {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusUnauthorized,
|
||||||
|
"API Key is missing",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
rateLimitKey := fmt.Sprintf("rate_limit:%s", apiKey)
|
||||||
|
|
||||||
|
count, _ := config.RedisClient.Incr(ctx, rateLimitKey).Result()
|
||||||
|
if count > 100 {
|
||||||
|
return c.Status(fiber.StatusTooManyRequests).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusTooManyRequests,
|
||||||
|
"Rate limit exceeded",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
config.RedisClient.Expire(ctx, rateLimitKey, time.Minute)
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
|
@ -13,9 +13,18 @@ import (
|
||||||
"github.com/pahmiudahgede/senggoldong/utils"
|
"github.com/pahmiudahgede/senggoldong/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func containsRole(roles []string, role string) bool {
|
||||||
|
for _, r := range roles {
|
||||||
|
if r == role {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func RoleRequired(roles ...string) fiber.Handler {
|
func RoleRequired(roles ...string) fiber.Handler {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
tokenString := c.Get("Authorization")
|
tokenString := strings.TrimPrefix(c.Get("Authorization"), "Bearer ")
|
||||||
if tokenString == "" {
|
if tokenString == "" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
fiber.StatusUnauthorized,
|
fiber.StatusUnauthorized,
|
||||||
|
@ -24,8 +33,6 @@ func RoleRequired(roles ...string) fiber.Handler {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenString = strings.TrimPrefix(tokenString, "Bearer ")
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cachedToken, err := config.RedisClient.Get(ctx, "auth_token:"+tokenString).Result()
|
cachedToken, err := config.RedisClient.Get(ctx, "auth_token:"+tokenString).Result()
|
||||||
if err != nil || cachedToken == "" {
|
if err != nil || cachedToken == "" {
|
||||||
|
@ -63,7 +70,7 @@ func RoleRequired(roles ...string) fiber.Handler {
|
||||||
if !ok || userID == "" {
|
if !ok || userID == "" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
fiber.StatusUnauthorized,
|
fiber.StatusUnauthorized,
|
||||||
"Invalid or missing user ID in token",
|
"Missing or invalid user ID in token",
|
||||||
nil,
|
nil,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -72,7 +79,7 @@ func RoleRequired(roles ...string) fiber.Handler {
|
||||||
if !ok || role == "" {
|
if !ok || role == "" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
fiber.StatusUnauthorized,
|
fiber.StatusUnauthorized,
|
||||||
"Invalid or missing role in token",
|
"Missing or invalid role in token",
|
||||||
nil,
|
nil,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -80,59 +87,62 @@ func RoleRequired(roles ...string) fiber.Handler {
|
||||||
c.Locals("userID", userID)
|
c.Locals("userID", userID)
|
||||||
c.Locals("role", role)
|
c.Locals("role", role)
|
||||||
|
|
||||||
for _, r := range roles {
|
if !containsRole(roles, role) {
|
||||||
if r == role {
|
return c.Status(fiber.StatusForbidden).JSON(utils.FormatResponse(
|
||||||
return c.Next()
|
fiber.StatusForbidden,
|
||||||
}
|
"You do not have permission to access this resource",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Status(fiber.StatusForbidden).JSON(utils.FormatResponse(
|
return c.Next()
|
||||||
fiber.StatusForbidden,
|
|
||||||
"You do not have permission to access this resource",
|
|
||||||
nil,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthMiddleware(c *fiber.Ctx) error {
|
func AuthMiddleware(c *fiber.Ctx) error {
|
||||||
tokenString := c.Get("Authorization")
|
tokenString := strings.TrimPrefix(c.Get("Authorization"), "Bearer ")
|
||||||
tokenString = strings.TrimPrefix(tokenString, "Bearer ")
|
|
||||||
|
|
||||||
if tokenString == "" {
|
if tokenString == "" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
"message": "Missing or invalid token",
|
fiber.StatusUnauthorized,
|
||||||
})
|
"Missing or invalid token",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cachedToken, err := config.RedisClient.Get(ctx, "auth_token:"+tokenString).Result()
|
cachedToken, err := config.RedisClient.Get(ctx, "auth_token:"+tokenString).Result()
|
||||||
if err != nil || cachedToken == "" {
|
if err != nil || cachedToken == "" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
"message": "Invalid or expired token",
|
fiber.StatusUnauthorized,
|
||||||
})
|
"Invalid or expired token",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
return []byte(os.Getenv("API_KEY")), nil
|
return []byte(os.Getenv("API_KEY")), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil || !token.Valid {
|
if err != nil || !token.Valid {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
"message": "Invalid or expired token",
|
fiber.StatusUnauthorized,
|
||||||
})
|
"Invalid or expired token",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, ok := token.Claims.(jwt.MapClaims)
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
if !ok {
|
if !ok {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse(
|
||||||
"message": "Invalid token claims",
|
fiber.StatusUnauthorized,
|
||||||
})
|
"Invalid token claims",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := claims["sub"].(string)
|
userID := claims["sub"].(string)
|
||||||
c.Locals("userID", userID)
|
c.Locals("userID", userID)
|
||||||
|
|
||||||
config.RedisClient.Expire(ctx, "auth_token:"+tokenString, time.Hour*24).Err()
|
config.RedisClient.Expire(ctx, "auth_token:"+tokenString, time.Hour*24)
|
||||||
|
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
|
@ -1,44 +1,44 @@
|
||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/pahmiudahgede/senggoldong/config"
|
"github.com/pahmiudahgede/senggoldong/config"
|
||||||
"github.com/pahmiudahgede/senggoldong/domain"
|
"github.com/pahmiudahgede/senggoldong/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPoints() ([]domain.Point, error) {
|
type PointRepository struct{}
|
||||||
|
|
||||||
|
func NewPointRepository() *PointRepository {
|
||||||
|
return &PointRepository{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PointRepository) GetAll() ([]domain.Point, error) {
|
||||||
var points []domain.Point
|
var points []domain.Point
|
||||||
if err := config.DB.Find(&points).Error; err != nil {
|
err := config.DB.Find(&points).Error
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to fetch points from database")
|
||||||
}
|
}
|
||||||
return points, nil
|
return points, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPointByID(id string) (domain.Point, error) {
|
func (r *PointRepository) GetByID(id string) (*domain.Point, error) {
|
||||||
var point domain.Point
|
var point domain.Point
|
||||||
if err := config.DB.Where("id = ?", id).First(&point).Error; err != nil {
|
err := config.DB.First(&point, "id = ?", id).Error
|
||||||
return point, err
|
if err != nil {
|
||||||
|
return nil, errors.New("point not found")
|
||||||
}
|
}
|
||||||
return point, nil
|
return &point, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePoint(point *domain.Point) error {
|
func (r *PointRepository) Create(point *domain.Point) error {
|
||||||
|
return config.DB.Create(point).Error
|
||||||
if err := config.DB.Create(point).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdatePoint(point *domain.Point) error {
|
func (r *PointRepository) Update(point *domain.Point) error {
|
||||||
if err := config.DB.Save(point).Error; err != nil {
|
return config.DB.Save(point).Error
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePoint(id string) error {
|
func (r *PointRepository) Delete(point *domain.Point) error {
|
||||||
if err := config.DB.Where("id = ?", id).Delete(&domain.Point{}).Error; err != nil {
|
return config.DB.Delete(point).Error
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
|
@ -1,65 +1,170 @@
|
||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pahmiudahgede/senggoldong/config"
|
||||||
"github.com/pahmiudahgede/senggoldong/domain"
|
"github.com/pahmiudahgede/senggoldong/domain"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/dto"
|
||||||
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPoints() ([]domain.Point, error) {
|
type PointService struct {
|
||||||
return repositories.GetPoints()
|
repo *repositories.PointRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPointByID(id string) (domain.Point, error) {
|
func NewPointService(repo *repositories.PointRepository) *PointService {
|
||||||
point, err := repositories.GetPointByID(id)
|
return &PointService{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PointService) GetAllPoints() ([]dto.PointResponse, error) {
|
||||||
|
ctx := config.Context()
|
||||||
|
|
||||||
|
cacheKey := "points:all"
|
||||||
|
cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result()
|
||||||
|
if err == nil && cachedData != "" {
|
||||||
|
var cachedPoints []dto.PointResponse
|
||||||
|
if err := json.Unmarshal([]byte(cachedData), &cachedPoints); err == nil {
|
||||||
|
return cachedPoints, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
points, err := s.repo.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Point{}, errors.New("point not found")
|
return nil, err
|
||||||
}
|
}
|
||||||
return point, nil
|
|
||||||
|
var result []dto.PointResponse
|
||||||
|
for _, point := range points {
|
||||||
|
result = append(result, dto.PointResponse{
|
||||||
|
ID: point.ID,
|
||||||
|
CoinName: point.CoinName,
|
||||||
|
ValuePerUnit: point.ValuePerUnit,
|
||||||
|
CreatedAt: utils.FormatDateToIndonesianFormat(point.CreatedAt),
|
||||||
|
UpdatedAt: utils.FormatDateToIndonesianFormat(point.UpdatedAt),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheData, _ := json.Marshal(result)
|
||||||
|
config.RedisClient.Set(ctx, cacheKey, cacheData, time.Minute*5)
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePoint(coinName string, valuePerUnit float64) (domain.Point, error) {
|
func (s *PointService) GetPointByID(id string) (*dto.PointResponse, error) {
|
||||||
|
ctx := config.Context()
|
||||||
|
|
||||||
newPoint := domain.Point{
|
cacheKey := "points:" + id
|
||||||
CoinName: coinName,
|
cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result()
|
||||||
ValuePerUnit: valuePerUnit,
|
if err == nil && cachedData != "" {
|
||||||
|
var cachedPoint dto.PointResponse
|
||||||
|
if err := json.Unmarshal([]byte(cachedData), &cachedPoint); err == nil {
|
||||||
|
return &cachedPoint, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := repositories.CreatePoint(&newPoint); err != nil {
|
point, err := s.repo.GetByID(id)
|
||||||
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 {
|
if err != nil {
|
||||||
return domain.Point{}, errors.New("point not found")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
point.CoinName = coinName
|
result := &dto.PointResponse{
|
||||||
point.ValuePerUnit = valuePerUnit
|
ID: point.ID,
|
||||||
|
CoinName: point.CoinName,
|
||||||
if err := repositories.UpdatePoint(&point); err != nil {
|
ValuePerUnit: point.ValuePerUnit,
|
||||||
return domain.Point{}, err
|
CreatedAt: utils.FormatDateToIndonesianFormat(point.CreatedAt),
|
||||||
|
UpdatedAt: utils.FormatDateToIndonesianFormat(point.UpdatedAt),
|
||||||
}
|
}
|
||||||
|
|
||||||
return point, nil
|
cacheData, _ := json.Marshal(result)
|
||||||
|
config.RedisClient.Set(ctx, cacheKey, cacheData, time.Minute*5)
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePoint(id string) error {
|
func (s *PointService) CreatePoint(request *dto.PointCreateRequest) (*dto.PointResponse, error) {
|
||||||
|
|
||||||
_, err := repositories.GetPointByID(id)
|
if request.CoinName == "" || request.ValuePerUnit <= 0 {
|
||||||
|
return nil, errors.New("invalid input data")
|
||||||
|
}
|
||||||
|
|
||||||
|
newPoint := &domain.Point{
|
||||||
|
CoinName: request.CoinName,
|
||||||
|
ValuePerUnit: request.ValuePerUnit,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.repo.Create(newPoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := config.Context()
|
||||||
|
config.RedisClient.Del(ctx, "points:all")
|
||||||
|
|
||||||
|
response := &dto.PointResponse{
|
||||||
|
ID: newPoint.ID,
|
||||||
|
CoinName: newPoint.CoinName,
|
||||||
|
ValuePerUnit: newPoint.ValuePerUnit,
|
||||||
|
CreatedAt: utils.FormatDateToIndonesianFormat(newPoint.CreatedAt),
|
||||||
|
UpdatedAt: utils.FormatDateToIndonesianFormat(newPoint.UpdatedAt),
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PointService) UpdatePoint(id string, request *dto.PointUpdateRequest) (*dto.PointResponse, error) {
|
||||||
|
|
||||||
|
point, err := s.repo.GetByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("point not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.CoinName != "" {
|
||||||
|
point.CoinName = request.CoinName
|
||||||
|
}
|
||||||
|
if request.ValuePerUnit > 0 {
|
||||||
|
point.ValuePerUnit = request.ValuePerUnit
|
||||||
|
}
|
||||||
|
point.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
err = s.repo.Update(point)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to update point")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := config.Context()
|
||||||
|
config.RedisClient.Del(ctx, "points:all")
|
||||||
|
config.RedisClient.Del(ctx, "points:"+id)
|
||||||
|
|
||||||
|
response := &dto.PointResponse{
|
||||||
|
ID: point.ID,
|
||||||
|
CoinName: point.CoinName,
|
||||||
|
ValuePerUnit: point.ValuePerUnit,
|
||||||
|
CreatedAt: utils.FormatDateToIndonesianFormat(point.CreatedAt),
|
||||||
|
UpdatedAt: utils.FormatDateToIndonesianFormat(point.UpdatedAt),
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PointService) DeletePoint(id string) error {
|
||||||
|
|
||||||
|
point, err := s.repo.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("point not found")
|
return errors.New("point not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := repositories.DeletePoint(id); err != nil {
|
err = s.repo.Delete(point)
|
||||||
return err
|
if err != nil {
|
||||||
|
return errors.New("failed to delete point")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := config.Context()
|
||||||
|
config.RedisClient.Del(ctx, "points:all")
|
||||||
|
config.RedisClient.Del(ctx, "points:"+id)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ type Meta struct {
|
||||||
|
|
||||||
type ApiResponse struct {
|
type ApiResponse struct {
|
||||||
Meta Meta `json:"meta"`
|
Meta Meta `json:"meta"`
|
||||||
Data interface{} `json:"data"`
|
Data interface{} `json:"data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatResponse(statusCode int, message string, data interface{}) ApiResponse {
|
func FormatResponse(statusCode int, message string, data interface{}) ApiResponse {
|
||||||
|
@ -19,3 +19,12 @@ func FormatResponse(statusCode int, message string, data interface{}) ApiRespons
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ErrorResponse(statusCode int, message string) ApiResponse {
|
||||||
|
return ApiResponse{
|
||||||
|
Meta: Meta{
|
||||||
|
StatusCode: statusCode,
|
||||||
|
Message: message,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue