package controller import ( "encoding/json" "fmt" "mime/multipart" "net/http" "strconv" "strings" "users_management/m/config" "users_management/m/middleware" "users_management/m/model/dto/req" "users_management/m/usecase" "users_management/m/utils/common" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type TowerController struct { tu usecase.TowerUseCase rg *gin.RouterGroup cfg *config.Config } func (tc *TowerController) Route() { rg := tc.rg.Group("/tower") rg.Use(middleware.ConditionalRequireAnyRole(tc.cfg,"Teknisi", "Admin","Super Admin")) // Apply middleware to all routes { rg.GET("", tc.GetTower()) rg.POST("", tc.CreateTower()) rg.GET("/:uuid", tc.GetTowerByID()) rg.PUT("/:uuid", tc.UpdateTower()) rg.POST("/bulk-upload-images", tc.BulkUploadImages()) } } func NewTowerController(tu usecase.TowerUseCase, rg *gin.RouterGroup, cfg *config.Config) *TowerController { return &TowerController{ tu: tu, rg: rg, cfg: cfg, } } func (tc *TowerController) BulkUploadImages() gin.HandlerFunc { return func(c *gin.Context) { // Parse multipart form err := c.Request.ParseMultipartForm(50 << 20) // 50MB max for bulk if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Failed to parse multipart form") return } // Get tower data from form towerDataStr := c.PostForm("towers") if towerDataStr == "" { common.ErrorResponses(c, http.StatusBadRequest, "towers data is required") return } // Parse tower data var towersData []req.BulkTowerImageUploadDTO if err := json.Unmarshal([]byte(towerDataStr), &towersData); err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid towers data format") return } // Get image files form := c.Request.MultipartForm files := form.File["images"] if len(files) == 0 { common.ErrorResponses(c, http.StatusBadRequest, "No image files provided") return } if len(files) != len(towersData) { common.ErrorResponses(c, http.StatusBadRequest, fmt.Sprintf("Number of images (%d) must match number of towers (%d)", len(files), len(towersData))) return } // Call use case err = tc.tu.BulkUploadImages(towersData, files) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, fmt.Sprintf("%d tower images uploaded successfully", len(towersData)), nil) } } func (tc *TowerController) GetTower() gin.HandlerFunc { return func(c *gin.Context) { towers, err := tc.tu.GetAll() if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, "Success", towers) } } func (tc *TowerController) CreateTower() gin.HandlerFunc { return func(c *gin.Context) { contentType := c.GetHeader("Content-Type") // Handle JSON request (no images) if strings.Contains(contentType, "application/json") { var towerDTO req.TowerDTO if err := c.ShouldBindJSON(&towerDTO); err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid JSON format: "+err.Error()) return } // No image files for JSON requests err := tc.tu.Post(towerDTO, nil) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, "Tower has been created", nil) return } // Parse multipart form err := c.Request.ParseMultipartForm(50 << 20) // Increase to 50MB for multiple images if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Failed to parse multipart form") return } // Extract form data deviceIDStr := c.PostForm("dev_id") towerCode := c.PostForm("tower_code") longitudeStr := c.PostForm("longitude") latitudeStr := c.PostForm("latitude") externalTowerStr := c.PostForm("external_tower") // Validate required fields if towerCode == "" || longitudeStr == "" || latitudeStr == "" { common.ErrorResponses(c, http.StatusBadRequest, "Missing required fields") return } var deviceID *uuid.UUID if deviceIDStr != "" { parsedDeviceID, err := uuid.Parse(deviceIDStr) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid device ID") return } deviceID = &parsedDeviceID } // Parse coordinates longitude, err := strconv.ParseFloat(longitudeStr, 64) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid longitude") return } latitude, err := strconv.ParseFloat(latitudeStr, 64) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid latitude") return } var externalTower *bool if externalTowerStr != "" { parsedExternalTower, err := strconv.ParseBool(externalTowerStr) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid external_tower value") return } externalTower = &parsedExternalTower } var backboneCode *string if bc := c.PostForm("backbone_code"); bc != "" { backboneCode = &bc } // Create DTO towerDTO := req.TowerDTO{ DeviceID: deviceID, TowerCode: towerCode, Longitude: longitude, Latitude: latitude, ExternalTower: externalTower, BackboneCode: backboneCode, } // Get multiple image files form := c.Request.MultipartForm imageFiles := form.File["images"] // Changed from "image" to "images" to support multiple // Also support single image upload for backward compatibility if len(imageFiles) == 0 { if singleImage, err := c.FormFile("image"); err == nil { imageFiles = []*multipart.FileHeader{singleImage} } } err = tc.tu.PostWithMultipleImages(towerDTO, imageFiles) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, "Tower has been created", nil) } } func (tc *TowerController) GetTowerByID() gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("uuid") uuid, err := uuid.Parse(id) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } tower, err := tc.tu.GetByID(uuid) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, "Success", tower) } } func (tc *TowerController) UpdateTower() gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("uuid") tower_uuid, err := uuid.Parse(id) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } contentType := c.GetHeader("Content-Type") // Handle JSON request (no images) if strings.Contains(contentType, "application/json") { var towerUpdateDTO req.UpdateTowerDTO if err := c.ShouldBindJSON(&towerUpdateDTO); err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Invalid JSON format: "+err.Error()) return } // No image files for JSON requests err := tc.tu.UpdateTowerWithMultipleImages(tower_uuid, towerUpdateDTO, nil) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, "Tower has been updated", nil) return } // Handle multipart form request err = c.Request.ParseMultipartForm(50 << 20) // Increase to 50MB for multiple images if err != nil { common.ErrorResponses(c, http.StatusBadRequest, "Failed to parse multipart form") return } // Create update DTO towerUpdateDTO := req.UpdateTowerDTO{} // Optional fields - handle form data if deviceIDStr := c.PostForm("dev_id"); deviceIDStr != "" { if deviceID, err := uuid.Parse(deviceIDStr); err == nil { towerUpdateDTO.DeviceID = &deviceID } else { common.ErrorResponses(c, http.StatusBadRequest, "Invalid device ID format") return } } if towerCode := c.PostForm("tower_code"); towerCode != "" { towerUpdateDTO.TowerCode = &towerCode } if longitudeStr := c.PostForm("longitude"); longitudeStr != "" { if longitude, err := strconv.ParseFloat(longitudeStr, 64); err == nil { towerUpdateDTO.Longitude = &longitude } else { common.ErrorResponses(c, http.StatusBadRequest, "Invalid longitude format") return } } if latitudeStr := c.PostForm("latitude"); latitudeStr != "" { if latitude, err := strconv.ParseFloat(latitudeStr, 64); err == nil { towerUpdateDTO.Latitude = &latitude } else { common.ErrorResponses(c, http.StatusBadRequest, "Invalid latitude format") return } } // Handle external_tower field if externalTowerStr := c.PostForm("external_tower"); externalTowerStr != "" { if externalTower, err := strconv.ParseBool(externalTowerStr); err == nil { towerUpdateDTO.ExternalTower = &externalTower } else { common.ErrorResponses(c, http.StatusBadRequest, "Invalid external_tower value") return } } // Handle image_url field (for updating image URL directly) if imageURL := c.PostForm("image_url"); imageURL != "" { towerUpdateDTO.ImageURL = &imageURL } if backboneCode := c.PostForm("backbone_code"); backboneCode != "" { towerUpdateDTO.BackboneCode = &backboneCode } // Get multiple image files form := c.Request.MultipartForm imageFiles := form.File["images"] // Support multiple images // Also support single image upload for backward compatibility if len(imageFiles) == 0 { if singleImage, err := c.FormFile("image"); err == nil { imageFiles = []*multipart.FileHeader{singleImage} } } // Handle replace_images flag - if true, replace all images; if false, append to existing replaceImages := c.PostForm("replace_images") == "true" err = tc.tu.UpdateTowerWithMultipleImages(tower_uuid, towerUpdateDTO, imageFiles, replaceImages) if err != nil { common.ErrorResponses(c, http.StatusBadRequest, err.Error()) return } common.SingleResponses(c, "Tower has been updated", nil) } }