Files
atahango/api/handlers/about_handler.go
Beyhan Oğur bbbf76b184 first commit
2026-04-26 21:35:24 +03:00

569 lines
16 KiB
Go

package handlers
import (
"fmt"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"gauth-central/config"
"gauth-central/internal/services"
"gauth-central/pkg/utils"
"github.com/gin-gonic/gin"
)
type AboutHandler struct {
aboutService *services.AboutService
}
func NewAboutHandler(aboutService *services.AboutService) *AboutHandler {
return &AboutHandler{aboutService: aboutService}
}
// GetAllAbout godoc
// @Summary Get all active about entries
// @Description Retrieve a list of active about entries
// @Tags about
// @Produce json
// @Success 200 {array} models.About
// @Failure 500 {object} map[string]string
// @Router /about [get]
func (h *AboutHandler) GetAllAbout(c *gin.Context) {
abouts, err := h.aboutService.GetAllAbout(true)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, abouts)
}
// GetActiveAbout godoc
// @Summary Get active about entry
// @Description Retrieve the newest active about entry
// @Tags about
// @Produce json
// @Success 200 {object} models.About
// @Failure 404 {object} map[string]string
// @Router /about/active [get]
func (h *AboutHandler) GetActiveAbout(c *gin.Context) {
about, err := h.aboutService.GetFirstActiveAbout()
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, about)
}
// AdminGetAllAbout godoc
// @Summary Get all about entries (Admin)
// @Description Retrieve a list of all about entries including inactive ones
// @Tags admin
// @Security ApiKeyAuth
// @Produce json
// @Success 200 {array} models.About
// @Failure 500 {object} map[string]string
// @Router /admin/about [get]
func (h *AboutHandler) AdminGetAllAbout(c *gin.Context) {
abouts, err := h.aboutService.GetAllAbout(false)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, abouts)
}
// AdminGetAboutByID godoc
// @Summary Get an about entry by ID (Admin)
// @Description Retrieve details of a specific about entry
// @Tags admin
// @Security ApiKeyAuth
// @Produce json
// @Param id path string true "About ID"
// @Success 200 {object} models.About
// @Failure 404 {object} map[string]string
// @Router /admin/about/{id} [get]
func (h *AboutHandler) AdminGetAboutByID(c *gin.Context) {
id := c.Param("id")
about, err := h.aboutService.GetAboutByID(id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, about)
}
// CreateAbout godoc
// @Summary Create a new about entry (Admin)
// @Description Create a new about entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param title formData string true "Title"
// @Param image formData file false "Image"
// @Param image_sub formData string false "Image subtitle"
// @Param cv formData file false "CV file"
// @Param birthday formData string false "Birthday"
// @Param city formData string false "City"
// @Param study formData string false "Study"
// @Param website formData string false "Website"
// @Param phone formData string false "Phone"
// @Param age formData string false "Age"
// @Param interests formData string false "Interests"
// @Param degree formData string false "Degree"
// @Param x formData string false "X"
// @Param mail formData string false "Mail"
// @Param done formData int false "Done"
// @Param project_done formData string false "Project done"
// @Param user_h formData int false "User count"
// @Param hapy_user formData string false "Happy user"
// @Param great formData int false "Great"
// @Param great_reviews formData string false "Great reviews"
// @Param team formData int false "Team"
// @Param support_team formData string false "Support team"
// @Param is_active formData bool false "Is active"
// @Param counter_active formData bool false "Counter active"
// @Success 201 {object} models.About
// @Failure 400 {object} map[string]string
// @Router /admin/about [post]
func (h *AboutHandler) CreateAbout(c *gin.Context) {
title := strings.TrimSpace(c.PostForm("title"))
if title == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "title is required"})
return
}
imageSub := strings.TrimSpace(c.PostForm("image_sub"))
birthday := strings.TrimSpace(c.PostForm("birthday"))
city := strings.TrimSpace(c.PostForm("city"))
study := strings.TrimSpace(c.PostForm("study"))
website := strings.TrimSpace(c.PostForm("website"))
phone := strings.TrimSpace(c.PostForm("phone"))
age := strings.TrimSpace(c.PostForm("age"))
interests := strings.TrimSpace(c.PostForm("interests"))
degree := strings.TrimSpace(c.PostForm("degree"))
xValue := strings.TrimSpace(c.PostForm("x"))
mail := strings.TrimSpace(c.PostForm("mail"))
projectDone := strings.TrimSpace(c.PostForm("project_done"))
hapyUser := strings.TrimSpace(c.PostForm("hapy_user"))
greatReviews := strings.TrimSpace(c.PostForm("great_reviews"))
supportTeam := strings.TrimSpace(c.PostForm("support_team"))
done, err := parseOptionalInt(c, "done")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "done must be a number"})
return
}
userH, err := parseOptionalInt(c, "user_h")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "user_h must be a number"})
return
}
great, err := parseOptionalInt(c, "great")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "great must be a number"})
return
}
team, err := parseOptionalInt(c, "team")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "team must be a number"})
return
}
isActivePtr, err := parseOptionalBool(c, "is_active")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"})
return
}
counterActivePtr, err := parseOptionalBool(c, "counter_active")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "counter_active must be true or false"})
return
}
isActive := false
if isActivePtr != nil {
isActive = *isActivePtr
}
counterActive := false
if counterActivePtr != nil {
counterActive = *counterActivePtr
}
imageURL := ""
imageFile, imageErr := c.FormFile("image")
if imageErr == nil {
if imageFile.Size > 5*1024*1024 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Image size exceeds 5MB limit"})
return
}
imageURL, err = utils.SaveOptimizedImage(imageFile, "./uploads/about", "about", &utils.ImageOptions{
Width: config.AppConfig.AboutImageWidth,
Height: config.AppConfig.AboutImageHeight,
Quality: float32(config.AppConfig.AboutImageQuality),
Format: config.AppConfig.AboutImageFormat,
Mode: config.AppConfig.AboutImageMode,
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + err.Error()})
return
}
}
cvPath := ""
cvFile, cvErr := c.FormFile("cv")
if cvErr == nil {
cvPath, err = saveUploadedFile(c, cvFile, "./uploads/cv", "cv")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save CV: " + err.Error()})
return
}
}
about, err := h.aboutService.CreateAbout(
title,
imageURL,
imageSub,
cvPath,
birthday,
city,
study,
website,
phone,
age,
interests,
degree,
xValue,
mail,
done,
projectDone,
userH,
hapyUser,
great,
greatReviews,
team,
supportTeam,
isActive,
counterActive,
)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, about)
}
// UpdateAbout godoc
// @Summary Update an about entry (Admin)
// @Description Update an existing about entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "About ID"
// @Param title formData string false "Title"
// @Param image formData file false "Image"
// @Param image_sub formData string false "Image subtitle"
// @Param cv formData file false "CV file"
// @Param birthday formData string false "Birthday"
// @Param city formData string false "City"
// @Param study formData string false "Study"
// @Param website formData string false "Website"
// @Param phone formData string false "Phone"
// @Param age formData string false "Age"
// @Param interests formData string false "Interests"
// @Param degree formData string false "Degree"
// @Param x formData string false "X"
// @Param mail formData string false "Mail"
// @Param done formData int false "Done"
// @Param project_done formData string false "Project done"
// @Param user_h formData int false "User count"
// @Param hapy_user formData string false "Happy user"
// @Param great formData int false "Great"
// @Param great_reviews formData string false "Great reviews"
// @Param team formData int false "Team"
// @Param support_team formData string false "Support team"
// @Param slug formData string false "Slug"
// @Param is_active formData bool false "Is active"
// @Param counter_active formData bool false "Counter active"
// @Success 200 {object} models.About
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/about/{id} [put]
func (h *AboutHandler) UpdateAbout(c *gin.Context) {
id := c.Param("id")
title, hasTitle := getOptionalFormValue(c, "title")
imageSub, hasImageSub := getOptionalFormValue(c, "image_sub")
birthday, hasBirthday := getOptionalFormValue(c, "birthday")
city, hasCity := getOptionalFormValue(c, "city")
study, hasStudy := getOptionalFormValue(c, "study")
website, hasWebsite := getOptionalFormValue(c, "website")
phone, hasPhone := getOptionalFormValue(c, "phone")
age, hasAge := getOptionalFormValue(c, "age")
interests, hasInterests := getOptionalFormValue(c, "interests")
degree, hasDegree := getOptionalFormValue(c, "degree")
xValue, hasX := getOptionalFormValue(c, "x")
mail, hasMail := getOptionalFormValue(c, "mail")
projectDone, hasProjectDone := getOptionalFormValue(c, "project_done")
hapyUser, hasHapyUser := getOptionalFormValue(c, "hapy_user")
greatReviews, hasGreatReviews := getOptionalFormValue(c, "great_reviews")
supportTeam, hasSupportTeam := getOptionalFormValue(c, "support_team")
slug, hasSlug := getOptionalFormValue(c, "slug")
done, err := parseOptionalInt(c, "done")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "done must be a number"})
return
}
userH, err := parseOptionalInt(c, "user_h")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "user_h must be a number"})
return
}
great, err := parseOptionalInt(c, "great")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "great must be a number"})
return
}
team, err := parseOptionalInt(c, "team")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "team must be a number"})
return
}
isActivePtr, err := parseOptionalBool(c, "is_active")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"})
return
}
counterActivePtr, err := parseOptionalBool(c, "counter_active")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "counter_active must be true or false"})
return
}
var titlePtr *string
var imageSubPtr *string
var birthdayPtr *string
var cityPtr *string
var studyPtr *string
var websitePtr *string
var phonePtr *string
var agePtr *string
var interestsPtr *string
var degreePtr *string
var xPtr *string
var mailPtr *string
var projectDonePtr *string
var hapyUserPtr *string
var greatReviewsPtr *string
var supportTeamPtr *string
var slugPtr *string
if hasTitle {
titlePtr = &title
}
if hasImageSub {
imageSubPtr = &imageSub
}
if hasBirthday {
birthdayPtr = &birthday
}
if hasCity {
cityPtr = &city
}
if hasStudy {
studyPtr = &study
}
if hasWebsite {
websitePtr = &website
}
if hasPhone {
phonePtr = &phone
}
if hasAge {
agePtr = &age
}
if hasInterests {
interestsPtr = &interests
}
if hasDegree {
degreePtr = &degree
}
if hasX {
xPtr = &xValue
}
if hasMail {
mailPtr = &mail
}
if hasProjectDone {
projectDonePtr = &projectDone
}
if hasHapyUser {
hapyUserPtr = &hapyUser
}
if hasGreatReviews {
greatReviewsPtr = &greatReviews
}
if hasSupportTeam {
supportTeamPtr = &supportTeam
}
if hasSlug {
slugPtr = &slug
}
var imagePtr *string
imageFile, imageErr := c.FormFile("image")
if imageErr == nil {
if imageFile.Size > 5*1024*1024 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Image size exceeds 5MB limit"})
return
}
about, fetchErr := h.aboutService.GetAboutByID(id)
if fetchErr != nil {
c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()})
return
}
if about.Image != "" && strings.HasPrefix(about.Image, "/uploads/") {
oldPath := "." + about.Image
_ = os.Remove(oldPath)
}
imageURL, saveErr := utils.SaveOptimizedImage(imageFile, "./uploads/about", id, &utils.ImageOptions{
Width: config.AppConfig.AboutImageWidth,
Height: config.AppConfig.AboutImageHeight,
Quality: float32(config.AppConfig.AboutImageQuality),
Format: config.AppConfig.AboutImageFormat,
Mode: config.AppConfig.AboutImageMode,
})
if saveErr != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + saveErr.Error()})
return
}
imagePtr = &imageURL
}
var cvPtr *string
cvFile, cvErr := c.FormFile("cv")
if cvErr == nil {
about, fetchErr := h.aboutService.GetAboutByID(id)
if fetchErr != nil {
c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()})
return
}
if about.CV != "" && strings.HasPrefix(about.CV, "/uploads/") {
oldPath := "." + about.CV
_ = os.Remove(oldPath)
}
cvPath, saveErr := saveUploadedFile(c, cvFile, "./uploads/cv", "cv")
if saveErr != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save CV: " + saveErr.Error()})
return
}
cvPtr = &cvPath
}
about, err := h.aboutService.UpdateAbout(
id,
titlePtr,
imagePtr,
imageSubPtr,
cvPtr,
birthdayPtr,
cityPtr,
studyPtr,
websitePtr,
phonePtr,
agePtr,
interestsPtr,
degreePtr,
xPtr,
mailPtr,
done,
projectDonePtr,
userH,
hapyUserPtr,
great,
greatReviewsPtr,
team,
supportTeamPtr,
slugPtr,
isActivePtr,
counterActivePtr,
)
if err != nil {
status := http.StatusInternalServerError
if err.Error() == "about not found" {
status = http.StatusNotFound
}
c.JSON(status, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, about)
}
// DeleteAbout godoc
// @Summary Delete an about entry (Admin)
// @Description Delete an about entry by ID
// @Tags admin
// @Security ApiKeyAuth
// @Param id path string true "About ID"
// @Success 200 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/about/{id} [delete]
func (h *AboutHandler) DeleteAbout(c *gin.Context) {
id := c.Param("id")
if err := h.aboutService.DeleteAbout(id); err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "About deleted successfully"})
}
func parseOptionalInt(c *gin.Context, key string) (*int, error) {
value, exists := c.GetPostForm(key)
if !exists {
return nil, nil
}
value = strings.TrimSpace(value)
if value == "" {
return nil, nil
}
parsed, err := strconv.Atoi(value)
if err != nil {
return nil, err
}
return &parsed, nil
}
func saveUploadedFile(c *gin.Context, file *multipart.FileHeader, uploadDir string, prefix string) (string, error) {
if err := os.MkdirAll(uploadDir, 0755); err != nil {
return "", err
}
ext := filepath.Ext(file.Filename)
filename := fmt.Sprintf("%s_%d%s", prefix, time.Now().UnixNano(), ext)
fullPath := filepath.Join(uploadDir, filename)
if err := c.SaveUploadedFile(file, fullPath); err != nil {
return "", err
}
relPath := filepath.Join(uploadDir, filename)
if strings.HasPrefix(relPath, ".") {
relPath = relPath[1:]
}
if !strings.HasPrefix(relPath, "/") {
relPath = "/" + relPath
}
return relPath, nil
}