Files
MyClub/internal/controllers/contact_info_controller.go
T
Tomáš Dvořák 12cba639b9 upload
2025-10-16 13:32:05 +02:00

360 lines
10 KiB
Go

package controllers
import (
"net/http"
"strings"
"fotbal-club/internal/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ContactInfoController handles contact information and categories
type ContactInfoController struct {
DB *gorm.DB
}
// NewContactInfoController creates a new ContactInfoController
func NewContactInfoController(db *gorm.DB) *ContactInfoController {
return &ContactInfoController{DB: db}
}
// ==================== PUBLIC ENDPOINTS ====================
// GetPublicContacts returns all active contacts grouped by category (public)
func (ctrl *ContactInfoController) GetPublicContacts(c *gin.Context) {
var contacts []models.Contact
if err := ctrl.DB.Preload("Category").
Where("is_active = ?", true).
Order("display_order ASC, created_at ASC").
Find(&contacts).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load contacts"})
return
}
// Group by category
grouped := make(map[string][]models.Contact)
uncategorized := []models.Contact{}
for _, contact := range contacts {
if contact.Category != nil && contact.Category.IsActive {
grouped[contact.Category.Name] = append(grouped[contact.Category.Name], contact)
} else {
uncategorized = append(uncategorized, contact)
}
}
c.JSON(http.StatusOK, gin.H{
"categories": grouped,
"uncategorized": uncategorized,
})
}
// GetPublicContactCategories returns all active contact categories (public)
func (ctrl *ContactInfoController) GetPublicContactCategories(c *gin.Context) {
var categories []models.ContactCategory
if err := ctrl.DB.Where("is_active = ?", true).
Order("display_order ASC, name ASC").
Find(&categories).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load categories"})
return
}
c.JSON(http.StatusOK, categories)
}
// ==================== ADMIN: CONTACT CATEGORIES ====================
// GetContactCategories lists all contact categories (admin)
func (ctrl *ContactInfoController) GetContactCategories(c *gin.Context) {
var categories []models.ContactCategory
if err := ctrl.DB.Order("display_order ASC, name ASC").Find(&categories).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load categories"})
return
}
c.JSON(http.StatusOK, categories)
}
// CreateContactCategory creates a new contact category (admin)
func (ctrl *ContactInfoController) CreateContactCategory(c *gin.Context) {
var body struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
DisplayOrder *int `json:"display_order"`
IsActive *bool `json:"is_active"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
category := models.ContactCategory{
Name: strings.TrimSpace(body.Name),
Description: strings.TrimSpace(body.Description),
}
if body.DisplayOrder != nil {
category.DisplayOrder = *body.DisplayOrder
}
if body.IsActive != nil {
category.IsActive = *body.IsActive
} else {
category.IsActive = true
}
if err := ctrl.DB.Create(&category).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create category"})
return
}
c.JSON(http.StatusCreated, category)
}
// UpdateContactCategory updates a contact category (admin)
func (ctrl *ContactInfoController) UpdateContactCategory(c *gin.Context) {
id := c.Param("id")
var category models.ContactCategory
if err := ctrl.DB.First(&category, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "Category not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
var body struct {
Name *string `json:"name"`
Description *string `json:"description"`
DisplayOrder *int `json:"display_order"`
IsActive *bool `json:"is_active"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if body.Name != nil {
category.Name = strings.TrimSpace(*body.Name)
}
if body.Description != nil {
category.Description = strings.TrimSpace(*body.Description)
}
if body.DisplayOrder != nil {
category.DisplayOrder = *body.DisplayOrder
}
if body.IsActive != nil {
category.IsActive = *body.IsActive
}
if err := ctrl.DB.Save(&category).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update category"})
return
}
c.JSON(http.StatusOK, category)
}
// DeleteContactCategory deletes a contact category (admin)
func (ctrl *ContactInfoController) DeleteContactCategory(c *gin.Context) {
id := c.Param("id")
// Check if any contacts use this category
var count int64
if err := ctrl.DB.Model(&models.Contact{}).Where("category_id = ?", id).Count(&count).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
if count > 0 {
c.JSON(http.StatusConflict, gin.H{"error": "Cannot delete category with contacts. Remove contacts first."})
return
}
if err := ctrl.DB.Delete(&models.ContactCategory{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete category"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Category deleted"})
}
// ==================== ADMIN: CONTACTS ====================
// GetContacts lists all contacts (admin)
func (ctrl *ContactInfoController) GetContacts(c *gin.Context) {
var contacts []models.Contact
if err := ctrl.DB.Preload("Category").
Order("display_order ASC, created_at ASC").
Find(&contacts).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load contacts"})
return
}
c.JSON(http.StatusOK, contacts)
}
// CreateContact creates a new contact (admin)
func (ctrl *ContactInfoController) CreateContact(c *gin.Context) {
var body struct {
CategoryID *uint `json:"category_id"`
Name string `json:"name" binding:"required"`
Position string `json:"position"`
Email string `json:"email"`
Phone string `json:"phone"`
ImageURL string `json:"image_url"`
Description string `json:"description"`
DisplayOrder *int `json:"display_order"`
IsActive *bool `json:"is_active"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
contact := models.Contact{
CategoryID: body.CategoryID,
Name: strings.TrimSpace(body.Name),
Position: strings.TrimSpace(body.Position),
Email: strings.TrimSpace(body.Email),
Phone: strings.TrimSpace(body.Phone),
ImageURL: strings.TrimSpace(body.ImageURL),
Description: strings.TrimSpace(body.Description),
}
if body.DisplayOrder != nil {
contact.DisplayOrder = *body.DisplayOrder
}
if body.IsActive != nil {
contact.IsActive = *body.IsActive
} else {
contact.IsActive = true
}
// Validate category if provided
if contact.CategoryID != nil {
var cat models.ContactCategory
if err := ctrl.DB.First(&cat, *contact.CategoryID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid category_id"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
}
if err := ctrl.DB.Create(&contact).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create contact"})
return
}
// Reload with category
ctrl.DB.Preload("Category").First(&contact, contact.ID)
c.JSON(http.StatusCreated, contact)
}
// UpdateContact updates a contact (admin)
func (ctrl *ContactInfoController) UpdateContact(c *gin.Context) {
id := c.Param("id")
var contact models.Contact
if err := ctrl.DB.First(&contact, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "Contact not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
var body struct {
CategoryID *uint `json:"category_id"`
Name *string `json:"name"`
Position *string `json:"position"`
Email *string `json:"email"`
Phone *string `json:"phone"`
ImageURL *string `json:"image_url"`
Description *string `json:"description"`
DisplayOrder *int `json:"display_order"`
IsActive *bool `json:"is_active"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Allow setting category to null by sending explicit null
if c.Request.Header.Get("Content-Type") == "application/json" {
var raw map[string]interface{}
if err := c.ShouldBindJSON(&raw); err == nil {
if _, exists := raw["category_id"]; exists {
contact.CategoryID = body.CategoryID
}
}
} else if body.CategoryID != nil {
// Validate new category
var cat models.ContactCategory
if err := ctrl.DB.First(&cat, *body.CategoryID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid category_id"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
contact.CategoryID = body.CategoryID
}
if body.Name != nil {
contact.Name = strings.TrimSpace(*body.Name)
}
if body.Position != nil {
contact.Position = strings.TrimSpace(*body.Position)
}
if body.Email != nil {
contact.Email = strings.TrimSpace(*body.Email)
}
if body.Phone != nil {
contact.Phone = strings.TrimSpace(*body.Phone)
}
if body.ImageURL != nil {
contact.ImageURL = strings.TrimSpace(*body.ImageURL)
}
if body.Description != nil {
contact.Description = strings.TrimSpace(*body.Description)
}
if body.DisplayOrder != nil {
contact.DisplayOrder = *body.DisplayOrder
}
if body.IsActive != nil {
contact.IsActive = *body.IsActive
}
if err := ctrl.DB.Save(&contact).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update contact"})
return
}
// Reload with category
ctrl.DB.Preload("Category").First(&contact, contact.ID)
c.JSON(http.StatusOK, contact)
}
// DeleteContact deletes a contact (admin)
func (ctrl *ContactInfoController) DeleteContact(c *gin.Context) {
id := c.Param("id")
if err := ctrl.DB.Delete(&models.Contact{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete contact"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Contact deleted"})
}