Files
atahango/internal/services/post_service.go
Beyhan Oğur bbbf76b184 first commit
2026-04-26 21:35:24 +03:00

298 lines
6.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package services
import (
"errors"
"fmt"
"regexp"
"strings"
"gauth-central/internal/database"
"gauth-central/internal/models"
"github.com/google/uuid"
"gorm.io/gorm"
)
type PostService struct{}
func NewPostService() *PostService {
return &PostService{}
}
func (s *PostService) CreatePost(
title string,
content string,
keywords string,
image string,
video string,
categoryIDs []string,
tagIDs []string,
parentID *uuid.UUID,
isActive bool,
isFront bool,
) (*models.Post, error) {
slug := s.generateUniqueSlug(slugifyPost(title), "")
if slug == "" {
return nil, errors.New("slug cannot be empty")
}
post := models.Post{
Title: title,
Content: content,
Keywords: keywords,
Image: image,
Video: video,
Slug: slug,
ParentID: parentID,
IsActive: isActive,
IsFront: isFront,
}
if len(categoryIDs) > 0 {
categories, err := s.fetchCategoriesByIDs(categoryIDs)
if err != nil {
return nil, err
}
post.Categories = categories
}
if len(tagIDs) > 0 {
tags, err := s.fetchTagsByIDs(tagIDs)
if err != nil {
return nil, err
}
post.Tags = tags
}
if err := database.DB.Create(&post).Error; err != nil {
return nil, err
}
return s.GetPostByID(post.ID.String())
}
func (s *PostService) GetAllPosts(onlyActive bool, onlyFront bool, page int, limit int) ([]models.Post, int64, error) {
var posts []models.Post
var total int64
query := database.DB.Model(&models.Post{})
if onlyActive {
query = query.Where("is_active = ?", true)
}
if onlyFront {
query = query.Where("is_front = ?", true)
}
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * limit
if err := query.Preload("Categories").Preload("Tags").
Order("created_at desc").
Limit(limit).
Offset(offset).
Find(&posts).Error; err != nil {
return nil, 0, err
}
return posts, total, nil
}
func (s *PostService) GetPostByID(id string) (*models.Post, error) {
var post models.Post
if err := database.DB.Preload("Categories").Preload("Tags").Where("id = ?", id).First(&post).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("post not found")
}
return nil, err
}
return &post, nil
}
func (s *PostService) GetPostBySlug(slug string, onlyActive bool) (*models.Post, error) {
var post models.Post
query := database.DB.Preload("Categories").Preload("Tags").Where("slug = ?", slug)
if onlyActive {
query = query.Where("is_active = ?", true)
}
if err := query.First(&post).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("post not found")
}
return nil, err
}
return &post, nil
}
func (s *PostService) UpdatePost(
id string,
title *string,
content *string,
keywords *string,
image *string,
video *string,
categoryIDs *[]string,
tagIDs *[]string,
parentID *uuid.UUID,
parentIDSet bool,
slug *string,
isActive *bool,
isFront *bool,
) (*models.Post, error) {
post, err := s.GetPostByID(id)
if err != nil {
return nil, err
}
updates := map[string]interface{}{}
if title != nil {
updates["title"] = *title
}
if content != nil {
updates["content"] = *content
}
if keywords != nil {
updates["keywords"] = *keywords
}
if image != nil {
updates["image"] = *image
}
if video != nil {
updates["video"] = *video
}
if parentIDSet {
updates["parent_id"] = parentID
}
if slug != nil {
clean := slugifyPost(*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 isFront != nil {
updates["is_front"] = *isFront
}
if len(updates) > 0 {
if err := database.DB.Model(post).Updates(updates).Error; err != nil {
return nil, err
}
}
if categoryIDs != nil {
categories, err := s.fetchCategoriesByIDs(*categoryIDs)
if err != nil {
return nil, err
}
if err := database.DB.Model(post).Association("Categories").Replace(categories); err != nil {
return nil, err
}
}
if tagIDs != nil {
tags, err := s.fetchTagsByIDs(*tagIDs)
if err != nil {
return nil, err
}
if err := database.DB.Model(post).Association("Tags").Replace(tags); err != nil {
return nil, err
}
}
return s.GetPostByID(id)
}
func (s *PostService) DeletePost(id string) error {
result := database.DB.Delete(&models.Post{}, "id = ?", id)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New("post not found")
}
return nil
}
func (s *PostService) fetchCategoriesByIDs(categoryIDs []string) ([]models.PostCategory, error) {
var categories []models.PostCategory
if err := database.DB.Where("id IN ?", categoryIDs).Find(&categories).Error; err != nil {
return nil, err
}
if len(categories) != len(categoryIDs) {
return nil, errors.New("one or more categories not found")
}
return categories, nil
}
func (s *PostService) fetchTagsByIDs(tagIDs []string) ([]models.PostTag, error) {
var tags []models.PostTag
if err := database.DB.Where("id IN ?", tagIDs).Find(&tags).Error; err != nil {
return nil, err
}
if len(tags) != len(tagIDs) {
return nil, errors.New("one or more tags not found")
}
return tags, nil
}
func (s *PostService) 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 *PostService) slugExists(slug string, excludeID string) bool {
var count int64
query := database.DB.Model(&models.Post{}).Where("slug = ?", slug)
if excludeID != "" {
query = query.Where("id <> ?", excludeID)
}
query.Count(&count)
return count > 0
}
func slugifyPost(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 "post"
}
return clean
}