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) }