tailly_back_v2/internal/service/post_service.go

157 lines
3.8 KiB
Go

package service
import (
"context"
"encoding/base64"
"errors"
"fmt"
"log"
"os"
"strings"
"tailly_back_v2/internal/domain"
"tailly_back_v2/internal/repository"
"tailly_back_v2/internal/utils"
"time"
)
// Интерфейс сервиса постов
type PostService interface {
Create(ctx context.Context, authorID int, title, content string) (*domain.Post, error)
GetByID(ctx context.Context, id int) (*domain.Post, error)
GetAll(ctx context.Context) ([]*domain.Post, error)
GetByAuthorID(ctx context.Context, authorID int) ([]*domain.Post, error)
Update(ctx context.Context, id int, title, content string) (*domain.Post, error)
Delete(ctx context.Context, id int) error
}
// Реализация сервиса постов
type postService struct {
postRepo repository.PostRepository
}
// Конструктор сервиса
func NewPostService(postRepo repository.PostRepository) PostService {
return &postService{postRepo: postRepo}
}
// Создание нового поста
func (s *postService) Create(ctx context.Context, authorID int, title, content string) (*domain.Post, error) {
const op = "service/postService.Create"
// Валидация данных
if title == "" {
return nil, errors.New("post title cannot be empty")
}
if content == "" {
return nil, errors.New("post content cannot be empty")
}
if strings.HasPrefix(content, "data:image/jpeg;base64,") {
content = strings.TrimPrefix(content, "data:image/jpeg;base64,")
}
imgBase64, err := base64.StdEncoding.DecodeString(content)
if err != nil {
log.Println("failed to decode image base64", op, err)
return nil, err
}
randName := utils.GenerateId()
upPath := fmt.Sprintf("./uploads/posts/images/%d", authorID)
err = os.MkdirAll(upPath, os.ModePerm)
if err != nil {
log.Println("failed to create directory", op, err)
return nil, err
}
fileName := fmt.Sprintf("%s/%s.jpg", upPath, randName)
err = os.WriteFile(fileName, imgBase64, os.ModePerm)
if err != nil {
log.Println("failed to write file", op, err)
return nil, err
}
post := &domain.Post{
Title: title,
Content: fileName,
AuthorID: authorID,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := s.postRepo.Create(ctx, post); err != nil {
return nil, err
}
return post, nil
}
// Получение поста по ID
func (s *postService) GetByID(ctx context.Context, id int) (*domain.Post, error) {
post, err := s.postRepo.GetByID(ctx, id)
if err != nil {
if errors.Is(err, repository.ErrPostNotFound) {
return nil, errors.New("post not found")
}
return nil, err
}
return post, nil
}
// Получение всех постов
func (s *postService) GetAll(ctx context.Context) ([]*domain.Post, error) {
posts, err := s.postRepo.GetAll(ctx)
if err != nil {
return nil, err
}
// Возвращаем пустой слайс вместо nil
if posts == nil {
return []*domain.Post{}, nil
}
return posts, nil
}
// Получение постов автора
func (s *postService) GetByAuthorID(ctx context.Context, authorID int) ([]*domain.Post, error) {
posts, err := s.postRepo.GetByAuthorID(ctx, authorID)
if err != nil {
return nil, err
}
if posts == nil {
return []*domain.Post{}, nil
}
return posts, nil
}
// Обновление поста
func (s *postService) Update(ctx context.Context, id int, title, content string) (*domain.Post, error) {
// Получаем существующий пост
post, err := s.postRepo.GetByID(ctx, id)
if err != nil {
return nil, err
}
// Обновляем поля
post.Title = title
post.Content = content
post.UpdatedAt = time.Now()
if err := s.postRepo.Update(ctx, post); err != nil {
return nil, err
}
return post, nil
}
// Удаление поста
func (s *postService) Delete(ctx context.Context, id int) error {
return s.postRepo.Delete(ctx, id)
}