diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8f6fb7e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,71 @@ +# Git +.git +.gitignore +README.md +.gitattributes + +# Documentation +*.md +docs/ + +# Environment files (kecuali yang diperlukan) +.env +.env.local +.env.example +# Kita tetap include .env.dev dan .env.docker untuk development + +# Logs +*.log +logs/ + +# Dependencies +vendor/ + +# Test files +*_test.go +testdata/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.temp +tmp/ + +# Build artifacts (untuk production) +main +*.exe + +# Docker +Dockerfile +docker-compose*.yml +.dockerignore + +# Air specific +.air.toml +tmp/ +*_templ.go + +# Coverage +*.out +coverage.html + +# Database +*.db +*.sqlite +*.sqlite3 + +# Public uploads (jika ada) +public/uploads/ + +# Makefile +Makefile \ No newline at end of file diff --git a/.gitignore b/.gitignore index e3d41dc..73071d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# # Binaries for programs and plugins *.exe *.exe~ @@ -14,17 +11,61 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ +# Dependency directories +vendor/ # Go workspace file go.work go.work.sum -# env file -.env -.env.prod -.env.dev +# Environment files - ignore all variations +.env* +!.env.example -# Ignore public uploads -/public/apirijig/v2/uploads/ \ No newline at end of file +# Logs +*.log +logs/ + +# Temporary files +tmp/ +*.tmp +*.temp + +# IDE/Editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Air live reload tool +.air.toml + +# Public uploads - user generated content +/public/apirijig/v2/uploads/ + +# Build outputs +/bin/ +/build/ +/dist/ + +# Coverage reports +coverage.txt +coverage.html +*.cover + +# Debug files +debug +*.pprof + +# Local development files +*.local \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..c08cd9d --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,28 @@ +# Dockerfile untuk development environment dengan Air hot reload +FROM golang:1.23-alpine + +# Install dependencies dan Air +RUN apk add --no-cache git ca-certificates curl && \ + go install github.com/cosmtrek/air@latest + +# Set working directory +WORKDIR /app + +# Copy go mod files dan download dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Copy source code +COPY . . + +# Create tmp directory untuk Air +RUN mkdir -p tmp + +# Set timezone (optional) +RUN cp /usr/share/zoneinfo/Asia/Jakarta /etc/localtime + +# Expose port +EXPOSE 7000 + +# Run Air untuk hot reload +CMD ["air", "-c", ".air.toml"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6179595 --- /dev/null +++ b/Makefile @@ -0,0 +1,153 @@ +# Makefile untuk mengelola Docker commands + +.PHONY: help build up down restart logs clean dev prod dev-build dev-up dev-down dev-logs + +# Color codes untuk output yang lebih menarik +GREEN := \033[0;32m +YELLOW := \033[1;33m +RED := \033[0;31m +NC := \033[0m # No Color + +# Default target +help: + @echo "$(GREEN)Available commands:$(NC)" + @echo "$(YELLOW)Production:$(NC)" + @echo " build - Build all Docker images" + @echo " up - Start all services" + @echo " down - Stop all services" + @echo " restart - Restart all services" + @echo " logs - Show logs for all services" + @echo " clean - Remove all containers and volumes" + @echo " prod - Start production environment" + @echo "" + @echo "$(YELLOW)Development (dengan Air hot reload):$(NC)" + @echo " dev-build - Build development images" + @echo " dev-up - Start development environment dengan hot reload" + @echo " dev-down - Stop development environment" + @echo " dev-logs - Show development logs" + @echo " dev-clean - Clean development environment" + @echo " dev-restart- Restart development environment" + @echo "" + @echo "$(YELLOW)Utilities:$(NC)" + @echo " app-logs - Show only app logs" + @echo " db-logs - Show only database logs" + @echo " status - Check service status" + @echo " shell - Execute bash in app container" + @echo " psql - Execute psql in postgres container" + @echo " redis-cli - Execute redis-cli in redis container" + +# Production Commands +build: + @echo "$(GREEN)Building production images...$(NC)" + docker compose build --no-cache + +up: + @echo "$(GREEN)Starting production services...$(NC)" + docker compose up -d + +down: + @echo "$(RED)Stopping production services...$(NC)" + docker compose down + +restart: + @echo "$(YELLOW)Restarting production services...$(NC)" + docker compose restart + +logs: + @echo "$(GREEN)Showing production logs...$(NC)" + docker compose logs -f + +clean: + @echo "$(RED)Cleaning production environment...$(NC)" + docker compose down -v --remove-orphans + docker system prune -f + docker volume prune -f + +prod: + @echo "$(GREEN)Starting production environment...$(NC)" + docker compose up -d + +# Development Commands (dengan Air hot reload) +dev-build: + @echo "$(GREEN)Building development images dengan Air...$(NC)" + docker compose -f docker-compose.dev.yml build --no-cache + +dev-up: + @echo "$(GREEN)Starting development environment dengan Air hot reload...$(NC)" + docker compose -f docker-compose.dev.yml up -d + @echo "$(GREEN)Development services started!$(NC)" + @echo "$(YELLOW)API Server: http://localhost:7000$(NC)" + @echo "$(YELLOW)PostgreSQL: localhost:5433$(NC)" + @echo "$(YELLOW)Redis: localhost:6378$(NC)" + @echo "$(YELLOW)pgAdmin: http://localhost:8080 (admin@rijig.com / admin123)$(NC)" + @echo "$(YELLOW)Redis Commander: http://localhost:8081$(NC)" + @echo "" + @echo "$(GREEN)✨ Hot reload is active! Edit your Go files and see changes automatically ✨$(NC)" + +dev-down: + @echo "$(RED)Stopping development services...$(NC)" + docker compose -f docker-compose.dev.yml down + +dev-logs: + @echo "$(GREEN)Showing development logs...$(NC)" + docker compose -f docker-compose.dev.yml logs -f + +dev-clean: + @echo "$(RED)Cleaning development environment...$(NC)" + docker compose -f docker-compose.dev.yml down -v --remove-orphans + docker system prune -f + +dev-restart: + @echo "$(YELLOW)Restarting development services...$(NC)" + docker compose -f docker-compose.dev.yml restart + +# Development utilities +dev-app-logs: + @echo "$(GREEN)Showing development app logs...$(NC)" + docker compose -f docker-compose.dev.yml logs -f app + +dev-db-logs: + @echo "$(GREEN)Showing development database logs...$(NC)" + docker compose -f docker-compose.dev.yml logs -f postgres + +dev-shell: + @echo "$(GREEN)Accessing development app container...$(NC)" + docker compose -f docker-compose.dev.yml exec app sh + +dev-status: + @echo "$(GREEN)Development service status:$(NC)" + docker compose -f docker-compose.dev.yml ps + +# Shared utilities +app-logs: + docker compose logs -f app + +db-logs: + docker compose logs -f postgres + +status: + docker compose ps + +shell: + docker compose exec app sh + +psql: + docker compose exec postgres psql -U postgres -d apirijig_v2 + +redis-cli: + docker compose exec redis redis-cli + +# Rebuild and restart app only +app-rebuild: + docker compose build app + docker compose up -d app + +# View real-time resource usage +stats: + docker stats + +# Quick development setup (recommended) +dev: + @echo "$(GREEN)Setting up complete development environment...$(NC)" + make dev-build + make dev-up \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 46df279..85c404a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,13 +1,11 @@ package main import ( - "log" "rijig/config" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/internal/worker" + // "rijig/internal/repositories" + // "rijig/internal/services" + "rijig/router" - "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" @@ -15,21 +13,21 @@ import ( func main() { config.SetupConfig() - cartRepo := repositories.NewCartRepository() - trashRepo := repositories.NewTrashRepository(config.DB) - cartService := services.NewCartService(cartRepo, trashRepo) - worker := worker.NewCartWorker(cartService, cartRepo, trashRepo) + // cartRepo := repositories.NewCartRepository() + // trashRepo := repositories.NewTrashRepository(config.DB) + // cartService := services.NewCartService(cartRepo, trashRepo) + // worker := worker.NewCartWorker(cartService, cartRepo, trashRepo) - go func() { - ticker := time.NewTicker(30 * time.Second) - defer ticker.Stop() + // go func() { + // ticker := time.NewTicker(30 * time.Second) + // defer ticker.Stop() - for range ticker.C { - if err := worker.AutoCommitExpiringCarts(); err != nil { - log.Printf("Auto-commit error: %v", err) - } - } - }() + // for range ticker.C { + // if err := worker.AutoCommitExpiringCarts(); err != nil { + // log.Printf("Auto-commit error: %v", err) + // } + // } + // }() app := fiber.New(fiber.Config{ ErrorHandler: func(c *fiber.Ctx, err error) error { @@ -45,7 +43,6 @@ func main() { app.Use(cors.New()) - router.SetupRoutes(app) config.StartServer(app) } diff --git a/config/setup_config.go b/config/setup_config.go index b302514..0702601 100644 --- a/config/setup_config.go +++ b/config/setup_config.go @@ -2,17 +2,29 @@ package config import ( "log" + "os" "github.com/joho/godotenv" ) func SetupConfig() { - err := godotenv.Load(".env.dev") - if err != nil { - log.Fatalf("Error loading .env file: %v", err) - } + if _, exists := os.LookupEnv("DOCKER_ENV"); exists { + + log.Println("Running in Docker container, using environment variables") + } else { + + err := godotenv.Load(".env.dev") + if err != nil { + log.Printf("Warning: Error loading .env file: %v", err) + log.Println("Trying to use system environment variables...") + } else { + log.Println("Loaded environment from .env.dev file") + } + } ConnectDatabase() ConnectRedis() - InitWhatsApp() + go func() { + InitWhatsApp() // Ini tidak akan blocking startup server + }() } diff --git a/config/whatsapp.go b/config/whatsapp.go index 1ed9dca..aef3559 100644 --- a/config/whatsapp.go +++ b/config/whatsapp.go @@ -6,7 +6,9 @@ import ( "log" "os" "os/signal" + "sync" "syscall" + "time" _ "github.com/lib/pq" "github.com/mdp/qrterminal/v3" @@ -14,15 +16,64 @@ import ( "go.mau.fi/whatsmeow/proto/waE2E" "go.mau.fi/whatsmeow/store/sqlstore" "go.mau.fi/whatsmeow/types" + "go.mau.fi/whatsmeow/types/events" waLog "go.mau.fi/whatsmeow/util/log" "google.golang.org/protobuf/proto" ) -var WhatsAppClient *whatsmeow.Client -var container *sqlstore.Container +type WhatsAppManager struct { + Client *whatsmeow.Client + container *sqlstore.Container + isConnected bool + mu sync.RWMutex + ctx context.Context + cancel context.CancelFunc + shutdownCh chan struct{} +} + +var ( + waManager *WhatsAppManager + once sync.Once +) + +func GetWhatsAppManager() *WhatsAppManager { + once.Do(func() { + ctx, cancel := context.WithCancel(context.Background()) + waManager = &WhatsAppManager{ + ctx: ctx, + cancel: cancel, + shutdownCh: make(chan struct{}), + } + }) + return waManager +} func InitWhatsApp() { - dbLog := waLog.Stdout("Database", "DEBUG", true) + manager := GetWhatsAppManager() + + log.Println("Initializing WhatsApp client...") + + if err := manager.setupDatabase(); err != nil { + log.Fatalf("Failed to setup WhatsApp database: %v", err) + } + + if err := manager.setupClient(); err != nil { + log.Fatalf("Failed to setup WhatsApp client: %v", err) + } + + if err := manager.handleAuthentication(); err != nil { + log.Fatalf("Failed to authenticate WhatsApp: %v", err) + } + + manager.setupEventHandlers() + + go manager.handleShutdown() + + log.Println("WhatsApp client initialized successfully and ready to send messages!") +} + +func (w *WhatsAppManager) setupDatabase() error { + dbLog := waLog.Stdout("WhatsApp-DB", "ERROR", true) dsn := fmt.Sprintf( "postgres://%s:%s@%s:%s/%s?sslmode=disable", @@ -34,114 +85,291 @@ func InitWhatsApp() { ) var err error - container, err = sqlstore.New("postgres", dsn, dbLog) + w.container, err = sqlstore.New("postgres", dsn, dbLog) if err != nil { - log.Fatalf("Failed to connect to WhatsApp database: %v", err) + return fmt.Errorf("failed to connect to database: %v", err) } - deviceStore, err := container.GetFirstDevice() + log.Println("WhatsApp database connection established") + return nil +} + +func (w *WhatsAppManager) setupClient() error { + deviceStore, err := w.container.GetFirstDevice() if err != nil { - log.Fatalf("Failed to get WhatsApp device: %v", err) + return fmt.Errorf("failed to get device store: %v", err) } - clientLog := waLog.Stdout("Client", "DEBUG", true) - WhatsAppClient = whatsmeow.NewClient(deviceStore, clientLog) + clientLog := waLog.Stdout("WhatsApp-Client", "ERROR", true) + w.Client = whatsmeow.NewClient(deviceStore, clientLog) - if WhatsAppClient.Store.ID == nil { - fmt.Println("WhatsApp Client is not logged in, generating QR Code...") + return nil +} - qrChan, _ := WhatsAppClient.GetQRChannel(context.Background()) - err = WhatsAppClient.Connect() - if err != nil { - log.Fatalf("Failed to connect WhatsApp client: %v", err) - } +func (w *WhatsAppManager) handleAuthentication() error { + if w.Client.Store.ID == nil { + log.Println("WhatsApp client not logged in, generating QR code...") + return w.authenticateWithQR() + } - for evt := range qrChan { - if evt.Event == "code" { - fmt.Println("QR Code untuk login:") + log.Println("WhatsApp client already logged in, connecting...") + return w.connect() +} + +func (w *WhatsAppManager) authenticateWithQR() error { + qrChan, err := w.Client.GetQRChannel(w.ctx) + if err != nil { + return fmt.Errorf("failed to get QR channel: %v", err) + } + + if err := w.Client.Connect(); err != nil { + return fmt.Errorf("failed to connect client: %v", err) + } + + qrTimeout := time.NewTimer(3 * time.Minute) + defer qrTimeout.Stop() + + for { + select { + case evt := <-qrChan: + switch evt.Event { + case "code": + fmt.Println("\n=== QR CODE UNTUK LOGIN WHATSAPP ===") generateQRCode(evt.Code) - } else { - fmt.Println("Login event:", evt.Event) + fmt.Println("Scan QR code di atas dengan WhatsApp Anda") + fmt.Println("QR code akan expired dalam 3 menit") + case "success": + log.Println("✅ WhatsApp login successful!") + w.setConnected(true) + return nil + case "timeout": + return fmt.Errorf("QR code expired, please restart") + default: + log.Printf("Login status: %s", evt.Event) } - } - } else { - fmt.Println("WhatsApp Client sudah login, langsung terhubung...") - err = WhatsAppClient.Connect() - if err != nil { - log.Fatalf("Failed to connect WhatsApp client: %v", err) + case <-qrTimeout.C: + return fmt.Errorf("QR code authentication timeout after 3 minutes") + case <-w.ctx.Done(): + return fmt.Errorf("authentication cancelled") } } +} - log.Println("WhatsApp client connected successfully!") - go handleShutdown() +func (w *WhatsAppManager) connect() error { + if err := w.Client.Connect(); err != nil { + return fmt.Errorf("failed to connect: %v", err) + } + + time.Sleep(2 * time.Second) + w.setConnected(true) + return nil +} + +func (w *WhatsAppManager) setupEventHandlers() { + w.Client.AddEventHandler(func(evt interface{}) { + switch v := evt.(type) { + case *events.Connected: + log.Println("✅ WhatsApp client connected") + w.setConnected(true) + case *events.Disconnected: + log.Println("❌ WhatsApp client disconnected") + w.setConnected(false) + case *events.LoggedOut: + log.Println("🚪 WhatsApp client logged out") + w.setConnected(false) + case *events.Message: + log.Printf("📨 Message received from %s", v.Info.Sender) + } + }) +} + +func (w *WhatsAppManager) setConnected(status bool) { + w.mu.Lock() + defer w.mu.Unlock() + w.isConnected = status +} + +func (w *WhatsAppManager) IsConnected() bool { + w.mu.RLock() + defer w.mu.RUnlock() + return w.isConnected } func generateQRCode(qrString string) { qrterminal.GenerateHalfBlock(qrString, qrterminal.M, os.Stdout) } -func handleShutdown() { +func (w *WhatsAppManager) handleShutdown() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) - <-sigChan + select { + case <-sigChan: + log.Println("Received shutdown signal...") + case <-w.ctx.Done(): + log.Println("Context cancelled...") + } + + w.shutdown() +} + +func (w *WhatsAppManager) shutdown() { log.Println("Shutting down WhatsApp client...") - WhatsAppClient.Disconnect() - os.Exit(0) + + w.cancel() + + if w.Client != nil { + w.Client.Disconnect() + } + + if w.container != nil { + w.container.Close() + } + + close(w.shutdownCh) + log.Println("WhatsApp client shutdown completed") } func SendWhatsAppMessage(phone, message string) error { - if WhatsAppClient == nil { + manager := GetWhatsAppManager() + + if manager.Client == nil { return fmt.Errorf("WhatsApp client is not initialized") } - targetJID, _ := types.ParseJID(phone + "@s.whatsapp.net") - msg := waE2E.Message{ + if !manager.IsConnected() { + return fmt.Errorf("WhatsApp client is not connected") + } + + if phone == "" || message == "" { + return fmt.Errorf("phone number and message cannot be empty") + } + + if phone[0] == '0' { + phone = "62" + phone[1:] // Convert 08xx menjadi 628xx + } + if phone[:2] != "62" { + phone = "62" + phone // Tambahkan 62 jika belum ada + } + + // Parse JID + targetJID, err := types.ParseJID(phone + "@s.whatsapp.net") + if err != nil { + return fmt.Errorf("invalid phone number format: %v", err) + } + + // Buat pesan + msg := &waE2E.Message{ Conversation: proto.String(message), } - _, err := WhatsAppClient.SendMessage(context.Background(), targetJID, &msg) + // Kirim dengan timeout + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + resp, err := manager.Client.SendMessage(ctx, targetJID, msg) if err != nil { - return fmt.Errorf("failed to send WhatsApp message: %v", err) + return fmt.Errorf("failed to send message: %v", err) } - log.Printf("WhatsApp message sent successfully to: %s", phone) + log.Printf("✅ Message sent to %s (ID: %s)", phone, resp.ID) return nil } +// SendWhatsAppMessageBatch - Kirim pesan ke multiple nomor +func SendWhatsAppMessageBatch(phoneNumbers []string, message string) []error { + var errors []error + + for _, phone := range phoneNumbers { + if err := SendWhatsAppMessage(phone, message); err != nil { + errors = append(errors, fmt.Errorf("failed to send to %s: %v", phone, err)) + continue + } + + // Delay untuk menghindari rate limit + time.Sleep(1 * time.Second) + } + + return errors +} + +// GetWhatsAppStatus - Cek status koneksi +func GetWhatsAppStatus() map[string]interface{} { + manager := GetWhatsAppManager() + + status := map[string]interface{}{ + "initialized": manager.Client != nil, + "connected": manager.IsConnected(), + "logged_in": false, + "jid": "", + } + + if manager.Client != nil && manager.Client.Store.ID != nil { + status["logged_in"] = true + status["jid"] = manager.Client.Store.ID.String() + } + + return status +} + +// LogoutWhatsApp - Logout dan cleanup func LogoutWhatsApp() error { - if WhatsAppClient == nil { + manager := GetWhatsAppManager() + + if manager.Client == nil { return fmt.Errorf("WhatsApp client is not initialized") } - WhatsAppClient.Disconnect() + log.Println("Logging out WhatsApp...") - err := removeWhatsAppDeviceFromContainer() + // Logout + err := manager.Client.Logout() if err != nil { - return fmt.Errorf("failed to remove device from container: %v", err) + log.Printf("Warning: Failed to logout properly: %v", err) } - err = container.Close() - if err != nil { - return fmt.Errorf("failed to close database connection: %v", err) + // Disconnect + manager.Client.Disconnect() + manager.setConnected(false) + + // Hapus device dari store + if err := manager.removeDeviceFromStore(); err != nil { + log.Printf("Warning: Failed to remove device: %v", err) } - log.Println("WhatsApp client disconnected and session cleared successfully.") + // Close database + if manager.container != nil { + manager.container.Close() + } + + log.Println("✅ WhatsApp logout completed") return nil } -func removeWhatsAppDeviceFromContainer() error { - deviceStore, err := container.GetFirstDevice() +func (w *WhatsAppManager) removeDeviceFromStore() error { + deviceStore, err := w.container.GetFirstDevice() if err != nil { - return fmt.Errorf("failed to get WhatsApp device: %v", err) + return err } - if deviceStore != nil { - err := deviceStore.Delete() - if err != nil { - return fmt.Errorf("failed to remove device from store: %v", err) - } + if deviceStore != nil && deviceStore.ID != nil { + return deviceStore.Delete() } return nil } + +// IsValidPhoneNumber - Validasi format nomor telepon Indonesia +func IsValidPhoneNumber(phone string) bool { + // Minimal validasi untuk nomor Indonesia + if len(phone) < 10 || len(phone) > 15 { + return false + } + + // Cek awalan nomor Indonesia + if phone[:2] == "62" || phone[0] == '0' { + return true + } + + return false +} diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..e152c00 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,139 @@ +# docker-compose.dev.yml - Development environment dengan Air hot reload +services: + # PostgreSQL Database + postgres: + image: postgres:16-alpine + container_name: rijig_postgres_dev + restart: unless-stopped + environment: + POSTGRES_DB: apirijig_v2 + POSTGRES_USER: postgres + POSTGRES_PASSWORD: pahmiadmin + PGDATA: /var/lib/postgresql/data/pgdata + ports: + - "5433:5432" + volumes: + - postgres_data_dev:/var/lib/postgresql/data + - ./init-db:/docker-entrypoint-initdb.d + networks: + - rijig_network_dev + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d apirijig_v2"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + # Redis Cache + redis: + image: redis:7-alpine + container_name: rijig_redis_dev + restart: unless-stopped + ports: + - "6378:6379" + volumes: + - redis_data_dev:/data + networks: + - rijig_network_dev + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 15s + + # Go Application dengan Air hot reload + app: + build: + context: . + dockerfile: Dockerfile.dev + container_name: rijig_app_dev + restart: unless-stopped + ports: + - "7000:7000" + environment: + # Docker Environment Flag + DOCKER_ENV: "true" + + # Base URL + BASE_URL: /apirijig/v2 + + # Server Settings + SERVER_HOST: 0.0.0.0 + SERVER_PORT: 7000 + + # Database Settings - menggunakan service name sebagai host + DB_HOST: postgres + DB_PORT: 5432 + DB_NAME: apirijig_v2 + DB_USER: postgres + DB_PASSWORD: pahmiadmin + + # Redis Settings - menggunakan service name sebagai host + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: "" + REDIS_DB: 0 + + # Auth Keys + API_KEY: apirijikL0RH64wfkEpPqjAroLVPuFgT0EpsSLBPsmyUvIqZrUAi6X3HNPM7Vter + SECRET_KEY: TJ6h3vPMPlAuv7cbD27RU1/UyRctEih5k4H3+o7tZM1PSwTcoFETL6lqB54= + + # TTL Settings + ACCESS_TOKEN_EXPIRY: 23*time.Hour + REFRESH_TOKEN_EXPIRY: 28*24*time.Hour + PARTIAL_TOKEN_EXPIRY: 2*time.Hour + volumes: + # Mount source code untuk hot reload + - .:/app + # Exclude node_modules dan vendor (jika ada) + - /app/tmp + - /app/vendor + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + networks: + - rijig_network_dev + + # pgAdmin (optional - untuk GUI database management) + pgadmin: + image: dpage/pgadmin4:latest + container_name: rijig_pgadmin_dev + restart: unless-stopped + environment: + PGADMIN_DEFAULT_EMAIL: admin@rijig.com + PGADMIN_DEFAULT_PASSWORD: admin123 + PGADMIN_CONFIG_SERVER_MODE: "False" + ports: + - "8080:80" + volumes: + - pgadmin_data_dev:/var/lib/pgadmin + depends_on: + - postgres + networks: + - rijig_network_dev + + # Redis Commander (optional - untuk GUI redis management) + redis-commander: + image: rediscommander/redis-commander:latest + container_name: rijig_redis_commander_dev + restart: unless-stopped + environment: + REDIS_HOSTS: local:redis:6379 + ports: + - "8081:8081" + depends_on: + - redis + networks: + - rijig_network_dev + +networks: + rijig_network_dev: + driver: bridge + +volumes: + postgres_data_dev: + redis_data_dev: + pgadmin_data_dev: diff --git a/dto/requestpickup_dto.go b/dto/requestpickup_dto.go index 01e7ad7..9ac69bd 100644 --- a/dto/requestpickup_dto.go +++ b/dto/requestpickup_dto.go @@ -38,7 +38,7 @@ type ResponseRequestPickup struct { type ResponseRequestPickupItem struct { ID string `json:"id,omitempty"` TrashCategoryID string `json:"trash_category_id,omitempty"` - TrashCategory []ResponseTrashCategoryDTO `json:"trash_category,omitempty"` + // TrashCategory []ResponseTrashCategoryDTO `json:"trash_category,omitempty"` EstimatedAmount float64 `json:"estimated_amount,omitempty"` } diff --git a/internal/about/about_handler.go b/internal/about/about_handler.go index 4ff94ae..ed2ed65 100644 --- a/internal/about/about_handler.go +++ b/internal/about/about_handler.go @@ -4,17 +4,16 @@ import ( "fmt" "log" "rijig/dto" - "rijig/internal/services" "rijig/utils" "github.com/gofiber/fiber/v2" ) type AboutHandler struct { - AboutService services.AboutService + AboutService AboutService } -func NewAboutHandler(aboutService services.AboutService) *AboutHandler { +func NewAboutHandler(aboutService AboutService) *AboutHandler { return &AboutHandler{ AboutService: aboutService, } @@ -36,7 +35,7 @@ func (h *AboutHandler) CreateAbout(c *fiber.Ctx) error { return utils.BadRequest(c, "Cover image is required") } - response, err := h.AboutService.CreateAbout(request, aboutCoverImage) + response, err := h.AboutService.CreateAbout(c.Context(), request, aboutCoverImage) if err != nil { log.Printf("Error creating About: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to create About: %v", err)) @@ -60,7 +59,7 @@ func (h *AboutHandler) UpdateAbout(c *fiber.Ctx) error { return utils.BadRequest(c, "cover_image is required") } - response, err := h.AboutService.UpdateAbout(id, request, aboutCoverImage) + response, err := h.AboutService.UpdateAbout(c.Context(), id, request, aboutCoverImage) if err != nil { log.Printf("Error updating About: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to update About: %v", err)) @@ -70,7 +69,7 @@ func (h *AboutHandler) UpdateAbout(c *fiber.Ctx) error { } func (h *AboutHandler) GetAllAbout(c *fiber.Ctx) error { - response, err := h.AboutService.GetAllAbout() + response, err := h.AboutService.GetAllAbout(c.Context()) if err != nil { log.Printf("Error fetching all About: %v", err) return utils.InternalServerError(c, "Failed to fetch About list") @@ -82,7 +81,7 @@ func (h *AboutHandler) GetAllAbout(c *fiber.Ctx) error { func (h *AboutHandler) GetAboutByID(c *fiber.Ctx) error { id := c.Params("id") - response, err := h.AboutService.GetAboutByID(id) + response, err := h.AboutService.GetAboutByID(c.Context(), id) if err != nil { log.Printf("Error fetching About by ID: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to fetch About by ID: %v", err)) @@ -94,7 +93,7 @@ func (h *AboutHandler) GetAboutByID(c *fiber.Ctx) error { func (h *AboutHandler) GetAboutDetailById(c *fiber.Ctx) error { id := c.Params("id") - response, err := h.AboutService.GetAboutDetailById(id) + response, err := h.AboutService.GetAboutDetailById(c.Context(), id) if err != nil { log.Printf("Error fetching About detail by ID: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to fetch About by ID: %v", err)) @@ -106,7 +105,7 @@ func (h *AboutHandler) GetAboutDetailById(c *fiber.Ctx) error { func (h *AboutHandler) DeleteAbout(c *fiber.Ctx) error { id := c.Params("id") - if err := h.AboutService.DeleteAbout(id); err != nil { + if err := h.AboutService.DeleteAbout(c.Context(), id); err != nil { log.Printf("Error deleting About: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to delete About: %v", err)) } @@ -132,7 +131,7 @@ func (h *AboutHandler) CreateAboutDetail(c *fiber.Ctx) error { return utils.BadRequest(c, "image_detail is required") } - response, err := h.AboutService.CreateAboutDetail(request, aboutDetailImage) + response, err := h.AboutService.CreateAboutDetail(c.Context(), request, aboutDetailImage) if err != nil { log.Printf("Error creating AboutDetail: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to create AboutDetail: %v", err)) @@ -156,7 +155,7 @@ func (h *AboutHandler) UpdateAboutDetail(c *fiber.Ctx) error { return utils.BadRequest(c, "image_detail is required") } - response, err := h.AboutService.UpdateAboutDetail(id, request, aboutDetailImage) + response, err := h.AboutService.UpdateAboutDetail(c.Context(), id, request, aboutDetailImage) if err != nil { log.Printf("Error updating AboutDetail: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to update AboutDetail: %v", err)) @@ -168,7 +167,7 @@ func (h *AboutHandler) UpdateAboutDetail(c *fiber.Ctx) error { func (h *AboutHandler) DeleteAboutDetail(c *fiber.Ctx) error { id := c.Params("id") - if err := h.AboutService.DeleteAboutDetail(id); err != nil { + if err := h.AboutService.DeleteAboutDetail(c.Context(), id); err != nil { log.Printf("Error deleting AboutDetail: %v", err) return utils.InternalServerError(c, fmt.Sprintf("Failed to delete AboutDetail: %v", err)) } diff --git a/internal/about/about_route.go b/internal/about/about_route.go index 5f6c9a3..03dfa0d 100644 --- a/internal/about/about_route.go +++ b/internal/about/about_route.go @@ -1 +1,32 @@ -package about \ No newline at end of file +package about + +import ( + "rijig/config" + "rijig/middleware" + "rijig/utils" + + "github.com/gofiber/fiber/v2" +) + +func AboutRouter(api fiber.Router) { + aboutRepo := NewAboutRepository(config.DB) + aboutService := NewAboutService(aboutRepo) + aboutHandler := NewAboutHandler(aboutService) + + aboutRoutes := api.Group("/about") + aboutRoutes.Use(middleware.AuthMiddleware()) + + aboutRoutes.Get("/", aboutHandler.GetAllAbout) + aboutRoutes.Get("/:id", aboutHandler.GetAboutByID) + aboutRoutes.Post("/", aboutHandler.CreateAbout) + aboutRoutes.Put("/:id", middleware.RequireRoles(utils.RoleAdministrator), aboutHandler.UpdateAbout) + aboutRoutes.Delete("/:id", aboutHandler.DeleteAbout) + + aboutDetailRoutes := api.Group("/about-detail") + aboutDetailRoutes.Use(middleware.AuthMiddleware()) + aboutDetailRoute := api.Group("/about-detail") + aboutDetailRoute.Get("/:id", aboutHandler.GetAboutDetailById) + aboutDetailRoutes.Post("/", aboutHandler.CreateAboutDetail) + aboutDetailRoutes.Put("/:id", middleware.RequireRoles(utils.RoleAdministrator), aboutHandler.UpdateAboutDetail) + aboutDetailRoutes.Delete("/:id", middleware.RequireRoles(utils.RoleAdministrator), aboutHandler.DeleteAboutDetail) +} diff --git a/internal/address/address_handler.go b/internal/address/address_handler.go index 0d5cc40..1c4eb44 100644 --- a/internal/address/address_handler.go +++ b/internal/address/address_handler.go @@ -1 +1,113 @@ -package address \ No newline at end of file +package address + +import ( + "rijig/dto" + "rijig/middleware" + "rijig/utils" + + "github.com/gofiber/fiber/v2" +) + +type AddressHandler struct { + AddressService AddressService +} + +func NewAddressHandler(addressService AddressService) *AddressHandler { + return &AddressHandler{AddressService: addressService} +} + +func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error { + var request dto.CreateAddressDTO + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + + if err := c.BodyParser(&request); err != nil { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Invalid request body", map[string][]string{"body": {"Invalid body"}}) + } + + errors, valid := request.ValidateAddress() + if !valid { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", errors) + } + addressResponse, err := h.AddressService.CreateAddress(c.Context(), claims.UserID, request) + if err != nil { + return utils.InternalServerError(c, err.Error()) + } + + return utils.CreateSuccessWithData(c, "user address created successfully", addressResponse) +} + +func (h *AddressHandler) GetAddressByUserID(c *fiber.Ctx) error { + + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + + addresses, err := h.AddressService.GetAddressByUserID(c.Context(), claims.UserID) + if err != nil { + return utils.NotFound(c, err.Error()) + } + + return utils.SuccessWithData(c, "User addresses fetched successfully", addresses) +} + +func (h *AddressHandler) GetAddressByID(c *fiber.Ctx) error { + + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + addressID := c.Params("address_id") + + address, err := h.AddressService.GetAddressByID(c.Context(), claims.UserID, addressID) + if err != nil { + return utils.NotFound(c, err.Error()) + } + + return utils.SuccessWithData(c, "Address fetched successfully", address) +} + +func (h *AddressHandler) UpdateAddress(c *fiber.Ctx) error { + + addressID := c.Params("address_id") + + var request dto.CreateAddressDTO + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + + if err := c.BodyParser(&request); err != nil { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Invalid request body", map[string][]string{"body": {"Invalid body"}}) + } + + errors, valid := request.ValidateAddress() + if !valid { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", errors) + } + + updatedAddress, err := h.AddressService.UpdateAddress(c.Context(), claims.UserID, addressID, request) + if err != nil { + return utils.NotFound(c, err.Error()) + } + + return utils.SuccessWithData(c, "User address updated successfully", updatedAddress) +} + +func (h *AddressHandler) DeleteAddress(c *fiber.Ctx) error { + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + addressID := c.Params("address_id") + + err = h.AddressService.DeleteAddress(c.Context(), claims.UserID, addressID) + if err != nil { + return utils.Forbidden(c, err.Error()) + } + + return utils.Success(c, "Address deleted successfully") +} diff --git a/internal/address/address_route.go b/internal/address/address_route.go index 0d5cc40..1eb7dd4 100644 --- a/internal/address/address_route.go +++ b/internal/address/address_route.go @@ -1 +1,24 @@ -package address \ No newline at end of file +package address + +import ( + "rijig/config" + "rijig/internal/wilayahindo" + "rijig/middleware" + + "github.com/gofiber/fiber/v2" +) + +func AddressRouter(api fiber.Router) { + addressRepo := NewAddressRepository(config.DB) + wilayahRepo := wilayahindo.NewWilayahIndonesiaRepository(config.DB) + addressService := NewAddressService(addressRepo, wilayahRepo) + addressHandler := NewAddressHandler(addressService) + + adddressAPI := api.Group("/user/address") + + adddressAPI.Post("/create-address", middleware.AuthMiddleware(), addressHandler.CreateAddress) + adddressAPI.Get("/get-address", middleware.AuthMiddleware(), addressHandler.GetAddressByUserID) + adddressAPI.Get("/get-address/:address_id", middleware.AuthMiddleware(), addressHandler.GetAddressByID) + adddressAPI.Put("/update-address/:address_id", middleware.AuthMiddleware(), addressHandler.UpdateAddress) + adddressAPI.Delete("/delete-address/:address_id", middleware.AuthMiddleware(), addressHandler.DeleteAddress) +} diff --git a/internal/article/article_route.go b/internal/article/article_route.go index e2928e0..78179aa 100644 --- a/internal/article/article_route.go +++ b/internal/article/article_route.go @@ -2,9 +2,6 @@ package article import ( "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" "rijig/middleware" "rijig/utils" @@ -12,9 +9,9 @@ import ( ) func ArticleRouter(api fiber.Router) { - articleRepo := repositories.NewArticleRepository(config.DB) - articleService := services.NewArticleService(articleRepo) - articleHandler := handler.NewArticleHandler(articleService) + articleRepo := NewArticleRepository(config.DB) + articleService := NewArticleService(articleRepo) + articleHandler := NewArticleHandler(articleService) articleAPI := api.Group("/article") diff --git a/internal/cart/cart_dto.go b/internal/cart/cart_dto.go index 795236c..3c6dfc5 100644 --- a/internal/cart/cart_dto.go +++ b/internal/cart/cart_dto.go @@ -1 +1,49 @@ -package cart \ No newline at end of file +package cart + +import ( + "fmt" + "strings" +) + +type RequestCartItemDTO struct { + TrashID string `json:"trash_id"` + Amount float64 `json:"amount"` +} + +type RequestCartDTO struct { + CartItems []RequestCartItemDTO `json:"cart_items"` +} + +type CartResponse struct { + ID string `json:"id"` + UserID string `json:"user_id"` + TotalAmount float64 `json:"total_amount"` + EstimatedTotalPrice float64 `json:"estimated_total_price"` + CartItems []CartItemResponse `json:"cart_items"` +} + +type CartItemResponse struct { + ID string `json:"id"` + TrashID string `json:"trash_id"` + TrashName string `json:"trash_name"` + TrashIcon string `json:"trash_icon"` + TrashPrice float64 `json:"trash_price"` + Amount float64 `json:"amount"` + SubTotalEstimatedPrice float64 `json:"subtotal_estimated_price"` +} + +func (r *RequestCartDTO) ValidateRequestCartDTO() (map[string][]string, bool) { + errors := make(map[string][]string) + + for i, item := range r.CartItems { + if strings.TrimSpace(item.TrashID) == "" { + errors[fmt.Sprintf("cart_items[%d].trash_id", i)] = append(errors[fmt.Sprintf("cart_items[%d].trash_id", i)], "trash_id tidak boleh kosong") + } + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} diff --git a/internal/cart/cart_repository.go b/internal/cart/cart_repository.go index 795236c..f68d1b2 100644 --- a/internal/cart/cart_repository.go +++ b/internal/cart/cart_repository.go @@ -1 +1,162 @@ -package cart \ No newline at end of file +package cart + +import ( + "context" + "errors" + "fmt" + + "rijig/config" + "rijig/model" + + "gorm.io/gorm" +) + +type CartRepository interface { + FindOrCreateCart(ctx context.Context, userID string) (*model.Cart, error) + AddOrUpdateCartItem(ctx context.Context, cartID, trashCategoryID string, amount float64, estimatedPrice float64) error + DeleteCartItem(ctx context.Context, cartID, trashCategoryID string) error + GetCartByUser(ctx context.Context, userID string) (*model.Cart, error) + UpdateCartTotals(ctx context.Context, cartID string) error + DeleteCart(ctx context.Context, userID string) error + + CreateCartWithItems(ctx context.Context, cart *model.Cart) error + HasExistingCart(ctx context.Context, userID string) (bool, error) +} + +type cartRepository struct{} + +func NewCartRepository() CartRepository { + return &cartRepository{} +} + +func (r *cartRepository) FindOrCreateCart(ctx context.Context, userID string) (*model.Cart, error) { + var cart model.Cart + db := config.DB.WithContext(ctx) + + err := db. + Preload("CartItems.TrashCategory"). + Where("user_id = ?", userID). + First(&cart).Error + + if err == nil { + return &cart, nil + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + newCart := model.Cart{ + UserID: userID, + TotalAmount: 0, + EstimatedTotalPrice: 0, + } + if err := db.Create(&newCart).Error; err != nil { + return nil, err + } + return &newCart, nil + } + + return nil, err +} + +func (r *cartRepository) AddOrUpdateCartItem(ctx context.Context, cartID, trashCategoryID string, amount float64, estimatedPrice float64) error { + db := config.DB.WithContext(ctx) + + var item model.CartItem + err := db. + Where("cart_id = ? AND trash_category_id = ?", cartID, trashCategoryID). + First(&item).Error + + if errors.Is(err, gorm.ErrRecordNotFound) { + newItem := model.CartItem{ + CartID: cartID, + TrashCategoryID: trashCategoryID, + Amount: amount, + SubTotalEstimatedPrice: amount * estimatedPrice, + } + return db.Create(&newItem).Error + } + + if err != nil { + return err + } + + item.Amount = amount + item.SubTotalEstimatedPrice = amount * estimatedPrice + return db.Save(&item).Error +} + +func (r *cartRepository) DeleteCartItem(ctx context.Context, cartID, trashCategoryID string) error { + db := config.DB.WithContext(ctx) + return db.Where("cart_id = ? AND trash_category_id = ?", cartID, trashCategoryID). + Delete(&model.CartItem{}).Error +} + +func (r *cartRepository) GetCartByUser(ctx context.Context, userID string) (*model.Cart, error) { + var cart model.Cart + db := config.DB.WithContext(ctx) + + err := db. + Preload("CartItems.TrashCategory"). + Where("user_id = ?", userID). + First(&cart).Error + + if err != nil { + return nil, err + } + return &cart, nil +} + +func (r *cartRepository) UpdateCartTotals(ctx context.Context, cartID string) error { + db := config.DB.WithContext(ctx) + + var items []model.CartItem + if err := db.Where("cart_id = ?", cartID).Find(&items).Error; err != nil { + return err + } + + var totalAmount float64 + var totalPrice float64 + + for _, item := range items { + totalAmount += item.Amount + totalPrice += item.SubTotalEstimatedPrice + } + + return db.Model(&model.Cart{}). + Where("id = ?", cartID). + Updates(map[string]interface{}{ + "total_amount": totalAmount, + "estimated_total_price": totalPrice, + }).Error +} + +func (r *cartRepository) DeleteCart(ctx context.Context, userID string) error { + db := config.DB.WithContext(ctx) + var cart model.Cart + if err := db.Where("user_id = ?", userID).First(&cart).Error; err != nil { + return err + } + return db.Delete(&cart).Error +} + +func (r *cartRepository) CreateCartWithItems(ctx context.Context, cart *model.Cart) error { + db := config.DB.WithContext(ctx) + + return db.Transaction(func(tx *gorm.DB) error { + if err := tx.Create(cart).Error; err != nil { + return fmt.Errorf("failed to create cart: %w", err) + } + return nil + }) +} + +func (r *cartRepository) HasExistingCart(ctx context.Context, userID string) (bool, error) { + db := config.DB.WithContext(ctx) + + var count int64 + err := db.Model(&model.Cart{}).Where("user_id = ?", userID).Count(&count).Error + if err != nil { + return false, err + } + + return count > 0, nil +} diff --git a/internal/cart/cart_service.go b/internal/cart/cart_service.go index 795236c..6684252 100644 --- a/internal/cart/cart_service.go +++ b/internal/cart/cart_service.go @@ -1 +1,356 @@ -package cart \ No newline at end of file +package cart + +import ( + "context" + "fmt" + "log" + "time" + + "rijig/internal/trash" + "rijig/model" + "rijig/utils" + + "github.com/google/uuid" +) + +type CartService struct { + cartRepo CartRepository + trashRepo trash.TrashRepositoryInterface +} + +func NewCartService(cartRepo CartRepository, trashRepo trash.TrashRepositoryInterface) *CartService { + return &CartService{ + cartRepo: cartRepo, + trashRepo: trashRepo, + } +} + +func (s *CartService) AddToCart(ctx context.Context, userID, trashCategoryID string, amount float64) error { + cartKey := fmt.Sprintf("cart:%s", userID) + + var cartItems map[string]model.CartItem + err := utils.GetCache(cartKey, &cartItems) + if err != nil && err.Error() != "ErrCacheMiss" { + return fmt.Errorf("failed to get cart from cache: %w", err) + } + + if cartItems == nil { + cartItems = make(map[string]model.CartItem) + } + + trashCategory, err := s.trashRepo.GetTrashCategoryByID(ctx, trashCategoryID) + if err != nil { + return fmt.Errorf("failed to get trash category: %w", err) + } + + cartItems[trashCategoryID] = model.CartItem{ + TrashCategoryID: trashCategoryID, + Amount: amount, + SubTotalEstimatedPrice: amount * float64(trashCategory.EstimatedPrice), + } + + return utils.SetCache(cartKey, cartItems, 24*time.Hour) +} + +func (s *CartService) RemoveFromCart(ctx context.Context, userID, trashCategoryID string) error { + cartKey := fmt.Sprintf("cart:%s", userID) + + var cartItems map[string]model.CartItem + err := utils.GetCache(cartKey, &cartItems) + if err != nil { + if err.Error() == "ErrCacheMiss" { + return nil + } + return fmt.Errorf("failed to get cart from cache: %w", err) + } + + delete(cartItems, trashCategoryID) + + if len(cartItems) == 0 { + return utils.DeleteCache(cartKey) + } + + return utils.SetCache(cartKey, cartItems, 24*time.Hour) +} + +func (s *CartService) ClearCart(userID string) error { + cartKey := fmt.Sprintf("cart:%s", userID) + return utils.DeleteCache(cartKey) +} + +func (s *CartService) GetCartFromRedis(ctx context.Context, userID string) (*CartResponse, error) { + cartKey := fmt.Sprintf("cart:%s", userID) + + var cartItems map[string]model.CartItem + err := utils.GetCache(cartKey, &cartItems) + if err != nil { + if err.Error() == "ErrCacheMiss" { + return &CartResponse{ + ID: "N/A", + UserID: userID, + TotalAmount: 0, + EstimatedTotalPrice: 0, + CartItems: []CartItemResponse{}, + }, nil + } + return nil, fmt.Errorf("failed to get cart from cache: %w", err) + } + + var totalAmount float64 + var estimatedTotal float64 + var cartItemDTOs []CartItemResponse + + for _, item := range cartItems { + trashCategory, err := s.trashRepo.GetTrashCategoryByID(ctx, item.TrashCategoryID) + if err != nil { + log.Printf("Failed to get trash category %s: %v", item.TrashCategoryID, err) + continue + } + + totalAmount += item.Amount + estimatedTotal += item.SubTotalEstimatedPrice + + cartItemDTOs = append(cartItemDTOs, CartItemResponse{ + ID: uuid.NewString(), + TrashID: trashCategory.ID, + TrashName: trashCategory.Name, + TrashIcon: trashCategory.IconTrash, + TrashPrice: float64(trashCategory.EstimatedPrice), + Amount: item.Amount, + SubTotalEstimatedPrice: item.SubTotalEstimatedPrice, + }) + } + + resp := &CartResponse{ + ID: "N/A", + UserID: userID, + TotalAmount: totalAmount, + EstimatedTotalPrice: estimatedTotal, + CartItems: cartItemDTOs, + } + + return resp, nil +} + +func (s *CartService) CommitCartToDatabase(ctx context.Context, userID string) error { + cartKey := fmt.Sprintf("cart:%s", userID) + + var cartItems map[string]model.CartItem + err := utils.GetCache(cartKey, &cartItems) + if err != nil { + if err.Error() == "ErrCacheMiss" { + log.Printf("No cart items found in Redis for user: %s", userID) + return fmt.Errorf("no cart items found") + } + return fmt.Errorf("failed to get cart from cache: %w", err) + } + + if len(cartItems) == 0 { + log.Printf("No items to commit for user: %s", userID) + return fmt.Errorf("no items to commit") + } + + hasCart, err := s.cartRepo.HasExistingCart(ctx, userID) + if err != nil { + return fmt.Errorf("failed to check existing cart: %w", err) + } + + var cart *model.Cart + if hasCart { + + cart, err = s.cartRepo.GetCartByUser(ctx, userID) + if err != nil { + return fmt.Errorf("failed to get existing cart: %w", err) + } + } else { + + cart, err = s.cartRepo.FindOrCreateCart(ctx, userID) + if err != nil { + return fmt.Errorf("failed to create cart: %w", err) + } + } + + for _, item := range cartItems { + trashCategory, err := s.trashRepo.GetTrashCategoryByID(ctx, item.TrashCategoryID) + if err != nil { + log.Printf("Trash category not found for trashID: %s", item.TrashCategoryID) + continue + } + + err = s.cartRepo.AddOrUpdateCartItem( + ctx, + cart.ID, + item.TrashCategoryID, + item.Amount, + float64(trashCategory.EstimatedPrice), + ) + if err != nil { + log.Printf("Failed to add/update cart item: %v", err) + continue + } + } + + if err := s.cartRepo.UpdateCartTotals(ctx, cart.ID); err != nil { + return fmt.Errorf("failed to update cart totals: %w", err) + } + + if err := utils.DeleteCache(cartKey); err != nil { + log.Printf("Failed to clear Redis cart: %v", err) + } + + log.Printf("Cart committed successfully for user: %s", userID) + return nil +} + +func (s *CartService) GetCart(ctx context.Context, userID string) (*CartResponse, error) { + + cartRedis, err := s.GetCartFromRedis(ctx, userID) + if err == nil && len(cartRedis.CartItems) > 0 { + return cartRedis, nil + } + + cartDB, err := s.cartRepo.GetCartByUser(ctx, userID) + if err != nil { + + return &CartResponse{ + ID: "N/A", + UserID: userID, + TotalAmount: 0, + EstimatedTotalPrice: 0, + CartItems: []CartItemResponse{}, + }, nil + } + + var items []CartItemResponse + for _, item := range cartDB.CartItems { + items = append(items, CartItemResponse{ + ID: item.ID, + TrashID: item.TrashCategoryID, + TrashName: item.TrashCategory.Name, + TrashIcon: item.TrashCategory.IconTrash, + TrashPrice: float64(item.TrashCategory.EstimatedPrice), + Amount: item.Amount, + SubTotalEstimatedPrice: item.SubTotalEstimatedPrice, + }) + } + + resp := &CartResponse{ + ID: cartDB.ID, + UserID: cartDB.UserID, + TotalAmount: cartDB.TotalAmount, + EstimatedTotalPrice: cartDB.EstimatedTotalPrice, + CartItems: items, + } + + return resp, nil +} + +func (s *CartService) SyncCartFromDatabaseToRedis(ctx context.Context, userID string) error { + + cartDB, err := s.cartRepo.GetCartByUser(ctx, userID) + if err != nil { + return fmt.Errorf("failed to get cart from database: %w", err) + } + + cartItems := make(map[string]model.CartItem) + for _, item := range cartDB.CartItems { + cartItems[item.TrashCategoryID] = model.CartItem{ + TrashCategoryID: item.TrashCategoryID, + Amount: item.Amount, + SubTotalEstimatedPrice: item.SubTotalEstimatedPrice, + } + } + + cartKey := fmt.Sprintf("cart:%s", userID) + return utils.SetCache(cartKey, cartItems, 24*time.Hour) +} + +func (s *CartService) GetCartItemCount(userID string) (int, error) { + cartKey := fmt.Sprintf("cart:%s", userID) + + var cartItems map[string]model.CartItem + err := utils.GetCache(cartKey, &cartItems) + if err != nil { + if err.Error() == "ErrCacheMiss" { + return 0, nil + } + return 0, fmt.Errorf("failed to get cart from cache: %w", err) + } + + return len(cartItems), nil +} + +func (s *CartService) DeleteCart(ctx context.Context, userID string) error { + + cartKey := fmt.Sprintf("cart:%s", userID) + if err := utils.DeleteCache(cartKey); err != nil { + log.Printf("Failed to delete cart from Redis: %v", err) + } + + return s.cartRepo.DeleteCart(ctx, userID) +} + +func (s *CartService) UpdateCartWithDTO(ctx context.Context, userID string, cartDTO *RequestCartDTO) error { + + if errors, valid := cartDTO.ValidateRequestCartDTO(); !valid { + return fmt.Errorf("validation failed: %v", errors) + } + + cartKey := fmt.Sprintf("cart:%s", userID) + cartItems := make(map[string]model.CartItem) + + for _, itemDTO := range cartDTO.CartItems { + + trashCategory, err := s.trashRepo.GetTrashCategoryByID(ctx, itemDTO.TrashID) + if err != nil { + log.Printf("Failed to get trash category %s: %v", itemDTO.TrashID, err) + continue + } + + subtotal := itemDTO.Amount * float64(trashCategory.EstimatedPrice) + + cartItems[itemDTO.TrashID] = model.CartItem{ + TrashCategoryID: itemDTO.TrashID, + Amount: itemDTO.Amount, + SubTotalEstimatedPrice: subtotal, + } + } + + return utils.SetCache(cartKey, cartItems, 24*time.Hour) +} + +func (s *CartService) AddItemsToCart(ctx context.Context, userID string, items []RequestCartItemDTO) error { + cartKey := fmt.Sprintf("cart:%s", userID) + + var cartItems map[string]model.CartItem + err := utils.GetCache(cartKey, &cartItems) + if err != nil && err.Error() != "ErrCacheMiss" { + return fmt.Errorf("failed to get cart from cache: %w", err) + } + + if cartItems == nil { + cartItems = make(map[string]model.CartItem) + } + + for _, itemDTO := range items { + if itemDTO.TrashID == "" { + continue + } + + trashCategory, err := s.trashRepo.GetTrashCategoryByID(ctx, itemDTO.TrashID) + if err != nil { + log.Printf("Failed to get trash category %s: %v", itemDTO.TrashID, err) + continue + } + + subtotal := itemDTO.Amount * float64(trashCategory.EstimatedPrice) + + cartItems[itemDTO.TrashID] = model.CartItem{ + TrashCategoryID: itemDTO.TrashID, + Amount: itemDTO.Amount, + SubTotalEstimatedPrice: subtotal, + } + } + + return utils.SetCache(cartKey, cartItems, 24*time.Hour) +} diff --git a/internal/collector/collector_dto.go b/internal/collector/collector_dto.go index c87b2bd..f7a4db4 100644 --- a/internal/collector/collector_dto.go +++ b/internal/collector/collector_dto.go @@ -1 +1,252 @@ -package collector \ No newline at end of file +package collector + +import ( + "fmt" + "rijig/internal/address" + "rijig/internal/trash" + "strings" + "time" +) + +type CreateCollectorRequest struct { + UserID string `json:"user_id" binding:"required"` + JobStatus string `json:"job_status,omitempty"` + AddressID string `json:"address_id" binding:"required"` + AvailableTrashItems []CreateAvailableTrashRequest `json:"available_trash_items,omitempty"` +} + +type UpdateCollectorRequest struct { + JobStatus string `json:"job_status,omitempty"` + AddressID string `json:"address_id,omitempty"` + AvailableTrashItems []CreateAvailableTrashRequest `json:"available_trash_items,omitempty"` +} + +type CreateAvailableTrashRequest struct { + TrashCategoryID string `json:"trash_category_id" binding:"required"` + Price float32 `json:"price" binding:"required"` +} + +type UpdateAvailableTrashRequest struct { + ID string `json:"id,omitempty"` + TrashCategoryID string `json:"trash_category_id,omitempty"` + Price float32 `json:"price,omitempty"` +} + +type CollectorResponse struct { + ID string `json:"id"` + UserID string `json:"user_id"` + JobStatus string `json:"job_status"` + Rating float32 `json:"rating"` + AddressID string `json:"address_id"` + Address *address.AddressResponseDTO `json:"address,omitempty"` + AvailableTrash []AvailableTrashResponse `json:"available_trash"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type AvailableTrashResponse struct { + ID string `json:"id"` + CollectorID string `json:"collector_id"` + TrashCategoryID string `json:"trash_category_id"` + TrashCategory *trash.ResponseTrashCategoryDTO `json:"trash_category,omitempty"` + Price float32 `json:"price"` +} + +func (r *CreateCollectorRequest) ValidateCreateCollectorRequest() (map[string][]string, bool) { + errors := make(map[string][]string) + + if strings.TrimSpace(r.UserID) == "" { + errors["user_id"] = append(errors["user_id"], "User ID tidak boleh kosong") + } + + if strings.TrimSpace(r.AddressID) == "" { + errors["address_id"] = append(errors["address_id"], "Address ID tidak boleh kosong") + } + + if r.JobStatus != "" { + r.JobStatus = strings.ToLower(strings.TrimSpace(r.JobStatus)) + if r.JobStatus != "active" && r.JobStatus != "inactive" { + errors["job_status"] = append(errors["job_status"], "Job status hanya boleh 'active' atau 'inactive'") + } + } else { + r.JobStatus = "inactive" + } + + if len(r.AvailableTrashItems) > 0 { + trashCategoryMap := make(map[string]bool) + for i, item := range r.AvailableTrashItems { + fieldPrefix := fmt.Sprintf("available_trash_items[%d]", i) + + if strings.TrimSpace(item.TrashCategoryID) == "" { + errors[fieldPrefix+".trash_category_id"] = append(errors[fieldPrefix+".trash_category_id"], "Trash category ID tidak boleh kosong") + } else { + + if trashCategoryMap[item.TrashCategoryID] { + errors[fieldPrefix+".trash_category_id"] = append(errors[fieldPrefix+".trash_category_id"], "Trash category ID sudah ada dalam daftar") + } else { + trashCategoryMap[item.TrashCategoryID] = true + } + } + + if item.Price <= 0 { + errors[fieldPrefix+".price"] = append(errors[fieldPrefix+".price"], "Harga harus lebih dari 0") + } + } + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} + +func (r *UpdateCollectorRequest) ValidateUpdateCollectorRequest() (map[string][]string, bool) { + errors := make(map[string][]string) + + if r.JobStatus != "" { + r.JobStatus = strings.ToLower(strings.TrimSpace(r.JobStatus)) + if r.JobStatus != "active" && r.JobStatus != "inactive" { + errors["job_status"] = append(errors["job_status"], "Job status hanya boleh 'active' atau 'inactive'") + } + } + + if r.AddressID != "" && strings.TrimSpace(r.AddressID) == "" { + errors["address_id"] = append(errors["address_id"], "Address ID tidak boleh kosong jika disediakan") + } + + if len(r.AvailableTrashItems) > 0 { + trashCategoryMap := make(map[string]bool) + for i, item := range r.AvailableTrashItems { + fieldPrefix := fmt.Sprintf("available_trash_items[%d]", i) + + if strings.TrimSpace(item.TrashCategoryID) == "" { + errors[fieldPrefix+".trash_category_id"] = append(errors[fieldPrefix+".trash_category_id"], "Trash category ID tidak boleh kosong") + } else { + + if trashCategoryMap[item.TrashCategoryID] { + errors[fieldPrefix+".trash_category_id"] = append(errors[fieldPrefix+".trash_category_id"], "Trash category ID sudah ada dalam daftar") + } else { + trashCategoryMap[item.TrashCategoryID] = true + } + } + + if item.Price <= 0 { + errors[fieldPrefix+".price"] = append(errors[fieldPrefix+".price"], "Harga harus lebih dari 0") + } + } + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} + +func (r *CreateAvailableTrashRequest) ValidateCreateAvailableTrashRequest() (map[string][]string, bool) { + errors := make(map[string][]string) + + if strings.TrimSpace(r.TrashCategoryID) == "" { + errors["trash_category_id"] = append(errors["trash_category_id"], "Trash category ID tidak boleh kosong") + } + + if r.Price <= 0 { + errors["price"] = append(errors["price"], "Harga harus lebih dari 0") + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} + +func (r *UpdateAvailableTrashRequest) ValidateUpdateAvailableTrashRequest() (map[string][]string, bool) { + errors := make(map[string][]string) + + if r.TrashCategoryID != "" && strings.TrimSpace(r.TrashCategoryID) == "" { + errors["trash_category_id"] = append(errors["trash_category_id"], "Trash category ID tidak boleh kosong jika disediakan") + } + + if r.Price != 0 && r.Price <= 0 { + errors["price"] = append(errors["price"], "Harga harus lebih dari 0 jika disediakan") + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} + +func (r *CreateCollectorRequest) IsValidJobStatus(status string) bool { + status = strings.ToLower(strings.TrimSpace(status)) + return status == "active" || status == "inactive" +} + +func (r *UpdateCollectorRequest) IsValidJobStatus(status string) bool { + status = strings.ToLower(strings.TrimSpace(status)) + return status == "active" || status == "inactive" +} + +func (r *CollectorResponse) FormatTimestamp(t time.Time) string { + return t.Format(time.RFC3339) +} + +func (r *CreateCollectorRequest) SetDefaults() { + if r.JobStatus == "" { + r.JobStatus = "inactive" + } else { + r.JobStatus = strings.ToLower(strings.TrimSpace(r.JobStatus)) + } +} + +func (r *UpdateCollectorRequest) NormalizeJobStatus() { + if r.JobStatus != "" { + r.JobStatus = strings.ToLower(strings.TrimSpace(r.JobStatus)) + } +} + +type BulkUpdateAvailableTrashRequest struct { + CollectorID string `json:"collector_id" binding:"required"` + AvailableTrashItems []CreateAvailableTrashRequest `json:"available_trash_items" binding:"required"` +} + +func (r *BulkUpdateAvailableTrashRequest) ValidateBulkUpdateAvailableTrashRequest() (map[string][]string, bool) { + errors := make(map[string][]string) + + if strings.TrimSpace(r.CollectorID) == "" { + errors["collector_id"] = append(errors["collector_id"], "Collector ID tidak boleh kosong") + } + + if len(r.AvailableTrashItems) == 0 { + errors["available_trash_items"] = append(errors["available_trash_items"], "Minimal harus ada 1 item sampah") + } else { + trashCategoryMap := make(map[string]bool) + for i, item := range r.AvailableTrashItems { + fieldPrefix := fmt.Sprintf("available_trash_items[%d]", i) + + if strings.TrimSpace(item.TrashCategoryID) == "" { + errors[fieldPrefix+".trash_category_id"] = append(errors[fieldPrefix+".trash_category_id"], "Trash category ID tidak boleh kosong") + } else { + + if trashCategoryMap[item.TrashCategoryID] { + errors[fieldPrefix+".trash_category_id"] = append(errors[fieldPrefix+".trash_category_id"], "Trash category ID sudah ada dalam daftar") + } else { + trashCategoryMap[item.TrashCategoryID] = true + } + } + + if item.Price <= 0 { + errors[fieldPrefix+".price"] = append(errors[fieldPrefix+".price"], "Harga harus lebih dari 0") + } + } + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} diff --git a/internal/collector/collector_handler.go b/internal/collector/collector_handler.go index c87b2bd..d9a23b1 100644 --- a/internal/collector/collector_handler.go +++ b/internal/collector/collector_handler.go @@ -1 +1,360 @@ -package collector \ No newline at end of file +package collector + +import ( + "rijig/middleware" + "rijig/utils" + "strconv" + "strings" + + "github.com/gofiber/fiber/v2" +) + +type CollectorHandler struct { + collectorService CollectorService +} + +func NewCollectorHandler(collectorService CollectorService) *CollectorHandler { + return &CollectorHandler{ + collectorService: collectorService, + } +} + +func (h *CollectorHandler) CreateCollector(c *fiber.Ctx) error { + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + var req CreateCollectorRequest + + if err := c.BodyParser(&req); err != nil { + return utils.BadRequest(c, "Invalid request format") + } + + errors, isValid := req.ValidateCreateCollectorRequest() + if !isValid { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", errors) + } + + req.SetDefaults() + + collector, err := h.collectorService.CreateCollector(c.Context(), &req, claims.UserID) + if err != nil { + if strings.Contains(err.Error(), "already exists") { + return utils.BadRequest(c, err.Error()) + } + return utils.InternalServerError(c, "Failed to create collector") + } + + return utils.CreateSuccessWithData(c, "Collector created successfully", collector) +} + +func (h *CollectorHandler) GetCollectorByID(c *fiber.Ctx) error { + id := c.Params("id") + if strings.TrimSpace(id) == "" { + return utils.BadRequest(c, "Collector ID is required") + } + + collector, err := h.collectorService.GetCollectorByID(c.Context(), id) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found") + } + return utils.InternalServerError(c, "Failed to get collector") + } + + return utils.SuccessWithData(c, "Collector retrieved successfully", collector) +} + +func (h *CollectorHandler) GetCollectorByUserID(c *fiber.Ctx) error { + // userID := c.Params("userID") + // if strings.TrimSpace(userID) == "" { + // return utils.BadRequest(c, "User ID is required") + // } + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + + collector, err := h.collectorService.GetCollectorByUserID(c.Context(), claims.UserID) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found for this user") + } + return utils.InternalServerError(c, "Failed to get collector") + } + + return utils.SuccessWithData(c, "Collector retrieved successfully", collector) +} + +func (h *CollectorHandler) UpdateCollector(c *fiber.Ctx) error { + /* id := c.Params("id") + if strings.TrimSpace(id) == "" { + return utils.BadRequest(c, "Collector ID is required") + } */ + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + + var req UpdateCollectorRequest + + if err := c.BodyParser(&req); err != nil { + return utils.BadRequest(c, "Invalid request format") + } + + errors, isValid := req.ValidateUpdateCollectorRequest() + if !isValid { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", errors) + } + + req.NormalizeJobStatus() + + collector, err := h.collectorService.UpdateCollector(c.Context(), claims.UserID, &req) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found") + } + return utils.InternalServerError(c, "Failed to update collector") + } + + return utils.SuccessWithData(c, "Collector updated successfully", collector) +} + +func (h *CollectorHandler) DeleteCollector(c *fiber.Ctx) error { + claims, err := middleware.GetUserFromContext(c) + if err != nil { + return err + } + + err = h.collectorService.DeleteCollector(c.Context(), claims.UserID) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found") + } + return utils.InternalServerError(c, "Failed to delete collector") + } + + return utils.Success(c, "Collector deleted successfully") +} + +func (h *CollectorHandler) ListCollectors(c *fiber.Ctx) error { + + limit, offset, page := h.parsePaginationParams(c) + + collectors, total, err := h.collectorService.ListCollectors(c.Context(), limit, offset) + if err != nil { + return utils.InternalServerError(c, "Failed to get collectors") + } + + responseData := map[string]interface{}{ + "collectors": collectors, + "total": total, + } + + return utils.SuccessWithPagination(c, "Collectors retrieved successfully", responseData, page, limit) +} + +func (h *CollectorHandler) GetActiveCollectors(c *fiber.Ctx) error { + + limit, offset, page := h.parsePaginationParams(c) + + collectors, total, err := h.collectorService.GetActiveCollectors(c.Context(), limit, offset) + if err != nil { + return utils.InternalServerError(c, "Failed to get active collectors") + } + + responseData := map[string]interface{}{ + "collectors": collectors, + "total": total, + } + + return utils.SuccessWithPagination(c, "Active collectors retrieved successfully", responseData, page, limit) +} + +func (h *CollectorHandler) GetCollectorsByAddress(c *fiber.Ctx) error { + addressID := c.Params("addressID") + if strings.TrimSpace(addressID) == "" { + return utils.BadRequest(c, "Address ID is required") + } + + limit, offset, page := h.parsePaginationParams(c) + + collectors, total, err := h.collectorService.GetCollectorsByAddress(c.Context(), addressID, limit, offset) + if err != nil { + return utils.InternalServerError(c, "Failed to get collectors by address") + } + + responseData := map[string]interface{}{ + "collectors": collectors, + "total": total, + "address_id": addressID, + } + + return utils.SuccessWithPagination(c, "Collectors by address retrieved successfully", responseData, page, limit) +} + +func (h *CollectorHandler) GetCollectorsByTrashCategory(c *fiber.Ctx) error { + trashCategoryID := c.Params("trashCategoryID") + if strings.TrimSpace(trashCategoryID) == "" { + return utils.BadRequest(c, "Trash category ID is required") + } + + limit, offset, page := h.parsePaginationParams(c) + + collectors, total, err := h.collectorService.GetCollectorsByTrashCategory(c.Context(), trashCategoryID, limit, offset) + if err != nil { + return utils.InternalServerError(c, "Failed to get collectors by trash category") + } + + responseData := map[string]interface{}{ + "collectors": collectors, + "total": total, + "trash_category_id": trashCategoryID, + } + + return utils.SuccessWithPagination(c, "Collectors by trash category retrieved successfully", responseData, page, limit) +} + +func (h *CollectorHandler) UpdateJobStatus(c *fiber.Ctx) error { + id := c.Params("id") + if strings.TrimSpace(id) == "" { + return utils.BadRequest(c, "Collector ID is required") + } + + var req struct { + JobStatus string `json:"job_status" binding:"required"` + } + + if err := c.BodyParser(&req); err != nil { + return utils.BadRequest(c, "Invalid request format") + } + + if strings.TrimSpace(req.JobStatus) == "" { + return utils.BadRequest(c, "Job status is required") + } + + jobStatus := strings.ToLower(strings.TrimSpace(req.JobStatus)) + validStatuses := []string{"active", "inactive", "busy"} + if !h.isValidJobStatus(jobStatus, validStatuses) { + return utils.BadRequest(c, "Invalid job status. Valid statuses: active, inactive, busy") + } + + err := h.collectorService.UpdateJobStatus(c.Context(), id, jobStatus) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found") + } + return utils.InternalServerError(c, "Failed to update job status") + } + + return utils.Success(c, "Job status updated successfully") +} + +func (h *CollectorHandler) UpdateRating(c *fiber.Ctx) error { + id := c.Params("id") + if strings.TrimSpace(id) == "" { + return utils.BadRequest(c, "Collector ID is required") + } + + var req struct { + Rating float32 `json:"rating" binding:"required"` + } + + if err := c.BodyParser(&req); err != nil { + return utils.BadRequest(c, "Invalid request format") + } + + if req.Rating < 1.0 || req.Rating > 5.0 { + return utils.BadRequest(c, "Rating must be between 1.0 and 5.0") + } + + err := h.collectorService.UpdateRating(c.Context(), id, req.Rating) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found") + } + return utils.InternalServerError(c, "Failed to update rating") + } + + return utils.Success(c, "Rating updated successfully") +} + +func (h *CollectorHandler) UpdateAvailableTrash(c *fiber.Ctx) error { + id := c.Params("id") + if strings.TrimSpace(id) == "" { + return utils.BadRequest(c, "Collector ID is required") + } + + var req BulkUpdateAvailableTrashRequest + req.CollectorID = id + + if err := c.BodyParser(&req); err != nil { + return utils.BadRequest(c, "Invalid request format") + } + + errors, isValid := req.ValidateBulkUpdateAvailableTrashRequest() + if !isValid { + return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", errors) + } + + err := h.collectorService.UpdateAvailableTrash(c.Context(), id, req.AvailableTrashItems) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return utils.NotFound(c, "Collector not found") + } + return utils.InternalServerError(c, "Failed to update available trash") + } + + return utils.Success(c, "Available trash updated successfully") +} + +func (h *CollectorHandler) parsePaginationParams(c *fiber.Ctx) (limit, offset, page int) { + + limitStr := c.Query("limit", "10") + limit, err := strconv.Atoi(limitStr) + if err != nil || limit <= 0 { + limit = 10 + } + if limit > 100 { + limit = 100 + } + + pageStr := c.Query("page", "1") + page, err = strconv.Atoi(pageStr) + if err != nil || page <= 0 { + page = 1 + } + + offset = (page - 1) * limit + + return limit, offset, page +} + +func (h *CollectorHandler) isValidJobStatus(status string, validStatuses []string) bool { + for _, validStatus := range validStatuses { + if status == validStatus { + return true + } + } + return false +} + +func (h *CollectorHandler) RegisterRoutes(app *fiber.App) { + + collectors := app.Group("/api/v1/collectors") + + collectors.Post("/", h.CreateCollector) + collectors.Get("/:id", h.GetCollectorByID) + collectors.Put("/:id", h.UpdateCollector) + collectors.Delete("/:id", h.DeleteCollector) + + collectors.Get("/", h.ListCollectors) + collectors.Get("/active", h.GetActiveCollectors) + collectors.Get("/user/:userID", h.GetCollectorByUserID) + collectors.Get("/address/:addressID", h.GetCollectorsByAddress) + collectors.Get("/trash-category/:trashCategoryID", h.GetCollectorsByTrashCategory) + + collectors.Patch("/:id/job-status", h.UpdateJobStatus) + collectors.Patch("/:id/rating", h.UpdateRating) + collectors.Put("/:id/available-trash", h.UpdateAvailableTrash) +} diff --git a/internal/collector/collector_repository.go b/internal/collector/collector_repository.go index c87b2bd..5bea6c9 100644 --- a/internal/collector/collector_repository.go +++ b/internal/collector/collector_repository.go @@ -1 +1,337 @@ -package collector \ No newline at end of file +package collector + +import ( + "context" + "fmt" + "rijig/model" + + "gorm.io/gorm" +) + +type CollectorRepository interface { + Create(ctx context.Context, collector *model.Collector) error + GetByID(ctx context.Context, id string) (*model.Collector, error) + GetByUserID(ctx context.Context, userID string) (*model.Collector, error) + Update(ctx context.Context, collector *model.Collector) error + Delete(ctx context.Context, UserID string) error + List(ctx context.Context, limit, offset int) ([]*model.Collector, int64, error) + + GetActiveCollectors(ctx context.Context, limit, offset int) ([]*model.Collector, int64, error) + GetCollectorsByAddress(ctx context.Context, addressID string, limit, offset int) ([]*model.Collector, int64, error) + GetCollectorsByTrashCategory(ctx context.Context, trashCategoryID string, limit, offset int) ([]*model.Collector, int64, error) + UpdateJobStatus(ctx context.Context, id string, jobStatus string) error + UpdateRating(ctx context.Context, id string, rating float32) error + + CreateAvailableTrash(ctx context.Context, availableTrash *model.AvaibleTrashByCollector) error + GetAvailableTrashByCollectorID(ctx context.Context, collectorID string) ([]*model.AvaibleTrashByCollector, error) + UpdateAvailableTrash(ctx context.Context, availableTrash *model.AvaibleTrashByCollector) error + DeleteAvailableTrash(ctx context.Context, id string) error + BulkCreateAvailableTrash(ctx context.Context, availableTrashList []*model.AvaibleTrashByCollector) error + BulkUpdateAvailableTrash(ctx context.Context, collectorID string, availableTrashList []*model.AvaibleTrashByCollector) error + DeleteAvailableTrashByCollectorID(ctx context.Context, collectorID string) error + + WithTx(tx *gorm.DB) CollectorRepository +} + +type collectorRepository struct { + db *gorm.DB +} + +func NewCollectorRepository(db *gorm.DB) CollectorRepository { + return &collectorRepository{ + db: db, + } +} + +func (r *collectorRepository) WithTx(tx *gorm.DB) CollectorRepository { + return &collectorRepository{ + db: tx, + } +} + +func (r *collectorRepository) Create(ctx context.Context, collector *model.Collector) error { + if err := r.db.WithContext(ctx).Create(collector).Error; err != nil { + return fmt.Errorf("failed to create collector: %w", err) + } + return nil +} + +func (r *collectorRepository) GetByID(ctx context.Context, id string) (*model.Collector, error) { + var collector model.Collector + + err := r.db.WithContext(ctx). + Preload("Address"). + Preload("AvaibleTrashByCollector"). + Preload("AvaibleTrashByCollector.TrashCategory"). + Where("id = ?", id). + First(&collector).Error + + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, fmt.Errorf("collector with id %s not found", id) + } + return nil, fmt.Errorf("failed to get collector by id: %w", err) + } + + return &collector, nil +} + +func (r *collectorRepository) GetByUserID(ctx context.Context, userID string) (*model.Collector, error) { + var collector model.Collector + + err := r.db.WithContext(ctx). + Preload("Address"). + Preload("AvaibleTrashByCollector"). + Preload("AvaibleTrashByCollector.TrashCategory"). + Where("user_id = ?", userID). + First(&collector).Error + + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, fmt.Errorf("collector with user_id %s not found", userID) + } + return nil, fmt.Errorf("failed to get collector by user_id: %w", err) + } + + return &collector, nil +} + +func (r *collectorRepository) Update(ctx context.Context, collector *model.Collector) error { + if err := r.db.WithContext(ctx).Save(collector).Error; err != nil { + return fmt.Errorf("failed to update collector: %w", err) + } + return nil +} + +func (r *collectorRepository) Delete(ctx context.Context, UserID string) error { + result := r.db.WithContext(ctx).Delete(&model.Collector{}, "user_id = ?", UserID) + if result.Error != nil { + return fmt.Errorf("failed to delete collector: %w", result.Error) + } + + if result.RowsAffected == 0 { + return fmt.Errorf("collector with user_id %s not found", UserID) + } + + return nil +} + +func (r *collectorRepository) List(ctx context.Context, limit, offset int) ([]*model.Collector, int64, error) { + var collectors []*model.Collector + var total int64 + + if err := r.db.WithContext(ctx).Model(&model.Collector{}).Count(&total).Error; err != nil { + return nil, 0, fmt.Errorf("failed to count collectors: %w", err) + } + + err := r.db.WithContext(ctx). + Preload("Address"). + Preload("AvaibleTrashByCollector"). + Preload("AvaibleTrashByCollector.TrashCategory"). + Limit(limit). + Offset(offset). + Find(&collectors).Error + + if err != nil { + return nil, 0, fmt.Errorf("failed to list collectors: %w", err) + } + + return collectors, total, nil +} + +func (r *collectorRepository) GetActiveCollectors(ctx context.Context, limit, offset int) ([]*model.Collector, int64, error) { + var collectors []*model.Collector + var total int64 + + query := r.db.WithContext(ctx).Where("job_status = ?", "active") + + if err := query.Model(&model.Collector{}).Count(&total).Error; err != nil { + return nil, 0, fmt.Errorf("failed to count active collectors: %w", err) + } + + err := query. + Preload("Address"). + Preload("AvaibleTrashByCollector"). + Preload("AvaibleTrashByCollector.TrashCategory"). + Limit(limit). + Offset(offset). + Find(&collectors).Error + + if err != nil { + return nil, 0, fmt.Errorf("failed to get active collectors: %w", err) + } + + return collectors, total, nil +} + +func (r *collectorRepository) GetCollectorsByAddress(ctx context.Context, addressID string, limit, offset int) ([]*model.Collector, int64, error) { + var collectors []*model.Collector + var total int64 + + query := r.db.WithContext(ctx).Where("address_id = ?", addressID) + + if err := query.Model(&model.Collector{}).Count(&total).Error; err != nil { + return nil, 0, fmt.Errorf("failed to count collectors by address: %w", err) + } + + err := query. + Preload("Address"). + Preload("AvaibleTrashByCollector"). + Preload("AvaibleTrashByCollector.TrashCategory"). + Limit(limit). + Offset(offset). + Find(&collectors).Error + + if err != nil { + return nil, 0, fmt.Errorf("failed to get collectors by address: %w", err) + } + + return collectors, total, nil +} + +func (r *collectorRepository) GetCollectorsByTrashCategory(ctx context.Context, trashCategoryID string, limit, offset int) ([]*model.Collector, int64, error) { + var collectors []*model.Collector + var total int64 + + subQuery := r.db.WithContext(ctx). + Table("avaible_trash_by_collectors"). + Select("collector_id"). + Where("trash_category_id = ?", trashCategoryID) + + query := r.db.WithContext(ctx). + Where("id IN (?)", subQuery) + + if err := query.Model(&model.Collector{}).Count(&total).Error; err != nil { + return nil, 0, fmt.Errorf("failed to count collectors by trash category: %w", err) + } + + err := query. + Preload("Address"). + Preload("AvaibleTrashByCollector"). + Preload("AvaibleTrashByCollector.TrashCategory"). + Limit(limit). + Offset(offset). + Find(&collectors).Error + + if err != nil { + return nil, 0, fmt.Errorf("failed to get collectors by trash category: %w", err) + } + + return collectors, total, nil +} + +func (r *collectorRepository) UpdateJobStatus(ctx context.Context, id string, jobStatus string) error { + result := r.db.WithContext(ctx). + Model(&model.Collector{}). + Where("id = ?", id). + Update("job_status", jobStatus) + + if result.Error != nil { + return fmt.Errorf("failed to update job status: %w", result.Error) + } + + if result.RowsAffected == 0 { + return fmt.Errorf("collector with id %s not found", id) + } + + return nil +} + +func (r *collectorRepository) UpdateRating(ctx context.Context, id string, rating float32) error { + result := r.db.WithContext(ctx). + Model(&model.Collector{}). + Where("id = ?", id). + Update("rating", rating) + + if result.Error != nil { + return fmt.Errorf("failed to update rating: %w", result.Error) + } + + if result.RowsAffected == 0 { + return fmt.Errorf("collector with id %s not found", id) + } + + return nil +} + +func (r *collectorRepository) CreateAvailableTrash(ctx context.Context, availableTrash *model.AvaibleTrashByCollector) error { + if err := r.db.WithContext(ctx).Create(availableTrash).Error; err != nil { + return fmt.Errorf("failed to create available trash: %w", err) + } + return nil +} + +func (r *collectorRepository) GetAvailableTrashByCollectorID(ctx context.Context, collectorID string) ([]*model.AvaibleTrashByCollector, error) { + var availableTrash []*model.AvaibleTrashByCollector + + err := r.db.WithContext(ctx). + Preload("TrashCategory"). + Where("collector_id = ?", collectorID). + Find(&availableTrash).Error + + if err != nil { + return nil, fmt.Errorf("failed to get available trash by collector id: %w", err) + } + + return availableTrash, nil +} + +func (r *collectorRepository) UpdateAvailableTrash(ctx context.Context, availableTrash *model.AvaibleTrashByCollector) error { + if err := r.db.WithContext(ctx).Save(availableTrash).Error; err != nil { + return fmt.Errorf("failed to update available trash: %w", err) + } + return nil +} + +func (r *collectorRepository) DeleteAvailableTrash(ctx context.Context, id string) error { + result := r.db.WithContext(ctx).Delete(&model.AvaibleTrashByCollector{}, "id = ?", id) + if result.Error != nil { + return fmt.Errorf("failed to delete available trash: %w", result.Error) + } + + if result.RowsAffected == 0 { + return fmt.Errorf("available trash with id %s not found", id) + } + + return nil +} + +func (r *collectorRepository) BulkCreateAvailableTrash(ctx context.Context, availableTrashList []*model.AvaibleTrashByCollector) error { + if len(availableTrashList) == 0 { + return nil + } + + if err := r.db.WithContext(ctx).CreateInBatches(availableTrashList, 100).Error; err != nil { + return fmt.Errorf("failed to bulk create available trash: %w", err) + } + + return nil +} + +func (r *collectorRepository) BulkUpdateAvailableTrash(ctx context.Context, collectorID string, availableTrashList []*model.AvaibleTrashByCollector) error { + return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + + if err := tx.Where("collector_id = ?", collectorID).Delete(&model.AvaibleTrashByCollector{}).Error; err != nil { + return fmt.Errorf("failed to delete existing available trash: %w", err) + } + + if len(availableTrashList) > 0 { + for _, item := range availableTrashList { + item.CollectorID = collectorID + } + + if err := tx.CreateInBatches(availableTrashList, 100).Error; err != nil { + return fmt.Errorf("failed to create new available trash: %w", err) + } + } + + return nil + }) +} + +func (r *collectorRepository) DeleteAvailableTrashByCollectorID(ctx context.Context, collectorID string) error { + if err := r.db.WithContext(ctx).Where("collector_id = ?", collectorID).Delete(&model.AvaibleTrashByCollector{}).Error; err != nil { + return fmt.Errorf("failed to delete available trash by collector id: %w", err) + } + return nil +} diff --git a/internal/collector/collector_service.go b/internal/collector/collector_service.go index c87b2bd..b1776ea 100644 --- a/internal/collector/collector_service.go +++ b/internal/collector/collector_service.go @@ -1 +1,349 @@ -package collector \ No newline at end of file +package collector + +import ( + "context" + "fmt" + "rijig/internal/address" + "rijig/internal/trash" + "rijig/model" + "strings" + "time" + + "gorm.io/gorm" +) + +type CollectorService interface { + CreateCollector(ctx context.Context, req *CreateCollectorRequest, UserID string) (*CollectorResponse, error) + GetCollectorByID(ctx context.Context, id string) (*CollectorResponse, error) + GetCollectorByUserID(ctx context.Context, userID string) (*CollectorResponse, error) + UpdateCollector(ctx context.Context, UserID string, req *UpdateCollectorRequest) (*CollectorResponse, error) + DeleteCollector(ctx context.Context, UserID string) error + ListCollectors(ctx context.Context, limit, offset int) ([]*CollectorResponse, int64, error) + + GetActiveCollectors(ctx context.Context, limit, offset int) ([]*CollectorResponse, int64, error) + GetCollectorsByAddress(ctx context.Context, addressID string, limit, offset int) ([]*CollectorResponse, int64, error) + GetCollectorsByTrashCategory(ctx context.Context, trashCategoryID string, limit, offset int) ([]*CollectorResponse, int64, error) + + UpdateJobStatus(ctx context.Context, id string, jobStatus string) error + UpdateRating(ctx context.Context, id string, rating float32) error + UpdateAvailableTrash(ctx context.Context, collectorID string, availableTrashItems []CreateAvailableTrashRequest) error +} + +type collectorService struct { + collectorRepo CollectorRepository + db *gorm.DB +} + +func NewCollectorService(collectorRepo CollectorRepository, db *gorm.DB) CollectorService { + return &collectorService{ + collectorRepo: collectorRepo, + db: db, + } +} + +func (s *collectorService) CreateCollector(ctx context.Context, req *CreateCollectorRequest, UserID string) (*CollectorResponse, error) { + + existingCollector, err := s.collectorRepo.GetByUserID(ctx, UserID) + if err != nil && !strings.Contains(err.Error(), "not found") { + return nil, fmt.Errorf("failed to check existing collector: %w", err) + } + if existingCollector != nil { + return nil, fmt.Errorf("collector already exists for user_id: %s", req.UserID) + } + + collector := &model.Collector{ + UserID: UserID, + JobStatus: "inactive", + AddressID: req.AddressID, + Rating: 5.0, + } + + if req.JobStatus != "" { + collector.JobStatus = req.JobStatus + } + + err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + collectorRepoTx := s.collectorRepo.WithTx(tx) + + if err := collectorRepoTx.Create(ctx, collector); err != nil { + return fmt.Errorf("failed to create collector: %w", err) + } + + if len(req.AvailableTrashItems) > 0 { + availableTrashList := s.buildAvailableTrashList(collector.ID, req.AvailableTrashItems) + if err := collectorRepoTx.BulkCreateAvailableTrash(ctx, availableTrashList); err != nil { + return fmt.Errorf("failed to create available trash items: %w", err) + } + } + + return nil + }) + + if err != nil { + return nil, err + } + + createdCollector, err := s.collectorRepo.GetByID(ctx, collector.ID) + if err != nil { + return nil, fmt.Errorf("failed to fetch created collector: %w", err) + } + + return s.toCollectorResponse(createdCollector), nil +} + +func (s *collectorService) GetCollectorByID(ctx context.Context, id string) (*CollectorResponse, error) { + collector, err := s.collectorRepo.GetByID(ctx, id) + if err != nil { + return nil, err + } + + return s.toCollectorResponse(collector), nil +} + +func (s *collectorService) GetCollectorByUserID(ctx context.Context, userID string) (*CollectorResponse, error) { + collector, err := s.collectorRepo.GetByUserID(ctx, userID) + if err != nil { + return nil, err + } + + return s.toCollectorResponse(collector), nil +} + +func (s *collectorService) UpdateCollector(ctx context.Context, UserID string, req *UpdateCollectorRequest) (*CollectorResponse, error) { + + collector, err := s.collectorRepo.GetByUserID(ctx, UserID) + if err != nil { + return nil, fmt.Errorf("failed to get collector: %w", err) + } + + needsUpdate := s.checkCollectorNeedsUpdate(collector, req) + + err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + collectorRepoTx := s.collectorRepo.WithTx(tx) + + if needsUpdate { + s.applyCollectorUpdates(collector, req) + collector.UpdatedAt = time.Now() + + if err := collectorRepoTx.Update(ctx, collector); err != nil { + return fmt.Errorf("failed to update collector: %w", err) + } + } + + if len(req.AvailableTrashItems) > 0 { + availableTrashList := s.buildAvailableTrashList(collector.ID, req.AvailableTrashItems) + if err := collectorRepoTx.BulkUpdateAvailableTrash(ctx, collector.ID, availableTrashList); err != nil { + return fmt.Errorf("failed to update available trash items: %w", err) + } + } + + return nil + }) + + if err != nil { + return nil, err + } + + updatedCollector, err := s.collectorRepo.GetByUserID(ctx, UserID) + if err != nil { + return nil, fmt.Errorf("failed to fetch updated collector: %w", err) + } + + return s.toCollectorResponse(updatedCollector), nil +} + +func (s *collectorService) DeleteCollector(ctx context.Context, UserID string) error { + + _, err := s.collectorRepo.GetByUserID(ctx, UserID) + if err != nil { + return fmt.Errorf("collector not found: %w", err) + } + + if err := s.collectorRepo.Delete(ctx, UserID); err != nil { + return fmt.Errorf("failed to delete collector: %w", err) + } + + return nil +} + +func (s *collectorService) ListCollectors(ctx context.Context, limit, offset int) ([]*CollectorResponse, int64, error) { + + limit, offset = s.normalizePagination(limit, offset) + + collectors, total, err := s.collectorRepo.List(ctx, limit, offset) + if err != nil { + return nil, 0, fmt.Errorf("failed to list collectors: %w", err) + } + + return s.buildCollectorResponseList(collectors), total, nil +} + +func (s *collectorService) GetActiveCollectors(ctx context.Context, limit, offset int) ([]*CollectorResponse, int64, error) { + + limit, offset = s.normalizePagination(limit, offset) + + collectors, total, err := s.collectorRepo.GetActiveCollectors(ctx, limit, offset) + if err != nil { + return nil, 0, fmt.Errorf("failed to get active collectors: %w", err) + } + + return s.buildCollectorResponseList(collectors), total, nil +} + +func (s *collectorService) GetCollectorsByAddress(ctx context.Context, addressID string, limit, offset int) ([]*CollectorResponse, int64, error) { + + limit, offset = s.normalizePagination(limit, offset) + + collectors, total, err := s.collectorRepo.GetCollectorsByAddress(ctx, addressID, limit, offset) + if err != nil { + return nil, 0, fmt.Errorf("failed to get collectors by address: %w", err) + } + + return s.buildCollectorResponseList(collectors), total, nil +} + +func (s *collectorService) GetCollectorsByTrashCategory(ctx context.Context, trashCategoryID string, limit, offset int) ([]*CollectorResponse, int64, error) { + + limit, offset = s.normalizePagination(limit, offset) + + collectors, total, err := s.collectorRepo.GetCollectorsByTrashCategory(ctx, trashCategoryID, limit, offset) + if err != nil { + return nil, 0, fmt.Errorf("failed to get collectors by trash category: %w", err) + } + + return s.buildCollectorResponseList(collectors), total, nil +} + +func (s *collectorService) UpdateJobStatus(ctx context.Context, id string, jobStatus string) error { + if err := s.collectorRepo.UpdateJobStatus(ctx, id, jobStatus); err != nil { + return fmt.Errorf("failed to update job status: %w", err) + } + + return nil +} + +func (s *collectorService) UpdateRating(ctx context.Context, id string, rating float32) error { + if err := s.collectorRepo.UpdateRating(ctx, id, rating); err != nil { + return fmt.Errorf("failed to update rating: %w", err) + } + + return nil +} + +func (s *collectorService) UpdateAvailableTrash(ctx context.Context, collectorID string, availableTrashItems []CreateAvailableTrashRequest) error { + availableTrashList := s.buildAvailableTrashList(collectorID, availableTrashItems) + + if err := s.collectorRepo.BulkUpdateAvailableTrash(ctx, collectorID, availableTrashList); err != nil { + return fmt.Errorf("failed to update available trash: %w", err) + } + + return nil +} + +func (s *collectorService) buildAvailableTrashList(collectorID string, items []CreateAvailableTrashRequest) []*model.AvaibleTrashByCollector { + availableTrashList := make([]*model.AvaibleTrashByCollector, 0, len(items)) + for _, item := range items { + availableTrash := &model.AvaibleTrashByCollector{ + CollectorID: collectorID, + TrashCategoryID: item.TrashCategoryID, + Price: item.Price, + } + availableTrashList = append(availableTrashList, availableTrash) + } + return availableTrashList +} + +func (s *collectorService) checkCollectorNeedsUpdate(collector *model.Collector, req *UpdateCollectorRequest) bool { + if req.JobStatus != "" && req.JobStatus != collector.JobStatus { + return true + } + if req.AddressID != "" && req.AddressID != collector.AddressID { + return true + } + return false +} + +func (s *collectorService) applyCollectorUpdates(collector *model.Collector, req *UpdateCollectorRequest) { + if req.JobStatus != "" { + collector.JobStatus = req.JobStatus + } + if req.AddressID != "" { + collector.AddressID = req.AddressID + } +} + +func (s *collectorService) normalizePagination(limit, offset int) (int, int) { + if limit <= 0 { + limit = 10 + } + if offset < 0 { + offset = 0 + } + if limit > 100 { + limit = 100 + } + return limit, offset +} + +func (s *collectorService) buildCollectorResponseList(collectors []*model.Collector) []*CollectorResponse { + responses := make([]*CollectorResponse, 0, len(collectors)) + for _, collector := range collectors { + responses = append(responses, s.toCollectorResponse(collector)) + } + return responses +} + +func (s *collectorService) toCollectorResponse(collector *model.Collector) *CollectorResponse { + response := &CollectorResponse{ + ID: collector.ID, + UserID: collector.UserID, + JobStatus: collector.JobStatus, + Rating: collector.Rating, + AddressID: collector.AddressID, + AvailableTrash: make([]AvailableTrashResponse, 0), + CreatedAt: collector.CreatedAt.Format(time.RFC3339), + UpdatedAt: collector.UpdatedAt.Format(time.RFC3339), + } + + if collector.Address.ID != "" { + response.Address = &address.AddressResponseDTO{ + ID: collector.Address.ID, + UserID: collector.Address.UserID, + Province: collector.Address.Province, + Regency: collector.Address.Regency, + District: collector.Address.District, + Village: collector.Address.Village, + PostalCode: collector.Address.PostalCode, + Detail: collector.Address.Detail, + Latitude: collector.Address.Latitude, + Longitude: collector.Address.Longitude, + CreatedAt: collector.Address.CreatedAt.Format(time.RFC3339), + UpdatedAt: collector.Address.UpdatedAt.Format(time.RFC3339), + } + } + + for _, availableTrash := range collector.AvaibleTrashByCollector { + trashResponse := AvailableTrashResponse{ + ID: availableTrash.ID, + CollectorID: availableTrash.CollectorID, + TrashCategoryID: availableTrash.TrashCategoryID, + Price: availableTrash.Price, + } + + if availableTrash.TrashCategory.ID != "" { + trashResponse.TrashCategory = &trash.ResponseTrashCategoryDTO{ + ID: availableTrash.TrashCategory.ID, + TrashName: availableTrash.TrashCategory.Name, + TrashIcon: availableTrash.TrashCategory.IconTrash, + EstimatedPrice: availableTrash.TrashCategory.EstimatedPrice, + Variety: availableTrash.TrashCategory.Variety, + CreatedAt: availableTrash.TrashCategory.CreatedAt.Format(time.RFC3339), + UpdatedAt: availableTrash.TrashCategory.UpdatedAt.Format(time.RFC3339), + } + } + + response.AvailableTrash = append(response.AvailableTrash, trashResponse) + } + + return response +} diff --git a/internal/handler/about_handler.go b/internal/handler/about_handler.go deleted file mode 100644 index 92fca2c..0000000 --- a/internal/handler/about_handler.go +++ /dev/null @@ -1,176 +0,0 @@ -package handler -/* -import ( - "fmt" - "log" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type AboutHandler struct { - AboutService services.AboutService -} - -func NewAboutHandler(aboutService services.AboutService) *AboutHandler { - return &AboutHandler{ - AboutService: aboutService, - } -} - -func (h *AboutHandler) CreateAbout(c *fiber.Ctx) error { - var request dto.RequestAboutDTO - if err := c.BodyParser(&request); err != nil { - log.Printf("Error parsing request body: %v", err) - return utils.ResponseErrorData(c, "Invalid input data") - } - - aboutCoverImage, err := c.FormFile("cover_image") - if err != nil { - log.Printf("Error retrieving cover image about from request: %v", err) - return utils.ErrorResponse(c, "cover_iamge is required") - } - - response, err := h.AboutService.CreateAbout(request, aboutCoverImage) - if err != nil { - log.Printf("Error creating About: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to create About: %v", err)) - } - - return utils.SuccessResponse(c, response, "Successfully created About") -} - -func (h *AboutHandler) UpdateAbout(c *fiber.Ctx) error { - id := c.Params("id") - - var request dto.RequestAboutDTO - if err := c.BodyParser(&request); err != nil { - log.Printf("Error parsing request body: %v", err) - return utils.ErrorResponse(c, "Invalid input data") - } - - aboutCoverImage, err := c.FormFile("cover_image") - if err != nil { - log.Printf("Error retrieving cover image about from request: %v", err) - return utils.ErrorResponse(c, "cover_iamge is required") - } - - response, err := h.AboutService.UpdateAbout(id, request, aboutCoverImage) - if err != nil { - log.Printf("Error updating About: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to update About: %v", err)) - } - - return utils.SuccessResponse(c, response, "Successfully updated About") -} - -func (h *AboutHandler) GetAllAbout(c *fiber.Ctx) error { - - response, err := h.AboutService.GetAllAbout() - if err != nil { - log.Printf("Error fetching all About: %v", err) - return utils.ErrorResponse(c, "Failed to fetch About list") - } - - return utils.PaginatedResponse(c, response, 1, len(response), len(response), "Successfully fetched About list") -} - -func (h *AboutHandler) GetAboutByID(c *fiber.Ctx) error { - id := c.Params("id") - - response, err := h.AboutService.GetAboutByID(id) - if err != nil { - log.Printf("Error fetching About by ID: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to fetch About by ID: %v", err)) - } - - return utils.SuccessResponse(c, response, "Successfully fetched About") -} - -func (h *AboutHandler) GetAboutDetailById(c *fiber.Ctx) error { - id := c.Params("id") - - response, err := h.AboutService.GetAboutDetailById(id) - if err != nil { - log.Printf("Error fetching About detail by ID: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to fetch About by ID: %v", err)) - } - - return utils.SuccessResponse(c, response, "Successfully fetched About") -} - -func (h *AboutHandler) DeleteAbout(c *fiber.Ctx) error { - id := c.Params("id") - - if err := h.AboutService.DeleteAbout(id); err != nil { - log.Printf("Error deleting About: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to delete About: %v", err)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Successfully deleted About") -} - -func (h *AboutHandler) CreateAboutDetail(c *fiber.Ctx) error { - var request dto.RequestAboutDetailDTO - if err := c.BodyParser(&request); err != nil { - log.Printf("Error parsing request body: %v", err) - return utils.ErrorResponse(c, "Invalid input data") - } - - errors, valid := request.ValidateAboutDetail() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - aboutDetailImage, err := c.FormFile("image_detail") - if err != nil { - log.Printf("Error retrieving image detail from request: %v", err) - return utils.ErrorResponse(c, "image_detail is required") - } - - response, err := h.AboutService.CreateAboutDetail(request, aboutDetailImage) - if err != nil { - log.Printf("Error creating AboutDetail: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to create AboutDetail: %v", err)) - } - - return utils.SuccessResponse(c, response, "Successfully created AboutDetail") -} - -func (h *AboutHandler) UpdateAboutDetail(c *fiber.Ctx) error { - id := c.Params("id") - - var request dto.RequestAboutDetailDTO - if err := c.BodyParser(&request); err != nil { - log.Printf("Error parsing request body: %v", err) - return utils.ErrorResponse(c, "Invalid input data") - } - - aboutDetailImage, err := c.FormFile("image_detail") - if err != nil { - log.Printf("Error retrieving image detail from request: %v", err) - return utils.ErrorResponse(c, "image_detail is required") - } - - response, err := h.AboutService.UpdateAboutDetail(id, request, aboutDetailImage) - if err != nil { - log.Printf("Error updating AboutDetail: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to update AboutDetail: %v", err)) - } - - return utils.SuccessResponse(c, response, "Successfully updated AboutDetail") -} - -func (h *AboutHandler) DeleteAboutDetail(c *fiber.Ctx) error { - id := c.Params("id") - - if err := h.AboutService.DeleteAboutDetail(id); err != nil { - log.Printf("Error deleting AboutDetail: %v", err) - return utils.ErrorResponse(c, fmt.Sprintf("Failed to delete AboutDetail: %v", err)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Successfully deleted AboutDetail") -} - */ \ No newline at end of file diff --git a/internal/handler/address_handler.go b/internal/handler/address_handler.go deleted file mode 100644 index de69c47..0000000 --- a/internal/handler/address_handler.go +++ /dev/null @@ -1,93 +0,0 @@ -package handler - -import ( - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type AddressHandler struct { - AddressService services.AddressService -} - -func NewAddressHandler(addressService services.AddressService) *AddressHandler { - return &AddressHandler{AddressService: addressService} -} - -func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error { - var requestAddressDTO dto.CreateAddressDTO - if err := c.BodyParser(&requestAddressDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := requestAddressDTO.ValidateAddress() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - addressResponse, err := h.AddressService.CreateAddress(c.Locals("userID").(string), requestAddressDTO) - if err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, err.Error()) - } - - return utils.CreateResponse(c, addressResponse, "user address created successfully") -} - -func (h *AddressHandler) GetAddressByUserID(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - addresses, err := h.AddressService.GetAddressByUserID(userID) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, addresses, "User addresses fetched successfully") -} - -func (h *AddressHandler) GetAddressByID(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - addressID := c.Params("address_id") - - address, err := h.AddressService.GetAddressByID(userID, addressID) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, address, "Address fetched successfully") -} - -func (h *AddressHandler) UpdateAddress(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - addressID := c.Params("address_id") - - var addressDTO dto.CreateAddressDTO - if err := c.BodyParser(&addressDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := addressDTO.ValidateAddress() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - updatedAddress, err := h.AddressService.UpdateAddress(userID, addressID, addressDTO) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, updatedAddress, "User address updated successfully") -} - -func (h *AddressHandler) DeleteAddress(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - addressID := c.Params("address_id") - - err := h.AddressService.DeleteAddress(userID, addressID) - if err != nil { - return utils.GenericResponse(c, fiber.StatusForbidden, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Address deleted successfully") -} diff --git a/internal/handler/article_handler.go b/internal/handler/article_handler.go deleted file mode 100644 index 844e554..0000000 --- a/internal/handler/article_handler.go +++ /dev/null @@ -1,138 +0,0 @@ -package handler - -import ( - "fmt" - "mime/multipart" - "strconv" - - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type ArticleHandler struct { - ArticleService services.ArticleService -} - -func NewArticleHandler(articleService services.ArticleService) *ArticleHandler { - return &ArticleHandler{ArticleService: articleService} -} - -func (h *ArticleHandler) CreateArticle(c *fiber.Ctx) error { - var request dto.RequestArticleDTO - - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.Validate() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - coverImage, err := c.FormFile("coverImage") - if err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Cover image is required") - } - - articleResponse, err := h.ArticleService.CreateArticle(request, coverImage) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.CreateResponse(c, articleResponse, "Article created successfully") -} - -func (h *ArticleHandler) GetAllArticles(c *fiber.Ctx) error { - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil || page < 1 { - page = 0 - } - - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil || limit < 1 { - limit = 0 - } - - articles, totalArticles, err := h.ArticleService.GetAllArticles(page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch articles") - } - - fmt.Printf("Total Articles: %d\n", totalArticles) - - if page == 0 && limit == 0 { - return utils.NonPaginatedResponse(c, articles, totalArticles, "Articles fetched successfully") - } - - return utils.PaginatedResponse(c, articles, page, limit, totalArticles, "Articles fetched successfully") -} - -func (h *ArticleHandler) GetArticleByID(c *fiber.Ctx) error { - id := c.Params("article_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Article ID is required") - } - - article, err := h.ArticleService.GetArticleByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, "Article not found") - } - - return utils.SuccessResponse(c, article, "Article fetched successfully") -} - -func (h *ArticleHandler) UpdateArticle(c *fiber.Ctx) error { - id := c.Params("article_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Article ID is required") - } - - var request dto.RequestArticleDTO - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.Validate() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - var coverImage *multipart.FileHeader - coverImage, err := c.FormFile("coverImage") - if err != nil && err.Error() != "no such file" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Cover image is required") - } - - articleResponse, err := h.ArticleService.UpdateArticle(id, request, coverImage) - if err != nil { - if err.Error() == fmt.Sprintf("article with ID %s not found", id) { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - - } - - return utils.SuccessResponse(c, articleResponse, "Article updated successfully") -} - -func (h *ArticleHandler) DeleteArticle(c *fiber.Ctx) error { - id := c.Params("article_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Article ID is required") - } - - err := h.ArticleService.DeleteArticle(id) - if err != nil { - - if err.Error() == fmt.Sprintf("article with ID %s not found", id) { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Article deleted successfully") -} diff --git a/internal/handler/auth/auth_admin_handler.go b/internal/handler/auth/auth_admin_handler.go deleted file mode 100644 index 3f3d78f..0000000 --- a/internal/handler/auth/auth_admin_handler.go +++ /dev/null @@ -1,81 +0,0 @@ -package handler -/* -import ( - "log" - dto "rijig/dto/auth" - services "rijig/internal/services/auth" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type AuthAdminHandler struct { - UserService services.AuthAdminService -} - -func NewAuthAdminHandler(userService services.AuthAdminService) *AuthAdminHandler { - return &AuthAdminHandler{UserService: userService} -} - -func (h *AuthAdminHandler) RegisterAdmin(c *fiber.Ctx) error { - var request dto.RegisterAdminRequest - - if err := c.BodyParser(&request); err != nil { - return utils.InternalServerErrorResponse(c, "Failed to parse request body") - } - - errors, valid := request.Validate() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - user, err := h.UserService.RegisterAdmin(&request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, err.Error()) - } - - return utils.SuccessResponse(c, user, "Admin registered successfully") -} - -func (h *AuthAdminHandler) LoginAdmin(c *fiber.Ctx) error { - var request dto.LoginAdminRequest - - if err := c.BodyParser(&request); err != nil { - return utils.InternalServerErrorResponse(c, "Failed to parse request body") - } - - loginResponse, err := h.UserService.LoginAdmin(&request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusUnauthorized, err.Error()) - } - - return utils.SuccessResponse(c, loginResponse, "Login successful") -} - -func (h *AuthAdminHandler) LogoutAdmin(c *fiber.Ctx) error { - // Ambil userID dari c.Locals - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - log.Println("Error: UserID is nil or empty") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User not authenticated") - } - - // Ambil deviceID dari header atau c.Locals - deviceID, ok := c.Locals("device_id").(string) - if !ok || deviceID == "" { - log.Println("Error: DeviceID is nil or empty") - return utils.ErrorResponse(c, "DeviceID is required") - } - - log.Printf("UserID: %s, DeviceID: %s", userID, deviceID) - - err := h.UserService.LogoutAdmin(userID, deviceID) - if err != nil { - log.Printf("Error during logout process for user %s: %v", userID, err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Successfully logged out") -} - - */ \ No newline at end of file diff --git a/internal/handler/auth/auth_masyarakat_handler.go b/internal/handler/auth/auth_masyarakat_handler.go deleted file mode 100644 index cf3750d..0000000 --- a/internal/handler/auth/auth_masyarakat_handler.go +++ /dev/null @@ -1,82 +0,0 @@ -package handler -/* -import ( - "log" - "rijig/dto" - services "rijig/internal/services/auth" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type AuthMasyarakatHandler struct { - authMasyarakatService services.AuthMasyarakatService -} - -func NewAuthMasyarakatHandler(authMasyarakatService services.AuthMasyarakatService) *AuthMasyarakatHandler { - return &AuthMasyarakatHandler{authMasyarakatService} -} - -func (h *AuthMasyarakatHandler) RegisterOrLoginHandler(c *fiber.Ctx) error { - var req dto.RegisterRequest - - if err := c.BodyParser(&req); err != nil { - return utils.ErrorResponse(c, "Invalid request body") - } - - if req.Phone == "" { - return utils.ErrorResponse(c, "Phone number is required") - } - - if err := h.authMasyarakatService.RegisterOrLogin(&req); err != nil { - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "OTP sent successfully") -} - -func (h *AuthMasyarakatHandler) VerifyOTPHandler(c *fiber.Ctx) error { - var req dto.VerifyOTPRequest - - if err := c.BodyParser(&req); err != nil { - return utils.ErrorResponse(c, "Invalid request body") - } - - if req.OTP == "" { - return utils.ErrorResponse(c, "OTP is required") - } - - if req.DeviceID == "" { - return utils.ErrorResponse(c, "DeviceID is required") - } - - response, err := h.authMasyarakatService.VerifyOTP(&req) - if err != nil { - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, response, "Registration/Login successful") -} - -func (h *AuthMasyarakatHandler) LogoutHandler(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.ErrorResponse(c, "User is not logged in or invalid session") - } - - deviceID, ok := c.Locals("device_id").(string) - if !ok || deviceID == "" { - log.Println("Error: DeviceID is nil or empty") - return utils.ErrorResponse(c, "DeviceID is required") - } - - err := h.authMasyarakatService.Logout(userID, deviceID) - if err != nil { - log.Printf("Error during logout process for user %s: %v", userID, err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Logged out successfully") -} - */ \ No newline at end of file diff --git a/internal/handler/auth/auth_pengepul_handler.go b/internal/handler/auth/auth_pengepul_handler.go deleted file mode 100644 index f034ab2..0000000 --- a/internal/handler/auth/auth_pengepul_handler.go +++ /dev/null @@ -1,82 +0,0 @@ -package handler -/* -import ( - "log" - "rijig/dto" - services "rijig/internal/services/auth" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type AuthPengepulHandler struct { - authPengepulService services.AuthMasyarakatService -} - -func NewAuthPengepulHandler(authPengepulService services.AuthMasyarakatService) *AuthPengepulHandler { - return &AuthPengepulHandler{authPengepulService} -} - -func (h *AuthPengepulHandler) RegisterOrLoginHandler(c *fiber.Ctx) error { - var req dto.RegisterRequest - - if err := c.BodyParser(&req); err != nil { - return utils.ErrorResponse(c, "Invalid request body") - } - - if req.Phone == "" { - return utils.ErrorResponse(c, "Phone number is required") - } - - if err := h.authPengepulService.RegisterOrLogin(&req); err != nil { - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "OTP sent successfully") -} - -func (h *AuthPengepulHandler) VerifyOTPHandler(c *fiber.Ctx) error { - var req dto.VerifyOTPRequest - - if err := c.BodyParser(&req); err != nil { - return utils.ErrorResponse(c, "Invalid request body") - } - - if req.OTP == "" { - return utils.ErrorResponse(c, "OTP is required") - } - - if req.DeviceID == "" { - return utils.ErrorResponse(c, "DeviceID is required") - } - - response, err := h.authPengepulService.VerifyOTP(&req) - if err != nil { - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, response, "Registration/Login successful") -} - -func (h *AuthPengepulHandler) LogoutHandler(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.ErrorResponse(c, "User is not logged in or invalid session") - } - - deviceID, ok := c.Locals("device_id").(string) - if !ok || deviceID == "" { - log.Println("Error: DeviceID is nil or empty") - return utils.ErrorResponse(c, "DeviceID is required") - } - - err := h.authPengepulService.Logout(userID, deviceID) - if err != nil { - log.Printf("Error during logout process for user %s: %v", userID, err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Logged out successfully") -} - */ \ No newline at end of file diff --git a/internal/handler/auth/auth_pnegelola_handler.go b/internal/handler/auth/auth_pnegelola_handler.go deleted file mode 100644 index 5382cf6..0000000 --- a/internal/handler/auth/auth_pnegelola_handler.go +++ /dev/null @@ -1,82 +0,0 @@ -package handler -/* -import ( - "log" - "rijig/dto" - services "rijig/internal/services/auth" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type AuthPengelolaHandler struct { - authPengelolaService services.AuthMasyarakatService -} - -func NewAuthPengelolaHandler(authPengelolaService services.AuthMasyarakatService) *AuthPengelolaHandler { - return &AuthPengelolaHandler{authPengelolaService} -} - -func (h *AuthPengelolaHandler) RegisterOrLoginHandler(c *fiber.Ctx) error { - var req dto.RegisterRequest - - if err := c.BodyParser(&req); err != nil { - return utils.ErrorResponse(c, "Invalid request body") - } - - if req.Phone == "" { - return utils.ErrorResponse(c, "Phone number is required") - } - - if err := h.authPengelolaService.RegisterOrLogin(&req); err != nil { - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "OTP sent successfully") -} - -func (h *AuthPengelolaHandler) VerifyOTPHandler(c *fiber.Ctx) error { - var req dto.VerifyOTPRequest - - if err := c.BodyParser(&req); err != nil { - return utils.ErrorResponse(c, "Invalid request body") - } - - if req.OTP == "" { - return utils.ErrorResponse(c, "OTP is required") - } - - if req.DeviceID == "" { - return utils.ErrorResponse(c, "DeviceID is required") - } - - response, err := h.authPengelolaService.VerifyOTP(&req) - if err != nil { - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, response, "Registration/Login successful") -} - -func (h *AuthPengelolaHandler) LogoutHandler(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.ErrorResponse(c, "User is not logged in or invalid session") - } - - deviceID, ok := c.Locals("device_id").(string) - if !ok || deviceID == "" { - log.Println("Error: DeviceID is nil or empty") - return utils.ErrorResponse(c, "DeviceID is required") - } - - err := h.authPengelolaService.Logout(userID, deviceID) - if err != nil { - log.Printf("Error during logout process for user %s: %v", userID, err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Logged out successfully") -} - */ \ No newline at end of file diff --git a/internal/handler/auth_handler.go b/internal/handler/auth_handler.go deleted file mode 100644 index 0782d02..0000000 --- a/internal/handler/auth_handler.go +++ /dev/null @@ -1,80 +0,0 @@ -package handler - -// import ( -// "log" -// "rijig/dto" -// "rijig/internal/services" -// "rijig/utils" - -// "github.com/gofiber/fiber/v2" -// ) - -// type AuthHandler struct { -// authService services.AuthService -// } - -// func NewAuthHandler(authService services.AuthService) *AuthHandler { -// return &AuthHandler{authService} -// } - -// func (h *AuthHandler) RegisterOrLoginHandler(c *fiber.Ctx) error { -// var req dto.RegisterRequest - -// if err := c.BodyParser(&req); err != nil { -// return utils.ErrorResponse(c, "Invalid request body") -// } - -// if req.Phone == "" || req.RoleID == "" { -// return utils.ErrorResponse(c, "Phone number and role ID are required") -// } - -// if err := h.authService.RegisterOrLogin(&req); err != nil { -// return utils.ErrorResponse(c, err.Error()) -// } - -// return utils.SuccessResponse(c, nil, "OTP sent successfully") -// } - -// func (h *AuthHandler) VerifyOTPHandler(c *fiber.Ctx) error { -// var req dto.VerifyOTPRequest - -// if err := c.BodyParser(&req); err != nil { -// return utils.ErrorResponse(c, "Invalid request body") -// } - -// if req.OTP == "" { -// return utils.ErrorResponse(c, "OTP is required") -// } - -// response, err := h.authService.VerifyOTP(&req) -// if err != nil { -// return utils.ErrorResponse(c, err.Error()) -// } - -// return utils.SuccessResponse(c, response, "Registration/Login successful") -// } - -// func (h *AuthHandler) LogoutHandler(c *fiber.Ctx) error { - -// userID, ok := c.Locals("userID").(string) -// if !ok || userID == "" { -// return utils.ErrorResponse(c, "User is not logged in or invalid session") -// } - -// phoneKey := "user_phone:" + userID -// phone, err := utils.GetStringData(phoneKey) -// if err != nil || phone == "" { - -// log.Printf("Error retrieving phone from Redis for user %s: %v", userID, err) -// return utils.ErrorResponse(c, "Phone number is missing or invalid session data") -// } - -// err = h.authService.Logout(userID, phone) -// if err != nil { - -// log.Printf("Error during logout process for user %s: %v", userID, err) -// return utils.ErrorResponse(c, err.Error()) -// } - -// return utils.SuccessResponse(c, nil, "Logged out successfully") -// } diff --git a/internal/handler/banner_handler.go b/internal/handler/banner_handler.go deleted file mode 100644 index 731fd1f..0000000 --- a/internal/handler/banner_handler.go +++ /dev/null @@ -1,109 +0,0 @@ -package handler - -import ( - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type BannerHandler struct { - BannerService services.BannerService -} - -func NewBannerHandler(bannerService services.BannerService) *BannerHandler { - return &BannerHandler{BannerService: bannerService} -} - -func (h *BannerHandler) CreateBanner(c *fiber.Ctx) error { - var request dto.RequestBannerDTO - - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.ValidateBannerInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - bannerImage, err := c.FormFile("bannerimage") - if err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Banner image is required") - } - - bannerResponse, err := h.BannerService.CreateBanner(request, bannerImage) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.CreateResponse(c, bannerResponse, "Banner created successfully") -} - -func (h *BannerHandler) GetAllBanners(c *fiber.Ctx) error { - banners, err := h.BannerService.GetAllBanners() - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch banners") - } - - return utils.NonPaginatedResponse(c, banners, len(banners), "Banners fetched successfully") -} - -func (h *BannerHandler) GetBannerByID(c *fiber.Ctx) error { - id := c.Params("banner_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Banner ID is required") - } - - banner, err := h.BannerService.GetBannerByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, "invalid banner id") - } - - return utils.SuccessResponse(c, banner, "Banner fetched successfully") -} - -func (h *BannerHandler) UpdateBanner(c *fiber.Ctx) error { - id := c.Params("banner_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Banner ID is required") - } - - var request dto.RequestBannerDTO - - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.ValidateBannerInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - bannerImage, err := c.FormFile("bannerimage") - if err != nil && err.Error() != "no such file" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Banner image is required") - } - - bannerResponse, err := h.BannerService.UpdateBanner(id, request, bannerImage) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, bannerResponse, "Banner updated successfully") -} - -func (h *BannerHandler) DeleteBanner(c *fiber.Ctx) error { - id := c.Params("banner_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Banner ID is required") - } - - err := h.BannerService.DeleteBanner(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Banner deleted successfully") -} diff --git a/internal/handler/cart_handler.go b/internal/handler/cart_handler.go deleted file mode 100644 index 4dd7c25..0000000 --- a/internal/handler/cart_handler.go +++ /dev/null @@ -1,93 +0,0 @@ -package handler - -import ( - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type CartHandler struct { - cartService services.CartService -} - -func NewCartHandler(cartService services.CartService) *CartHandler { - return &CartHandler{cartService: cartService} -} - -func (h *CartHandler) AddOrUpdateItem(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - var req dto.RequestCartItemDTO - - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "request": {"Payload tidak valid"}, - }) - } - - hasErrors, _ := req.Amount > 0 && req.TrashID != "", true - if !hasErrors { - errs := make(map[string][]string) - if req.Amount <= 0 { - errs["amount"] = append(errs["amount"], "Amount harus lebih dari 0") - } - if req.TrashID == "" { - errs["trash_id"] = append(errs["trash_id"], "Trash ID tidak boleh kosong") - } - return utils.ValidationErrorResponse(c, errs) - } - - if err := h.cartService.AddOrUpdateItem(c.Context(), userID, req); err != nil { - return utils.InternalServerErrorResponse(c, "Gagal menambahkan item ke keranjang") - } - - return utils.GenericResponse(c, fiber.StatusOK, "Item berhasil ditambahkan ke keranjang") -} - -func (h *CartHandler) GetCart(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - cart, err := h.cartService.GetCart(c.Context(), userID) - if err != nil { - return utils.ErrorResponse(c, "Gagal mengambil data keranjang") - } - - return utils.SuccessResponse(c, cart, "Berhasil mengambil data keranjang") -} - -func (h *CartHandler) DeleteItem(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - trashID := c.Params("trash_id") - - if trashID == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Trash ID tidak boleh kosong") - } - - if err := h.cartService.DeleteItem(c.Context(), userID, trashID); err != nil { - return utils.InternalServerErrorResponse(c, "Gagal menghapus item dari keranjang") - } - - return utils.GenericResponse(c, fiber.StatusOK, "Item berhasil dihapus dari keranjang") -} - -func (h *CartHandler) Checkout(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - if err := h.cartService.Checkout(c.Context(), userID); err != nil { - return utils.InternalServerErrorResponse(c, "Gagal melakukan checkout keranjang") - } - - return utils.GenericResponse(c, fiber.StatusOK, "Checkout berhasil. Permintaan pickup telah dibuat.") -} - -func (h *CartHandler) ClearCart(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - err := h.cartService.ClearCart(c.Context(), userID) - if err != nil { - return utils.InternalServerErrorResponse(c, "Gagal menghapus keranjang") - } - - return utils.GenericResponse(c, fiber.StatusOK, "Keranjang berhasil dikosongkan") -} \ No newline at end of file diff --git a/internal/handler/collector_handler.go b/internal/handler/collector_handler.go deleted file mode 100644 index 25a73fb..0000000 --- a/internal/handler/collector_handler.go +++ /dev/null @@ -1,194 +0,0 @@ -package handler - -import ( - "context" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type CollectorHandler interface { - CreateCollector(c *fiber.Ctx) error - AddTrashToCollector(c *fiber.Ctx) error - GetCollectorByID(c *fiber.Ctx) error - GetCollectorByUserID(c *fiber.Ctx) error - UpdateCollector(c *fiber.Ctx) error - UpdateJobStatus(c *fiber.Ctx) error - UpdateTrash(c *fiber.Ctx) error - DeleteTrash(c *fiber.Ctx) error -} -type collectorHandler struct { - service services.CollectorService -} - -func NewCollectorHandler(service services.CollectorService) CollectorHandler { - return &collectorHandler{service: service} -} - -func (h *collectorHandler) CreateCollector(c *fiber.Ctx) error { - var req dto.RequestCollectorDTO - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if errs, valid := req.ValidateRequestCollector(); !valid { - return utils.ValidationErrorResponse(c, errs) - } - - userID := c.Locals("userID").(string) - err := h.service.CreateCollector(context.Background(), userID, req) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.CreateResponse(c, nil, "Collector berhasil dibuat") -} - -func (h *collectorHandler) AddTrashToCollector(c *fiber.Ctx) error { - collectorID := c.Params("id") - var req dto.RequestAddAvaibleTrash - - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if errs, valid := req.ValidateRequestAddAvaibleTrash(); !valid { - return utils.ValidationErrorResponse(c, errs) - } - - err := h.service.AddTrashToCollector(context.Background(), collectorID, req) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Trash berhasil ditambahkan") -} - -func (h *collectorHandler) GetCollectorByID(c *fiber.Ctx) error { - collectorID := c.Params("id") - result, err := h.service.GetCollectorByID(context.Background(), collectorID) - if err != nil { - return utils.ErrorResponse(c, "Collector tidak ditemukan") - } - return utils.SuccessResponse(c, result, "Data collector berhasil diambil") -} -func (h *collectorHandler) GetCollectorByUserID(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - result, err := h.service.GetCollectorByUserID(context.Background(), userID) - if err != nil { - return utils.ErrorResponse(c, "Collector tidak ditemukan") - } - return utils.SuccessResponse(c, result, "Data collector berhasil diambil") -} - -func (h *collectorHandler) UpdateCollector(c *fiber.Ctx) error { - collectorID := c.Params("id") - var req struct { - JobStatus *string `json:"job_status"` - Rating float32 `json:"rating"` - AddressID string `json:"address_id"` - } - - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if req.AddressID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "address_id": {"tidak boleh kosong"}, - }) - } - - err := h.service.UpdateCollector(context.Background(), collectorID, req.JobStatus, req.Rating, req.AddressID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Collector berhasil diperbarui") -} - -func (h *collectorHandler) UpdateJobStatus(c *fiber.Ctx) error { - collectorID := c.Params("id") - var req struct { - JobStatus string `json:"job_status"` - } - - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if req.JobStatus != "active" && req.JobStatus != "inactive" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "job_status": {"harus bernilai 'active' atau 'inactive'"}, - }) - } - - err := h.service.UpdateCollector(c.Context(), collectorID, &req.JobStatus, 0, "") - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Status collector berhasil diperbarui") -} - -func (h *collectorHandler) UpdateTrash(c *fiber.Ctx) error { - collectorID := c.Params("id") - var req []dto.RequestAvaibleTrashbyCollector - - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - for i, t := range req { - if t.TrashId == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "trash_id": {t.TrashId, "trash_id tidak boleh kosong pada item ke " + string(rune(i))}, - }) - } - if t.TrashPrice <= 0 { - return utils.ValidationErrorResponse(c, map[string][]string{ - "trash_price": {"trash_price harus lebih dari 0 pada item ke " + string(rune(i))}, - }) - } - } - - err := h.service.UpdateAvaibleTrashByCollector(context.Background(), collectorID, req) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Trash berhasil diperbarui") -} - -func (h *collectorHandler) DeleteTrash(c *fiber.Ctx) error { - trashID := c.Params("id") - if trashID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "trash_id": {"tidak boleh kosong"}, - }) - } - - err := h.service.DeleteAvaibleTrash(context.Background(), trashID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Trash berhasil dihapus") -} diff --git a/internal/handler/company_profile_handler.go b/internal/handler/company_profile_handler.go deleted file mode 100644 index 2d8d7aa..0000000 --- a/internal/handler/company_profile_handler.go +++ /dev/null @@ -1,100 +0,0 @@ -package handler - -import ( - "fmt" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type CompanyProfileHandler struct { - companyProfileService services.CompanyProfileService -} - -func NewCompanyProfileHandler(service services.CompanyProfileService) *CompanyProfileHandler { - return &CompanyProfileHandler{ - companyProfileService: service, - } -} - -func (h *CompanyProfileHandler) CreateCompanyProfile(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - var requestDTO dto.RequestCompanyProfileDTO - if err := c.BodyParser(&requestDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid input data"}}) - } - - companyProfileResponse, err := h.companyProfileService.CreateCompanyProfile(userID, &requestDTO) - if err != nil { - return utils.ErrorResponse(c, fmt.Sprintf("Failed to create company profile: %v", err)) - } - - return utils.SuccessResponse(c, companyProfileResponse, "Company profile created successfully") -} - -func (h *CompanyProfileHandler) GetCompanyProfileByID(c *fiber.Ctx) error { - id := c.Params("company_id") - - companyProfileResponse, err := h.companyProfileService.GetCompanyProfileByID(id) - if err != nil { - return utils.ErrorResponse(c, fmt.Sprintf("Failed to fetch company profile: %v", err)) - } - - return utils.SuccessResponse(c, companyProfileResponse, "Company profile fetched successfully") -} - -func (h *CompanyProfileHandler) GetCompanyProfilesByUserID(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - companyProfilesResponse, err := h.companyProfileService.GetCompanyProfilesByUserID(userID) - if err != nil { - return utils.ErrorResponse(c, fmt.Sprintf("Failed to fetch company profiles: %v", err)) - } - - return utils.NonPaginatedResponse(c, companyProfilesResponse, len(companyProfilesResponse), "Company profiles fetched successfully") -} - -func (h *CompanyProfileHandler) UpdateCompanyProfile(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - id := c.Params("company_id") - - var requestDTO dto.RequestCompanyProfileDTO - if err := c.BodyParser(&requestDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid input data"}}) - } - - companyProfileResponse, err := h.companyProfileService.UpdateCompanyProfile(id, &requestDTO) - if err != nil { - return utils.ErrorResponse(c, fmt.Sprintf("Failed to update company profile: %v", err)) - } - - return utils.SuccessResponse(c, companyProfileResponse, "Company profile updated successfully") -} - -func (h *CompanyProfileHandler) DeleteCompanyProfile(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - id := c.Params("company_id") - - err := h.companyProfileService.DeleteCompanyProfile(id) - if err != nil { - return utils.ErrorResponse(c, fmt.Sprintf("Failed to delete company profile: %v", err)) - } - - return utils.SuccessResponse(c, nil, "Company profile deleted successfully") -} diff --git a/internal/handler/coveragearea_handler.go b/internal/handler/coveragearea_handler.go deleted file mode 100644 index 08cb17d..0000000 --- a/internal/handler/coveragearea_handler.go +++ /dev/null @@ -1,93 +0,0 @@ -package handler - -import ( - "fmt" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type CoverageAreaHandler struct { - service services.CoverageAreaService -} - -func NewCoverageAreaHandler(service services.CoverageAreaService) *CoverageAreaHandler { - return &CoverageAreaHandler{service: service} -} - -func (h *CoverageAreaHandler) CreateCoverageArea(c *fiber.Ctx) error { - var request dto.RequestCoverageArea - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"Invalid request body"}, - }) - } - - errors, valid := request.ValidateCoverageArea() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - response, err := h.service.CreateCoverageArea(request) - if err != nil { - return utils.InternalServerErrorResponse(c, fmt.Sprintf("Error creating coverage area: %v", err)) - } - - return utils.SuccessResponse(c, response, "Coverage area created successfully") -} - -func (h *CoverageAreaHandler) GetCoverageAreaByID(c *fiber.Ctx) error { - id := c.Params("id") - - response, err := h.service.GetCoverageAreaByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Coverage area with ID %s not found", id)) - } - - return utils.SuccessResponse(c, response, "Coverage area found") -} - -func (h *CoverageAreaHandler) GetAllCoverageAreas(c *fiber.Ctx) error { - - response, err := h.service.GetAllCoverageAreas() - if err != nil { - return utils.InternalServerErrorResponse(c, "Error fetching coverage areas") - } - - return utils.SuccessResponse(c, response, "Coverage areas fetched successfully") -} - -func (h *CoverageAreaHandler) UpdateCoverageArea(c *fiber.Ctx) error { - id := c.Params("id") - var request dto.RequestCoverageArea - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"Invalid request body"}, - }) - } - - errors, valid := request.ValidateCoverageArea() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - response, err := h.service.UpdateCoverageArea(id, request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Coverage area with ID %s not found", id)) - } - - return utils.SuccessResponse(c, response, "Coverage area updated successfully") -} - -func (h *CoverageAreaHandler) DeleteCoverageArea(c *fiber.Ctx) error { - id := c.Params("id") - - err := h.service.DeleteCoverageArea(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Coverage area with ID %s not found", id)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Coverage area deleted successfully") -} diff --git a/internal/handler/identitycard_handler.go b/internal/handler/identitycard_handler.go deleted file mode 100644 index b05ba95..0000000 --- a/internal/handler/identitycard_handler.go +++ /dev/null @@ -1,134 +0,0 @@ -package handler - -import ( - "log" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type IdentityCardHandler struct { - IdentityCardService services.IdentityCardService -} - -func NewIdentityCardHandler(identityCardService services.IdentityCardService) *IdentityCardHandler { - return &IdentityCardHandler{ - IdentityCardService: identityCardService, - } -} - -func (h *IdentityCardHandler) CreateIdentityCard(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User not authenticated") - } - - var request dto.RequestIdentityCardDTO - if err := c.BodyParser(&request); err != nil { - log.Printf("Error parsing body: %v", err) - return utils.ErrorResponse(c, "Invalid request data") - } - - cardPhoto, err := c.FormFile("cardphoto") - if err != nil { - log.Printf("Error retrieving card photo from request: %v", err) - return utils.ErrorResponse(c, "Card photo is required") - } - - identityCard, err := h.IdentityCardService.CreateIdentityCard(userID, &request, cardPhoto) - if err != nil { - log.Printf("Error creating identity card: %v", err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.CreateResponse(c, identityCard, "Identity card created successfully") -} - -func (h *IdentityCardHandler) UpdateIdentityCard(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User not authenticated") - } - - id := c.Params("identity_id") - if id == "" { - return utils.ErrorResponse(c, "Identity card ID is required") - } - - var request dto.RequestIdentityCardDTO - if err := c.BodyParser(&request); err != nil { - log.Printf("Error parsing body: %v", err) - return utils.ErrorResponse(c, "Invalid request data") - } - - cardPhoto, err := c.FormFile("cardphoto") - if err != nil && err.Error() != "File not found" { - log.Printf("Error retrieving card photo: %v", err) - return utils.ErrorResponse(c, "Card photo is required") - } - - updatedCard, err := h.IdentityCardService.UpdateIdentityCard(userID, id, &request, cardPhoto) - if err != nil { - log.Printf("Error updating identity card: %v", err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, updatedCard, "Identity card updated successfully") -} - -func (h *IdentityCardHandler) GetIdentityCardById(c *fiber.Ctx) error { - - id := c.Params("identity_id") - if id == "" { - return utils.ErrorResponse(c, "Identity card ID is required") - } - - identityCard, err := h.IdentityCardService.GetIdentityCardByID(id) - if err != nil { - log.Printf("Error retrieving identity card: %v", err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, identityCard, "Identity card retrieved successfully") -} - -func (h *IdentityCardHandler) GetIdentityCard(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - identityCard, err := h.IdentityCardService.GetIdentityCardsByUserID(userID) - if err != nil { - log.Printf("Error retrieving identity card: %v", err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, identityCard, "Identity card retrieved successfully") -} - -func (h *IdentityCardHandler) DeleteIdentityCard(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User not authenticated") - } - - id := c.Params("identity_id") - if id == "" { - return utils.ErrorResponse(c, "Identity card ID is required") - } - - err := h.IdentityCardService.DeleteIdentityCard(id) - if err != nil { - log.Printf("Error deleting identity card: %v", err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Identity card deleted successfully") -} diff --git a/internal/handler/initialcoint_handler.go b/internal/handler/initialcoint_handler.go deleted file mode 100644 index c80b466..0000000 --- a/internal/handler/initialcoint_handler.go +++ /dev/null @@ -1,99 +0,0 @@ -package handler - -import ( - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type InitialCointHandler struct { - InitialCointService services.InitialCointService -} - -func NewInitialCointHandler(initialCointService services.InitialCointService) *InitialCointHandler { - return &InitialCointHandler{InitialCointService: initialCointService} -} - -func (h *InitialCointHandler) CreateInitialCoint(c *fiber.Ctx) error { - var request dto.RequestInitialCointDTO - - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.ValidateCointInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - initialCointResponse, err := h.InitialCointService.CreateInitialCoint(request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.CreateResponse(c, initialCointResponse, "Initial coint created successfully") -} - -func (h *InitialCointHandler) GetAllInitialCoints(c *fiber.Ctx) error { - initialCoints, err := h.InitialCointService.GetAllInitialCoints() - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch initial coints") - } - - return utils.NonPaginatedResponse(c, initialCoints, len(initialCoints), "Initial coints fetched successfully") -} - -func (h *InitialCointHandler) GetInitialCointByID(c *fiber.Ctx) error { - id := c.Params("coin_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Coin ID is required") - } - - initialCoint, err := h.InitialCointService.GetInitialCointByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, "Invalid coin ID") - } - - return utils.SuccessResponse(c, initialCoint, "Initial coint fetched successfully") -} - -func (h *InitialCointHandler) UpdateInitialCoint(c *fiber.Ctx) error { - id := c.Params("coin_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Coin ID is required") - } - - var request dto.RequestInitialCointDTO - - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.ValidateCointInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - initialCointResponse, err := h.InitialCointService.UpdateInitialCoint(id, request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, initialCointResponse, "Initial coint updated successfully") -} - -func (h *InitialCointHandler) DeleteInitialCoint(c *fiber.Ctx) error { - id := c.Params("coin_id") - if id == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Coin ID is required") - } - - err := h.InitialCointService.DeleteInitialCoint(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Initial coint deleted successfully") -} diff --git a/internal/handler/pickup_history_handler.go b/internal/handler/pickup_history_handler.go deleted file mode 100644 index 2525f44..0000000 --- a/internal/handler/pickup_history_handler.go +++ /dev/null @@ -1,37 +0,0 @@ -package handler - -import ( - "context" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type PickupStatusHistoryHandler interface { - GetStatusHistory(c *fiber.Ctx) error -} - -type pickupStatusHistoryHandler struct { - service services.PickupStatusHistoryService -} - -func NewPickupStatusHistoryHandler(service services.PickupStatusHistoryService) PickupStatusHistoryHandler { - return &pickupStatusHistoryHandler{service: service} -} - -func (h *pickupStatusHistoryHandler) GetStatusHistory(c *fiber.Ctx) error { - pickupID := c.Params("id") - if pickupID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "pickup_id": {"pickup ID tidak boleh kosong"}, - }) - } - - histories, err := h.service.GetStatusHistory(context.Background(), pickupID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, histories, "Riwayat status pickup berhasil diambil") -} diff --git a/internal/handler/pickup_matching_handler.go b/internal/handler/pickup_matching_handler.go deleted file mode 100644 index ecb39d9..0000000 --- a/internal/handler/pickup_matching_handler.go +++ /dev/null @@ -1,49 +0,0 @@ -package handler - -import ( - "context" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type PickupMatchingHandler interface { - GetNearbyCollectorsForPickup(c *fiber.Ctx) error - GetAvailablePickupForCollector(c *fiber.Ctx) error -} - -type pickupMatchingHandler struct { - service services.PickupMatchingService -} - -func NewPickupMatchingHandler(service services.PickupMatchingService) PickupMatchingHandler { - return &pickupMatchingHandler{service: service} -} - -func (h *pickupMatchingHandler) GetNearbyCollectorsForPickup(c *fiber.Ctx) error { - pickupID := c.Params("pickupID") - if pickupID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "pickup_id": {"pickup ID harus disertakan"}, - }) - } - - collectors, err := h.service.FindNearbyCollectorsForPickup(context.Background(), pickupID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, collectors, "Data collector terdekat berhasil diambil") -} - -func (h *pickupMatchingHandler) GetAvailablePickupForCollector(c *fiber.Ctx) error { - collectorID := c.Locals("userID").(string) - - pickups, err := h.service.FindAvailableRequestsForCollector(context.Background(), collectorID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, pickups, "Data request pickup otomatis berhasil diambil") -} diff --git a/internal/handler/product_handler.go b/internal/handler/product_handler.go deleted file mode 100644 index 5c0eccf..0000000 --- a/internal/handler/product_handler.go +++ /dev/null @@ -1,227 +0,0 @@ -package handler - -import ( - "fmt" - "log" - "strconv" - - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type ProductHandler struct { - ProductService services.ProductService -} - -func NewProductHandler(productService services.ProductService) *ProductHandler { - return &ProductHandler{ProductService: productService} -} - -func ConvertStringToInt(value string) (int, error) { - convertedValue, err := strconv.Atoi(value) - if err != nil { - return 0, fmt.Errorf("invalid integer format: %s", value) - } - return convertedValue, nil -} - -func GetPaginationParams(c *fiber.Ctx) (int, int, error) { - pageStr := c.Query("page", "1") - limitStr := c.Query("limit", "50") - - page, err := strconv.Atoi(pageStr) - if err != nil || page <= 0 { - return 0, 0, fmt.Errorf("invalid page value") - } - - limit, err := strconv.Atoi(limitStr) - if err != nil || limit <= 0 { - return 0, 0, fmt.Errorf("invalid limit value") - } - - return page, limit, nil -} - -func (h *ProductHandler) CreateProduct(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok { - log.Println("User ID not found in Locals") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") - } - - productName := c.FormValue("product_name") - quantityStr := c.FormValue("quantity") - productImages, err := c.MultipartForm() - if err != nil { - log.Printf("Error parsing form data: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Error parsing form data") - } - - quantity, err := ConvertStringToInt(quantityStr) - if err != nil { - log.Printf("Invalid quantity: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid quantity") - } - - productDTO := dto.RequestProductDTO{ - ProductName: productName, - Quantity: quantity, - ProductImages: productImages.File["product_image"], - } - - product, err := h.ProductService.CreateProduct(userID, &productDTO) - if err != nil { - log.Printf("Error creating product: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, err.Error()) - } - - return utils.CreateResponse(c, product, "Product created successfully") -} - -func (h *ProductHandler) GetAllProductsByStoreID(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok { - log.Println("User ID not found in Locals") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") - } - - page, limit, err := GetPaginationParams(c) - if err != nil { - log.Printf("Invalid pagination params: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid pagination parameters") - } - - products, total, err := h.ProductService.GetAllProductsByStoreID(userID, page, limit) - if err != nil { - log.Printf("Error fetching products: %v", err) - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.PaginatedResponse(c, products, page, limit, int(total), "Products fetched successfully") -} - -func (h *ProductHandler) GetProductByID(c *fiber.Ctx) error { - - productID := c.Params("product_id") - if productID == "" { - log.Println("Product ID is required") - return utils.GenericResponse(c, fiber.StatusBadRequest, "Product ID is required") - } - - product, err := h.ProductService.GetProductByID(productID) - if err != nil { - log.Printf("Error fetching product: %v", err) - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, product, "Product fetched successfully") -} - -func (h *ProductHandler) UpdateProduct(c *fiber.Ctx) error { - - userID, ok := c.Locals("userID").(string) - if !ok { - log.Println("User ID not found in Locals") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") - } - - productID := c.Params("product_id") - if productID == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Product ID is required") - } - - var productDTO dto.RequestProductDTO - if err := c.BodyParser(&productDTO); err != nil { - log.Printf("Error parsing body: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid request body") - } - - productImages, err := c.MultipartForm() - if err != nil { - log.Printf("Error parsing form data: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Error parsing form data") - } - - productDTO.ProductImages = productImages.File["product_images"] - - product, err := h.ProductService.UpdateProduct(userID, productID, &productDTO) - if err != nil { - log.Printf("Error updating product: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, err.Error()) - } - - return utils.CreateResponse(c, product, "Product updated successfully") -} - -func (h *ProductHandler) DeleteProduct(c *fiber.Ctx) error { - productID := c.Params("product_id") - if productID == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Product ID is required") - } - - err := h.ProductService.DeleteProduct(productID) - if err != nil { - log.Printf("Error deleting product: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, fmt.Sprintf("Failed to delete product: %v", err)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Product deleted successfully") -} - -func (h *ProductHandler) DeleteProducts(c *fiber.Ctx) error { - var productIDs []string - if err := c.BodyParser(&productIDs); err != nil { - log.Printf("Error parsing product IDs: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid input for product IDs") - } - - if len(productIDs) == 0 { - return utils.GenericResponse(c, fiber.StatusBadRequest, "No product IDs provided") - } - - err := h.ProductService.DeleteProducts(productIDs) - if err != nil { - log.Printf("Error deleting products: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, fmt.Sprintf("Failed to delete products: %v", err)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Products deleted successfully") -} - -func (h *ProductHandler) DeleteProductImage(c *fiber.Ctx) error { - imageID := c.Params("image_id") - if imageID == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Image ID is required") - } - - err := h.ProductService.DeleteProductImage(imageID) - if err != nil { - log.Printf("Error deleting product image: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, fmt.Sprintf("Failed to delete product image: %v", err)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Product image deleted successfully") -} - -func (h *ProductHandler) DeleteProductImages(c *fiber.Ctx) error { - var imageIDs []string - if err := c.BodyParser(&imageIDs); err != nil { - log.Printf("Error parsing image IDs: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid input for image IDs") - } - - if len(imageIDs) == 0 { - return utils.GenericResponse(c, fiber.StatusBadRequest, "No image IDs provided") - } - - err := h.ProductService.DeleteProductImages(imageIDs) - if err != nil { - log.Printf("Error deleting product images: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, fmt.Sprintf("Failed to delete product images: %v", err)) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Product images deleted successfully") -} diff --git a/internal/handler/rating_handler.go b/internal/handler/rating_handler.go deleted file mode 100644 index 6f64916..0000000 --- a/internal/handler/rating_handler.go +++ /dev/null @@ -1,66 +0,0 @@ -package handler - -import ( - "context" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type PickupRatingHandler interface { - CreateRating(c *fiber.Ctx) error - GetRatingsByCollector(c *fiber.Ctx) error - GetAverageRating(c *fiber.Ctx) error -} - -type pickupRatingHandler struct { - service services.PickupRatingService -} - -func NewPickupRatingHandler(service services.PickupRatingService) PickupRatingHandler { - return &pickupRatingHandler{service: service} -} - -func (h *pickupRatingHandler) CreateRating(c *fiber.Ctx) error { - pickupID := c.Params("id") - userID := c.Locals("userID").(string) - collectorID := c.Query("collector_id") - - var req dto.CreatePickupRatingDTO - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"Format JSON tidak valid"}, - }) - } - - if errs, ok := req.ValidateCreatePickupRatingDTO(); !ok { - return utils.ValidationErrorResponse(c, errs) - } - - err := h.service.CreateRating(context.Background(), userID, pickupID, collectorID, req) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Rating berhasil dikirim") -} - -func (h *pickupRatingHandler) GetRatingsByCollector(c *fiber.Ctx) error { - collectorID := c.Params("id") - ratings, err := h.service.GetRatingsByCollector(context.Background(), collectorID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - return utils.SuccessResponse(c, ratings, "Daftar rating collector berhasil diambil") -} - -func (h *pickupRatingHandler) GetAverageRating(c *fiber.Ctx) error { - collectorID := c.Params("id") - avg, err := h.service.GetAverageRating(context.Background(), collectorID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - return utils.SuccessResponse(c, fiber.Map{"average_rating": avg}, "Rata-rata rating collector") -} diff --git a/internal/handler/request_pickup_handler.go b/internal/handler/request_pickup_handler.go deleted file mode 100644 index f5c2826..0000000 --- a/internal/handler/request_pickup_handler.go +++ /dev/null @@ -1,150 +0,0 @@ -package handler - -import ( - "context" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - "time" - - "github.com/gofiber/fiber/v2" -) - -type RequestPickupHandler interface { - CreateRequestPickup(c *fiber.Ctx) error - SelectCollector(c *fiber.Ctx) error - GetAssignedPickup(c *fiber.Ctx) error - ConfirmPickup(c *fiber.Ctx) error - UpdatePickupStatus(c *fiber.Ctx) error - UpdatePickupItemActualAmount(c *fiber.Ctx) error -} - -type requestPickupHandler struct { - service services.RequestPickupService -} - -func NewRequestPickupHandler(service services.RequestPickupService) RequestPickupHandler { - return &requestPickupHandler{service: service} -} - -func (h *requestPickupHandler) CreateRequestPickup(c *fiber.Ctx) error { - userID := c.Locals("userID").(string) - - var req dto.RequestPickupDTO - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if errs, ok := req.Validate(); !ok { - return utils.ValidationErrorResponse(c, errs) - } - - if err := h.service.ConvertCartToRequestPickup(context.Background(), userID, req); err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Request pickup berhasil dibuat") -} - -func (h *requestPickupHandler) SelectCollector(c *fiber.Ctx) error { - pickupID := c.Params("id") - if pickupID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "pickup_id": {"pickup ID harus disertakan"}, - }) - } - - var req dto.SelectCollectorDTO - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if errs, ok := req.Validate(); !ok { - return utils.ValidationErrorResponse(c, errs) - } - - if err := h.service.AssignCollectorToRequest(context.Background(), pickupID, req); err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Collector berhasil dipilih untuk pickup") -} - -func (h *requestPickupHandler) GetAssignedPickup(c *fiber.Ctx) error { - collectorID := c.Locals("userID").(string) - result, err := h.service.FindRequestsAssignedToCollector(context.Background(), collectorID) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - return utils.SuccessResponse(c, result, "Data pickup yang ditugaskan berhasil diambil") -} - -func (h *requestPickupHandler) ConfirmPickup(c *fiber.Ctx) error { - pickupID := c.Params("id") - if pickupID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "pickup_id": {"pickup ID wajib diisi"}, - }) - } - - err := h.service.ConfirmPickupByCollector(context.Background(), pickupID, time.Now()) - if err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - return utils.SuccessResponse(c, nil, "Pickup berhasil dikonfirmasi oleh collector") -} - -func (h *requestPickupHandler) UpdatePickupStatus(c *fiber.Ctx) error { - pickupID := c.Params("id") - if pickupID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "pickup_id": {"pickup ID tidak boleh kosong"}, - }) - } - - if err := h.service.UpdatePickupStatusToPickingUp(context.Background(), pickupID); err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Status pickup berhasil diperbarui menjadi 'collector_are_picking_up'") -} - -func (h *requestPickupHandler) UpdatePickupItemActualAmount(c *fiber.Ctx) error { - pickupID := c.Params("id") - if pickupID == "" { - return utils.ValidationErrorResponse(c, map[string][]string{ - "pickup_id": {"pickup ID tidak boleh kosong"}, - }) - } - - var req dto.UpdatePickupItemsRequest - if err := c.BodyParser(&req); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{ - "body": {"format JSON tidak valid"}, - }) - } - - if len(req.Items) == 0 { - return utils.ValidationErrorResponse(c, map[string][]string{ - "items": {"daftar item tidak boleh kosong"}, - }) - } - - for _, item := range req.Items { - if item.ItemID == "" || item.Amount <= 0 { - return utils.ValidationErrorResponse(c, map[string][]string{ - "item": {"item_id harus valid dan amount > 0"}, - }) - } - } - - if err := h.service.UpdateActualPickupItems(context.Background(), pickupID, req.Items); err != nil { - return utils.InternalServerErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Berat aktual dan harga berhasil diperbarui") -} \ No newline at end of file diff --git a/internal/handler/role_handler.go b/internal/handler/role_handler.go deleted file mode 100644 index b399aa1..0000000 --- a/internal/handler/role_handler.go +++ /dev/null @@ -1,47 +0,0 @@ -package handler - -import ( - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type RoleHandler struct { - RoleService services.RoleService -} - -func NewRoleHandler(roleService services.RoleService) *RoleHandler { - return &RoleHandler{RoleService: roleService} -} - -func (h *RoleHandler) GetRoles(c *fiber.Ctx) error { - - // roleID, ok := c.Locals("roleID").(string) - // if !ok || roleID != utils.RoleAdministrator { - // return utils.GenericResponse(c, fiber.StatusForbidden, "Forbidden: You don't have permission to access this resource") - // } - - roles, err := h.RoleService.GetRoles(c.Context()) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.SuccessResponse(c, roles, "Roles fetched successfully") -} - -func (h *RoleHandler) GetRoleByID(c *fiber.Ctx) error { - roleID := c.Params("role_id") - - // roleIDFromSession, ok := c.Locals("roleID").(string) - // if !ok || roleIDFromSession != utils.RoleAdministrator { - // return utils.GenericResponse(c, fiber.StatusForbidden, "Forbidden: You don't have permission to access this resource") - // } - - role, err := h.RoleService.GetRoleByID(c.Context(), roleID) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, "role id tidak ditemukan") - } - - return utils.SuccessResponse(c, role, "Role fetched successfully") -} diff --git a/internal/handler/store_handler.go b/internal/handler/store_handler.go deleted file mode 100644 index dde89f1..0000000 --- a/internal/handler/store_handler.go +++ /dev/null @@ -1,159 +0,0 @@ -package handler - -import ( - "log" - - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type StoreHandler struct { - StoreService services.StoreService -} - -func NewStoreHandler(storeService services.StoreService) *StoreHandler { - return &StoreHandler{StoreService: storeService} -} - -func (h *StoreHandler) CreateStore(c *fiber.Ctx) error { - - storeName := c.FormValue("store_name") - storeInfo := c.FormValue("store_info") - storeAddressID := c.FormValue("store_address_id") - - if storeName == "" || storeInfo == "" || storeAddressID == "" { - log.Println("Missing required fields") - return utils.GenericResponse(c, fiber.StatusBadRequest, "All fields are required") - } - - storeLogo, err := c.FormFile("store_logo") - if err != nil { - log.Printf("Error parsing store logo: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Store logo is required") - } - - storeBanner, err := c.FormFile("store_banner") - if err != nil { - log.Printf("Error parsing store banner: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Store banner is required") - } - - requestStoreDTO := dto.RequestStoreDTO{ - StoreName: storeName, - StoreLogo: storeLogo.Filename, - StoreBanner: storeBanner.Filename, - StoreInfo: storeInfo, - StoreAddressID: storeAddressID, - } - - errors, valid := requestStoreDTO.ValidateStoreInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - userID, ok := c.Locals("userID").(string) - if !ok { - log.Println("User ID not found in Locals") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") - } - - store, err := h.StoreService.CreateStore(userID, requestStoreDTO, storeLogo, storeBanner) - if err != nil { - log.Printf("Error creating store: %v", err) - return utils.GenericResponse(c, fiber.StatusConflict, err.Error()) - } - - return utils.CreateResponse(c, store, "Store created successfully") -} - -func (h *StoreHandler) GetStoreByUserID(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok { - log.Println("User ID not found in Locals") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") - } - - store, err := h.StoreService.GetStoreByUserID(userID) - if err != nil { - log.Printf("Error fetching store: %v", err) - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - log.Printf("Store fetched successfully: %v", store) - return utils.SuccessResponse(c, store, "Store fetched successfully") -} - -func (h *StoreHandler) UpdateStore(c *fiber.Ctx) error { - storeID := c.Params("store_id") - if storeID == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Store ID is required") - } - - storeName := c.FormValue("store_name") - storeInfo := c.FormValue("store_info") - storeAddressID := c.FormValue("store_address_id") - - if storeName == "" || storeInfo == "" || storeAddressID == "" { - log.Println("Missing required fields") - return utils.GenericResponse(c, fiber.StatusBadRequest, "All fields are required") - } - - storeLogo, err := c.FormFile("store_logo") - if err != nil && err.Error() != "missing file" { - log.Printf("Error parsing store logo: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Error parsing store logo") - } - - storeBanner, err := c.FormFile("store_banner") - if err != nil && err.Error() != "missing file" { - log.Printf("Error parsing store banner: %v", err) - return utils.GenericResponse(c, fiber.StatusBadRequest, "Error parsing store banner") - } - - requestStoreDTO := dto.RequestStoreDTO{ - StoreName: storeName, - StoreLogo: storeLogo.Filename, - StoreBanner: storeBanner.Filename, - StoreInfo: storeInfo, - StoreAddressID: storeAddressID, - } - - errors, valid := requestStoreDTO.ValidateStoreInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - userID, ok := c.Locals("userID").(string) - if !ok { - log.Println("User ID not found in Locals") - return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") - } - - store, err := h.StoreService.UpdateStore(storeID, &requestStoreDTO, storeLogo, storeBanner, userID) - if err != nil { - log.Printf("Error updating store: %v", err) - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - log.Printf("Store updated successfully: %v", store) - return utils.SuccessResponse(c, store, "Store updated successfully") -} - -func (h *StoreHandler) DeleteStore(c *fiber.Ctx) error { - storeID := c.Params("store_id") - if storeID == "" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Store ID is required") - } - - err := h.StoreService.DeleteStore(storeID) - if err != nil { - log.Printf("Error deleting store: %v", err) - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - log.Printf("Store deleted successfully: %v", storeID) - return utils.GenericResponse(c, fiber.StatusOK, "Store deleted successfully") -} diff --git a/internal/handler/trash_handler.go b/internal/handler/trash_handler.go deleted file mode 100644 index 3bec83f..0000000 --- a/internal/handler/trash_handler.go +++ /dev/null @@ -1,148 +0,0 @@ -package handler - -import ( - "log" - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type TrashHandler struct { - TrashService services.TrashService -} - -func NewTrashHandler(trashService services.TrashService) *TrashHandler { - return &TrashHandler{TrashService: trashService} -} - -func (h *TrashHandler) CreateCategory(c *fiber.Ctx) error { - var request dto.RequestTrashCategoryDTO - - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := request.ValidateTrashCategoryInput() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - iconTrash, err := c.FormFile("icon") - if err != nil { - log.Printf("Error retrieving card photo from request: %v", err) - return utils.ErrorResponse(c, "Card photo is required") - } - - categoryResponse, err := h.TrashService.CreateCategory(request, iconTrash) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to create category: "+err.Error()) - } - - return utils.CreateResponse(c, categoryResponse, "Category created successfully") -} - -func (h *TrashHandler) AddDetailToCategory(c *fiber.Ctx) error { - var request dto.RequestTrashDetailDTO - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - detailResponse, err := h.TrashService.AddDetailToCategory(request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to add detail to category: "+err.Error()) - } - - return utils.CreateResponse(c, detailResponse, "Trash detail added successfully") -} - -func (h *TrashHandler) GetCategories(c *fiber.Ctx) error { - - categories, err := h.TrashService.GetCategories() - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch categories: "+err.Error()) - } - - return utils.NonPaginatedResponse(c, categories, len(categories), "Categories retrieved successfully") -} - -func (h *TrashHandler) GetCategoryByID(c *fiber.Ctx) error { - id := c.Params("category_id") - - category, err := h.TrashService.GetCategoryByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, "Category not found: "+err.Error()) - } - - return utils.SuccessResponse(c, category, "Category retrieved successfully") -} - -func (h *TrashHandler) GetTrashDetailByID(c *fiber.Ctx) error { - id := c.Params("detail_id") - - detail, err := h.TrashService.GetTrashDetailByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, "Trash detail not found: "+err.Error()) - } - - return utils.SuccessResponse(c, detail, "Trash detail retrieved successfully") -} - -func (h *TrashHandler) UpdateCategory(c *fiber.Ctx) error { - id := c.Params("category_id") - - var request dto.RequestTrashCategoryDTO - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid request body"}}) - } - - iconTrash, err := c.FormFile("icon") - if err != nil && err.Error() != "File not found" { - log.Printf("Error retrieving icon trash from request: %v", err) - return utils.ErrorResponse(c, "icon trash is required") - } - - updatedCategory, err := h.TrashService.UpdateCategory(id, request, iconTrash) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error updating category: "+err.Error()) - } - - return utils.SuccessResponse(c, updatedCategory, "Category updated successfully") -} - -func (h *TrashHandler) UpdateDetail(c *fiber.Ctx) error { - id := c.Params("detail_id") - - var request dto.RequestTrashDetailDTO - if err := c.BodyParser(&request); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid request body"}}) - } - - updatedDetail, err := h.TrashService.UpdateDetail(id, request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error updating detail: "+err.Error()) - } - - return utils.SuccessResponse(c, updatedDetail, "Trash detail updated successfully") -} - -func (h *TrashHandler) DeleteCategory(c *fiber.Ctx) error { - id := c.Params("category_id") - - if err := h.TrashService.DeleteCategory(id); err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error deleting category: "+err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Category deleted successfully") -} - -func (h *TrashHandler) DeleteDetail(c *fiber.Ctx) error { - id := c.Params("detail_id") - - if err := h.TrashService.DeleteDetail(id); err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Error deleting detail: "+err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, "Trash detail deleted successfully") -} diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go deleted file mode 100644 index 9b60bec..0000000 --- a/internal/handler/user_handler.go +++ /dev/null @@ -1,101 +0,0 @@ -package handler - -import ( - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - "strconv" - - "github.com/gofiber/fiber/v2" -) - -type UserHandler struct { - userService services.UserService -} - -func NewUserHandler(userService services.UserService) *UserHandler { - return &UserHandler{userService: userService} -} - -func (h *UserHandler) UpdateUserAvatarHandler(c *fiber.Ctx) error { - - userID := c.Locals("userID").(string) - - avatar, err := c.FormFile("avatar") - if err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, "No avatar file provided") - } - - updatedUser, err := h.userService.UpdateUserAvatar(userID, avatar) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.SuccessResponse(c, updatedUser, "Avatar updated successfully") -} - -func (h *UserHandler) GetUserByIDHandler(c *fiber.Ctx) error { - // userID := c.Params("id") - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - user, err := h.userService.GetUserByID(userID) - if err != nil { - return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) - } - - return utils.SuccessResponse(c, user, "User retrieved successfully") -} - -func (h *UserHandler) GetAllUsersHandler(c *fiber.Ctx) error { - - page := 1 - limit := 10 - - if p := c.Query("page"); p != "" { - page, _ = strconv.Atoi(p) - } - - if l := c.Query("limit"); l != "" { - limit, _ = strconv.Atoi(l) - } - - users, err := h.userService.GetAllUsers(page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.PaginatedResponse(c, users, page, limit, len(users), "Users retrieved successfully") -} - -func (h *UserHandler) UpdateUserHandler(c *fiber.Ctx) error { - var request dto.RequestUserDTO - if err := c.BodyParser(&request); err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid request body") - } - - userID := c.Locals("userID").(string) - updatedUser, err := h.userService.UpdateUser(userID, &request) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.SuccessResponse(c, updatedUser, "User profile updated successfully") -} - -func (h *UserHandler) UpdateUserPasswordHandler(c *fiber.Ctx) error { - var request dto.UpdatePasswordDTO - if err := c.BodyParser(&request); err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid request body") - } - - userID := c.Locals("userID").(string) - err := h.userService.UpdateUserPassword(userID, request.OldPassword, request.NewPassword, request.ConfirmNewPassword) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Password updated successfully") -} diff --git a/internal/handler/userpin_handler.go b/internal/handler/userpin_handler.go deleted file mode 100644 index bb65b4b..0000000 --- a/internal/handler/userpin_handler.go +++ /dev/null @@ -1,102 +0,0 @@ -package handler - -import ( - "rijig/dto" - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type UserPinHandler struct { - UserPinService services.UserPinService -} - -func NewUserPinHandler(userPinService services.UserPinService) *UserPinHandler { - return &UserPinHandler{UserPinService: userPinService} -} - -func (h *UserPinHandler) VerifyUserPin(c *fiber.Ctx) error { - var requestUserPinDTO dto.RequestUserPinDTO - if err := c.BodyParser(&requestUserPinDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := requestUserPinDTO.Validate() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - message, err := h.UserPinService.VerifyUserPin(userID, requestUserPinDTO.Pin) - if err != nil { - return utils.GenericResponse(c, fiber.StatusUnauthorized, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, message) -} - -func (h *UserPinHandler) CheckPinStatus(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") - } - - status, err := h.UserPinService.CheckPinStatus(userID) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - if status == "Pin not created" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "Pin belum dibuat") - } - - return utils.GenericResponse(c, fiber.StatusOK, "Pin sudah dibuat") -} - -func (h *UserPinHandler) CreateUserPin(c *fiber.Ctx) error { - var requestUserPinDTO dto.RequestUserPinDTO - if err := c.BodyParser(&requestUserPinDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := requestUserPinDTO.Validate() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - userID := c.Locals("userID").(string) - - message, err := h.UserPinService.CreateUserPin(userID, requestUserPinDTO.Pin) - if err != nil { - - return utils.GenericResponse(c, fiber.StatusConflict, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusCreated, message) -} - -func (h *UserPinHandler) UpdateUserPin(c *fiber.Ctx) error { - var requestUserPinDTO dto.UpdateUserPinDTO - if err := c.BodyParser(&requestUserPinDTO); err != nil { - return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) - } - - errors, valid := requestUserPinDTO.Validate() - if !valid { - return utils.ValidationErrorResponse(c, errors) - } - - userID := c.Locals("userID").(string) - - message, err := h.UserPinService.UpdateUserPin(userID, requestUserPinDTO.OldPin, requestUserPinDTO.NewPin) - if err != nil { - return utils.GenericResponse(c, fiber.StatusBadRequest, err.Error()) - } - - return utils.GenericResponse(c, fiber.StatusOK, message) -} diff --git a/internal/handler/whatsapp_handler.go b/internal/handler/whatsapp_handler.go deleted file mode 100644 index e875f36..0000000 --- a/internal/handler/whatsapp_handler.go +++ /dev/null @@ -1,24 +0,0 @@ -package handler - -import ( - "log" - "rijig/config" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -func WhatsAppHandler(c *fiber.Ctx) error { - userID, ok := c.Locals("userID").(string) - if !ok || userID == "" { - return utils.ErrorResponse(c, "User is not logged in or invalid session") - } - - err := config.LogoutWhatsApp() - if err != nil { - log.Printf("Error during logout process for user %s: %v", userID, err) - return utils.ErrorResponse(c, err.Error()) - } - - return utils.SuccessResponse(c, nil, "Logged out successfully") -} diff --git a/internal/handler/wilayah_indonesia_handler.go b/internal/handler/wilayah_indonesia_handler.go deleted file mode 100644 index bde943a..0000000 --- a/internal/handler/wilayah_indonesia_handler.go +++ /dev/null @@ -1,200 +0,0 @@ -package handler - -import ( - "strconv" - - "rijig/internal/services" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -type WilayahIndonesiaHandler struct { - WilayahService services.WilayahIndonesiaService -} - -func NewWilayahImportHandler(wilayahService services.WilayahIndonesiaService) *WilayahIndonesiaHandler { - return &WilayahIndonesiaHandler{WilayahService: wilayahService} -} - -func (h *WilayahIndonesiaHandler) ImportWilayahData(c *fiber.Ctx) error { - - err := h.WilayahService.ImportDataFromCSV() - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.SuccessResponse(c, fiber.StatusCreated, "Data imported successfully") -} - -func (h *WilayahIndonesiaHandler) GetProvinces(c *fiber.Ctx) error { - - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - provinces, totalProvinces, err := h.WilayahService.GetAllProvinces(page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch provinces") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, provinces, page, limit, totalProvinces, "Provinces fetched successfully") - } - - return utils.NonPaginatedResponse(c, provinces, totalProvinces, "Provinces fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetProvinceByID(c *fiber.Ctx) error { - provinceID := c.Params("provinceid") - - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - province, totalRegencies, err := h.WilayahService.GetProvinceByID(provinceID, page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch province") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, province, page, limit, totalRegencies, "Province fetched successfully") - } - - return utils.NonPaginatedResponse(c, province, totalRegencies, "Province fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetAllRegencies(c *fiber.Ctx) error { - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - regencies, totalRegencies, err := h.WilayahService.GetAllRegencies(page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch regency") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, regencies, page, limit, totalRegencies, "regency fetched successfully") - } - - return utils.NonPaginatedResponse(c, regencies, totalRegencies, "Provinces fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetRegencyByID(c *fiber.Ctx) error { - regencyId := c.Params("regencyid") - - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - regency, totalDistrict, err := h.WilayahService.GetRegencyByID(regencyId, page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch regency") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, regency, page, limit, totalDistrict, "regency fetched successfully") - } - - return utils.NonPaginatedResponse(c, regency, totalDistrict, "regency fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetAllDistricts(c *fiber.Ctx) error { - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - districts, totalDistricts, err := h.WilayahService.GetAllDistricts(page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch districts") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, districts, page, limit, totalDistricts, "districts fetched successfully") - } - - return utils.NonPaginatedResponse(c, districts, totalDistricts, "districts fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetDistrictByID(c *fiber.Ctx) error { - districtId := c.Params("districtid") - - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - district, totalVillages, err := h.WilayahService.GetDistrictByID(districtId, page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch district") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, district, page, limit, totalVillages, "district fetched successfully") - } - - return utils.NonPaginatedResponse(c, district, totalVillages, "district fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetAllVillages(c *fiber.Ctx) error { - page, err := strconv.Atoi(c.Query("page", "0")) - if err != nil { - page = 0 - } - limit, err := strconv.Atoi(c.Query("limit", "0")) - if err != nil { - limit = 0 - } - - villages, totalVillages, err := h.WilayahService.GetAllVillages(page, limit) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, "Failed to fetch villages") - } - - if page > 0 && limit > 0 { - return utils.PaginatedResponse(c, villages, page, limit, totalVillages, "villages fetched successfully") - } - - return utils.NonPaginatedResponse(c, villages, totalVillages, "villages fetched successfully") -} - -func (h *WilayahIndonesiaHandler) GetVillageByID(c *fiber.Ctx) error { - id := c.Params("villageid") - - village, err := h.WilayahService.GetVillageByID(id) - if err != nil { - return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) - } - - return utils.SuccessResponse(c, village, "Village fetched successfully") -} diff --git a/internal/repositories/about_repo.go b/internal/repositories/about_repo.go deleted file mode 100644 index 29224f5..0000000 --- a/internal/repositories/about_repo.go +++ /dev/null @@ -1,112 +0,0 @@ -package repositories - -import ( - "fmt" - "rijig/model" - - "gorm.io/gorm" -) - -type AboutRepository interface { - CreateAbout(about *model.About) error - CreateAboutDetail(aboutDetail *model.AboutDetail) error - GetAllAbout() ([]model.About, error) - GetAboutByID(id string) (*model.About, error) - GetAboutByIDWithoutPrel(id string) (*model.About, error) - GetAboutDetailByID(id string) (*model.AboutDetail, error) - UpdateAbout(id string, about *model.About) (*model.About, error) - UpdateAboutDetail(id string, aboutDetail *model.AboutDetail) (*model.AboutDetail, error) - DeleteAbout(id string) error - DeleteAboutDetail(id string) error -} - -type aboutRepository struct { - DB *gorm.DB -} - -func NewAboutRepository(db *gorm.DB) AboutRepository { - return &aboutRepository{DB: db} -} - -func (r *aboutRepository) CreateAbout(about *model.About) error { - if err := r.DB.Create(&about).Error; err != nil { - return fmt.Errorf("failed to create About: %v", err) - } - return nil -} - -func (r *aboutRepository) CreateAboutDetail(aboutDetail *model.AboutDetail) error { - if err := r.DB.Create(&aboutDetail).Error; err != nil { - return fmt.Errorf("failed to create AboutDetail: %v", err) - } - return nil -} - -func (r *aboutRepository) GetAllAbout() ([]model.About, error) { - var abouts []model.About - if err := r.DB.Find(&abouts).Error; err != nil { - return nil, fmt.Errorf("failed to fetch all About records: %v", err) - } - return abouts, nil -} - -func (r *aboutRepository) GetAboutByID(id string) (*model.About, error) { - var about model.About - if err := r.DB.Preload("AboutDetail").Where("id = ?", id).First(&about).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("about with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch About by ID: %v", err) - } - return &about, nil -} - -func (r *aboutRepository) GetAboutByIDWithoutPrel(id string) (*model.About, error) { - var about model.About - if err := r.DB.Where("id = ?", id).First(&about).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("about with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch About by ID: %v", err) - } - return &about, nil -} - -func (r *aboutRepository) GetAboutDetailByID(id string) (*model.AboutDetail, error) { - var aboutDetail model.AboutDetail - if err := r.DB.Where("id = ?", id).First(&aboutDetail).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("aboutdetail with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch About by ID: %v", err) - } - return &aboutDetail, nil -} - -func (r *aboutRepository) UpdateAbout(id string, about *model.About) (*model.About, error) { - if err := r.DB.Model(&about).Where("id = ?", id).Updates(about).Error; err != nil { - return nil, fmt.Errorf("failed to update About: %v", err) - } - return about, nil -} - -func (r *aboutRepository) UpdateAboutDetail(id string, aboutDetail *model.AboutDetail) (*model.AboutDetail, error) { - if err := r.DB.Model(&aboutDetail).Where("id = ?", id).Updates(aboutDetail).Error; err != nil { - return nil, fmt.Errorf("failed to update AboutDetail: %v", err) - } - return aboutDetail, nil -} - -func (r *aboutRepository) DeleteAbout(id string) error { - if err := r.DB.Where("id = ?", id).Delete(&model.About{}).Error; err != nil { - return fmt.Errorf("failed to delete About: %v", err) - } - return nil -} - -func (r *aboutRepository) DeleteAboutDetail(id string) error { - if err := r.DB.Where("id = ?", id).Delete(&model.AboutDetail{}).Error; err != nil { - return fmt.Errorf("failed to delete AboutDetail: %v", err) - } - return nil -} diff --git a/internal/repositories/address_repo.go b/internal/repositories/address_repo.go deleted file mode 100644 index d8c2cf5..0000000 --- a/internal/repositories/address_repo.go +++ /dev/null @@ -1,61 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type AddressRepository interface { - CreateAddress(address *model.Address) error - FindAddressByUserID(userID string) ([]model.Address, error) - FindAddressByID(id string) (*model.Address, error) - UpdateAddress(address *model.Address) error - DeleteAddress(id string) error -} - -type addressRepository struct { - DB *gorm.DB -} - -func NewAddressRepository(db *gorm.DB) AddressRepository { - return &addressRepository{DB: db} -} - -func (r *addressRepository) CreateAddress(address *model.Address) error { - return r.DB.Create(address).Error -} - -func (r *addressRepository) FindAddressByUserID(userID string) ([]model.Address, error) { - var addresses []model.Address - err := r.DB.Where("user_id = ?", userID).Find(&addresses).Error - if err != nil { - return nil, err - } - return addresses, nil -} - -func (r *addressRepository) FindAddressByID(id string) (*model.Address, error) { - var address model.Address - err := r.DB.Where("id = ?", id).First(&address).Error - if err != nil { - return nil, err - } - return &address, nil -} - -func (r *addressRepository) UpdateAddress(address *model.Address) error { - err := r.DB.Save(address).Error - if err != nil { - return err - } - return nil -} - -func (r *addressRepository) DeleteAddress(id string) error { - err := r.DB.Where("id = ?", id).Delete(&model.Address{}).Error - if err != nil { - return err - } - return nil -} diff --git a/internal/repositories/article_repo.go b/internal/repositories/article_repo.go deleted file mode 100644 index d9a1222..0000000 --- a/internal/repositories/article_repo.go +++ /dev/null @@ -1,75 +0,0 @@ -package repositories - -import ( - "fmt" - - "rijig/model" - - "gorm.io/gorm" -) - -type ArticleRepository interface { - CreateArticle(article *model.Article) error - FindArticleByID(id string) (*model.Article, error) - FindAllArticles(page, limit int) ([]model.Article, int, error) - UpdateArticle(id string, article *model.Article) error - DeleteArticle(id string) error -} - -type articleRepository struct { - DB *gorm.DB -} - -func NewArticleRepository(db *gorm.DB) ArticleRepository { - return &articleRepository{DB: db} -} - -func (r *articleRepository) CreateArticle(article *model.Article) error { - return r.DB.Create(article).Error -} - -func (r *articleRepository) FindArticleByID(id string) (*model.Article, error) { - var article model.Article - err := r.DB.Where("id = ?", id).First(&article).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("article with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch article: %v", err) - } - return &article, nil -} - -func (r *articleRepository) FindAllArticles(page, limit int) ([]model.Article, int, error) { - var articles []model.Article - var total int64 - - if err := r.DB.Model(&model.Article{}).Count(&total).Error; err != nil { - return nil, 0, fmt.Errorf("failed to count articles: %v", err) - } - - fmt.Printf("Total Articles Count: %d\n", total) - - if page > 0 && limit > 0 { - err := r.DB.Offset((page - 1) * limit).Limit(limit).Find(&articles).Error - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch articles: %v", err) - } - } else { - err := r.DB.Find(&articles).Error - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch articles: %v", err) - } - } - - return articles, int(total), nil -} - -func (r *articleRepository) UpdateArticle(id string, article *model.Article) error { - return r.DB.Model(&model.Article{}).Where("id = ?", id).Updates(article).Error -} - -func (r *articleRepository) DeleteArticle(id string) error { - result := r.DB.Delete(&model.Article{}, "id = ?", id) - return result.Error -} diff --git a/internal/repositories/auth/auth_admin_repo.go b/internal/repositories/auth/auth_admin_repo.go deleted file mode 100644 index 4652e1d..0000000 --- a/internal/repositories/auth/auth_admin_repo.go +++ /dev/null @@ -1,93 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type AuthAdminRepository interface { - FindByEmail(email string) (*model.User, error) - FindAdminByEmailandRoleid(email, roleId string) (*model.User, error) - FindAdminByPhoneandRoleid(phone, roleId string) (*model.User, error) - FindByPhone(phone string) (*model.User, error) - FindByEmailOrPhone(identifier string) (*model.User, error) - FindRoleByName(roleName string) (*model.Role, error) - CreateUser(user *model.User) (*model.User, error) -} - -type authAdminRepository struct { - DB *gorm.DB -} - -func NewAuthAdminRepository(db *gorm.DB) AuthAdminRepository { - return &authAdminRepository{DB: db} -} - -func (r *authAdminRepository) FindByEmail(email string) (*model.User, error) { - var user model.User - err := r.DB.Preload("Role").Where("email = ?", email).First(&user).Error - if err != nil { - return nil, err - } - return &user, nil -} - -func (r *authAdminRepository) FindAdminByEmailandRoleid(email, roleId string) (*model.User, error) { - var user model.User - err := r.DB.Where("email = ? AND role_id = ?", email, roleId).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &user, nil -} - -func (r *authAdminRepository) FindAdminByPhoneandRoleid(phone, roleId string) (*model.User, error) { - var user model.User - err := r.DB.Where("phone = ? AND role_id = ?", phone, roleId).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &user, nil -} - -func (r *authAdminRepository) FindByPhone(phone string) (*model.User, error) { - var user model.User - err := r.DB.Where("phone = ?", phone).First(&user).Error - if err != nil { - return nil, err - } - return &user, nil -} - -func (r *authAdminRepository) FindByEmailOrPhone(identifier string) (*model.User, error) { - var user model.User - err := r.DB.Where("email = ? OR phone = ?", identifier, identifier).First(&user).Error - if err != nil { - return nil, err - } - return &user, nil -} - -func (r *authAdminRepository) CreateUser(user *model.User) (*model.User, error) { - err := r.DB.Create(user).Error - if err != nil { - return nil, err - } - return user, nil -} - -func (r *authAdminRepository) FindRoleByName(roleName string) (*model.Role, error) { - var role model.Role - err := r.DB.Where("role_name = ?", roleName).First(&role).Error - if err != nil { - return nil, err - } - return &role, nil -} diff --git a/internal/repositories/auth/auth_masyarakat_repo.go b/internal/repositories/auth/auth_masyarakat_repo.go deleted file mode 100644 index f49bfd0..0000000 --- a/internal/repositories/auth/auth_masyarakat_repo.go +++ /dev/null @@ -1,48 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type AuthMasyarakatRepository interface { - CreateUser(user *model.User) (*model.User, error) - GetUserByPhone(phone string) (*model.User, error) - GetUserByPhoneAndRole(phone string, roleId string) (*model.User, error) -} - -type authMasyarakatRepository struct { - db *gorm.DB -} - -func NewAuthMasyarakatRepositories(db *gorm.DB) AuthMasyarakatRepository { - return &authMasyarakatRepository{db} -} - -func (r *authMasyarakatRepository) CreateUser(user *model.User) (*model.User, error) { - if err := r.db.Create(user).Error; err != nil { - return nil, err - } - return user, nil -} - -func (r *authMasyarakatRepository) GetUserByPhone(phone string) (*model.User, error) { - var user model.User - if err := r.db.Where("phone = ?", phone).First(&user).Error; err != nil { - return nil, err - } - return &user, nil -} - -func (r *authMasyarakatRepository) GetUserByPhoneAndRole(phone string, roleId string) (*model.User, error) { - var user model.User - err := r.db.Where("phone = ? AND role_id = ?", phone, roleId).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &user, nil -} diff --git a/internal/repositories/auth/auth_pengelola_repo.go b/internal/repositories/auth/auth_pengelola_repo.go deleted file mode 100644 index f7b561a..0000000 --- a/internal/repositories/auth/auth_pengelola_repo.go +++ /dev/null @@ -1,48 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type AuthPengelolaRepository interface { - CreateUser(user *model.User) (*model.User, error) - GetUserByPhone(phone string) (*model.User, error) - GetUserByPhoneAndRole(phone string, roleId string) (*model.User, error) -} - -type authPengelolaRepository struct { - db *gorm.DB -} - -func NewAuthPengelolaRepositories(db *gorm.DB) AuthPengelolaRepository { - return &authPengelolaRepository{db} -} - -func (r *authPengelolaRepository) CreateUser(user *model.User) (*model.User, error) { - if err := r.db.Create(user).Error; err != nil { - return nil, err - } - return user, nil -} - -func (r *authPengelolaRepository) GetUserByPhone(phone string) (*model.User, error) { - var user model.User - if err := r.db.Where("phone = ?", phone).First(&user).Error; err != nil { - return nil, err - } - return &user, nil -} - -func (r *authPengelolaRepository) GetUserByPhoneAndRole(phone string, roleId string) (*model.User, error) { - var user model.User - err := r.db.Where("phone = ? AND role_id = ?", phone, roleId).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &user, nil -} diff --git a/internal/repositories/auth/auth_pengepul_repo.go b/internal/repositories/auth/auth_pengepul_repo.go deleted file mode 100644 index 5253ee1..0000000 --- a/internal/repositories/auth/auth_pengepul_repo.go +++ /dev/null @@ -1,48 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type AuthPengepulRepository interface { - CreateUser(user *model.User) (*model.User, error) - GetUserByPhone(phone string) (*model.User, error) - GetUserByPhoneAndRole(phone string, roleId string) (*model.User, error) -} - -type authPengepulRepository struct { - db *gorm.DB -} - -func NewAuthPengepulRepositories(db *gorm.DB) AuthPengepulRepository { - return &authPengepulRepository{db} -} - -func (r *authPengepulRepository) CreateUser(user *model.User) (*model.User, error) { - if err := r.db.Create(user).Error; err != nil { - return nil, err - } - return user, nil -} - -func (r *authPengepulRepository) GetUserByPhone(phone string) (*model.User, error) { - var user model.User - if err := r.db.Where("phone = ?", phone).First(&user).Error; err != nil { - return nil, err - } - return &user, nil -} - -func (r *authPengepulRepository) GetUserByPhoneAndRole(phone string, roleId string) (*model.User, error) { - var user model.User - err := r.db.Where("phone = ? AND role_id = ?", phone, roleId).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &user, nil -} diff --git a/internal/repositories/auth_repo.go b/internal/repositories/auth_repo.go deleted file mode 100644 index a9466ca..0000000 --- a/internal/repositories/auth_repo.go +++ /dev/null @@ -1,48 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type UserRepository interface { - CreateUser(user *model.User) (*model.User, error) - GetUserByPhone(phone string) (*model.User, error) - GetUserByPhoneAndRole(phone string, roleID string) (*model.User, error) -} - -type userRepository struct { - db *gorm.DB -} - -func NewUserRepository(db *gorm.DB) UserRepository { - return &userRepository{db} -} - -func (r *userRepository) CreateUser(user *model.User) (*model.User, error) { - if err := r.db.Create(user).Error; err != nil { - return nil, err - } - return user, nil -} - -func (r *userRepository) GetUserByPhone(phone string) (*model.User, error) { - var user model.User - if err := r.db.Where("phone = ?", phone).First(&user).Error; err != nil { - return nil, err - } - return &user, nil -} - -func (r *userRepository) GetUserByPhoneAndRole(phone string, roleID string) (*model.User, error) { - var user model.User - err := r.db.Where("phone = ? AND role_id = ?", phone, roleID).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &user, nil -} diff --git a/internal/repositories/banner_repo.go b/internal/repositories/banner_repo.go deleted file mode 100644 index 41803de..0000000 --- a/internal/repositories/banner_repo.go +++ /dev/null @@ -1,70 +0,0 @@ -package repositories - -import ( - "fmt" - - "rijig/model" - - "gorm.io/gorm" -) - -type BannerRepository interface { - CreateBanner(banner *model.Banner) error - FindBannerByID(id string) (*model.Banner, error) - FindAllBanners() ([]model.Banner, error) - UpdateBanner(id string, banner *model.Banner) error - DeleteBanner(id string) error -} - -type bannerRepository struct { - DB *gorm.DB -} - -func NewBannerRepository(db *gorm.DB) BannerRepository { - return &bannerRepository{DB: db} -} - -func (r *bannerRepository) CreateBanner(banner *model.Banner) error { - if err := r.DB.Create(banner).Error; err != nil { - return fmt.Errorf("failed to create banner: %v", err) - } - return nil -} - -func (r *bannerRepository) FindBannerByID(id string) (*model.Banner, error) { - var banner model.Banner - err := r.DB.Where("id = ?", id).First(&banner).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("banner with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch banner by ID: %v", err) - } - return &banner, nil -} - -func (r *bannerRepository) FindAllBanners() ([]model.Banner, error) { - var banners []model.Banner - err := r.DB.Find(&banners).Error - if err != nil { - return nil, fmt.Errorf("failed to fetch banners: %v", err) - } - - return banners, nil -} - -func (r *bannerRepository) UpdateBanner(id string, banner *model.Banner) error { - err := r.DB.Model(&model.Banner{}).Where("id = ?", id).Updates(banner).Error - if err != nil { - return fmt.Errorf("failed to update banner: %v", err) - } - return nil -} - -func (r *bannerRepository) DeleteBanner(id string) error { - result := r.DB.Delete(&model.Banner{}, "id = ?", id) - if result.Error != nil { - return fmt.Errorf("failed to delete banner: %v", result.Error) - } - return nil -} diff --git a/internal/repositories/collector_repo.go b/internal/repositories/collector_repo.go deleted file mode 100644 index 7cfc218..0000000 --- a/internal/repositories/collector_repo.go +++ /dev/null @@ -1,135 +0,0 @@ -package repositories - -import ( - "context" - "errors" - - "rijig/config" - "rijig/model" -) - -type CollectorRepository interface { - CreateCollector(ctx context.Context, collector *model.Collector) error - AddAvaibleTrash(ctx context.Context, trashItems []model.AvaibleTrashByCollector) error - GetCollectorByID(ctx context.Context, collectorID string) (*model.Collector, error) - GetCollectorByUserID(ctx context.Context, userID string) (*model.Collector, error) - GetTrashItemByID(ctx context.Context, id string) (*model.AvaibleTrashByCollector, error) - UpdateCollector(ctx context.Context, collector *model.Collector, updates map[string]interface{}) error - UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []model.AvaibleTrashByCollector) error - DeleteAvaibleTrash(ctx context.Context, trashID string) error - - GetActiveCollectorsWithTrashAndAddress(ctx context.Context) ([]model.Collector, error) - GetCollectorWithAddressAndTrash(ctx context.Context, collectorID string) (*model.Collector, error) -} - -type collectorRepository struct { -} - -func NewCollectorRepository() CollectorRepository { - return &collectorRepository{} -} - -func (r *collectorRepository) CreateCollector(ctx context.Context, collector *model.Collector) error { - return config.DB.WithContext(ctx).Create(collector).Error -} - -func (r *collectorRepository) AddAvaibleTrash(ctx context.Context, trashItems []model.AvaibleTrashByCollector) error { - if len(trashItems) == 0 { - return nil - } - return config.DB.WithContext(ctx).Create(&trashItems).Error -} - -func (r *collectorRepository) GetCollectorByID(ctx context.Context, collectorID string) (*model.Collector, error) { - var collector model.Collector - err := config.DB.WithContext(ctx). - Preload("User"). - Preload("Address"). - Preload("AvaibleTrashByCollector.TrashCategory"). - First(&collector, "id = ?", collectorID).Error - - if err != nil { - return nil, err - } - return &collector, nil -} - -func (r *collectorRepository) GetCollectorByUserID(ctx context.Context, userID string) (*model.Collector, error) { - var collector model.Collector - err := config.DB.WithContext(ctx). - Preload("User"). - Preload("Address"). - Preload("AvaibleTrashByCollector.TrashCategory"). - First(&collector, "user_id = ?", userID).Error - - if err != nil { - return nil, err - } - return &collector, nil -} - -func (r *collectorRepository) GetTrashItemByID(ctx context.Context, id string) (*model.AvaibleTrashByCollector, error) { - var item model.AvaibleTrashByCollector - if err := config.DB.WithContext(ctx).First(&item, "id = ?", id).Error; err != nil { - return nil, err - } - return &item, nil -} - -func (r *collectorRepository) UpdateCollector(ctx context.Context, collector *model.Collector, updates map[string]interface{}) error { - return config.DB.WithContext(ctx). - Model(&model.Collector{}). - Where("id = ?", collector.ID). - Updates(updates).Error -} - -func (r *collectorRepository) UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []model.AvaibleTrashByCollector) error { - for _, trash := range updatedTrash { - err := config.DB.WithContext(ctx). - Model(&model.AvaibleTrashByCollector{}). - Where("collector_id = ? AND trash_category_id = ?", collectorID, trash.TrashCategoryID). - Update("price", trash.Price).Error - if err != nil { - return err - } - } - return nil -} - -func (r *collectorRepository) DeleteAvaibleTrash(ctx context.Context, trashID string) error { - if trashID == "" { - return errors.New("trash_id cannot be empty") - } - return config.DB.WithContext(ctx). - Delete(&model.AvaibleTrashByCollector{}, "id = ?", trashID).Error -} - -func (r *collectorRepository) GetActiveCollectorsWithTrashAndAddress(ctx context.Context) ([]model.Collector, error) { - var collectors []model.Collector - err := config.DB.WithContext(ctx). - Preload("User"). - Preload("Address"). - Preload("AvaibleTrashbyCollector.TrashCategory"). - Where("job_status = ?", "active"). - Find(&collectors).Error - - if err != nil { - return nil, err - } - - return collectors, nil -} - -func (r *collectorRepository) GetCollectorWithAddressAndTrash(ctx context.Context, collectorID string) (*model.Collector, error) { - var collector model.Collector - err := config.DB.WithContext(ctx). - Preload("Address"). - Preload("AvaibleTrashbyCollector"). - Where("id = ?", collectorID). - First(&collector).Error - - if err != nil { - return nil, err - } - return &collector, nil -} diff --git a/internal/repositories/company_profile_repo.go b/internal/repositories/company_profile_repo.go deleted file mode 100644 index bf0d4ea..0000000 --- a/internal/repositories/company_profile_repo.go +++ /dev/null @@ -1,78 +0,0 @@ -package repositories - -import ( - "fmt" - "rijig/model" - - "gorm.io/gorm" -) - -type CompanyProfileRepository interface { - CreateCompanyProfile(companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) - GetCompanyProfileByID(id string) (*model.CompanyProfile, error) - GetCompanyProfilesByUserID(userID string) ([]model.CompanyProfile, error) - UpdateCompanyProfile(id string, companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) - DeleteCompanyProfile(id string) error -} - -type companyProfileRepository struct { - DB *gorm.DB -} - -func NewCompanyProfileRepository(db *gorm.DB) CompanyProfileRepository { - return &companyProfileRepository{ - DB: db, - } -} - -func (r *companyProfileRepository) CreateCompanyProfile(companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) { - err := r.DB.Create(companyProfile).Error - if err != nil { - return nil, fmt.Errorf("failed to create company profile: %v", err) - } - return companyProfile, nil -} - -func (r *companyProfileRepository) GetCompanyProfileByID(id string) (*model.CompanyProfile, error) { - var companyProfile model.CompanyProfile - err := r.DB.Preload("User").First(&companyProfile, "id = ?", id).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("company profile with ID %s not found", id) - } - return nil, fmt.Errorf("error fetching company profile: %v", err) - } - return &companyProfile, nil -} - -func (r *companyProfileRepository) GetCompanyProfilesByUserID(userID string) ([]model.CompanyProfile, error) { - var companyProfiles []model.CompanyProfile - err := r.DB.Preload("User").Where("user_id = ?", userID).Find(&companyProfiles).Error - if err != nil { - return nil, fmt.Errorf("error fetching company profiles for userID %s: %v", userID, err) - } - return companyProfiles, nil -} - -func (r *companyProfileRepository) UpdateCompanyProfile(id string, companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) { - var existingProfile model.CompanyProfile - err := r.DB.First(&existingProfile, "id = ?", id).Error - if err != nil { - return nil, fmt.Errorf("company profile not found: %v", err) - } - - err = r.DB.Model(&existingProfile).Updates(companyProfile).Error - if err != nil { - return nil, fmt.Errorf("failed to update company profile: %v", err) - } - - return &existingProfile, nil -} - -func (r *companyProfileRepository) DeleteCompanyProfile(id string) error { - err := r.DB.Delete(&model.CompanyProfile{}, "id = ?", id).Error - if err != nil { - return fmt.Errorf("failed to delete company profile: %v", err) - } - return nil -} diff --git a/internal/repositories/coveragearea_repo.go b/internal/repositories/coveragearea_repo.go deleted file mode 100644 index 02674a9..0000000 --- a/internal/repositories/coveragearea_repo.go +++ /dev/null @@ -1,82 +0,0 @@ -package repositories - -import ( - "fmt" - "rijig/model" - - "gorm.io/gorm" -) - -type CoverageAreaRepository interface { - FindCoverageByProvinceAndRegency(province, regency string) (*model.CoverageArea, error) - CreateCoverage(coverage *model.CoverageArea) error - FindCoverageById(id string) (*model.CoverageArea, error) - FindAllCoverage() ([]model.CoverageArea, error) - UpdateCoverage(id string, coverage *model.CoverageArea) error - DeleteCoverage(id string) error -} - -type coverageAreaRepository struct { - DB *gorm.DB -} - -func NewCoverageAreaRepository(db *gorm.DB) CoverageAreaRepository { - return &coverageAreaRepository{DB: db} -} - -func (r *coverageAreaRepository) FindCoverageByProvinceAndRegency(province, regency string) (*model.CoverageArea, error) { - var coverage model.CoverageArea - err := r.DB.Where("province = ? AND regency = ?", province, regency).First(&coverage).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &coverage, nil -} - -func (r *coverageAreaRepository) CreateCoverage(coverage *model.CoverageArea) error { - if err := r.DB.Create(coverage).Error; err != nil { - return fmt.Errorf("failed to create coverage: %v", err) - } - return nil -} - -func (r *coverageAreaRepository) FindCoverageById(id string) (*model.CoverageArea, error) { - var coverage model.CoverageArea - err := r.DB.Where("id = ?", id).First(&coverage).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("coverage with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch coverage by ID: %v", err) - } - return &coverage, nil -} - -func (r *coverageAreaRepository) FindAllCoverage() ([]model.CoverageArea, error) { - var coverage []model.CoverageArea - err := r.DB.Find(&coverage).Error - if err != nil { - return nil, fmt.Errorf("failed to fetch coverage: %v", err) - } - - return coverage, nil -} - -func (r *coverageAreaRepository) UpdateCoverage(id string, coverage *model.CoverageArea) error { - err := r.DB.Model(&model.CoverageArea{}).Where("id = ?", id).Updates(coverage).Error - if err != nil { - return fmt.Errorf("failed to update coverage: %v", err) - } - return nil -} - -func (r *coverageAreaRepository) DeleteCoverage(id string) error { - result := r.DB.Delete(&model.CoverageArea{}, "id = ?", id) - if result.Error != nil { - return fmt.Errorf("failed to delete coverage: %v", result.Error) - } - return nil -} diff --git a/internal/repositories/identitycard_repo.go b/internal/repositories/identitycard_repo.go deleted file mode 100644 index 763791a..0000000 --- a/internal/repositories/identitycard_repo.go +++ /dev/null @@ -1,82 +0,0 @@ -package repositories - -import ( - "errors" - "fmt" - "log" - "rijig/model" - - "gorm.io/gorm" -) - -type IdentityCardRepository interface { - CreateIdentityCard(identityCard *model.IdentityCard) (*model.IdentityCard, error) - GetIdentityCardByID(id string) (*model.IdentityCard, error) - GetIdentityCardsByUserID(userID string) ([]model.IdentityCard, error) - UpdateIdentityCard(id string, updatedCard *model.IdentityCard) (*model.IdentityCard, error) - DeleteIdentityCard(id string) error -} - -type identityCardRepository struct { - db *gorm.DB -} - -func NewIdentityCardRepository(db *gorm.DB) IdentityCardRepository { - return &identityCardRepository{ - db: db, - } -} - -func (r *identityCardRepository) CreateIdentityCard(identityCard *model.IdentityCard) (*model.IdentityCard, error) { - if err := r.db.Create(identityCard).Error; err != nil { - log.Printf("Error creating identity card: %v", err) - return nil, fmt.Errorf("failed to create identity card: %w", err) - } - return identityCard, nil -} - -func (r *identityCardRepository) GetIdentityCardByID(id string) (*model.IdentityCard, error) { - var identityCard model.IdentityCard - if err := r.db.Where("id = ?", id).First(&identityCard).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("identity card not found with id %s", id) - } - log.Printf("Error fetching identity card by ID: %v", err) - return nil, fmt.Errorf("error fetching identity card by ID: %w", err) - } - return &identityCard, nil -} - -func (r *identityCardRepository) GetIdentityCardsByUserID(userID string) ([]model.IdentityCard, error) { - var identityCards []model.IdentityCard - if err := r.db.Where("user_id = ?", userID).Find(&identityCards).Error; err != nil { - log.Printf("Error fetching identity cards by userID: %v", err) - return nil, fmt.Errorf("error fetching identity cards by userID: %w", err) - } - return identityCards, nil -} - -func (r *identityCardRepository) UpdateIdentityCard(id string, updatedCard *model.IdentityCard) (*model.IdentityCard, error) { - var existingCard model.IdentityCard - if err := r.db.Where("id = ?", id).First(&existingCard).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("identity card with ID %s not found", id) - } - log.Printf("Error fetching identity card for update: %v", err) - return nil, fmt.Errorf("error fetching identity card for update: %w", err) - } - - if err := r.db.Save(&existingCard).Error; err != nil { - log.Printf("Error updating identity card: %v", err) - return nil, fmt.Errorf("failed to update identity card: %w", err) - } - return &existingCard, nil -} - -func (r *identityCardRepository) DeleteIdentityCard(id string) error { - if err := r.db.Where("id = ?", id).Delete(&model.IdentityCard{}).Error; err != nil { - log.Printf("Error deleting identity card: %v", err) - return fmt.Errorf("failed to delete identity card: %w", err) - } - return nil -} diff --git a/internal/repositories/initialcoint_repo.go b/internal/repositories/initialcoint_repo.go deleted file mode 100644 index ec03479..0000000 --- a/internal/repositories/initialcoint_repo.go +++ /dev/null @@ -1,68 +0,0 @@ -package repositories - -import ( - "fmt" - "rijig/model" - - "gorm.io/gorm" -) - -type InitialCointRepository interface { - CreateInitialCoint(coint *model.InitialCoint) error - FindInitialCointByID(id string) (*model.InitialCoint, error) - FindAllInitialCoints() ([]model.InitialCoint, error) - UpdateInitialCoint(id string, coint *model.InitialCoint) error - DeleteInitialCoint(id string) error -} - -type initialCointRepository struct { - DB *gorm.DB -} - -func NewInitialCointRepository(db *gorm.DB) InitialCointRepository { - return &initialCointRepository{DB: db} -} - -func (r *initialCointRepository) CreateInitialCoint(coint *model.InitialCoint) error { - if err := r.DB.Create(coint).Error; err != nil { - return fmt.Errorf("failed to create initial coint: %v", err) - } - return nil -} - -func (r *initialCointRepository) FindInitialCointByID(id string) (*model.InitialCoint, error) { - var coint model.InitialCoint - err := r.DB.Where("id = ?", id).First(&coint).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("initial coint with ID %s not found", id) - } - return nil, fmt.Errorf("failed to fetch initial coint by ID: %v", err) - } - return &coint, nil -} - -func (r *initialCointRepository) FindAllInitialCoints() ([]model.InitialCoint, error) { - var coints []model.InitialCoint - err := r.DB.Find(&coints).Error - if err != nil { - return nil, fmt.Errorf("failed to fetch initial coints: %v", err) - } - return coints, nil -} - -func (r *initialCointRepository) UpdateInitialCoint(id string, coint *model.InitialCoint) error { - err := r.DB.Model(&model.InitialCoint{}).Where("id = ?", id).Updates(coint).Error - if err != nil { - return fmt.Errorf("failed to update initial coint: %v", err) - } - return nil -} - -func (r *initialCointRepository) DeleteInitialCoint(id string) error { - result := r.DB.Delete(&model.InitialCoint{}, "id = ?", id) - if result.Error != nil { - return fmt.Errorf("failed to delete initial coint: %v", result.Error) - } - return nil -} diff --git a/internal/repositories/pickup_history_repo.go b/internal/repositories/pickup_history_repo.go deleted file mode 100644 index 536ecf7..0000000 --- a/internal/repositories/pickup_history_repo.go +++ /dev/null @@ -1,34 +0,0 @@ -package repositories - -import ( - "context" - "rijig/config" - "rijig/model" -) - -type PickupStatusHistoryRepository interface { - CreateStatusHistory(ctx context.Context, history model.PickupStatusHistory) error - GetStatusHistoryByRequestID(ctx context.Context, requestID string) ([]model.PickupStatusHistory, error) -} - -type pickupStatusHistoryRepository struct{} - -func NewPickupStatusHistoryRepository() PickupStatusHistoryRepository { - return &pickupStatusHistoryRepository{} -} - -func (r *pickupStatusHistoryRepository) CreateStatusHistory(ctx context.Context, history model.PickupStatusHistory) error { - return config.DB.WithContext(ctx).Create(&history).Error -} - -func (r *pickupStatusHistoryRepository) GetStatusHistoryByRequestID(ctx context.Context, requestID string) ([]model.PickupStatusHistory, error) { - var histories []model.PickupStatusHistory - err := config.DB.WithContext(ctx). - Where("request_id = ?", requestID). - Order("changed_at asc"). - Find(&histories).Error - if err != nil { - return nil, err - } - return histories, nil -} diff --git a/internal/repositories/product_repo.go b/internal/repositories/product_repo.go deleted file mode 100644 index 08f1b1f..0000000 --- a/internal/repositories/product_repo.go +++ /dev/null @@ -1,139 +0,0 @@ -package repositories - -import ( - "fmt" - - "rijig/model" - - "gorm.io/gorm" -) - -type ProductRepository interface { - CountProductsByStoreID(storeID string) (int64, error) - CreateProduct(product *model.Product) error - GetProductByID(productID string) (*model.Product, error) - GetProductsByStoreID(storeID string) ([]model.Product, error) - FindProductsByStoreID(storeID string, page, limit int) ([]model.Product, error) - FindProductImagesByProductID(productID string) ([]model.ProductImage, error) - GetProductImageByID(imageID string) (*model.ProductImage, error) - UpdateProduct(product *model.Product) error - DeleteProduct(productID string) error - DeleteProductsByID(productIDs []string) error - AddProductImages(images []model.ProductImage) error - DeleteProductImagesByProductID(productID string) error - DeleteProductImagesByID(imageIDs []string) error - DeleteProductImageByID(imageID string) error -} - -type productRepository struct { - DB *gorm.DB -} - -func NewProductRepository(DB *gorm.DB) ProductRepository { - return &productRepository{DB} -} - -func (r *productRepository) CreateProduct(product *model.Product) error { - return r.DB.Create(product).Error -} - -func (r *productRepository) CountProductsByStoreID(storeID string) (int64, error) { - var count int64 - if err := r.DB.Model(&model.Product{}).Where("store_id = ?", storeID).Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -func (r *productRepository) GetProductByID(productID string) (*model.Product, error) { - var product model.Product - if err := r.DB.Preload("ProductImages").Where("id = ?", productID).First(&product).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &product, nil -} - -func (r *productRepository) GetProductsByStoreID(storeID string) ([]model.Product, error) { - var products []model.Product - if err := r.DB.Where("store_id = ?", storeID).Preload("ProductImages").Find(&products).Error; err != nil { - return nil, err - } - return products, nil -} - -func (r *productRepository) FindProductsByStoreID(storeID string, page, limit int) ([]model.Product, error) { - var products []model.Product - offset := (page - 1) * limit - - if err := r.DB. - Where("store_id = ?", storeID). - Limit(limit). - Offset(offset). - Find(&products).Error; err != nil { - return nil, err - } - - return products, nil -} - -func (r *productRepository) FindProductImagesByProductID(productID string) ([]model.ProductImage, error) { - var productImages []model.ProductImage - if err := r.DB.Where("product_id = ?", productID).Find(&productImages).Error; err != nil { - return nil, err - } - return productImages, nil -} - -func (r *productRepository) GetProductImageByID(imageID string) (*model.ProductImage, error) { - var productImage model.ProductImage - if err := r.DB.Where("id = ?", imageID).First(&productImage).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &productImage, nil -} - -func (r *productRepository) UpdateProduct(product *model.Product) error { - return r.DB.Save(product).Error -} - -func (r *productRepository) DeleteProduct(productID string) error { - return r.DB.Delete(&model.Product{}, "id = ?", productID).Error -} - -func (r *productRepository) DeleteProductsByID(productIDs []string) error { - if err := r.DB.Where("id IN ?", productIDs).Delete(&model.Product{}).Error; err != nil { - return fmt.Errorf("failed to delete products: %v", err) - } - return nil -} - -func (r *productRepository) AddProductImages(images []model.ProductImage) error { - if len(images) == 0 { - return nil - } - return r.DB.Create(&images).Error -} - -func (r *productRepository) DeleteProductImagesByProductID(productID string) error { - return r.DB.Where("product_id = ?", productID).Delete(&model.ProductImage{}).Error -} - -func (r *productRepository) DeleteProductImagesByID(imageIDs []string) error { - if err := r.DB.Where("id IN ?", imageIDs).Delete(&model.ProductImage{}).Error; err != nil { - return fmt.Errorf("failed to delete product images: %v", err) - } - return nil -} - -func (r *productRepository) DeleteProductImageByID(imageID string) error { - if err := r.DB.Where("id = ?", imageID).Delete(&model.ProductImage{}).Error; err != nil { - return fmt.Errorf("failed to delete product image: %v", err) - } - return nil -} diff --git a/internal/repositories/rating_repo.go b/internal/repositories/rating_repo.go deleted file mode 100644 index b593cd8..0000000 --- a/internal/repositories/rating_repo.go +++ /dev/null @@ -1,48 +0,0 @@ -package repositories - -import ( - "context" - "rijig/config" - "rijig/model" -) - -type PickupRatingRepository interface { - CreateRating(ctx context.Context, rating model.PickupRating) error - GetRatingsByCollector(ctx context.Context, collectorID string) ([]model.PickupRating, error) - CalculateAverageRating(ctx context.Context, collectorID string) (float32, error) -} - -type pickupRatingRepository struct{} - -func NewPickupRatingRepository() PickupRatingRepository { - return &pickupRatingRepository{} -} - -func (r *pickupRatingRepository) CreateRating(ctx context.Context, rating model.PickupRating) error { - return config.DB.WithContext(ctx).Create(&rating).Error -} - -func (r *pickupRatingRepository) GetRatingsByCollector(ctx context.Context, collectorID string) ([]model.PickupRating, error) { - var ratings []model.PickupRating - err := config.DB.WithContext(ctx). - Where("collector_id = ?", collectorID). - Order("created_at desc"). - Find(&ratings).Error - if err != nil { - return nil, err - } - return ratings, nil -} - -func (r *pickupRatingRepository) CalculateAverageRating(ctx context.Context, collectorID string) (float32, error) { - var avg float32 - err := config.DB.WithContext(ctx). - Model(&model.PickupRating{}). - Select("AVG(rating)"). - Where("collector_id = ?", collectorID). - Scan(&avg).Error - if err != nil { - return 0, err - } - return avg, nil -} diff --git a/internal/repositories/request_pickup_repo.go b/internal/repositories/request_pickup_repo.go deleted file mode 100644 index 25f3225..0000000 --- a/internal/repositories/request_pickup_repo.go +++ /dev/null @@ -1,143 +0,0 @@ -package repositories - -import ( - "context" - "rijig/config" - "rijig/dto" - "rijig/model" - "time" -) - -type RequestPickupRepository interface { - CreateRequestPickup(ctx context.Context, pickup *model.RequestPickup) error - GetPickupWithItemsAndAddress(ctx context.Context, id string) (*model.RequestPickup, error) - GetAllAutomaticRequestsWithAddress(ctx context.Context) ([]model.RequestPickup, error) - UpdateCollectorID(ctx context.Context, pickupID, collectorID string) error - GetRequestsAssignedToCollector(ctx context.Context, collectorID string) ([]model.RequestPickup, error) - UpdatePickupStatusAndConfirmationTime(ctx context.Context, pickupID string, status string, confirmedAt time.Time) error - UpdatePickupStatus(ctx context.Context, pickupID string, status string) error - UpdateRequestPickupItemsAmountAndPrice(ctx context.Context, pickupID string, items []dto.UpdateRequestPickupItemDTO) error -} - -type requestPickupRepository struct{} - -func NewRequestPickupRepository() RequestPickupRepository { - return &requestPickupRepository{} -} - -func (r *requestPickupRepository) CreateRequestPickup(ctx context.Context, pickup *model.RequestPickup) error { - return config.DB.WithContext(ctx).Create(pickup).Error -} - -func (r *requestPickupRepository) GetPickupWithItemsAndAddress(ctx context.Context, id string) (*model.RequestPickup, error) { - var pickup model.RequestPickup - err := config.DB.WithContext(ctx). - Preload("RequestItems"). - Preload("Address"). - Where("id = ?", id). - First(&pickup).Error - - if err != nil { - return nil, err - } - return &pickup, nil -} - -func (r *requestPickupRepository) UpdateCollectorID(ctx context.Context, pickupID, collectorID string) error { - return config.DB.WithContext(ctx). - Model(&model.RequestPickup{}). - Where("id = ?", pickupID). - Update("collector_id", collectorID). - Error -} - -func (r *requestPickupRepository) GetAllAutomaticRequestsWithAddress(ctx context.Context) ([]model.RequestPickup, error) { - var pickups []model.RequestPickup - err := config.DB.WithContext(ctx). - Preload("RequestItems"). - Preload("Address"). - Where("request_method = ?", "otomatis"). - Find(&pickups).Error - - if err != nil { - return nil, err - } - return pickups, nil -} - -func (r *requestPickupRepository) GetRequestsAssignedToCollector(ctx context.Context, collectorID string) ([]model.RequestPickup, error) { - var pickups []model.RequestPickup - err := config.DB.WithContext(ctx). - Preload("User"). - Preload("Address"). - Preload("RequestItems"). - Where("collector_id = ? AND status_pickup = ?", collectorID, "waiting_collector"). - Find(&pickups).Error - - if err != nil { - return nil, err - } - return pickups, nil -} - -func (r *requestPickupRepository) UpdatePickupStatusAndConfirmationTime(ctx context.Context, pickupID string, status string, confirmedAt time.Time) error { - return config.DB.WithContext(ctx). - Model(&model.RequestPickup{}). - Where("id = ?", pickupID). - Updates(map[string]interface{}{ - "status_pickup": status, - "confirmed_by_collector_at": confirmedAt, - }).Error -} - -func (r *requestPickupRepository) UpdatePickupStatus(ctx context.Context, pickupID string, status string) error { - return config.DB.WithContext(ctx). - Model(&model.RequestPickup{}). - Where("id = ?", pickupID). - Update("status_pickup", status). - Error -} - -func (r *requestPickupRepository) UpdateRequestPickupItemsAmountAndPrice(ctx context.Context, pickupID string, items []dto.UpdateRequestPickupItemDTO) error { - // ambil collector_id dulu dari pickup - var pickup model.RequestPickup - if err := config.DB.WithContext(ctx). - Select("collector_id"). - Where("id = ?", pickupID). - First(&pickup).Error; err != nil { - return err - } - - for _, item := range items { - var pickupItem model.RequestPickupItem - err := config.DB.WithContext(ctx). - Where("id = ? AND request_pickup_id = ?", item.ItemID, pickupID). - First(&pickupItem).Error - if err != nil { - return err - } - - var price float64 - err = config.DB.WithContext(ctx). - Model(&model.AvaibleTrashByCollector{}). - Where("collector_id = ? AND trash_category_id = ?", pickup.CollectorID, pickupItem.TrashCategoryId). - Select("price"). - Scan(&price).Error - if err != nil { - return err - } - - finalPrice := item.Amount * price - err = config.DB.WithContext(ctx). - Model(&model.RequestPickupItem{}). - Where("id = ?", item.ItemID). - Updates(map[string]interface{}{ - "estimated_amount": item.Amount, - "final_price": finalPrice, - }).Error - if err != nil { - return err - } - } - return nil -} diff --git a/internal/repositories/role_repo.go b/internal/repositories/role_repo.go deleted file mode 100644 index e048df8..0000000 --- a/internal/repositories/role_repo.go +++ /dev/null @@ -1,49 +0,0 @@ -package repositories - -import ( - "context" - "rijig/model" - - "gorm.io/gorm" -) - -type RoleRepository interface { - FindByID(ctx context.Context, id string) (*model.Role, error) - FindRoleByName(ctx context.Context, roleName string) (*model.Role, error) - FindAll(ctx context.Context) ([]model.Role, error) -} - -type roleRepository struct { - db *gorm.DB -} - -func NewRoleRepository(db *gorm.DB) RoleRepository { - return &roleRepository{db} -} - -func (r *roleRepository) FindByID(ctx context.Context, id string) (*model.Role, error) { - var role model.Role - err := r.db.WithContext(ctx).Where("id = ?", id).First(&role).Error - if err != nil { - return nil, err - } - return &role, nil -} - -func (r *roleRepository) FindRoleByName(ctx context.Context, roleName string) (*model.Role, error) { - var role model.Role - err := r.db.WithContext(ctx).Where("role_name = ?", roleName).First(&role).Error - if err != nil { - return nil, err - } - return &role, nil -} - -func (r *roleRepository) FindAll(ctx context.Context) ([]model.Role, error) { - var roles []model.Role - err := r.db.WithContext(ctx).Find(&roles).Error - if err != nil { - return nil, err - } - return roles, nil -} diff --git a/internal/repositories/store_repo.go b/internal/repositories/store_repo.go deleted file mode 100644 index 9b02bb7..0000000 --- a/internal/repositories/store_repo.go +++ /dev/null @@ -1,88 +0,0 @@ -package repositories - -import ( - "fmt" - - "rijig/model" - - "gorm.io/gorm" -) - -type StoreRepository interface { - FindStoreByUserID(userID string) (*model.Store, error) - FindStoreByID(storeID string) (*model.Store, error) - FindAddressByID(addressID string) (*model.Address, error) - - CreateStore(store *model.Store) error - UpdateStore(store *model.Store) error - - DeleteStore(storeID string) error -} - -type storeRepository struct { - DB *gorm.DB -} - -func NewStoreRepository(DB *gorm.DB) StoreRepository { - return &storeRepository{DB} -} - -func (r *storeRepository) FindStoreByUserID(userID string) (*model.Store, error) { - var store model.Store - if err := r.DB.Where("user_id = ?", userID).First(&store).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &store, nil -} - -func (r *storeRepository) FindStoreByID(storeID string) (*model.Store, error) { - var store model.Store - if err := r.DB.Where("id = ?", storeID).First(&store).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &store, nil -} - -func (r *storeRepository) FindAddressByID(addressID string) (*model.Address, error) { - var address model.Address - if err := r.DB.Where("id = ?", addressID).First(&address).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &address, nil -} - -func (r *storeRepository) CreateStore(store *model.Store) error { - if err := r.DB.Create(store).Error; err != nil { - return err - } - return nil -} - -func (r *storeRepository) UpdateStore(store *model.Store) error { - if err := r.DB.Save(store).Error; err != nil { - return err - } - return nil -} - -func (r *storeRepository) DeleteStore(storeID string) error { - - if storeID == "" { - return fmt.Errorf("store ID cannot be empty") - } - - if err := r.DB.Where("id = ?", storeID).Delete(&model.Store{}).Error; err != nil { - return fmt.Errorf("failed to delete store: %w", err) - } - - return nil -} diff --git a/internal/repositories/trash_repo.go b/internal/repositories/trash_repo.go deleted file mode 100644 index 19bee10..0000000 --- a/internal/repositories/trash_repo.go +++ /dev/null @@ -1,175 +0,0 @@ -package repositories - -import ( - "context" - "errors" - "fmt" - "log" - - "rijig/config" - "rijig/model" - - "gorm.io/gorm" -) - -type TrashRepository interface { - CreateCategory(category *model.TrashCategory) error - AddDetailToCategory(detail *model.TrashDetail) error - GetCategories() ([]model.TrashCategory, error) - GetCategoryByID(id string) (*model.TrashCategory, error) - FindCategoryId(id string) (*model.TrashCategory, error) - GetTrashCategoryByName(name string) (*model.TrashCategory, error) - GetTrashDetailByID(id string) (*model.TrashDetail, error) - GetTrashCategoryByID(ctx context.Context, id string) (*model.TrashCategory, error) - GetDetailsByCategoryID(categoryID string) ([]model.TrashDetail, error) - UpdateCategoryName(id string, newName string) error - UpdateCategory(id string, updateTrashCategory *model.TrashCategory) (*model.TrashCategory, error) - UpdateTrashDetail(id string, description string, price float64) error - UpdateEstimatedPrice(ctx context.Context, trashCategoryID string) error - DeleteCategory(id string) error - DeleteTrashDetail(id string) error -} - -type trashRepository struct { - DB *gorm.DB -} - -func NewTrashRepository(db *gorm.DB) TrashRepository { - return &trashRepository{DB: db} -} - -func (r *trashRepository) CreateCategory(category *model.TrashCategory) error { - if err := r.DB.Create(category).Error; err != nil { - return fmt.Errorf("failed to create category: %v", err) - } - return nil -} - -func (r *trashRepository) AddDetailToCategory(detail *model.TrashDetail) error { - if err := r.DB.Create(detail).Error; err != nil { - return fmt.Errorf("failed to add detail to category: %v", err) - } - return nil -} - -func (r *trashRepository) GetCategories() ([]model.TrashCategory, error) { - var categories []model.TrashCategory - if err := r.DB.Preload("Details").Find(&categories).Error; err != nil { - return nil, fmt.Errorf("failed to fetch categories: %v", err) - } - return categories, nil -} - -func (r *trashRepository) GetCategoryByID(id string) (*model.TrashCategory, error) { - var category model.TrashCategory - - if err := r.DB.Preload("Details").First(&category, "id = ?", id).Error; err != nil { - return nil, fmt.Errorf("category not found: %v", err) - } - return &category, nil -} - -func (r *trashRepository) GetTrashCategoryByID(ctx context.Context, id string) (*model.TrashCategory, error) { - var trash model.TrashCategory - if err := config.DB.WithContext(ctx).First(&trash, "id = ?", id).Error; err != nil { - return nil, err - } - return &trash, nil -} - -func (r *trashRepository) FindCategoryId(id string) (*model.TrashCategory, error) { - var category model.TrashCategory - - if err := r.DB.First(&category, "id = ?", id).Error; err != nil { - return nil, fmt.Errorf("category not found: %v", err) - } - return &category, nil -} - -func (r *trashRepository) GetTrashCategoryByName(name string) (*model.TrashCategory, error) { - var category model.TrashCategory - - if err := r.DB.Find(&category, "name = ?", name).Error; err != nil { - return nil, fmt.Errorf("category not found: %v", err) - } - return &category, nil -} - -func (r *trashRepository) GetTrashDetailByID(id string) (*model.TrashDetail, error) { - var detail model.TrashDetail - if err := r.DB.First(&detail, "id = ?", id).Error; err != nil { - return nil, fmt.Errorf("trash detail not found: %v", err) - } - return &detail, nil -} - -func (r *trashRepository) GetDetailsByCategoryID(categoryID string) ([]model.TrashDetail, error) { - var details []model.TrashDetail - - if err := r.DB.Where("category_id = ?", categoryID).Find(&details).Error; err != nil { - return nil, fmt.Errorf("failed to fetch details for category %s: %v", categoryID, err) - } - return details, nil -} - -func (r *trashRepository) UpdateCategoryName(id string, newName string) error { - if err := r.DB.Model(&model.TrashCategory{}).Where("id = ?", id).Update("name", newName).Error; err != nil { - return fmt.Errorf("failed to update category name: %v", err) - } - return nil -} - -func (r *trashRepository) UpdateCategory(id string, updateTrashCategory *model.TrashCategory) (*model.TrashCategory, error) { - var existingtrashCtgry model.TrashCategory - if err := r.DB.Where("id = ?", id).First(&existingtrashCtgry).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("trashCategory with ID %s not found", id) - } - log.Printf("Error fetching trash category for update: %v", err) - return nil, fmt.Errorf("error fetching trash category for update: %w", err) - } - - if err := r.DB.Save(&existingtrashCtgry).Error; err != nil { - log.Printf("Error updating trash category: %v", err) - return nil, fmt.Errorf("failed to update trash category: %w", err) - } - return &existingtrashCtgry, nil -} - -func (r *trashRepository) UpdateTrashDetail(id string, description string, price float64) error { - if err := r.DB.Model(&model.TrashDetail{}).Where("id = ?", id).Updates(model.TrashDetail{Description: description, Price: price}).Error; err != nil { - return fmt.Errorf("failed to update trash detail: %v", err) - } - return nil -} - -func (r *trashRepository) UpdateEstimatedPrice(ctx context.Context, trashCategoryID string) error { - var avg float64 - - err := config.DB.WithContext(ctx). - Model(&model.AvaibleTrashByCollector{}). - Where("trash_category_id = ?", trashCategoryID). - Select("AVG(price)").Scan(&avg).Error - if err != nil { - return err - } - - return config.DB.WithContext(ctx). - Model(&model.TrashCategory{}). - Where("id = ?", trashCategoryID). - Update("estimated_price", avg).Error -} - -func (r *trashRepository) DeleteCategory(id string) error { - if err := r.DB.Delete(&model.TrashCategory{}, "id = ?", id).Error; err != nil { - return fmt.Errorf("failed to delete category: %v", err) - } - return nil -} - -func (r *trashRepository) DeleteTrashDetail(id string) error { - if err := r.DB.Delete(&model.TrashDetail{}, "id = ?", id).Error; err != nil { - return fmt.Errorf("failed to delete trash detail: %v", err) - } - return nil -} diff --git a/internal/repositories/trashcart_repo.go b/internal/repositories/trashcart_repo.go deleted file mode 100644 index 81c7e20..0000000 --- a/internal/repositories/trashcart_repo.go +++ /dev/null @@ -1,166 +0,0 @@ -package repositories - -import ( - "context" - "errors" - "fmt" - - "rijig/config" - "rijig/model" - - "gorm.io/gorm" -) - -type CartRepository interface { - FindOrCreateCart(ctx context.Context, userID string) (*model.Cart, error) - AddOrUpdateCartItem(ctx context.Context, cartID, trashCategoryID string, amount float64, estimatedPrice float64) error - DeleteCartItem(ctx context.Context, cartID, trashCategoryID string) error - GetCartByUser(ctx context.Context, userID string) (*model.Cart, error) - UpdateCartTotals(ctx context.Context, cartID string) error - DeleteCart(ctx context.Context, userID string) error - // New method for batch cart creation - CreateCartWithItems(ctx context.Context, cart *model.Cart) error - // Check if user already has a cart - HasExistingCart(ctx context.Context, userID string) (bool, error) -} - -type cartRepository struct{} - -func NewCartRepository() CartRepository { - return &cartRepository{} -} - -func (r *cartRepository) FindOrCreateCart(ctx context.Context, userID string) (*model.Cart, error) { - var cart model.Cart - db := config.DB.WithContext(ctx) - - err := db. - Preload("CartItems.TrashCategory"). - Where("user_id = ?", userID). - First(&cart).Error - - if err == nil { - return &cart, nil - } - - if errors.Is(err, gorm.ErrRecordNotFound) { - newCart := model.Cart{ - UserID: userID, - TotalAmount: 0, - EstimatedTotalPrice: 0, - } - if err := db.Create(&newCart).Error; err != nil { - return nil, err - } - return &newCart, nil - } - - return nil, err -} - -func (r *cartRepository) AddOrUpdateCartItem(ctx context.Context, cartID, trashCategoryID string, amount float64, estimatedPrice float64) error { - db := config.DB.WithContext(ctx) - - var item model.CartItem - err := db. - Where("cart_id = ? AND trash_category_id = ?", cartID, trashCategoryID). - First(&item).Error - - if errors.Is(err, gorm.ErrRecordNotFound) { - newItem := model.CartItem{ - CartID: cartID, - TrashCategoryID: trashCategoryID, - Amount: amount, - SubTotalEstimatedPrice: amount * estimatedPrice, - } - return db.Create(&newItem).Error - } - - if err != nil { - return err - } - - item.Amount = amount - item.SubTotalEstimatedPrice = amount * estimatedPrice - return db.Save(&item).Error -} - -func (r *cartRepository) DeleteCartItem(ctx context.Context, cartID, trashCategoryID string) error { - db := config.DB.WithContext(ctx) - return db.Where("cart_id = ? AND trash_category_id = ?", cartID, trashCategoryID). - Delete(&model.CartItem{}).Error -} - -func (r *cartRepository) GetCartByUser(ctx context.Context, userID string) (*model.Cart, error) { - var cart model.Cart - db := config.DB.WithContext(ctx) - - err := db. - Preload("CartItems.TrashCategory"). - Where("user_id = ?", userID). - First(&cart).Error - - if err != nil { - return nil, err - } - return &cart, nil -} - -func (r *cartRepository) UpdateCartTotals(ctx context.Context, cartID string) error { - db := config.DB.WithContext(ctx) - - var items []model.CartItem - if err := db.Where("cart_id = ?", cartID).Find(&items).Error; err != nil { - return err - } - - var totalAmount float64 - var totalPrice float64 - - for _, item := range items { - totalAmount += item.Amount - totalPrice += item.SubTotalEstimatedPrice - } - - return db.Model(&model.Cart{}). - Where("id = ?", cartID). - Updates(map[string]interface{}{ - "total_amount": totalAmount, - "estimated_total_price": totalPrice, - }).Error -} - -func (r *cartRepository) DeleteCart(ctx context.Context, userID string) error { - db := config.DB.WithContext(ctx) - var cart model.Cart - if err := db.Where("user_id = ?", userID).First(&cart).Error; err != nil { - return err - } - return db.Delete(&cart).Error -} - -// New method for batch cart creation with transaction -func (r *cartRepository) CreateCartWithItems(ctx context.Context, cart *model.Cart) error { - db := config.DB.WithContext(ctx) - - // Use transaction to ensure data consistency - return db.Transaction(func(tx *gorm.DB) error { - if err := tx.Create(cart).Error; err != nil { - return fmt.Errorf("failed to create cart: %w", err) - } - return nil - }) -} - -// Check if user already has a cart -func (r *cartRepository) HasExistingCart(ctx context.Context, userID string) (bool, error) { - db := config.DB.WithContext(ctx) - - var count int64 - err := db.Model(&model.Cart{}).Where("user_id = ?", userID).Count(&count).Error - if err != nil { - return false, err - } - - return count > 0, nil -} diff --git a/internal/repositories/user_repo.go b/internal/repositories/user_repo.go deleted file mode 100644 index 8c7e085..0000000 --- a/internal/repositories/user_repo.go +++ /dev/null @@ -1,77 +0,0 @@ -package repositories - -import ( - "fmt" - "rijig/model" - - "gorm.io/gorm" -) - -type UserProfilRepository interface { - FindByID(userID string) (*model.User, error) - FindAll(page, limit int) ([]model.User, error) - Update(user *model.User) error - UpdateAvatar(userID, avatarURL string) error - UpdatePassword(userID string, newPassword string) error -} - -type userProfilRepository struct { - DB *gorm.DB -} - -func NewUserProfilRepository(db *gorm.DB) UserProfilRepository { - return &userProfilRepository{DB: db} -} - -func (r *userProfilRepository) FindByID(userID string) (*model.User, error) { - var user model.User - err := r.DB.Preload("Role").Where("id = ?", userID).First(&user).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("user with ID %s not found", userID) - } - return nil, fmt.Errorf("error finding user with ID %s: %v", userID, err) - } - - if user.Role == nil { - return nil, fmt.Errorf("role not found for user ID %s", userID) - } - - return &user, nil -} - -func (r *userProfilRepository) FindAll(page, limit int) ([]model.User, error) { - var users []model.User - offset := (page - 1) * limit - err := r.DB.Preload("Role").Offset(offset).Limit(limit).Find(&users).Error - if err != nil { - return nil, fmt.Errorf("error finding all users: %v", err) - } - return users, nil -} - -func (r *userProfilRepository) Update(user *model.User) error { - err := r.DB.Save(user).Error - if err != nil { - return fmt.Errorf("error updating user: %v", err) - } - return nil -} - -func (r *userProfilRepository) UpdateAvatar(userID, avatarURL string) error { - var user model.User - err := r.DB.Model(&user).Where("id = ?", userID).Update("avatar", avatarURL).Error - if err != nil { - return fmt.Errorf("error updating avatar for user ID %s: %v", userID, err) - } - return nil -} - -func (r *userProfilRepository) UpdatePassword(userID string, newPassword string) error { - var user model.User - err := r.DB.Model(&user).Where("id = ?", userID).Update("password", newPassword).Error - if err != nil { - return fmt.Errorf("error updating password for user ID %s: %v", userID, err) - } - return nil -} diff --git a/internal/repositories/userpin_repo.go b/internal/repositories/userpin_repo.go deleted file mode 100644 index 47d7118..0000000 --- a/internal/repositories/userpin_repo.go +++ /dev/null @@ -1,60 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type UserPinRepository interface { - FindByUserID(userID string) (*model.UserPin, error) - FindByPin(userPin string) (*model.UserPin, error) - Create(userPin *model.UserPin) error - Update(userPin *model.UserPin) error -} - -type userPinRepository struct { - DB *gorm.DB -} - -func NewUserPinRepository(db *gorm.DB) UserPinRepository { - return &userPinRepository{DB: db} -} - -func (r *userPinRepository) FindByUserID(userID string) (*model.UserPin, error) { - var userPin model.UserPin - err := r.DB.Where("user_id = ?", userID).First(&userPin).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - - return nil, nil - } - return nil, err - } - return &userPin, nil -} - -func (r *userPinRepository) FindByPin(pin string) (*model.UserPin, error) { - var userPin model.UserPin - err := r.DB.Where("pin = ?", pin).First(&userPin).Error - if err != nil { - return nil, err - } - return &userPin, nil -} - -func (r *userPinRepository) Create(userPin *model.UserPin) error { - err := r.DB.Create(userPin).Error - if err != nil { - return err - } - return nil -} - -func (r *userPinRepository) Update(userPin *model.UserPin) error { - err := r.DB.Save(userPin).Error - if err != nil { - return err - } - return nil -} diff --git a/internal/repositories/wilayah_indonesia_repo.go b/internal/repositories/wilayah_indonesia_repo.go deleted file mode 100644 index 60a53bf..0000000 --- a/internal/repositories/wilayah_indonesia_repo.go +++ /dev/null @@ -1,244 +0,0 @@ -package repositories - -import ( - "rijig/model" - - "gorm.io/gorm" -) - -type WilayahIndonesiaRepository interface { - ImportProvinces(provinces []model.Province) error - ImportRegencies(regencies []model.Regency) error - ImportDistricts(districts []model.District) error - ImportVillages(villages []model.Village) error - - FindAllProvinces(page, limit int) ([]model.Province, int, error) - FindProvinceByID(id string, page, limit int) (*model.Province, int, error) - - FindAllRegencies(page, limit int) ([]model.Regency, int, error) - FindRegencyByID(id string, page, limit int) (*model.Regency, int, error) - - FindAllDistricts(page, limit int) ([]model.District, int, error) - FindDistrictByID(id string, page, limit int) (*model.District, int, error) - - FindAllVillages(page, limit int) ([]model.Village, int, error) - FindVillageByID(id string) (*model.Village, error) -} - -type wilayahIndonesiaRepository struct { - DB *gorm.DB -} - -func NewWilayahIndonesiaRepository(db *gorm.DB) WilayahIndonesiaRepository { - return &wilayahIndonesiaRepository{DB: db} -} - -func (r *wilayahIndonesiaRepository) ImportProvinces(provinces []model.Province) error { - for _, province := range provinces { - if err := r.DB.Create(&province).Error; err != nil { - return err - } - } - return nil -} - -func (r *wilayahIndonesiaRepository) ImportRegencies(regencies []model.Regency) error { - for _, regency := range regencies { - if err := r.DB.Create(®ency).Error; err != nil { - return err - } - } - return nil -} - -func (r *wilayahIndonesiaRepository) ImportDistricts(districts []model.District) error { - for _, district := range districts { - if err := r.DB.Create(&district).Error; err != nil { - return err - } - } - return nil -} - -func (r *wilayahIndonesiaRepository) ImportVillages(villages []model.Village) error { - for _, village := range villages { - if err := r.DB.Create(&village).Error; err != nil { - return err - } - } - return nil -} - -func (r *wilayahIndonesiaRepository) FindAllProvinces(page, limit int) ([]model.Province, int, error) { - var provinces []model.Province - var total int64 - - err := r.DB.Model(&model.Province{}).Count(&total).Error - if err != nil { - return nil, 0, err - } - - if page > 0 && limit > 0 { - err := r.DB.Offset((page - 1) * limit).Limit(limit).Find(&provinces).Error - if err != nil { - return nil, 0, err - } - } else { - - err := r.DB.Find(&provinces).Error - if err != nil { - return nil, 0, err - } - } - - return provinces, int(total), nil -} - -func (r *wilayahIndonesiaRepository) FindProvinceByID(id string, page, limit int) (*model.Province, int, error) { - var province model.Province - - err := r.DB.Preload("Regencies", func(db *gorm.DB) *gorm.DB { - if page > 0 && limit > 0 { - - return db.Offset((page - 1) * limit).Limit(limit) - } - - return db - }).Where("id = ?", id).First(&province).Error - if err != nil { - return nil, 0, err - } - - var totalRegencies int64 - r.DB.Model(&model.Regency{}).Where("province_id = ?", id).Count(&totalRegencies) - - return &province, int(totalRegencies), nil -} - -func (r *wilayahIndonesiaRepository) FindAllRegencies(page, limit int) ([]model.Regency, int, error) { - var regencies []model.Regency - var total int64 - - err := r.DB.Model(&model.Regency{}).Count(&total).Error - if err != nil { - return nil, 0, err - } - - if page > 0 && limit > 0 { - err := r.DB.Offset((page - 1) * limit).Limit(limit).Find(®encies).Error - if err != nil { - return nil, 0, err - } - } else { - - err := r.DB.Find(®encies).Error - if err != nil { - return nil, 0, err - } - } - - return regencies, int(total), nil -} - -func (r *wilayahIndonesiaRepository) FindRegencyByID(id string, page, limit int) (*model.Regency, int, error) { - var regency model.Regency - - err := r.DB.Preload("Districts", func(db *gorm.DB) *gorm.DB { - if page > 0 && limit > 0 { - return db.Offset((page - 1) * limit).Limit(limit) - } - return db - }).Where("id = ?", id).First(®ency).Error - - if err != nil { - return nil, 0, err - } - - var totalDistricts int64 - err = r.DB.Model(&model.District{}).Where("regency_id = ?", id).Count(&totalDistricts).Error - if err != nil { - return nil, 0, err - } - - return ®ency, int(totalDistricts), nil -} - -func (r *wilayahIndonesiaRepository) FindAllDistricts(page, limit int) ([]model.District, int, error) { - var district []model.District - var total int64 - - err := r.DB.Model(&model.District{}).Count(&total).Error - if err != nil { - return nil, 0, err - } - - if page > 0 && limit > 0 { - err := r.DB.Offset((page - 1) * limit).Limit(limit).Find(&district).Error - if err != nil { - return nil, 0, err - } - } else { - - err := r.DB.Find(&district).Error - if err != nil { - return nil, 0, err - } - } - - return district, int(total), nil -} - -func (r *wilayahIndonesiaRepository) FindDistrictByID(id string, page, limit int) (*model.District, int, error) { - var district model.District - - err := r.DB.Preload("Villages", func(db *gorm.DB) *gorm.DB { - if page > 0 && limit > 0 { - - return db.Offset((page - 1) * limit).Limit(limit) - } - - return db - }).Where("id = ?", id).First(&district).Error - if err != nil { - return nil, 0, err - } - - var totalVillage int64 - r.DB.Model(&model.Village{}).Where("district_id = ?", id).Count(&totalVillage) - - return &district, int(totalVillage), nil -} - -func (r *wilayahIndonesiaRepository) FindAllVillages(page, limit int) ([]model.Village, int, error) { - var villages []model.Village - var total int64 - - err := r.DB.Model(&model.Village{}).Count(&total).Error - if err != nil { - return nil, 0, err - } - - if page > 0 && limit > 0 { - err := r.DB.Offset((page - 1) * limit).Limit(limit).Find(&villages).Error - if err != nil { - return nil, 0, err - } - } else { - - err := r.DB.Find(&villages).Error - if err != nil { - return nil, 0, err - } - } - - return villages, int(total), nil -} - -func (r *wilayahIndonesiaRepository) FindVillageByID(id string) (*model.Village, error) { - var village model.Village - err := r.DB.Where("id = ?", id).First(&village).Error - if err != nil { - return nil, err - } - return &village, nil -} diff --git a/internal/services/about_service.go b/internal/services/about_service.go deleted file mode 100644 index 27a7f17..0000000 --- a/internal/services/about_service.go +++ /dev/null @@ -1,436 +0,0 @@ -package services - -import ( - "fmt" - "log" - "mime/multipart" - "os" - "path/filepath" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "github.com/google/uuid" -) - -type AboutService interface { - CreateAbout(request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error) - UpdateAbout(id string, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error) - GetAllAbout() ([]dto.ResponseAboutDTO, error) - GetAboutByID(id string) (*dto.ResponseAboutDTO, error) - GetAboutDetailById(id string) (*dto.ResponseAboutDetailDTO, error) - DeleteAbout(id string) error - - CreateAboutDetail(request dto.RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error) - UpdateAboutDetail(id string, request dto.RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error) - DeleteAboutDetail(id string) error -} - -type aboutService struct { - aboutRepo repositories.AboutRepository -} - -func NewAboutService(aboutRepo repositories.AboutRepository) AboutService { - return &aboutService{aboutRepo: aboutRepo} -} - -func formatResponseAboutDetailDTO(about *model.AboutDetail) (*dto.ResponseAboutDetailDTO, error) { - createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt) - - response := &dto.ResponseAboutDetailDTO{ - ID: about.ID, - AboutID: about.AboutID, - ImageDetail: about.ImageDetail, - Description: about.Description, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return response, nil -} - -func formatResponseAboutDTO(about *model.About) (*dto.ResponseAboutDTO, error) { - createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt) - - response := &dto.ResponseAboutDTO{ - ID: about.ID, - Title: about.Title, - CoverImage: about.CoverImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return response, nil -} - -func (s *aboutService) saveCoverImageAbout(coverImageAbout *multipart.FileHeader) (string, error) { - pathImage := "/uploads/coverabout/" - coverImageAboutDir := "./public" + os.Getenv("BASE_URL") + pathImage - if _, err := os.Stat(coverImageAboutDir); os.IsNotExist(err) { - - if err := os.MkdirAll(coverImageAboutDir, os.ModePerm); err != nil { - return "", fmt.Errorf("gagal membuat direktori untuk cover image about: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true, ".svg": true} - extension := filepath.Ext(coverImageAbout.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - coverImageFileName := fmt.Sprintf("%s_coverabout%s", uuid.New().String(), extension) - coverImagePath := filepath.Join(coverImageAboutDir, coverImageFileName) - - src, err := coverImageAbout.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(coverImagePath) - if err != nil { - return "", fmt.Errorf("failed to create cover image about file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save cover image about: %v", err) - } - - coverImageAboutUrl := fmt.Sprintf("%s%s", pathImage, coverImageFileName) - - return coverImageAboutUrl, nil -} - -func (s *aboutService) saveCoverImageAboutDetail(coverImageAbout *multipart.FileHeader) (string, error) { - pathImage := "/uploads/coverabout/coveraboutdetail/" - coverImageAboutDir := "./public" + os.Getenv("BASE_URL") + pathImage - if _, err := os.Stat(coverImageAboutDir); os.IsNotExist(err) { - - if err := os.MkdirAll(coverImageAboutDir, os.ModePerm); err != nil { - return "", fmt.Errorf("gagal membuat direktori untuk cover image about: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true, ".svg": true} - extension := filepath.Ext(coverImageAbout.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - coverImageFileName := fmt.Sprintf("%s_coveraboutdetail_%s", uuid.New().String(), extension) - coverImagePath := filepath.Join(coverImageAboutDir, coverImageFileName) - - src, err := coverImageAbout.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(coverImagePath) - if err != nil { - return "", fmt.Errorf("failed to create cover image about file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save cover image about: %v", err) - } - - coverImageAboutUrl := fmt.Sprintf("%s%s", pathImage, coverImageFileName) - - return coverImageAboutUrl, nil -} - -func deleteCoverImageAbout(coverimageAboutPath string) error { - if coverimageAboutPath == "" { - return nil - } - - baseDir := "./public/" + os.Getenv("BASE_URL") - absolutePath := baseDir + coverimageAboutPath - - if _, err := os.Stat(absolutePath); os.IsNotExist(err) { - return fmt.Errorf("image file not found: %v", err) - } - - err := os.Remove(absolutePath) - if err != nil { - return fmt.Errorf("failed to delete image: %v", err) - } - - log.Printf("Image deleted successfully: %s", absolutePath) - return nil -} - -func (s *aboutService) CreateAbout(request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error) { - errors, valid := request.ValidateAbout() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - coverImageAboutPath, err := s.saveCoverImageAbout(coverImageAbout) - if err != nil { - return nil, fmt.Errorf("gagal menyimpan cover image about: %v ", err) - } - - about := model.About{ - Title: request.Title, - CoverImage: coverImageAboutPath, - } - - if err := s.aboutRepo.CreateAbout(&about); err != nil { - return nil, fmt.Errorf("failed to create About: %v", err) - } - - response, err := formatResponseAboutDTO(&about) - if err != nil { - return nil, fmt.Errorf("error formatting About response: %v", err) - } - - return response, nil -} - -func (s *aboutService) UpdateAbout(id string, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error) { - - errors, valid := request.ValidateAbout() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - about, err := s.aboutRepo.GetAboutByID(id) - if err != nil { - return nil, fmt.Errorf("about not found: %v", err) - } - - if about.CoverImage != "" { - err := deleteCoverImageAbout(about.CoverImage) - if err != nil { - return nil, fmt.Errorf("gagal mengahpus gambar lama: %v", err) - } - } - - var coverImageAboutPath string - if coverImageAbout != nil { - coverImageAboutPath, err = s.saveCoverImageAbout(coverImageAbout) - if err != nil { - return nil, fmt.Errorf("gagal menyimpan gambar baru: %v", err) - } - } - - about.Title = request.Title - if coverImageAboutPath != "" { - about.CoverImage = coverImageAboutPath - } - - updatedAbout, err := s.aboutRepo.UpdateAbout(id, about) - if err != nil { - return nil, fmt.Errorf("failed to update About: %v", err) - } - - response, err := formatResponseAboutDTO(updatedAbout) - if err != nil { - return nil, fmt.Errorf("error formatting About response: %v", err) - } - - return response, nil -} - -func (s *aboutService) GetAllAbout() ([]dto.ResponseAboutDTO, error) { - - aboutList, err := s.aboutRepo.GetAllAbout() - if err != nil { - return nil, fmt.Errorf("failed to get About list: %v", err) - } - - var aboutDTOList []dto.ResponseAboutDTO - for _, about := range aboutList { - response, err := formatResponseAboutDTO(&about) - if err != nil { - log.Printf("Error formatting About response: %v", err) - continue - } - aboutDTOList = append(aboutDTOList, *response) - } - - return aboutDTOList, nil -} - -func (s *aboutService) GetAboutByID(id string) (*dto.ResponseAboutDTO, error) { - - about, err := s.aboutRepo.GetAboutByID(id) - if err != nil { - return nil, fmt.Errorf("about not found: %v", err) - } - - response, err := formatResponseAboutDTO(about) - if err != nil { - return nil, fmt.Errorf("error formatting About response: %v", err) - } - - var responseDetails []dto.ResponseAboutDetailDTO - for _, detail := range about.AboutDetail { - formattedDetail, err := formatResponseAboutDetailDTO(&detail) - if err != nil { - return nil, fmt.Errorf("error formatting AboutDetail response: %v", err) - } - responseDetails = append(responseDetails, *formattedDetail) - } - - response.AboutDetail = &responseDetails - - return response, nil -} - -func (s *aboutService) GetAboutDetailById(id string) (*dto.ResponseAboutDetailDTO, error) { - - about, err := s.aboutRepo.GetAboutDetailByID(id) - if err != nil { - return nil, fmt.Errorf("about not found: %v", err) - } - - response, err := formatResponseAboutDetailDTO(about) - if err != nil { - return nil, fmt.Errorf("error formatting About response: %v", err) - } - - return response, nil -} - -func (s *aboutService) DeleteAbout(id string) error { - about, err := s.aboutRepo.GetAboutByID(id) - if err != nil { - return fmt.Errorf("about not found: %v", err) - } - - if about.CoverImage != "" { - err := deleteCoverImageAbout(about.CoverImage) - if err != nil { - return fmt.Errorf("gagal mengahpus gambar lama: %v", err) - } - } - - if err := s.aboutRepo.DeleteAbout(id); err != nil { - return fmt.Errorf("failed to delete About: %v", err) - } - - return nil -} - -func (s *aboutService) CreateAboutDetail(request dto.RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error) { - - errors, valid := request.ValidateAboutDetail() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - _, err := s.aboutRepo.GetAboutByIDWithoutPrel(request.AboutId) - if err != nil { - return nil, fmt.Errorf("about_id tidak ditemukan: %v", err) - } - - coverImageAboutDetailPath, err := s.saveCoverImageAboutDetail(coverImageAboutDetail) - if err != nil { - return nil, fmt.Errorf("gagal menyimpan cover image about detail: %v ", err) - } - - aboutDetail := model.AboutDetail{ - AboutID: request.AboutId, - ImageDetail: coverImageAboutDetailPath, - Description: request.Description, - } - - if err := s.aboutRepo.CreateAboutDetail(&aboutDetail); err != nil { - return nil, fmt.Errorf("failed to create AboutDetail: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(aboutDetail.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(aboutDetail.UpdatedAt) - - response := &dto.ResponseAboutDetailDTO{ - ID: aboutDetail.ID, - AboutID: aboutDetail.AboutID, - ImageDetail: aboutDetail.ImageDetail, - Description: aboutDetail.Description, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return response, nil -} - -func (s *aboutService) UpdateAboutDetail(id string, request dto.RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error) { - - errors, valid := request.ValidateAboutDetail() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - aboutDetail, err := s.aboutRepo.GetAboutDetailByID(id) - if err != nil { - return nil, fmt.Errorf("about detail tidakck ditemukan: %v", err) - } - - if aboutDetail.ImageDetail != "" { - err := deleteCoverImageAbout(aboutDetail.ImageDetail) - if err != nil { - return nil, fmt.Errorf("gagal menghapus gambar lama: %v", err) - } - } - - var coverImageAboutDeatilPath string - if imageDetail != nil { - coverImageAboutDeatilPath, err = s.saveCoverImageAbout(imageDetail) - if err != nil { - return nil, fmt.Errorf("gagal menyimpan gambar baru: %v", err) - } - } - - aboutDetail.Description = request.Description - if coverImageAboutDeatilPath != "" { - aboutDetail.ImageDetail = coverImageAboutDeatilPath - } - - aboutDetail, err = s.aboutRepo.UpdateAboutDetail(id, aboutDetail) - if err != nil { - log.Printf("Error updating about detail: %v", err) - return nil, fmt.Errorf("failed to update about detail: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(aboutDetail.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(aboutDetail.UpdatedAt) - - response := &dto.ResponseAboutDetailDTO{ - ID: aboutDetail.ID, - AboutID: aboutDetail.AboutID, - ImageDetail: aboutDetail.ImageDetail, - Description: aboutDetail.Description, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return response, nil -} - -func (s *aboutService) DeleteAboutDetail(id string) error { - aboutDetail, err := s.aboutRepo.GetAboutDetailByID(id) - if err != nil { - return fmt.Errorf("about detail tidakck ditemukan: %v", err) - } - - if aboutDetail.ImageDetail != "" { - err := deleteCoverImageAbout(aboutDetail.ImageDetail) - if err != nil { - return fmt.Errorf("gagal menghapus gambar lama: %v", err) - } - } - - if err := s.aboutRepo.DeleteAboutDetail(id); err != nil { - return fmt.Errorf("failed to delete AboutDetail: %v", err) - } - return nil -} diff --git a/internal/services/address_service.go b/internal/services/address_service.go deleted file mode 100644 index b6b25c8..0000000 --- a/internal/services/address_service.go +++ /dev/null @@ -1,412 +0,0 @@ -package services - -import ( - "fmt" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type AddressService interface { - CreateAddress(userID string, request dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) - GetAddressByUserID(userID string) ([]dto.AddressResponseDTO, error) - GetAddressByID(userID, id string) (*dto.AddressResponseDTO, error) - UpdateAddress(userID, id string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) - DeleteAddress(userID, id string) error -} - -type addressService struct { - AddressRepo repositories.AddressRepository - WilayahRepo repositories.WilayahIndonesiaRepository -} - -func NewAddressService(addressRepo repositories.AddressRepository, wilayahRepo repositories.WilayahIndonesiaRepository) AddressService { - return &addressService{ - AddressRepo: addressRepo, - WilayahRepo: wilayahRepo, - } -} - -func (s *addressService) CreateAddress(userID string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) { - - province, _, err := s.WilayahRepo.FindProvinceByID(addressDTO.Province, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid province_id") - } - - regency, _, err := s.WilayahRepo.FindRegencyByID(addressDTO.Regency, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid regency_id") - } - - district, _, err := s.WilayahRepo.FindDistrictByID(addressDTO.District, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid district_id") - } - - village, err := s.WilayahRepo.FindVillageByID(addressDTO.Village) - if err != nil { - return nil, fmt.Errorf("invalid village_id") - } - - address := model.Address{ - UserID: userID, - Province: province.Name, - Regency: regency.Name, - District: district.Name, - Village: village.Name, - PostalCode: addressDTO.PostalCode, - Detail: addressDTO.Detail, - Latitude: addressDTO.Latitude, - Longitude: addressDTO.Longitude, - } - - err = s.AddressRepo.CreateAddress(&address) - if err != nil { - return nil, fmt.Errorf("failed to create address: %v", err) - } - - userCacheKey := fmt.Sprintf("user:%s:addresses", userID) - utils.DeleteData(userCacheKey) - - createdAt, _ := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressResponseDTO := &dto.AddressResponseDTO{ - UserID: address.UserID, - ID: address.ID, - Province: address.Province, - Regency: address.Regency, - District: address.District, - Village: address.Village, - PostalCode: address.PostalCode, - Detail: address.Detail, - Latitude: address.Latitude, - Longitude: address.Longitude, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("address:%s", address.ID) - cacheData := map[string]interface{}{ - "data": addressResponseDTO, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching new address to Redis: %v\n", err) - } - - addresses, err := s.AddressRepo.FindAddressByUserID(userID) - if err != nil { - return nil, fmt.Errorf("failed to fetch updated addresses for user: %v", err) - } - - var addressDTOs []dto.AddressResponseDTO - for _, addr := range addresses { - createdAt, _ := utils.FormatDateToIndonesianFormat(addr.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(addr.UpdatedAt) - - addressDTOs = append(addressDTOs, dto.AddressResponseDTO{ - UserID: addr.UserID, - ID: addr.ID, - Province: addr.Province, - Regency: addr.Regency, - District: addr.District, - Village: addr.Village, - PostalCode: addr.PostalCode, - Detail: addr.Detail, - Latitude: addr.Latitude, - Longitude: addr.Longitude, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData = map[string]interface{}{ - "data": addressDTOs, - } - err = utils.SetJSONData(userCacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching updated user addresses to Redis: %v\n", err) - } - - return addressResponseDTO, nil -} - -func (s *addressService) GetAddressByUserID(userID string) ([]dto.AddressResponseDTO, error) { - - cacheKey := fmt.Sprintf("user:%s:addresses", userID) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - var addresses []dto.AddressResponseDTO - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - addressData, ok := item.(map[string]interface{}) - if ok { - addresses = append(addresses, dto.AddressResponseDTO{ - UserID: addressData["user_id"].(string), - ID: addressData["address_id"].(string), - Province: addressData["province"].(string), - Regency: addressData["regency"].(string), - District: addressData["district"].(string), - Village: addressData["village"].(string), - PostalCode: addressData["postalCode"].(string), - Detail: addressData["detail"].(string), - Latitude: addressData["latitude"].(float64), - Longitude: addressData["longitude"].(float64), - CreatedAt: addressData["createdAt"].(string), - UpdatedAt: addressData["updatedAt"].(string), - }) - } - } - return addresses, nil - } - } - - addresses, err := s.AddressRepo.FindAddressByUserID(userID) - if err != nil { - return nil, fmt.Errorf("failed to fetch addresses: %v", err) - } - - var addressDTOs []dto.AddressResponseDTO - for _, address := range addresses { - createdAt, _ := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressDTOs = append(addressDTOs, dto.AddressResponseDTO{ - UserID: address.UserID, - ID: address.ID, - Province: address.Province, - Regency: address.Regency, - District: address.District, - Village: address.Village, - PostalCode: address.PostalCode, - Detail: address.Detail, - Latitude: address.Latitude, - Longitude: address.Longitude, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData := map[string]interface{}{ - "data": addressDTOs, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching addresses to Redis: %v\n", err) - } - - return addressDTOs, nil -} - -func (s *addressService) GetAddressByID(userID, id string) (*dto.AddressResponseDTO, error) { - address, err := s.AddressRepo.FindAddressByID(id) - if err != nil { - return nil, fmt.Errorf("address not found: %v", err) - } - - if address.UserID != userID { - return nil, fmt.Errorf("you are not authorized to update this address") - } - - cacheKey := fmt.Sprintf("address:%s", id) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - addressData, ok := cachedData["data"].(map[string]interface{}) - if ok { - address := dto.AddressResponseDTO{ - UserID: addressData["user_id"].(string), - ID: addressData["address_id"].(string), - Province: addressData["province"].(string), - Regency: addressData["regency"].(string), - District: addressData["district"].(string), - Village: addressData["village"].(string), - PostalCode: addressData["postalCode"].(string), - Detail: addressData["detail"].(string), - Latitude: addressData["latitude"].(float64), - Longitude: addressData["longitude"].(float64), - CreatedAt: addressData["createdAt"].(string), - UpdatedAt: addressData["updatedAt"].(string), - } - return &address, nil - } - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressDTO := &dto.AddressResponseDTO{ - UserID: address.UserID, - ID: address.ID, - Province: address.Province, - Regency: address.Regency, - District: address.District, - Village: address.Village, - PostalCode: address.PostalCode, - Detail: address.Detail, - Latitude: address.Latitude, - Longitude: address.Longitude, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheData := map[string]interface{}{ - "data": addressDTO, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching address to Redis: %v\n", err) - } - - return addressDTO, nil -} - -func (s *addressService) UpdateAddress(userID, id string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) { - - address, err := s.AddressRepo.FindAddressByID(id) - if err != nil { - return nil, fmt.Errorf("address not found: %v", err) - } - - if address.UserID != userID { - return nil, fmt.Errorf("you are not authorized to update this address") - } - - province, _, err := s.WilayahRepo.FindProvinceByID(addressDTO.Province, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid province_id") - } - - regency, _, err := s.WilayahRepo.FindRegencyByID(addressDTO.Regency, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid regency_id") - } - - district, _, err := s.WilayahRepo.FindDistrictByID(addressDTO.District, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid district_id") - } - - village, err := s.WilayahRepo.FindVillageByID(addressDTO.Village) - if err != nil { - return nil, fmt.Errorf("invalid village_id") - } - - address.Province = province.Name - address.Regency = regency.Name - address.District = district.Name - address.Village = village.Name - address.PostalCode = addressDTO.PostalCode - address.Detail = addressDTO.Detail - address.Latitude = addressDTO.Latitude - address.Longitude = addressDTO.Longitude - // address.UpdatedAt = time.Now() - - err = s.AddressRepo.UpdateAddress(address) - if err != nil { - return nil, fmt.Errorf("failed to update address: %v", err) - } - - addressCacheKey := fmt.Sprintf("address:%s", id) - utils.DeleteData(addressCacheKey) - - userAddressesCacheKey := fmt.Sprintf("user:%s:addresses", userID) - utils.DeleteData(userAddressesCacheKey) - - createdAt, _ := utils.FormatDateToIndonesianFormat(address.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt) - - addressResponseDTO := &dto.AddressResponseDTO{ - UserID: address.UserID, - ID: address.ID, - Province: address.Province, - Regency: address.Regency, - District: address.District, - Village: address.Village, - PostalCode: address.PostalCode, - Detail: address.Detail, - Latitude: address.Latitude, - Longitude: address.Longitude, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheData := map[string]interface{}{ - "data": addressResponseDTO, - } - err = utils.SetJSONData(addressCacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching updated address to Redis: %v\n", err) - } - - addresses, err := s.AddressRepo.FindAddressByUserID(address.UserID) - if err != nil { - return nil, fmt.Errorf("failed to fetch updated addresses for user: %v", err) - } - - var addressDTOs []dto.AddressResponseDTO - for _, addr := range addresses { - createdAt, _ := utils.FormatDateToIndonesianFormat(addr.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(addr.UpdatedAt) - - addressDTOs = append(addressDTOs, dto.AddressResponseDTO{ - UserID: addr.UserID, - ID: addr.ID, - Province: addr.Province, - Regency: addr.Regency, - District: addr.District, - Village: addr.Village, - PostalCode: addr.PostalCode, - Detail: addr.Detail, - Latitude: addr.Latitude, - Longitude: addr.Longitude, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData = map[string]interface{}{ - "data": addressDTOs, - } - err = utils.SetJSONData(userAddressesCacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching updated user addresses to Redis: %v\n", err) - } - - return addressResponseDTO, nil -} - -func (s *addressService) DeleteAddress(userID, addressID string) error { - - address, err := s.AddressRepo.FindAddressByID(addressID) - if err != nil { - return fmt.Errorf("address not found: %v", err) - } - - if address.UserID != userID { - return fmt.Errorf("you are not authorized to delete this address") - } - - err = s.AddressRepo.DeleteAddress(addressID) - if err != nil { - return fmt.Errorf("failed to delete address: %v", err) - } - - addressCacheKey := fmt.Sprintf("address:%s", addressID) - err = utils.DeleteData(addressCacheKey) - if err != nil { - fmt.Printf("Error deleting address cache: %v\n", err) - } - - userAddressesCacheKey := fmt.Sprintf("user:%s:addresses", address.UserID) - err = utils.DeleteData(userAddressesCacheKey) - if err != nil { - fmt.Printf("Error deleting user addresses cache: %v\n", err) - } - - return nil -} diff --git a/internal/services/article_service.go b/internal/services/article_service.go deleted file mode 100644 index a2e10ee..0000000 --- a/internal/services/article_service.go +++ /dev/null @@ -1,415 +0,0 @@ -package services - -import ( - "encoding/json" - "fmt" - "log" - "mime/multipart" - "os" - "path/filepath" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "github.com/google/uuid" -) - -type ArticleService interface { - CreateArticle(request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error) - GetAllArticles(page, limit int) ([]dto.ArticleResponseDTO, int, error) - GetArticleByID(id string) (*dto.ArticleResponseDTO, error) - UpdateArticle(id string, request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error) - DeleteArticle(id string) error -} - -type articleService struct { - ArticleRepo repositories.ArticleRepository -} - -func NewArticleService(articleRepo repositories.ArticleRepository) ArticleService { - return &articleService{ArticleRepo: articleRepo} -} - -func (s *articleService) saveCoverArticle(coverArticle *multipart.FileHeader) (string, error) { - pathImage := "/uploads/articles/" - coverArticleDir := "./public" + os.Getenv("BASE_URL") + pathImage - if _, err := os.Stat(coverArticleDir); os.IsNotExist(err) { - - if err := os.MkdirAll(coverArticleDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for cover article: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true, ".svg": true} - extension := filepath.Ext(coverArticle.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - coverArticleFileName := fmt.Sprintf("%s_coverarticle%s", uuid.New().String(), extension) - coverArticlePath := filepath.Join(coverArticleDir, coverArticleFileName) - - src, err := coverArticle.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(coverArticlePath) - if err != nil { - return "", fmt.Errorf("failed to create cover article file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save cover article: %v", err) - } - - iconTrashUrl := fmt.Sprintf("%s%s", pathImage, coverArticleFileName) - - return iconTrashUrl, nil -} - -func deleteCoverArticle(imagePath string) error { - if imagePath == "" { - return nil - } - - baseDir := "./public/" + os.Getenv("BASE_URL") - absolutePath := baseDir + imagePath - - if _, err := os.Stat(absolutePath); os.IsNotExist(err) { - return fmt.Errorf("image file not found: %v", err) - } - - err := os.Remove(absolutePath) - if err != nil { - return fmt.Errorf("failed to delete image: %v", err) - } - - log.Printf("Image deleted successfully: %s", absolutePath) - return nil -} - -func (s *articleService) CreateArticle(request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error) { - - coverArticlePath, err := s.saveCoverArticle(coverImage) - if err != nil { - return nil, fmt.Errorf("gagal menyimpan ikon sampah: %v", err) - } - - article := model.Article{ - Title: request.Title, - CoverImage: coverArticlePath, - Author: request.Author, - Heading: request.Heading, - Content: request.Content, - } - - if err := s.ArticleRepo.CreateArticle(&article); err != nil { - return nil, fmt.Errorf("failed to create article: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(article.PublishedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(article.UpdatedAt) - - articleResponseDTO := &dto.ArticleResponseDTO{ - ID: article.ID, - Title: article.Title, - CoverImage: article.CoverImage, - Author: article.Author, - Heading: article.Heading, - Content: article.Content, - PublishedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("article:%s", article.ID) - cacheData := map[string]interface{}{ - "data": articleResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching article to Redis: %v\n", err) - } - - articles, total, err := s.ArticleRepo.FindAllArticles(0, 0) - if err != nil { - fmt.Printf("Error fetching all articles: %v\n", err) - } - - var articleDTOs []dto.ArticleResponseDTO - for _, a := range articles { - createdAt, _ := utils.FormatDateToIndonesianFormat(a.PublishedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(a.UpdatedAt) - - articleDTOs = append(articleDTOs, dto.ArticleResponseDTO{ - ID: a.ID, - Title: a.Title, - CoverImage: a.CoverImage, - Author: a.Author, - Heading: a.Heading, - Content: a.Content, - PublishedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - articlesCacheKey := "articles:all" - cacheData = map[string]interface{}{ - "data": articleDTOs, - "total": total, - } - if err := utils.SetJSONData(articlesCacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching all articles to Redis: %v\n", err) - } - - return articleResponseDTO, nil -} - -func (s *articleService) GetAllArticles(page, limit int) ([]dto.ArticleResponseDTO, int, error) { - var cacheKey string - - if page == 0 && limit == 0 { - cacheKey = "articles:all" - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - if data, ok := cachedData["data"].([]interface{}); ok { - var articles []dto.ArticleResponseDTO - for _, item := range data { - articleData, ok := item.(map[string]interface{}) - if ok { - articles = append(articles, dto.ArticleResponseDTO{ - ID: articleData["article_id"].(string), - Title: articleData["title"].(string), - CoverImage: articleData["coverImage"].(string), - Author: articleData["author"].(string), - Heading: articleData["heading"].(string), - Content: articleData["content"].(string), - PublishedAt: articleData["publishedAt"].(string), - UpdatedAt: articleData["updatedAt"].(string), - }) - } - } - - if total, ok := cachedData["total"].(float64); ok { - fmt.Printf("Cached Total Articles: %f\n", total) - return articles, int(total), nil - } else { - fmt.Println("Total articles not found in cache, using 0 as fallback.") - return articles, 0, nil - } - } - } - } - - articles, total, err := s.ArticleRepo.FindAllArticles(page, limit) - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch articles: %v", err) - } - - fmt.Printf("Total Articles from Database: %d\n", total) - - var articleDTOs []dto.ArticleResponseDTO - for _, article := range articles { - publishedAt, _ := utils.FormatDateToIndonesianFormat(article.PublishedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(article.UpdatedAt) - - articleDTOs = append(articleDTOs, dto.ArticleResponseDTO{ - ID: article.ID, - Title: article.Title, - CoverImage: article.CoverImage, - Author: article.Author, - Heading: article.Heading, - Content: article.Content, - PublishedAt: publishedAt, - UpdatedAt: updatedAt, - }) - } - - cacheKey = fmt.Sprintf("articles_page:%d_limit:%d", page, limit) - cacheData := map[string]interface{}{ - "data": articleDTOs, - "total": total, - } - - fmt.Printf("Setting cache with total: %d\n", total) - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching articles to Redis: %v\n", err) - } - - return articleDTOs, total, nil -} - -func (s *articleService) GetArticleByID(id string) (*dto.ArticleResponseDTO, error) { - - cacheKey := fmt.Sprintf("article:%s", id) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - articleResponse := &dto.ArticleResponseDTO{} - if data, ok := cachedData["data"].(string); ok { - if err := json.Unmarshal([]byte(data), articleResponse); err == nil { - return articleResponse, nil - } - } - } - - article, err := s.ArticleRepo.FindArticleByID(id) - if err != nil { - return nil, fmt.Errorf("failed to fetch article by ID: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(article.PublishedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(article.UpdatedAt) - - articleResponseDTO := &dto.ArticleResponseDTO{ - ID: article.ID, - Title: article.Title, - CoverImage: article.CoverImage, - Author: article.Author, - Heading: article.Heading, - Content: article.Content, - PublishedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheData := map[string]interface{}{ - "data": articleResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching article to Redis: %v\n", err) - } - - return articleResponseDTO, nil -} - -func (s *articleService) UpdateArticle(id string, request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error) { - article, err := s.ArticleRepo.FindArticleByID(id) - if err != nil { - return nil, fmt.Errorf("article not found: %v", id) - } - - if article.CoverImage != "" { - err := deleteCoverArticle(article.CoverImage) - if err != nil { - return nil, fmt.Errorf("failed to delete old image: %v", err) - } - } - - var coverArticlePath string - if coverImage != nil { - coverArticlePath, err = s.saveCoverArticle(coverImage) - if err != nil { - return nil, fmt.Errorf("failed to save card photo: %v", err) - } - } - - if coverArticlePath != "" { - article.CoverImage = coverArticlePath - } - - article.Title = request.Title - article.Heading = request.Heading - article.Content = request.Content - article.Author = request.Author - - err = s.ArticleRepo.UpdateArticle(id, article) - if err != nil { - return nil, fmt.Errorf("failed to update article: %v", err) - } - - updatedArticle, err := s.ArticleRepo.FindArticleByID(id) - if err != nil { - return nil, fmt.Errorf("failed to fetch updated article: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(updatedArticle.PublishedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(updatedArticle.UpdatedAt) - - articleResponseDTO := &dto.ArticleResponseDTO{ - ID: updatedArticle.ID, - Title: updatedArticle.Title, - CoverImage: updatedArticle.CoverImage, - Author: updatedArticle.Author, - Heading: updatedArticle.Heading, - Content: updatedArticle.Content, - PublishedAt: createdAt, - UpdatedAt: updatedAt, - } - - articleCacheKey := fmt.Sprintf("article:%s", updatedArticle.ID) - err = utils.SetJSONData(articleCacheKey, map[string]interface{}{"data": articleResponseDTO}, time.Hour*24) - if err != nil { - fmt.Printf("Error caching updated article to Redis: %v\n", err) - } - - articlesCacheKey := "articles:all" - err = utils.DeleteData(articlesCacheKey) - if err != nil { - fmt.Printf("Error deleting articles cache: %v\n", err) - } - - articles, _, err := s.ArticleRepo.FindAllArticles(0, 0) - if err != nil { - fmt.Printf("Error fetching all articles: %v\n", err) - } else { - var articleDTOs []dto.ArticleResponseDTO - for _, a := range articles { - createdAt, _ := utils.FormatDateToIndonesianFormat(a.PublishedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(a.UpdatedAt) - - articleDTOs = append(articleDTOs, dto.ArticleResponseDTO{ - ID: a.ID, - Title: a.Title, - CoverImage: a.CoverImage, - Author: a.Author, - Heading: a.Heading, - Content: a.Content, - PublishedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData := map[string]interface{}{ - "data": articleDTOs, - } - err = utils.SetJSONData(articlesCacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching updated articles to Redis: %v\n", err) - } - } - - return articleResponseDTO, nil -} - -func (s *articleService) DeleteArticle(id string) error { - article, err := s.ArticleRepo.FindArticleByID(id) - if err != nil { - return fmt.Errorf("failed to find article: %v", id) - } - - if err := deleteCoverArticle(article.CoverImage); err != nil { - return fmt.Errorf("error waktu menghapus cover image article %s: %v", id, err) - } - - err = s.ArticleRepo.DeleteArticle(id) - if err != nil { - return fmt.Errorf("failed to delete article: %v", err) - } - - articleCacheKey := fmt.Sprintf("article:%s", id) - err = utils.DeleteData(articleCacheKey) - if err != nil { - fmt.Printf("Error deleting cache for article: %v\n", err) - } - - articlesCacheKey := "articles:all" - err = utils.DeleteData(articlesCacheKey) - if err != nil { - fmt.Printf("Error deleting cache for all articles: %v\n", err) - } - - return nil -} diff --git a/internal/services/auth/auth_admin_service.go b/internal/services/auth/auth_admin_service.go deleted file mode 100644 index 7adb5af..0000000 --- a/internal/services/auth/auth_admin_service.go +++ /dev/null @@ -1,192 +0,0 @@ -package service -/* -import ( - "errors" - "fmt" - "log" - "rijig/config" - dto "rijig/dto/auth" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - "rijig/model" - "rijig/utils" - "time" - - "github.com/golang-jwt/jwt/v5" - "golang.org/x/crypto/bcrypt" -) - -const ( - ErrEmailTaken = "email is already used" - ErrPhoneTaken = "phone number is already used" - ErrInvalidPassword = "password does not match" - ErrRoleNotFound = "role not found" - ErrFailedToGenerateToken = "failed to generate token" - ErrFailedToHashPassword = "failed to hash password" - ErrFailedToCreateUser = "failed to create user" - ErrIncorrectPassword = "incorrect password" - ErrAccountNotFound = "account not found" -) - -type AuthAdminService interface { - RegisterAdmin(request *dto.RegisterAdminRequest) (*model.User, error) - - LoginAdmin(req *dto.LoginAdminRequest) (*dto.LoginResponse, error) - LogoutAdmin(userID, deviceID string) error -} - -type authAdminService struct { - UserRepo repository.AuthAdminRepository - RoleRepo repositories.RoleRepository - SecretKey string -} - -func NewAuthAdminService(userRepo repository.AuthAdminRepository, roleRepo repositories.RoleRepository, secretKey string) AuthAdminService { - return &authAdminService{UserRepo: userRepo, RoleRepo: roleRepo, SecretKey: secretKey} -} - -func (s *authAdminService) RegisterAdmin(request *dto.RegisterAdminRequest) (*model.User, error) { - - if existingUser, _ := s.UserRepo.FindByEmail(request.Email); existingUser != nil { - return nil, errors.New(ErrEmailTaken) - } - - if existingUser, _ := s.UserRepo.FindByPhone(request.Phone); existingUser != nil { - return nil, errors.New(ErrPhoneTaken) - } - - role, err := s.UserRepo.FindRoleByName("administrator") - if err != nil { - return nil, errors.New(ErrRoleNotFound) - } - - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(request.Password), bcrypt.DefaultCost) - if err != nil { - log.Println("Error hashing password:", err) - return nil, errors.New(ErrFailedToHashPassword) - } - - user := &model.User{ - Name: request.Name, - Email: request.Email, - Phone: request.Phone, - Password: string(hashedPassword), - RoleID: role.ID, - Role: role, - Dateofbirth: request.Dateofbirth, - Placeofbirth: request.Placeofbirth, - Gender: request.Gender, - RegistrationStatus: "completed", - } - - createdUser, err := s.UserRepo.CreateUser(user) - if err != nil { - log.Println("Error creating user:", err) - return nil, fmt.Errorf("%s: %v", ErrFailedToCreateUser, err) - } - - return createdUser, nil -} - -func (s *authAdminService) LoginAdmin(req *dto.LoginAdminRequest) (*dto.LoginResponse, error) { - - user, err := s.UserRepo.FindByEmail(req.Email) - if err != nil { - log.Println("User not found:", err) - return nil, errors.New(ErrAccountNotFound) - } - - if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil { - log.Println("Incorrect password:", err) - return nil, errors.New(ErrIncorrectPassword) - } - - existingUser, err := s.UserRepo.FindAdminByEmailandRoleid(req.Email, "42bdecce-f2ad-44ae-b3d6-883c1fbddaf7") - if err != nil { - return nil, fmt.Errorf("failed to check existing user: %w", err) - } - - var adminUser *model.User - if existingUser != nil { - adminUser = existingUser - } else { - - adminUser = &model.User{ - Email: req.Email, - RoleID: "42bdecce-f2ad-44ae-b3d6-883c1fbddaf7", - } - createdUser, err := s.UserRepo.CreateUser(adminUser) - if err != nil { - return nil, err - } - adminUser = createdUser - } - - token, err := s.generateJWTToken(adminUser.ID, req.Deviceid) - if err != nil { - return nil, err - } - - role, err := s.RoleRepo.FindByID(user.RoleID) - if err != nil { - return nil, fmt.Errorf("failed to get role: %w", err) - } - - deviceID := req.Deviceid - if err := s.saveSessionAdminData(user.ID, deviceID, user.RoleID, role.RoleName, token); err != nil { - return nil, err - } - - return &dto.LoginResponse{ - UserID: user.ID, - Role: user.Role.RoleName, - Token: token, - }, nil -} - -func (s *authAdminService) saveSessionAdminData(userID string, deviceID string, roleID string, roleName string, token string) error { - sessionKey := fmt.Sprintf("session:%s:%s", userID, deviceID) - sessionData := map[string]interface{}{ - "userID": userID, - "roleID": roleID, - "roleName": roleName, - } - - if err := utils.SetJSONData(sessionKey, sessionData, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session data: %w", err) - } - - if err := utils.SetStringData("session_token:"+userID+":"+deviceID, token, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session token: %w", err) - } - - return nil -} - -func (s *authAdminService) generateJWTToken(userID string, deviceID string) (string, error) { - - expirationTime := time.Now().Add(24 * time.Hour) - - claims := jwt.MapClaims{ - "sub": userID, - "exp": expirationTime.Unix(), - "device_id": deviceID, - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - secretKey := config.GetSecretKey() - - return token.SignedString([]byte(secretKey)) -} - -func (s *authAdminService) LogoutAdmin(userID, deviceID string) error { - - err := utils.DeleteSessionData(userID, deviceID) - if err != nil { - return fmt.Errorf("failed to delete session from Redis: %w", err) - } - - return nil -} - */ \ No newline at end of file diff --git a/internal/services/auth/auth_masyarakat_service.go b/internal/services/auth/auth_masyarakat_service.go deleted file mode 100644 index 11070da..0000000 --- a/internal/services/auth/auth_masyarakat_service.go +++ /dev/null @@ -1,171 +0,0 @@ -package service -/* -import ( - "errors" - "fmt" - "rijig/config" - "rijig/dto" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - "rijig/model" - "rijig/utils" - "time" - - "github.com/golang-jwt/jwt/v5" -) - -type AuthMasyarakatService interface { - RegisterOrLogin(req *dto.RegisterRequest) error - VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) - Logout(userID, deviceID string) error -} - -type authMasyarakatService struct { - userRepo repository.AuthPengelolaRepository - roleRepo repositories.RoleRepository -} - -func NewAuthMasyarakatService(userRepo repositories.UserRepository, roleRepo repositories.RoleRepository) AuthMasyarakatService { - return &authMasyarakatService{userRepo, roleRepo} -} - -func (s *authMasyarakatService) generateJWTToken(userID string, deviceID string) (string, error) { - - expirationTime := time.Now().Add(672 * time.Hour) - - claims := jwt.MapClaims{ - "sub": userID, - "exp": expirationTime.Unix(), - "device_id": deviceID, - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - secretKey := config.GetSecretKey() - - return token.SignedString([]byte(secretKey)) -} - -func (s *authMasyarakatService) RegisterOrLogin(req *dto.RegisterRequest) error { - if err := s.checkOTPRequestCooldown(req.Phone); err != nil { - return err - } - return s.sendOTP(req.Phone) -} - -func (s *authMasyarakatService) checkOTPRequestCooldown(phone string) error { - otpSentTime, err := utils.GetStringData("otp_sent:" + phone) - if err != nil || otpSentTime == "" { - return nil - } - lastSent, _ := time.Parse(time.RFC3339, otpSentTime) - if time.Since(lastSent) < otpCooldown { - return errors.New("please wait before requesting a new OTP") - } - return nil -} - -func (s *authMasyarakatService) sendOTP(phone string) error { - otp := generateOTP() - if err := config.SendWhatsAppMessage(phone, fmt.Sprintf("Your OTP is: %s", otp)); err != nil { - return err - } - - if err := utils.SetStringData("otp:"+phone, otp, 10*time.Minute); err != nil { - return err - } - return utils.SetStringData("otp_sent:"+phone, time.Now().Format(time.RFC3339), 10*time.Minute) -} - -func (s *authMasyarakatService) VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) { - - storedOTP, err := utils.GetStringData("otp:" + req.Phone) - if err != nil || storedOTP == "" { - return nil, errors.New("OTP expired or not found") - } - - if storedOTP != req.OTP { - return nil, errors.New("invalid OTP") - } - - if err := utils.DeleteData("otp:" + req.Phone); err != nil { - return nil, fmt.Errorf("failed to remove OTP from Redis: %w", err) - } - if err := utils.DeleteData("otp_sent:" + req.Phone); err != nil { - return nil, fmt.Errorf("failed to remove otp_sent from Redis: %w", err) - } - - existingUser, err := s.userRepo.GetUserByPhoneAndRole(req.Phone, "0e5684e4-b214-4bd0-972f-3be80c4649a0") - if err != nil { - return nil, fmt.Errorf("failed to check existing user: %w", err) - } - - var user *model.User - if existingUser != nil { - user = existingUser - } else { - - user = &model.User{ - Phone: req.Phone, - RoleID: "0e5684e4-b214-4bd0-972f-3be80c4649a0", - PhoneVerified: true, - RegistrationStatus: "completed", - } - createdUser, err := s.userRepo.CreateUser(user) - if err != nil { - return nil, err - } - user = createdUser - } - - token, err := s.generateJWTToken(user.ID, req.DeviceID) - if err != nil { - return nil, err - } - - role, err := s.roleRepo.FindByID(user.RoleID) - if err != nil { - return nil, fmt.Errorf("failed to get role: %w", err) - } - - deviceID := req.DeviceID - if err := s.saveSessionData(user.ID, deviceID, user.RoleID, role.RoleName, token); err != nil { - return nil, err - } - - return &dto.UserDataResponse{ - UserID: user.ID, - UserRole: role.RoleName, - Token: token, - }, nil -} - -func (s *authMasyarakatService) saveSessionData(userID string, deviceID string, roleID string, roleName string, token string) error { - sessionKey := fmt.Sprintf("session:%s:%s", userID, deviceID) - sessionData := map[string]interface{}{ - "userID": userID, - "roleID": roleID, - "roleName": roleName, - } - - if err := utils.SetJSONData(sessionKey, sessionData, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session data: %w", err) - } - - if err := utils.SetStringData("session_token:"+userID+":"+deviceID, token, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session token: %w", err) - } - - return nil -} - -func (s *authMasyarakatService) Logout(userID, deviceID string) error { - - err := utils.DeleteSessionData(userID, deviceID) - if err != nil { - return fmt.Errorf("failed to delete session from Redis: %w", err) - } - - return nil -} - */ \ No newline at end of file diff --git a/internal/services/auth/auth_pengelola_service.go b/internal/services/auth/auth_pengelola_service.go deleted file mode 100644 index 0c2b33e..0000000 --- a/internal/services/auth/auth_pengelola_service.go +++ /dev/null @@ -1,171 +0,0 @@ -package service -/* -import ( - "errors" - "fmt" - "rijig/config" - "rijig/dto" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - "rijig/model" - "rijig/utils" - "time" - - "github.com/golang-jwt/jwt/v5" -) - -type AuthPengelolaService interface { - RegisterOrLogin(req *dto.RegisterRequest) error - VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) - Logout(userID, deviceID string) error -} - -type authPengelolaService struct { - userRepo repository.AuthPengelolaRepository - roleRepo repositories.RoleRepository -} - -func NewAuthPengelolaService(userRepo repositories.UserRepository, roleRepo repositories.RoleRepository) AuthPengelolaService { - return &authPengelolaService{userRepo, roleRepo} -} - -func (s *authPengelolaService) generateJWTToken(userID string, deviceID string) (string, error) { - - expirationTime := time.Now().Add(168 * time.Hour) - - claims := jwt.MapClaims{ - "sub": userID, - "exp": expirationTime.Unix(), - "device_id": deviceID, - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - secretKey := config.GetSecretKey() - - return token.SignedString([]byte(secretKey)) -} - -func (s *authPengelolaService) RegisterOrLogin(req *dto.RegisterRequest) error { - if err := s.checkOTPRequestCooldown(req.Phone); err != nil { - return err - } - return s.sendOTP(req.Phone) -} - -func (s *authPengelolaService) checkOTPRequestCooldown(phone string) error { - otpSentTime, err := utils.GetStringData("otp_sent:" + phone) - if err != nil || otpSentTime == "" { - return nil - } - lastSent, _ := time.Parse(time.RFC3339, otpSentTime) - if time.Since(lastSent) < otpCooldown { - return errors.New("please wait before requesting a new OTP") - } - return nil -} - -func (s *authPengelolaService) sendOTP(phone string) error { - otp := generateOTP() - if err := config.SendWhatsAppMessage(phone, fmt.Sprintf("Your OTP is: %s", otp)); err != nil { - return err - } - - if err := utils.SetStringData("otp:"+phone, otp, 10*time.Minute); err != nil { - return err - } - return utils.SetStringData("otp_sent:"+phone, time.Now().Format(time.RFC3339), 10*time.Minute) -} - -func (s *authPengelolaService) VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) { - - storedOTP, err := utils.GetStringData("otp:" + req.Phone) - if err != nil || storedOTP == "" { - return nil, errors.New("OTP expired or not found") - } - - if storedOTP != req.OTP { - return nil, errors.New("invalid OTP") - } - - if err := utils.DeleteData("otp:" + req.Phone); err != nil { - return nil, fmt.Errorf("failed to remove OTP from Redis: %w", err) - } - if err := utils.DeleteData("otp_sent:" + req.Phone); err != nil { - return nil, fmt.Errorf("failed to remove otp_sent from Redis: %w", err) - } - - existingUser, err := s.userRepo.GetUserByPhoneAndRole(req.Phone, "0bf86966-7042-410a-a88c-d01f70832348") - if err != nil { - return nil, fmt.Errorf("failed to check existing user: %w", err) - } - - var user *model.User - if existingUser != nil { - user = existingUser - } else { - - user = &model.User{ - Phone: req.Phone, - RoleID: "0bf86966-7042-410a-a88c-d01f70832348", - PhoneVerified: true, - RegistrationStatus: "uncompleted", - } - createdUser, err := s.userRepo.CreateUser(user) - if err != nil { - return nil, err - } - user = createdUser - } - - token, err := s.generateJWTToken(user.ID, req.DeviceID) - if err != nil { - return nil, err - } - - role, err := s.roleRepo.FindByID(user.RoleID) - if err != nil { - return nil, fmt.Errorf("failed to get role: %w", err) - } - - deviceID := req.DeviceID - if err := s.saveSessionData(user.ID, deviceID, user.RoleID, role.RoleName, token); err != nil { - return nil, err - } - - return &dto.UserDataResponse{ - UserID: user.ID, - UserRole: role.RoleName, - Token: token, - }, nil -} - -func (s *authPengelolaService) saveSessionData(userID string, deviceID string, roleID string, roleName string, token string) error { - sessionKey := fmt.Sprintf("session:%s:%s", userID, deviceID) - sessionData := map[string]interface{}{ - "userID": userID, - "roleID": roleID, - "roleName": roleName, - } - - if err := utils.SetJSONData(sessionKey, sessionData, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session data: %w", err) - } - - if err := utils.SetStringData("session_token:"+userID+":"+deviceID, token, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session token: %w", err) - } - - return nil -} - -func (s *authPengelolaService) Logout(userID, deviceID string) error { - - err := utils.DeleteSessionData(userID, deviceID) - if err != nil { - return fmt.Errorf("failed to delete session from Redis: %w", err) - } - - return nil -} - */ \ No newline at end of file diff --git a/internal/services/auth/auth_pengepul_service.go b/internal/services/auth/auth_pengepul_service.go deleted file mode 100644 index fd91d95..0000000 --- a/internal/services/auth/auth_pengepul_service.go +++ /dev/null @@ -1,172 +0,0 @@ -package service -/* -import ( - "errors" - "fmt" - "rijig/config" - "rijig/dto" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - "rijig/model" - "rijig/utils" - "time" - - "github.com/golang-jwt/jwt/v5" -) - -type AuthPengepulService interface { - RegisterOrLogin(req *dto.RegisterRequest) error - VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) - Logout(userID, deviceID string) error -} - -type authPengepulService struct { - userRepo repository.AuthPengelolaRepository - roleRepo repositories.RoleRepository -} - -func NewAuthPengepulService(userRepo repositories.UserRepository, roleRepo repositories.RoleRepository) AuthPengepulService { - return &authPengepulService{userRepo, roleRepo} -} - -func (s *authPengepulService) generateJWTToken(userID string, deviceID string) (string, error) { - - expirationTime := time.Now().Add(480 * time.Hour) - - claims := jwt.MapClaims{ - "sub": userID, - "exp": expirationTime.Unix(), - "device_id": deviceID, - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - secretKey := config.GetSecretKey() - - return token.SignedString([]byte(secretKey)) -} - -func (s *authPengepulService) RegisterOrLogin(req *dto.RegisterRequest) error { - if err := s.checkOTPRequestCooldown(req.Phone); err != nil { - return err - } - return s.sendOTP(req.Phone) -} - -func (s *authPengepulService) checkOTPRequestCooldown(phone string) error { - otpSentTime, err := utils.GetStringData("otp_sent:" + phone) - if err != nil || otpSentTime == "" { - return nil - } - lastSent, _ := time.Parse(time.RFC3339, otpSentTime) - if time.Since(lastSent) < otpCooldown { - return errors.New("please wait before requesting a new OTP") - } - return nil -} - -func (s *authPengepulService) sendOTP(phone string) error { - otp := generateOTP() - fmt.Printf("ur otp is:%s", otp) - // if err := config.SendWhatsAppMessage(phone, fmt.Sprintf("Your OTP is: %s", otp)); err != nil { - // return err - // } - - if err := utils.SetStringData("otp:"+phone, otp, 10*time.Minute); err != nil { - return err - } - return utils.SetStringData("otp_sent:"+phone, time.Now().Format(time.RFC3339), 10*time.Minute) -} - -func (s *authPengepulService) VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) { - - storedOTP, err := utils.GetStringData("otp:" + req.Phone) - if err != nil || storedOTP == "" { - return nil, errors.New("OTP expired or not found") - } - - if storedOTP != req.OTP { - return nil, errors.New("invalid OTP") - } - - if err := utils.DeleteData("otp:" + req.Phone); err != nil { - return nil, fmt.Errorf("failed to remove OTP from Redis: %w", err) - } - if err := utils.DeleteData("otp_sent:" + req.Phone); err != nil { - return nil, fmt.Errorf("failed to remove otp_sent from Redis: %w", err) - } - - existingUser, err := s.userRepo.GetUserByPhoneAndRole(req.Phone, "d7245535-0e9e-4d35-ab39-baece5c10b3c") - if err != nil { - return nil, fmt.Errorf("failed to check existing user: %w", err) - } - - var user *model.User - if existingUser != nil { - user = existingUser - } else { - - user = &model.User{ - Phone: req.Phone, - RoleID: "d7245535-0e9e-4d35-ab39-baece5c10b3c", - PhoneVerified: true, - RegistrationStatus: "uncompleted", - } - createdUser, err := s.userRepo.CreateUser(user) - if err != nil { - return nil, err - } - user = createdUser - } - - token, err := s.generateJWTToken(user.ID, req.DeviceID) - if err != nil { - return nil, err - } - - role, err := s.roleRepo.FindByID(user.RoleID) - if err != nil { - return nil, fmt.Errorf("failed to get role: %w", err) - } - - deviceID := req.DeviceID - if err := s.saveSessionData(user.ID, deviceID, user.RoleID, role.RoleName, token); err != nil { - return nil, err - } - - return &dto.UserDataResponse{ - UserID: user.ID, - UserRole: role.RoleName, - Token: token, - }, nil -} - -func (s *authPengepulService) saveSessionData(userID string, deviceID string, roleID string, roleName string, token string) error { - sessionKey := fmt.Sprintf("session:%s:%s", userID, deviceID) - sessionData := map[string]interface{}{ - "userID": userID, - "roleID": roleID, - "roleName": roleName, - } - - if err := utils.SetJSONData(sessionKey, sessionData, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session data: %w", err) - } - - if err := utils.SetStringData("session_token:"+userID+":"+deviceID, token, 24*time.Hour); err != nil { - return fmt.Errorf("failed to set session token: %w", err) - } - - return nil -} - -func (s *authPengepulService) Logout(userID, deviceID string) error { - - err := utils.DeleteSessionData(userID, deviceID) - if err != nil { - return fmt.Errorf("failed to delete session from Redis: %w", err) - } - - return nil -} - */ \ No newline at end of file diff --git a/internal/services/auth/otp.go b/internal/services/auth/otp.go deleted file mode 100644 index d96c534..0000000 --- a/internal/services/auth/otp.go +++ /dev/null @@ -1,14 +0,0 @@ -package service - -import ( - "fmt" - "math/rand" - "time" -) - -func generateOTP() string { - randGenerator := rand.New(rand.NewSource(time.Now().UnixNano())) - return fmt.Sprintf("%04d", randGenerator.Intn(10000)) -} - -const otpCooldown = 50 * time.Second diff --git a/internal/services/auth_service.go b/internal/services/auth_service.go deleted file mode 100644 index 47a733d..0000000 --- a/internal/services/auth_service.go +++ /dev/null @@ -1,213 +0,0 @@ -package services - -// import ( -// "errors" -// "fmt" -// "math/rand" -// "rijig/config" -// "rijig/dto" -// "rijig/internal/repositories" -// "rijig/model" -// "rijig/utils" -// "time" - -// "github.com/golang-jwt/jwt/v5" -// ) - -// const otpCooldown = 30 * time.Second - -// type AuthService interface { -// RegisterOrLogin(req *dto.RegisterRequest) error -// VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) -// Logout(userID, phone string) error -// } - -// type authService struct { -// userRepo repositories.UserRepository -// roleRepo repositories.RoleRepository -// } - -// func NewAuthService(userRepo repositories.UserRepository, roleRepo repositories.RoleRepository) AuthService { -// return &authService{userRepo, roleRepo} -// } - -// func (s *authService) RegisterOrLogin(req *dto.RegisterRequest) error { - -// if err := s.checkOTPRequestCooldown(req.Phone); err != nil { -// return err -// } - -// user, err := s.userRepo.GetUserByPhoneAndRole(req.Phone, req.RoleID) -// if err != nil { -// return fmt.Errorf("failed to check existing user: %w", err) -// } - -// if user != nil { -// return s.sendOTP(req.Phone) -// } - -// user = &model.User{ -// Phone: req.Phone, -// RoleID: req.RoleID, -// } - -// createdUser, err := s.userRepo.CreateUser(user) -// if err != nil { -// return fmt.Errorf("failed to create new user: %w", err) -// } - -// if err := s.saveUserToRedis(createdUser.ID, createdUser, req.Phone); err != nil { -// return err -// } - -// return s.sendOTP(req.Phone) -// } - -// func (s *authService) checkOTPRequestCooldown(phone string) error { -// otpSentTime, err := utils.GetStringData("otp_sent:" + phone) -// if err != nil || otpSentTime == "" { -// return nil -// } -// lastSent, _ := time.Parse(time.RFC3339, otpSentTime) -// if time.Since(lastSent) < otpCooldown { -// return errors.New("please wait before requesting a new OTP") -// } -// return nil -// } - -// func (s *authService) sendOTP(phone string) error { -// otp := generateOTP() -// if err := config.SendWhatsAppMessage(phone, fmt.Sprintf("Your OTP is: %s", otp)); err != nil { -// return err -// } - -// if err := utils.SetStringData("otp:"+phone, otp, 10*time.Minute); err != nil { -// return err -// } -// return utils.SetStringData("otp_sent:"+phone, time.Now().Format(time.RFC3339), 10*time.Minute) -// } - -// func (s *authService) VerifyOTP(req *dto.VerifyOTPRequest) (*dto.UserDataResponse, error) { - -// storedOTP, err := utils.GetStringData("otp:" + req.Phone) -// if err != nil || storedOTP == "" { -// return nil, errors.New("OTP expired or not found") -// } - -// if storedOTP != req.OTP { -// return nil, errors.New("invalid OTP") -// } - -// if err := utils.DeleteData("otp:" + req.Phone); err != nil { -// return nil, fmt.Errorf("failed to remove OTP from Redis: %w", err) -// } - -// existingUser, err := s.userRepo.GetUserByPhoneAndRole(req.Phone, req.RoleID) -// if err != nil { -// return nil, fmt.Errorf("failed to check existing user: %w", err) -// } - -// var user *model.User -// if existingUser != nil { -// user = existingUser -// } else { - -// user = &model.User{ -// Phone: req.Phone, -// RoleID: req.RoleID, -// } -// createdUser, err := s.userRepo.CreateUser(user) -// if err != nil { -// return nil, err -// } -// user = createdUser -// } - -// token, err := s.generateJWTToken(user.ID) -// if err != nil { -// return nil, err -// } - -// role, err := s.roleRepo.FindByID(user.RoleID) -// if err != nil { -// return nil, fmt.Errorf("failed to get role: %w", err) -// } - -// if err := s.saveSessionData(user.ID, user.RoleID, role.RoleName, token); err != nil { -// return nil, err -// } - -// return &dto.UserDataResponse{ -// UserID: user.ID, -// UserRole: role.RoleName, -// Token: token, -// }, nil -// } - -// func (s *authService) saveUserToRedis(userID string, user *model.User, phone string) error { -// if err := utils.SetJSONData("user:"+userID, user, 10*time.Minute); err != nil { -// return fmt.Errorf("failed to store user data in Redis: %w", err) -// } - -// if err := utils.SetStringData("user_phone:"+userID, phone, 10*time.Minute); err != nil { -// return fmt.Errorf("failed to store user phone in Redis: %w", err) -// } - -// return nil -// } - -// func (s *authService) generateJWTToken(userID string) (string, error) { -// expirationTime := time.Now().Add(24 * time.Hour) -// claims := &jwt.RegisteredClaims{ -// Subject: userID, -// ExpiresAt: jwt.NewNumericDate(expirationTime), -// } - -// token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) -// secretKey := config.GetSecretKey() - -// return token.SignedString([]byte(secretKey)) -// } - -// func (s *authService) saveSessionData(userID string, roleID string, roleName string, token string) error { -// sessionKey := fmt.Sprintf("session:%s", userID) -// sessionData := map[string]interface{}{ -// "userID": userID, -// "roleID": roleID, -// "roleName": roleName, -// } - -// if err := utils.SetJSONData(sessionKey, sessionData, 24*time.Hour); err != nil { -// return fmt.Errorf("failed to set session data: %w", err) -// } - -// if err := utils.SetStringData("session_token:"+userID, token, 24*time.Hour); err != nil { -// return fmt.Errorf("failed to set session token: %w", err) -// } - -// return nil -// } - -// func (s *authService) Logout(userID, phone string) error { -// keys := []string{ -// "session:" + userID, -// "session_token:" + userID, -// "user_logged_in:" + userID, -// "user:" + userID, -// "user_phone:" + userID, -// "otp_sent:" + phone, -// } - -// for _, key := range keys { -// if err := utils.DeleteData(key); err != nil { -// return fmt.Errorf("failed to delete key %s from Redis: %w", key, err) -// } -// } - -// return nil -// } - -// func generateOTP() string { -// randGenerator := rand.New(rand.NewSource(time.Now().UnixNano())) -// return fmt.Sprintf("%04d", randGenerator.Intn(10000)) -// } diff --git a/internal/services/banner_service.go b/internal/services/banner_service.go deleted file mode 100644 index 1b1b734..0000000 --- a/internal/services/banner_service.go +++ /dev/null @@ -1,366 +0,0 @@ -package services - -import ( - "fmt" - "mime/multipart" - "os" - "path/filepath" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "github.com/google/uuid" -) - -type BannerService interface { - CreateBanner(request dto.RequestBannerDTO, bannerImage *multipart.FileHeader) (*dto.ResponseBannerDTO, error) - GetAllBanners() ([]dto.ResponseBannerDTO, error) - GetBannerByID(id string) (*dto.ResponseBannerDTO, error) - UpdateBanner(id string, request dto.RequestBannerDTO, bannerImage *multipart.FileHeader) (*dto.ResponseBannerDTO, error) - DeleteBanner(id string) error -} - -type bannerService struct { - BannerRepo repositories.BannerRepository -} - -func NewBannerService(bannerRepo repositories.BannerRepository) BannerService { - return &bannerService{BannerRepo: bannerRepo} -} - -func (s *bannerService) saveBannerImage(bannerImage *multipart.FileHeader) (string, error) { - bannerImageDir := "./public" + os.Getenv("BASE_URL") + "/uploads/banners" - if _, err := os.Stat(bannerImageDir); os.IsNotExist(err) { - if err := os.MkdirAll(bannerImageDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for banner image: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true} - extension := filepath.Ext(bannerImage.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - bannerImageFileName := fmt.Sprintf("%s_banner%s", uuid.New().String(), extension) - bannerImagePath := filepath.Join(bannerImageDir, bannerImageFileName) - - src, err := bannerImage.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(bannerImagePath) - if err != nil { - return "", fmt.Errorf("failed to create banner image file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save banner image: %v", err) - } - - return bannerImagePath, nil -} - -func (s *bannerService) CreateBanner(request dto.RequestBannerDTO, bannerImage *multipart.FileHeader) (*dto.ResponseBannerDTO, error) { - - errors, valid := request.ValidateBannerInput() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - bannerImagePath, err := s.saveBannerImage(bannerImage) - if err != nil { - return nil, fmt.Errorf("failed to save banner image: %v", err) - } - - banner := model.Banner{ - BannerName: request.BannerName, - BannerImage: bannerImagePath, - } - - if err := s.BannerRepo.CreateBanner(&banner); err != nil { - return nil, fmt.Errorf("failed to create banner: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(banner.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(banner.UpdatedAt) - - bannerResponseDTO := &dto.ResponseBannerDTO{ - ID: banner.ID, - BannerName: banner.BannerName, - BannerImage: banner.BannerImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - articlesCacheKey := "banners:all" - err = utils.DeleteData(articlesCacheKey) - if err != nil { - fmt.Printf("Error deleting cache for all banners: %v\n", err) - } - - cacheKey := fmt.Sprintf("banner:%s", banner.ID) - cacheData := map[string]interface{}{ - "data": bannerResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching banner: %v\n", err) - } - - banners, err := s.BannerRepo.FindAllBanners() - if err == nil { - var bannersDTO []dto.ResponseBannerDTO - for _, b := range banners { - createdAt, _ := utils.FormatDateToIndonesianFormat(b.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(b.UpdatedAt) - - bannersDTO = append(bannersDTO, dto.ResponseBannerDTO{ - ID: b.ID, - BannerName: b.BannerName, - BannerImage: b.BannerImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData = map[string]interface{}{ - "data": bannersDTO, - } - if err := utils.SetJSONData(articlesCacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching updated banners to Redis: %v\n", err) - } - } else { - fmt.Printf("Error fetching all banners: %v\n", err) - } - - return bannerResponseDTO, nil -} - -func (s *bannerService) GetAllBanners() ([]dto.ResponseBannerDTO, error) { - var banners []dto.ResponseBannerDTO - - cacheKey := "banners:all" - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - if bannerData, ok := item.(map[string]interface{}); ok { - banners = append(banners, dto.ResponseBannerDTO{ - ID: bannerData["id"].(string), - BannerName: bannerData["bannername"].(string), - BannerImage: bannerData["bannerimage"].(string), - CreatedAt: bannerData["createdAt"].(string), - UpdatedAt: bannerData["updatedAt"].(string), - }) - } - } - return banners, nil - } - } - - records, err := s.BannerRepo.FindAllBanners() - if err != nil { - return nil, fmt.Errorf("failed to fetch banners: %v", err) - } - - for _, record := range records { - createdAt, _ := utils.FormatDateToIndonesianFormat(record.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(record.UpdatedAt) - - banners = append(banners, dto.ResponseBannerDTO{ - ID: record.ID, - BannerName: record.BannerName, - BannerImage: record.BannerImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData := map[string]interface{}{ - "data": banners, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching banners: %v\n", err) - } - - return banners, nil -} - -func (s *bannerService) GetBannerByID(id string) (*dto.ResponseBannerDTO, error) { - - cacheKey := fmt.Sprintf("banner:%s", id) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - if data, ok := cachedData["data"].(map[string]interface{}); ok { - return &dto.ResponseBannerDTO{ - ID: data["id"].(string), - BannerName: data["bannername"].(string), - BannerImage: data["bannerimage"].(string), - CreatedAt: data["createdAt"].(string), - UpdatedAt: data["updatedAt"].(string), - }, nil - } - } - - banner, err := s.BannerRepo.FindBannerByID(id) - if err != nil { - - return nil, fmt.Errorf("banner with ID %s not found", id) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(banner.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(banner.UpdatedAt) - - bannerResponseDTO := &dto.ResponseBannerDTO{ - ID: banner.ID, - BannerName: banner.BannerName, - BannerImage: banner.BannerImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheData := map[string]interface{}{ - "data": bannerResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching banner: %v\n", err) - } - - return bannerResponseDTO, nil -} - -func (s *bannerService) UpdateBanner(id string, request dto.RequestBannerDTO, bannerImage *multipart.FileHeader) (*dto.ResponseBannerDTO, error) { - - banner, err := s.BannerRepo.FindBannerByID(id) - if err != nil { - - return nil, fmt.Errorf("banner with ID %s not found", id) - } - - var oldImagePath string - if bannerImage != nil { - - bannerImagePath, err := s.saveBannerImage(bannerImage) - if err != nil { - return nil, fmt.Errorf("failed to save banner image: %v", err) - } - - oldImagePath = banner.BannerImage - banner.BannerImage = bannerImagePath - } - - banner.BannerName = request.BannerName - - if err := s.BannerRepo.UpdateBanner(id, banner); err != nil { - return nil, fmt.Errorf("failed to update banner: %v", err) - } - - if oldImagePath != "" { - err := os.Remove(oldImagePath) - if err != nil { - fmt.Printf("Failed to delete old banner image: %v\n", err) - } - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(banner.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(banner.UpdatedAt) - - bannerResponseDTO := &dto.ResponseBannerDTO{ - ID: banner.ID, - BannerName: banner.BannerName, - BannerImage: banner.BannerImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("banner:%s", id) - err = utils.DeleteData(cacheKey) - if err != nil { - fmt.Printf("Error deleting cache for banner: %v\n", err) - } - - cacheData := map[string]interface{}{ - "data": bannerResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching updated banner: %v\n", err) - } - - articlesCacheKey := "banners:all" - err = utils.DeleteData(articlesCacheKey) - if err != nil { - fmt.Printf("Error deleting cache for all banners: %v\n", err) - } - - banners, err := s.BannerRepo.FindAllBanners() - if err == nil { - var bannersDTO []dto.ResponseBannerDTO - for _, b := range banners { - createdAt, _ := utils.FormatDateToIndonesianFormat(b.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(b.UpdatedAt) - - bannersDTO = append(bannersDTO, dto.ResponseBannerDTO{ - ID: b.ID, - BannerName: b.BannerName, - BannerImage: b.BannerImage, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData = map[string]interface{}{ - "data": bannersDTO, - } - if err := utils.SetJSONData(articlesCacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching updated banners to Redis: %v\n", err) - } - } else { - fmt.Printf("Error fetching all banners: %v\n", err) - } - - return bannerResponseDTO, nil -} - -func (s *bannerService) DeleteBanner(id string) error { - - banner, err := s.BannerRepo.FindBannerByID(id) - if err != nil { - - return fmt.Errorf("banner with ID %s not found", id) - } - - if banner.BannerImage != "" { - err := os.Remove(banner.BannerImage) - if err != nil { - - fmt.Printf("Failed to delete banner image: %v\n", err) - } else { - fmt.Printf("Successfully deleted banner image: %s\n", banner.BannerImage) - } - } - - if err := s.BannerRepo.DeleteBanner(id); err != nil { - return fmt.Errorf("failed to delete banner from database: %v", err) - } - - cacheKey := fmt.Sprintf("banner:%s", banner.ID) - err = utils.DeleteData(cacheKey) - if err != nil { - fmt.Printf("Error deleting cache for banner: %v\n", err) - } - - articlesCacheKey := "banners:all" - err = utils.DeleteData(articlesCacheKey) - if err != nil { - fmt.Printf("Error deleting cache for all banners: %v\n", err) - } - - return nil -} diff --git a/internal/services/cart_redis.go b/internal/services/cart_redis.go deleted file mode 100644 index 80b0aae..0000000 --- a/internal/services/cart_redis.go +++ /dev/null @@ -1,73 +0,0 @@ -package services - -import ( - "context" - "encoding/json" - "fmt" - "time" - - "rijig/config" - "rijig/dto" - - "github.com/go-redis/redis/v8" -) - -const CartTTL = 30 * time.Minute -const CartKeyPrefix = "cart:" - -func buildCartKey(userID string) string { - return fmt.Sprintf("%s%s", CartKeyPrefix, userID) -} - -func SetCartToRedis(ctx context.Context, userID string, cart dto.RequestCartDTO) error { - data, err := json.Marshal(cart) - if err != nil { - return err - } - - return config.RedisClient.Set(ctx, buildCartKey(userID), data, CartTTL).Err() -} - -func RefreshCartTTL(ctx context.Context, userID string) error { - return config.RedisClient.Expire(ctx, buildCartKey(userID), CartTTL).Err() -} - -func GetCartFromRedis(ctx context.Context, userID string) (*dto.RequestCartDTO, error) { - val, err := config.RedisClient.Get(ctx, buildCartKey(userID)).Result() - if err == redis.Nil { - return nil, nil - } else if err != nil { - return nil, err - } - - var cart dto.RequestCartDTO - if err := json.Unmarshal([]byte(val), &cart); err != nil { - return nil, err - } - return &cart, nil -} - -func DeleteCartFromRedis(ctx context.Context, userID string) error { - return config.RedisClient.Del(ctx, buildCartKey(userID)).Err() -} - -func GetExpiringCartKeys(ctx context.Context, threshold time.Duration) ([]string, error) { - keys, err := config.RedisClient.Keys(ctx, CartKeyPrefix+"*").Result() - if err != nil { - return nil, err - } - - var expiringKeys []string - for _, key := range keys { - ttl, err := config.RedisClient.TTL(ctx, key).Result() - if err != nil { - continue - } - - if ttl > 0 && ttl <= threshold { - expiringKeys = append(expiringKeys, key) - } - } - - return expiringKeys, nil -} diff --git a/internal/services/cart_service.go b/internal/services/cart_service.go deleted file mode 100644 index 3a905dc..0000000 --- a/internal/services/cart_service.go +++ /dev/null @@ -1,266 +0,0 @@ -package services - -import ( - "context" - "errors" - "log" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" -) - -type CartService interface { - AddOrUpdateItem(ctx context.Context, userID string, req dto.RequestCartItemDTO) error - GetCart(ctx context.Context, userID string) (*dto.ResponseCartDTO, error) - DeleteItem(ctx context.Context, userID string, trashID string) error - ClearCart(ctx context.Context, userID string) error - Checkout(ctx context.Context, userID string) error -} - -type cartService struct { - repo repositories.CartRepository - trashRepo repositories.TrashRepository -} - -func NewCartService(repo repositories.CartRepository, trashRepo repositories.TrashRepository) CartService { - return &cartService{repo: repo, trashRepo: trashRepo} -} - -func (s *cartService) AddOrUpdateItem(ctx context.Context, userID string, req dto.RequestCartItemDTO) error { - if req.Amount <= 0 { - return errors.New("amount harus lebih dari 0") - } - - _, err := s.trashRepo.GetTrashCategoryByID(ctx, req.TrashID) - if err != nil { - return err - } - - existingCart, err := GetCartFromRedis(ctx, userID) - if err != nil { - return err - } - - if existingCart == nil { - existingCart = &dto.RequestCartDTO{ - CartItems: []dto.RequestCartItemDTO{}, - } - } - - updated := false - for i, item := range existingCart.CartItems { - if item.TrashID == req.TrashID { - existingCart.CartItems[i].Amount = req.Amount - updated = true - break - } - } - - if !updated { - existingCart.CartItems = append(existingCart.CartItems, dto.RequestCartItemDTO{ - TrashID: req.TrashID, - Amount: req.Amount, - }) - } - - return SetCartToRedis(ctx, userID, *existingCart) -} - -func (s *cartService) GetCart(ctx context.Context, userID string) (*dto.ResponseCartDTO, error) { - - cached, err := GetCartFromRedis(ctx, userID) - if err != nil { - return nil, err - } - - if cached != nil { - - if err := RefreshCartTTL(ctx, userID); err != nil { - log.Printf("Warning: Failed to refresh cart TTL for user %s: %v", userID, err) - } - - return s.buildResponseFromCache(ctx, userID, cached) - } - - cart, err := s.repo.GetCartByUser(ctx, userID) - if err != nil { - - return &dto.ResponseCartDTO{ - ID: "", - UserID: userID, - TotalAmount: 0, - EstimatedTotalPrice: 0, - CartItems: []dto.ResponseCartItemDTO{}, - }, nil - - } - - response := s.buildResponseFromDB(cart) - - cacheData := dto.RequestCartDTO{CartItems: []dto.RequestCartItemDTO{}} - for _, item := range cart.CartItems { - cacheData.CartItems = append(cacheData.CartItems, dto.RequestCartItemDTO{ - TrashID: item.TrashCategoryID, - Amount: item.Amount, - }) - } - - if err := SetCartToRedis(ctx, userID, cacheData); err != nil { - log.Printf("Warning: Failed to cache cart for user %s: %v", userID, err) - } - - return response, nil -} - -func (s *cartService) DeleteItem(ctx context.Context, userID string, trashID string) error { - - existingCart, err := GetCartFromRedis(ctx, userID) - if err != nil { - return err - } - if existingCart == nil { - return errors.New("keranjang tidak ditemukan") - } - - filtered := []dto.RequestCartItemDTO{} - for _, item := range existingCart.CartItems { - if item.TrashID != trashID { - filtered = append(filtered, item) - } - } - existingCart.CartItems = filtered - - return SetCartToRedis(ctx, userID, *existingCart) -} - -func (s *cartService) ClearCart(ctx context.Context, userID string) error { - - if err := DeleteCartFromRedis(ctx, userID); err != nil { - return err - } - - return s.repo.DeleteCart(ctx, userID) -} - -func (s *cartService) Checkout(ctx context.Context, userID string) error { - - cachedCart, err := GetCartFromRedis(ctx, userID) - if err != nil { - return err - } - - if cachedCart != nil { - if err := s.commitCartFromRedis(ctx, userID, cachedCart); err != nil { - return err - } - } - - _, err = s.repo.GetCartByUser(ctx, userID) - if err != nil { - return err - } - - DeleteCartFromRedis(ctx, userID) - return s.repo.DeleteCart(ctx, userID) -} - -func (s *cartService) buildResponseFromCache(ctx context.Context, userID string, cached *dto.RequestCartDTO) (*dto.ResponseCartDTO, error) { - totalQty := 0.0 - totalPrice := 0.0 - items := []dto.ResponseCartItemDTO{} - - for _, item := range cached.CartItems { - trash, err := s.trashRepo.GetTrashCategoryByID(ctx, item.TrashID) - if err != nil { - log.Printf("Warning: Trash category %s not found for cached cart item", item.TrashID) - continue - } - - subtotal := item.Amount * trash.EstimatedPrice - totalQty += item.Amount - totalPrice += subtotal - - items = append(items, dto.ResponseCartItemDTO{ - ID: "", - TrashID: item.TrashID, - TrashName: trash.Name, - TrashIcon: trash.Icon, - TrashPrice: trash.EstimatedPrice, - Amount: item.Amount, - SubTotalEstimatedPrice: subtotal, - }) - } - - return &dto.ResponseCartDTO{ - ID: "-", - UserID: userID, - TotalAmount: totalQty, - EstimatedTotalPrice: totalPrice, - CartItems: items, - }, nil -} - -func (s *cartService) buildResponseFromDB(cart *model.Cart) *dto.ResponseCartDTO { - var items []dto.ResponseCartItemDTO - for _, item := range cart.CartItems { - items = append(items, dto.ResponseCartItemDTO{ - ID: item.ID, - TrashID: item.TrashCategoryID, - TrashName: item.TrashCategory.Name, - TrashIcon: item.TrashCategory.Icon, - TrashPrice: item.TrashCategory.EstimatedPrice, - Amount: item.Amount, - SubTotalEstimatedPrice: item.SubTotalEstimatedPrice, - }) - } - - return &dto.ResponseCartDTO{ - ID: cart.ID, - UserID: cart.UserID, - TotalAmount: cart.TotalAmount, - EstimatedTotalPrice: cart.EstimatedTotalPrice, - CartItems: items, - } -} - -func (s *cartService) commitCartFromRedis(ctx context.Context, userID string, cachedCart *dto.RequestCartDTO) error { - if len(cachedCart.CartItems) == 0 { - return nil - } - - totalAmount := 0.0 - totalPrice := 0.0 - var cartItems []model.CartItem - - for _, item := range cachedCart.CartItems { - trash, err := s.trashRepo.GetTrashCategoryByID(ctx, item.TrashID) - if err != nil { - log.Printf("Warning: Skipping invalid trash category %s during commit", item.TrashID) - continue - } - - subtotal := item.Amount * trash.EstimatedPrice - totalAmount += item.Amount - totalPrice += subtotal - - cartItems = append(cartItems, model.CartItem{ - TrashCategoryID: item.TrashID, - Amount: item.Amount, - SubTotalEstimatedPrice: subtotal, - }) - } - - if len(cartItems) == 0 { - return nil - } - - newCart := &model.Cart{ - UserID: userID, - TotalAmount: totalAmount, - EstimatedTotalPrice: totalPrice, - CartItems: cartItems, - } - - return s.repo.CreateCartWithItems(ctx, newCart) -} diff --git a/internal/services/collector_service.go b/internal/services/collector_service.go deleted file mode 100644 index 0984d31..0000000 --- a/internal/services/collector_service.go +++ /dev/null @@ -1,224 +0,0 @@ -package services - -import ( - "context" - "errors" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" -) - -type CollectorService interface { - CreateCollector(ctx context.Context, userID string, req dto.RequestCollectorDTO) error - AddTrashToCollector(ctx context.Context, collectorID string, req dto.RequestAddAvaibleTrash) error - GetCollectorByID(ctx context.Context, collectorID string) (*dto.ResponseCollectorDTO, error) - GetCollectorByUserID(ctx context.Context, userID string) (*dto.ResponseCollectorDTO, error) - UpdateCollector(ctx context.Context, collectorID string, jobStatus *string, rating float32, addressID string) error - UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []dto.RequestAvaibleTrashbyCollector) error - DeleteAvaibleTrash(ctx context.Context, trashID string) error -} - -type collectorService struct { - repo repositories.CollectorRepository - trashRepo repositories.TrashRepository -} - -func NewCollectorService(repo repositories.CollectorRepository, trashRepo repositories.TrashRepository, - -) CollectorService { - - return &collectorService{repo: repo, trashRepo: trashRepo} -} - -func (s *collectorService) CreateCollector(ctx context.Context, userID string, req dto.RequestCollectorDTO) error { - collector := &model.Collector{ - UserID: userID, - AddressID: req.AddressId, - JobStatus: "inactive", - Rating: 5, - } - - if err := s.repo.CreateCollector(ctx, collector); err != nil { - return err - } - - var trashItems []model.AvaibleTrashByCollector - for _, item := range req.AvaibleTrashbyCollector { - trashItems = append(trashItems, model.AvaibleTrashByCollector{ - CollectorID: collector.ID, - TrashCategoryID: item.TrashId, - Price: item.TrashPrice, - }) - } - - if err := s.repo.AddAvaibleTrash(ctx, trashItems); err != nil { - return err - } - - for _, t := range trashItems { - _ = s.trashRepo.UpdateEstimatedPrice(ctx, t.TrashCategoryID) - } - - return nil -} - -func (s *collectorService) AddTrashToCollector(ctx context.Context, collectorID string, req dto.RequestAddAvaibleTrash) error { - var trashItems []model.AvaibleTrashByCollector - for _, item := range req.AvaibleTrash { - trashItems = append(trashItems, model.AvaibleTrashByCollector{ - CollectorID: collectorID, - TrashCategoryID: item.TrashId, - Price: item.TrashPrice, - }) - } - if err := s.repo.AddAvaibleTrash(ctx, trashItems); err != nil { - return err - } - - for _, t := range trashItems { - _ = s.trashRepo.UpdateEstimatedPrice(ctx, t.TrashCategoryID) - } - - return nil -} - -func (s *collectorService) GetCollectorByID(ctx context.Context, collectorID string) (*dto.ResponseCollectorDTO, error) { - collector, err := s.repo.GetCollectorByID(ctx, collectorID) - if err != nil { - return nil, err - } - - response := &dto.ResponseCollectorDTO{ - ID: collector.ID, - UserId: collector.UserID, - AddressId: collector.AddressID, - JobStatus: &collector.JobStatus, - Rating: collector.Rating, - User: &dto.UserResponseDTO{ - ID: collector.User.ID, - Name: collector.User.Name, - Phone: collector.User.Phone, - }, - Address: &dto.AddressResponseDTO{ - Province: collector.Address.Province, - District: collector.Address.District, - Regency: collector.Address.Regency, - Village: collector.Address.Village, - PostalCode: collector.Address.PostalCode, - Latitude: collector.Address.Latitude, - Longitude: collector.Address.Longitude, - }, - } - - for _, item := range collector.AvaibleTrashByCollector { - response.AvaibleTrashbyCollector = append(response.AvaibleTrashbyCollector, dto.ResponseAvaibleTrashByCollector{ - ID: item.ID, - TrashId: item.TrashCategory.ID, - TrashName: item.TrashCategory.Name, - TrashIcon: item.TrashCategory.Icon, - TrashPrice: item.Price, - }) - } - - return response, nil -} - -func (s *collectorService) GetCollectorByUserID(ctx context.Context, userID string) (*dto.ResponseCollectorDTO, error) { - collector, err := s.repo.GetCollectorByUserID(ctx, userID) - if err != nil { - return nil, err - } - - response := &dto.ResponseCollectorDTO{ - ID: collector.ID, - UserId: collector.UserID, - AddressId: collector.AddressID, - JobStatus: &collector.JobStatus, - Rating: collector.Rating, - User: &dto.UserResponseDTO{ - ID: collector.User.ID, - Name: collector.User.Name, - Phone: collector.User.Phone, - }, - Address: &dto.AddressResponseDTO{ - Province: collector.Address.Province, - District: collector.Address.District, - Regency: collector.Address.Regency, - Village: collector.Address.Village, - PostalCode: collector.Address.PostalCode, - Latitude: collector.Address.Latitude, - Longitude: collector.Address.Longitude, - }, - } - - for _, item := range collector.AvaibleTrashByCollector { - response.AvaibleTrashbyCollector = append(response.AvaibleTrashbyCollector, dto.ResponseAvaibleTrashByCollector{ - ID: item.ID, - TrashId: item.TrashCategory.ID, - TrashName: item.TrashCategory.Name, - TrashIcon: item.TrashCategory.Icon, - TrashPrice: item.Price, - }) - } - - return response, nil -} - -func (s *collectorService) UpdateCollector(ctx context.Context, collectorID string, jobStatus *string, rating float32, addressID string) error { - updates := make(map[string]interface{}) - - if jobStatus != nil { - updates["job_status"] = *jobStatus - } - if rating > 0 { - updates["rating"] = rating - } - if addressID != "" { - updates["address_id"] = addressID - } - - if len(updates) == 0 { - return errors.New("tidak ada data yang diubah") - } - - return s.repo.UpdateCollector(ctx, &model.Collector{ID: collectorID}, updates) -} - -func (s *collectorService) UpdateAvaibleTrashByCollector(ctx context.Context, collectorID string, updatedTrash []dto.RequestAvaibleTrashbyCollector) error { - var updated []model.AvaibleTrashByCollector - for _, item := range updatedTrash { - updated = append(updated, model.AvaibleTrashByCollector{ - CollectorID: collectorID, - TrashCategoryID: item.TrashId, - Price: item.TrashPrice, - }) - } - - if err := s.repo.UpdateAvaibleTrashByCollector(ctx, collectorID, updated); err != nil { - return err - } - - for _, item := range updated { - _ = s.trashRepo.UpdateEstimatedPrice(ctx, item.TrashCategoryID) - } - - return nil -} - -func (s *collectorService) DeleteAvaibleTrash(ctx context.Context, trashID string) error { - if trashID == "" { - return errors.New("trash_id tidak boleh kosong") - } - - item, err := s.repo.GetTrashItemByID(ctx, trashID) - if err != nil { - return err - } - - if err := s.repo.DeleteAvaibleTrash(ctx, trashID); err != nil { - return err - } - - return s.trashRepo.UpdateEstimatedPrice(ctx, item.TrashCategoryID) -} diff --git a/internal/services/company_profile_service.go b/internal/services/company_profile_service.go deleted file mode 100644 index 6c2714b..0000000 --- a/internal/services/company_profile_service.go +++ /dev/null @@ -1,163 +0,0 @@ -package services - -import ( - "fmt" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type CompanyProfileService interface { - CreateCompanyProfile(userID string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) - GetCompanyProfileByID(id string) (*dto.ResponseCompanyProfileDTO, error) - GetCompanyProfilesByUserID(userID string) ([]dto.ResponseCompanyProfileDTO, error) - UpdateCompanyProfile(id string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) - DeleteCompanyProfile(id string) error -} - -type companyProfileService struct { - companyProfileRepo repositories.CompanyProfileRepository -} - -func NewCompanyProfileService(companyProfileRepo repositories.CompanyProfileRepository) CompanyProfileService { - return &companyProfileService{ - companyProfileRepo: companyProfileRepo, - } -} - -func FormatResponseCompanyProfile(companyProfile *model.CompanyProfile) (*dto.ResponseCompanyProfileDTO, error) { - - createdAt, _ := utils.FormatDateToIndonesianFormat(companyProfile.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(companyProfile.UpdatedAt) - - responseDTO := &dto.ResponseCompanyProfileDTO{ - ID: companyProfile.ID, - UserID: companyProfile.UserID, - CompanyName: companyProfile.CompanyName, - CompanyAddress: companyProfile.CompanyAddress, - CompanyPhone: companyProfile.CompanyPhone, - CompanyEmail: companyProfile.CompanyEmail, - CompanyLogo: companyProfile.CompanyLogo, - CompanyWebsite: companyProfile.CompanyWebsite, - TaxID: companyProfile.TaxID, - FoundedDate: companyProfile.FoundedDate, - CompanyType: companyProfile.CompanyType, - CompanyDescription: companyProfile.CompanyDescription, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return responseDTO, nil -} - -func (s *companyProfileService) CreateCompanyProfile(userID string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) { - - errors, valid := request.ValidateCompanyProfileInput() - if !valid { - return nil, fmt.Errorf("validation failed: %v", errors) - } - - companyProfile := &model.CompanyProfile{ - UserID: userID, - CompanyName: request.CompanyName, - CompanyAddress: request.CompanyAddress, - CompanyPhone: request.CompanyPhone, - CompanyEmail: request.CompanyEmail, - CompanyLogo: request.CompanyLogo, - CompanyWebsite: request.CompanyWebsite, - TaxID: request.TaxID, - FoundedDate: request.FoundedDate, - CompanyType: request.CompanyType, - CompanyDescription: request.CompanyDescription, - } - - createdCompanyProfile, err := s.companyProfileRepo.CreateCompanyProfile(companyProfile) - if err != nil { - return nil, fmt.Errorf("failed to create company profile: %v", err) - } - - responseDTO, err := FormatResponseCompanyProfile(createdCompanyProfile) - if err != nil { - return nil, fmt.Errorf("failed to format company profile response: %v", err) - } - - return responseDTO, nil -} - -func (s *companyProfileService) GetCompanyProfileByID(id string) (*dto.ResponseCompanyProfileDTO, error) { - - companyProfile, err := s.companyProfileRepo.GetCompanyProfileByID(id) - if err != nil { - return nil, fmt.Errorf("error retrieving company profile by ID: %v", err) - } - - responseDTO, err := FormatResponseCompanyProfile(companyProfile) - if err != nil { - return nil, fmt.Errorf("error formatting company profile response: %v", err) - } - - return responseDTO, nil -} - -func (s *companyProfileService) GetCompanyProfilesByUserID(userID string) ([]dto.ResponseCompanyProfileDTO, error) { - - companyProfiles, err := s.companyProfileRepo.GetCompanyProfilesByUserID(userID) - if err != nil { - return nil, fmt.Errorf("error retrieving company profiles by userID: %v", err) - } - - var responseDTOs []dto.ResponseCompanyProfileDTO - for _, companyProfile := range companyProfiles { - responseDTO, err := FormatResponseCompanyProfile(&companyProfile) - if err != nil { - return nil, fmt.Errorf("error formatting company profile response: %v", err) - } - responseDTOs = append(responseDTOs, *responseDTO) - } - - return responseDTOs, nil -} - -func (s *companyProfileService) UpdateCompanyProfile(id string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) { - - errors, valid := request.ValidateCompanyProfileInput() - if !valid { - return nil, fmt.Errorf("validation failed: %v", errors) - } - - companyProfile := &model.CompanyProfile{ - CompanyName: request.CompanyName, - CompanyAddress: request.CompanyAddress, - CompanyPhone: request.CompanyPhone, - CompanyEmail: request.CompanyEmail, - CompanyLogo: request.CompanyLogo, - CompanyWebsite: request.CompanyWebsite, - TaxID: request.TaxID, - FoundedDate: request.FoundedDate, - CompanyType: request.CompanyType, - CompanyDescription: request.CompanyDescription, - } - - updatedCompanyProfile, err := s.companyProfileRepo.UpdateCompanyProfile(id, companyProfile) - if err != nil { - return nil, fmt.Errorf("failed to update company profile: %v", err) - } - - responseDTO, err := FormatResponseCompanyProfile(updatedCompanyProfile) - if err != nil { - return nil, fmt.Errorf("failed to format company profile response: %v", err) - } - - return responseDTO, nil -} - -func (s *companyProfileService) DeleteCompanyProfile(id string) error { - - err := s.companyProfileRepo.DeleteCompanyProfile(id) - if err != nil { - return fmt.Errorf("failed to delete company profile: %v", err) - } - - return nil -} diff --git a/internal/services/coveragearea_service.go b/internal/services/coveragearea_service.go deleted file mode 100644 index 1a0f522..0000000 --- a/internal/services/coveragearea_service.go +++ /dev/null @@ -1,155 +0,0 @@ -package services - -import ( - "fmt" - "log" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type CoverageAreaService interface { - CreateCoverageArea(request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) - GetCoverageAreaByID(id string) (*dto.ResponseCoverageArea, error) - GetAllCoverageAreas() ([]dto.ResponseCoverageArea, error) - UpdateCoverageArea(id string, request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) - DeleteCoverageArea(id string) error -} - -type coverageAreaService struct { - repo repositories.CoverageAreaRepository - WilayahRepo repositories.WilayahIndonesiaRepository -} - -func NewCoverageAreaService(repo repositories.CoverageAreaRepository, WilayahRepo repositories.WilayahIndonesiaRepository) CoverageAreaService { - return &coverageAreaService{repo: repo, WilayahRepo: WilayahRepo} -} - -func ConvertCoverageAreaToResponse(coverage *model.CoverageArea) *dto.ResponseCoverageArea { - createdAt, _ := utils.FormatDateToIndonesianFormat(coverage.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(coverage.UpdatedAt) - - return &dto.ResponseCoverageArea{ - ID: coverage.ID, - Province: coverage.Province, - Regency: coverage.Regency, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} - -func (s *coverageAreaService) CreateCoverageArea(request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) { - errors, valid := request.ValidateCoverageArea() - if !valid { - return nil, fmt.Errorf("validation errors: %v", errors) - } - - province, _, err := s.WilayahRepo.FindProvinceByID(request.Province, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid province_id") - } - - regency, _, err := s.WilayahRepo.FindRegencyByID(request.Regency, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid regency_id") - } - - existingCoverage, err := s.repo.FindCoverageByProvinceAndRegency(province.Name, regency.Name) - if err == nil && existingCoverage != nil { - return nil, fmt.Errorf("coverage area with province %s and regency %s already exists", province.Name, regency.Name) - } - - coverage := model.CoverageArea{ - Province: province.Name, - Regency: regency.Name, - } - - if err := s.repo.CreateCoverage(&coverage); err != nil { - return nil, fmt.Errorf("failed to create coverage area: %v", err) - } - - response := ConvertCoverageAreaToResponse(&coverage) - - return response, nil -} - -func (s *coverageAreaService) GetCoverageAreaByID(id string) (*dto.ResponseCoverageArea, error) { - coverage, err := s.repo.FindCoverageById(id) - if err != nil { - return nil, err - } - - response := ConvertCoverageAreaToResponse(coverage) - - return response, nil -} - -func (s *coverageAreaService) GetAllCoverageAreas() ([]dto.ResponseCoverageArea, error) { - coverageAreas, err := s.repo.FindAllCoverage() - if err != nil { - return nil, err - } - - var response []dto.ResponseCoverageArea - for _, coverage := range coverageAreas { - - response = append(response, *ConvertCoverageAreaToResponse(&coverage)) - } - - return response, nil -} - -func (s *coverageAreaService) UpdateCoverageArea(id string, request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) { - - errors, valid := request.ValidateCoverageArea() - if !valid { - return nil, fmt.Errorf("validation errors: %v", errors) - } - - coverage, err := s.repo.FindCoverageById(id) - if err != nil { - return nil, fmt.Errorf("coverage area with ID %s not found: %v", id, err) - } - - province, _, err := s.WilayahRepo.FindProvinceByID(request.Province, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid province_id") - } - - regency, _, err := s.WilayahRepo.FindRegencyByID(request.Regency, 0, 0) - if err != nil { - return nil, fmt.Errorf("invalid regency_id") - } - - existingCoverage, err := s.repo.FindCoverageByProvinceAndRegency(province.Name, regency.Name) - if err == nil && existingCoverage != nil { - return nil, fmt.Errorf("coverage area with province %s and regency %s already exists", province.Name, regency.Name) - } - - coverage.Province = province.Name - coverage.Regency = regency.Name - - if err := s.repo.UpdateCoverage(id, coverage); err != nil { - return nil, fmt.Errorf("failed to update coverage area: %v", err) - } - - response := ConvertCoverageAreaToResponse(coverage) - - return response, nil -} - -func (s *coverageAreaService) DeleteCoverageArea(id string) error { - - coverage, err := s.repo.FindCoverageById(id) - if err != nil { - return fmt.Errorf("coverage area with ID %s not found: %v", id, err) - } - - if err := s.repo.DeleteCoverage(id); err != nil { - return fmt.Errorf("failed to delete coverage area: %v", err) - } - - log.Printf("Coverage area with ID %s successfully deleted", coverage.ID) - return nil -} diff --git a/internal/services/identitycard_service.go b/internal/services/identitycard_service.go deleted file mode 100644 index b2435cd..0000000 --- a/internal/services/identitycard_service.go +++ /dev/null @@ -1,289 +0,0 @@ -package services - -import ( - "fmt" - "log" - "mime/multipart" - "os" - "path/filepath" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type IdentityCardService interface { - CreateIdentityCard(userID string, request *dto.RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*dto.ResponseIdentityCardDTO, error) - GetIdentityCardByID(id string) (*dto.ResponseIdentityCardDTO, error) - GetIdentityCardsByUserID(userID string) ([]dto.ResponseIdentityCardDTO, error) - UpdateIdentityCard(userID string, id string, request *dto.RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*dto.ResponseIdentityCardDTO, error) - DeleteIdentityCard(id string) error -} - -type identityCardService struct { - identityCardRepo repositories.IdentityCardRepository - userRepo repositories.UserProfilRepository -} - -func NewIdentityCardService(identityCardRepo repositories.IdentityCardRepository, userRepo repositories.UserProfilRepository) IdentityCardService { - return &identityCardService{ - identityCardRepo: identityCardRepo, - userRepo: userRepo, - } -} - -func FormatResponseIdentityCars(identityCard *model.IdentityCard) (*dto.ResponseIdentityCardDTO, error) { - - createdAt, _ := utils.FormatDateToIndonesianFormat(identityCard.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(identityCard.UpdatedAt) - - idcardResponseDTO := &dto.ResponseIdentityCardDTO{ - ID: identityCard.ID, - UserID: identityCard.UserID, - Identificationumber: identityCard.Identificationumber, - Placeofbirth: identityCard.Placeofbirth, - Dateofbirth: identityCard.Dateofbirth, - Gender: identityCard.Gender, - BloodType: identityCard.BloodType, - District: identityCard.District, - Village: identityCard.Village, - Neighbourhood: identityCard.Neighbourhood, - Religion: identityCard.Religion, - Maritalstatus: identityCard.Maritalstatus, - Job: identityCard.Job, - Citizenship: identityCard.Citizenship, - Validuntil: identityCard.Validuntil, - Cardphoto: identityCard.Cardphoto, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return idcardResponseDTO, nil -} - -func (s *identityCardService) saveIdentityCardImage(userID string, cardPhoto *multipart.FileHeader) (string, error) { - pathImage := "/uploads/identitycards/" - cardPhotoDir := "./public" + os.Getenv("BASE_URL") + pathImage - if _, err := os.Stat(cardPhotoDir); os.IsNotExist(err) { - - if err := os.MkdirAll(cardPhotoDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for identity card photo: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true} - extension := filepath.Ext(cardPhoto.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - cardPhotoFileName := fmt.Sprintf("%s_cardphoto%s", userID, extension) - cardPhotoPath := filepath.Join(cardPhotoDir, cardPhotoFileName) - - src, err := cardPhoto.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(cardPhotoPath) - if err != nil { - return "", fmt.Errorf("failed to create card photo file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save card photo: %v", err) - } - - cardPhotoURL := fmt.Sprintf("%s%s", pathImage, cardPhotoFileName) - - return cardPhotoURL, nil -} - -func deleteIdentityCardImage(imagePath string) error { - if imagePath == "" { - return nil - } - - baseDir := "./public/" + os.Getenv("BASE_URL") - absolutePath := baseDir + imagePath - - if _, err := os.Stat(absolutePath); os.IsNotExist(err) { - return fmt.Errorf("image file not found: %v", err) - } - - err := os.Remove(absolutePath) - if err != nil { - return fmt.Errorf("failed to delete image: %v", err) - } - - log.Printf("Image deleted successfully: %s", absolutePath) - return nil -} - -func (s *identityCardService) CreateIdentityCard(userID string, request *dto.RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*dto.ResponseIdentityCardDTO, error) { - - errors, valid := request.ValidateIdentityCardInput() - if !valid { - return nil, fmt.Errorf("validation failed: %v", errors) - } - - cardPhotoPath, err := s.saveIdentityCardImage(userID, cardPhoto) - if err != nil { - return nil, fmt.Errorf("failed to save card photo: %v", err) - } - - identityCard := &model.IdentityCard{ - UserID: userID, - Identificationumber: request.Identificationumber, - Placeofbirth: request.Placeofbirth, - Dateofbirth: request.Dateofbirth, - Gender: request.Gender, - BloodType: request.BloodType, - District: request.District, - Village: request.Village, - Neighbourhood: request.Neighbourhood, - Religion: request.Religion, - Maritalstatus: request.Maritalstatus, - Job: request.Job, - Citizenship: request.Citizenship, - Validuntil: request.Validuntil, - Cardphoto: cardPhotoPath, - } - - identityCard, err = s.identityCardRepo.CreateIdentityCard(identityCard) - if err != nil { - log.Printf("Error creating identity card: %v", err) - return nil, fmt.Errorf("failed to create identity card: %v", err) - } - - user, err := s.userRepo.FindByID(userID) - if err != nil { - return nil, fmt.Errorf("failde to fint user: %v", err) - } - - user.RegistrationStatus = "onreview" - - err = s.userRepo.Update(user) - if err != nil { - return nil, fmt.Errorf("failed to update user: %v", err) - } - idcardResponseDTO, _ := FormatResponseIdentityCars(identityCard) - - return idcardResponseDTO, nil -} - -func (s *identityCardService) GetIdentityCardByID(id string) (*dto.ResponseIdentityCardDTO, error) { - - identityCard, err := s.identityCardRepo.GetIdentityCardByID(id) - if err != nil { - log.Printf("Error fetching identity card: %v", err) - return nil, fmt.Errorf("failed to fetch identity card") - } - - idcardResponseDTO, _ := FormatResponseIdentityCars(identityCard) - - return idcardResponseDTO, nil - -} - -func (s *identityCardService) GetIdentityCardsByUserID(userID string) ([]dto.ResponseIdentityCardDTO, error) { - - identityCards, err := s.identityCardRepo.GetIdentityCardsByUserID(userID) - if err != nil { - log.Printf("Error fetching identity cards by userID: %v", err) - return nil, fmt.Errorf("failed to fetch identity cards by userID") - } - - var response []dto.ResponseIdentityCardDTO - for _, card := range identityCards { - - idcardResponseDTO, err := FormatResponseIdentityCars(&card) - if err != nil { - log.Printf("Error creating response DTO for identity card ID %v: %v", card.ID, err) - - continue - } - response = append(response, *idcardResponseDTO) - } - - return response, nil -} - -func (s *identityCardService) UpdateIdentityCard(userID string, id string, request *dto.RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*dto.ResponseIdentityCardDTO, error) { - - errors, valid := request.ValidateIdentityCardInput() - if !valid { - return nil, fmt.Errorf("validation failed: %v", errors) - } - - identityCard, err := s.identityCardRepo.GetIdentityCardByID(id) - if err != nil { - return nil, fmt.Errorf("identity card not found: %v", err) - } - - if identityCard.Cardphoto != "" { - err := deleteIdentityCardImage(identityCard.Cardphoto) - if err != nil { - return nil, fmt.Errorf("failed to delete old image: %v", err) - } - } - - var cardPhotoPath string - if cardPhoto != nil { - cardPhotoPath, err = s.saveIdentityCardImage(userID, cardPhoto) - if err != nil { - return nil, fmt.Errorf("failed to save card photo: %v", err) - } - } - - identityCard.Identificationumber = request.Identificationumber - identityCard.Placeofbirth = request.Placeofbirth - identityCard.Dateofbirth = request.Dateofbirth - identityCard.Gender = request.Gender - identityCard.BloodType = request.BloodType - identityCard.District = request.District - identityCard.Village = request.Village - identityCard.Neighbourhood = request.Neighbourhood - identityCard.Religion = request.Religion - identityCard.Maritalstatus = request.Maritalstatus - identityCard.Job = request.Job - identityCard.Citizenship = request.Citizenship - identityCard.Validuntil = request.Validuntil - if cardPhotoPath != "" { - identityCard.Cardphoto = cardPhotoPath - } - - identityCard, err = s.identityCardRepo.UpdateIdentityCard(id, identityCard) - if err != nil { - log.Printf("Error updating identity card: %v", err) - return nil, fmt.Errorf("failed to update identity card: %v", err) - } - - idcardResponseDTO, _ := FormatResponseIdentityCars(identityCard) - - return idcardResponseDTO, nil -} - -func (s *identityCardService) DeleteIdentityCard(id string) error { - - identityCard, err := s.identityCardRepo.GetIdentityCardByID(id) - if err != nil { - return fmt.Errorf("identity card not found: %v", err) - } - - if identityCard.Cardphoto != "" { - err := deleteIdentityCardImage(identityCard.Cardphoto) - if err != nil { - return fmt.Errorf("failed to delete card photo: %v", err) - } - } - - err = s.identityCardRepo.DeleteIdentityCard(id) - if err != nil { - return fmt.Errorf("failed to delete identity card: %v", err) - } - - return nil -} diff --git a/internal/services/initialcoint_service.go b/internal/services/initialcoint_service.go deleted file mode 100644 index 2791335..0000000 --- a/internal/services/initialcoint_service.go +++ /dev/null @@ -1,299 +0,0 @@ -package services - -import ( - "fmt" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type InitialCointService interface { - CreateInitialCoint(request dto.RequestInitialCointDTO) (*dto.ReponseInitialCointDTO, error) - GetAllInitialCoints() ([]dto.ReponseInitialCointDTO, error) - GetInitialCointByID(id string) (*dto.ReponseInitialCointDTO, error) - UpdateInitialCoint(id string, request dto.RequestInitialCointDTO) (*dto.ReponseInitialCointDTO, error) - DeleteInitialCoint(id string) error -} - -type initialCointService struct { - InitialCointRepo repositories.InitialCointRepository -} - -func NewInitialCointService(repo repositories.InitialCointRepository) InitialCointService { - return &initialCointService{InitialCointRepo: repo} -} - -func (s *initialCointService) CreateInitialCoint(request dto.RequestInitialCointDTO) (*dto.ReponseInitialCointDTO, error) { - - errors, valid := request.ValidateCointInput() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - coint := model.InitialCoint{ - CoinName: request.CoinName, - ValuePerUnit: request.ValuePerUnit, - } - if err := s.InitialCointRepo.CreateInitialCoint(&coint); err != nil { - return nil, fmt.Errorf("failed to create initial coint: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(coint.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(coint.UpdatedAt) - - responseDTO := &dto.ReponseInitialCointDTO{ - ID: coint.ID, - CoinName: coint.CoinName, - ValuePerUnit: coint.ValuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("initialcoint:%s", coint.ID) - cacheData := map[string]interface{}{ - "data": responseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching new initial coint: %v\n", err) - } - - err := s.updateAllCointCache() - if err != nil { - return nil, fmt.Errorf("error updating all initial coint cache: %v", err) - } - - return responseDTO, nil -} - -func (s *initialCointService) GetAllInitialCoints() ([]dto.ReponseInitialCointDTO, error) { - var cointsDTO []dto.ReponseInitialCointDTO - cacheKey := "initialcoints:all" - - cachedData, err := utils.GetJSONData(cacheKey) - if err != nil { - fmt.Printf("Error fetching cache for initialcoints: %v\n", err) - } - - if cachedData != nil { - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - if cointData, ok := item.(map[string]interface{}); ok { - - if coinID, ok := cointData["coin_id"].(string); ok { - if coinName, ok := cointData["coin_name"].(string); ok { - if valuePerUnit, ok := cointData["value_perunit"].(float64); ok { - if createdAt, ok := cointData["createdAt"].(string); ok { - if updatedAt, ok := cointData["updatedAt"].(string); ok { - - cointsDTO = append(cointsDTO, dto.ReponseInitialCointDTO{ - ID: coinID, - CoinName: coinName, - ValuePerUnit: valuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - } - } - } - } - } - } - return cointsDTO, nil - } - } - - records, err := s.InitialCointRepo.FindAllInitialCoints() - if err != nil { - return nil, fmt.Errorf("failed to fetch initial coints from database: %v", err) - } - - if len(records) == 0 { - return cointsDTO, nil - } - - for _, record := range records { - createdAt, _ := utils.FormatDateToIndonesianFormat(record.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(record.UpdatedAt) - - cointsDTO = append(cointsDTO, dto.ReponseInitialCointDTO{ - ID: record.ID, - CoinName: record.CoinName, - ValuePerUnit: record.ValuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData := map[string]interface{}{ - "data": cointsDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching all initial coints: %v\n", err) - } - - return cointsDTO, nil -} - -func (s *initialCointService) GetInitialCointByID(id string) (*dto.ReponseInitialCointDTO, error) { - cacheKey := fmt.Sprintf("initialcoint:%s", id) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - - if data, ok := cachedData["data"].(map[string]interface{}); ok { - - return &dto.ReponseInitialCointDTO{ - ID: data["coin_id"].(string), - CoinName: data["coin_name"].(string), - ValuePerUnit: data["value_perunit"].(float64), - CreatedAt: data["createdAt"].(string), - UpdatedAt: data["updatedAt"].(string), - }, nil - } else { - return nil, fmt.Errorf("error: cache data is not in the expected format for coin ID %s", id) - } - } - - coint, err := s.InitialCointRepo.FindInitialCointByID(id) - if err != nil { - return nil, fmt.Errorf("failed to fetch initial coint by ID %s: %v", id, err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(coint.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(coint.UpdatedAt) - - cointDTO := &dto.ReponseInitialCointDTO{ - ID: coint.ID, - CoinName: coint.CoinName, - ValuePerUnit: coint.ValuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheData := map[string]interface{}{ - "data": cointDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching initial coint by ID: %v\n", err) - } - - return cointDTO, nil -} - -func (s *initialCointService) UpdateInitialCoint(id string, request dto.RequestInitialCointDTO) (*dto.ReponseInitialCointDTO, error) { - - coint, err := s.InitialCointRepo.FindInitialCointByID(id) - if err != nil { - return nil, fmt.Errorf("initial coint with ID %s not found", id) - } - - coint.CoinName = request.CoinName - coint.ValuePerUnit = request.ValuePerUnit - - if err := s.InitialCointRepo.UpdateInitialCoint(id, coint); err != nil { - return nil, fmt.Errorf("failed to update initial coint: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(coint.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(coint.UpdatedAt) - - cointDTO := &dto.ReponseInitialCointDTO{ - ID: coint.ID, - CoinName: coint.CoinName, - ValuePerUnit: coint.ValuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("initialcoint:%s", id) - cacheData := map[string]interface{}{ - "data": cointDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - fmt.Printf("Error caching updated initial coint: %v\n", err) - } - - allCoints, err := s.InitialCointRepo.FindAllInitialCoints() - if err != nil { - return nil, fmt.Errorf("failed to fetch all initial coints from database: %v", err) - } - - var cointsDTO []dto.ReponseInitialCointDTO - for _, record := range allCoints { - createdAt, _ := utils.FormatDateToIndonesianFormat(record.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(record.UpdatedAt) - - cointsDTO = append(cointsDTO, dto.ReponseInitialCointDTO{ - ID: record.ID, - CoinName: record.CoinName, - ValuePerUnit: record.ValuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheAllKey := "initialcoints:all" - cacheAllData := map[string]interface{}{ - "data": cointsDTO, - } - if err := utils.SetJSONData(cacheAllKey, cacheAllData, time.Hour*24); err != nil { - fmt.Printf("Error caching all initial coints: %v\n", err) - } - - return cointDTO, nil -} - -func (s *initialCointService) DeleteInitialCoint(id string) error { - - coint, err := s.InitialCointRepo.FindInitialCointByID(id) - if err != nil { - return fmt.Errorf("initial coint with ID %s not found", id) - } - - if err := s.InitialCointRepo.DeleteInitialCoint(id); err != nil { - return fmt.Errorf("failed to delete initial coint: %v", err) - } - - cacheKey := fmt.Sprintf("initialcoint:%s", coint.ID) - if err := utils.DeleteData(cacheKey); err != nil { - fmt.Printf("Error deleting cache for initial coint: %v\n", err) - } - - return s.updateAllCointCache() -} - -func (s *initialCointService) updateAllCointCache() error { - - records, err := s.InitialCointRepo.FindAllInitialCoints() - if err != nil { - return fmt.Errorf("failed to fetch all initial coints from database: %v", err) - } - - var cointsDTO []dto.ReponseInitialCointDTO - for _, record := range records { - createdAt, _ := utils.FormatDateToIndonesianFormat(record.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(record.UpdatedAt) - - cointsDTO = append(cointsDTO, dto.ReponseInitialCointDTO{ - ID: record.ID, - CoinName: record.CoinName, - ValuePerUnit: record.ValuePerUnit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheAllKey := "initialcoints:all" - cacheAllData := map[string]interface{}{ - "data": cointsDTO, - } - if err := utils.SetJSONData(cacheAllKey, cacheAllData, time.Hour*24); err != nil { - fmt.Printf("Error caching all initial coints: %v\n", err) - return err - } - - return nil -} diff --git a/internal/services/pickup_history_service.go b/internal/services/pickup_history_service.go deleted file mode 100644 index 5362664..0000000 --- a/internal/services/pickup_history_service.go +++ /dev/null @@ -1,36 +0,0 @@ -package services - -import ( - "context" - "time" - "rijig/model" - "rijig/internal/repositories" -) - -type PickupStatusHistoryService interface { - LogStatusChange(ctx context.Context, requestID, status, changedByID, changedByRole string) error - GetStatusHistory(ctx context.Context, requestID string) ([]model.PickupStatusHistory, error) -} - -type pickupStatusHistoryService struct { - repo repositories.PickupStatusHistoryRepository -} - -func NewPickupStatusHistoryService(repo repositories.PickupStatusHistoryRepository) PickupStatusHistoryService { - return &pickupStatusHistoryService{repo: repo} -} - -func (s *pickupStatusHistoryService) LogStatusChange(ctx context.Context, requestID, status, changedByID, changedByRole string) error { - history := model.PickupStatusHistory{ - RequestID: requestID, - Status: status, - ChangedAt: time.Now(), - ChangedByID: changedByID, - ChangedByRole: changedByRole, - } - return s.repo.CreateStatusHistory(ctx, history) -} - -func (s *pickupStatusHistoryService) GetStatusHistory(ctx context.Context, requestID string) ([]model.PickupStatusHistory, error) { - return s.repo.GetStatusHistoryByRequestID(ctx, requestID) -} diff --git a/internal/services/pickup_maching_service.go b/internal/services/pickup_maching_service.go deleted file mode 100644 index ae36e1a..0000000 --- a/internal/services/pickup_maching_service.go +++ /dev/null @@ -1,146 +0,0 @@ -package services - -import ( - "context" - "fmt" - "rijig/dto" - "rijig/internal/repositories" - "rijig/utils" -) - -type PickupMatchingService interface { - FindNearbyCollectorsForPickup(ctx context.Context, pickupID string) ([]dto.NearbyCollectorDTO, error) - FindAvailableRequestsForCollector(ctx context.Context, collectorID string) ([]dto.PickupRequestForCollectorDTO, error) -} - -type pickupMatchingService struct { - pickupRepo repositories.RequestPickupRepository - collectorRepo repositories.CollectorRepository -} - -func NewPickupMatchingService(pickupRepo repositories.RequestPickupRepository, collectorRepo repositories.CollectorRepository) PickupMatchingService { - return &pickupMatchingService{ - pickupRepo: pickupRepo, - collectorRepo: collectorRepo, - } -} - -func (s *pickupMatchingService) FindNearbyCollectorsForPickup(ctx context.Context, pickupID string) ([]dto.NearbyCollectorDTO, error) { - pickup, err := s.pickupRepo.GetPickupWithItemsAndAddress(ctx, pickupID) - if err != nil { - return nil, fmt.Errorf("pickup tidak ditemukan: %w", err) - } - - userCoord := utils.Coord{ - Lat: pickup.Address.Latitude, - Lon: pickup.Address.Longitude, - } - - requestedTrash := make(map[string]bool) - for _, item := range pickup.RequestItems { - requestedTrash[item.TrashCategoryId] = true - } - - collectors, err := s.collectorRepo.GetActiveCollectorsWithTrashAndAddress(ctx) - if err != nil { - return nil, fmt.Errorf("gagal mengambil data collector: %w", err) - } - - var result []dto.NearbyCollectorDTO - for _, col := range collectors { - coord := utils.Coord{ - Lat: col.Address.Latitude, - Lon: col.Address.Longitude, - } - - _, km := utils.Distance(userCoord, coord) - if km > 10 { - continue - } - - var matchedTrash []string - for _, item := range col.AvaibleTrashByCollector { - if requestedTrash[item.TrashCategoryID] { - matchedTrash = append(matchedTrash, item.TrashCategoryID) - } - } - - if len(matchedTrash) == 0 { - continue - } - - result = append(result, dto.NearbyCollectorDTO{ - CollectorID: col.ID, - Name: col.User.Name, - Phone: col.User.Phone, - Rating: col.Rating, - Latitude: col.Address.Latitude, - Longitude: col.Address.Longitude, - DistanceKm: km, - MatchedTrash: matchedTrash, - }) - } - - return result, nil -} - -// terdpaat error seperti ini: "undefined: dto.PickupRequestForCollectorDTO" dan seprti ini: s.collectorRepo.GetCollectorWithAddressAndTrash undefined (type repositories.CollectorRepository has no field or method GetCollectorWithAddressAndTrash) pada kode berikut: - -func (s *pickupMatchingService) FindAvailableRequestsForCollector(ctx context.Context, collectorID string) ([]dto.PickupRequestForCollectorDTO, error) { - collector, err := s.collectorRepo.GetCollectorWithAddressAndTrash(ctx, collectorID) - if err != nil { - return nil, fmt.Errorf("collector tidak ditemukan: %w", err) - } - - pickupList, err := s.pickupRepo.GetAllAutomaticRequestsWithAddress(ctx) - if err != nil { - return nil, fmt.Errorf("gagal mengambil pickup otomatis: %w", err) - } - - collectorCoord := utils.Coord{ - Lat: collector.Address.Latitude, - Lon: collector.Address.Longitude, - } - - // map trash collector - collectorTrash := make(map[string]bool) - for _, t := range collector.AvaibleTrashByCollector { - collectorTrash[t.TrashCategoryID] = true - } - - var results []dto.PickupRequestForCollectorDTO - for _, p := range pickupList { - if p.StatusPickup != "waiting_collector" { - continue - } - coord := utils.Coord{ - Lat: p.Address.Latitude, - Lon: p.Address.Longitude, - } - _, km := utils.Distance(collectorCoord, coord) - if km > 10 { - continue - } - - match := false - var matchedTrash []string - for _, item := range p.RequestItems { - if collectorTrash[item.TrashCategoryId] { - match = true - matchedTrash = append(matchedTrash, item.TrashCategoryId) - } - } - if match { - results = append(results, dto.PickupRequestForCollectorDTO{ - PickupID: p.ID, - UserID: p.UserId, - Latitude: p.Address.Latitude, - Longitude: p.Address.Longitude, - DistanceKm: km, - MatchedTrash: matchedTrash, - }) - } - } - - return results, nil -} diff --git a/internal/services/product_service.go b/internal/services/product_service.go deleted file mode 100644 index f448396..0000000 --- a/internal/services/product_service.go +++ /dev/null @@ -1,404 +0,0 @@ -package services - -import ( - "fmt" - "mime/multipart" - "os" - "path/filepath" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "github.com/google/uuid" -) - -type ProductService interface { - SaveProductImage(file *multipart.FileHeader, imageType string) (string, error) - CreateProduct(userID string, productDTO *dto.RequestProductDTO) (*dto.ResponseProductDTO, error) - - GetAllProductsByStoreID(userID string, page, limit int) ([]dto.ResponseProductDTO, int64, error) - GetProductByID(productID string) (*dto.ResponseProductDTO, error) - - UpdateProduct(userID, productID string, productDTO *dto.RequestProductDTO) (*dto.ResponseProductDTO, error) - DeleteProduct(productID string) error - DeleteProducts(productIDs []string) error - DeleteProductImage(imageID string) error - DeleteProductImages(imageIDs []string) error - deleteImageFile(imageID string) error -} - -type productService struct { - productRepo repositories.ProductRepository - storeRepo repositories.StoreRepository -} - -func NewProductService(productRepo repositories.ProductRepository, storeRepo repositories.StoreRepository) ProductService { - return &productService{productRepo, storeRepo} -} - -func (s *productService) CreateProduct(userID string, productDTO *dto.RequestProductDTO) (*dto.ResponseProductDTO, error) { - store, err := s.storeRepo.FindStoreByUserID(userID) - if err != nil { - return nil, fmt.Errorf("error retrieving store by user ID: %w", err) - } - if store == nil { - return nil, fmt.Errorf("store not found for user %s", userID) - } - - var imagePaths []string - var productImages []model.ProductImage - for _, file := range productDTO.ProductImages { - imagePath, err := s.SaveProductImage(file, "product") - if err != nil { - return nil, fmt.Errorf("failed to save product image: %w", err) - } - imagePaths = append(imagePaths, imagePath) - - productImages = append(productImages, model.ProductImage{ - ImageURL: imagePath, - }) - } - - if len(imagePaths) == 0 { - return nil, fmt.Errorf("at least one image is required for the product") - } - - product := model.Product{ - StoreID: store.ID, - ProductName: productDTO.ProductName, - Quantity: productDTO.Quantity, - } - - product.ProductImages = productImages - - if err := s.productRepo.CreateProduct(&product); err != nil { - return nil, fmt.Errorf("failed to create product: %w", err) - } - - createdAt, err := utils.FormatDateToIndonesianFormat(product.CreatedAt) - if err != nil { - return nil, fmt.Errorf("failed to format createdAt: %w", err) - } - updatedAt, err := utils.FormatDateToIndonesianFormat(product.UpdatedAt) - if err != nil { - return nil, fmt.Errorf("failed to format updatedAt: %w", err) - } - - var productImagesDTO []dto.ResponseProductImageDTO - for _, img := range product.ProductImages { - productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ - ID: img.ID, - ProductID: img.ProductID, - ImageURL: img.ImageURL, - }) - } - - productDTOResponse := &dto.ResponseProductDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductName: product.ProductName, - Quantity: product.Quantity, - ProductImages: productImagesDTO, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return productDTOResponse, nil -} - -func (s *productService) GetAllProductsByStoreID(userID string, page, limit int) ([]dto.ResponseProductDTO, int64, error) { - - store, err := s.storeRepo.FindStoreByUserID(userID) - if err != nil { - return nil, 0, fmt.Errorf("error retrieving store by user ID: %w", err) - } - if store == nil { - return nil, 0, fmt.Errorf("store not found for user %s", userID) - } - - total, err := s.productRepo.CountProductsByStoreID(store.ID) - if err != nil { - return nil, 0, fmt.Errorf("error counting products: %w", err) - } - - products, err := s.productRepo.FindProductsByStoreID(store.ID, page, limit) - if err != nil { - return nil, 0, fmt.Errorf("error fetching products: %w", err) - } - - var productDTOs []dto.ResponseProductDTO - for _, product := range products { - productImages, err := s.productRepo.FindProductImagesByProductID(product.ID) - if err != nil { - return nil, 0, fmt.Errorf("error fetching product images: %w", err) - } - - var productImagesDTO []dto.ResponseProductImageDTO - for _, img := range productImages { - productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ - ID: img.ID, - ProductID: img.ProductID, - ImageURL: img.ImageURL, - }) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(product.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(product.UpdatedAt) - - productDTOs = append(productDTOs, dto.ResponseProductDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductName: product.ProductName, - Quantity: product.Quantity, - Saled: product.Saled, - ProductImages: productImagesDTO, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - return productDTOs, total, nil -} - -func (s *productService) GetProductByID(productID string) (*dto.ResponseProductDTO, error) { - - product, err := s.productRepo.GetProductByID(productID) - if err != nil { - return nil, fmt.Errorf("failed to retrieve product: %w", err) - } - if product == nil { - return nil, fmt.Errorf("product not found") - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(product.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(product.UpdatedAt) - - productDTO := &dto.ResponseProductDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductName: product.ProductName, - Quantity: product.Quantity, - Saled: product.Saled, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - var productImagesDTO []dto.ResponseProductImageDTO - for _, image := range product.ProductImages { - productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ - ID: image.ID, - ProductID: image.ProductID, - ImageURL: image.ImageURL, - }) - } - - productDTO.ProductImages = productImagesDTO - - return productDTO, nil -} - -func (s *productService) UpdateProduct(userID, productID string, productDTO *dto.RequestProductDTO) (*dto.ResponseProductDTO, error) { - - store, err := s.storeRepo.FindStoreByUserID(userID) - if err != nil { - return nil, fmt.Errorf("error retrieving store by user ID: %w", err) - } - if store == nil { - return nil, fmt.Errorf("store not found for user %s", userID) - } - - product, err := s.productRepo.GetProductByID(productID) - if err != nil { - return nil, fmt.Errorf("failed to retrieve product: %v", err) - } - if product == nil { - return nil, fmt.Errorf("product not found") - } - - if product.StoreID != store.ID { - return nil, fmt.Errorf("user does not own the store for this product") - } - - if err := s.deleteProductImages(productID); err != nil { - return nil, fmt.Errorf("failed to delete old product images: %v", err) - } - - var productImages []model.ProductImage - for _, file := range productDTO.ProductImages { - imagePath, err := s.SaveProductImage(file, "product") - if err != nil { - return nil, fmt.Errorf("failed to save product image: %w", err) - } - - productImages = append(productImages, model.ProductImage{ - ImageURL: imagePath, - }) - } - - product.ProductName = productDTO.ProductName - product.Quantity = productDTO.Quantity - product.ProductImages = productImages - - if err := s.productRepo.UpdateProduct(product); err != nil { - return nil, fmt.Errorf("failed to update product: %w", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(product.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(product.UpdatedAt) - - var productImagesDTO []dto.ResponseProductImageDTO - for _, img := range product.ProductImages { - productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ - ID: img.ID, - ProductID: img.ProductID, - ImageURL: img.ImageURL, - }) - } - - productDTOResponse := &dto.ResponseProductDTO{ - ID: product.ID, - StoreID: product.StoreID, - ProductName: product.ProductName, - Quantity: product.Quantity, - ProductImages: productImagesDTO, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return productDTOResponse, nil -} - -func (s *productService) SaveProductImage(file *multipart.FileHeader, imageType string) (string, error) { - - imageDir := fmt.Sprintf("./public%s/uploads/store/%s", os.Getenv("BASE_URL"), imageType) - - if _, err := os.Stat(imageDir); os.IsNotExist(err) { - if err := os.MkdirAll(imageDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for %s image: %v", imageType, err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true} - extension := filepath.Ext(file.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed for %s", imageType) - } - - fileName := fmt.Sprintf("%s_%s%s", imageType, uuid.New().String(), extension) - filePath := filepath.Join(imageDir, fileName) - - fileData, err := file.Open() - if err != nil { - return "", fmt.Errorf("failed to open file: %w", err) - } - defer fileData.Close() - - outFile, err := os.Create(filePath) - if err != nil { - return "", fmt.Errorf("failed to create %s image file: %v", imageType, err) - } - defer outFile.Close() - - if _, err := outFile.ReadFrom(fileData); err != nil { - return "", fmt.Errorf("failed to save %s image: %v", imageType, err) - } - - return filepath.Join("/uploads/store/", imageType, fileName), nil -} - -func (s *productService) DeleteProduct(productID string) error { - - if err := s.deleteProductImages(productID); err != nil { - return fmt.Errorf("failed to delete associated product images: %w", err) - } - - if err := s.productRepo.DeleteProduct(productID); err != nil { - return fmt.Errorf("failed to delete product: %w", err) - } - return nil -} - -func (s *productService) DeleteProducts(productIDs []string) error { - - for _, productID := range productIDs { - if err := s.deleteProductImages(productID); err != nil { - return fmt.Errorf("failed to delete associated images for product %s: %w", productID, err) - } - } - - if err := s.productRepo.DeleteProductsByID(productIDs); err != nil { - return fmt.Errorf("failed to delete products: %w", err) - } - - return nil -} - -func (s *productService) DeleteProductImage(imageID string) error { - - if err := s.deleteImageFile(imageID); err != nil { - return fmt.Errorf("failed to delete image file with ID %s: %w", imageID, err) - } - - if err := s.productRepo.DeleteProductImageByID(imageID); err != nil { - return fmt.Errorf("failed to delete product image from database: %w", err) - } - - return nil -} - -func (s *productService) DeleteProductImages(imageIDs []string) error { - - for _, imageID := range imageIDs { - if err := s.deleteImageFile(imageID); err != nil { - return fmt.Errorf("failed to delete image file with ID %s: %w", imageID, err) - } - } - - if err := s.productRepo.DeleteProductImagesByID(imageIDs); err != nil { - return fmt.Errorf("failed to delete product images from database: %w", err) - } - - return nil -} - -func (s *productService) deleteProductImages(productID string) error { - productImages, err := s.productRepo.FindProductImagesByProductID(productID) - if err != nil { - return fmt.Errorf("failed to fetch product images: %w", err) - } - - for _, img := range productImages { - if err := s.deleteImageFile(img.ID); err != nil { - return fmt.Errorf("failed to delete image file: %w", err) - } - } - - if err := s.productRepo.DeleteProductImagesByProductID(productID); err != nil { - return fmt.Errorf("failed to delete product images from database: %w", err) - } - - return nil -} - -func (s *productService) deleteImageFile(imageID string) error { - productImage, err := s.productRepo.GetProductImageByID(imageID) - if err != nil { - return fmt.Errorf("failed to fetch product image: %w", err) - } - - if productImage == nil { - return fmt.Errorf("product image with ID %s not found", imageID) - } - - baseURL := os.Getenv("BASE_URL") - - imagePath := fmt.Sprintf("./public%s%s", baseURL, productImage.ImageURL) - - if err := os.Remove(imagePath); err != nil { - return fmt.Errorf("failed to delete image file: %w", err) - } - - return nil -} diff --git a/internal/services/rating_service.go b/internal/services/rating_service.go deleted file mode 100644 index e5d7c55..0000000 --- a/internal/services/rating_service.go +++ /dev/null @@ -1,43 +0,0 @@ -package services - -import ( - "context" - "time" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" -) - -type PickupRatingService interface { - CreateRating(ctx context.Context, userID, pickupID, collectorID string, input dto.CreatePickupRatingDTO) error - GetRatingsByCollector(ctx context.Context, collectorID string) ([]model.PickupRating, error) - GetAverageRating(ctx context.Context, collectorID string) (float32, error) -} - -type pickupRatingService struct { - repo repositories.PickupRatingRepository -} - -func NewPickupRatingService(repo repositories.PickupRatingRepository) PickupRatingService { - return &pickupRatingService{repo: repo} -} - -func (s *pickupRatingService) CreateRating(ctx context.Context, userID, pickupID, collectorID string, input dto.CreatePickupRatingDTO) error { - rating := model.PickupRating{ - RequestID: pickupID, - UserID: userID, - CollectorID: collectorID, - Rating: input.Rating, - Feedback: input.Feedback, - CreatedAt: time.Now(), - } - return s.repo.CreateRating(ctx, rating) -} - -func (s *pickupRatingService) GetRatingsByCollector(ctx context.Context, collectorID string) ([]model.PickupRating, error) { - return s.repo.GetRatingsByCollector(ctx, collectorID) -} - -func (s *pickupRatingService) GetAverageRating(ctx context.Context, collectorID string) (float32, error) { - return s.repo.CalculateAverageRating(ctx, collectorID) -} diff --git a/internal/services/request_pickup_service.go b/internal/services/request_pickup_service.go deleted file mode 100644 index 363d6a4..0000000 --- a/internal/services/request_pickup_service.go +++ /dev/null @@ -1,137 +0,0 @@ -package services - -import ( - "context" - "fmt" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "time" -) - -type RequestPickupService interface { - ConvertCartToRequestPickup(ctx context.Context, userID string, req dto.RequestPickupDTO) error - AssignCollectorToRequest(ctx context.Context, pickupID string, req dto.SelectCollectorDTO) error - FindRequestsAssignedToCollector(ctx context.Context, collectorID string) ([]dto.AssignedPickupDTO, error) - ConfirmPickupByCollector(ctx context.Context, pickupID string, confirmedAt time.Time) error - UpdatePickupStatusToPickingUp(ctx context.Context, pickupID string) error - UpdateActualPickupItems(ctx context.Context, pickupID string, items []dto.UpdateRequestPickupItemDTO) error -} - -type requestPickupService struct { - trashRepo repositories.TrashRepository - pickupRepo repositories.RequestPickupRepository - cartService CartService - historyRepo repositories.PickupStatusHistoryRepository -} - -func NewRequestPickupService(trashRepo repositories.TrashRepository, pickupRepo repositories.RequestPickupRepository, cartService CartService, historyRepo repositories.PickupStatusHistoryRepository) RequestPickupService { - return &requestPickupService{ - trashRepo: trashRepo, - pickupRepo: pickupRepo, - cartService: cartService, - historyRepo: historyRepo, - } -} - -func (s *requestPickupService) ConvertCartToRequestPickup(ctx context.Context, userID string, req dto.RequestPickupDTO) error { - cart, err := s.cartService.GetCart(ctx, userID) - if err != nil || len(cart.CartItems) == 0 { - return fmt.Errorf("cart kosong atau tidak ditemukan") - } - - var requestItems []model.RequestPickupItem - for _, item := range cart.CartItems { - trash, err := s.trashRepo.GetTrashCategoryByID(ctx, item.TrashID) - if err != nil { - continue - } - subtotal := float64(item.Amount) * trash.EstimatedPrice - - requestItems = append(requestItems, model.RequestPickupItem{ - TrashCategoryId: item.TrashID, - EstimatedAmount: float64(item.Amount), - EstimatedPricePerKg: trash.EstimatedPrice, - EstimatedSubtotalPrice: subtotal, - }) - } - - if len(requestItems) == 0 { - return fmt.Errorf("tidak ada item valid dalam cart") - } - - pickup := model.RequestPickup{ - UserId: userID, - AddressId: req.AddressID, - RequestMethod: req.RequestMethod, - Notes: req.Notes, - StatusPickup: "waiting_collector", - RequestItems: requestItems, - } - - if err := s.pickupRepo.CreateRequestPickup(ctx, &pickup); err != nil { - return fmt.Errorf("gagal menyimpan request pickup: %w", err) - } - - if err := s.cartService.ClearCart(ctx, userID); err != nil { - return fmt.Errorf("request berhasil, tapi gagal hapus cart: %w", err) - } - - return nil -} - -func (s *requestPickupService) AssignCollectorToRequest(ctx context.Context, pickupID string, req dto.SelectCollectorDTO) error { - if req.CollectorID == "" { - return fmt.Errorf("collector_id tidak boleh kosong") - } - return s.pickupRepo.UpdateCollectorID(ctx, pickupID, req.CollectorID) -} - -func (s *requestPickupService) FindRequestsAssignedToCollector(ctx context.Context, collectorID string) ([]dto.AssignedPickupDTO, error) { - pickups, err := s.pickupRepo.GetRequestsAssignedToCollector(ctx, collectorID) - if err != nil { - return nil, err - } - - var result []dto.AssignedPickupDTO - for _, p := range pickups { - var matchedTrash []string - for _, item := range p.RequestItems { - matchedTrash = append(matchedTrash, item.TrashCategoryId) - } - - result = append(result, dto.AssignedPickupDTO{ - PickupID: p.ID, - UserID: p.UserId, - UserName: p.User.Name, - Latitude: p.Address.Latitude, - Longitude: p.Address.Longitude, - Notes: p.Notes, - MatchedTrash: matchedTrash, - }) - } - - return result, nil -} - -func (s *requestPickupService) ConfirmPickupByCollector(ctx context.Context, pickupID string, confirmedAt time.Time) error { - return s.pickupRepo.UpdatePickupStatusAndConfirmationTime(ctx, pickupID, "confirmed_by_collector", confirmedAt) -} - -func (s *requestPickupService) UpdatePickupStatusToPickingUp(ctx context.Context, pickupID string) error { - err := s.pickupRepo.UpdatePickupStatus(ctx, pickupID, "collector_are_picking_up") - if err != nil { - return err - } - return s.historyRepo.CreateStatusHistory(ctx, model.PickupStatusHistory{ - RequestID: pickupID, - Status: "collector_are_picking_up", - ChangedAt: time.Now(), - ChangedByID: "collector", - ChangedByRole: "collector", - }) -} - -func (s *requestPickupService) UpdateActualPickupItems(ctx context.Context, pickupID string, items []dto.UpdateRequestPickupItemDTO) error { - return s.pickupRepo.UpdateRequestPickupItemsAmountAndPrice(ctx, pickupID, items) -} diff --git a/internal/services/role_service.go b/internal/services/role_service.go deleted file mode 100644 index 5d938bc..0000000 --- a/internal/services/role_service.go +++ /dev/null @@ -1,103 +0,0 @@ -package services - -import ( - "context" - "fmt" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/utils" -) - -type RoleService interface { - GetRoles(ctx context.Context) ([]dto.RoleResponseDTO, error) - GetRoleByID(ctx context.Context, roleID string) (*dto.RoleResponseDTO, error) -} - -type roleService struct { - RoleRepo repositories.RoleRepository -} - -func NewRoleService(roleRepo repositories.RoleRepository) RoleService { - return &roleService{RoleRepo: roleRepo} -} - -func (s *roleService) GetRoles(ctx context.Context) ([]dto.RoleResponseDTO, error) { - cacheKey := "roles_list" - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - var roles []dto.RoleResponseDTO - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - role, ok := item.(map[string]interface{}) - if ok { - roles = append(roles, dto.RoleResponseDTO{ - ID: role["role_id"].(string), - RoleName: role["role_name"].(string), - CreatedAt: role["createdAt"].(string), - UpdatedAt: role["updatedAt"].(string), - }) - } - } - return roles, nil - } - } - - roles, err := s.RoleRepo.FindAll(ctx) - if err != nil { - return nil, fmt.Errorf("failed to fetch roles: %v", err) - } - - var roleDTOs []dto.RoleResponseDTO - for _, role := range roles { - createdAt, _ := utils.FormatDateToIndonesianFormat(role.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(role.UpdatedAt) - - roleDTOs = append(roleDTOs, dto.RoleResponseDTO{ - ID: role.ID, - RoleName: role.RoleName, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData := map[string]interface{}{ - "data": roleDTOs, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching roles data to Redis: %v\n", err) - } - - return roleDTOs, nil -} - -func (s *roleService) GetRoleByID(ctx context.Context, roleID string) (*dto.RoleResponseDTO, error) { - - role, err := s.RoleRepo.FindByID(ctx, roleID) - if err != nil { - return nil, fmt.Errorf("role not found: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(role.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(role.UpdatedAt) - - roleDTO := &dto.RoleResponseDTO{ - ID: role.ID, - RoleName: role.RoleName, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("role:%s", roleID) - cacheData := map[string]interface{}{ - "data": roleDTO, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching role data to Redis: %v\n", err) - } - - return roleDTO, nil -} diff --git a/internal/services/store_service.go b/internal/services/store_service.go deleted file mode 100644 index ef855c7..0000000 --- a/internal/services/store_service.go +++ /dev/null @@ -1,294 +0,0 @@ -package services - -import ( - "fmt" - "mime/multipart" - "os" - "path/filepath" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "github.com/google/uuid" -) - -type StoreService interface { - CreateStore(userID string, storeDTO dto.RequestStoreDTO, storeLogo *multipart.FileHeader, storeBanner *multipart.FileHeader) (*dto.ResponseStoreDTO, error) - GetStoreByUserID(userID string) (*dto.ResponseStoreDTO, error) - UpdateStore(storeID string, storeDTO *dto.RequestStoreDTO, storeLogo *multipart.FileHeader, storeBanner *multipart.FileHeader, userID string) (*dto.ResponseStoreDTO, error) - DeleteStore(storeID string) error -} - -type storeService struct { - storeRepo repositories.StoreRepository -} - -func NewStoreService(storeRepo repositories.StoreRepository) StoreService { - return &storeService{storeRepo} -} - -func (s *storeService) CreateStore(userID string, storeDTO dto.RequestStoreDTO, storeLogo, storeBanner *multipart.FileHeader) (*dto.ResponseStoreDTO, error) { - - if errors, valid := storeDTO.ValidateStoreInput(); !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - existingStore, err := s.storeRepo.FindStoreByUserID(userID) - if err != nil { - return nil, fmt.Errorf("error checking if user already has a store: %w", err) - } - if existingStore != nil { - return nil, fmt.Errorf("user already has a store") - } - - address, err := s.storeRepo.FindAddressByID(storeDTO.StoreAddressID) - if err != nil { - return nil, fmt.Errorf("error validating store address ID: %w", err) - } - if address == nil { - return nil, fmt.Errorf("store address ID not found") - } - - storeLogoPath, err := s.saveStoreImage(storeLogo, "logo") - if err != nil { - return nil, fmt.Errorf("failed to save store logo: %w", err) - } - - storeBannerPath, err := s.saveStoreImage(storeBanner, "banner") - if err != nil { - return nil, fmt.Errorf("failed to save store banner: %w", err) - } - - store := model.Store{ - UserID: userID, - StoreName: storeDTO.StoreName, - StoreLogo: storeLogoPath, - StoreBanner: storeBannerPath, - StoreInfo: storeDTO.StoreInfo, - StoreAddressID: storeDTO.StoreAddressID, - } - - if err := s.storeRepo.CreateStore(&store); err != nil { - return nil, fmt.Errorf("failed to create store: %w", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(store.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(store.UpdatedAt) - - storeResponseDTO := &dto.ResponseStoreDTO{ - ID: store.ID, - UserID: store.UserID, - StoreName: store.StoreName, - StoreLogo: store.StoreLogo, - StoreBanner: store.StoreBanner, - StoreInfo: store.StoreInfo, - StoreAddressID: store.StoreAddressID, - TotalProduct: store.TotalProduct, - Followers: store.Followers, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return storeResponseDTO, nil -} - -func (s *storeService) GetStoreByUserID(userID string) (*dto.ResponseStoreDTO, error) { - - store, err := s.storeRepo.FindStoreByUserID(userID) - if err != nil { - return nil, fmt.Errorf("error retrieving store by user ID: %w", err) - } - if store == nil { - return nil, fmt.Errorf("store not found for user ID: %s", userID) - } - - createdAt, err := utils.FormatDateToIndonesianFormat(store.CreatedAt) - if err != nil { - return nil, fmt.Errorf("failed to format createdAt: %w", err) - } - - updatedAt, err := utils.FormatDateToIndonesianFormat(store.UpdatedAt) - if err != nil { - return nil, fmt.Errorf("failed to format updatedAt: %w", err) - } - - storeResponseDTO := &dto.ResponseStoreDTO{ - ID: store.ID, - UserID: store.UserID, - StoreName: store.StoreName, - StoreLogo: store.StoreLogo, - StoreBanner: store.StoreBanner, - StoreInfo: store.StoreInfo, - StoreAddressID: store.StoreAddressID, - TotalProduct: store.TotalProduct, - Followers: store.Followers, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return storeResponseDTO, nil -} - -func (s *storeService) UpdateStore(storeID string, storeDTO *dto.RequestStoreDTO, storeLogo, storeBanner *multipart.FileHeader, userID string) (*dto.ResponseStoreDTO, error) { - store, err := s.storeRepo.FindStoreByID(storeID) - if err != nil { - return nil, fmt.Errorf("error retrieving store by ID: %w", err) - } - if store == nil { - return nil, fmt.Errorf("store not found") - } - - if storeDTO.StoreAddressID == "" { - return nil, fmt.Errorf("store address ID cannot be empty") - } - - address, err := s.storeRepo.FindAddressByID(storeDTO.StoreAddressID) - if err != nil { - return nil, fmt.Errorf("error validating store address ID: %w", err) - } - if address == nil { - return nil, fmt.Errorf("store address ID not found") - } - - if storeLogo != nil { - if err := s.deleteStoreImage(store.StoreLogo); err != nil { - return nil, fmt.Errorf("failed to delete old store logo: %w", err) - } - storeLogoPath, err := s.saveStoreImage(storeLogo, "logo") - if err != nil { - return nil, fmt.Errorf("failed to save store logo: %w", err) - } - store.StoreLogo = storeLogoPath - } - - if storeBanner != nil { - if err := s.deleteStoreImage(store.StoreBanner); err != nil { - return nil, fmt.Errorf("failed to delete old store banner: %w", err) - } - storeBannerPath, err := s.saveStoreImage(storeBanner, "banner") - if err != nil { - return nil, fmt.Errorf("failed to save store banner: %w", err) - } - store.StoreBanner = storeBannerPath - } - - store.StoreName = storeDTO.StoreName - store.StoreInfo = storeDTO.StoreInfo - store.StoreAddressID = storeDTO.StoreAddressID - - if err := s.storeRepo.UpdateStore(store); err != nil { - return nil, fmt.Errorf("failed to update store: %w", err) - } - - createdAt, err := utils.FormatDateToIndonesianFormat(store.CreatedAt) - if err != nil { - return nil, fmt.Errorf("failed to format createdAt: %w", err) - } - updatedAt, err := utils.FormatDateToIndonesianFormat(store.UpdatedAt) - if err != nil { - return nil, fmt.Errorf("failed to format updatedAt: %w", err) - } - - storeResponseDTO := &dto.ResponseStoreDTO{ - ID: store.ID, - UserID: store.UserID, - StoreName: store.StoreName, - StoreLogo: store.StoreLogo, - StoreBanner: store.StoreBanner, - StoreInfo: store.StoreInfo, - StoreAddressID: store.StoreAddressID, - TotalProduct: store.TotalProduct, - Followers: store.Followers, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return storeResponseDTO, nil -} - -func (s *storeService) DeleteStore(storeID string) error { - store, err := s.storeRepo.FindStoreByID(storeID) - if err != nil { - return fmt.Errorf("error retrieving store by ID: %w", err) - } - if store == nil { - return fmt.Errorf("store not found") - } - - if store.StoreLogo != "" { - if err := s.deleteStoreImage(store.StoreLogo); err != nil { - return fmt.Errorf("failed to delete store logo: %w", err) - } - } - - if store.StoreBanner != "" { - if err := s.deleteStoreImage(store.StoreBanner); err != nil { - return fmt.Errorf("failed to delete store banner: %w", err) - } - } - - if err := s.storeRepo.DeleteStore(storeID); err != nil { - return fmt.Errorf("failed to delete store: %w", err) - } - - return nil -} - -func (s *storeService) saveStoreImage(file *multipart.FileHeader, imageType string) (string, error) { - - imageDir := fmt.Sprintf("./public%s/uploads/store/%s", os.Getenv("BASE_URL"), imageType) - if _, err := os.Stat(imageDir); os.IsNotExist(err) { - - if err := os.MkdirAll(imageDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for %s image: %v", imageType, err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true} - extension := filepath.Ext(file.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed for %s", imageType) - } - - fileName := fmt.Sprintf("%s_%s%s", imageType, uuid.New().String(), extension) - filePath := filepath.Join(imageDir, fileName) - - fileData, err := file.Open() - if err != nil { - return "", fmt.Errorf("failed to open file: %w", err) - } - defer fileData.Close() - - outFile, err := os.Create(filePath) - if err != nil { - return "", fmt.Errorf("failed to create %s image file: %v", imageType, err) - } - defer outFile.Close() - - if _, err := outFile.ReadFrom(fileData); err != nil { - return "", fmt.Errorf("failed to save %s image: %v", imageType, err) - } - - return filepath.Join("/uploads/store", imageType, fileName), nil -} - -func (s *storeService) deleteStoreImage(imagePath string) error { - if imagePath == "" { - return nil - } - - filePath := filepath.Join("./public", imagePath) - - if _, err := os.Stat(filePath); os.IsNotExist(err) { - return nil - } - - err := os.Remove(filePath) - if err != nil { - return fmt.Errorf("failed to delete file at %s: %w", filePath, err) - } - - return nil -} diff --git a/internal/services/trash_service.go b/internal/services/trash_service.go deleted file mode 100644 index c4601e9..0000000 --- a/internal/services/trash_service.go +++ /dev/null @@ -1,631 +0,0 @@ -package services - -import ( - "fmt" - "log" - "mime/multipart" - "os" - "path/filepath" - "strconv" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "github.com/google/uuid" -) - -type TrashService interface { - CreateCategory(request dto.RequestTrashCategoryDTO, iconTrash *multipart.FileHeader) (*dto.ResponseTrashCategoryDTO, error) - AddDetailToCategory(request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error) - - GetCategories() ([]dto.ResponseTrashCategoryDTO, error) - GetCategoryByID(id string) (*dto.ResponseTrashCategoryDTO, error) - GetTrashDetailByID(id string) (*dto.ResponseTrashDetailDTO, error) - - UpdateCategory(id string, request dto.RequestTrashCategoryDTO, iconPath *multipart.FileHeader) (*dto.ResponseTrashCategoryDTO, error) - UpdateDetail(id string, request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error) - - DeleteCategory(id string) error - DeleteDetail(id string) error -} - -type trashService struct { - TrashRepo repositories.TrashRepository -} - -func NewTrashService(trashRepo repositories.TrashRepository) TrashService { - return &trashService{TrashRepo: trashRepo} -} - -func (s *trashService) saveIconOfTrash(iconTrash *multipart.FileHeader) (string, error) { - pathImage := "/uploads/icontrash/" - iconTrashDir := "./public" + os.Getenv("BASE_URL") + pathImage - if _, err := os.Stat(iconTrashDir); os.IsNotExist(err) { - - if err := os.MkdirAll(iconTrashDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for icon trash: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true, ".svg": true} - extension := filepath.Ext(iconTrash.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - iconTrashFIleName := fmt.Sprintf("%s_icontrash%s", uuid.New().String(), extension) - iconTrashPath := filepath.Join(iconTrashDir, iconTrashFIleName) - - src, err := iconTrash.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(iconTrashPath) - if err != nil { - return "", fmt.Errorf("failed to create icon trash file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save icon trash: %v", err) - } - - iconTrashUrl := fmt.Sprintf("%s%s", pathImage, iconTrashFIleName) - - return iconTrashUrl, nil -} - -func deleteIconTrashFIle(imagePath string) error { - if imagePath == "" { - return nil - } - - baseDir := "./public/" + os.Getenv("BASE_URL") - absolutePath := baseDir + imagePath - - if _, err := os.Stat(absolutePath); os.IsNotExist(err) { - return fmt.Errorf("image file not found: %v", err) - } - - err := os.Remove(absolutePath) - if err != nil { - return fmt.Errorf("failed to delete image: %v", err) - } - - log.Printf("Image deleted successfully: %s", absolutePath) - return nil -} - -func (s *trashService) CreateCategory(request dto.RequestTrashCategoryDTO, iconTrash *multipart.FileHeader) (*dto.ResponseTrashCategoryDTO, error) { - - parsedPrice, err := strconv.ParseFloat(request.EstimatedPrice, 64) - fmt.Println("Received estimatedprice:", request.EstimatedPrice) - if err != nil { - return nil, fmt.Errorf("gagal memvalidasi harga: %v", err) - } else { - fmt.Printf("hasil parsing%v", parsedPrice) - } - - icontrashPath, err := s.saveIconOfTrash(iconTrash) - if err != nil { - return nil, fmt.Errorf("gagal menyimpan ikon sampah: %v", err) - } - - category := model.TrashCategory{ - Name: request.Name, - - EstimatedPrice: parsedPrice, - Icon: icontrashPath, - } - - if err := s.TrashRepo.CreateCategory(&category); err != nil { - return nil, fmt.Errorf("failed to create category: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(category.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(category.UpdatedAt) - - categoryResponseDTO := &dto.ResponseTrashCategoryDTO{ - ID: category.ID, - Name: category.Name, - EstimatedPrice: float64(category.EstimatedPrice), - Icon: category.Icon, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - if err := s.CacheCategoryAndDetails(category.ID, categoryResponseDTO, nil, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching category: %v", err) - } - - categories, err := s.TrashRepo.GetCategories() - if err == nil { - var categoriesDTO []dto.ResponseTrashCategoryDTO - for _, c := range categories { - ccreatedAt, _ := utils.FormatDateToIndonesianFormat(c.CreatedAt) - cupdatedAt, _ := utils.FormatDateToIndonesianFormat(c.UpdatedAt) - categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{ - ID: c.ID, - Name: c.Name, - EstimatedPrice: float64(c.EstimatedPrice), - Icon: c.Icon, - CreatedAt: ccreatedAt, - UpdatedAt: cupdatedAt, - }) - } - - if err := s.CacheCategoryList(categoriesDTO, time.Hour*6); err != nil { - fmt.Printf("Error caching all categories: %v\n", err) - } - } - - return categoryResponseDTO, nil -} - -func (s *trashService) AddDetailToCategory(request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error) { - errors, valid := request.ValidateTrashDetailInput() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - detail := model.TrashDetail{ - CategoryID: request.CategoryID, - Description: request.Description, - Price: request.Price, - } - - if err := s.TrashRepo.AddDetailToCategory(&detail); err != nil { - return nil, fmt.Errorf("failed to add detail to category: %v", err) - } - - dcreatedAt, _ := utils.FormatDateToIndonesianFormat(detail.CreatedAt) - dupdatedAt, _ := utils.FormatDateToIndonesianFormat(detail.UpdatedAt) - - detailResponseDTO := &dto.ResponseTrashDetailDTO{ - ID: detail.ID, - CategoryID: detail.CategoryID, - Description: detail.Description, - Price: detail.Price, - CreatedAt: dcreatedAt, - UpdatedAt: dupdatedAt, - } - - cacheKey := fmt.Sprintf("detail:%s", detail.ID) - cacheData := map[string]interface{}{ - "data": detailResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching detail: %v", err) - } - - category, err := s.TrashRepo.GetCategoryByID(detail.CategoryID) - - if err == nil { - - ccreatedAt, _ := utils.FormatDateToIndonesianFormat(category.CreatedAt) - cupdatedAt, _ := utils.FormatDateToIndonesianFormat(category.UpdatedAt) - - categoryResponseDTO := &dto.ResponseTrashCategoryDTO{ - ID: category.ID, - Name: category.Name, - Icon: category.Icon, - CreatedAt: ccreatedAt, - UpdatedAt: cupdatedAt, - } - - if err := s.CacheCategoryAndDetails(detail.CategoryID, categoryResponseDTO, category.Details, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching updated category: %v", err) - } - } else { - return nil, fmt.Errorf("error fetching category for cache update: %v", err) - } - - return detailResponseDTO, nil -} - -func (s *trashService) GetCategories() ([]dto.ResponseTrashCategoryDTO, error) { - cacheKey := "categories:all" - cachedCategories, err := utils.GetJSONData(cacheKey) - if err == nil && cachedCategories != nil { - var categoriesDTO []dto.ResponseTrashCategoryDTO - for _, category := range cachedCategories["data"].([]interface{}) { - categoryData := category.(map[string]interface{}) - categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{ - ID: categoryData["id"].(string), - Name: categoryData["name"].(string), - EstimatedPrice: categoryData["estimatedprice"].(float64), - Icon: categoryData["icon"].(string), - CreatedAt: categoryData["createdAt"].(string), - UpdatedAt: categoryData["updatedAt"].(string), - }) - } - return categoriesDTO, nil - } - - categories, err := s.TrashRepo.GetCategories() - if err != nil { - return nil, fmt.Errorf("failed to fetch categories: %v", err) - } - - var categoriesDTO []dto.ResponseTrashCategoryDTO - for _, category := range categories { - - createdAt, _ := utils.FormatDateToIndonesianFormat(category.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(category.UpdatedAt) - categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{ - ID: category.ID, - Name: category.Name, - EstimatedPrice: category.EstimatedPrice, - Icon: category.Icon, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - - cacheData := map[string]interface{}{ - "data": categoriesDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*6); err != nil { - fmt.Printf("Error caching categories: %v\n", err) - } - - return categoriesDTO, nil -} - -func (s *trashService) GetCategoryByID(id string) (*dto.ResponseTrashCategoryDTO, error) { - cacheKey := fmt.Sprintf("category:%s", id) - cachedCategory, err := utils.GetJSONData(cacheKey) - if err == nil && cachedCategory != nil { - categoryData := cachedCategory["data"].(map[string]interface{}) - details := mapDetails(cachedCategory["details"]) - return &dto.ResponseTrashCategoryDTO{ - ID: categoryData["id"].(string), - Name: categoryData["name"].(string), - EstimatedPrice: categoryData["estimatedprice"].(float64), - Icon: categoryData["icon"].(string), - CreatedAt: categoryData["createdAt"].(string), - UpdatedAt: categoryData["updatedAt"].(string), - Details: details, - }, nil - } - - category, err := s.TrashRepo.GetCategoryByID(id) - if err != nil { - return nil, fmt.Errorf("category not found: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(category.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(category.UpdatedAt) - - categoryDTO := &dto.ResponseTrashCategoryDTO{ - ID: category.ID, - Name: category.Name, - EstimatedPrice: category.EstimatedPrice, - Icon: category.Icon, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - if category.Details != nil { - var detailsDTO []dto.ResponseTrashDetailDTO - for _, detail := range category.Details { - createdAt, _ := utils.FormatDateToIndonesianFormat(detail.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(detail.UpdatedAt) - detailsDTO = append(detailsDTO, dto.ResponseTrashDetailDTO{ - ID: detail.ID, - CategoryID: detail.CategoryID, - Description: detail.Description, - Price: detail.Price, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - }) - } - categoryDTO.Details = detailsDTO - } - - if err := s.CacheCategoryAndDetails(category.ID, categoryDTO, categoryDTO.Details, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching category and details: %v", err) - } - - return categoryDTO, nil -} - -func (s *trashService) GetTrashDetailByID(id string) (*dto.ResponseTrashDetailDTO, error) { - cacheKey := fmt.Sprintf("detail:%s", id) - cachedDetail, err := utils.GetJSONData(cacheKey) - if err == nil && cachedDetail != nil { - detailData := cachedDetail["data"].(map[string]interface{}) - return &dto.ResponseTrashDetailDTO{ - ID: detailData["id"].(string), - CategoryID: detailData["category_id"].(string), - Description: detailData["description"].(string), - Price: detailData["price"].(float64), - CreatedAt: detailData["createdAt"].(string), - UpdatedAt: detailData["updatedAt"].(string), - }, nil - } - - detail, err := s.TrashRepo.GetTrashDetailByID(id) - if err != nil { - return nil, fmt.Errorf("trash detail not found: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(detail.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(detail.UpdatedAt) - - detailDTO := &dto.ResponseTrashDetailDTO{ - ID: detail.ID, - CategoryID: detail.CategoryID, - Description: detail.Description, - Price: detail.Price, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheData := map[string]interface{}{ - "data": detailDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*24); err != nil { - return nil, fmt.Errorf("error caching detail: %v", err) - } - - return detailDTO, nil -} - -func (s *trashService) UpdateCategory(id string, request dto.RequestTrashCategoryDTO, iconPath *multipart.FileHeader) (*dto.ResponseTrashCategoryDTO, error) { - errors, valid := request.ValidateTrashCategoryInput() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - category, err := s.TrashRepo.GetCategoryByID(id) - if err != nil { - return nil, fmt.Errorf("category not found: %v", err) - } - - if category.Icon != "" { - err := deleteIconTrashFIle(category.Icon) - if err != nil { - return nil, fmt.Errorf("failed to delete old image: %v", err) - } - } - - var iconTrashPath string - if iconPath != nil { - iconTrashPath, err = s.saveIconOfTrash(iconPath) - if err != nil { - return nil, fmt.Errorf("failed to save card photo: %v", err) - } - } - - if iconTrashPath != "" { - category.Icon = iconTrashPath - } - - category, err = s.TrashRepo.UpdateCategory(id, category) - if err != nil { - log.Printf("Error updating trash category: %v", err) - return nil, fmt.Errorf("failed to update category: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(category.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(category.UpdatedAt) - - categoryResponseDTO := &dto.ResponseTrashCategoryDTO{ - ID: category.ID, - Name: category.Name, - EstimatedPrice: category.EstimatedPrice, - Icon: category.Icon, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - if err := s.CacheCategoryAndDetails(category.ID, categoryResponseDTO, category.Details, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching updated category: %v", err) - } - - allCategories, err := s.TrashRepo.GetCategories() - if err == nil { - var categoriesDTO []dto.ResponseTrashCategoryDTO - for _, c := range allCategories { - ccreatedAt, _ := utils.FormatDateToIndonesianFormat(c.CreatedAt) - cupdatedAt, _ := utils.FormatDateToIndonesianFormat(c.UpdatedAt) - categoriesDTO = append(categoriesDTO, dto.ResponseTrashCategoryDTO{ - ID: c.ID, - Name: c.Name, - EstimatedPrice: c.EstimatedPrice, - Icon: c.Icon, - CreatedAt: ccreatedAt, - UpdatedAt: cupdatedAt, - }) - } - - if err := s.CacheCategoryList(categoriesDTO, time.Hour*6); err != nil { - fmt.Printf("Error caching all categories: %v\n", err) - } - } - - return categoryResponseDTO, nil -} - -func (s *trashService) UpdateDetail(id string, request dto.RequestTrashDetailDTO) (*dto.ResponseTrashDetailDTO, error) { - errors, valid := request.ValidateTrashDetailInput() - if !valid { - return nil, fmt.Errorf("validation error: %v", errors) - } - - if err := s.TrashRepo.UpdateTrashDetail(id, request.Description, request.Price); err != nil { - return nil, fmt.Errorf("failed to update detail: %v", err) - } - - detail, err := s.TrashRepo.GetTrashDetailByID(id) - if err != nil { - return nil, fmt.Errorf("trash detail not found: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(detail.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(detail.UpdatedAt) - - detailResponseDTO := &dto.ResponseTrashDetailDTO{ - ID: detail.ID, - CategoryID: detail.CategoryID, - Description: detail.Description, - Price: detail.Price, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - cacheKey := fmt.Sprintf("detail:%s", detail.ID) - cacheData := map[string]interface{}{ - "data": detailResponseDTO, - } - if err := utils.SetJSONData(cacheKey, cacheData, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching updated detail: %v", err) - } - - category, err := s.TrashRepo.GetCategoryByID(detail.CategoryID) - if err == nil { - - ccreatedAt, _ := utils.FormatDateToIndonesianFormat(category.CreatedAt) - cupdatedAt, _ := utils.FormatDateToIndonesianFormat(category.UpdatedAt) - - categoryResponseDTO := &dto.ResponseTrashCategoryDTO{ - ID: category.ID, - Name: category.Name, - Icon: category.Icon, - CreatedAt: ccreatedAt, - UpdatedAt: cupdatedAt, - } - - if err := s.CacheCategoryAndDetails(detail.CategoryID, categoryResponseDTO, category.Details, time.Hour*6); err != nil { - return nil, fmt.Errorf("error caching updated category: %v", err) - } - } else { - fmt.Printf("Error fetching category for cache update: %v\n", err) - } - - return detailResponseDTO, nil -} - -func (s *trashService) DeleteCategory(id string) error { - detailsCacheKeyPrefix := "detail:" - details, err := s.TrashRepo.GetDetailsByCategoryID(id) - if err != nil { - return fmt.Errorf("failed to fetch details for category %s: %v", id, err) - } - - for _, detail := range details { - detailCacheKey := detailsCacheKeyPrefix + detail.ID - if err := s.deleteCache(detailCacheKey); err != nil { - return fmt.Errorf("error clearing cache for deleted detail: %v", err) - } - } - - category, err := s.TrashRepo.GetCategoryByID(id) - if err != nil { - return fmt.Errorf("failed to fetch category for deletion: %v", err) - } - - if err := deleteIconTrashFIle(category.Icon); err != nil { - return fmt.Errorf("error deleting icon for category %s: %v", id, err) - } - - if err := s.TrashRepo.DeleteCategory(id); err != nil { - return fmt.Errorf("failed to delete category: %v", err) - } - - if err := s.deleteCache("category:" + id); err != nil { - return fmt.Errorf("error clearing cache for deleted category: %v", err) - } - - if err := s.deleteCache("categories:all"); err != nil { - return fmt.Errorf("error clearing categories list cache: %v", err) - } - - return nil -} - -func (s *trashService) DeleteDetail(id string) error { - - detail, err := s.TrashRepo.GetTrashDetailByID(id) - if err != nil { - return fmt.Errorf("trash detail not found: %v", err) - } - - if err := s.TrashRepo.DeleteTrashDetail(id); err != nil { - return fmt.Errorf("failed to delete detail: %v", err) - } - - detailCacheKey := fmt.Sprintf("detail:%s", id) - if err := s.deleteCache(detailCacheKey); err != nil { - return fmt.Errorf("error clearing cache for deleted detail: %v", err) - } - - categoryCacheKey := fmt.Sprintf("category:%s", detail.CategoryID) - if err := s.deleteCache(categoryCacheKey); err != nil { - return fmt.Errorf("error clearing cache for category after detail deletion: %v", err) - } - - return nil -} - -func mapDetails(details interface{}) []dto.ResponseTrashDetailDTO { - var detailsDTO []dto.ResponseTrashDetailDTO - if details != nil { - for _, detail := range details.([]interface{}) { - detailData := detail.(map[string]interface{}) - detailsDTO = append(detailsDTO, dto.ResponseTrashDetailDTO{ - ID: detailData["id"].(string), - CategoryID: detailData["category_id"].(string), - Description: detailData["description"].(string), - Price: detailData["price"].(float64), - CreatedAt: detailData["createdAt"].(string), - UpdatedAt: detailData["updatedAt"].(string), - }) - } - } - return detailsDTO -} - -func (s *trashService) CacheCategoryAndDetails(categoryID string, categoryData interface{}, detailsData interface{}, expiration time.Duration) error { - cacheKey := fmt.Sprintf("category:%s", categoryID) - cacheData := map[string]interface{}{ - "data": categoryData, - "details": detailsData, - } - - err := utils.SetJSONData(cacheKey, cacheData, expiration) - if err != nil { - return fmt.Errorf("error caching category and details: %v", err) - } - - return nil -} - -func (s *trashService) CacheCategoryList(categoriesData interface{}, expiration time.Duration) error { - cacheKey := "categories:all" - cacheData := map[string]interface{}{ - "data": categoriesData, - } - - err := utils.SetJSONData(cacheKey, cacheData, expiration) - if err != nil { - return fmt.Errorf("error caching categories list: %v", err) - } - - return nil -} - -func (s *trashService) deleteCache(cacheKey string) error { - if err := utils.DeleteData(cacheKey); err != nil { - fmt.Printf("Error clearing cache for key: %v\n", cacheKey) - return fmt.Errorf("error clearing cache for key %s: %v", cacheKey, err) - } - fmt.Printf("Deleted cache for key: %s\n", cacheKey) - return nil -} diff --git a/internal/services/trashcart_service.go b/internal/services/trashcart_service.go deleted file mode 100644 index a231c47..0000000 --- a/internal/services/trashcart_service.go +++ /dev/null @@ -1,154 +0,0 @@ -package services - -// import ( -// "log" -// "time" - -// "rijig/dto" -// "rijig/internal/repositories" -// "rijig/model" - -// "github.com/google/uuid" -// ) - -// type CartService struct { -// Repo repositories.CartRepository -// } - -// func NewCartService(repo repositories.CartRepository) *CartService { -// return &CartService{Repo: repo} -// } - -// func (s *CartService) CommitCartToDatabase(userID string) error { -// items, err := GetCartItems(userID) -// if err != nil || len(items) == 0 { -// log.Printf("No items to commit for user: %s", userID) -// return err -// } - -// var cartItems []model.CartItem -// var totalAmount float32 -// var estimatedTotal float32 - -// for _, item := range items { -// trash, err := s.Repo.GetTrashCategoryByID(item.TrashCategoryID) -// if err != nil { -// log.Printf("Trash category not found for trashID: %s", item.TrashCategoryID) -// continue -// } - -// subTotal := float32(trash.EstimatedPrice) * item.Amount -// totalAmount += item.Amount -// estimatedTotal += subTotal - -// cartItems = append(cartItems, model.CartItem{ -// ID: uuid.NewString(), -// TrashCategoryID: item.TrashCategoryID, -// Amount: item.Amount, -// SubTotalEstimatedPrice: subTotal, -// }) -// } - -// cart := &model.Cart{ -// ID: uuid.NewString(), -// UserID: userID, -// CartItems: cartItems, -// TotalAmount: totalAmount, -// EstimatedTotalPrice: estimatedTotal, -// CreatedAt: time.Now(), -// UpdatedAt: time.Now(), -// } - -// if err := s.Repo.DeleteCartByUserID(userID); err != nil { -// log.Printf("Failed to delete old cart: %v", err) -// } - -// if err := s.Repo.CreateCart(cart); err != nil { -// log.Printf("Failed to create cart: %v", err) -// return err -// } - -// if err := ClearCart(userID); err != nil { -// log.Printf("Failed to clear Redis cart: %v", err) -// } - -// log.Printf("Cart committed successfully for user: %s", userID) -// return nil -// } - -// func (s *CartService) GetCartFromRedis(userID string) (*dto.CartResponse, error) { -// items, err := GetCartItems(userID) -// if err != nil || len(items) == 0 { -// return nil, err -// } - -// var totalAmount float32 -// var estimatedTotal float32 -// var cartItemDTOs []dto.CartItemResponse - -// for _, item := range items { -// trash, err := s.Repo.GetTrashCategoryByID(item.TrashCategoryID) -// if err != nil { -// continue -// } - -// subtotal := float32(trash.EstimatedPrice) * item.Amount -// totalAmount += item.Amount -// estimatedTotal += subtotal - -// cartItemDTOs = append(cartItemDTOs, dto.CartItemResponse{ -// TrashId: trash.ID, -// TrashIcon: trash.Icon, -// TrashName: trash.Name, -// Amount: item.Amount, -// EstimatedSubTotalPrice: subtotal, -// }) -// } - -// resp := &dto.CartResponse{ -// ID: "N/A", -// UserID: userID, -// TotalAmount: totalAmount, -// EstimatedTotalPrice: estimatedTotal, -// CreatedAt: time.Now().Format(time.RFC3339), -// UpdatedAt: time.Now().Format(time.RFC3339), -// CartItems: cartItemDTOs, -// } -// return resp, nil -// } - -// func (s *CartService) GetCart(userID string) (*dto.CartResponse, error) { - -// cartRedis, err := s.GetCartFromRedis(userID) -// if err == nil && len(cartRedis.CartItems) > 0 { -// return cartRedis, nil -// } - -// cartDB, err := s.Repo.GetCartByUserID(userID) -// if err != nil { -// return nil, err -// } - -// var items []dto.CartItemResponse -// for _, item := range cartDB.CartItems { -// items = append(items, dto.CartItemResponse{ -// ItemId: item.ID, -// TrashId: item.TrashCategoryID, -// TrashIcon: item.TrashCategory.Icon, -// TrashName: item.TrashCategory.Name, -// Amount: item.Amount, -// EstimatedSubTotalPrice: item.SubTotalEstimatedPrice, -// }) -// } - -// resp := &dto.CartResponse{ -// ID: cartDB.ID, -// UserID: cartDB.UserID, -// TotalAmount: cartDB.TotalAmount, -// EstimatedTotalPrice: cartDB.EstimatedTotalPrice, -// CreatedAt: cartDB.CreatedAt.Format(time.RFC3339), -// UpdatedAt: cartDB.UpdatedAt.Format(time.RFC3339), -// CartItems: items, -// } -// return resp, nil -// } diff --git a/internal/services/user_service.go b/internal/services/user_service.go deleted file mode 100644 index 05c2774..0000000 --- a/internal/services/user_service.go +++ /dev/null @@ -1,231 +0,0 @@ -package services - -import ( - "fmt" - "log" - "mime/multipart" - "os" - "path/filepath" - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type UserService interface { - GetUserByID(userID string) (*dto.UserResponseDTO, error) - GetAllUsers(page, limit int) ([]dto.UserResponseDTO, error) - UpdateUser(userID string, request *dto.RequestUserDTO) (*dto.UserResponseDTO, error) - UpdateUserAvatar(userID string, avatar *multipart.FileHeader) (*dto.UserResponseDTO, error) - UpdateUserPassword(userID, oldPassword, newPassword, confirmNewPassword string) error -} - -type userService struct { - userRepo repositories.UserProfilRepository -} - -func NewUserService(userRepo repositories.UserProfilRepository) UserService { - return &userService{userRepo: userRepo} -} - -func (s *userService) GetUserByID(userID string) (*dto.UserResponseDTO, error) { - user, err := s.userRepo.FindByID(userID) - if err != nil { - return nil, fmt.Errorf("error retrieving user by ID: %v", err) - } - - userDTO, err := s.formatUserResponse(user) - if err != nil { - return nil, fmt.Errorf("error formatting user response: %v", err) - } - - return userDTO, nil -} - -func (s *userService) GetAllUsers(page, limit int) ([]dto.UserResponseDTO, error) { - users, err := s.userRepo.FindAll(page, limit) - if err != nil { - return nil, fmt.Errorf("error retrieving all users: %v", err) - } - - var userDTOs []dto.UserResponseDTO - for _, user := range users { - userDTO, err := s.formatUserResponse(&user) - if err != nil { - log.Printf("Error formatting user response for userID %s: %v", user.ID, err) - continue - } - userDTOs = append(userDTOs, *userDTO) - } - - return userDTOs, nil -} - -func (s *userService) UpdateUser(userID string, request *dto.RequestUserDTO) (*dto.UserResponseDTO, error) { - - errors, valid := request.Validate() - if !valid { - return nil, fmt.Errorf("validation failed: %v", errors) - } - - user, err := s.userRepo.FindByID(userID) - if err != nil { - return nil, fmt.Errorf("user not found: %v", err) - } - - user.Name = request.Name - user.Phone = request.Phone - user.Email = request.Email - - err = s.userRepo.Update(user) - if err != nil { - return nil, fmt.Errorf("error updating user: %v", err) - } - - userDTO, err := s.formatUserResponse(user) - if err != nil { - return nil, fmt.Errorf("error formatting updated user response: %v", err) - } - - return userDTO, nil -} - -func (s *userService) UpdateUserAvatar(userID string, avatar *multipart.FileHeader) (*dto.UserResponseDTO, error) { - - user, err := s.userRepo.FindByID(userID) - if err != nil { - return nil, fmt.Errorf("user not found: %v", err) - } - - if *user.Avatar != "" { - err := s.deleteAvatarImage(*user.Avatar) - if err != nil { - return nil, fmt.Errorf("failed to delete old image: %v", err) - } - } - - avatarURL, err := s.saveAvatarImage(userID, avatar) - if err != nil { - return nil, fmt.Errorf("failed to save avatar image: %v", err) - } - - err = s.userRepo.UpdateAvatar(userID, avatarURL) - if err != nil { - return nil, fmt.Errorf("failed to update avatar in the database: %v", err) - } - - userDTO, err := s.formatUserResponse(user) - if err != nil { - return nil, fmt.Errorf("failed to format user response: %v", err) - } - - return userDTO, nil -} - -func (s *userService) UpdateUserPassword(userID, oldPassword, newPassword, confirmNewPassword string) error { - - // errors, valid := utils.ValidatePasswordUpdate(oldPassword, newPassword, confirmNewPassword) - // if !valid { - // return fmt.Errorf("password validation error: %v", errors) - // } - - user, err := s.userRepo.FindByID(userID) - if err != nil { - return fmt.Errorf("user not found: %v", err) - } - - if user.Password != oldPassword { - return fmt.Errorf("old password is incorrect") - } - - err = s.userRepo.UpdatePassword(userID, newPassword) - if err != nil { - return fmt.Errorf("error updating password: %v", err) - } - - return nil -} - -func (s *userService) formatUserResponse(user *model.User) (*dto.UserResponseDTO, error) { - - createdAt, _ := utils.FormatDateToIndonesianFormat(user.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(user.UpdatedAt) - - userDTO := &dto.UserResponseDTO{ - ID: user.ID, - Username: user.Name, - Avatar: user.Avatar, - Name: user.Name, - Phone: user.Phone, - Email: user.Email, - EmailVerified: user.PhoneVerified, - RoleName: user.Role.RoleName, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return userDTO, nil -} - -func (s *userService) saveAvatarImage(userID string, avatar *multipart.FileHeader) (string, error) { - - pathImage := "/uploads/avatars/" - avatarDir := "./public" + os.Getenv("BASE_URL") + pathImage - - if _, err := os.Stat(avatarDir); os.IsNotExist(err) { - if err := os.MkdirAll(avatarDir, os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create directory for avatar: %v", err) - } - } - - allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true} - extension := filepath.Ext(avatar.Filename) - if !allowedExtensions[extension] { - return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") - } - - avatarFileName := fmt.Sprintf("%s_avatar%s", userID, extension) - avatarPath := filepath.Join(avatarDir, avatarFileName) - - src, err := avatar.Open() - if err != nil { - return "", fmt.Errorf("failed to open uploaded file: %v", err) - } - defer src.Close() - - dst, err := os.Create(avatarPath) - if err != nil { - return "", fmt.Errorf("failed to create avatar file: %v", err) - } - defer dst.Close() - - if _, err := dst.ReadFrom(src); err != nil { - return "", fmt.Errorf("failed to save avatar: %v", err) - } - - avatarURL := fmt.Sprintf("%s%s", pathImage, avatarFileName) - - return avatarURL, nil -} - -func (s *userService) deleteAvatarImage(avatarPath string) error { - - if avatarPath == "" { - return nil - } - - baseDir := "./public/" + os.Getenv("BASE_URL") - absolutePath := baseDir + avatarPath - - if _, err := os.Stat(absolutePath); os.IsNotExist(err) { - return fmt.Errorf("image file not found: %v", err) - } - - err := os.Remove(absolutePath) - if err != nil { - return fmt.Errorf("failed to delete avatar image: %v", err) - } - - log.Printf("Avatar image deleted successfully: %s", absolutePath) - return nil -} diff --git a/internal/services/userpin_service.go b/internal/services/userpin_service.go deleted file mode 100644 index 9a2ba45..0000000 --- a/internal/services/userpin_service.go +++ /dev/null @@ -1,133 +0,0 @@ -package services - -import ( - "fmt" - "time" - - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" - - "golang.org/x/crypto/bcrypt" -) - -type UserPinService interface { - CreateUserPin(userID, pin string) (string, error) - VerifyUserPin(userID, pin string) (string, error) - CheckPinStatus(userID string) (string, error) - UpdateUserPin(userID, oldPin, newPin string) (string, error) -} - -type userPinService struct { - UserPinRepo repositories.UserPinRepository -} - -func NewUserPinService(userPinRepo repositories.UserPinRepository) UserPinService { - return &userPinService{UserPinRepo: userPinRepo} -} - -func (s *userPinService) VerifyUserPin(userID, pin string) (string, error) { - if pin == "" { - return "", fmt.Errorf("pin tidak boleh kosong") - } - - userPin, err := s.UserPinRepo.FindByUserID(userID) - if err != nil { - return "", fmt.Errorf("error fetching user pin: %v", err) - } - if userPin == nil { - return "", fmt.Errorf("user pin not found") - } - - err = bcrypt.CompareHashAndPassword([]byte(userPin.Pin), []byte(pin)) - if err != nil { - return "", fmt.Errorf("incorrect pin") - } - - return "Pin yang anda masukkan benar", nil -} - -func (s *userPinService) CheckPinStatus(userID string) (string, error) { - userPin, err := s.UserPinRepo.FindByUserID(userID) - if err != nil { - return "", fmt.Errorf("error checking pin status: %v", err) - } - if userPin == nil { - return "Pin not created", nil - } - - return "Pin already created", nil -} - -func (s *userPinService) CreateUserPin(userID, pin string) (string, error) { - - existingPin, err := s.UserPinRepo.FindByUserID(userID) - if err != nil { - return "", fmt.Errorf("error checking existing pin: %v", err) - } - - if existingPin != nil { - return "", fmt.Errorf("you have already created a pin, you don't need to create another one") - } - - hashedPin, err := bcrypt.GenerateFromPassword([]byte(pin), bcrypt.DefaultCost) - if err != nil { - return "", fmt.Errorf("error hashing the pin: %v", err) - } - - newPin := model.UserPin{ - UserID: userID, - Pin: string(hashedPin), - } - - err = s.UserPinRepo.Create(&newPin) - if err != nil { - return "", fmt.Errorf("error creating user pin: %v", err) - } - - cacheKey := fmt.Sprintf("userpin:%s", userID) - cacheData := map[string]interface{}{"data": newPin} - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching new user pin to Redis: %v\n", err) - } - - return "Pin berhasil dibuat", nil -} - -func (s *userPinService) UpdateUserPin(userID, oldPin, newPin string) (string, error) { - - userPin, err := s.UserPinRepo.FindByUserID(userID) - if err != nil { - return "", fmt.Errorf("error fetching user pin: %v", err) - } - - if userPin == nil { - return "", fmt.Errorf("user pin not found") - } - - err = bcrypt.CompareHashAndPassword([]byte(userPin.Pin), []byte(oldPin)) - if err != nil { - return "", fmt.Errorf("incorrect old pin") - } - - hashedPin, err := bcrypt.GenerateFromPassword([]byte(newPin), bcrypt.DefaultCost) - if err != nil { - return "", fmt.Errorf("error hashing the new pin: %v", err) - } - - userPin.Pin = string(hashedPin) - err = s.UserPinRepo.Update(userPin) - if err != nil { - return "", fmt.Errorf("error updating user pin: %v", err) - } - - cacheKey := fmt.Sprintf("userpin:%s", userID) - cacheData := map[string]interface{}{"data": userPin} - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching updated user pin to Redis: %v\n", err) - } - - return "Pin berhasil diperbarui", nil -} diff --git a/internal/services/wilayah_indonesia_service.go b/internal/services/wilayah_indonesia_service.go deleted file mode 100644 index 519522a..0000000 --- a/internal/services/wilayah_indonesia_service.go +++ /dev/null @@ -1,494 +0,0 @@ -package services - -import ( - "encoding/json" - "fmt" - "strconv" - "time" - - "rijig/dto" - "rijig/internal/repositories" - "rijig/model" - "rijig/utils" -) - -type WilayahIndonesiaService interface { - ImportDataFromCSV() error - - GetAllProvinces(page, limit int) ([]dto.ProvinceResponseDTO, int, error) - GetProvinceByID(id string, page, limit int) (*dto.ProvinceResponseDTO, int, error) - - GetAllRegencies(page, limit int) ([]dto.RegencyResponseDTO, int, error) - GetRegencyByID(id string, page, limit int) (*dto.RegencyResponseDTO, int, error) - - GetAllDistricts(page, limit int) ([]dto.DistrictResponseDTO, int, error) - GetDistrictByID(id string, page, limit int) (*dto.DistrictResponseDTO, int, error) - - GetAllVillages(page, limit int) ([]dto.VillageResponseDTO, int, error) - GetVillageByID(id string) (*dto.VillageResponseDTO, error) -} - -type wilayahIndonesiaService struct { - WilayahRepo repositories.WilayahIndonesiaRepository -} - -func NewWilayahIndonesiaService(wilayahRepo repositories.WilayahIndonesiaRepository) WilayahIndonesiaService { - return &wilayahIndonesiaService{WilayahRepo: wilayahRepo} -} - -func (s *wilayahIndonesiaService) ImportDataFromCSV() error { - - provinces, err := utils.ReadCSV("public/document/provinces.csv") - if err != nil { - return fmt.Errorf("failed to read provinces CSV: %v", err) - } - - var provinceList []model.Province - for _, record := range provinces[1:] { - province := model.Province{ - ID: record[0], - Name: record[1], - } - provinceList = append(provinceList, province) - } - - if err := s.WilayahRepo.ImportProvinces(provinceList); err != nil { - return fmt.Errorf("failed to import provinces: %v", err) - } - - regencies, err := utils.ReadCSV("public/document/regencies.csv") - if err != nil { - return fmt.Errorf("failed to read regencies CSV: %v", err) - } - - var regencyList []model.Regency - for _, record := range regencies[1:] { - regency := model.Regency{ - ID: record[0], - ProvinceID: record[1], - Name: record[2], - } - regencyList = append(regencyList, regency) - } - - if err := s.WilayahRepo.ImportRegencies(regencyList); err != nil { - return fmt.Errorf("failed to import regencies: %v", err) - } - - districts, err := utils.ReadCSV("public/document/districts.csv") - if err != nil { - return fmt.Errorf("failed to read districts CSV: %v", err) - } - - var districtList []model.District - for _, record := range districts[1:] { - district := model.District{ - ID: record[0], - RegencyID: record[1], - Name: record[2], - } - districtList = append(districtList, district) - } - - if err := s.WilayahRepo.ImportDistricts(districtList); err != nil { - return fmt.Errorf("failed to import districts: %v", err) - } - - villages, err := utils.ReadCSV("public/document/villages.csv") - if err != nil { - return fmt.Errorf("failed to read villages CSV: %v", err) - } - - var villageList []model.Village - for _, record := range villages[1:] { - village := model.Village{ - ID: record[0], - DistrictID: record[1], - Name: record[2], - } - villageList = append(villageList, village) - } - - if err := s.WilayahRepo.ImportVillages(villageList); err != nil { - return fmt.Errorf("failed to import villages: %v", err) - } - - return nil -} - -func (s *wilayahIndonesiaService) GetAllProvinces(page, limit int) ([]dto.ProvinceResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("provinces_page:%d_limit:%d", page, limit) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - var provinces []dto.ProvinceResponseDTO - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - province, ok := item.(map[string]interface{}) - if ok { - provinces = append(provinces, dto.ProvinceResponseDTO{ - ID: province["id"].(string), - Name: province["name"].(string), - }) - } - } - total := int(cachedData["total"].(float64)) - return provinces, total, nil - } - } - - provinces, total, err := s.WilayahRepo.FindAllProvinces(page, limit) - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch provinces: %v", err) - } - - var provinceDTOs []dto.ProvinceResponseDTO - for _, province := range provinces { - provinceDTOs = append(provinceDTOs, dto.ProvinceResponseDTO{ - ID: province.ID, - Name: province.Name, - }) - } - - cacheData := map[string]interface{}{ - "data": provinceDTOs, - "total": total, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching provinces data: %v\n", err) - } - - return provinceDTOs, total, nil -} - -func (s *wilayahIndonesiaService) GetProvinceByID(id string, page, limit int) (*dto.ProvinceResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("province:%s_page:%d_limit:%d", id, page, limit) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - - var provinceDTO dto.ProvinceResponseDTO - if data, ok := cachedData["data"].(string); ok { - if err := json.Unmarshal([]byte(data), &provinceDTO); err == nil { - - totalRegencies, _ := strconv.Atoi(cachedData["total_regencies"].(string)) - return &provinceDTO, totalRegencies, nil - } - } - } - - province, totalRegencies, err := s.WilayahRepo.FindProvinceByID(id, page, limit) - if err != nil { - return nil, 0, err - } - - provinceDTO := dto.ProvinceResponseDTO{ - ID: province.ID, - Name: province.Name, - } - - var regencyDTOs []dto.RegencyResponseDTO - for _, regency := range province.Regencies { - regencyDTO := dto.RegencyResponseDTO{ - ID: regency.ID, - ProvinceID: regency.ProvinceID, - Name: regency.Name, - } - regencyDTOs = append(regencyDTOs, regencyDTO) - } - - provinceDTO.Regencies = regencyDTOs - - cacheData := map[string]interface{}{ - "data": provinceDTO, - "total_regencies": strconv.Itoa(totalRegencies), - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching province data: %v\n", err) - } - - return &provinceDTO, totalRegencies, nil -} - -func (s *wilayahIndonesiaService) GetAllRegencies(page, limit int) ([]dto.RegencyResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("regencies_page:%d_limit:%d", page, limit) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - var regencies []dto.RegencyResponseDTO - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - regency, ok := item.(map[string]interface{}) - if ok { - regencies = append(regencies, dto.RegencyResponseDTO{ - ID: regency["id"].(string), - ProvinceID: regency["province_id"].(string), - Name: regency["name"].(string), - }) - } - } - total := int(cachedData["total"].(float64)) - return regencies, total, nil - } - } - - regencies, total, err := s.WilayahRepo.FindAllRegencies(page, limit) - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch provinces: %v", err) - } - - var regencyDTOs []dto.RegencyResponseDTO - for _, regency := range regencies { - regencyDTOs = append(regencyDTOs, dto.RegencyResponseDTO{ - ID: regency.ID, - ProvinceID: regency.ProvinceID, - Name: regency.Name, - }) - } - - cacheData := map[string]interface{}{ - "data": regencyDTOs, - "total": total, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching regencies data: %v\n", err) - } - - return regencyDTOs, total, nil -} - -func (s *wilayahIndonesiaService) GetRegencyByID(id string, page, limit int) (*dto.RegencyResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("regency:%s_page:%d_limit:%d", id, page, limit) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - - var regencyDTO dto.RegencyResponseDTO - if data, ok := cachedData["data"].(string); ok { - if err := json.Unmarshal([]byte(data), ®encyDTO); err == nil { - - totalDistrict, _ := strconv.Atoi(cachedData["total_regencies"].(string)) - return ®encyDTO, totalDistrict, nil - } - } - } - - regency, totalDistrict, err := s.WilayahRepo.FindRegencyByID(id, page, limit) - if err != nil { - return nil, 0, err - } - - regencyDTO := dto.RegencyResponseDTO{ - ID: regency.ID, - ProvinceID: regency.ProvinceID, - Name: regency.Name, - } - - var districtDTOs []dto.DistrictResponseDTO - for _, regency := range regency.Districts { - districtDTO := dto.DistrictResponseDTO{ - ID: regency.ID, - RegencyID: regency.RegencyID, - Name: regency.Name, - } - districtDTOs = append(districtDTOs, districtDTO) - } - - regencyDTO.Districts = districtDTOs - - cacheData := map[string]interface{}{ - "data": regencyDTO, - "total_regencies": strconv.Itoa(totalDistrict), - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching province data: %v\n", err) - } - - return ®encyDTO, totalDistrict, nil -} - -func (s *wilayahIndonesiaService) GetAllDistricts(page, limit int) ([]dto.DistrictResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("district_page:%d_limit:%d", page, limit) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - var districts []dto.DistrictResponseDTO - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - district, ok := item.(map[string]interface{}) - if ok { - districts = append(districts, dto.DistrictResponseDTO{ - ID: district["id"].(string), - RegencyID: district["regency_id"].(string), - Name: district["name"].(string), - }) - } - } - total := int(cachedData["total"].(float64)) - return districts, total, nil - } - } - - districts, total, err := s.WilayahRepo.FindAllDistricts(page, limit) - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch districts: %v", err) - } - - var districtsDTOs []dto.DistrictResponseDTO - for _, district := range districts { - districtsDTOs = append(districtsDTOs, dto.DistrictResponseDTO{ - ID: district.ID, - RegencyID: district.RegencyID, - Name: district.Name, - }) - } - - cacheData := map[string]interface{}{ - "data": districtsDTOs, - "total": total, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching districts data: %v\n", err) - } - - return districtsDTOs, total, nil -} - -func (s *wilayahIndonesiaService) GetDistrictByID(id string, page, limit int) (*dto.DistrictResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("district:%s_page:%d_limit:%d", id, page, limit) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - - var districtDTO dto.DistrictResponseDTO - if data, ok := cachedData["data"].(string); ok { - if err := json.Unmarshal([]byte(data), &districtDTO); err == nil { - - totalVillage, _ := strconv.Atoi(cachedData["total_village"].(string)) - return &districtDTO, totalVillage, nil - } - } - } - - district, totalVillages, err := s.WilayahRepo.FindDistrictByID(id, page, limit) - if err != nil { - return nil, 0, err - } - - districtDTO := dto.DistrictResponseDTO{ - ID: district.ID, - RegencyID: district.RegencyID, - Name: district.Name, - } - - var villageDTOs []dto.VillageResponseDTO - for _, village := range district.Villages { - regencyDTO := dto.VillageResponseDTO{ - ID: village.ID, - DistrictID: village.DistrictID, - Name: village.Name, - } - villageDTOs = append(villageDTOs, regencyDTO) - } - - districtDTO.Villages = villageDTOs - - cacheData := map[string]interface{}{ - "data": districtDTO, - "total_villages": strconv.Itoa(totalVillages), - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching province data: %v\n", err) - } - - return &districtDTO, totalVillages, nil -} - -func (s *wilayahIndonesiaService) GetAllVillages(page, limit int) ([]dto.VillageResponseDTO, int, error) { - - cacheKey := fmt.Sprintf("villages_page:%d_limit:%d", page, limit) - - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - var villages []dto.VillageResponseDTO - if data, ok := cachedData["data"].([]interface{}); ok { - for _, item := range data { - villageData, ok := item.(map[string]interface{}) - if ok { - villages = append(villages, dto.VillageResponseDTO{ - ID: villageData["id"].(string), - DistrictID: villageData["district_id"].(string), - Name: villageData["name"].(string), - }) - } - } - return villages, int(cachedData["total"].(float64)), nil - } - } - - villages, total, err := s.WilayahRepo.FindAllVillages(page, limit) - if err != nil { - return nil, 0, fmt.Errorf("failed to fetch villages: %v", err) - } - - var villageDTOs []dto.VillageResponseDTO - for _, village := range villages { - villageDTOs = append(villageDTOs, dto.VillageResponseDTO{ - ID: village.ID, - DistrictID: village.DistrictID, - Name: village.Name, - }) - } - - cacheData := map[string]interface{}{ - "data": villageDTOs, - "total": total, - } - err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) - if err != nil { - fmt.Printf("Error caching villages data to Redis: %v\n", err) - } - - return villageDTOs, total, nil -} - -func (s *wilayahIndonesiaService) GetVillageByID(id string) (*dto.VillageResponseDTO, error) { - - cacheKey := fmt.Sprintf("village:%s", id) - cachedData, err := utils.GetJSONData(cacheKey) - if err == nil && cachedData != nil { - villageResponse := &dto.VillageResponseDTO{} - if data, ok := cachedData["data"].(string); ok { - if err := json.Unmarshal([]byte(data), villageResponse); err == nil { - return villageResponse, nil - } - } - } - - village, err := s.WilayahRepo.FindVillageByID(id) - if err != nil { - return nil, fmt.Errorf("village not found: %v", err) - } - - villageResponse := &dto.VillageResponseDTO{ - ID: village.ID, - DistrictID: village.DistrictID, - Name: village.Name, - } - - cacheData := map[string]interface{}{ - "data": villageResponse, - } - err = utils.SetJSONData(cacheKey, cacheData, 24*time.Hour) - if err != nil { - fmt.Printf("Error caching village data to Redis: %v\n", err) - } - - return villageResponse, nil -} diff --git a/internal/worker/cart_worker.go b/internal/worker/cart_worker.go index 5c292da..e6bd367 100644 --- a/internal/worker/cart_worker.go +++ b/internal/worker/cart_worker.go @@ -1,5 +1,5 @@ package worker - +/* import ( "context" "encoding/json" @@ -156,3 +156,4 @@ func (w *CartWorker) commitCartToDB(ctx context.Context, userID string, cartData return w.cartRepo.CreateCartWithItems(ctx, newCart) } + */ \ No newline at end of file diff --git a/presentation/about_route.go b/presentation/about_route.go deleted file mode 100644 index 78871ed..0000000 --- a/presentation/about_route.go +++ /dev/null @@ -1,35 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/about" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -func AboutRouter(api fiber.Router) { - aboutRepo := repositories.NewAboutRepository(config.DB) - aboutService := services.NewAboutService(aboutRepo) - aboutHandler := about.NewAboutHandler(aboutService) - - aboutRoutes := api.Group("/about") - aboutRoutes.Use(middleware.AuthMiddleware()) - - aboutRoutes.Get("/", aboutHandler.GetAllAbout) - aboutRoutes.Get("/:id", aboutHandler.GetAboutByID) - aboutRoutes.Post("/", aboutHandler.CreateAbout) // admin - aboutRoutes.Put("/:id", middleware.RequireRoles(utils.RoleAdministrator), aboutHandler.UpdateAbout) - aboutRoutes.Delete("/:id", aboutHandler.DeleteAbout) // admin - - aboutDetailRoutes := api.Group("/about-detail") - aboutDetailRoutes.Use(middleware.AuthMiddleware()) - aboutDetailRoute := api.Group("/about-detail") - aboutDetailRoute.Get("/:id", aboutHandler.GetAboutDetailById) - aboutDetailRoutes.Post("/", aboutHandler.CreateAboutDetail) // admin - aboutDetailRoutes.Put("/:id", middleware.RequireRoles(utils.RoleAdministrator), aboutHandler.UpdateAboutDetail) - aboutDetailRoutes.Delete("/:id", middleware.RequireRoles(utils.RoleAdministrator), aboutHandler.DeleteAboutDetail) -} diff --git a/presentation/address_route.go b/presentation/address_route.go deleted file mode 100644 index 6b563a8..0000000 --- a/presentation/address_route.go +++ /dev/null @@ -1,26 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func AddressRouter(api fiber.Router) { - addressRepo := repositories.NewAddressRepository(config.DB) - wilayahRepo := repositories.NewWilayahIndonesiaRepository(config.DB) - addressService := services.NewAddressService(addressRepo, wilayahRepo) - addressHandler := handler.NewAddressHandler(addressService) - - adddressAPI := api.Group("/user/address") - - adddressAPI.Post("/create-address", middleware.AuthMiddleware(), addressHandler.CreateAddress) - adddressAPI.Get("/get-address", middleware.AuthMiddleware(), addressHandler.GetAddressByUserID) - adddressAPI.Get("/get-address/:address_id", middleware.AuthMiddleware(), addressHandler.GetAddressByID) - adddressAPI.Put("/update-address/:address_id", middleware.AuthMiddleware(), addressHandler.UpdateAddress) - adddressAPI.Delete("/delete-address/:address_id", middleware.AuthMiddleware(), addressHandler.DeleteAddress) -} diff --git a/presentation/article_route.go b/presentation/article_route.go deleted file mode 100644 index 1a741f2..0000000 --- a/presentation/article_route.go +++ /dev/null @@ -1,26 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -func ArticleRouter(api fiber.Router) { - articleRepo := repositories.NewArticleRepository(config.DB) - articleService := services.NewArticleService(articleRepo) - articleHandler := handler.NewArticleHandler(articleService) - - articleAPI := api.Group("/article-rijik") - - articleAPI.Post("/create-article", middleware.AuthMiddleware(), middleware.RequireRoles(utils.RoleAdministrator), articleHandler.CreateArticle) - articleAPI.Get("/view-article", articleHandler.GetAllArticles) - articleAPI.Get("/view-article/:article_id", articleHandler.GetArticleByID) - articleAPI.Put("/update-article/:article_id", middleware.AuthMiddleware(), middleware.RequireRoles(utils.RoleAdministrator), articleHandler.UpdateArticle) - articleAPI.Delete("/delete-article/:article_id", middleware.AuthMiddleware(), middleware.RequireRoles(utils.RoleAdministrator), articleHandler.DeleteArticle) -} diff --git a/presentation/auth/auth_admin_route.go b/presentation/auth/auth_admin_route.go deleted file mode 100644 index 3d20de9..0000000 --- a/presentation/auth/auth_admin_route.go +++ /dev/null @@ -1,36 +0,0 @@ -package presentation -/* -import ( - "log" - "os" - "rijig/config" - handler "rijig/internal/handler/auth" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - services "rijig/internal/services/auth" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func AuthAdminRouter(api fiber.Router) { - secretKey := os.Getenv("SECRET_KEY") - if secretKey == "" { - log.Fatal("SECRET_KEY is not set in the environment variables") - os.Exit(1) - } - - adminAuthRepo := repository.NewAuthAdminRepository(config.DB) - roleRepo := repositories.NewRoleRepository(config.DB) - - adminAuthService := services.NewAuthAdminService(adminAuthRepo, roleRepo, secretKey) - - adminAuthHandler := handler.NewAuthAdminHandler(adminAuthService) - - adminAuthAPI := api.Group("/admin-auth") - - adminAuthAPI.Post("/register", adminAuthHandler.RegisterAdmin) - adminAuthAPI.Post("/login", adminAuthHandler.LoginAdmin) - adminAuthAPI.Post("/logout", middleware.AuthMiddleware, adminAuthHandler.LogoutAdmin) -} - */ \ No newline at end of file diff --git a/presentation/auth/auth_masyarakat_route.go b/presentation/auth/auth_masyarakat_route.go deleted file mode 100644 index c5f8af7..0000000 --- a/presentation/auth/auth_masyarakat_route.go +++ /dev/null @@ -1,27 +0,0 @@ -package presentation -/* -import ( - "rijig/config" - handler "rijig/internal/handler/auth" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - services "rijig/internal/services/auth" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func AuthMasyarakatRouter(api fiber.Router) { - authMasyarakatRepo := repository.NewAuthMasyarakatRepositories(config.DB) - roleRepo := repositories.NewRoleRepository(config.DB) - authMasyarakatService := services.NewAuthMasyarakatService(authMasyarakatRepo, roleRepo) - - authHandler := handler.NewAuthMasyarakatHandler(authMasyarakatService) - - authMasyarakat := api.Group("/authmasyarakat") - - authMasyarakat.Post("/auth", authHandler.RegisterOrLoginHandler) - authMasyarakat.Post("/logout", middleware.AuthMiddleware, authHandler.LogoutHandler) - authMasyarakat.Post("/verify-otp", authHandler.VerifyOTPHandler) -} - */ \ No newline at end of file diff --git a/presentation/auth/auth_pengelola_route.go b/presentation/auth/auth_pengelola_route.go deleted file mode 100644 index efcd9e1..0000000 --- a/presentation/auth/auth_pengelola_route.go +++ /dev/null @@ -1,27 +0,0 @@ -package presentation -/* -import ( - "rijig/config" - handler "rijig/internal/handler/auth" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - services "rijig/internal/services/auth" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func AuthPengelolaRouter(api fiber.Router) { - authPengelolaRepo := repository.NewAuthPengelolaRepositories(config.DB) - roleRepo := repositories.NewRoleRepository(config.DB) - authPengelolaService := services.NewAuthPengelolaService(authPengelolaRepo, roleRepo) - - authHandler := handler.NewAuthPengelolaHandler(authPengelolaService) - - authPengelola := api.Group("/authpengelola") - - authPengelola.Post("/auth", authHandler.RegisterOrLoginHandler) - authPengelola.Post("/logout", middleware.AuthMiddleware, authHandler.LogoutHandler) - authPengelola.Post("/verify-otp", authHandler.VerifyOTPHandler) -} - */ \ No newline at end of file diff --git a/presentation/auth/auth_pengepul_route.go b/presentation/auth/auth_pengepul_route.go deleted file mode 100644 index d796da4..0000000 --- a/presentation/auth/auth_pengepul_route.go +++ /dev/null @@ -1,27 +0,0 @@ -package presentation -/* -import ( - "rijig/config" - handler "rijig/internal/handler/auth" - "rijig/internal/repositories" - repository "rijig/internal/repositories/auth" - services "rijig/internal/services/auth" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func AuthPengepulRouter(api fiber.Router) { - authPengepulRepo := repository.NewAuthPengepulRepositories(config.DB) - roleRepo := repositories.NewRoleRepository(config.DB) - authPengepulService := services.NewAuthPengepulService(authPengepulRepo, roleRepo) - - authHandler := handler.NewAuthPengepulHandler(authPengepulService) - - authPengepul := api.Group("/authpengepul") - - authPengepul.Post("/auth", authHandler.RegisterOrLoginHandler) - authPengepul.Post("/logout", middleware.AuthMiddleware, authHandler.LogoutHandler) - authPengepul.Post("/verify-otp", authHandler.VerifyOTPHandler) -} - */ \ No newline at end of file diff --git a/presentation/auth_route.go b/presentation/auth_route.go deleted file mode 100644 index ee733c1..0000000 --- a/presentation/auth_route.go +++ /dev/null @@ -1,23 +0,0 @@ -package presentation - -// import ( -// "rijig/config" -// "rijig/internal/handler" -// "rijig/internal/repositories" -// "rijig/internal/services" -// "rijig/middleware" - -// "github.com/gofiber/fiber/v2" -// ) - -// func AuthRouter(api fiber.Router) { -// userRepo := repositories.NewUserRepository(config.DB) -// roleRepo := repositories.NewRoleRepository(config.DB) -// authService := services.NewAuthService(userRepo, roleRepo) - -// authHandler := handler.NewAuthHandler(authService) - -// api.Post("/auth", authHandler.RegisterOrLoginHandler) -// api.Post("/logout", middleware.AuthMiddleware, authHandler.LogoutHandler) -// api.Post("/verify-otp", authHandler.VerifyOTPHandler) -// } diff --git a/presentation/cart_router.go b/presentation/cart_router.go deleted file mode 100644 index 05d66fb..0000000 --- a/presentation/cart_router.go +++ /dev/null @@ -1,28 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func TrashCartRouter(api fiber.Router) { - repo := repositories.NewCartRepository() - trashRepo := repositories.NewTrashRepository(config.DB) - cartService := services.NewCartService(repo, trashRepo) - cartHandler := handler.NewCartHandler(cartService) - - cart := api.Group("/cart") - cart.Use(middleware.AuthMiddleware()) - - cart.Get("/", cartHandler.GetCart) - cart.Post("/item", cartHandler.AddOrUpdateItem) - cart.Delete("/item/:trash_id", cartHandler.DeleteItem) - cart.Delete("/clear", cartHandler.ClearCart) -} - -// cart.Post("/items", cartHandler.AddMultipleCartItems) diff --git a/presentation/collector_route.go b/presentation/collector_route.go deleted file mode 100644 index a5f9b17..0000000 --- a/presentation/collector_route.go +++ /dev/null @@ -1,42 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func CollectorRouter(api fiber.Router) { - cartRepo := repositories.NewCartRepository() - // trashRepo repositories.TrashRepository - - pickupRepo := repositories.NewRequestPickupRepository() - trashRepo := repositories.NewTrashRepository(config.DB) - historyRepo := repositories.NewPickupStatusHistoryRepository() - cartService := services.NewCartService(cartRepo, trashRepo) - - pickupService := services.NewRequestPickupService(trashRepo, pickupRepo, cartService, historyRepo) - pickupHandler := handler.NewRequestPickupHandler(pickupService) - collectorRepo := repositories.NewCollectorRepository() - - collectorService := services.NewCollectorService(collectorRepo, trashRepo) - collectorHandler := handler.NewCollectorHandler(collectorService) - - collectors := api.Group("/collectors") - collectors.Use(middleware.AuthMiddleware()) - - collectors.Post("/", collectorHandler.CreateCollector) - collectors.Post("/:id/trash", collectorHandler.AddTrashToCollector) - collectors.Get("/:id", collectorHandler.GetCollectorByID) - collectors.Get("/", collectorHandler.GetCollectorByUserID) - collectors.Get("/pickup/assigned-to-me", pickupHandler.GetAssignedPickup) - - collectors.Patch("/:id", collectorHandler.UpdateCollector) - collectors.Patch("/:id/trash", collectorHandler.UpdateTrash) - collectors.Patch("/:id/job-status", collectorHandler.UpdateJobStatus) - collectors.Delete("/trash/:id", collectorHandler.DeleteTrash) -} diff --git a/presentation/company_profile_route.go b/presentation/company_profile_route.go deleted file mode 100644 index 709ab0b..0000000 --- a/presentation/company_profile_route.go +++ /dev/null @@ -1,27 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func CompanyProfileRouter(api fiber.Router) { - - companyProfileRepo := repositories.NewCompanyProfileRepository(config.DB) - companyProfileService := services.NewCompanyProfileService(companyProfileRepo) - companyProfileHandler := handler.NewCompanyProfileHandler(companyProfileService) - - companyProfileAPI := api.Group("/company-profile") - companyProfileAPI.Use(middleware.AuthMiddleware()) - - companyProfileAPI.Post("/create", companyProfileHandler.CreateCompanyProfile) - companyProfileAPI.Get("/get/:company_id", companyProfileHandler.GetCompanyProfileByID) - companyProfileAPI.Get("/get", companyProfileHandler.GetCompanyProfilesByUserID) - companyProfileAPI.Put("/update/:company_id", companyProfileHandler.UpdateCompanyProfile) - companyProfileAPI.Delete("/delete/:company_id", companyProfileHandler.DeleteCompanyProfile) -} diff --git a/presentation/coveragearea_route.go b/presentation/coveragearea_route.go deleted file mode 100644 index a1603ed..0000000 --- a/presentation/coveragearea_route.go +++ /dev/null @@ -1,25 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - - "github.com/gofiber/fiber/v2" -) - -func CoverageAreaRouter(api fiber.Router) { - coverageAreaRepo := repositories.NewCoverageAreaRepository(config.DB) - wilayahRepo := repositories.NewWilayahIndonesiaRepository(config.DB) - coverageAreaService := services.NewCoverageAreaService(coverageAreaRepo, wilayahRepo) - coverageAreaHandler := handler.NewCoverageAreaHandler(coverageAreaService) - - coverage := api.Group("/coveragearea") - - coverage.Post("/", coverageAreaHandler.CreateCoverageArea) - coverage.Get("/", coverageAreaHandler.GetAllCoverageAreas) - coverage.Get("/:id", coverageAreaHandler.GetCoverageAreaByID) - coverage.Put("/:id", coverageAreaHandler.UpdateCoverageArea) - coverage.Delete("/:id", coverageAreaHandler.DeleteCoverageArea) -} diff --git a/presentation/identitycard_route.go b/presentation/identitycard_route.go deleted file mode 100644 index 39301b2..0000000 --- a/presentation/identitycard_route.go +++ /dev/null @@ -1,29 +0,0 @@ -package presentation -/* -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -func IdentityCardRouter(api fiber.Router) { - identityCardRepo := repositories.NewIdentityCardRepository(config.DB) - userRepo := repositories.NewUserProfilRepository(config.DB) - identityCardService := services.NewIdentityCardService(identityCardRepo, userRepo) - identityCardHandler := handler.NewIdentityCardHandler(identityCardService) - - identityCardApi := api.Group("/identitycard") - identityCardApi.Use(middleware.AuthMiddleware) - - identityCardApi.Post("/create", middleware.RoleMiddleware(utils.RolePengelola, utils.RolePengepul), identityCardHandler.CreateIdentityCard) - identityCardApi.Get("/get/:identity_id", identityCardHandler.GetIdentityCardById) - identityCardApi.Get("/get", identityCardHandler.GetIdentityCard) - identityCardApi.Put("/update/:identity_id", middleware.RoleMiddleware(utils.RolePengelola, utils.RolePengepul), identityCardHandler.UpdateIdentityCard) - identityCardApi.Delete("/delete/:identity_id", middleware.RoleMiddleware(utils.RolePengelola, utils.RolePengepul), identityCardHandler.DeleteIdentityCard) -} - */ \ No newline at end of file diff --git a/presentation/pickup_matching_route.go b/presentation/pickup_matching_route.go deleted file mode 100644 index a389640..0000000 --- a/presentation/pickup_matching_route.go +++ /dev/null @@ -1,25 +0,0 @@ -package presentation - -import ( - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func PickupMatchingRouter(api fiber.Router) { - pickupRepo := repositories.NewRequestPickupRepository() - collectorRepo := repositories.NewCollectorRepository() - service := services.NewPickupMatchingService(pickupRepo, collectorRepo) - handler := handler.NewPickupMatchingHandler(service) - - manual := api.Group("/pickup/manual") - manual.Use(middleware.AuthMiddleware()) - manual.Get("/:pickupID/nearby-collectors", handler.GetNearbyCollectorsForPickup) - - auto := api.Group("/pickup/otomatis") - auto.Use(middleware.AuthMiddleware()) - auto.Get("/available-requests", handler.GetAvailablePickupForCollector) -} diff --git a/presentation/rating_route.go b/presentation/rating_route.go deleted file mode 100644 index 6d801aa..0000000 --- a/presentation/rating_route.go +++ /dev/null @@ -1,24 +0,0 @@ -package presentation - -import ( - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func PickupRatingRouter(api fiber.Router) { - ratingRepo := repositories.NewPickupRatingRepository() - ratingService := services.NewPickupRatingService(ratingRepo) - ratingHandler := handler.NewPickupRatingHandler(ratingService) - - rating := api.Group("/pickup") - rating.Use(middleware.AuthMiddleware()) - rating.Post("/:id/rating", ratingHandler.CreateRating) - - collector := api.Group("/collector") - collector.Get("/:id/ratings", ratingHandler.GetRatingsByCollector) - collector.Get("/:id/ratings/average", ratingHandler.GetAverageRating) -} diff --git a/presentation/request_pickup_route.go b/presentation/request_pickup_route.go deleted file mode 100644 index 81c6681..0000000 --- a/presentation/request_pickup_route.go +++ /dev/null @@ -1,35 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func RequestPickupRouter(api fiber.Router) { - cartRepo := repositories.NewCartRepository() - pickupRepo := repositories.NewRequestPickupRepository() - historyRepo := repositories.NewPickupStatusHistoryRepository() - trashRepo := repositories.NewTrashRepository(config.DB) - - cartService := services.NewCartService(cartRepo, trashRepo) - historyService := services.NewPickupStatusHistoryService(historyRepo) - - pickupService := services.NewRequestPickupService(trashRepo, pickupRepo, cartService, historyRepo) - pickupHandler := handler.NewRequestPickupHandler(pickupService) - statuspickupHandler := handler.NewPickupStatusHistoryHandler(historyService) - - reqpickup := api.Group("/reqpickup") - reqpickup.Use(middleware.AuthMiddleware()) - - reqpickup.Post("/manual", pickupHandler.CreateRequestPickup) - reqpickup.Get("/pickup/:id/history", statuspickupHandler.GetStatusHistory) - reqpickup.Post("/otomatis", pickupHandler.CreateRequestPickup) - reqpickup.Put("/:id/select-collector", pickupHandler.SelectCollector) - reqpickup.Put("/pickup/:id/status", pickupHandler.UpdatePickupStatus) - reqpickup.Put("/pickup/:id/item/update-actual", pickupHandler.UpdatePickupItemActualAmount) -} diff --git a/presentation/role_route.go b/presentation/role_route.go deleted file mode 100644 index 6ec230a..0000000 --- a/presentation/role_route.go +++ /dev/null @@ -1,19 +0,0 @@ -package presentation - -// import ( -// "rijig/config" -// "rijig/internal/handler" -// "rijig/internal/repositories" -// "rijig/internal/services" - -// "github.com/gofiber/fiber/v2" -// ) - -// func RoleRouter(api fiber.Router) { -// roleRepo := repositories.NewRoleRepository(config.DB) -// roleService := services.NewRoleService(roleRepo) -// roleHandler := handler.NewRoleHandler(roleService) - -// api.Get("/roles", roleHandler.GetRoles) -// api.Get("/role/:role_id", roleHandler.GetRoleByID) -// } diff --git a/presentation/trash_route.go b/presentation/trash_route.go deleted file mode 100644 index bef7b83..0000000 --- a/presentation/trash_route.go +++ /dev/null @@ -1,33 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -func TrashRouter(api fiber.Router) { - trashRepo := repositories.NewTrashRepository(config.DB) - trashService := services.NewTrashService(trashRepo) - trashHandler := handler.NewTrashHandler(trashService) - - trashAPI := api.Group("/trash") - trashAPI.Use(middleware.AuthMiddleware()) - - trashAPI.Post("/category", middleware.RequireRoles(utils.RoleAdministrator), trashHandler.CreateCategory) - trashAPI.Post("/category/detail", middleware.RequireRoles(utils.RoleAdministrator), trashHandler.AddDetailToCategory) - trashAPI.Get("/categories", trashHandler.GetCategories) - trashAPI.Get("/category/:category_id", trashHandler.GetCategoryByID) - trashAPI.Get("/detail/:detail_id", trashHandler.GetTrashDetailByID) - - trashAPI.Patch("/category/:category_id", middleware.RequireRoles(utils.RoleAdministrator), trashHandler.UpdateCategory) - trashAPI.Put("/detail/:detail_id", middleware.RequireRoles(utils.RoleAdministrator), trashHandler.UpdateDetail) - - trashAPI.Delete("/category/:category_id", middleware.RequireRoles(utils.RoleAdministrator), trashHandler.DeleteCategory) - trashAPI.Delete("/detail/:detail_id", middleware.RequireRoles(utils.RoleAdministrator), trashHandler.DeleteDetail) -} diff --git a/presentation/user_route.go b/presentation/user_route.go deleted file mode 100644 index c008ace..0000000 --- a/presentation/user_route.go +++ /dev/null @@ -1,29 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - - "github.com/gofiber/fiber/v2" -) - -func UserProfileRouter(api fiber.Router) { - userProfileRepo := repositories.NewUserProfilRepository(config.DB) - userProfileService := services.NewUserService(userProfileRepo) - userProfileHandler := handler.NewUserHandler(userProfileService) - - userProfilRoute := api.Group("/user") - - userProfilRoute.Get("/info", middleware.AuthMiddleware(), userProfileHandler.GetUserByIDHandler) - - userProfilRoute.Get("/show-all", middleware.AuthMiddleware(), userProfileHandler.GetAllUsersHandler) - // userProfilRoute.Get("/:userid", middleware.AuthMiddleware, userProfileHandler.GetUserProfileById) - // userProfilRoute.Get("/:roleid", middleware.AuthMiddleware, userProfileHandler.GetUsersByRoleID) - - userProfilRoute.Put("/update-user", middleware.AuthMiddleware(), userProfileHandler.UpdateUserHandler) - userProfilRoute.Patch("/update-user-password", middleware.AuthMiddleware(), userProfileHandler.UpdateUserPasswordHandler) - userProfilRoute.Patch("/upload-photoprofile", middleware.AuthMiddleware(), userProfileHandler.UpdateUserAvatarHandler) -} diff --git a/presentation/userpin_route.go b/presentation/userpin_route.go deleted file mode 100644 index 9d6dbbb..0000000 --- a/presentation/userpin_route.go +++ /dev/null @@ -1,24 +0,0 @@ -package presentation - -import ( - /* "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" */ - - "github.com/gofiber/fiber/v2" -) - -func UserPinRouter(api fiber.Router) { - // userPinRepo := repositories.NewUserPinRepository(config.DB) - - // userPinService := services.NewUserPinService(userPinRepo) - - // userPinHandler := handler.NewUserPinHandler(userPinService) - - // api.Post("/set-pin", middleware.AuthMiddleware, userPinHandler.CreateUserPin) - // api.Post("/verif-pin", middleware.AuthMiddleware, userPinHandler.VerifyUserPin) - // api.Get("/cek-pin-status", middleware.AuthMiddleware, userPinHandler.CheckPinStatus) - // api.Patch("/update-pin", middleware.AuthMiddleware, userPinHandler.UpdateUserPin) -} diff --git a/presentation/wilayahindonesia_route.go b/presentation/wilayahindonesia_route.go deleted file mode 100644 index 13bfa44..0000000 --- a/presentation/wilayahindonesia_route.go +++ /dev/null @@ -1,36 +0,0 @@ -package presentation - -import ( - "rijig/config" - "rijig/internal/handler" - "rijig/internal/repositories" - "rijig/internal/services" - "rijig/middleware" - "rijig/utils" - - "github.com/gofiber/fiber/v2" -) - -func WilayahRouter(api fiber.Router) { - - wilayahRepo := repositories.NewWilayahIndonesiaRepository(config.DB) - wilayahService := services.NewWilayahIndonesiaService(wilayahRepo) - wilayahHandler := handler.NewWilayahImportHandler(wilayahService) - - api.Post("/import/data-wilayah-indonesia", middleware.RequireRoles(utils.RoleAdministrator), wilayahHandler.ImportWilayahData) - - wilayahAPI := api.Group("/wilayah-indonesia") - - wilayahAPI.Get("/provinces", wilayahHandler.GetProvinces) - wilayahAPI.Get("/provinces/:provinceid", wilayahHandler.GetProvinceByID) - - wilayahAPI.Get("/regencies", wilayahHandler.GetAllRegencies) - wilayahAPI.Get("/regencies/:regencyid", wilayahHandler.GetRegencyByID) - - wilayahAPI.Get("/districts", wilayahHandler.GetAllDistricts) - wilayahAPI.Get("/districts/:districtid", wilayahHandler.GetDistrictByID) - - wilayahAPI.Get("/villages", wilayahHandler.GetAllVillages) - wilayahAPI.Get("/villages/:villageid", wilayahHandler.GetVillageByID) - -} diff --git a/router/setup_routes.go.go b/router/setup_routes.go.go index cdcb51f..d06911a 100644 --- a/router/setup_routes.go.go +++ b/router/setup_routes.go.go @@ -11,9 +11,8 @@ import ( "rijig/internal/userpin" "rijig/internal/whatsapp" "rijig/middleware" - "rijig/presentation" + // "rijig/presentation" - // presentationn "rijig/presentation/auth" "github.com/gofiber/fiber/v2" ) @@ -41,22 +40,22 @@ func SetupRoutes(app *fiber.App) { // presentationn.AuthMasyarakatRouter(api) // || auth router || // // presentation.IdentityCardRouter(api) - presentation.CompanyProfileRouter(api) - presentation.RequestPickupRouter(api) - presentation.PickupMatchingRouter(api) - presentation.PickupRatingRouter(api) + // presentation.CompanyProfileRouter(api) + // presentation.RequestPickupRouter(api) + // presentation.PickupMatchingRouter(api) + // presentation.PickupRatingRouter(api) - presentation.CollectorRouter(api) - presentation.TrashCartRouter(api) + // presentation.CollectorRouter(api) + // presentation.TrashCartRouter(api) - presentation.UserProfileRouter(api) - presentation.UserPinRouter(api) - // presentation.RoleRouter(api) - presentation.WilayahRouter(api) - presentation.AddressRouter(api) - // presentation.ArticleRouter(api) - presentation.AboutRouter(api) - presentation.TrashRouter(api) - presentation.CoverageAreaRouter(api) + // presentation.UserProfileRouter(api) + // presentation.UserPinRouter(api) + // // presentation.RoleRouter(api) + // presentation.WilayahRouter(api) + // presentation.AddressRouter(api) + // // presentation.ArticleRouter(api) + // // presentation.AboutRouter(api) + // presentation.TrashRouter(api) + // presentation.CoverageAreaRouter(api) whatsapp.WhatsAppRouter(api) }