feat: add feature upload file coverimage in article
This commit is contained in:
parent
76bd158b55
commit
fc1298e894
|
@ -28,3 +28,4 @@ go.work.sum
|
||||||
|
|
||||||
# Ignore avatar images
|
# Ignore avatar images
|
||||||
/public/uploads/avatars/
|
/public/uploads/avatars/
|
||||||
|
/public/uploads/articles/
|
|
@ -29,9 +29,7 @@ func (r *RequestArticleDTO) Validate() (map[string][]string, bool) {
|
||||||
if strings.TrimSpace(r.Title) == "" {
|
if strings.TrimSpace(r.Title) == "" {
|
||||||
errors["title"] = append(errors["title"], "Title is required")
|
errors["title"] = append(errors["title"], "Title is required")
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(r.CoverImage) == "" {
|
|
||||||
errors["coverImage"] = append(errors["coverImage"], "Cover image is required")
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(r.Author) == "" {
|
if strings.TrimSpace(r.Author) == "" {
|
||||||
errors["author"] = append(errors["author"], "Author is required")
|
errors["author"] = append(errors["author"], "Author is required")
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,22 +18,28 @@ func NewArticleHandler(articleService services.ArticleService) *ArticleHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ArticleHandler) CreateArticle(c *fiber.Ctx) error {
|
func (h *ArticleHandler) CreateArticle(c *fiber.Ctx) error {
|
||||||
var requestArticleDTO dto.RequestArticleDTO
|
|
||||||
if err := c.BodyParser(&requestArticleDTO); err != nil {
|
var request dto.RequestArticleDTO
|
||||||
|
if err := c.BodyParser(&request); err != nil {
|
||||||
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}})
|
return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}})
|
||||||
}
|
}
|
||||||
|
|
||||||
errors, valid := requestArticleDTO.Validate()
|
errors, valid := request.Validate()
|
||||||
if !valid {
|
if !valid {
|
||||||
return utils.ValidationErrorResponse(c, errors)
|
return utils.ValidationErrorResponse(c, errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
articleResponse, err := h.ArticleService.CreateArticle(requestArticleDTO)
|
coverImage, err := c.FormFile("coverImage")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, err.Error())
|
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, "Cover image is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.CreateResponse(c, articleResponse, "Article created successfully")
|
articleResponse, err := h.ArticleService.CreateArticle(request, coverImage)
|
||||||
|
if err != nil {
|
||||||
|
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessResponse(c, articleResponse, "Article created successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ArticleHandler) GetAllArticles(c *fiber.Ctx) error {
|
func (h *ArticleHandler) GetAllArticles(c *fiber.Ctx) error {
|
||||||
|
|
|
@ -2,8 +2,12 @@ package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mime/multipart"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/pahmiudahgede/senggoldong/dto"
|
"github.com/pahmiudahgede/senggoldong/dto"
|
||||||
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||||
"github.com/pahmiudahgede/senggoldong/model"
|
"github.com/pahmiudahgede/senggoldong/model"
|
||||||
|
@ -11,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ArticleService interface {
|
type ArticleService interface {
|
||||||
CreateArticle(articleDTO dto.RequestArticleDTO) (*dto.ArticleResponseDTO, error)
|
CreateArticle(request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error)
|
||||||
GetAllArticles(page, limit int) ([]dto.ArticleResponseDTO, int, error)
|
GetAllArticles(page, limit int) ([]dto.ArticleResponseDTO, int, error)
|
||||||
GetArticleByID(id string) (*dto.ArticleResponseDTO, error)
|
GetArticleByID(id string) (*dto.ArticleResponseDTO, error)
|
||||||
}
|
}
|
||||||
|
@ -24,22 +28,55 @@ func NewArticleService(articleRepo repositories.ArticleRepository) ArticleServic
|
||||||
return &articleService{ArticleRepo: articleRepo}
|
return &articleService{ArticleRepo: articleRepo}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *articleService) CreateArticle(articleDTO dto.RequestArticleDTO) (*dto.ArticleResponseDTO, error) {
|
func (s *articleService) CreateArticle(request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error) {
|
||||||
|
|
||||||
article := &model.Article{
|
coverImageDir := "./public/uploads/articles"
|
||||||
Title: articleDTO.Title,
|
if _, err := os.Stat(coverImageDir); os.IsNotExist(err) {
|
||||||
CoverImage: articleDTO.CoverImage,
|
err := os.MkdirAll(coverImageDir, os.ModePerm)
|
||||||
Author: articleDTO.Author,
|
if err != nil {
|
||||||
Heading: articleDTO.Heading,
|
return nil, fmt.Errorf("failed to create directory for cover image: %v", err)
|
||||||
Content: articleDTO.Content,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.ArticleRepo.CreateArticle(article)
|
extension := filepath.Ext(coverImage.Filename)
|
||||||
|
if extension != ".jpg" && extension != ".jpeg" && extension != ".png" {
|
||||||
|
return nil, fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
coverImageFileName := fmt.Sprintf("%s_cover%s", uuid.New().String(), extension)
|
||||||
|
coverImagePath := filepath.Join(coverImageDir, coverImageFileName)
|
||||||
|
|
||||||
|
src, err := coverImage.Open()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to open uploaded file: %v", err)
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
|
||||||
|
dst, err := os.Create(coverImagePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create cover image file: %v", err)
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
_, err = dst.ReadFrom(src)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to save cover image: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
article := model.Article{
|
||||||
|
Title: request.Title,
|
||||||
|
CoverImage: coverImagePath,
|
||||||
|
Author: request.Author,
|
||||||
|
Heading: request.Heading,
|
||||||
|
Content: request.Content,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.ArticleRepo.CreateArticle(&article)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create article: %v", err)
|
return nil, fmt.Errorf("failed to create article: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
publishedAt, _ := utils.FormatDateToIndonesianFormat(article.PublishedAt)
|
createdAt, _ := utils.FormatDateToIndonesianFormat(article.PublishedAt)
|
||||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(article.UpdatedAt)
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(article.UpdatedAt)
|
||||||
|
|
||||||
articleResponseDTO := &dto.ArticleResponseDTO{
|
articleResponseDTO := &dto.ArticleResponseDTO{
|
||||||
|
@ -49,7 +86,7 @@ func (s *articleService) CreateArticle(articleDTO dto.RequestArticleDTO) (*dto.A
|
||||||
Author: article.Author,
|
Author: article.Author,
|
||||||
Heading: article.Heading,
|
Heading: article.Heading,
|
||||||
Content: article.Content,
|
Content: article.Content,
|
||||||
PublishedAt: publishedAt,
|
PublishedAt: createdAt,
|
||||||
UpdatedAt: updatedAt,
|
UpdatedAt: updatedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue