From 822caa81211dda954c1f3e35157d58568bc5eca9 Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Tue, 28 Jan 2025 23:16:33 +0700 Subject: [PATCH] fix and refact: architecture updated and refactored --- .env.example | 22 +- .gitignore | 4 +- cmd/main.go | 17 + config/database.go | 46 +- config/loader.go | 44 -- config/redis.go | 52 +-- config/server.go | 21 + config/setup.go | 17 + domain/Indonesian_territory.go | 30 -- domain/address.go | 18 - domain/article.go | 14 - domain/banner.go | 11 - domain/coveragearea.go | 29 -- domain/initialcoint.go | 11 - domain/menuaccess.go | 14 - domain/platform.go | 7 - domain/product.go | 28 -- domain/request_pickup.go | 24 - domain/role.go | 7 - domain/store.go | 80 ---- domain/trashtype.go | 20 - domain/userpin.go | 11 - dto/address.go | 84 ---- dto/article.go | 38 -- dto/auth_dto.go | 11 + dto/banner.go | 19 - dto/coveragearea.go | 119 ----- dto/initialcoint.go | 29 -- dto/product.go | 93 ---- dto/request_pickup.go | 46 -- dto/store.go | 14 - dto/trashtype.go | 76 ---- dto/user.go | 152 ------- dto/userpin.go | 47 -- dto/validator.go | 9 - internal/api/routes.go | 137 ------ internal/controllers/Indonesian_territory.go | 147 ------- internal/controllers/address.go | 205 --------- internal/controllers/article.go | 122 ------ internal/controllers/auth.go | 294 ------------- internal/controllers/banner.go | 128 ------ internal/controllers/coveragearea.go | 409 ------------------ internal/controllers/initialcoint.go | 123 ------ internal/controllers/product.go | 262 ----------- internal/controllers/request_pickup.go | 203 --------- internal/controllers/role.go | 43 -- internal/controllers/store.go | 70 --- internal/controllers/trashtype.go | 293 ------------- internal/controllers/user.go | 75 ---- internal/controllers/userpin.go | 240 ---------- internal/handler/auth_handler.go | 40 ++ internal/middleware/api_secure.go | 54 --- internal/middleware/auth.go | 148 ------- internal/repositories/Indonesian_territory.go | 205 --------- internal/repositories/address.go | 83 ---- internal/repositories/article.go | 44 -- internal/repositories/auth.go | 176 -------- internal/repositories/auth_repo.go | 27 ++ internal/repositories/banner.go | 44 -- internal/repositories/coveragearea.go | 148 ------- internal/repositories/initialcoint.go | 44 -- internal/repositories/product.go | 108 ----- internal/repositories/request_pickup.go | 64 --- internal/repositories/role.go | 76 ---- internal/repositories/store.go | 24 - internal/repositories/trashtype.go | 81 ---- internal/repositories/user.go | 33 -- internal/repositories/userpin.go | 72 --- internal/services/Indonesian_territory.go | 70 --- internal/services/address.go | 110 ----- internal/services/article.go | 192 -------- internal/services/auth.go | 154 ------- internal/services/auth_service.go | 76 ++++ internal/services/banner.go | 170 -------- internal/services/coveragearea.go | 89 ---- internal/services/initialcoint.go | 170 -------- internal/services/product.go | 208 --------- internal/services/request_pickup.go | 42 -- internal/services/role.go | 24 - internal/services/store.go | 53 --- internal/services/trashtype.go | 85 ---- internal/services/user.go | 71 --- internal/services/userpin.go | 63 --- middleware/api_key.go | 24 + domain/user.go => model/user_model.go | 7 +- presentation/auth_route.go | 26 ++ presentation/main.go | 31 -- test/go.txt | 1 + utils/format_time.go | 9 +- utils/redis_caching.go | 67 +++ utils/response.go | 98 ++++- 91 files changed, 455 insertions(+), 6871 deletions(-) create mode 100644 cmd/main.go delete mode 100644 config/loader.go create mode 100644 config/server.go create mode 100644 config/setup.go delete mode 100644 domain/Indonesian_territory.go delete mode 100644 domain/address.go delete mode 100644 domain/article.go delete mode 100644 domain/banner.go delete mode 100644 domain/coveragearea.go delete mode 100644 domain/initialcoint.go delete mode 100644 domain/menuaccess.go delete mode 100644 domain/platform.go delete mode 100644 domain/product.go delete mode 100644 domain/request_pickup.go delete mode 100644 domain/role.go delete mode 100644 domain/store.go delete mode 100644 domain/trashtype.go delete mode 100644 domain/userpin.go delete mode 100644 dto/address.go delete mode 100644 dto/article.go create mode 100644 dto/auth_dto.go delete mode 100644 dto/banner.go delete mode 100644 dto/coveragearea.go delete mode 100644 dto/initialcoint.go delete mode 100644 dto/product.go delete mode 100644 dto/request_pickup.go delete mode 100644 dto/store.go delete mode 100644 dto/trashtype.go delete mode 100644 dto/user.go delete mode 100644 dto/userpin.go delete mode 100644 dto/validator.go delete mode 100644 internal/api/routes.go delete mode 100644 internal/controllers/Indonesian_territory.go delete mode 100644 internal/controllers/address.go delete mode 100644 internal/controllers/article.go delete mode 100644 internal/controllers/auth.go delete mode 100644 internal/controllers/banner.go delete mode 100644 internal/controllers/coveragearea.go delete mode 100644 internal/controllers/initialcoint.go delete mode 100644 internal/controllers/product.go delete mode 100644 internal/controllers/request_pickup.go delete mode 100644 internal/controllers/role.go delete mode 100644 internal/controllers/store.go delete mode 100644 internal/controllers/trashtype.go delete mode 100644 internal/controllers/user.go delete mode 100644 internal/controllers/userpin.go create mode 100644 internal/handler/auth_handler.go delete mode 100644 internal/middleware/api_secure.go delete mode 100644 internal/middleware/auth.go delete mode 100644 internal/repositories/Indonesian_territory.go delete mode 100644 internal/repositories/address.go delete mode 100644 internal/repositories/article.go delete mode 100644 internal/repositories/auth.go create mode 100644 internal/repositories/auth_repo.go delete mode 100644 internal/repositories/banner.go delete mode 100644 internal/repositories/coveragearea.go delete mode 100644 internal/repositories/initialcoint.go delete mode 100644 internal/repositories/product.go delete mode 100644 internal/repositories/request_pickup.go delete mode 100644 internal/repositories/role.go delete mode 100644 internal/repositories/store.go delete mode 100644 internal/repositories/trashtype.go delete mode 100644 internal/repositories/user.go delete mode 100644 internal/repositories/userpin.go delete mode 100644 internal/services/Indonesian_territory.go delete mode 100644 internal/services/address.go delete mode 100644 internal/services/article.go delete mode 100644 internal/services/auth.go create mode 100644 internal/services/auth_service.go delete mode 100644 internal/services/banner.go delete mode 100644 internal/services/coveragearea.go delete mode 100644 internal/services/initialcoint.go delete mode 100644 internal/services/product.go delete mode 100644 internal/services/request_pickup.go delete mode 100644 internal/services/role.go delete mode 100644 internal/services/store.go delete mode 100644 internal/services/trashtype.go delete mode 100644 internal/services/user.go delete mode 100644 internal/services/userpin.go create mode 100644 middleware/api_key.go rename domain/user.go => model/user_model.go (59%) create mode 100644 presentation/auth_route.go delete mode 100644 presentation/main.go create mode 100644 test/go.txt create mode 100644 utils/redis_caching.go diff --git a/.env.example b/.env.example index 4dfeb60..40797fc 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,19 @@ # SERVER SETTINGS -SERVER_HOST=localhost -SERVER_PORT= # isi listen port anda (bebas) +SERVER_HOST= +SERVER_PORT= # DATABASE SETTINGS -DB_HOST=localhost -DB_PORT=5432 # port default postgres -DB_NAME= # nama_database di postgres -DB_USER= # username yang digunakan di postgres -DB_PASSWORD= # password yang digunakan di postgres +DB_HOST= +DB_PORT= +DB_NAME= +DB_USER= +DB_PASSWORD= -# api keyauth +# REDIS SETTINGS +REDIS_HOST= +REDIS_PORT= +REDIS_PASSWORD= +REDIS_DB= + +# Keyauth API_KEY= diff --git a/.gitignore b/.gitignore index 64ae7f3..58713d7 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,6 @@ go.work go.work.sum # env file -.env \ No newline at end of file +.env +.env.prod +.env.dev \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..c645b7a --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/config" + "github.com/pahmiudahgede/senggoldong/middleware" + "github.com/pahmiudahgede/senggoldong/presentation" +) + +func main() { + config.SetupConfig() + + app := fiber.New() + app.Use(middleware.APIKeyMiddleware) + presentation.AuthRouter(app) + config.StartServer(app) +} diff --git a/config/database.go b/config/database.go index 9d25b23..ffbc685 100644 --- a/config/database.go +++ b/config/database.go @@ -3,54 +3,36 @@ package config import ( "fmt" "log" + "os" - "github.com/pahmiudahgede/senggoldong/domain" + "github.com/pahmiudahgede/senggoldong/model" "gorm.io/driver/postgres" "gorm.io/gorm" ) var DB *gorm.DB -func InitDatabase() { - - InitConfig() +func ConnectDatabase() { dsn := fmt.Sprintf( - "host=%s port=%s user=%s dbname=%s password=%s sslmode=disable", - DBHost, DBPort, DBUser, DBName, DBPassword, + "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable", + os.Getenv("DB_HOST"), + os.Getenv("DB_USER"), + os.Getenv("DB_PASSWORD"), + os.Getenv("DB_NAME"), + os.Getenv("DB_PORT"), ) var err error - DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { - log.Fatalf("Error: Gagal terhubung ke database: %v", err) + log.Fatalf("Error connecting to database: %v", err) } + log.Println("Database connected successfully!") - 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{}, - ) + err = DB.AutoMigrate(&model.User{}) if err != nil { - log.Fatalf("Error: Gagal melakukan migrasi schema: %v", err) + log.Fatalf("Error performing auto-migration: %v", err) } - - log.Println("Koneksi ke database berhasil dan migrasi schema juga berhasil") + log.Println("Database migrated successfully!") } diff --git a/config/loader.go b/config/loader.go deleted file mode 100644 index 7f80e34..0000000 --- a/config/loader.go +++ /dev/null @@ -1,44 +0,0 @@ -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.") - } -} diff --git a/config/redis.go b/config/redis.go index d771094..1d93165 100644 --- a/config/redis.go +++ b/config/redis.go @@ -4,58 +4,24 @@ import ( "context" "fmt" "log" - "time" + "os" "github.com/go-redis/redis/v8" ) var RedisClient *redis.Client +var Ctx = context.Background() -func Context() context.Context { - return context.Background() -} - -func InitRedis() { - - InitConfig() - +func ConnectRedis() { RedisClient = redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%s", RedisHost, RedisPort), - Password: RedisPassword, - DB: RedisDB, + Addr: fmt.Sprintf("%s:%s", os.Getenv("REDIS_HOST"), os.Getenv("REDIS_PORT")), + Password: os.Getenv("REDIS_PASSWORD"), + DB: 0, }) - _, err := RedisClient.Ping(context.Background()).Result() + _, err := RedisClient.Ping(Ctx).Result() if err != nil { - log.Fatalf("Error: Gagal terhubung ke Redis: %v", err) + log.Fatalf("Error connecting to 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 + log.Println("Redis connected successfully!") } diff --git a/config/server.go b/config/server.go new file mode 100644 index 0000000..8fc1592 --- /dev/null +++ b/config/server.go @@ -0,0 +1,21 @@ +package config + +import ( + "fmt" + "log" + "os" + + "github.com/gofiber/fiber/v2" +) + +func StartServer(app *fiber.App) { + host := os.Getenv("SERVER_HOST") + port := os.Getenv("SERVER_PORT") + + address := fmt.Sprintf("%s:%s", host, port) + + log.Printf("Server is running on http://%s", address) + if err := app.Listen(address); err != nil { + log.Fatalf("Error starting server: %v", err) + } +} diff --git a/config/setup.go b/config/setup.go new file mode 100644 index 0000000..e6679a2 --- /dev/null +++ b/config/setup.go @@ -0,0 +1,17 @@ +package config + +import ( + "log" + + "github.com/joho/godotenv" +) + +func SetupConfig() { + err := godotenv.Load(".env.dev") + if err != nil { + log.Fatalf("Error loading .env file: %v", err) + } + + ConnectDatabase() + ConnectRedis() +} diff --git a/domain/Indonesian_territory.go b/domain/Indonesian_territory.go deleted file mode 100644 index 0bea32b..0000000 --- a/domain/Indonesian_territory.go +++ /dev/null @@ -1,30 +0,0 @@ -package domain - -type Province struct { - ID string `json:"id"` - Name string `json:"name"` - ListRegency []Regency `json:"list_regency,omitempty"` -} - -type Regency struct { - ID string `json:"id"` - ProvinceID string `json:"province_id"` - Name string `json:"name"` - Province *Province `json:"province,omitempty"` - ListDistrict []District `json:"list_district,omitempty"` -} - -type District struct { - ID string `json:"id"` - RegencyID string `json:"regency_id"` - Name string `json:"name"` - Regency *Regency `json:"regency,omitempty"` - ListVillage []Village `json:"list_village,omitempty"` -} - -type Village struct { - ID string `json:"id"` - DistrictID string `json:"district_id"` - Name string `json:"name"` - District *District `json:"district,omitempty"` -} diff --git a/domain/address.go b/domain/address.go deleted file mode 100644 index 9d6075a..0000000 --- a/domain/address.go +++ /dev/null @@ -1,18 +0,0 @@ -package domain - -import "time" - -type Address struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` - UserID string `gorm:"not null" json:"userId"` - User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"` - Province string `gorm:"not null" json:"province"` - District string `gorm:"not null" json:"district"` - Subdistrict string `gorm:"not null" json:"subdistrict"` - PostalCode int `gorm:"not null" json:"postalCode"` - Village string `gorm:"not null" json:"village"` - Detail string `gorm:"not null" json:"detail"` - Geography string `gorm:"not null" json:"geography"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/domain/article.go b/domain/article.go deleted file mode 100644 index 1006852..0000000 --- a/domain/article.go +++ /dev/null @@ -1,14 +0,0 @@ -package domain - -import "time" - -type Article struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` - Title string `gorm:"not null" json:"title"` - CoverImage string `gorm:"not null" json:"coverImage"` - Author string `gorm:"not null" json:"author"` - Heading string `gorm:"not null" json:"heading"` - Content string `gorm:"not null" json:"content"` - PublishedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/domain/banner.go b/domain/banner.go deleted file mode 100644 index 50e783d..0000000 --- a/domain/banner.go +++ /dev/null @@ -1,11 +0,0 @@ -package domain - -import "time" - -type Banner struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - BannerName string `gorm:"not null" json:"bannername"` - BannerImage string `gorm:"not null" json:"bannerimage"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/domain/coveragearea.go b/domain/coveragearea.go deleted file mode 100644 index 76fd9c8..0000000 --- a/domain/coveragearea.go +++ /dev/null @@ -1,29 +0,0 @@ -package domain - -import "time" - -type CoverageArea struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - Province string `gorm:"not null" json:"province"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` - CoverageDistrics []CoverageDistric `gorm:"foreignKey:CoverageAreaID" json:"coverage_districs"` -} - -type CoverageDistric struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - CoverageAreaID string `gorm:"not null;constraint:OnDelete:CASCADE;OnUpdate:CASCADE;" json:"coverage_area_id"` - District string `gorm:"not null" json:"district"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` - CoverageSubdistricts []CoverageSubdistrict `gorm:"foreignKey:CoverageDistrictId" json:"subdistricts"` -} - -type CoverageSubdistrict struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - CoverageAreaID string `gorm:"not null" json:"coverage_area_id"` - CoverageDistrictId string `gorm:"not null;constraint:OnDelete:CASCADE;OnUpdate:CASCADE;" json:"coverage_district_id"` - Subdistrict string `gorm:"not null" json:"subdistrict"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/domain/initialcoint.go b/domain/initialcoint.go deleted file mode 100644 index 02e142d..0000000 --- a/domain/initialcoint.go +++ /dev/null @@ -1,11 +0,0 @@ -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/domain/menuaccess.go b/domain/menuaccess.go deleted file mode 100644 index b5d2f42..0000000 --- a/domain/menuaccess.go +++ /dev/null @@ -1,14 +0,0 @@ -package domain - -import "time" - -type MenuAccess struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` - RoleID string `gorm:"not null" json:"roleId"` - Role UserRole `gorm:"foreignKey:RoleID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"role"` - MenuName string `gorm:"not null" json:"menuName"` - Path string `gorm:"not null" json:"path"` - IconURL string `gorm:"not null" json:"iconUrl"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/domain/platform.go b/domain/platform.go deleted file mode 100644 index b75b8e7..0000000 --- a/domain/platform.go +++ /dev/null @@ -1,7 +0,0 @@ -package domain - -type PlatformHandle struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` - Platform string `gorm:"not null" json:"platform"` - Description string `gorm:"not null" json:"description"` -} diff --git a/domain/product.go b/domain/product.go deleted file mode 100644 index 8c7e025..0000000 --- a/domain/product.go +++ /dev/null @@ -1,28 +0,0 @@ -package domain - -import "time" - -type Product struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - UserID string `gorm:"type:uuid;not null" json:"user_id"` - StoreID string `gorm:"type:uuid;not null" json:"store_id"` - Store Store `gorm:"foreignKey:StoreID" json:"store"` - ProductTitle string `gorm:"not null" json:"product_title"` - ProductImages []ProductImage `gorm:"foreignKey:ProductID;constraint:OnDelete:CASCADE;" json:"product_images"` - TrashDetailID string `gorm:"type:uuid;not null" json:"trash_detail_id"` - TrashDetail TrashDetail `gorm:"foreignKey:TrashDetailID" json:"trash_detail"` - SalePrice int64 `gorm:"not null" json:"sale_price"` - Quantity int `gorm:"not null" json:"quantity"` - ProductDescribe string `gorm:"type:text" json:"product_describe"` - Sold int `gorm:"default:0" json:"sold"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -} - -type ProductImage struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - ProductID string `gorm:"type:uuid;not null" json:"product_id"` - ImageURL string `gorm:"not null" json:"image_url"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -} diff --git a/domain/request_pickup.go b/domain/request_pickup.go deleted file mode 100644 index 6042eaa..0000000 --- a/domain/request_pickup.go +++ /dev/null @@ -1,24 +0,0 @@ -package domain - -import "time" - - -type RequestPickup struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - UserID string `gorm:"type:uuid;not null" json:"userId"` - Request []RequestItem `gorm:"foreignKey:RequestPickupID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"request"` - RequestTime string `gorm:"type:text;not null" json:"requestTime"` - UserAddressID string `gorm:"type:uuid;not null" json:"userAddressId"` - UserAddress Address `gorm:"foreignKey:UserAddressID" json:"userAddress"` - StatusRequest string `gorm:"type:text;not null" json:"statusRequest"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} - -type RequestItem struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - RequestPickupID string `gorm:"type:uuid;not null;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"requestPickupId"` - TrashCategoryID string `gorm:"type:uuid;not null" json:"trashCategoryId"` - TrashCategory TrashCategory `gorm:"foreignKey:TrashCategoryID" json:"trashCategory"` - EstimatedAmount string `gorm:"type:text;not null" json:"estimatedAmount"` -} \ No newline at end of file diff --git a/domain/role.go b/domain/role.go deleted file mode 100644 index 10738e0..0000000 --- a/domain/role.go +++ /dev/null @@ -1,7 +0,0 @@ -package domain - -type UserRole struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` - RoleName string `gorm:"unique;not null" json:"roleName"` - // Users []User `gorm:"foreignKey:RoleID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"users"` -} diff --git a/domain/store.go b/domain/store.go deleted file mode 100644 index 851a619..0000000 --- a/domain/store.go +++ /dev/null @@ -1,80 +0,0 @@ -package domain - -import "time" - -type Store struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - UserID string `gorm:"type:uuid;not null" json:"user_id"` - User User `gorm:"foreignKey:UserID" json:"user"` - StoreName string `gorm:"not null;unique" json:"store_name"` - StoreLogo string `json:"store_logo"` - StoreBanner string `json:"store_banner"` - StoreDesc string `gorm:"type:text" json:"store_desc"` - Follower int `gorm:"default:0" json:"follower"` - StoreRating float64 `gorm:"default:0" json:"store_rating"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -} - -// type StoreFinance struct { -// ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` -// StoreID string `gorm:"type:uuid;not null" json:"store_id"` -// TotalRevenue int64 `gorm:"default:0" json:"total_revenue"` -// TotalExpenses int64 `gorm:"default:0" json:"total_expenses"` -// NetProfit int64 `gorm:"default:0" json:"net_profit"` -// OrdersCount int `gorm:"default:0" json:"orders_count"` -// CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` -// UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -// } - -// type Order struct { -// ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` -// StoreID string `gorm:"type:uuid;not null" json:"store_id"` -// UserID string `gorm:"type:uuid;not null" json:"user_id"` -// TotalPrice int64 `gorm:"not null" json:"total_price"` -// OrderStatus string `gorm:"not null" json:"order_status"` -// ShippingStatus string `gorm:"not null" json:"shipping_status"` -// PaymentStatus string `gorm:"not null" json:"payment_status"` -// CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` -// UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -// } - -// type OrderDetail struct { -// ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` -// OrderID string `gorm:"type:uuid;not null" json:"order_id"` -// ProductID string `gorm:"type:uuid;not null" json:"product_id"` -// Quantity int `gorm:"not null" json:"quantity"` -// UnitPrice int64 `gorm:"not null" json:"unit_price"` -// TotalPrice int64 `gorm:"not null" json:"total_price"` -// CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` -// UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -// } - -// type Shipping struct { -// ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` -// OrderID string `gorm:"type:uuid;not null" json:"order_id"` -// ShippingDate time.Time `gorm:"default:current_timestamp" json:"shipping_date"` -// ShippingCost int64 `gorm:"not null" json:"shipping_cost"` -// TrackingNo string `gorm:"not null" json:"tracking_no"` -// ShippingStatus string `gorm:"not null" json:"shipping_status"` -// CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` -// UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -// } - -// type Cancellation struct { -// ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` -// OrderID string `gorm:"type:uuid;not null" json:"order_id"` -// Reason string `gorm:"type:text" json:"reason"` -// CancelledAt time.Time `gorm:"default:current_timestamp" json:"cancelled_at"` -// CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` -// UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -// } - -// type Return struct { -// ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` -// OrderID string `gorm:"type:uuid;not null" json:"order_id"` -// Reason string `gorm:"type:text" json:"reason"` -// ReturnedAt time.Time `gorm:"default:current_timestamp" json:"returned_at"` -// CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` -// UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` -// } diff --git a/domain/trashtype.go b/domain/trashtype.go deleted file mode 100644 index 4144a80..0000000 --- a/domain/trashtype.go +++ /dev/null @@ -1,20 +0,0 @@ -package domain - -import "time" - -type TrashCategory struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - Name string `gorm:"not null" json:"name"` - Details []TrashDetail `gorm:"foreignKey:CategoryID" json:"details"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} - -type TrashDetail struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` - CategoryID string `gorm:"type:uuid;not null" json:"category_id"` - Description string `gorm:"not null" json:"description"` - Price int `gorm:"not null" json:"price"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/domain/userpin.go b/domain/userpin.go deleted file mode 100644 index a8c5d4c..0000000 --- a/domain/userpin.go +++ /dev/null @@ -1,11 +0,0 @@ -package domain - -import "time" - -type UserPin struct { - ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` - UserID string `gorm:"not null" json:"userId"` - Pin string `gorm:"not null" json:"pin"` - CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` - UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` -} diff --git a/dto/address.go b/dto/address.go deleted file mode 100644 index 836d073..0000000 --- a/dto/address.go +++ /dev/null @@ -1,84 +0,0 @@ -package dto - -import ( - "fmt" - - "github.com/go-playground/validator/v10" -) - -type AddressInput struct { - Province string `json:"province" validate:"required"` - District string `json:"district" validate:"required"` - Subdistrict string `json:"subdistrict" validate:"required"` - PostalCode int `json:"postalCode" validate:"required,numeric"` - Village string `json:"village" validate:"required"` - Detail string `json:"detail" validate:"required"` - Geography string `json:"geography" validate:"required"` -} - -type AddressResponse struct { - ID string `json:"id"` - Province string `json:"province"` - District string `json:"district"` - Subdistrict string `json:"subdistrict"` - PostalCode int `json:"postalCode"` - Village string `json:"village"` - Detail string `json:"detail"` - Geography string `json:"geography"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -func (c *AddressInput) ValidatePost() error { - err := validate.Struct(c) - if err != nil { - - for _, e := range err.(validator.ValidationErrors) { - - switch e.Field() { - case "Province": - return fmt.Errorf("provinsi harus diisisi") - case "District": - return fmt.Errorf("kabupaten harus diisi") - case "Subdistrict": - return fmt.Errorf("kecamatan harus diisi") - case "PostalCode": - return fmt.Errorf("postal code harus diisi dan berupa angka") - case "Village": - return fmt.Errorf("desa harus diisi") - case "Detail": - return fmt.Errorf("detail wajib diisi") - case "Geography": - return fmt.Errorf("lokasi kordinat harus diisi") - } - } - } - return nil -} - -func (c *AddressInput) ValidateUpdate() error { - err := validate.Struct(c) - if err != nil { - - for _, e := range err.(validator.ValidationErrors) { - - switch e.Field() { - case "Province": - return fmt.Errorf("provinsi harus diisisi") - case "District": - return fmt.Errorf("kabupaten harus diisi") - case "Subdistrict": - return fmt.Errorf("kecamatan harus diisi") - case "PostalCode": - return fmt.Errorf("postal code harus diisi dan berupa angka") - case "Village": - return fmt.Errorf("desa harus diisi") - case "Detail": - return fmt.Errorf("detail wajib diisi") - case "Geography": - return fmt.Errorf("lokasi kordinat harus diisi") - } - } - } - return nil -} diff --git a/dto/article.go b/dto/article.go deleted file mode 100644 index c298ae0..0000000 --- a/dto/article.go +++ /dev/null @@ -1,38 +0,0 @@ -package dto - -type ArticleResponse struct { - ID string `json:"id"` - Title string `json:"title"` - CoverImage string `json:"coverImage"` - Author string `json:"author"` - Heading string `json:"heading"` - Content string `json:"content"` - PublishedAt string `json:"publishedAt"` - UpdatedAt string `json:"updatedAt"` -} - -type ArticleCreateRequest struct { - Title string `json:"title" validate:"required"` - CoverImage string `json:"coverImage" validate:"required"` - Author string `json:"author" validate:"required"` - Heading string `json:"heading" validate:"required"` - Content string `json:"content" validate:"required"` -} - -type ArticleUpdateRequest struct { - Title string `json:"title" validate:"required"` - CoverImage string `json:"coverImage" validate:"required"` - Author string `json:"author" validate:"required"` - Heading string `json:"heading" validate:"required"` - Content string `json:"content" validate:"required"` -} - -func (p *ArticleCreateRequest) Validate() error { - validate := GetValidator() - return validate.Struct(p) -} - -func (p *ArticleUpdateRequest) Validate() error { - validate := GetValidator() - return validate.Struct(p) -} diff --git a/dto/auth_dto.go b/dto/auth_dto.go new file mode 100644 index 0000000..b308725 --- /dev/null +++ b/dto/auth_dto.go @@ -0,0 +1,11 @@ +package dto + +type LoginDTO struct { + Identifier string `json:"identifier" validate:"required"` + Password string `json:"password" validate:"required,min=6"` +} + +type UserResponseWithToken struct { + UserID string `json:"user_id"` + Token string `json:"token"` +} diff --git a/dto/banner.go b/dto/banner.go deleted file mode 100644 index 55fc2d4..0000000 --- a/dto/banner.go +++ /dev/null @@ -1,19 +0,0 @@ -package dto - -type BannerResponse struct { - ID string `json:"id"` - BannerName string `json:"bannername"` - BannerImage string `json:"bannerimage"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -type BannerCreateRequest struct { - BannerName string `json:"bannername" validate:"required"` - BannerImage string `json:"bannerimage" validate:"required"` -} - -type BannerUpdateRequest struct { - BannerName *string `json:"bannername,omitempty"` - BannerImage *string `json:"bannerimage,omitempty"` -} diff --git a/dto/coveragearea.go b/dto/coveragearea.go deleted file mode 100644 index a1894f8..0000000 --- a/dto/coveragearea.go +++ /dev/null @@ -1,119 +0,0 @@ -package dto - -type CoverageAreaResponse struct { - ID string `json:"id"` - Province string `json:"province"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -type CoverageAreaWithDistrictsResponse struct { - ID string `json:"id"` - Province string `json:"province"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` - CoverageArea []CoverageAreaResponse `json:"coverage_area"` -} - -type CoverageAreaDetailWithLocation struct { - ID string `json:"id"` - Province string `json:"province"` - District string `json:"district"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` - Subdistrict []SubdistrictResponse `json:"subdistrict"` -} - -type SubdistrictResponse struct { - ID string `json:"id"` - Subdistrict string `json:"subdistrict"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -func NewCoverageAreaResponse(id, province, createdAt, updatedAt string) CoverageAreaResponse { - return CoverageAreaResponse{ - ID: id, - Province: province, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} - -func NewCoverageAreaWithDistrictsResponse(id, province, createdAt, updatedAt string, coverageArea []CoverageAreaResponse) CoverageAreaWithDistrictsResponse { - return CoverageAreaWithDistrictsResponse{ - ID: id, - Province: province, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - CoverageArea: coverageArea, - } -} - -func NewCoverageAreaDetailWithLocation(id, province, district, createdAt, updatedAt string, subdistricts []SubdistrictResponse) CoverageAreaDetailWithLocation { - return CoverageAreaDetailWithLocation{ - ID: id, - Province: province, - District: district, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - Subdistrict: subdistricts, - } -} - -func NewSubdistrictResponse(id, subdistrict, createdAt, updatedAt string) SubdistrictResponse { - return SubdistrictResponse{ - ID: id, - Subdistrict: subdistrict, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} - -type CoverageAreaCreateRequest struct { - Province string `json:"province" validate:"required"` -} - -func NewCoverageAreaCreateRequest(province string) CoverageAreaCreateRequest { - return CoverageAreaCreateRequest{ - Province: province, - } -} - -type CoverageDistrictCreateRequest struct { - CoverageAreaID string `json:"coverage_area_id" validate:"required"` - District string `json:"district" validate:"required"` -} - -func NewCoverageDistrictCreateRequest(coverageAreaID, district string) CoverageDistrictCreateRequest { - return CoverageDistrictCreateRequest{ - CoverageAreaID: coverageAreaID, - District: district, - } -} - -type CoverageSubdistrictCreateRequest struct { - CoverageAreaID string `json:"coverage_area_id" validate:"required"` - CoverageDistrictId string `json:"coverage_district_id" validate:"required"` - Subdistrict string `json:"subdistrict" validate:"required"` -} - -func NewCoverageSubdistrictCreateRequest(coverageAreaID, coverageDistrictId, subdistrict string) CoverageSubdistrictCreateRequest { - return CoverageSubdistrictCreateRequest{ - CoverageAreaID: coverageAreaID, - CoverageDistrictId: coverageDistrictId, - Subdistrict: subdistrict, - } -} - -type CoverageAreaUpdateRequest struct { - Province string `json:"province" validate:"required"` -} - -type CoverageDistrictUpdateRequest struct { - District string `json:"district" validate:"required"` -} - -type CoverageSubdistrictUpdateRequest struct { - Subdistrict string `json:"subdistrict" validate:"required"` -} \ No newline at end of file diff --git a/dto/initialcoint.go b/dto/initialcoint.go deleted file mode 100644 index bf59be1..0000000 --- a/dto/initialcoint.go +++ /dev/null @@ -1,29 +0,0 @@ -package dto - -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"` -} - -type PointCreateRequest struct { - CoinName string `json:"coin_name" validate:"required"` - ValuePerUnit float64 `json:"value_perunit" validate:"required,gt=0"` -} - -type PointUpdateRequest struct { - CoinName string `json:"coin_name" validate:"required"` - ValuePerUnit float64 `json:"value_perunit" validate:"required,gt=0"` -} - -func (p *PointCreateRequest) Validate() error { - validate := GetValidator() - return validate.Struct(p) -} - -func (p *PointUpdateRequest) Validate() error { - validate := GetValidator() - return validate.Struct(p) -} diff --git a/dto/product.go b/dto/product.go deleted file mode 100644 index 6a64851..0000000 --- a/dto/product.go +++ /dev/null @@ -1,93 +0,0 @@ -package dto - -import "errors" - -type ProductResponseWithSoldDTO struct { - ID string `json:"id"` - StoreID string `json:"store_id"` - ProductTitle string `json:"product_title"` - ProductImages []ProductImageDTO `json:"product_images"` - TrashDetail TrashDetailResponseDTO `json:"trash_detail"` - SalePrice int64 `json:"sale_price"` - Quantity int `json:"quantity"` - ProductDescribe string `json:"product_describe"` - Sold int `json:"sold"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type ProductResponseWithoutSoldDTO struct { - ID string `json:"id"` - StoreID string `json:"store_id"` - ProductTitle string `json:"product_title"` - ProductImages []ProductImageDTO `json:"product_images"` - TrashDetail TrashDetailResponseDTO `json:"trash_detail"` - SalePrice int64 `json:"sale_price"` - Quantity int `json:"quantity"` - ProductDescribe string `json:"product_describe"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type ProductResponseDTO struct { - ID string `json:"id"` - StoreID string `json:"store_id"` - ProductTitle string `json:"product_title"` - ProductImages []ProductImageDTO `json:"product_images"` - TrashDetail TrashDetailResponseDTO `json:"trash_detail"` - SalePrice int64 `json:"sale_price"` - Quantity int `json:"quantity"` - ProductDescribe string `json:"product_describe"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type ProductImageDTO struct { - ImageURL string `json:"image_url"` -} - -type TrashDetailResponseDTO struct { - ID string `json:"id"` - Description string `json:"description"` - Price int `json:"price"` -} - -type CreateProductRequestDTO struct { - StoreID string `json:"storeid" validate:"required,uuid"` - ProductTitle string `json:"product_title" validate:"required,min=3,max=255"` - ProductImages []string `json:"product_images" validate:"required,min=1,dive,url"` - TrashDetailID string `json:"trash_detail_id" validate:"required,uuid"` - SalePrice int64 `json:"sale_price" validate:"required,gt=0"` - Quantity int `json:"quantity" validate:"required,gt=0"` - ProductDescribe string `json:"product_describe,omitempty"` -} - -type CreateProductResponseDTO struct { - ID string `json:"id"` - StoreID string `json:"store_id"` - ProductTitle string `json:"product_title"` - ProductImages []string `json:"product_images"` - TrashDetail TrashDetailResponseDTO `json:"trash_detail"` - SalePrice int64 `json:"sale_price"` - Quantity int `json:"quantity"` - ProductDescribe string `json:"product_describe,omitempty"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type UpdateProductRequestDTO struct { - ProductTitle string `json:"product_title" validate:"required,min=3,max=255"` - ProductImages []string `json:"product_images" validate:"required,min=1,dive,url"` - TrashDetailID string `json:"trash_detail_id" validate:"required,uuid"` - SalePrice int64 `json:"sale_price" validate:"required,gt=0"` - Quantity int `json:"quantity" validate:"required,gt=0"` - ProductDescribe string `json:"product_describe,omitempty"` -} - -func ValidateSalePrice(marketPrice, salePrice int64) error { - - if salePrice > marketPrice*2 { - return errors.New("sale price cannot be more than twice the market price") - } - return nil -} diff --git a/dto/request_pickup.go b/dto/request_pickup.go deleted file mode 100644 index 89a3276..0000000 --- a/dto/request_pickup.go +++ /dev/null @@ -1,46 +0,0 @@ -package dto - -type RequestPickupRequest struct { - RequestItems []RequestItemDTO `json:"request_items"` - RequestTime string `json:"requestTime"` - UserAddressID string `json:"userAddressId"` -} - -type RequestPickupResponse struct { - ID string `json:"id"` - UserID string `json:"userId"` - Request []RequestItemDTO `json:"request"` - RequestTime string `json:"requestTimePickup"` - UserAddress UserAddressDTO `json:"userAddress"` - StatusRequest string `json:"status"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -type RequestItemDTO struct { - TrashCategory string `json:"trashCategory"` - EstimatedAmount string `json:"estimatedAmount"` -} - -type UserAddressDTO struct { - Province string `json:"province"` - District string `json:"district"` - Subdistrict string `json:"subdistrict"` - PostalCode int `json:"postalCode"` - Village string `json:"village"` - Detail string `json:"detail"` - Geography string `json:"geography"` -} - -func NewRequestPickupResponse(id, userID, requestTime, statusRequest string, request []RequestItemDTO, userAddress UserAddressDTO, createdAt, updatedAt string) RequestPickupResponse { - return RequestPickupResponse{ - ID: id, - UserID: userID, - Request: request, - RequestTime: requestTime, - UserAddress: userAddress, - StatusRequest: statusRequest, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} \ No newline at end of file diff --git a/dto/store.go b/dto/store.go deleted file mode 100644 index e3990b0..0000000 --- a/dto/store.go +++ /dev/null @@ -1,14 +0,0 @@ -package dto - -type StoreResponseDTO struct { - ID string `json:"id"` - UserID string `json:"user_id"` - StoreName string `json:"store_name"` - StoreLogo string `json:"store_logo"` - StoreBanner string `json:"store_banner"` - StoreDesc string `json:"store_desc"` - Follower int `json:"follower"` - StoreRating float64 `json:"store_rating"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} diff --git a/dto/trashtype.go b/dto/trashtype.go deleted file mode 100644 index 30e24a8..0000000 --- a/dto/trashtype.go +++ /dev/null @@ -1,76 +0,0 @@ -package dto - -import "github.com/go-playground/validator/v10" - -type TrashCategoryDTO struct { - Name string `json:"name" validate:"required,min=3,max=100"` -} - -func (t *TrashCategoryDTO) Validate() error { - validate := validator.New() - return validate.Struct(t) -} - -type TrashDetailDTO struct { - CategoryID string `json:"category_id" validate:"required,uuid4"` - Description string `json:"description" validate:"required,min=3,max=255"` - Price int `json:"price" validate:"required,min=0"` -} - -func (t *TrashDetailDTO) Validate() error { - validate := validator.New() - return validate.Struct(t) -} - -type TrashCategoryResponse struct { - ID string `json:"id"` - Name string `json:"name"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -func NewTrashCategoryResponse(id, name, createdAt, updatedAt string) TrashCategoryResponse { - return TrashCategoryResponse{ - ID: id, - Name: name, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} - -type TrashDetailResponse struct { - ID string `json:"id"` - Description string `json:"description"` - Price int `json:"price"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -func NewTrashDetailResponse(id, description string, price int, createdAt, updatedAt string) TrashDetailResponse { - return TrashDetailResponse{ - ID: id, - Description: description, - Price: price, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} - -type UpdateTrashCategoryDTO struct { - Name string `json:"name" validate:"required,min=3,max=100"` -} - -func (t *UpdateTrashCategoryDTO) Validate() error { - validate := validator.New() - return validate.Struct(t) -} - -type UpdateTrashDetailDTO struct { - Description string `json:"description" validate:"required,min=3,max=255"` - Price int `json:"price" validate:"required,min=0"` -} - -func (t *UpdateTrashDetailDTO) Validate() error { - validate := validator.New() - return validate.Struct(t) -} \ No newline at end of file diff --git a/dto/user.go b/dto/user.go deleted file mode 100644 index 61a0e6e..0000000 --- a/dto/user.go +++ /dev/null @@ -1,152 +0,0 @@ -package dto - -import ( - "errors" - "regexp" -) - -type UserResponseDTO struct { - ID string `json:"id"` - Username string `json:"username"` - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - RoleId string `json:"roleId"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -func ValidateEmail(email string) error { - if email == "" { - return errors.New("email harus diisi") - } - - emailRegex := `^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$` - re := regexp.MustCompile(emailRegex) - if !re.MatchString(email) { - return errors.New("format email belum sesuai") - } - return nil -} - -func ValidatePhone(phone string) error { - if phone == "" { - return errors.New("nomor telepon harus diisi") - } - - phoneRegex := `^\+?[0-9]{10,15}$` - re := regexp.MustCompile(phoneRegex) - if !re.MatchString(phone) { - return errors.New("nomor telepon tidak valid") - } - - return nil -} - -func ValidatePassword(password string) error { - if password == "" { - return errors.New("password harus diisi") - } - - if len(password) < 8 { - return errors.New("password minimal 8 karakter") - } - return nil -} - -type RegisterUserInput struct { - Username string `json:"username"` - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - Password string `json:"password"` - ConfirmPassword string `json:"confirm_password"` - RoleId string `json:"roleId"` -} - -func (input *RegisterUserInput) Validate() error { - - if input.Username == "" { - return errors.New("username harus diisi") - } - - if input.Name == "" { - return errors.New("nama harus diisi") - } - - if err := ValidateEmail(input.Email); err != nil { - return err - } - - if err := ValidatePhone(input.Phone); err != nil { - return err - } - - if err := ValidatePassword(input.Password); err != nil { - return err - } - - if input.Password != input.ConfirmPassword { - return errors.New("password dan confirm password tidak cocok") - } - - if input.RoleId == "" { - return errors.New("roleId harus diisi") - } - - return nil -} - -type UpdatePasswordInput struct { - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` -} - -func (input *UpdatePasswordInput) Validate() error { - - if input.OldPassword == "" { - return errors.New("old password must be provided") - } - - if input.NewPassword == "" { - return errors.New("new password must be provided") - } - - if len(input.NewPassword) < 8 { - return errors.New("new password must be at least 8 characters long") - } - - return nil -} - -type UpdateUserInput struct { - Email string `json:"email"` - Username string `json:"username"` - Name string `json:"name"` - Phone string `json:"phone"` -} - -func (input *UpdateUserInput) Validate() error { - - if input.Email != "" { - if err := ValidateEmail(input.Email); err != nil { - return err - } - } - - if input.Username == "" { - return errors.New("username harus diisi") - } - - if input.Name == "" { - return errors.New("name harus diisi") - } - - if input.Phone != "" { - if err := ValidatePhone(input.Phone); err != nil { - return err - } - } - - return nil -} diff --git a/dto/userpin.go b/dto/userpin.go deleted file mode 100644 index f7b1b47..0000000 --- a/dto/userpin.go +++ /dev/null @@ -1,47 +0,0 @@ -package dto - -import ( - "fmt" - - "github.com/go-playground/validator/v10" -) - -type PinResponse struct { - CreatedAt string `json:"createdAt"` -} -type PinInput struct { - Pin string `json:"pin" validate:"required,len=6,numeric"` -} - -func (p *PinInput) ValidateCreate() error { - err := validate.Struct(p) - if err != nil { - for _, e := range err.(validator.ValidationErrors) { - switch e.Field() { - case "Pin": - return fmt.Errorf("PIN harus terdiri dari 6 digit angka") - } - } - } - return nil -} - -type PinUpdateInput struct { - OldPin string `json:"old_pin" validate:"required,len=6,numeric"` - NewPin string `json:"new_pin" validate:"required,len=6,numeric"` -} - -func (p *PinUpdateInput) ValidateUpdate() error { - err := validate.Struct(p) - if err != nil { - for _, e := range err.(validator.ValidationErrors) { - switch e.Field() { - case "OldPin": - return fmt.Errorf("PIN lama harus terdiri dari 6 digit angka") - case "NewPin": - return fmt.Errorf("PIN baru harus terdiri dari 6 digit angka") - } - } - } - return nil -} diff --git a/dto/validator.go b/dto/validator.go deleted file mode 100644 index 47d9a65..0000000 --- a/dto/validator.go +++ /dev/null @@ -1,9 +0,0 @@ -package dto - -import "github.com/go-playground/validator/v10" - -var validate = validator.New() - -func GetValidator() *validator.Validate { - return validate -} diff --git a/internal/api/routes.go b/internal/api/routes.go deleted file mode 100644 index de65c04..0000000 --- a/internal/api/routes.go +++ /dev/null @@ -1,137 +0,0 @@ -package api - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/internal/controllers" - "github.com/pahmiudahgede/senggoldong/internal/middleware" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func AppRouter(app *fiber.App) { - // # init - pointRepo := repositories.NewPointRepository() - pointService := services.NewPointService(pointRepo) - pointController := controllers.NewPointController(pointService) - - bannerRepo := repositories.NewBannerRepository() - bannerService := services.NewBannerService(bannerRepo) - bannerController := controllers.NewBannerController(bannerService) - - articleRepo := repositories.NewArticleRepository() - articleService := services.NewArticleService(articleRepo) - articleController := controllers.NewArticleController(articleService) - - // # api group domain endpoint # - api := app.Group("/apirijikid") - - // # API Secure # - api.Use(middleware.APIKeyMiddleware) - api.Use(middleware.RateLimitMiddleware) - - // # user initial coint # - api.Get("/user/initial-coint", pointController.GetAllPoints) - api.Get("/user/initial-coint/:id", pointController.GetPointByID) - api.Post("/user/initial-coint", middleware.RoleRequired(utils.RoleAdministrator), pointController.CreatePoint) - api.Put("/user/initial-coint/:id", middleware.RoleRequired(utils.RoleAdministrator), pointController.UpdatePoint) - api.Delete("/user/initial-coint/:id", middleware.RoleRequired(utils.RoleAdministrator), pointController.DeletePoint) - - //# coverage area # - api.Get("/coverage-areas", controllers.GetCoverageAreas) - api.Get("/coverage-areas-district/:id", controllers.GetCoverageAreaByIDProvince) - api.Get("/coverage-areas-subdistrict/:id", controllers.GetCoverageAreaByIDDistrict) - api.Post("/coverage-areas", middleware.RoleRequired(utils.RoleAdministrator), controllers.CreateCoverageArea) - api.Post("/coverage-areas-district", middleware.RoleRequired(utils.RoleAdministrator), controllers.CreateCoverageDistrict) - api.Post("/coverage-areas-subdistrict", middleware.RoleRequired(utils.RoleAdministrator), controllers.CreateCoverageSubdistrict) - api.Put("/coverage-areas/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.UpdateCoverageArea) - api.Put("/coverage-areas-district/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.UpdateCoverageDistrict) - api.Put("/coverage-areas-subdistrict/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.UpdateCoverageSubdistrict) - api.Delete("/coverage-areas/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.DeleteCoverageArea) - api.Delete("/coverage-areas-district/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.DeleteCoverageDistrict) - api.Delete("/coverage-areas-subdistrict/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.DeleteCoverageSubdistrict) - - // # role # - api.Get("/roles", middleware.RoleRequired(utils.RoleAdministrator), controllers.GetAllUserRoles) - api.Get("/role/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.GetUserRoleByID) - - // # authentication # - api.Post("/register", controllers.Register) - api.Post("/login", controllers.Login) - api.Post("/logout", controllers.Logout) - - // # userinfo # - api.Get("/user", middleware.AuthMiddleware, controllers.GetUserInfo) - api.Post("/user/update-password", middleware.AuthMiddleware, controllers.UpdatePassword) - api.Put("/user/update-user", middleware.AuthMiddleware, controllers.UpdateUser) - - // # view all user (admin) - api.Get("/user/listallusers", middleware.RoleRequired(utils.RoleAdministrator), controllers.GetListUsers) - api.Get("/user/listalluser/:roleid", middleware.RoleRequired(utils.RoleAdministrator), controllers.GetUsersByRole) - api.Get("/user/listuser/:userid", middleware.RoleRequired(utils.RoleAdministrator), controllers.GetUserByUserID) - - // # user set pin # - api.Get("/user/verif-pin", middleware.AuthMiddleware, controllers.GetPin) - api.Get("/user/cek-pin-status", middleware.AuthMiddleware, controllers.GetPinStatus) - api.Post("/user/set-pin", middleware.AuthMiddleware, controllers.CreatePin) - api.Put("/user/update-pin", middleware.AuthMiddleware, controllers.UpdatePin) - api.Put("/user/update-pin", middleware.AuthMiddleware, controllers.UpdatePin) - - // # address routing # - api.Get("/addresses", middleware.AuthMiddleware, controllers.GetListAddress) - api.Get("/address/:id", middleware.AuthMiddleware, controllers.GetAddressByID) - api.Post("/address/create-address", middleware.AuthMiddleware, controllers.CreateAddress) - api.Put("/address/update-address/:id", middleware.AuthMiddleware, controllers.UpdateAddress) - api.Delete("/address/delete-address/:id", middleware.AuthMiddleware, controllers.DeleteAddress) - - // # article # - api.Get("/articles", articleController.GetAllArticles) - api.Get("/article/:id", articleController.GetArticleByID) - api.Post("/article/create-article", middleware.RoleRequired(utils.RoleAdministrator), articleController.CreateArticle) - api.Put("/article/update-article/:id", middleware.RoleRequired(utils.RoleAdministrator), articleController.UpdateArticle) - api.Delete("/article/delete-article/:id", middleware.RoleRequired(utils.RoleAdministrator), articleController.DeleteArticle) - - // # trash type # - api.Get("/trash-categorys", controllers.GetTrashCategories) - api.Get("/trash-category/:id", controllers.GetTrashCategoryDetail) - api.Post("/trash-category/create-trash-category", middleware.RoleRequired(utils.RoleAdministrator), controllers.CreateTrashCategory) - api.Post("/trash-category/create-trash-categorydetail", middleware.RoleRequired(utils.RoleAdministrator), controllers.CreateTrashDetail) - api.Put("/trash-category/update-trash-category/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.UpdateTrashCategory) - api.Put("/trash-category/update-trash-detail/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.UpdateTrashDetail) - api.Delete("/trash-category/delete-trash-category/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.DeleteTrashCategory) - api.Delete("/trash-category/delete-trash-detail/:id", middleware.RoleRequired(utils.RoleAdministrator), controllers.DeleteTrashDetail) - - // # banner # - api.Get("/banners", bannerController.GetAllBanners) - api.Get("/banner/:id", bannerController.GetBannerByID) - api.Post("/banner/create-banner", middleware.RoleRequired(utils.RoleAdministrator), bannerController.CreateBanner) - api.Put("/banner/update-banner/:id", middleware.RoleRequired(utils.RoleAdministrator), bannerController.UpdateBanner) - api.Delete("/banner/delete-banner/:id", middleware.RoleRequired(utils.RoleAdministrator), bannerController.DeleteBanner) - - // # wilayah di indonesia # - api.Get("/wilayah-indonesia/provinces", controllers.GetProvinces) - api.Get("/wilayah-indonesia/regencies", controllers.GetRegencies) - api.Get("/wilayah-indonesia/subdistricts", controllers.GetDistricts) - api.Get("/wilayah-indonesia/villages", controllers.GetVillages) - api.Get("/wilayah-indonesia/provinces/:id", controllers.GetProvinceByID) - api.Get("/wilayah-indonesia/regencies/:id", controllers.GetRegencyByID) - api.Get("/wilayah-indonesia/subdistricts/:id", controllers.GetDistrictByID) - api.Get("/wilayah-indonesia/villages/:id", controllers.GetVillageByID) - - // # request pickup by user (masyarakat) # - api.Get("/requestpickup", middleware.RoleRequired(utils.RoleMasyarakat, utils.RolePengepul), controllers.GetRequestPickupsByUser) - api.Post("/addrequestpickup", middleware.RoleRequired(utils.RoleMasyarakat), controllers.CreateRequestPickup) - api.Delete("/deleterequestpickup/:id", middleware.RoleRequired(utils.RoleMasyarakat), controllers.DeleteRequestPickup) - - // # product post by pengepul - api.Get("/post/products", middleware.RoleRequired(utils.RolePengepul), controllers.GetAllProducts) - api.Get("/post/product/:productid", middleware.RoleRequired(utils.RolePengepul), controllers.GetProductByID) - api.Get("/view/product/:storeid", middleware.RoleRequired(utils.RolePengepul), controllers.GetProductsByStore) - api.Post("/post/addproduct", middleware.RoleRequired(utils.RolePengepul), controllers.CreateProduct) - api.Put("/post/product/:productid", middleware.RoleRequired(utils.RolePengepul), controllers.UpdateProduct) - api.Delete("/delete/product/:productid", middleware.RoleRequired(utils.RolePengepul), controllers.DeleteProduct) - - // # marketplace - api.Get("/store/marketplace", middleware.RoleRequired(utils.RolePengepul), controllers.GetStoresByUserID) - api.Get("/store/marketplace/:storeid", middleware.RoleRequired(utils.RolePengepul), controllers.GetStoreByID) -} diff --git a/internal/controllers/Indonesian_territory.go b/internal/controllers/Indonesian_territory.go deleted file mode 100644 index c009ab3..0000000 --- a/internal/controllers/Indonesian_territory.go +++ /dev/null @@ -1,147 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetProvinces(c *fiber.Ctx) error { - provinces, err := services.GetProvinces() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve provinces", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Provinces retrieved successfully", - provinces, - )) -} - -func GetRegencies(c *fiber.Ctx) error { - regencies, err := services.GetRegencies() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve regencies", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Regencies retrieved successfully", - regencies, - )) -} - -func GetDistricts(c *fiber.Ctx) error { - districts, err := services.GetDistricts() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve districts", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Districts retrieved successfully", - districts, - )) -} - -func GetVillages(c *fiber.Ctx) error { - villages, err := services.GetVillages() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve villages", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Villages retrieved successfully", - villages, - )) -} - -func GetProvinceByID(c *fiber.Ctx) error { - id := c.Params("id") - province, err := services.GetProvinceByID(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve province", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Province by id retrieved successfully", - province, - )) -} - -func GetRegencyByID(c *fiber.Ctx) error { - id := c.Params("id") - regency, err := services.GetRegencyByID(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve regency", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Regency by id retrieved successfully", - regency, - )) -} - -func GetDistrictByID(c *fiber.Ctx) error { - id := c.Params("id") - district, err := services.GetDistrictByID(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve district", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "District by id retrieved successfully", - district, - )) -} - -func GetVillageByID(c *fiber.Ctx) error { - id := c.Params("id") - village, err := services.GetVillageByID(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to retrieve village", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Village by id retrieved successfully", - village, - )) -} diff --git a/internal/controllers/address.go b/internal/controllers/address.go deleted file mode 100644 index f1f5c0a..0000000 --- a/internal/controllers/address.go +++ /dev/null @@ -1,205 +0,0 @@ -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 CreateAddress(c *fiber.Ctx) error { - var input dto.AddressInput - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Mohon masukkan alamat dengan benar", - nil, - )) - } - - if err := input.ValidatePost(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - userID := c.Locals("userID").(string) - address, err := services.CreateAddress(userID, input) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create address", - nil, - )) - } - - createdAtFormatted := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAtFormatted := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressResponse := dto.AddressResponse{ - ID: address.ID, - Province: address.Province, - District: address.District, - Subdistrict: address.Subdistrict, - PostalCode: address.PostalCode, - Village: address.Village, - Detail: address.Detail, - Geography: address.Geography, - CreatedAt: createdAtFormatted, - UpdatedAt: updatedAtFormatted, - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Address created successfully", - addressResponse, - )) -} - -func GetListAddress(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - addresses, err := services.GetAllAddressesByUserID(userID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Addresses not found", - nil, - )) - } - - var addressResponses []dto.AddressResponse - for _, address := range addresses { - - createdAtFormatted := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAtFormatted := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressResponse := dto.AddressResponse{ - ID: address.ID, - Province: address.Province, - District: address.District, - Subdistrict: address.Subdistrict, - PostalCode: address.PostalCode, - Village: address.Village, - Detail: address.Detail, - Geography: address.Geography, - CreatedAt: createdAtFormatted, - UpdatedAt: updatedAtFormatted, - } - addressResponses = append(addressResponses, addressResponse) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Addresses fetched successfully", - addressResponses, - )) -} - -func GetAddressByID(c *fiber.Ctx) error { - addressID := c.Params("id") - - address, err := services.GetAddressByID(addressID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Address not found", - nil, - )) - } - - createdAtFormatted := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAtFormatted := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressResponse := dto.AddressResponse{ - ID: address.ID, - Province: address.Province, - District: address.District, - Subdistrict: address.Subdistrict, - PostalCode: address.PostalCode, - Village: address.Village, - Detail: address.Detail, - Geography: address.Geography, - CreatedAt: createdAtFormatted, - UpdatedAt: updatedAtFormatted, - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Address fetched successfully", - addressResponse, - )) -} - -func UpdateAddress(c *fiber.Ctx) error { - addressID := c.Params("id") - - var input dto.AddressInput - - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := input.ValidateUpdate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - address, err := services.UpdateAddress(addressID, input) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update address", - nil, - )) - } - - createdAtFormatted := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAtFormatted := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressResponse := dto.AddressResponse{ - ID: address.ID, - Province: address.Province, - District: address.District, - Subdistrict: address.Subdistrict, - PostalCode: address.PostalCode, - Village: address.Village, - Detail: address.Detail, - Geography: address.Geography, - CreatedAt: createdAtFormatted, - UpdatedAt: updatedAtFormatted, - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Address updated successfully", - addressResponse, - )) -} - -func DeleteAddress(c *fiber.Ctx) error { - addressID := c.Params("id") - - err := services.DeleteAddress(addressID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete address", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Address deleted successfully", - nil, - )) -} diff --git a/internal/controllers/article.go b/internal/controllers/article.go deleted file mode 100644 index 1bbf5bd..0000000 --- a/internal/controllers/article.go +++ /dev/null @@ -1,122 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -type ArticleController struct { - service *services.ArticleService -} - -func NewArticleController(service *services.ArticleService) *ArticleController { - return &ArticleController{service: service} -} - -func (ac *ArticleController) GetAllArticles(c *fiber.Ctx) error { - articles, err := ac.service.GetAllArticles() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - "Failed to fetch articles", - )) - } - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Articles fetched successfully", - articles, - )) -} - -func (ac *ArticleController) GetArticleByID(c *fiber.Ctx) error { - id := c.Params("id") - article, err := ac.service.GetArticleByID(id) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse( - fiber.StatusNotFound, - "Article not found", - )) - } - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Article fetched successfully", - article, - )) -} - -func (ac *ArticleController) CreateArticle(c *fiber.Ctx) error { - var request dto.ArticleCreateRequest - - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - "Invalid request body", - )) - } - - article, err := ac.service.CreateArticle(&request) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - err.Error(), - )) - } - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Article created successfully", - article, - )) -} - -func (ac *ArticleController) UpdateArticle(c *fiber.Ctx) error { - id := c.Params("id") - var request dto.ArticleUpdateRequest - - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - "Invalid request body", - )) - } - - article, err := ac.service.UpdateArticle(id, &request) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - err.Error(), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Point updated successfully", - article, - )) -} - -func (ac *ArticleController) DeleteArticle(c *fiber.Ctx) error { - id := c.Params("id") - - err := ac.service.DeleteArticle(id) - if err != nil { - if err.Error() == "article not found" { - return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse( - fiber.StatusNotFound, - "Article not found", - )) - } - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - err.Error(), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Article deleted successfully", - nil, - )) -} diff --git a/internal/controllers/auth.go b/internal/controllers/auth.go deleted file mode 100644 index 1a52e60..0000000 --- a/internal/controllers/auth.go +++ /dev/null @@ -1,294 +0,0 @@ -package controllers - -import ( - "context" - "strings" - "time" - - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func Register(c *fiber.Ctx) error { - var userInput dto.RegisterUserInput - - if err := c.BodyParser(&userInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := userInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - err := services.RegisterUser(userInput.Username, userInput.Name, userInput.Email, userInput.Phone, userInput.Password, userInput.ConfirmPassword, userInput.RoleId) - if err != nil { - return c.Status(fiber.StatusConflict).JSON(utils.FormatResponse( - fiber.StatusConflict, - err.Error(), - nil, - )) - } - - user, err := repositories.GetUserByEmailUsernameOrPhone(userInput.Email, userInput.RoleId) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch user after registration", - nil, - )) - } - - userResponse := dto.UserResponseDTO{ - ID: user.ID, - Username: user.Username, - Name: user.Name, - Email: user.Email, - Phone: user.Phone, - RoleId: user.RoleID, - CreatedAt: utils.FormatDateToIndonesianFormat(user.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(user.UpdatedAt), - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "User registered successfully", - userResponse, - )) -} - -func Login(c *fiber.Ctx) error { - var credentials struct { - Identifier string `json:"identifier"` - Password string `json:"password"` - } - - if err := c.BodyParser(&credentials); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - token, err := services.LoginUser(credentials.Identifier, credentials.Password) - if err != nil { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - err.Error(), - nil, - )) - } - - ctx := context.Background() - err = config.RedisClient.Set(ctx, "auth_token:"+token, credentials.Identifier, time.Hour*24).Err() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to store session", - nil, - )) - } - - user, err := repositories.GetUserByEmailUsernameOrPhone(credentials.Identifier, "") - if err != nil { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - err.Error(), - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Login successful", - map[string]interface{}{ - "token": token, - "role": user.RoleID, - }, - )) -} - -func GetUserInfo(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - user, err := services.GetUserByID(userID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "user tidak ditemukan", - nil, - )) - } - - userResponse := dto.UserResponseDTO{ - ID: user.ID, - Username: user.Username, - Name: user.Name, - Phone: user.Phone, - Email: user.Email, - RoleId: user.RoleID, - CreatedAt: utils.FormatDateToIndonesianFormat(user.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(user.UpdatedAt), - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Data user berhasil ditampilkan", - userResponse, - )) -} - -func UpdateUser(c *fiber.Ctx) error { - var userInput dto.UpdateUserInput - - if err := c.BodyParser(&userInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := userInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized access", - nil, - )) - } - - err := services.UpdateUser(userID, userInput.Email, userInput.Username, userInput.Name, userInput.Phone) - if err != nil { - return c.Status(fiber.StatusConflict).JSON(utils.FormatResponse( - fiber.StatusConflict, - err.Error(), - nil, - )) - } - - user, err := repositories.GetUserByID(userID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch user after update", - nil, - )) - } - - userResponse := dto.UserResponseDTO{ - ID: user.ID, - Username: user.Username, - Name: user.Name, - Email: user.Email, - Phone: user.Phone, - RoleId: user.RoleID, - CreatedAt: utils.FormatDateToIndonesianFormat(user.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(user.UpdatedAt), - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "User updated successfully", - userResponse, - )) -} - -func UpdatePassword(c *fiber.Ctx) error { - var passwordInput dto.UpdatePasswordInput - - if err := c.BodyParser(&passwordInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := passwordInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - userID := c.Locals("userID").(string) - - err := services.UpdatePassword(userID, passwordInput.OldPassword, passwordInput.NewPassword) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - err.Error(), - nil, - )) - } - - user, err := repositories.GetUserByID(userID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch user after password update", - nil, - )) - } - - updatedAtFormatted := utils.FormatDateToIndonesianFormat(user.UpdatedAt) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Password updated successfully", - map[string]string{ - "updatedAt": updatedAtFormatted, - }, - )) -} - -func Logout(c *fiber.Ctx) error { - tokenString := c.Get("Authorization") - tokenString = strings.TrimPrefix(tokenString, "Bearer ") - - if tokenString == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Token is required", - nil, - )) - } - - ctx := context.Background() - err := config.RedisClient.Del(ctx, "auth_token:"+tokenString).Err() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete session", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Logout successful", - nil, - )) -} diff --git a/internal/controllers/banner.go b/internal/controllers/banner.go deleted file mode 100644 index c98d2dd..0000000 --- a/internal/controllers/banner.go +++ /dev/null @@ -1,128 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -type BannerController struct { - service *services.BannerService -} - -func NewBannerController(service *services.BannerService) *BannerController { - return &BannerController{service: service} -} - -func (bc *BannerController) GetAllBanners(c *fiber.Ctx) error { - banners, err := bc.service.GetAllBanners() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - "Failed to fetch banners", - )) - } - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Banners fetched successfully", - banners, - )) -} - -func (bc *BannerController) GetBannerByID(c *fiber.Ctx) error { - id := c.Params("id") - banner, err := bc.service.GetBannerByID(id) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse( - fiber.StatusNotFound, - "Banner not found", - )) - } - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Banner fetched successfully", - banner, - )) -} - -func (bc *BannerController) CreateBanner(c *fiber.Ctx) error { - var request dto.BannerCreateRequest - - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - "Invalid request body", - )) - } - - banner, err := bc.service.CreateBanner(&request) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - err.Error(), - )) - } - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Banner created successfully", - banner, - )) -} - -func (bc *BannerController) UpdateBanner(c *fiber.Ctx) error { - id := c.Params("id") - var request dto.BannerUpdateRequest - - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - "Invalid request body", - )) - } - - banner, err := bc.service.UpdateBanner(id, &request) - if err != nil { - if err.Error() == "banner not found" { - return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse( - fiber.StatusNotFound, - "Banner not found", - )) - } - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - err.Error(), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Banner updated successfully", - banner, - )) -} - -func (bc *BannerController) DeleteBanner(c *fiber.Ctx) error { - id := c.Params("id") - - err := bc.service.DeleteBanner(id) - if err != nil { - if err.Error() == "banner not found" { - return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse( - fiber.StatusNotFound, - "Banner not found", - )) - } - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - err.Error(), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Banner deleted successfully", - nil, - )) -} diff --git a/internal/controllers/coveragearea.go b/internal/controllers/coveragearea.go deleted file mode 100644 index 0b6b988..0000000 --- a/internal/controllers/coveragearea.go +++ /dev/null @@ -1,409 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetCoverageAreas(c *fiber.Ctx) error { - coverageAreas, err := services.GetCoverageAreas() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch coverage areas", - nil, - )) - } - - var coverageAreaResponses []dto.CoverageAreaResponse - for _, area := range coverageAreas { - coverageAreaResponses = append(coverageAreaResponses, dto.NewCoverageAreaResponse( - area.ID, - area.Province, - utils.FormatDateToIndonesianFormat(area.CreatedAt), - utils.FormatDateToIndonesianFormat(area.UpdatedAt), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage areas has been fetched", - coverageAreaResponses, - )) -} - -func GetCoverageAreaByIDProvince(c *fiber.Ctx) error { - id := c.Params("id") - - coverageArea, err := services.GetCoverageAreaByID(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch coverage area details by province", - nil, - )) - } - - var coverageAreaResponse dto.CoverageAreaWithDistrictsResponse - coverageAreaResponse.ID = coverageArea.ID - coverageAreaResponse.Province = coverageArea.Province - coverageAreaResponse.CreatedAt = utils.FormatDateToIndonesianFormat(coverageArea.CreatedAt) - coverageAreaResponse.UpdatedAt = utils.FormatDateToIndonesianFormat(coverageArea.UpdatedAt) - - districts, err := services.GetCoverageDistricsByCoverageAreaID(coverageArea.ID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch coverage districts", - nil, - )) - } - - var coverageAreas []dto.CoverageAreaResponse - for _, district := range districts { - coverageAreas = append(coverageAreas, dto.NewCoverageAreaResponse( - district.ID, - district.District, - utils.FormatDateToIndonesianFormat(district.CreatedAt), - utils.FormatDateToIndonesianFormat(district.UpdatedAt), - )) - } - - coverageAreaResponse.CoverageArea = coverageAreas - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage areas detail by province has been fetched", - coverageAreaResponse, - )) -} - -func GetCoverageAreaByIDDistrict(c *fiber.Ctx) error { - id := c.Params("id") - - coverageDetail, err := services.GetCoverageAreaByDistrictID(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch coverage area details by district", - nil, - )) - } - - coverageArea, err := services.GetCoverageAreaByID(coverageDetail.CoverageAreaID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch coverage area details by province", - nil, - )) - } - - subdistricts, err := services.GetSubdistrictsByCoverageDistrictID(coverageDetail.ID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch subdistricts", - nil, - )) - } - - var subdistrictResponses []dto.SubdistrictResponse - for _, loc := range subdistricts { - subdistrictResponses = append(subdistrictResponses, dto.NewSubdistrictResponse( - loc.ID, - loc.Subdistrict, - utils.FormatDateToIndonesianFormat(loc.CreatedAt), - utils.FormatDateToIndonesianFormat(loc.UpdatedAt), - )) - } - - coverageAreaResponse := dto.NewCoverageAreaDetailWithLocation( - coverageDetail.ID, - coverageArea.Province, - coverageDetail.District, - utils.FormatDateToIndonesianFormat(coverageDetail.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageDetail.UpdatedAt), - subdistrictResponses, - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage areas detail by district has been fetched", - coverageAreaResponse, - )) -} - -func CreateCoverageArea(c *fiber.Ctx) error { - var request dto.CoverageAreaCreateRequest - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - coverageArea, err := services.CreateCoverageArea(request.Province) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create coverage area", - nil, - )) - } - - coverageAreaResponse := dto.NewCoverageAreaResponse( - coverageArea.ID, - coverageArea.Province, - utils.FormatDateToIndonesianFormat(coverageArea.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageArea.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage area has been created", - coverageAreaResponse, - )) -} - -func CreateCoverageDistrict(c *fiber.Ctx) error { - var request dto.CoverageDistrictCreateRequest - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - coverageDistrict, err := services.CreateCoverageDistrict(request.CoverageAreaID, request.District) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create coverage district", - nil, - )) - } - - coverageDistrictResponse := dto.NewCoverageAreaResponse( - coverageDistrict.ID, - coverageDistrict.District, - utils.FormatDateToIndonesianFormat(coverageDistrict.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageDistrict.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage district has been created", - coverageDistrictResponse, - )) -} - -func CreateCoverageSubdistrict(c *fiber.Ctx) error { - - var request dto.CoverageSubdistrictCreateRequest - if err := c.BodyParser(&request); err != nil { - - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - coverageSubdistrict, err := services.CreateCoverageSubdistrict( - request.CoverageAreaID, - request.CoverageDistrictId, - request.Subdistrict, - ) - if err != nil { - - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create coverage subdistrict", - nil, - )) - } - - coverageSubdistrictResponse := dto.NewCoverageAreaResponse( - coverageSubdistrict.ID, - coverageSubdistrict.Subdistrict, - utils.FormatDateToIndonesianFormat(coverageSubdistrict.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageSubdistrict.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage subdistrict has been created", - coverageSubdistrictResponse, - )) -} - -func UpdateCoverageArea(c *fiber.Ctx) error { - id := c.Params("id") - - var request dto.CoverageAreaUpdateRequest - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - coverageArea, err := services.UpdateCoverageArea(id, domain.CoverageArea{ - Province: request.Province, - }) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update coverage area", - nil, - )) - } - - coverageAreaResponse := dto.NewCoverageAreaResponse( - coverageArea.ID, - coverageArea.Province, - utils.FormatDateToIndonesianFormat(coverageArea.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageArea.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage area has been updated", - coverageAreaResponse, - )) -} - -func UpdateCoverageDistrict(c *fiber.Ctx) error { - id := c.Params("id") - - var request dto.CoverageDistrictUpdateRequest - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - coverageDistrict, err := services.UpdateCoverageDistrict(id, domain.CoverageDistric{ - District: request.District, - }) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update coverage district", - nil, - )) - } - - coverageDistrictResponse := dto.NewCoverageAreaResponse( - coverageDistrict.ID, - coverageDistrict.District, - utils.FormatDateToIndonesianFormat(coverageDistrict.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageDistrict.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage district has been updated", - coverageDistrictResponse, - )) -} - -func UpdateCoverageSubdistrict(c *fiber.Ctx) error { - id := c.Params("id") - - var request dto.CoverageSubdistrictUpdateRequest - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - coverageSubdistrict, err := services.UpdateCoverageSubdistrict(id, domain.CoverageSubdistrict{ - Subdistrict: request.Subdistrict, - }) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update coverage subdistrict", - nil, - )) - } - - coverageSubdistrictResponse := dto.NewSubdistrictResponse( - coverageSubdistrict.ID, - coverageSubdistrict.Subdistrict, - utils.FormatDateToIndonesianFormat(coverageSubdistrict.CreatedAt), - utils.FormatDateToIndonesianFormat(coverageSubdistrict.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage subdistrict has been updated", - coverageSubdistrictResponse, - )) -} - -func DeleteCoverageArea(c *fiber.Ctx) error { - id := c.Params("id") - - if err := services.DeleteCoverageArea(id); err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete coverage area", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage area has been deleted", - nil, - )) -} - -func DeleteCoverageDistrict(c *fiber.Ctx) error { - id := c.Params("id") - - if err := services.DeleteCoverageDistrict(id); err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete coverage district", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage district has been deleted", - nil, - )) -} - -func DeleteCoverageSubdistrict(c *fiber.Ctx) error { - id := c.Params("id") - - if err := services.DeleteCoverageSubdistrict(id); err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete coverage subdistrict", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Coverage subdistrict has been deleted", - nil, - )) -} diff --git a/internal/controllers/initialcoint.go b/internal/controllers/initialcoint.go deleted file mode 100644 index f7e1bee..0000000 --- a/internal/controllers/initialcoint.go +++ /dev/null @@ -1,123 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -type PointController struct { - 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 { - return c.Status(fiber.StatusInternalServerError).JSON(utils.ErrorResponse( - fiber.StatusInternalServerError, - "Failed to fetch points", - )) - } - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Points fetched successfully", - points, - )) -} - -func (pc *PointController) GetPointByID(c *fiber.Ctx) error { - id := c.Params("id") - point, err := pc.service.GetPointByID(id) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.ErrorResponse( - fiber.StatusNotFound, - "Point not found", - )) - } - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Point fetched successfully", - point, - )) -} - -func (pc *PointController) CreatePoint(c *fiber.Ctx) error { - var request dto.PointCreateRequest - - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - "Invalid request body", - )) - } - - point, err := pc.service.CreatePoint(&request) - if err != nil { - - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - err.Error(), - )) - } - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Point created successfully", - point, - )) -} - -func (pc *PointController) UpdatePoint(c *fiber.Ctx) error { - id := c.Params("id") - var request dto.PointUpdateRequest - - if err := c.BodyParser(&request); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - "Invalid request body", - )) - } - - point, err := pc.service.UpdatePoint(id, &request) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.ErrorResponse( - fiber.StatusBadRequest, - err.Error(), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Point updated successfully", - point, - )) -} - -func (pc *PointController) DeletePoint(c *fiber.Ctx) error { - id := c.Params("id") - - err := pc.service.DeletePoint(id) - if err != nil { - 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, - err.Error(), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Point deleted successfully", - nil, - )) -} diff --git a/internal/controllers/product.go b/internal/controllers/product.go deleted file mode 100644 index a985015..0000000 --- a/internal/controllers/product.go +++ /dev/null @@ -1,262 +0,0 @@ -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 GetAllProducts(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized: user ID is missing", - nil, - )) - } - - storeID := c.Query("storeID", "") - - limit := c.QueryInt("limit", 10) - page := c.QueryInt("page", 1) - - if limit <= 0 || page <= 0 { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid pagination parameters", - nil, - )) - } - - var products []dto.ProductResponseWithSoldDTO - var err error - - if storeID != "" { - - products, err = services.GetProductsByStoreID(storeID, limit, page) - } else { - - products, err = services.GetProductsByUserID(userID, limit, page) - } - - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch products", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Products fetched successfully", - products, - )) -} - -func GetProductByID(c *fiber.Ctx) error { - storeID, ok := c.Locals("userID").(string) - if !ok || storeID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized: store ID is missing", - nil, - )) - } - - productID := c.Params("productid") - if productID == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Product ID is required", - nil, - )) - } - - product, err := services.GetProductByIDAndStoreID(productID, storeID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Product not found", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Product fetched successfully", - product, - )) -} - -func GetProductsByStore(c *fiber.Ctx) error { - storeID := c.Params("storeid") - if storeID == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Store ID is required", - nil, - )) - } - - limit := c.QueryInt("limit", 10) - page := c.QueryInt("page", 1) - - if limit <= 0 || page <= 0 { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid pagination parameters", - nil, - )) - } - - products, err := services.GetProductsByStoreID(storeID, limit, page) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Store not found", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Products fetched successfully", - products, - )) -} - -func CreateProduct(c *fiber.Ctx) error { - var input dto.CreateProductRequestDTO - - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized: user ID is missing", - nil, - )) - } - - if input.StoreID == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Store ID is required in the body", - nil, - )) - } - - product, err := services.CreateProduct(input, userID) - if err != nil { - return c.Status(fiber.StatusUnprocessableEntity).JSON(utils.FormatResponse( - fiber.StatusUnprocessableEntity, - err.Error(), - nil, - )) - } - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Product created successfully", - product, - )) -} - -func UpdateProduct(c *fiber.Ctx) error { - productID := c.Params("productid") - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized: user ID is missing", - nil, - )) - } - - if productID == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Product ID is required", - nil, - )) - } - - var input dto.UpdateProductRequestDTO - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request payload", - nil, - )) - } - - if err := dto.GetValidator().Struct(input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid product data", - nil, - )) - } - - updatedProduct, err := services.UpdateProduct(productID, input) - if err != nil { - return c.Status(fiber.StatusUnprocessableEntity).JSON(utils.FormatResponse( - fiber.StatusUnprocessableEntity, - err.Error(), - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Product updated successfully", - updatedProduct, - )) -} - -func DeleteProduct(c *fiber.Ctx) error { - productID := c.Params("productid") - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized: user ID is missing", - nil, - )) - } - - if productID == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Product ID is required", - nil, - )) - } - - err := services.DeleteProduct(productID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Product not found or unable to delete", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Product deleted successfully", - nil, - )) -} diff --git a/internal/controllers/request_pickup.go b/internal/controllers/request_pickup.go deleted file mode 100644 index 03dc8ec..0000000 --- a/internal/controllers/request_pickup.go +++ /dev/null @@ -1,203 +0,0 @@ -package controllers - -import ( - "fmt" - - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetRequestPickupsByUser(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "User not authenticated", - nil, - )) - } - - service := services.NewRequestPickupService(repositories.NewRequestPickupRepository()) - - requestPickups, err := service.GetRequestPickupsByUser(userID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch request pickups", - nil, - )) - } - - var requestPickupResponses []dto.RequestPickupResponse - for _, requestPickup := range requestPickups { - userAddress := dto.UserAddressDTO{ - Province: requestPickup.UserAddress.Province, - District: requestPickup.UserAddress.District, - Subdistrict: requestPickup.UserAddress.Subdistrict, - PostalCode: requestPickup.UserAddress.PostalCode, - Village: requestPickup.UserAddress.Village, - Detail: requestPickup.UserAddress.Detail, - Geography: requestPickup.UserAddress.Geography, - } - - var requestItems []dto.RequestItemDTO - for _, item := range requestPickup.Request { - requestItems = append(requestItems, dto.RequestItemDTO{ - TrashCategory: item.TrashCategory.Name, - EstimatedAmount: item.EstimatedAmount, - }) - } - - requestPickupResponses = append(requestPickupResponses, dto.NewRequestPickupResponse( - requestPickup.ID, - requestPickup.UserID, - requestPickup.RequestTime, - requestPickup.StatusRequest, - requestItems, - userAddress, - utils.FormatDateToIndonesianFormat(requestPickup.CreatedAt), - utils.FormatDateToIndonesianFormat(requestPickup.UpdatedAt), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Request pickup by user has been fetched", - requestPickupResponses, - )) -} - -func CreateRequestPickup(c *fiber.Ctx) error { - var req dto.RequestPickupRequest - if err := c.BodyParser(&req); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid request body", - nil, - )) - } - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "User not authenticated", - nil, - )) - } - - if req.UserAddressID == "" || len(req.RequestItems) == 0 { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Missing required fields", - nil, - )) - } - - var requestItems []domain.RequestItem - for _, item := range req.RequestItems { - requestItems = append(requestItems, domain.RequestItem{ - TrashCategoryID: item.TrashCategory, - EstimatedAmount: item.EstimatedAmount, - }) - } - - requestPickup := &domain.RequestPickup{ - UserID: userID, - Request: requestItems, - RequestTime: req.RequestTime, - UserAddressID: req.UserAddressID, - StatusRequest: "Pending", - } - - service := services.NewRequestPickupService(repositories.NewRequestPickupRepository()) - - if err := service.CreateRequestPickup(requestPickup); err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create request pickup", - nil, - )) - } - - detail, err := service.GetRequestPickupByID(requestPickup.ID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch created request pickup", - nil, - )) - } - - var requestItemsDTO []dto.RequestItemDTO - for _, item := range detail.Request { - requestItemsDTO = append(requestItemsDTO, dto.RequestItemDTO{ - TrashCategory: item.TrashCategory.Name, - EstimatedAmount: item.EstimatedAmount, - }) - } - - userAddressDTO := dto.UserAddressDTO{ - Province: detail.UserAddress.Province, - District: detail.UserAddress.District, - Subdistrict: detail.UserAddress.Subdistrict, - PostalCode: detail.UserAddress.PostalCode, - Village: detail.UserAddress.Village, - Detail: detail.UserAddress.Detail, - Geography: detail.UserAddress.Geography, - } - - response := dto.NewRequestPickupResponse( - detail.ID, - detail.UserID, - detail.RequestTime, - detail.StatusRequest, - requestItemsDTO, - userAddressDTO, - utils.FormatDateToIndonesianFormat(detail.CreatedAt), - utils.FormatDateToIndonesianFormat(detail.UpdatedAt), - ) - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Request pickup created successfully", - response, - )) -} - -func DeleteRequestPickup(c *fiber.Ctx) error { - id := c.Params("id") - if id == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Missing required ID", - nil, - )) - } - - service := services.NewRequestPickupService(repositories.NewRequestPickupRepository()) - if err := service.DeleteRequestPickupByID(id); err != nil { - if err.Error() == fmt.Sprintf("request pickup with id %s not found", id) { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Request pickup not found", - nil, - )) - } - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete request pickup", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Request pickup deleted successfully", - nil, - )) -} diff --git a/internal/controllers/role.go b/internal/controllers/role.go deleted file mode 100644 index 6662a0e..0000000 --- a/internal/controllers/role.go +++ /dev/null @@ -1,43 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetUserRoleByID(c *fiber.Ctx) error { - id := c.Params("id") - - role, err := services.GetUserRoleByID(id) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "UserRole tidak ditemukan", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "UserRole ditemukan", - role, - )) -} - -func GetAllUserRoles(c *fiber.Ctx) error { - roles, err := services.GetAllUserRoles() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Gagal mengambil data UserRole", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Daftar UserRole", - roles, - )) -} diff --git a/internal/controllers/store.go b/internal/controllers/store.go deleted file mode 100644 index e50d905..0000000 --- a/internal/controllers/store.go +++ /dev/null @@ -1,70 +0,0 @@ -package controllers - -import ( - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetStoreByID(c *fiber.Ctx) error { - storeID := c.Params("storeid") - if storeID == "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Store ID is required", - nil, - )) - } - - store, err := services.GetStoreByID(storeID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Store not found", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Store fetched successfully", - store, - )) -} - -func GetStoresByUserID(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Unauthorized: user ID is missing", - nil, - )) - } - - limit := c.QueryInt("limit", 0) - page := c.QueryInt("page", 1) - - if limit < 0 || page <= 0 { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid pagination parameters", - nil, - )) - } - - stores, err := services.GetStoresByUserID(userID, limit, page) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch stores", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Stores fetched successfully", - stores, - )) -} diff --git a/internal/controllers/trashtype.go b/internal/controllers/trashtype.go deleted file mode 100644 index 6f98f64..0000000 --- a/internal/controllers/trashtype.go +++ /dev/null @@ -1,293 +0,0 @@ -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 GetTrashCategories(c *fiber.Ctx) error { - trashCategories, err := services.GetTrashCategories() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch trash categories", - nil, - )) - } - - var response []dto.TrashCategoryResponse - for _, category := range trashCategories { - - response = append(response, dto.NewTrashCategoryResponse( - category.ID, - category.Name, - utils.FormatDateToIndonesianFormat(category.CreatedAt), - utils.FormatDateToIndonesianFormat(category.UpdatedAt), - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Trash categories fetched successfully", - response, - )) -} - -func GetTrashCategoryDetail(c *fiber.Ctx) error { - id := c.Params("id") - - trashCategoryDetail, err := services.GetTrashCategoryDetail(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch trash category detail", - nil, - )) - } - - detailResponse := dto.NewTrashCategoryResponse( - trashCategoryDetail.ID, - trashCategoryDetail.Name, - utils.FormatDateToIndonesianFormat(trashCategoryDetail.CreatedAt), - utils.FormatDateToIndonesianFormat(trashCategoryDetail.UpdatedAt), - ) - - var detailResponseList []dto.TrashDetailResponse - if trashCategoryDetail.Details != nil { - for _, detail := range trashCategoryDetail.Details { - detailResponseList = append(detailResponseList, dto.NewTrashDetailResponse( - detail.ID, - detail.Description, - detail.Price, - utils.FormatDateToIndonesianFormat(detail.CreatedAt), - utils.FormatDateToIndonesianFormat(detail.UpdatedAt), - )) - } - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Trash category detail fetched successfully", - struct { - Category dto.TrashCategoryResponse `json:"category"` - Details []dto.TrashDetailResponse `json:"details,omitempty"` - }{ - Category: detailResponse, - Details: detailResponseList, - }, - )) -} - -func CreateTrashCategory(c *fiber.Ctx) error { - var categoryInput dto.TrashCategoryDTO - - if err := c.BodyParser(&categoryInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := categoryInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Validation failed: "+err.Error(), - nil, - )) - } - - newCategory, err := services.CreateTrashCategory(categoryInput.Name) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create trash category", - nil, - )) - } - - categoryResponse := map[string]interface{}{ - "id": newCategory.ID, - "name": newCategory.Name, - "createdAt": newCategory.CreatedAt, - "updatedAt": newCategory.UpdatedAt, - } - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Trash category created successfully", - categoryResponse, - )) -} - -func CreateTrashDetail(c *fiber.Ctx) error { - var detailInput dto.TrashDetailDTO - - if err := c.BodyParser(&detailInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := detailInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Validation failed: "+err.Error(), - nil, - )) - } - - newDetail, err := services.CreateTrashDetail(detailInput.CategoryID, detailInput.Description, detailInput.Price) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create trash detail", - nil, - )) - } - - detailResponse := map[string]interface{}{ - "id": newDetail.ID, - "description": newDetail.Description, - "price": newDetail.Price, - "createdAt": newDetail.CreatedAt, - "updatedAt": newDetail.UpdatedAt, - } - - return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( - fiber.StatusCreated, - "Trash detail created successfully", - detailResponse, - )) -} - -func UpdateTrashCategory(c *fiber.Ctx) error { - id := c.Params("id") - - var categoryInput dto.UpdateTrashCategoryDTO - if err := c.BodyParser(&categoryInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := categoryInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Validation failed: "+err.Error(), - nil, - )) - } - - updatedCategory, err := services.UpdateTrashCategory(id, categoryInput.Name) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update trash category", - nil, - )) - } - - response := dto.NewTrashCategoryResponse( - updatedCategory.ID, - updatedCategory.Name, - utils.FormatDateToIndonesianFormat(updatedCategory.CreatedAt), - utils.FormatDateToIndonesianFormat(updatedCategory.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Trash category updated successfully", - response, - )) -} - -func UpdateTrashDetail(c *fiber.Ctx) error { - id := c.Params("id") - - var detailInput dto.UpdateTrashDetailDTO - if err := c.BodyParser(&detailInput); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Invalid input data", - nil, - )) - } - - if err := detailInput.Validate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Validation failed: "+err.Error(), - nil, - )) - } - - updatedDetail, err := services.UpdateTrashDetail(id, detailInput.Description, detailInput.Price) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update trash detail", - nil, - )) - } - - response := dto.NewTrashDetailResponse( - updatedDetail.ID, - updatedDetail.Description, - updatedDetail.Price, - utils.FormatDateToIndonesianFormat(updatedDetail.CreatedAt), - utils.FormatDateToIndonesianFormat(updatedDetail.UpdatedAt), - ) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Trash detail updated successfully", - response, - )) -} - -func DeleteTrashCategory(c *fiber.Ctx) error { - id := c.Params("id") - - err := services.DeleteTrashCategory(id) - if err != nil { - - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete trash category", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Trash category deleted successfully", - nil, - )) -} - -func DeleteTrashDetail(c *fiber.Ctx) error { - id := c.Params("id") - - err := services.DeleteTrashDetail(id) - if err != nil { - - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to delete trash detail", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Trash detail deleted successfully", - nil, - )) -} diff --git a/internal/controllers/user.go b/internal/controllers/user.go deleted file mode 100644 index cad2efc..0000000 --- a/internal/controllers/user.go +++ /dev/null @@ -1,75 +0,0 @@ -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 GetListUsers(c *fiber.Ctx) error { - users, err := services.GetUsers() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch users", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Users fetched successfully", - users, - )) -} - -func GetUsersByRole(c *fiber.Ctx) error { - roleID := c.Params("roleID") - - users, err := services.GetUsersByRole(roleID) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch users by role", - nil, - )) - } - - if len(users) == 0 { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "No users found for the specified role", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "Users fetched successfully", - users, - )) -} - -func GetUserByUserID(c *fiber.Ctx) error { - userID := c.Params("userID") - - user, err := services.GetUserByUserID(userID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "User not found", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "User fetched successfully", - struct { - User dto.UserResponseDTO `json:"user"` - }{ - User: user, - }, - )) -} diff --git a/internal/controllers/userpin.go b/internal/controllers/userpin.go deleted file mode 100644 index a92f4aa..0000000 --- a/internal/controllers/userpin.go +++ /dev/null @@ -1,240 +0,0 @@ -package controllers - -import ( - "time" - - "github.com/go-redis/redis/v8" - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/services" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func CreatePin(c *fiber.Ctx) error { - var input dto.PinInput - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Data input tidak valid", - nil, - )) - } - - if err := input.ValidateCreate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - userID := c.Locals("userID").(string) - - redisPin, err := config.RedisClient.Get(c.Context(), "pin:"+userID).Result() - if err != nil && err != redis.Nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to check PIN from Redis", - nil, - )) - } - - if redisPin != "" { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "PIN sudah ada, tidak perlu dibuat lagi", - nil, - )) - } - - pin, err := services.CreatePin(userID, input) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to create PIN", - nil, - )) - } - - err = config.RedisClient.Set(c.Context(), "pin:"+userID, pin.Pin, time.Minute*30).Err() - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to save PIN to Redis", - nil, - )) - } - - formattedCreatedAt := utils.FormatDateToIndonesianFormat(pin.CreatedAt) - - pinResponse := dto.PinResponse{ - CreatedAt: formattedCreatedAt, - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "PIN created successfully", - pinResponse, - )) -} - -func GetPinStatus(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - _, err := config.RedisClient.Get(c.Context(), "pin:"+userID).Result() - if err == redis.Nil { - - pin, err := services.GetPinByUserID(userID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Anda belum membuat PIN", - nil, - )) - } - - formattedCreatedAt := utils.FormatDateToIndonesianFormat(pin.CreatedAt) - formattedUpdatedAt := utils.FormatDateToIndonesianFormat(pin.UpdatedAt) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "PIN sudah dibuat", - map[string]interface{}{ - "createdAt": formattedCreatedAt, - "updatedAt": formattedUpdatedAt, - }, - )) - } else if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch PIN from Redis", - nil, - )) - } - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "PIN sudah dibuat", - map[string]interface{}{ - "createdAt": "PIN ditemukan di Redis", - "updatedAt": "PIN ditemukan di Redis", - }, - )) -} - -func GetPin(c *fiber.Ctx) error { - var input dto.PinInput - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Data input tidak valid", - nil, - )) - } - - userID := c.Locals("userID").(string) - - redisPin, err := config.RedisClient.Get(c.Context(), "pin:"+userID).Result() - if err == redis.Nil { - - pin, err := services.GetPinByUserID(userID) - if err != nil { - return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( - fiber.StatusNotFound, - "Sepertinya anda belum membuat pin", - nil, - )) - } - - isPinValid := services.CheckPin(pin.Pin, input.Pin) - if isPinValid { - - config.RedisClient.Set(c.Context(), "pin:"+userID, pin.Pin, time.Minute*30) - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "PIN benar", - true, - )) - } - - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "PIN salah", - false, - )) - } else if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to fetch PIN from Redis", - nil, - )) - } - - isPinValid := services.CheckPin(redisPin, input.Pin) - if isPinValid { - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "PIN benar", - true, - )) - } - - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "PIN salah", - false, - )) -} - -func UpdatePin(c *fiber.Ctx) error { - var input dto.PinUpdateInput - if err := c.BodyParser(&input); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - "Data input tidak valid", - nil, - )) - } - - if err := input.ValidateUpdate(); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( - fiber.StatusBadRequest, - err.Error(), - nil, - )) - } - - userID := c.Locals("userID").(string) - - updatedPin, err := services.UpdatePin(userID, input.OldPin, input.NewPin) - if err != nil { - if err.Error() == "PIN lama salah" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "PIN lama salah", - nil, - )) - } - - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, - "Failed to update PIN", - nil, - )) - } - - config.RedisClient.Del(c.Context(), "pin:"+userID) - config.RedisClient.Set(c.Context(), "pin:"+userID, updatedPin.Pin, time.Minute*30) - - formattedUpdatedAt := utils.FormatDateToIndonesianFormat(updatedPin.UpdatedAt) - - return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( - fiber.StatusOK, - "PIN updated successfully", - map[string]interface{}{ - "id": updatedPin.ID, - "updatedAt": formattedUpdatedAt, - }, - )) -} diff --git a/internal/handler/auth_handler.go b/internal/handler/auth_handler.go new file mode 100644 index 0000000..bc25077 --- /dev/null +++ b/internal/handler/auth_handler.go @@ -0,0 +1,40 @@ +package handler + +import ( + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/services" + "github.com/pahmiudahgede/senggoldong/utils" + "golang.org/x/crypto/bcrypt" +) + +type UserHandler struct { + UserService services.UserService +} + +func NewUserHandler(userService services.UserService) *UserHandler { + return &UserHandler{UserService: userService} +} + +func (h *UserHandler) Login(c *fiber.Ctx) error { + var loginDTO dto.LoginDTO + if err := c.BodyParser(&loginDTO); err != nil { + return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) + } + + user, err := h.UserService.Login(loginDTO) + if err != nil { + if err.Error() == "user not found" { + + return utils.ErrorResponse(c, "User not found") + } + if err == bcrypt.ErrMismatchedHashAndPassword { + + return utils.ErrorResponse(c, "Invalid password") + } + + return utils.InternalServerErrorResponse(c, "Error logging in") + } + + return utils.LogResponse(c, user, "Login successful") +} diff --git a/internal/middleware/api_secure.go b/internal/middleware/api_secure.go deleted file mode 100644 index a8b848e..0000000 --- a/internal/middleware/api_secure.go +++ /dev/null @@ -1,54 +0,0 @@ -package middleware - -import ( - "context" - "fmt" - "os" - "time" - - "github.com/gofiber/fiber/v2" - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func APIKeyMiddleware(c *fiber.Ctx) error { - apiKey := c.Get("x-api-key") - expectedAPIKey := os.Getenv("API_KEY") - - if apiKey != expectedAPIKey { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid API Key", - nil, - )) - } - - 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() -} diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go deleted file mode 100644 index 2e3fdf7..0000000 --- a/internal/middleware/auth.go +++ /dev/null @@ -1,148 +0,0 @@ -package middleware - -import ( - "context" - "errors" - "os" - "strings" - "time" - - "github.com/gofiber/fiber/v2" - "github.com/golang-jwt/jwt/v5" - "github.com/pahmiudahgede/senggoldong/config" - "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 { - return func(c *fiber.Ctx) error { - tokenString := strings.TrimPrefix(c.Get("Authorization"), "Bearer ") - if tokenString == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Token is required", - nil, - )) - } - - ctx := context.Background() - cachedToken, err := config.RedisClient.Get(ctx, "auth_token:"+tokenString).Result() - if err != nil || cachedToken == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid or expired token", - nil, - )) - } - - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { - if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { - return nil, errors.New("unexpected signing method") - } - return []byte(os.Getenv("API_KEY")), nil - }) - if err != nil || !token.Valid { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid or expired token", - nil, - )) - } - - claims, ok := token.Claims.(jwt.MapClaims) - if !ok { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid token claims", - nil, - )) - } - - userID, ok := claims["sub"].(string) - if !ok || userID == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Missing or invalid user ID in token", - nil, - )) - } - - role, ok := claims["role"].(string) - if !ok || role == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Missing or invalid role in token", - nil, - )) - } - - c.Locals("userID", userID) - c.Locals("role", role) - - if !containsRole(roles, role) { - return c.Status(fiber.StatusForbidden).JSON(utils.FormatResponse( - fiber.StatusForbidden, - "You do not have permission to access this resource", - nil, - )) - } - - return c.Next() - } -} - -func AuthMiddleware(c *fiber.Ctx) error { - tokenString := strings.TrimPrefix(c.Get("Authorization"), "Bearer ") - if tokenString == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Missing or invalid token", - nil, - )) - } - - ctx := context.Background() - cachedToken, err := config.RedisClient.Get(ctx, "auth_token:"+tokenString).Result() - if err != nil || cachedToken == "" { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid or expired token", - nil, - )) - } - - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { - return []byte(os.Getenv("API_KEY")), nil - }) - if err != nil || !token.Valid { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid or expired token", - nil, - )) - } - - claims, ok := token.Claims.(jwt.MapClaims) - if !ok { - return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( - fiber.StatusUnauthorized, - "Invalid token claims", - nil, - )) - } - - userID := claims["sub"].(string) - c.Locals("userID", userID) - - config.RedisClient.Expire(ctx, "auth_token:"+tokenString, time.Hour*24) - - return c.Next() -} \ No newline at end of file diff --git a/internal/repositories/Indonesian_territory.go b/internal/repositories/Indonesian_territory.go deleted file mode 100644 index 0789992..0000000 --- a/internal/repositories/Indonesian_territory.go +++ /dev/null @@ -1,205 +0,0 @@ -package repositories - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetProvinces() ([]domain.Province, error) { - records, err := utils.ReadCSV("public/document/provinces.csv") - if err != nil { - return nil, err - } - - var provinces []domain.Province - for _, record := range records { - province := domain.Province{ - ID: record[0], - Name: record[1], - } - provinces = append(provinces, province) - } - - return provinces, nil -} - -func GetRegencies() ([]domain.Regency, error) { - records, err := utils.ReadCSV("public/document/regencies.csv") - if err != nil { - return nil, err - } - - var regencies []domain.Regency - for _, record := range records { - regency := domain.Regency{ - ID: record[0], - ProvinceID: record[1], - Name: record[2], - } - regencies = append(regencies, regency) - } - - return regencies, nil -} - -func GetDistricts() ([]domain.District, error) { - records, err := utils.ReadCSV("public/document/districts.csv") - if err != nil { - return nil, err - } - - var districts []domain.District - for _, record := range records { - district := domain.District{ - ID: record[0], - RegencyID: record[1], - Name: record[2], - } - districts = append(districts, district) - } - - return districts, nil -} - -func GetVillages() ([]domain.Village, error) { - records, err := utils.ReadCSV("public/document/villages.csv") - if err != nil { - return nil, err - } - - var villages []domain.Village - for _, record := range records { - village := domain.Village{ - ID: record[0], - DistrictID: record[1], - Name: record[2], - } - villages = append(villages, village) - } - - return villages, nil -} - -func GetProvinceByID(id string) (domain.Province, error) { - provinces, err := GetProvinces() - if err != nil { - return domain.Province{}, err - } - - for _, province := range provinces { - if province.ID == id { - - regencies, err := GetRegenciesByProvinceID(id) - if err != nil { - return domain.Province{}, err - } - - province.ListRegency = regencies - return province, nil - } - } - return domain.Province{}, errors.New("province not found") -} - -func GetRegencyByID(id string) (domain.Regency, error) { - regencies, err := GetRegencies() - if err != nil { - return domain.Regency{}, err - } - - for _, regency := range regencies { - if regency.ID == id { - - districts, err := GetDistrictsByRegencyID(id) - if err != nil { - return domain.Regency{}, err - } - - regency.ListDistrict = districts - return regency, nil - } - } - return domain.Regency{}, errors.New("regency not found") -} - -func GetDistrictByID(id string) (domain.District, error) { - districts, err := GetDistricts() - if err != nil { - return domain.District{}, err - } - - for _, district := range districts { - if district.ID == id { - - villages, err := GetVillagesByDistrictID(id) - if err != nil { - return domain.District{}, err - } - - district.ListVillage = villages - return district, nil - } - } - return domain.District{}, errors.New("district not found") -} - -func GetVillageByID(id string) (domain.Village, error) { - villages, err := GetVillages() - if err != nil { - return domain.Village{}, err - } - - for _, village := range villages { - if village.ID == id { - return village, nil - } - } - return domain.Village{}, errors.New("village not found") -} - -func GetRegenciesByProvinceID(provinceID string) ([]domain.Regency, error) { - regencies, err := GetRegencies() - if err != nil { - return nil, err - } - - var result []domain.Regency - for _, regency := range regencies { - if regency.ProvinceID == provinceID { - result = append(result, regency) - } - } - return result, nil -} - -func GetDistrictsByRegencyID(regencyID string) ([]domain.District, error) { - districts, err := GetDistricts() - if err != nil { - return nil, err - } - - var result []domain.District - for _, district := range districts { - if district.RegencyID == regencyID { - result = append(result, district) - } - } - return result, nil -} - -func GetVillagesByDistrictID(districtID string) ([]domain.Village, error) { - villages, err := GetVillages() - if err != nil { - return nil, err - } - - var result []domain.Village - for _, village := range villages { - if village.DistrictID == districtID { - result = append(result, village) - } - } - return result, nil -} diff --git a/internal/repositories/address.go b/internal/repositories/address.go deleted file mode 100644 index 1699f1a..0000000 --- a/internal/repositories/address.go +++ /dev/null @@ -1,83 +0,0 @@ -package repositories - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -func CreateAddress(address *domain.Address) error { - result := config.DB.Create(address) - if result.Error != nil { - return result.Error - } - - cacheKey := fmt.Sprintf("address:user:%s", address.UserID) - config.RedisClient.Del(context.Background(), cacheKey) - - return nil -} - -func GetAddressesByUserID(userID string) ([]domain.Address, error) { - ctx := context.Background() - cacheKey := fmt.Sprintf("address:user:%s", userID) - - cachedAddresses, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil { - var addresses []domain.Address - if json.Unmarshal([]byte(cachedAddresses), &addresses) == nil { - return addresses, nil - } - } - - var addresses []domain.Address - err = config.DB.Where("user_id = ?", userID).Find(&addresses).Error - if err != nil { - return nil, err - } - - addressesJSON, _ := json.Marshal(addresses) - config.RedisClient.Set(ctx, cacheKey, addressesJSON, time.Hour).Err() - - return addresses, nil -} - -func GetAddressByID(addressID string) (domain.Address, error) { - var address domain.Address - if err := config.DB.Where("id = ?", addressID).First(&address).Error; err != nil { - return address, errors.New("address not found") - } - return address, nil -} - -func UpdateAddress(address domain.Address) (domain.Address, error) { - if err := config.DB.Save(&address).Error; err != nil { - return address, err - } - - cacheKey := fmt.Sprintf("address:user:%s", address.UserID) - config.RedisClient.Del(context.Background(), cacheKey) - - return address, nil -} - -func DeleteAddress(addressID string) error { - var address domain.Address - if err := config.DB.Where("id = ?", addressID).First(&address).Error; err != nil { - return err - } - - if err := config.DB.Delete(&address).Error; err != nil { - return err - } - - cacheKey := fmt.Sprintf("address:user:%s", address.UserID) - config.RedisClient.Del(context.Background(), cacheKey) - - return nil -} diff --git a/internal/repositories/article.go b/internal/repositories/article.go deleted file mode 100644 index 7ef8822..0000000 --- a/internal/repositories/article.go +++ /dev/null @@ -1,44 +0,0 @@ -package repositories - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -type ArticleRepository struct{} - -func NewArticleRepository() *ArticleRepository { - return &ArticleRepository{} -} - -func (r *ArticleRepository) GetAll() ([]domain.Article, error) { - var articles []domain.Article - err := config.DB.Find(&articles).Error - if err != nil { - return nil, errors.New("failed to fetch articles from database") - } - return articles, nil -} - -func (r *ArticleRepository) GetByID(id string) (*domain.Article, error) { - var article domain.Article - err := config.DB.First(&article, "id = ?", id).Error - if err != nil { - return nil, errors.New("article not found") - } - return &article, nil -} - -func (r *ArticleRepository) Create(article *domain.Article) error { - return config.DB.Create(article).Error -} - -func (r *ArticleRepository) Update(article *domain.Article) error { - return config.DB.Save(article).Error -} - -func (r *ArticleRepository) Delete(article *domain.Article) error { - return config.DB.Delete(article).Error -} \ No newline at end of file diff --git a/internal/repositories/auth.go b/internal/repositories/auth.go deleted file mode 100644 index c865c5e..0000000 --- a/internal/repositories/auth.go +++ /dev/null @@ -1,176 +0,0 @@ -package repositories - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -func IsEmailExist(email, roleId string) bool { - ctx := context.Background() - cacheKey := fmt.Sprintf("email:%s", email) - cachedRole, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedRole == roleId { - return true - } - - var user domain.User - if err := config.DB.Where("email = ?", email).First(&user).Error; err == nil { - if user.RoleID == roleId { - if err := config.RedisClient.Set(ctx, cacheKey, roleId, 24*time.Hour).Err(); err != nil { - log.Printf("Redis Set error: %v", err) - } - return true - } - } - return false -} - -func IsUsernameExist(username, roleId string) bool { - ctx := context.Background() - cacheKey := fmt.Sprintf("username:%s", username) - cachedRole, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedRole == roleId { - return true - } - - var user domain.User - if err := config.DB.Where("username = ?", username).First(&user).Error; err == nil { - if user.RoleID == roleId { - if err := config.RedisClient.Set(ctx, cacheKey, roleId, 24*time.Hour).Err(); err != nil { - log.Printf("Redis Set error: %v", err) - } - return true - } - } - return false -} - -func IsPhoneExist(phone, roleId string) bool { - ctx := context.Background() - cacheKey := fmt.Sprintf("phone:%s", phone) - cachedRole, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedRole == roleId { - return true - } - - var user domain.User - if err := config.DB.Where("phone = ?", phone).First(&user).Error; err == nil { - if user.RoleID == roleId { - if err := config.RedisClient.Set(ctx, cacheKey, roleId, 24*time.Hour).Err(); err != nil { - log.Printf("Redis Set error: %v", err) - } - return true - } - } - return false -} - -func CreateUser(username, name, email, phone, password, roleId string) error { - user := domain.User{ - Username: username, - Name: name, - Email: email, - Phone: phone, - Password: password, - RoleID: roleId, - } - - result := config.DB.Create(&user) - if result.Error != nil { - return errors.New("failed to create user") - } - return nil -} - -func GetUserByEmailUsernameOrPhone(identifier, roleId string) (domain.User, error) { - ctx := context.Background() - cacheKey := fmt.Sprintf("user:%s", identifier) - var user domain.User - - cachedUser, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil { - if err := json.Unmarshal([]byte(cachedUser), &user); err == nil { - if roleId == "" || user.RoleID == roleId { - return user, nil - } - } - } - - err = config.DB.Where("email = ? OR username = ? OR phone = ?", identifier, identifier, identifier).First(&user).Error - if err != nil { - return user, errors.New("user not found") - } - - if roleId != "" && user.RoleID != roleId { - return user, errors.New("identifier found but role does not match") - } - - userJSON, _ := json.Marshal(user) - if err := config.RedisClient.Set(ctx, cacheKey, userJSON, 1*time.Hour).Err(); err != nil { - log.Printf("Redis Set error: %v", err) - } - return user, nil -} - -func GetUserByID(userID string) (domain.User, error) { - ctx := context.Background() - cacheKey := fmt.Sprintf("user:%s", userID) - var user domain.User - - cachedUser, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil { - if err := json.Unmarshal([]byte(cachedUser), &user); err == nil { - return user, nil - } - } - - if err := config.DB.Preload("Role").Where("id = ?", userID).First(&user).Error; err != nil { - return user, errors.New("user not found") - } - - userJSON, _ := json.Marshal(user) - if err := config.RedisClient.Set(ctx, cacheKey, userJSON, 1*time.Hour).Err(); err != nil { - log.Printf("Redis Set error: %v", err) - } - - return user, nil -} - -func UpdateUser(user *domain.User) error { - if err := config.DB.Save(user).Error; err != nil { - return errors.New("failed to update user") - } - cacheKey := fmt.Sprintf("user:%s", user.ID) - if err := config.RedisClient.Del(context.Background(), cacheKey).Err(); err != nil { - log.Printf("Redis Del error: %v", err) - } - return nil -} - -func UpdateUserPassword(userID, newPassword string) error { - var user domain.User - - if err := config.DB.Where("id = ?", userID).First(&user).Error; err != nil { - return errors.New("user not found") - } - - user.Password = newPassword - - if err := config.DB.Save(&user).Error; err != nil { - return errors.New("failed to update password") - } - - cacheKey := fmt.Sprintf("user:%s", userID) - if err := config.RedisClient.Del(context.Background(), cacheKey).Err(); err != nil { - log.Printf("Redis Del error: %v", err) - } - - return nil -} diff --git a/internal/repositories/auth_repo.go b/internal/repositories/auth_repo.go new file mode 100644 index 0000000..5035d32 --- /dev/null +++ b/internal/repositories/auth_repo.go @@ -0,0 +1,27 @@ +package repositories + +import ( + "github.com/pahmiudahgede/senggoldong/model" + "gorm.io/gorm" +) + +type UserRepository interface { + FindByEmailOrUsernameOrPhone(identifier string) (*model.User, error) +} + +type userRepository struct { + DB *gorm.DB +} + +func NewUserRepository(db *gorm.DB) UserRepository { + return &userRepository{DB: db} +} + +func (r *userRepository) FindByEmailOrUsernameOrPhone(identifier string) (*model.User, error) { + var user model.User + err := r.DB.Where("email = ? OR username = ? OR phone = ?", identifier, identifier, identifier).First(&user).Error + if err != nil { + return nil, err + } + return &user, nil +} diff --git a/internal/repositories/banner.go b/internal/repositories/banner.go deleted file mode 100644 index 857f122..0000000 --- a/internal/repositories/banner.go +++ /dev/null @@ -1,44 +0,0 @@ -package repositories - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -type BannerRepository struct{} - -func NewBannerRepository() *BannerRepository { - return &BannerRepository{} -} - -func (r *BannerRepository) GetAll() ([]domain.Banner, error) { - var banners []domain.Banner - err := config.DB.Find(&banners).Error - if err != nil { - return nil, errors.New("failed to fetch banners from database") - } - return banners, nil -} - -func (r *BannerRepository) GetByID(id string) (*domain.Banner, error) { - var banner domain.Banner - err := config.DB.First(&banner, "id = ?", id).Error - if err != nil { - return nil, errors.New("banner not found") - } - return &banner, nil -} - -func (r *BannerRepository) Create(banner *domain.Banner) error { - return config.DB.Create(banner).Error -} - -func (r *BannerRepository) Update(banner *domain.Banner) error { - return config.DB.Save(banner).Error -} - -func (r *BannerRepository) Delete(banner *domain.Banner) error { - return config.DB.Delete(banner).Error -} diff --git a/internal/repositories/coveragearea.go b/internal/repositories/coveragearea.go deleted file mode 100644 index 6eb9022..0000000 --- a/internal/repositories/coveragearea.go +++ /dev/null @@ -1,148 +0,0 @@ -package repositories - -import ( - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -func GetCoverageAreas() ([]domain.CoverageArea, error) { - var coverageAreas []domain.CoverageArea - if err := config.DB.Find(&coverageAreas).Error; err != nil { - return nil, err - } - return coverageAreas, nil -} - -func GetCoverageAreaByID(id string) (domain.CoverageArea, error) { - var coverageArea domain.CoverageArea - if err := config.DB.Where("id = ?", id).First(&coverageArea).Error; err != nil { - return coverageArea, err - } - return coverageArea, nil -} - -func GetCoverageAreaByDistrictID(id string) (domain.CoverageDistric, error) { - var coverageDistric domain.CoverageDistric - if err := config.DB.Where("id = ?", id).First(&coverageDistric).Error; err != nil { - return coverageDistric, err - } - return coverageDistric, nil -} - -func GetCoverageDistricsByCoverageAreaID(areaID string) ([]domain.CoverageDistric, error) { - var districts []domain.CoverageDistric - if err := config.DB.Where("coverage_area_id = ?", areaID).Find(&districts).Error; err != nil { - return nil, err - } - return districts, nil -} - -func GetSubdistrictsByCoverageDistrictID(districtID string) ([]domain.CoverageSubdistrict, error) { - var subdistricts []domain.CoverageSubdistrict - if err := config.DB.Where("coverage_district_id = ?", districtID).Find(&subdistricts).Error; err != nil { - return nil, err - } - return subdistricts, nil -} - -func CreateCoverageArea(coverageArea *domain.CoverageArea) error { - if err := config.DB.Create(&coverageArea).Error; err != nil { - return err - } - return nil -} - -func CreateCoverageDistrict(coverageDistrict *domain.CoverageDistric) error { - if err := config.DB.Create(&coverageDistrict).Error; err != nil { - return err - } - return nil -} - -func CreateCoverageSubdistrict(coverageSubdistrict *domain.CoverageSubdistrict) error { - if err := config.DB.Create(&coverageSubdistrict).Error; err != nil { - return err - } - return nil -} - -func UpdateCoverageArea(id string, coverageArea domain.CoverageArea) (domain.CoverageArea, error) { - var existingCoverageArea domain.CoverageArea - if err := config.DB.Where("id = ?", id).First(&existingCoverageArea).Error; err != nil { - return existingCoverageArea, err - } - - existingCoverageArea.Province = coverageArea.Province - if err := config.DB.Save(&existingCoverageArea).Error; err != nil { - return existingCoverageArea, err - } - - return existingCoverageArea, nil -} - -func UpdateCoverageDistrict(id string, coverageDistrict domain.CoverageDistric) (domain.CoverageDistric, error) { - var existingCoverageDistrict domain.CoverageDistric - if err := config.DB.Where("id = ?", id).First(&existingCoverageDistrict).Error; err != nil { - return existingCoverageDistrict, err - } - - existingCoverageDistrict.District = coverageDistrict.District - if err := config.DB.Save(&existingCoverageDistrict).Error; err != nil { - return existingCoverageDistrict, err - } - - return existingCoverageDistrict, nil -} - -func UpdateCoverageSubdistrict(id string, coverageSubdistrict domain.CoverageSubdistrict) (domain.CoverageSubdistrict, error) { - var existingCoverageSubdistrict domain.CoverageSubdistrict - if err := config.DB.Where("id = ?", id).First(&existingCoverageSubdistrict).Error; err != nil { - return existingCoverageSubdistrict, err - } - - existingCoverageSubdistrict.Subdistrict = coverageSubdistrict.Subdistrict - if err := config.DB.Save(&existingCoverageSubdistrict).Error; err != nil { - return existingCoverageSubdistrict, err - } - - return existingCoverageSubdistrict, nil -} - -func DeleteCoverageArea(id string) error { - var coverageArea domain.CoverageArea - if err := config.DB.Where("id = ?", id).First(&coverageArea).Error; err != nil { - return err - } - - if err := config.DB.Delete(&coverageArea).Error; err != nil { - return err - } - - return nil -} - -func DeleteCoverageDistrict(id string) error { - var coverageDistrict domain.CoverageDistric - if err := config.DB.Where("id = ?", id).First(&coverageDistrict).Error; err != nil { - return err - } - - if err := config.DB.Delete(&coverageDistrict).Error; err != nil { - return err - } - - return nil -} - -func DeleteCoverageSubdistrict(id string) error { - var coverageSubdistrict domain.CoverageSubdistrict - if err := config.DB.Where("id = ?", id).First(&coverageSubdistrict).Error; err != nil { - return err - } - - if err := config.DB.Delete(&coverageSubdistrict).Error; err != nil { - return err - } - - return nil -} diff --git a/internal/repositories/initialcoint.go b/internal/repositories/initialcoint.go deleted file mode 100644 index ab0b0c6..0000000 --- a/internal/repositories/initialcoint.go +++ /dev/null @@ -1,44 +0,0 @@ -package repositories - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -type PointRepository struct{} - -func NewPointRepository() *PointRepository { - return &PointRepository{} -} - -func (r *PointRepository) GetAll() ([]domain.Point, error) { - var points []domain.Point - err := config.DB.Find(&points).Error - if err != nil { - return nil, errors.New("failed to fetch points from database") - } - return points, nil -} - -func (r *PointRepository) GetByID(id string) (*domain.Point, error) { - var point domain.Point - err := config.DB.First(&point, "id = ?", id).Error - if err != nil { - return nil, errors.New("point not found") - } - return &point, nil -} - -func (r *PointRepository) Create(point *domain.Point) error { - return config.DB.Create(point).Error -} - -func (r *PointRepository) Update(point *domain.Point) error { - return config.DB.Save(point).Error -} - -func (r *PointRepository) Delete(point *domain.Point) error { - return config.DB.Delete(point).Error -} \ No newline at end of file diff --git a/internal/repositories/product.go b/internal/repositories/product.go deleted file mode 100644 index 703a437..0000000 --- a/internal/repositories/product.go +++ /dev/null @@ -1,108 +0,0 @@ -package repositories - -import ( - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" - "gorm.io/gorm" -) - -func GetProductsByStoreID(storeID string, limit, offset int) ([]domain.Product, error) { - var products []domain.Product - query := config.DB.Preload("ProductImages").Preload("TrashDetail").Where("store_id = ?", storeID) - - if limit > 0 { - query = query.Limit(limit).Offset(offset) - } - - err := query.Find(&products).Error - return products, err -} - -func GetProductsByUserID(userID string, limit, offset int) ([]domain.Product, error) { - var products []domain.Product - query := config.DB.Preload("ProductImages").Preload("TrashDetail").Where("user_id = ?", userID) - - if limit > 0 { - query = query.Limit(limit).Offset(offset) - } - - err := query.Find(&products).Error - return products, err -} - -func GetProductByIDAndStoreID(productID, storeID string) (domain.Product, error) { - var product domain.Product - err := config.DB.Preload("ProductImages").Preload("TrashDetail"). - Where("id = ? AND store_id = ?", productID, storeID). - First(&product).Error - - return product, err -} - -func GetProductByID(productID string) (domain.Product, error) { - var product domain.Product - err := config.DB.Preload("ProductImages").Preload("TrashDetail"). - Where("id = ?", productID).First(&product).Error - return product, err -} - -func IsValidStoreID(storeID string) bool { - var count int64 - err := config.DB.Model(&domain.Store{}).Where("id = ?", storeID).Count(&count).Error - if err != nil || count == 0 { - return false - } - return true -} - -func CreateProduct(product *domain.Product, images []domain.ProductImage) error { - - return config.DB.Transaction(func(tx *gorm.DB) error { - - if err := tx.Create(product).Error; err != nil { - return err - } - - if len(images) > 0 { - for i := range images { - images[i].ProductID = product.ID - } - - if err := tx.Create(&images).Error; err != nil { - return err - } - } - - return nil - }) -} - -func UpdateProduct(product *domain.Product, images []domain.ProductImage) error { - return config.DB.Transaction(func(tx *gorm.DB) error { - - if err := tx.Save(product).Error; err != nil { - return err - } - - if len(images) > 0 { - for i := range images { - images[i].ProductID = product.ID - } - - if err := tx.Where("product_id = ?", product.ID).Delete(&domain.ProductImage{}).Error; err != nil { - return err - } - - if err := tx.Create(&images).Error; err != nil { - return err - } - } - - return nil - }) -} - -func DeleteProduct(productID string) error { - - return config.DB.Where("id = ?", productID).Delete(&domain.Product{}).Error -} diff --git a/internal/repositories/request_pickup.go b/internal/repositories/request_pickup.go deleted file mode 100644 index d09efae..0000000 --- a/internal/repositories/request_pickup.go +++ /dev/null @@ -1,64 +0,0 @@ -package repositories - -import ( - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -type RequestPickupRepository interface { - Create(request *domain.RequestPickup) error - GetByID(id string) (*domain.RequestPickup, error) - GetByUserID(userID string) ([]domain.RequestPickup, error) - DeleteByID(id string) error - ExistsByID(id string) (bool, error) -} - -type requestPickupRepository struct{} - -func NewRequestPickupRepository() RequestPickupRepository { - return &requestPickupRepository{} -} - -func (r *requestPickupRepository) Create(request *domain.RequestPickup) error { - return config.DB.Create(request).Error -} - -func (r *requestPickupRepository) GetByID(id string) (*domain.RequestPickup, error) { - var requestPickup domain.RequestPickup - if err := config.DB.Preload("Request"). - Preload("Request.TrashCategory"). - Preload("UserAddress"). - Where("id = ?", id). - First(&requestPickup).Error; err != nil { - return nil, err - } - return &requestPickup, nil -} - -func (r *requestPickupRepository) GetByUserID(userID string) ([]domain.RequestPickup, error) { - var requestPickups []domain.RequestPickup - err := config.DB.Preload("Request"). - Preload("Request.TrashCategory"). - Preload("UserAddress"). - Where("user_id = ?", userID). - Find(&requestPickups).Error - - if err != nil { - return nil, err - } - - return requestPickups, nil -} - -func (r *requestPickupRepository) ExistsByID(id string) (bool, error) { - var count int64 - if err := config.DB.Model(&domain.RequestPickup{}).Where("id = ?", id).Count(&count).Error; err != nil { - return false, err - } - return count > 0, nil -} - - -func (r *requestPickupRepository) DeleteByID(id string) error { - return config.DB.Where("id = ?", id).Delete(&domain.RequestPickup{}).Error -} diff --git a/internal/repositories/role.go b/internal/repositories/role.go deleted file mode 100644 index bdd467f..0000000 --- a/internal/repositories/role.go +++ /dev/null @@ -1,76 +0,0 @@ -package repositories - -import ( - "encoding/json" - "errors" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -func GetUserRoleByID(id string) (domain.UserRole, error) { - var role domain.UserRole - - ctx := config.Context() - cachedRole, err := config.RedisClient.Get(ctx, "userRole:"+id).Result() - - if err == nil { - - err := json.Unmarshal([]byte(cachedRole), &role) - if err != nil { - return role, errors.New("gagal mendekode data cache Redis") - } - return role, nil - } - - err = config.DB.Where("id = ?", id).First(&role).Error - if err != nil { - return role, errors.New("userRole tidak ditemukan") - } - - roleJSON, err := json.Marshal(role) - if err != nil { - return role, errors.New("gagal mendekode data untuk Redis") - } - - err = config.RedisClient.Set(ctx, "userRole:"+id, roleJSON, time.Hour*24).Err() - if err != nil { - return role, errors.New("gagal menyimpan data di Redis") - } - - return role, nil -} - -func GetAllUserRoles() ([]domain.UserRole, error) { - var roles []domain.UserRole - - ctx := config.Context() - cachedRoles, err := config.RedisClient.Get(ctx, "allUserRoles").Result() - - if err == nil { - - err := json.Unmarshal([]byte(cachedRoles), &roles) - if err != nil { - return roles, errors.New("gagal mendekode data cache Redis") - } - return roles, nil - } - - err = config.DB.Find(&roles).Error - if err != nil { - return nil, errors.New("gagal mengambil data UserRole") - } - - rolesJSON, err := json.Marshal(roles) - if err != nil { - return roles, errors.New("gagal mendekode data untuk Redis") - } - - err = config.RedisClient.Set(ctx, "allUserRoles", rolesJSON, time.Hour*24).Err() - if err != nil { - return roles, errors.New("gagal menyimpan data di Redis") - } - - return roles, nil -} diff --git a/internal/repositories/store.go b/internal/repositories/store.go deleted file mode 100644 index 9e32c02..0000000 --- a/internal/repositories/store.go +++ /dev/null @@ -1,24 +0,0 @@ -package repositories - -import ( - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -func GetStoreByID(storeID string) (domain.Store, error) { - var store domain.Store - err := config.DB.Where("id = ?", storeID).First(&store).Error - return store, err -} - -func GetStoresByUserID(userID string, limit, offset int) ([]domain.Store, error) { - var stores []domain.Store - query := config.DB.Where("user_id = ?", userID) - - if limit > 0 { - query = query.Limit(limit).Offset(offset) - } - - err := query.Find(&stores).Error - return stores, err -} diff --git a/internal/repositories/trashtype.go b/internal/repositories/trashtype.go deleted file mode 100644 index d57b5f6..0000000 --- a/internal/repositories/trashtype.go +++ /dev/null @@ -1,81 +0,0 @@ -package repositories - -import ( - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" -) - -func GetTrashCategories() ([]domain.TrashCategory, error) { - var categories []domain.TrashCategory - if err := config.DB.Find(&categories).Error; err != nil { - return nil, err - } - return categories, nil -} - -func GetTrashCategoryDetail(id string) (domain.TrashCategory, error) { - var category domain.TrashCategory - if err := config.DB.Preload("Details").Where("id = ?", id).First(&category).Error; err != nil { - return category, err - } - return category, nil -} - -func GetTrashDetailByID(id string) (domain.TrashDetail, error) { - var detail domain.TrashDetail - - if err := config.DB.Where("id = ?", id).First(&detail).Error; err != nil { - return detail, err - } - return detail, nil -} - -func CreateTrashCategory(category *domain.TrashCategory) error { - if err := config.DB.Create(category).Error; err != nil { - return err - } - return nil -} - -func CreateTrashDetail(detail *domain.TrashDetail) error { - if err := config.DB.Create(detail).Error; err != nil { - return err - } - return nil -} - -func UpdateTrashCategory(category *domain.TrashCategory) error { - if err := config.DB.Save(category).Error; err != nil { - return err - } - return nil -} - -func UpdateTrashDetail(detail *domain.TrashDetail) error { - if err := config.DB.Save(detail).Error; err != nil { - return err - } - return nil -} - -func DeleteTrashCategory(id string) error { - - if err := config.DB.Where("category_id = ?", id).Delete(&domain.TrashDetail{}).Error; err != nil { - return err - } - - if err := config.DB.Where("id = ?", id).Delete(&domain.TrashCategory{}).Error; err != nil { - return err - } - - return nil -} - -func DeleteTrashDetail(id string) error { - - if err := config.DB.Where("id = ?", id).Delete(&domain.TrashDetail{}).Error; err != nil { - return err - } - - return nil -} diff --git a/internal/repositories/user.go b/internal/repositories/user.go deleted file mode 100644 index 1a4aa1a..0000000 --- a/internal/repositories/user.go +++ /dev/null @@ -1,33 +0,0 @@ -package repositories - -import ( - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/config" -) - -func GetUsers() ([]domain.User, error) { - var users []domain.User - - if err := config.DB.Find(&users).Error; err != nil { - return nil, err - } - return users, nil -} - -func GetUsersByRole(roleID string) ([]domain.User, error) { - var users []domain.User - - if err := config.DB.Where("role_id = ?", roleID).Find(&users).Error; err != nil { - return nil, err - } - return users, nil -} - -func GetUserByUserrId(userID string) (domain.User, error) { - var user domain.User - - if err := config.DB.Where("id = ?", userID).First(&user).Error; err != nil { - return domain.User{}, err - } - return user, nil -} \ No newline at end of file diff --git a/internal/repositories/userpin.go b/internal/repositories/userpin.go deleted file mode 100644 index 5ce2160..0000000 --- a/internal/repositories/userpin.go +++ /dev/null @@ -1,72 +0,0 @@ -package repositories - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" - "golang.org/x/crypto/bcrypt" -) - -func CreatePin(pin *domain.UserPin) error { - result := config.DB.Create(pin) - if result.Error != nil { - return result.Error - } - return nil -} - -func GetPinByUserID(userID string) (domain.UserPin, error) { - - ctx := context.Background() - redisClient := config.RedisClient - - redisKey := fmt.Sprintf("user_pin:%s", userID) - - pin, err := redisClient.Get(ctx, redisKey).Result() - if err == nil { - - return domain.UserPin{ - UserID: userID, - Pin: pin, - }, nil - } - - var dbPin domain.UserPin - err = config.DB.Where("user_id = ?", userID).First(&dbPin).Error - if err != nil { - return dbPin, errors.New("PIN tidak ditemukan") - } - - redisClient.Set(ctx, redisKey, dbPin.Pin, 5*time.Minute) - - return dbPin, nil -} - -func UpdatePin(userID string, newPin string) (domain.UserPin, error) { - var pin domain.UserPin - - err := config.DB.Where("user_id = ?", userID).First(&pin).Error - if err != nil { - return pin, errors.New("PIN tidak ditemukan") - } - - hashedPin, err := bcrypt.GenerateFromPassword([]byte(newPin), bcrypt.DefaultCost) - if err != nil { - return pin, err - } - - pin.Pin = string(hashedPin) - - if err := config.DB.Save(&pin).Error; err != nil { - return pin, err - } - - redisClient := config.RedisClient - redisClient.Del(context.Background(), fmt.Sprintf("user_pin:%s", userID)) - - return pin, nil -} diff --git a/internal/services/Indonesian_territory.go b/internal/services/Indonesian_territory.go deleted file mode 100644 index aa48a05..0000000 --- a/internal/services/Indonesian_territory.go +++ /dev/null @@ -1,70 +0,0 @@ -package services - -import ( - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/internal/repositories" -) - -func GetProvinces() ([]domain.Province, error) { - provinces, err := repositories.GetProvinces() - if err != nil { - return nil, err - } - return provinces, nil -} - -func GetRegencies() ([]domain.Regency, error) { - regencies, err := repositories.GetRegencies() - if err != nil { - return nil, err - } - return regencies, nil -} - -func GetDistricts() ([]domain.District, error) { - districts, err := repositories.GetDistricts() - if err != nil { - return nil, err - } - return districts, nil -} - -func GetVillages() ([]domain.Village, error) { - villages, err := repositories.GetVillages() - if err != nil { - return nil, err - } - return villages, nil -} - -func GetProvinceByID(id string) (domain.Province, error) { - province, err := repositories.GetProvinceByID(id) - if err != nil { - return domain.Province{}, err - } - return province, nil -} - -func GetRegencyByID(id string) (domain.Regency, error) { - regency, err := repositories.GetRegencyByID(id) - if err != nil { - return domain.Regency{}, err - } - return regency, nil -} - -func GetDistrictByID(id string) (domain.District, error) { - district, err := repositories.GetDistrictByID(id) - if err != nil { - return domain.District{}, err - } - return district, nil -} - -func GetVillageByID(id string) (domain.Village, error) { - village, err := repositories.GetVillageByID(id) - if err != nil { - return domain.Village{}, err - } - return village, nil -} diff --git a/internal/services/address.go b/internal/services/address.go deleted file mode 100644 index bc62090..0000000 --- a/internal/services/address.go +++ /dev/null @@ -1,110 +0,0 @@ -package services - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" -) - -func CreateAddress(userID string, input dto.AddressInput) (domain.Address, error) { - address := domain.Address{ - UserID: userID, - Province: input.Province, - District: input.District, - Subdistrict: input.Subdistrict, - PostalCode: input.PostalCode, - Village: input.Village, - Detail: input.Detail, - Geography: input.Geography, - } - - err := repositories.CreateAddress(&address) - if err != nil { - return domain.Address{}, err - } - - cacheKey := fmt.Sprintf("address:user:%s", userID) - config.RedisClient.Del(context.Background(), cacheKey) - - return address, nil -} - -func GetAllAddressesByUserID(userID string) ([]domain.Address, error) { - ctx := context.Background() - cacheKey := fmt.Sprintf("address:user:%s", userID) - - cachedAddresses, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil { - var addresses []domain.Address - if json.Unmarshal([]byte(cachedAddresses), &addresses) == nil { - return addresses, nil - } - } - - addresses, err := repositories.GetAddressesByUserID(userID) - if err != nil { - return nil, err - } - - addressesJSON, _ := json.Marshal(addresses) - config.RedisClient.Set(ctx, cacheKey, addressesJSON, time.Hour).Err() - - return addresses, nil -} - -func GetAddressByID(addressID string) (domain.Address, error) { - address, err := repositories.GetAddressByID(addressID) - if err != nil { - return address, errors.New("address not found") - } - return address, nil -} - -func UpdateAddress(addressID string, input dto.AddressInput) (domain.Address, error) { - address, err := repositories.GetAddressByID(addressID) - if err != nil { - return address, errors.New("address not found") - } - - address.Province = input.Province - address.District = input.District - address.Subdistrict = input.Subdistrict - address.PostalCode = input.PostalCode - address.Village = input.Village - address.Detail = input.Detail - address.Geography = input.Geography - - updatedAddress, err := repositories.UpdateAddress(address) - if err != nil { - return updatedAddress, errors.New("failed to update address") - } - - cacheKey := fmt.Sprintf("address:user:%s", address.UserID) - config.RedisClient.Del(context.Background(), cacheKey) - - return updatedAddress, nil -} - -func DeleteAddress(addressID string) error { - address, err := repositories.GetAddressByID(addressID) - if err != nil { - return errors.New("address not found") - } - - err = repositories.DeleteAddress(addressID) - if err != nil { - return errors.New("failed to delete address") - } - - cacheKey := fmt.Sprintf("address:user:%s", address.UserID) - config.RedisClient.Del(context.Background(), cacheKey) - - return nil -} diff --git a/internal/services/article.go b/internal/services/article.go deleted file mode 100644 index 4618512..0000000 --- a/internal/services/article.go +++ /dev/null @@ -1,192 +0,0 @@ -package services - -import ( - "encoding/json" - "errors" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/utils" -) - -type ArticleService struct { - repo *repositories.ArticleRepository -} - -func NewArticleService(repo *repositories.ArticleRepository) *ArticleService { - return &ArticleService{repo: repo} -} - -func (s *ArticleService) GetAllArticles() ([]dto.ArticleResponse, error) { - ctx := config.Context() - cacheKey := "articles:all" - - cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedData != "" { - var cachedArticles []dto.ArticleResponse - if err := json.Unmarshal([]byte(cachedData), &cachedArticles); err == nil { - return cachedArticles, nil - } - } - - articles, err := s.repo.GetAll() - if err != nil { - return nil, err - } - - var result []dto.ArticleResponse - for _, article := range articles { - result = append(result, dto.ArticleResponse{ - ID: article.ID, - Title: article.Title, - CoverImage: article.CoverImage, - Author: article.Author, - Heading: article.Heading, - Content: article.Content, - PublishedAt: utils.FormatDateToIndonesianFormat(article.PublishedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(article.UpdatedAt), - }) - } - - cacheData, _ := json.Marshal(result) - config.RedisClient.Set(ctx, cacheKey, cacheData, time.Minute*5) - - return result, nil -} - -func (s *ArticleService) GetArticleByID(id string) (*dto.ArticleResponse, error) { - ctx := config.Context() - cacheKey := "articles:" + id - - cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedData != "" { - var cachedArticle dto.ArticleResponse - if err := json.Unmarshal([]byte(cachedData), &cachedArticle); err == nil { - return &cachedArticle, nil - } - } - - article, err := s.repo.GetByID(id) - if err != nil { - return nil, err - } - - result := &dto.ArticleResponse{ - ID: article.ID, - Title: article.Title, - CoverImage: article.CoverImage, - Author: article.Author, - Heading: article.Heading, - Content: article.Content, - PublishedAt: utils.FormatDateToIndonesianFormat(article.PublishedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(article.UpdatedAt), - } - - cacheData, _ := json.Marshal(result) - config.RedisClient.Set(ctx, cacheKey, cacheData, time.Minute*5) - - return result, nil -} - -func (s *ArticleService) CreateArticle(request *dto.ArticleCreateRequest) (*dto.ArticleResponse, error) { - - if err := request.Validate(); err != nil { - return nil, err - } - - newArticle := &domain.Article{ - Title: request.Title, - CoverImage: request.CoverImage, - Author: request.Author, - Heading: request.Heading, - Content: request.Content, - } - - err := s.repo.Create(newArticle) - if err != nil { - return nil, errors.New("failed to create article") - } - - ctx := config.Context() - config.RedisClient.Del(ctx, "articles:all") - - response := &dto.ArticleResponse{ - ID: newArticle.ID, - Title: newArticle.Title, - CoverImage: newArticle.CoverImage, - Author: newArticle.Author, - Heading: newArticle.Heading, - Content: newArticle.Content, - PublishedAt: utils.FormatDateToIndonesianFormat(newArticle.PublishedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(newArticle.UpdatedAt), - } - - return response, nil -} - -func (s *ArticleService) UpdateArticle(id string, request *dto.ArticleUpdateRequest) (*dto.ArticleResponse, error) { - - // if err := dto.GetValidator().Struct(request); err != nil { - // return nil, errors.New("invalid input data") - // } - - if err := request.Validate(); err != nil { - return nil, err - } - - article, err := s.repo.GetByID(id) - if err != nil { - return nil, errors.New("article not found") - } - - article.Title = request.Title - article.CoverImage = request.CoverImage - article.Author = request.Author - article.Heading = request.Heading - article.Content = request.Content - article.UpdatedAt = time.Now() - - err = s.repo.Update(article) - if err != nil { - return nil, errors.New("failed to update article") - } - - ctx := config.Context() - config.RedisClient.Del(ctx, "articles:all") - config.RedisClient.Del(ctx, "articles:"+id) - - response := &dto.ArticleResponse{ - ID: article.ID, - Title: article.Title, - CoverImage: article.CoverImage, - Author: article.Author, - Heading: article.Heading, - Content: article.Content, - PublishedAt: utils.FormatDateToIndonesianFormat(article.PublishedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(article.UpdatedAt), - } - - return response, nil -} - -func (s *ArticleService) DeleteArticle(id string) error { - - article, err := s.repo.GetByID(id) - if err != nil { - return errors.New("article not found") - } - - err = s.repo.Delete(article) - if err != nil { - return errors.New("failed to delete article") - } - - ctx := config.Context() - config.RedisClient.Del(ctx, "articles:all") - config.RedisClient.Del(ctx, "articles:"+id) - - return nil -} diff --git a/internal/services/auth.go b/internal/services/auth.go deleted file mode 100644 index 500b0f9..0000000 --- a/internal/services/auth.go +++ /dev/null @@ -1,154 +0,0 @@ -package services - -import ( - "errors" - "os" - "time" - - "github.com/golang-jwt/jwt/v5" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "golang.org/x/crypto/bcrypt" -) - -func RegisterUser(username, name, email, phone, password, confirmPassword, roleId string) error { - if password != confirmPassword { - return errors.New("password dan confirm password tidak cocok") - } - - if repositories.IsEmailExist(email, roleId) { - return errors.New("email is already registered with the same role") - } - - if repositories.IsUsernameExist(username, roleId) { - return errors.New("username is already registered with the same role") - } - - if repositories.IsPhoneExist(phone, roleId) { - return errors.New("phone number is already registered with the same role") - } - - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return errors.New("failed to hash password") - } - - err = repositories.CreateUser(username, name, email, phone, string(hashedPassword), roleId) - if err != nil { - return err - } - - return nil -} - -func LoginUser(identifier, password string) (string, error) { - if identifier == "" || password == "" { - return "", errors.New("email/username/phone and password must be provided") - } - - const roleId = "" - user, err := repositories.GetUserByEmailUsernameOrPhone(identifier, roleId) - if err != nil { - return "", errors.New("invalid email/username/phone or password") - } - - err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) - if err != nil { - return "", errors.New("invalid email/username/phone or password") - } - - token := generateJWT(user.ID, user.RoleID) - return token, nil -} - -func generateJWT(userID, role string) string { - claims := jwt.MapClaims{ - "sub": userID, - "role": role, - "exp": time.Now().Add(time.Hour * 24 * 7).Unix(), - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - t, err := token.SignedString([]byte(os.Getenv("API_KEY"))) - if err != nil { - return "" - } - - return t -} - -func GetUserByID(userID string) (domain.User, error) { - user, err := repositories.GetUserByID(userID) - if err != nil { - return user, errors.New("user not found") - } - return user, nil -} - -func UpdateUser(userID, email, username, name, phone string) error { - user, err := repositories.GetUserByID(userID) - if err != nil { - return errors.New("user not found") - } - - if email != "" && email != user.Email { - if repositories.IsEmailExist(email, user.RoleID) { - return errors.New("email is already registered with the same role") - } - user.Email = email - } - - if username != "" && username != user.Username { - if repositories.IsUsernameExist(username, user.RoleID) { - return errors.New("username is already registered with the same role") - } - user.Username = username - } - - if phone != "" && phone != user.Phone { - if repositories.IsPhoneExist(phone, user.RoleID) { - return errors.New("phone number is already registered with the same role") - } - user.Phone = phone - } - - if name != "" { - user.Name = name - } - - err = repositories.UpdateUser(&user) - if err != nil { - return errors.New("failed to update user") - } - - return nil -} - -func UpdatePassword(userID, oldPassword, newPassword string) error { - user, err := repositories.GetUserByID(userID) - if err != nil { - return errors.New("user not found") - } - - err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)) - if err != nil { - return errors.New("old password is incorrect") - } - - err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(newPassword)) - if err == nil { - return errors.New("new password cannot be the same as the old password") - } - - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) - if err != nil { - return errors.New("failed to hash new password") - } - - err = repositories.UpdateUserPassword(userID, string(hashedPassword)) - if err != nil { - return errors.New("failed to update password") - } - - return nil -} diff --git a/internal/services/auth_service.go b/internal/services/auth_service.go new file mode 100644 index 0000000..9bce0d1 --- /dev/null +++ b/internal/services/auth_service.go @@ -0,0 +1,76 @@ +package services + +import ( + "fmt" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/repositories" + "github.com/pahmiudahgede/senggoldong/model" + "github.com/pahmiudahgede/senggoldong/utils" + "golang.org/x/crypto/bcrypt" +) + +type UserService interface { + Login(credentials dto.LoginDTO) (*dto.UserResponseWithToken, error) +} + +type userService struct { + UserRepo repositories.UserRepository + SecretKey string +} + +func NewUserService(userRepo repositories.UserRepository, secretKey string) UserService { + return &userService{UserRepo: userRepo, SecretKey: secretKey} +} + +func (s *userService) Login(credentials dto.LoginDTO) (*dto.UserResponseWithToken, error) { + + user, err := s.UserRepo.FindByEmailOrUsernameOrPhone(credentials.Identifier) + if err != nil { + + return nil, fmt.Errorf("user not found") + } + + if !CheckPasswordHash(credentials.Password, user.Password) { + return nil, bcrypt.ErrMismatchedHashAndPassword + } + + token, err := s.generateJWT(user) + if err != nil { + return nil, err + } + + err = utils.SetData(credentials.Identifier, token, time.Hour*24) + if err != nil { + return nil, err + } + + return &dto.UserResponseWithToken{ + UserID: user.ID, + Token: token, + }, nil +} + +func (s *userService) generateJWT(user *model.User) (string, error) { + claims := jwt.MapClaims{ + "sub": user.ID, + "iat": time.Now().Unix(), + "exp": time.Now().Add(time.Hour * 24).Unix(), + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + tokenString, err := token.SignedString([]byte(s.SecretKey)) + if err != nil { + return "", err + } + + return tokenString, nil +} + +func CheckPasswordHash(password, hashedPassword string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) + return err == nil +} \ No newline at end of file diff --git a/internal/services/banner.go b/internal/services/banner.go deleted file mode 100644 index fb3125a..0000000 --- a/internal/services/banner.go +++ /dev/null @@ -1,170 +0,0 @@ -package services - -import ( - "encoding/json" - "errors" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/utils" -) - -type BannerService struct { - repo *repositories.BannerRepository -} - -func NewBannerService(repo *repositories.BannerRepository) *BannerService { - return &BannerService{repo: repo} -} - -func (s *BannerService) GetAllBanners() ([]dto.BannerResponse, error) { - ctx := config.Context() - cacheKey := "banners:all" - - cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedData != "" { - var cachedBanners []dto.BannerResponse - if err := json.Unmarshal([]byte(cachedData), &cachedBanners); err == nil { - return cachedBanners, nil - } - } - - banners, err := s.repo.GetAll() - if err != nil { - return nil, err - } - - var result []dto.BannerResponse - for _, banner := range banners { - result = append(result, dto.BannerResponse{ - ID: banner.ID, - BannerName: banner.BannerName, - BannerImage: banner.BannerImage, - CreatedAt: utils.FormatDateToIndonesianFormat(banner.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(banner.UpdatedAt), - }) - } - - cacheData, _ := json.Marshal(result) - config.RedisClient.Set(ctx, cacheKey, cacheData, time.Minute*5) - - return result, nil -} - -func (s *BannerService) GetBannerByID(id string) (*dto.BannerResponse, error) { - ctx := config.Context() - cacheKey := "banners:" + id - - cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedData != "" { - var cachedBanner dto.BannerResponse - if err := json.Unmarshal([]byte(cachedData), &cachedBanner); err == nil { - return &cachedBanner, nil - } - } - - banner, err := s.repo.GetByID(id) - if err != nil { - return nil, err - } - - result := &dto.BannerResponse{ - ID: banner.ID, - BannerName: banner.BannerName, - BannerImage: banner.BannerImage, - CreatedAt: utils.FormatDateToIndonesianFormat(banner.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(banner.UpdatedAt), - } - - cacheData, _ := json.Marshal(result) - config.RedisClient.Set(ctx, cacheKey, cacheData, time.Minute*5) - - return result, nil -} - -func (s *BannerService) CreateBanner(request *dto.BannerCreateRequest) (*dto.BannerResponse, error) { - - if request.BannerName == "" || request.BannerImage == "" { - return nil, errors.New("invalid input data") - } - - newBanner := &domain.Banner{ - BannerName: request.BannerName, - BannerImage: request.BannerImage, - } - - err := s.repo.Create(newBanner) - if err != nil { - return nil, errors.New("failed to create banner") - } - - ctx := config.Context() - config.RedisClient.Del(ctx, "banners:all") - - response := &dto.BannerResponse{ - ID: newBanner.ID, - BannerName: newBanner.BannerName, - BannerImage: newBanner.BannerImage, - CreatedAt: utils.FormatDateToIndonesianFormat(newBanner.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(newBanner.UpdatedAt), - } - - return response, nil -} - -func (s *BannerService) UpdateBanner(id string, request *dto.BannerUpdateRequest) (*dto.BannerResponse, error) { - - banner, err := s.repo.GetByID(id) - if err != nil { - return nil, errors.New("banner not found") - } - - if request.BannerName != nil && *request.BannerName != "" { - banner.BannerName = *request.BannerName - } - if request.BannerImage != nil && *request.BannerImage != "" { - banner.BannerImage = *request.BannerImage - } - banner.UpdatedAt = time.Now() - - err = s.repo.Update(banner) - if err != nil { - return nil, errors.New("failed to update banner") - } - - ctx := config.Context() - config.RedisClient.Del(ctx, "banners:all") - config.RedisClient.Del(ctx, "banners:"+id) - - response := &dto.BannerResponse{ - ID: banner.ID, - BannerName: banner.BannerName, - BannerImage: banner.BannerImage, - CreatedAt: utils.FormatDateToIndonesianFormat(banner.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(banner.UpdatedAt), - } - - return response, nil -} - -func (s *BannerService) DeleteBanner(id string) error { - - banner, err := s.repo.GetByID(id) - if err != nil { - return errors.New("banner not found") - } - - err = s.repo.Delete(banner) - if err != nil { - return errors.New("failed to delete banner") - } - - ctx := config.Context() - config.RedisClient.Del(ctx, "banners:all") - config.RedisClient.Del(ctx, "banners:"+id) - - return nil -} diff --git a/internal/services/coveragearea.go b/internal/services/coveragearea.go deleted file mode 100644 index db90dd3..0000000 --- a/internal/services/coveragearea.go +++ /dev/null @@ -1,89 +0,0 @@ -package services - -import ( - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/internal/repositories" -) - -func GetCoverageAreas() ([]domain.CoverageArea, error) { - return repositories.GetCoverageAreas() -} - -func GetCoverageAreaByID(id string) (domain.CoverageArea, error) { - return repositories.GetCoverageAreaByID(id) -} - -func GetCoverageAreaByDistrictID(id string) (domain.CoverageDistric, error) { - return repositories.GetCoverageAreaByDistrictID(id) -} - -func GetCoverageDistricsByCoverageAreaID(areaID string) ([]domain.CoverageDistric, error) { - return repositories.GetCoverageDistricsByCoverageAreaID(areaID) -} - -func GetSubdistrictsByCoverageDistrictID(districtID string) ([]domain.CoverageSubdistrict, error) { - return repositories.GetSubdistrictsByCoverageDistrictID(districtID) -} - -func CreateCoverageArea(province string) (*domain.CoverageArea, error) { - coverageArea := &domain.CoverageArea{ - Province: province, - } - - if err := repositories.CreateCoverageArea(coverageArea); err != nil { - return nil, err - } - - return coverageArea, nil -} - -func CreateCoverageDistrict(coverageAreaID, district string) (*domain.CoverageDistric, error) { - coverageDistrict := &domain.CoverageDistric{ - CoverageAreaID: coverageAreaID, - District: district, - } - - if err := repositories.CreateCoverageDistrict(coverageDistrict); err != nil { - return nil, err - } - - return coverageDistrict, nil -} - -func CreateCoverageSubdistrict(coverageAreaID, coverageDistrictId, subdistrict string) (*domain.CoverageSubdistrict, error) { - coverageSubdistrict := &domain.CoverageSubdistrict{ - CoverageAreaID: coverageAreaID, - CoverageDistrictId: coverageDistrictId, - Subdistrict: subdistrict, - } - - if err := repositories.CreateCoverageSubdistrict(coverageSubdistrict); err != nil { - return nil, err - } - - return coverageSubdistrict, nil -} - -func UpdateCoverageArea(id string, request domain.CoverageArea) (domain.CoverageArea, error) { - return repositories.UpdateCoverageArea(id, request) -} - -func UpdateCoverageDistrict(id string, request domain.CoverageDistric) (domain.CoverageDistric, error) { - return repositories.UpdateCoverageDistrict(id, request) -} - -func UpdateCoverageSubdistrict(id string, request domain.CoverageSubdistrict) (domain.CoverageSubdistrict, error) { - return repositories.UpdateCoverageSubdistrict(id, request) -} - -func DeleteCoverageArea(id string) error { - return repositories.DeleteCoverageArea(id) -} - -func DeleteCoverageDistrict(id string) error { - return repositories.DeleteCoverageDistrict(id) -} - -func DeleteCoverageSubdistrict(id string) error { - return repositories.DeleteCoverageSubdistrict(id) -} \ No newline at end of file diff --git a/internal/services/initialcoint.go b/internal/services/initialcoint.go deleted file mode 100644 index 13fa8e1..0000000 --- a/internal/services/initialcoint.go +++ /dev/null @@ -1,170 +0,0 @@ -package services - -import ( - "encoding/json" - "errors" - "time" - - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/utils" -) - -type PointService struct { - repo *repositories.PointRepository -} - -func NewPointService(repo *repositories.PointRepository) *PointService { - 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 { - return nil, err - } - - 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 (s *PointService) GetPointByID(id string) (*dto.PointResponse, error) { - ctx := config.Context() - - cacheKey := "points:" + id - cachedData, err := config.RedisClient.Get(ctx, cacheKey).Result() - if err == nil && cachedData != "" { - var cachedPoint dto.PointResponse - if err := json.Unmarshal([]byte(cachedData), &cachedPoint); err == nil { - return &cachedPoint, nil - } - } - - point, err := s.repo.GetByID(id) - if err != nil { - return nil, err - } - - 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 (s *PointService) CreatePoint(request *dto.PointCreateRequest) (*dto.PointResponse, error) { - - if err := request.Validate(); err != nil { - return nil, err - } - - 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) { - - if err := request.Validate(); err != nil { - return nil, err - } - - point, err := s.repo.GetByID(id) - if err != nil { - return nil, errors.New("point not found") - } - - point.CoinName = request.CoinName - 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 { - return errors.New("point not found") - } - - err = s.repo.Delete(point) - 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 -} diff --git a/internal/services/product.go b/internal/services/product.go deleted file mode 100644 index c70727f..0000000 --- a/internal/services/product.go +++ /dev/null @@ -1,208 +0,0 @@ -package services - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetProductsByStoreID(storeID string, limit, page int) ([]dto.ProductResponseWithSoldDTO, error) { - - offset := (page - 1) * limit - - products, err := repositories.GetProductsByStoreID(storeID, limit, offset) - if err != nil { - return nil, err - } - - return mapProductsToDTO(products), nil -} - -func GetProductsByUserID(userID string, limit, page int) ([]dto.ProductResponseWithSoldDTO, error) { - offset := (page - 1) * limit - products, err := repositories.GetProductsByUserID(userID, limit, offset) - if err != nil { - return nil, err - } - - return mapProductsToDTO(products), nil -} - -func mapProductsToDTO(products []domain.Product) []dto.ProductResponseWithSoldDTO { - var productResponses []dto.ProductResponseWithSoldDTO - for _, product := range products { - var images []dto.ProductImageDTO - for _, img := range product.ProductImages { - images = append(images, dto.ProductImageDTO{ImageURL: img.ImageURL}) - } - - productResponses = append(productResponses, dto.ProductResponseWithSoldDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductTitle: product.ProductTitle, - ProductImages: images, - TrashDetail: dto.TrashDetailResponseDTO{ - ID: product.TrashDetail.ID, - Description: product.TrashDetail.Description, - Price: product.TrashDetail.Price, - }, - SalePrice: product.SalePrice, - Quantity: product.Quantity, - ProductDescribe: product.ProductDescribe, - Sold: product.Sold, - CreatedAt: utils.FormatDateToIndonesianFormat(product.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(product.UpdatedAt), - }) - } - return productResponses -} - -func GetProductByIDAndStoreID(productID, storeID string) (dto.ProductResponseWithSoldDTO, error) { - product, err := repositories.GetProductByIDAndStoreID(productID, storeID) - if err != nil { - return dto.ProductResponseWithSoldDTO{}, err - } - - var images []dto.ProductImageDTO - for _, img := range product.ProductImages { - images = append(images, dto.ProductImageDTO{ImageURL: img.ImageURL}) - } - - return dto.ProductResponseWithSoldDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductTitle: product.ProductTitle, - ProductImages: images, - TrashDetail: dto.TrashDetailResponseDTO{ - ID: product.TrashDetail.ID, - Description: product.TrashDetail.Description, - Price: product.TrashDetail.Price, - }, - SalePrice: product.SalePrice, - Quantity: product.Quantity, - ProductDescribe: product.ProductDescribe, - Sold: product.Sold, - CreatedAt: utils.FormatDateToIndonesianFormat(product.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(product.UpdatedAt), - }, nil -} - -func CreateProduct(input dto.CreateProductRequestDTO, userID string) (dto.CreateProductResponseDTO, error) { - if err := dto.GetValidator().Struct(input); err != nil { - return dto.CreateProductResponseDTO{}, err - } - - trashDetail, err := repositories.GetTrashDetailByID(input.TrashDetailID) - if err != nil { - return dto.CreateProductResponseDTO{}, err - } - - marketPrice := int64(trashDetail.Price) - - if err := dto.ValidateSalePrice(marketPrice, input.SalePrice); err != nil { - return dto.CreateProductResponseDTO{}, err - } - - product := &domain.Product{ - UserID: userID, - StoreID: input.StoreID, - ProductTitle: input.ProductTitle, - TrashDetailID: input.TrashDetailID, - SalePrice: input.SalePrice, - Quantity: input.Quantity, - ProductDescribe: input.ProductDescribe, - } - - var images []domain.ProductImage - for _, imageURL := range input.ProductImages { - images = append(images, domain.ProductImage{ImageURL: imageURL}) - } - - if err := repositories.CreateProduct(product, images); err != nil { - return dto.CreateProductResponseDTO{}, err - } - - trashDetail, err = repositories.GetTrashDetailByID(product.TrashDetailID) - if err != nil { - return dto.CreateProductResponseDTO{}, err - } - - return dto.CreateProductResponseDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductTitle: product.ProductTitle, - ProductImages: input.ProductImages, - TrashDetail: dto.TrashDetailResponseDTO{ - ID: trashDetail.ID, - Description: trashDetail.Description, - Price: trashDetail.Price, - }, - SalePrice: product.SalePrice, - Quantity: product.Quantity, - ProductDescribe: product.ProductDescribe, - CreatedAt: utils.FormatDateToIndonesianFormat(product.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(product.UpdatedAt), - }, nil -} - -func UpdateProduct(productID string, input dto.UpdateProductRequestDTO) (dto.CreateProductResponseDTO, error) { - - product, err := repositories.GetProductByID(productID) - if err != nil { - return dto.CreateProductResponseDTO{}, errors.New("product not found") - } - - product.ProductTitle = input.ProductTitle - product.TrashDetailID = input.TrashDetailID - product.SalePrice = input.SalePrice - product.Quantity = input.Quantity - product.ProductDescribe = input.ProductDescribe - - var images []domain.ProductImage - for _, imageURL := range input.ProductImages { - images = append(images, domain.ProductImage{ImageURL: imageURL}) - } - - if err := repositories.UpdateProduct(&product, images); err != nil { - return dto.CreateProductResponseDTO{}, err - } - - trashDetail, err := repositories.GetTrashDetailByID(product.TrashDetailID) - if err != nil { - return dto.CreateProductResponseDTO{}, err - } - - return dto.CreateProductResponseDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductTitle: product.ProductTitle, - ProductImages: input.ProductImages, - TrashDetail: dto.TrashDetailResponseDTO{ - ID: trashDetail.ID, - Description: trashDetail.Description, - Price: trashDetail.Price, - }, - SalePrice: product.SalePrice, - Quantity: product.Quantity, - ProductDescribe: product.ProductDescribe, - CreatedAt: utils.FormatDateToIndonesianFormat(product.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(product.UpdatedAt), - }, nil -} - -func DeleteProduct(productID string) error { - - _, err := repositories.GetProductByID(productID) - if err != nil { - return errors.New("product not found") - } - - if err := repositories.DeleteProduct(productID); err != nil { - return err - } - - return nil -} diff --git a/internal/services/request_pickup.go b/internal/services/request_pickup.go deleted file mode 100644 index 117fdf2..0000000 --- a/internal/services/request_pickup.go +++ /dev/null @@ -1,42 +0,0 @@ -package services - -import ( - "fmt" - - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/internal/repositories" -) - -type RequestPickupService struct { - repository repositories.RequestPickupRepository -} - -func NewRequestPickupService(repository repositories.RequestPickupRepository) *RequestPickupService { - return &RequestPickupService{repository: repository} -} - -func (s *RequestPickupService) CreateRequestPickup(request *domain.RequestPickup) error { - return s.repository.Create(request) -} - -func (s *RequestPickupService) GetRequestPickupByID(id string) (*domain.RequestPickup, error) { - return s.repository.GetByID(id) -} - -func (s *RequestPickupService) GetRequestPickupsByUser(userID string) ([]domain.RequestPickup, error) { - return s.repository.GetByUserID(userID) -} - -func (s *RequestPickupService) DeleteRequestPickupByID(id string) error { - - exists, err := s.repository.ExistsByID(id) - if err != nil { - return err - } - - if !exists { - return fmt.Errorf("request pickup with id %s not found", id) - } - - return s.repository.DeleteByID(id) -} diff --git a/internal/services/role.go b/internal/services/role.go deleted file mode 100644 index a05077c..0000000 --- a/internal/services/role.go +++ /dev/null @@ -1,24 +0,0 @@ -package services - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/internal/repositories" -) - -func GetUserRoleByID(id string) (domain.UserRole, error) { - role, err := repositories.GetUserRoleByID(id) - if err != nil { - return role, errors.New("userRole tidak ditemukan") - } - return role, nil -} - -func GetAllUserRoles() ([]domain.UserRole, error) { - roles, err := repositories.GetAllUserRoles() - if err != nil { - return nil, errors.New("gagal mengambil data UserRole") - } - return roles, nil -} diff --git a/internal/services/store.go b/internal/services/store.go deleted file mode 100644 index f9648a9..0000000 --- a/internal/services/store.go +++ /dev/null @@ -1,53 +0,0 @@ -package services - -import ( - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetStoreByID(storeID string) (dto.StoreResponseDTO, error) { - store, err := repositories.GetStoreByID(storeID) - if err != nil { - return dto.StoreResponseDTO{}, err - } - - return dto.StoreResponseDTO{ - ID: store.ID, - UserID: store.UserID, - StoreName: store.StoreName, - StoreLogo: store.StoreLogo, - StoreBanner: store.StoreBanner, - StoreDesc: store.StoreDesc, - Follower: store.Follower, - StoreRating: store.StoreRating, - CreatedAt: utils.FormatDateToIndonesianFormat(store.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(store.UpdatedAt), - }, nil -} - -func GetStoresByUserID(userID string, limit, page int) ([]dto.StoreResponseDTO, error) { - offset := (page - 1) * limit - stores, err := repositories.GetStoresByUserID(userID, limit, offset) - if err != nil { - return nil, err - } - - var storeResponses []dto.StoreResponseDTO - for _, store := range stores { - storeResponses = append(storeResponses, dto.StoreResponseDTO{ - ID: store.ID, - UserID: store.UserID, - StoreName: store.StoreName, - StoreLogo: store.StoreLogo, - StoreBanner: store.StoreBanner, - StoreDesc: store.StoreDesc, - Follower: store.Follower, - StoreRating: store.StoreRating, - CreatedAt: utils.FormatDateToIndonesianFormat(store.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(store.UpdatedAt), - }) - } - - return storeResponses, nil -} diff --git a/internal/services/trashtype.go b/internal/services/trashtype.go deleted file mode 100644 index c8b74d7..0000000 --- a/internal/services/trashtype.go +++ /dev/null @@ -1,85 +0,0 @@ -package services - -import ( - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/internal/repositories" -) - -func GetTrashCategories() ([]domain.TrashCategory, error) { - return repositories.GetTrashCategories() -} - -func GetTrashCategoryDetail(id string) (domain.TrashCategory, error) { - return repositories.GetTrashCategoryDetail(id) -} - -func CreateTrashCategory(name string) (domain.TrashCategory, error) { - category := domain.TrashCategory{Name: name} - err := repositories.CreateTrashCategory(&category) - if err != nil { - return category, err - } - return category, nil -} - -func CreateTrashDetail(categoryID, description string, price int) (domain.TrashDetail, error) { - detail := domain.TrashDetail{ - CategoryID: categoryID, - Description: description, - Price: price, - } - err := repositories.CreateTrashDetail(&detail) - if err != nil { - return detail, err - } - return detail, nil -} - -func UpdateTrashCategory(id, name string) (domain.TrashCategory, error) { - category, err := repositories.GetTrashCategoryDetail(id) - if err != nil { - return domain.TrashCategory{}, err - } - category.Name = name - if err := repositories.UpdateTrashCategory(&category); err != nil { - return domain.TrashCategory{}, err - } - return category, nil -} - -func UpdateTrashDetail(id, description string, price int) (domain.TrashDetail, error) { - - detail, err := repositories.GetTrashDetailByID(id) - if err != nil { - - return domain.TrashDetail{}, err - } - - detail.Description = description - detail.Price = price - - if err := repositories.UpdateTrashDetail(&detail); err != nil { - - return domain.TrashDetail{}, err - } - - return detail, nil -} - -func DeleteTrashCategory(id string) error { - - err := repositories.DeleteTrashCategory(id) - if err != nil { - return err - } - return nil -} - -func DeleteTrashDetail(id string) error { - - err := repositories.DeleteTrashDetail(id) - if err != nil { - return err - } - return nil -} diff --git a/internal/services/user.go b/internal/services/user.go deleted file mode 100644 index ea50f73..0000000 --- a/internal/services/user.go +++ /dev/null @@ -1,71 +0,0 @@ -package services - -import ( - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "github.com/pahmiudahgede/senggoldong/utils" -) - -func GetUsers() ([]dto.UserResponseDTO, error) { - users, err := repositories.GetUsers() - if err != nil { - return nil, err - } - - var userResponses []dto.UserResponseDTO - for _, user := range users { - userResponses = append(userResponses, dto.UserResponseDTO{ - ID: user.ID, - Username: user.Username, - Name: user.Name, - Email: user.Email, - Phone: user.Phone, - RoleId: user.RoleID, - CreatedAt: utils.FormatDateToIndonesianFormat(user.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(user.UpdatedAt), - }) - } - return userResponses, nil -} - -func GetUsersByRole(roleID string) ([]dto.UserResponseDTO, error) { - users, err := repositories.GetUsersByRole(roleID) - if err != nil { - return nil, err - } - - var userResponses []dto.UserResponseDTO - for _, user := range users { - userResponses = append(userResponses, dto.UserResponseDTO{ - ID: user.ID, - Username: user.Username, - Name: user.Name, - Email: user.Email, - Phone: user.Phone, - RoleId: user.RoleID, - CreatedAt: utils.FormatDateToIndonesianFormat(user.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(user.UpdatedAt), - }) - } - return userResponses, nil -} - -func GetUserByUserID(userID string) (dto.UserResponseDTO, error) { - user, err := repositories.GetUserByID(userID) - if err != nil { - return dto.UserResponseDTO{}, err - } - - userResponse := dto.UserResponseDTO{ - ID: user.ID, - Username: user.Username, - Name: user.Name, - Email: user.Email, - Phone: user.Phone, - RoleId: user.RoleID, - CreatedAt: utils.FormatDateToIndonesianFormat(user.CreatedAt), - UpdatedAt: utils.FormatDateToIndonesianFormat(user.UpdatedAt), - } - - return userResponse, nil -} \ No newline at end of file diff --git a/internal/services/userpin.go b/internal/services/userpin.go deleted file mode 100644 index bbe7b12..0000000 --- a/internal/services/userpin.go +++ /dev/null @@ -1,63 +0,0 @@ -package services - -import ( - "errors" - - "github.com/pahmiudahgede/senggoldong/domain" - "github.com/pahmiudahgede/senggoldong/dto" - "github.com/pahmiudahgede/senggoldong/internal/repositories" - "golang.org/x/crypto/bcrypt" -) - -func CreatePin(userID string, input dto.PinInput) (domain.UserPin, error) { - - hashedPin, err := bcrypt.GenerateFromPassword([]byte(input.Pin), bcrypt.DefaultCost) - if err != nil { - return domain.UserPin{}, err - } - - pin := domain.UserPin{ - UserID: userID, - Pin: string(hashedPin), - } - - err = repositories.CreatePin(&pin) - if err != nil { - return domain.UserPin{}, err - } - - return pin, nil -} - -func GetPinByUserID(userID string) (domain.UserPin, error) { - - pin, err := repositories.GetPinByUserID(userID) - if err != nil { - return pin, errors.New("PIN tidak ditemukan") - } - return pin, nil -} - -func UpdatePin(userID string, oldPin string, newPin string) (domain.UserPin, error) { - - pin, err := repositories.GetPinByUserID(userID) - if err != nil { - return pin, errors.New("PIN tidak ditemukan") - } - - if err := bcrypt.CompareHashAndPassword([]byte(pin.Pin), []byte(oldPin)); err != nil { - return pin, errors.New("PIN lama salah") - } - - updatedPin, err := repositories.UpdatePin(userID, newPin) - if err != nil { - return updatedPin, err - } - - return updatedPin, nil -} - -func CheckPin(storedPinHash string, inputPin string) bool { - err := bcrypt.CompareHashAndPassword([]byte(storedPinHash), []byte(inputPin)) - return err == nil -} diff --git a/middleware/api_key.go b/middleware/api_key.go new file mode 100644 index 0000000..6a720f8 --- /dev/null +++ b/middleware/api_key.go @@ -0,0 +1,24 @@ +package middleware + +import ( + "log" + "os" + + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func APIKeyMiddleware(c *fiber.Ctx) error { + + apiKey := c.Get("x-api-key") + + validAPIKey := os.Getenv("API_KEY") + + if apiKey != validAPIKey { + log.Printf("Invalid API Key: %s", apiKey) + + return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Unauthorized: api key yang anda masukkan tidak valid") + } + + return c.Next() +} diff --git a/domain/user.go b/model/user_model.go similarity index 59% rename from domain/user.go rename to model/user_model.go index 075ead1..e7f6806 100644 --- a/domain/user.go +++ b/model/user_model.go @@ -1,4 +1,4 @@ -package domain +package model import "time" @@ -11,11 +11,6 @@ type User struct { Email string `gorm:"not null" json:"email"` EmailVerified bool `gorm:"default:false" json:"emailVerified"` Password string `gorm:"not null" json:"password"` - Pin UserPin `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"pin"` CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` - RoleID string `gorm:"not null" json:"roleId"` - Role UserRole `gorm:"foreignKey:RoleID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"role"` - AddressId *string `gorm:"default:null" json:"addressId"` - Addresses []Address `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"addresses"` } diff --git a/presentation/auth_route.go b/presentation/auth_route.go new file mode 100644 index 0000000..db16eda --- /dev/null +++ b/presentation/auth_route.go @@ -0,0 +1,26 @@ +package presentation + +import ( + "os" + + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/config" + "github.com/pahmiudahgede/senggoldong/internal/handler" + "github.com/pahmiudahgede/senggoldong/internal/repositories" + "github.com/pahmiudahgede/senggoldong/internal/services" +) + +func AuthRouter(app *fiber.App) { + api := app.Group("/apirijikid") + + secretKey := os.Getenv("SECRET_KEY") + if secretKey == "" { + panic("SECRET_KEY is not set in the environment variables") + } + + userRepo := repositories.NewUserRepository(config.DB) + userService := services.NewUserService(userRepo, secretKey) + userHandler := handler.NewUserHandler(userService) + + api.Post("/login", userHandler.Login) +} diff --git a/presentation/main.go b/presentation/main.go deleted file mode 100644 index c95c8b1..0000000 --- a/presentation/main.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "log" - "os" - - "github.com/gofiber/fiber/v2" - "github.com/joho/godotenv" - "github.com/pahmiudahgede/senggoldong/config" - "github.com/pahmiudahgede/senggoldong/internal/api" -) - -func init() { - err := godotenv.Load() - if err != nil { - log.Fatal("error saat memuat file .env") - } - - config.InitConfig() - config.InitDatabase() - config.InitRedis() - -} - -func main() { - app := fiber.New() - - api.AppRouter(app) - - log.Fatal(app.Listen(":" + os.Getenv("SERVER_PORT"))) -} diff --git a/test/go.txt b/test/go.txt new file mode 100644 index 0000000..45eae7f --- /dev/null +++ b/test/go.txt @@ -0,0 +1 @@ +setup \ No newline at end of file diff --git a/utils/format_time.go b/utils/format_time.go index 5f5b7d8..6536600 100644 --- a/utils/format_time.go +++ b/utils/format_time.go @@ -1,21 +1,22 @@ package utils import ( + "fmt" "log" "time" ) -func FormatDateToIndonesianFormat(t time.Time) string { +func FormatDateToIndonesianFormat(t time.Time) (string, error) { utcTime := t.UTC() loc, err := time.LoadLocation("Asia/Jakarta") if err != nil { log.Printf("Error loading timezone: %v", err) - return "" + return "", fmt.Errorf("could not load location 'Asia/Jakarta'") } indonesianTime := utcTime.In(loc) - return indonesianTime.Format("02-01-2006 15:04") -} + return indonesianTime.Format("02-01-2006 15:04"), nil +} \ No newline at end of file diff --git a/utils/redis_caching.go b/utils/redis_caching.go new file mode 100644 index 0000000..9678b80 --- /dev/null +++ b/utils/redis_caching.go @@ -0,0 +1,67 @@ +package utils + +import ( + "context" + "log" + "time" + + "github.com/go-redis/redis/v8" + "github.com/pahmiudahgede/senggoldong/config" +) + +func SetData(key string, value interface{}, expiration time.Duration) error { + + err := config.RedisClient.Set(context.Background(), key, value, expiration).Err() + if err != nil { + log.Printf("Error setting data to Redis: %v", err) + return err + } + log.Printf("Data stored in Redis with key: %s", key) + return nil +} + +func GetData(key string) (string, error) { + + val, err := config.RedisClient.Get(context.Background(), key).Result() + if err == redis.Nil { + log.Printf("No data found for key: %s", key) + return "", nil + } else if err != nil { + log.Printf("Error getting data from Redis: %v", err) + return "", err + } + log.Printf("Data retrieved from Redis for key: %s", key) + return val, nil +} + +func DeleteData(key string) error { + + err := config.RedisClient.Del(context.Background(), key).Err() + if err != nil { + log.Printf("Error deleting data from Redis: %v", err) + return err + } + log.Printf("Data deleted from Redis with key: %s", key) + return nil +} + +func SetDataWithExpire(key string, value interface{}, expiration time.Duration) error { + + err := config.RedisClient.Set(context.Background(), key, value, expiration).Err() + if err != nil { + log.Printf("Error setting data with expiration to Redis: %v", err) + return err + } + log.Printf("Data stored in Redis with key: %s and expiration: %v", key, expiration) + return nil +} + +func CheckKeyExists(key string) (bool, error) { + + val, err := config.RedisClient.Exists(context.Background(), key).Result() + if err != nil { + log.Printf("Error checking if key exists in Redis: %v", err) + return false, err + } + return val > 0, nil +} diff --git a/utils/response.go b/utils/response.go index 80eb5e5..d26eafe 100644 --- a/utils/response.go +++ b/utils/response.go @@ -1,30 +1,96 @@ package utils -type Meta struct { - StatusCode int `json:"statusCode"` - Message string `json:"message"` +import ( + "github.com/gofiber/fiber/v2" +) + +type MetaData struct { + Status int `json:"status"` + Page int `json:"page,omitempty"` + Limit int `json:"limit,omitempty"` + Total int `json:"total,omitempty"` + Message string `json:"message"` } -type ApiResponse struct { - Meta Meta `json:"meta"` +type APIResponse struct { + Meta MetaData `json:"meta"` Data interface{} `json:"data,omitempty"` } -func FormatResponse(statusCode int, message string, data interface{}) ApiResponse { - return ApiResponse{ - Meta: Meta{ - StatusCode: statusCode, - Message: message, +func PaginatedResponse(c *fiber.Ctx, data interface{}, page, limit, total int, message string) error { + response := APIResponse{ + Meta: MetaData{ + Status: fiber.StatusOK, + Page: page, + Limit: limit, + Total: total, + Message: message, }, Data: data, } + return c.Status(fiber.StatusOK).JSON(response) } -func ErrorResponse(statusCode int, message string) ApiResponse { - return ApiResponse{ - Meta: Meta{ - StatusCode: statusCode, - Message: message, +func NonPaginatedResponse(c *fiber.Ctx, data interface{}, total int, message string) error { + response := APIResponse{ + Meta: MetaData{ + Status: fiber.StatusOK, + Total: total, + Message: message, + }, + Data: data, + } + return c.Status(fiber.StatusOK).JSON(response) +} + +func ErrorResponse(c *fiber.Ctx, message string) error { + response := APIResponse{ + Meta: MetaData{ + Status: fiber.StatusNotFound, + Message: message, }, } -} \ No newline at end of file + return c.Status(fiber.StatusNotFound).JSON(response) +} + +func ValidationErrorResponse(c *fiber.Ctx, errors map[string][]string) error { + response := APIResponse{ + Meta: MetaData{ + Status: fiber.StatusBadRequest, + Message: "invalid user request", + }, + Data: errors, + } + return c.Status(fiber.StatusBadRequest).JSON(response) +} + +func InternalServerErrorResponse(c *fiber.Ctx, message string) error { + response := APIResponse{ + Meta: MetaData{ + Status: fiber.StatusInternalServerError, + Message: message, + }, + } + return c.Status(fiber.StatusInternalServerError).JSON(response) +} + +func GenericErrorResponse(c *fiber.Ctx, status int, message string) error { + response := APIResponse{ + Meta: MetaData{ + Status: status, + Message: message, + }, + } + return c.Status(status).JSON(response) +} + +func LogResponse(c *fiber.Ctx, data interface{}, message string) error { + response := APIResponse{ + Meta: MetaData{ + Status: fiber.StatusOK, + Message: message, + }, + Data: data, + } + return c.Status(fiber.StatusOK).JSON(response) +}