package handlers import ( "net/http" "os" "strings" "gauth-central/config" "gauth-central/internal/services" "gauth-central/pkg/utils" "github.com/gin-gonic/gin" ) type SiteInfoHandler struct { siteInfoService *services.SiteInfoService } func NewSiteInfoHandler(siteInfoService *services.SiteInfoService) *SiteInfoHandler { return &SiteInfoHandler{siteInfoService: siteInfoService} } // GetAllSiteInfos godoc // @Summary Get all active site info // @Description Retrieve a list of active site info entries // @Tags site-info // @Produce json // @Success 200 {array} models.Setting // @Failure 500 {object} map[string]string // @Router /site-info [get] func (h *SiteInfoHandler) GetAllSiteInfos(c *gin.Context) { items, err := h.siteInfoService.GetAllSiteInfos(true) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, items) } // GetActiveSiteInfo godoc // @Summary Get active site info // @Description Retrieve the newest active site info entry // @Tags site-info // @Produce json // @Success 200 {object} models.Setting // @Failure 404 {object} map[string]string // @Router /site-info/active [get] func (h *SiteInfoHandler) GetActiveSiteInfo(c *gin.Context) { item, err := h.siteInfoService.GetFirstActiveSiteInfo() if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, item) } // AdminGetAllSiteInfos godoc // @Summary Get all site info (Admin) // @Description Retrieve a list of all site info entries including inactive ones // @Tags admin // @Security ApiKeyAuth // @Produce json // @Success 200 {array} models.Setting // @Failure 500 {object} map[string]string // @Router /admin/site-info [get] func (h *SiteInfoHandler) AdminGetAllSiteInfos(c *gin.Context) { items, err := h.siteInfoService.GetAllSiteInfos(false) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, items) } // AdminGetSiteInfoByID godoc // @Summary Get site info by ID (Admin) // @Description Retrieve details of a specific site info entry // @Tags admin // @Security ApiKeyAuth // @Produce json // @Param id path string true "Site Info ID" // @Success 200 {object} models.Setting // @Failure 404 {object} map[string]string // @Router /admin/site-info/{id} [get] func (h *SiteInfoHandler) AdminGetSiteInfoByID(c *gin.Context) { id := c.Param("id") item, err := h.siteInfoService.GetSiteInfoByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, item) } // CreateSiteInfo godoc // @Summary Create site info (Admin) // @Description Create a new site info entry // @Tags admin // @Security ApiKeyAuth // @Accept multipart/form-data // @Produce json // @Param title formData string true "Title" // @Param meta_title formData string false "Meta title" // @Param meta_description formData string false "Meta description" // @Param phone formData string true "Phone" // @Param url formData string false "Site URL" // @Param email formData string true "Email" // @Param facebook formData string false "Facebook" // @Param x formData string false "X" // @Param instagram formData string false "Instagram" // @Param whatsapp formData string false "Whatsapp" // @Param pinterest formData string false "Pinterest" // @Param linkedin formData string false "LinkedIn" // @Param slogan formData string false "Slogan" // @Param w_logo formData file false "White logo" // @Param b_logo formData file false "Black logo" // @Param is_active formData bool false "Is active" // @Success 201 {object} models.Setting // @Failure 400 {object} map[string]string // @Router /admin/site-info [post] func (h *SiteInfoHandler) CreateSiteInfo(c *gin.Context) { title := strings.TrimSpace(c.PostForm("title")) phone := strings.TrimSpace(c.PostForm("phone")) email := strings.TrimSpace(c.PostForm("email")) if title == "" || phone == "" || email == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "title, phone, and email are required"}) return } metaTitle := strings.TrimSpace(c.PostForm("meta_title")) metaDescription := strings.TrimSpace(c.PostForm("meta_description")) url := strings.TrimSpace(c.PostForm("url")) facebook := strings.TrimSpace(c.PostForm("facebook")) xValue := strings.TrimSpace(c.PostForm("x")) instagram := strings.TrimSpace(c.PostForm("instagram")) whatsapp := strings.TrimSpace(c.PostForm("whatsapp")) pinterest := strings.TrimSpace(c.PostForm("pinterest")) linkedin := strings.TrimSpace(c.PostForm("linkedin")) slogan := strings.TrimSpace(c.PostForm("slogan")) address := strings.TrimSpace(c.PostForm("address")) copyright := strings.TrimSpace(c.PostForm("copyright")) mapEmbed := strings.TrimSpace(c.PostForm("map_embed")) isActive := false isActivePtr, err := parseOptionalBool(c, "is_active") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"}) return } if isActivePtr != nil { isActive = *isActivePtr } wLogo := "" wLogoFile, wLogoErr := c.FormFile("w_logo") if wLogoErr == nil { if wLogoFile.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"error": "w_logo size exceeds 5MB limit"}) return } wLogo, err = utils.SaveOptimizedImage(wLogoFile, "./uploads/logo", "wlogo", &utils.ImageOptions{ Width: config.AppConfig.SettingsLogoWidth, Height: config.AppConfig.SettingsLogoHeight, Quality: float32(config.AppConfig.SettingsLogoQuality), Format: config.AppConfig.SettingsLogoFormat, Mode: config.AppConfig.SettingsLogoMode, }) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save w_logo: " + err.Error()}) return } } bLogo := "" bLogoFile, bLogoErr := c.FormFile("b_logo") if bLogoErr == nil { if bLogoFile.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"error": "b_logo size exceeds 5MB limit"}) return } bLogo, err = utils.SaveOptimizedImage(bLogoFile, "./uploads/logo", "blogo", &utils.ImageOptions{ Width: config.AppConfig.SettingsLogoWidth, Height: config.AppConfig.SettingsLogoHeight, Quality: float32(config.AppConfig.SettingsLogoQuality), Format: config.AppConfig.SettingsLogoFormat, Mode: config.AppConfig.SettingsLogoMode, }) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save b_logo: " + err.Error()}) return } } item, err := h.siteInfoService.CreateSiteInfo( title, metaTitle, metaDescription, phone, url, email, facebook, xValue, instagram, whatsapp, pinterest, linkedin, slogan, wLogo, bLogo, isActive, address, copyright, mapEmbed, ) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, item) } // UpdateSiteInfo godoc // @Summary Update site info (Admin) // @Description Update an existing site info entry // @Tags admin // @Security ApiKeyAuth // @Accept multipart/form-data // @Produce json // @Param id path string true "Site Info ID" // @Param title formData string false "Title" // @Param meta_title formData string false "Meta title" // @Param meta_description formData string false "Meta description" // @Param phone formData string false "Phone" // @Param url formData string false "Site URL" // @Param email formData string false "Email" // @Param facebook formData string false "Facebook" // @Param x formData string false "X" // @Param instagram formData string false "Instagram" // @Param whatsapp formData string false "Whatsapp" // @Param pinterest formData string false "Pinterest" // @Param linkedin formData string false "LinkedIn" // @Param slogan formData string false "Slogan" // @Param w_logo formData file false "White logo" // @Param b_logo formData file false "Black logo" // @Param is_active formData bool false "Is active" // @Success 200 {object} models.Setting // @Failure 400 {object} map[string]string // @Failure 404 {object} map[string]string // @Router /admin/site-info/{id} [put] func (h *SiteInfoHandler) UpdateSiteInfo(c *gin.Context) { id := c.Param("id") title, hasTitle := getOptionalFormValue(c, "title") metaTitle, hasMetaTitle := getOptionalFormValue(c, "meta_title") metaDescription, hasMetaDescription := getOptionalFormValue(c, "meta_description") phone, hasPhone := getOptionalFormValue(c, "phone") url, hasURL := getOptionalFormValue(c, "url") email, hasEmail := getOptionalFormValue(c, "email") facebook, hasFacebook := getOptionalFormValue(c, "facebook") xValue, hasX := getOptionalFormValue(c, "x") instagram, hasInstagram := getOptionalFormValue(c, "instagram") whatsapp, hasWhatsapp := getOptionalFormValue(c, "whatsapp") pinterest, hasPinterest := getOptionalFormValue(c, "pinterest") linkedin, hasLinkedin := getOptionalFormValue(c, "linkedin") slogan, hasSlogan := getOptionalFormValue(c, "slogan") address, hasAddress := getOptionalFormValue(c, "address") copyright, hasCopyright := getOptionalFormValue(c, "copyright") mapEmbed, hasMapEmbed := getOptionalFormValue(c, "map_embed") var titlePtr *string var metaTitlePtr *string var metaDescriptionPtr *string var phonePtr *string var urlPtr *string var emailPtr *string var facebookPtr *string var xPtr *string var instagramPtr *string var whatsappPtr *string var pinterestPtr *string var linkedinPtr *string var sloganPtr *string var addressPtr *string var copyrightPtr *string var mapEmbedPtr *string if hasTitle { titlePtr = &title } if hasMetaTitle { metaTitlePtr = &metaTitle } if hasMetaDescription { metaDescriptionPtr = &metaDescription } if hasPhone { phonePtr = &phone } if hasURL { urlPtr = &url } if hasEmail { emailPtr = &email } if hasFacebook { facebookPtr = &facebook } if hasX { xPtr = &xValue } if hasInstagram { instagramPtr = &instagram } if hasWhatsapp { whatsappPtr = &whatsapp } if hasPinterest { pinterestPtr = &pinterest } if hasLinkedin { linkedinPtr = &linkedin } if hasSlogan { sloganPtr = &slogan } if hasAddress { addressPtr = &address } if hasCopyright { copyrightPtr = ©right } if hasMapEmbed { mapEmbedPtr = &mapEmbed } isActivePtr, err := parseOptionalBool(c, "is_active") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"}) return } var wLogoPtr *string wLogoFile, wLogoErr := c.FormFile("w_logo") if wLogoErr == nil { if wLogoFile.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"error": "w_logo size exceeds 5MB limit"}) return } item, fetchErr := h.siteInfoService.GetSiteInfoByID(id) if fetchErr != nil { c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()}) return } if item.WLogo != "" && strings.HasPrefix(item.WLogo, "/uploads/") { _ = os.Remove("." + item.WLogo) } wLogo, saveErr := utils.SaveOptimizedImage(wLogoFile, "./uploads/logo", id+"_w", &utils.ImageOptions{ Width: config.AppConfig.SettingsLogoWidth, Height: config.AppConfig.SettingsLogoHeight, Quality: float32(config.AppConfig.SettingsLogoQuality), Format: config.AppConfig.SettingsLogoFormat, Mode: config.AppConfig.SettingsLogoMode, }) if saveErr != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save w_logo: " + saveErr.Error()}) return } wLogoPtr = &wLogo } var bLogoPtr *string bLogoFile, bLogoErr := c.FormFile("b_logo") if bLogoErr == nil { if bLogoFile.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"error": "b_logo size exceeds 5MB limit"}) return } item, fetchErr := h.siteInfoService.GetSiteInfoByID(id) if fetchErr != nil { c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()}) return } if item.BLogo != "" && strings.HasPrefix(item.BLogo, "/uploads/") { _ = os.Remove("." + item.BLogo) } bLogo, saveErr := utils.SaveOptimizedImage(bLogoFile, "./uploads/logo", id+"_b", &utils.ImageOptions{ Width: config.AppConfig.SettingsLogoWidth, Height: config.AppConfig.SettingsLogoHeight, Quality: float32(config.AppConfig.SettingsLogoQuality), Format: config.AppConfig.SettingsLogoFormat, Mode: config.AppConfig.SettingsLogoMode, }) if saveErr != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save b_logo: " + saveErr.Error()}) return } bLogoPtr = &bLogo } item, err := h.siteInfoService.UpdateSiteInfo( id, titlePtr, metaTitlePtr, metaDescriptionPtr, phonePtr, urlPtr, emailPtr, facebookPtr, xPtr, instagramPtr, whatsappPtr, pinterestPtr, linkedinPtr, sloganPtr, wLogoPtr, bLogoPtr, isActivePtr, addressPtr, copyrightPtr, mapEmbedPtr, ) if err != nil { status := http.StatusInternalServerError if err.Error() == "site info not found" { status = http.StatusNotFound } c.JSON(status, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, item) } // DeleteSiteInfo godoc // @Summary Delete site info (Admin) // @Description Delete a site info entry by ID // @Tags admin // @Security ApiKeyAuth // @Param id path string true "Site Info ID" // @Success 200 {object} map[string]string // @Failure 404 {object} map[string]string // @Router /admin/site-info/{id} [delete] func (h *SiteInfoHandler) DeleteSiteInfo(c *gin.Context) { id := c.Param("id") if err := h.siteInfoService.DeleteSiteInfo(id); err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "Site info deleted successfully"}) }