package services import ( "errors" "fmt" "regexp" "strings" "gauth-central/internal/database" "gauth-central/internal/models" "github.com/google/uuid" "gorm.io/gorm" ) type PostCategoryService struct{} func NewPostCategoryService() *PostCategoryService { return &PostCategoryService{} } func (s *PostCategoryService) CreatePostCategory( title string, keywords string, description string, image string, order int, parentID *uuid.UUID, isActive bool, ) (*models.PostCategory, error) { slug := s.generateUniqueSlug(slugifyPostCategory(title), "") if slug == "" { return nil, errors.New("slug cannot be empty") } category := models.PostCategory{ Title: title, Keywords: keywords, Description: description, Image: image, Order: order, ParentID: parentID, Slug: slug, IsActive: isActive, } if err := database.DB.Create(&category).Error; err != nil { return nil, err } return s.GetPostCategoryByID(category.ID.String()) } func (s *PostCategoryService) GetAllPostCategories(onlyActive bool) ([]models.PostCategory, error) { var categories []models.PostCategory query := database.DB.Order("\"order\" asc").Preload("Children").Where("parent_id IS NULL") if onlyActive { query = query.Where("is_active = ?", true) } if err := query.Find(&categories).Error; err != nil { return nil, err } return categories, nil } func (s *PostCategoryService) GetPostCategoryByID(id string) (*models.PostCategory, error) { var category models.PostCategory if err := database.DB.Preload("Children").Where("id = ?", id).First(&category).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("post category not found") } return nil, err } return &category, nil } func (s *PostCategoryService) GetPostCategoryBySlug(slug string, onlyActive bool) (*models.PostCategory, error) { var category models.PostCategory query := database.DB.Preload("Children").Where("slug = ?", slug) if onlyActive { query = query.Where("is_active = ?", true) } if err := query.First(&category).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("post category not found") } return nil, err } return &category, nil } func (s *PostCategoryService) UpdatePostCategory( id string, title *string, keywords *string, description *string, image *string, order *int, parentID *uuid.UUID, parentIDSet bool, slug *string, isActive *bool, ) (*models.PostCategory, error) { category, err := s.GetPostCategoryByID(id) if err != nil { return nil, err } updates := map[string]interface{}{} if title != nil { updates["title"] = *title } if keywords != nil { updates["keywords"] = *keywords } if description != nil { updates["description"] = *description } if image != nil { updates["image"] = *image } if order != nil { updates["order"] = *order } if parentIDSet { updates["parent_id"] = parentID } if slug != nil { clean := slugifyPostCategory(*slug) if clean == "" { return nil, errors.New("slug cannot be empty") } if s.slugExists(clean, id) { return nil, errors.New("slug already exists") } updates["slug"] = clean } if isActive != nil { updates["is_active"] = *isActive } if len(updates) > 0 { if err := database.DB.Model(category).Updates(updates).Error; err != nil { return nil, err } } return s.GetPostCategoryByID(id) } func (s *PostCategoryService) DeletePostCategory(id string) error { result := database.DB.Delete(&models.PostCategory{}, "id = ?", id) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return errors.New("post category not found") } return nil } func (s *PostCategoryService) generateUniqueSlug(baseSlug string, excludeID string) string { slug := baseSlug counter := 1 for s.slugExists(slug, excludeID) { slug = fmt.Sprintf("%s-%d", baseSlug, counter) counter++ } return slug } func (s *PostCategoryService) slugExists(slug string, excludeID string) bool { var count int64 query := database.DB.Model(&models.PostCategory{}).Where("slug = ?", slug) if excludeID != "" { query = query.Where("id <> ?", excludeID) } query.Count(&count) return count > 0 } func slugifyPostCategory(input string) string { clean := strings.TrimSpace(input) if clean == "" { return "" } replacer := strings.NewReplacer( "ı", "i", "İ", "i", "ş", "s", "Ş", "s", "ğ", "g", "Ğ", "g", "ç", "c", "Ç", "c", "ö", "o", "Ö", "o", "ü", "u", "Ü", "u", ) clean = strings.ToLower(replacer.Replace(clean)) re := regexp.MustCompile(`[^a-z0-9]+`) clean = re.ReplaceAllString(clean, "-") clean = strings.Trim(clean, "-") if clean == "" { return "category" } return clean }