feat: add feature article
This commit is contained in:
parent
c326fcc6fc
commit
a05edce16a
|
@ -57,6 +57,7 @@ func InitDatabase() {
|
||||||
&domain.MenuAccess{},
|
&domain.MenuAccess{},
|
||||||
&domain.PlatformHandle{},
|
&domain.PlatformHandle{},
|
||||||
&domain.Address{},
|
&domain.Address{},
|
||||||
|
&domain.Article{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error: Failed to auto migrate domain:", err)
|
log.Fatal("Error: Failed to auto migrate domain:", err)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Article struct {
|
||||||
|
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
|
||||||
|
Title string `gorm:"not null" json:"title"`
|
||||||
|
CoverImage string `gorm:"not null" json:"coverImage"`
|
||||||
|
Author string `gorm:"not null" json:"author"`
|
||||||
|
Heading string `gorm:"not null" json:"heading"`
|
||||||
|
Content string `gorm:"not null" json:"content"`
|
||||||
|
PublishedAt time.Time `gorm:"not null" json:"publishedAt"`
|
||||||
|
UpdatedAt time.Time `gorm:"not null" json:"updatedAt"`
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package dto
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type ArticleRequest struct {
|
||||||
|
Title string `json:"title" validate:"required"`
|
||||||
|
CoverImage string `json:"coverImage" validate:"required"`
|
||||||
|
Author string `json:"author" validate:"required"`
|
||||||
|
Heading string `json:"heading" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
PublishedAt time.Time `json:"publishedAt" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArticleResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
CoverImage string `json:"coverImage"`
|
||||||
|
Author string `json:"author"`
|
||||||
|
Heading string `json:"heading"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
PublishedAt time.Time `json:"publishedAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArticleUpdateRequest struct {
|
||||||
|
Title string `json:"title" validate:"required"`
|
||||||
|
CoverImage string `json:"coverImage" validate:"required"`
|
||||||
|
Author string `json:"author" validate:"required"`
|
||||||
|
Heading string `json:"heading" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ar *ArticleRequest) Validate() error {
|
||||||
|
return validate.Struct(ar)
|
||||||
|
}
|
|
@ -31,4 +31,11 @@ func AppRouter(app *fiber.App) {
|
||||||
app.Post("/create-address", middleware.AuthMiddleware, controllers.CreateAddress)
|
app.Post("/create-address", middleware.AuthMiddleware, controllers.CreateAddress)
|
||||||
app.Put("/address/:id", middleware.AuthMiddleware, controllers.UpdateAddress)
|
app.Put("/address/:id", middleware.AuthMiddleware, controllers.UpdateAddress)
|
||||||
app.Delete("/address/:id", middleware.AuthMiddleware, controllers.DeleteAddress)
|
app.Delete("/address/:id", middleware.AuthMiddleware, controllers.DeleteAddress)
|
||||||
|
|
||||||
|
// # article
|
||||||
|
app.Post("/articles", middleware.AuthMiddleware, controllers.CreateArticle)
|
||||||
|
app.Get("/articles", middleware.AuthMiddleware, controllers.GetArticles)
|
||||||
|
app.Get("/articles/:id", middleware.AuthMiddleware, controllers.GetArticleByID)
|
||||||
|
app.Put("/articles/:id", middleware.AuthMiddleware, controllers.UpdateArticle)
|
||||||
|
app.Delete("/articles/:id", middleware.AuthMiddleware, controllers.DeleteArticle)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/dto"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/internal/services"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateArticle(c *fiber.Ctx) error {
|
||||||
|
var articleRequest dto.ArticleRequest
|
||||||
|
if err := c.BodyParser(&articleRequest); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusBadRequest,
|
||||||
|
"Invalid input",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := validator.New()
|
||||||
|
err := validate.Struct(articleRequest)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusBadRequest,
|
||||||
|
"Validation error",
|
||||||
|
err.Error(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
createdArticle, err := services.CreateArticle(&articleRequest)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusInternalServerError,
|
||||||
|
"Failed to create article",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusCreated,
|
||||||
|
"Article created successfully",
|
||||||
|
createdArticle,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArticles(c *fiber.Ctx) error {
|
||||||
|
articles, err := services.GetArticles()
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusInternalServerError,
|
||||||
|
"Failed to fetch articles",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusOK,
|
||||||
|
"Articles fetched successfully",
|
||||||
|
articles,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArticleByID(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
|
||||||
|
article, err := services.GetArticleByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusNotFound,
|
||||||
|
"Article not found",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusOK,
|
||||||
|
"Article fetched successfully",
|
||||||
|
article,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateArticle(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
|
||||||
|
var articleUpdateRequest dto.ArticleUpdateRequest
|
||||||
|
if err := c.BodyParser(&articleUpdateRequest); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusBadRequest,
|
||||||
|
"Invalid input",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := validator.New()
|
||||||
|
err := validate.Struct(articleUpdateRequest)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusBadRequest,
|
||||||
|
"Validation error",
|
||||||
|
err.Error(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedArticle, err := services.UpdateArticle(id, &articleUpdateRequest)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusInternalServerError,
|
||||||
|
"Failed to update article",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusOK,
|
||||||
|
"Article updated successfully",
|
||||||
|
updatedArticle,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteArticle(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
|
||||||
|
err := services.DeleteArticle(id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusInternalServerError,
|
||||||
|
"Failed to delete article",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
|
||||||
|
fiber.StatusOK,
|
||||||
|
"Article deleted successfully",
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pahmiudahgede/senggoldong/config"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateArticle(article *domain.Article) error {
|
||||||
|
err := config.DB.Create(article).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArticles() ([]domain.Article, error) {
|
||||||
|
var articles []domain.Article
|
||||||
|
err := config.DB.Find(&articles).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return articles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArticleByID(id string) (domain.Article, error) {
|
||||||
|
var article domain.Article
|
||||||
|
err := config.DB.Where("id = ?", id).First(&article).Error
|
||||||
|
if err != nil {
|
||||||
|
return article, err
|
||||||
|
}
|
||||||
|
return article, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateArticle(article *domain.Article) error {
|
||||||
|
|
||||||
|
err := config.DB.Save(article).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteArticle(id string) error {
|
||||||
|
|
||||||
|
var article domain.Article
|
||||||
|
err := config.DB.Where("id = ?", id).First(&article).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = config.DB.Delete(&article).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ func GetUserRoleByID(id string) (domain.UserRole, error) {
|
||||||
var role domain.UserRole
|
var role domain.UserRole
|
||||||
err := config.DB.Where("id = ?", id).First(&role).Error
|
err := config.DB.Where("id = ?", id).First(&role).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return role, errors.New("UserRole tidak ditemukan")
|
return role, errors.New("userRole tidak ditemukan")
|
||||||
}
|
}
|
||||||
return role, nil
|
return role, nil
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func GetAllUserRoles() ([]domain.UserRole, error) {
|
||||||
var roles []domain.UserRole
|
var roles []domain.UserRole
|
||||||
err := config.DB.Find(&roles).Error
|
err := config.DB.Find(&roles).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Gagal mengambil data UserRole")
|
return nil, errors.New("gagal mengambil data UserRole")
|
||||||
}
|
}
|
||||||
return roles, nil
|
return roles, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pahmiudahgede/senggoldong/domain"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/dto"
|
||||||
|
"github.com/pahmiudahgede/senggoldong/internal/repositories"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateArticle(articleRequest *dto.ArticleRequest) (*dto.ArticleResponse, error) {
|
||||||
|
article := domain.Article{
|
||||||
|
Title: articleRequest.Title,
|
||||||
|
CoverImage: articleRequest.CoverImage,
|
||||||
|
Author: articleRequest.Author,
|
||||||
|
Heading: articleRequest.Heading,
|
||||||
|
Content: articleRequest.Content,
|
||||||
|
PublishedAt: articleRequest.PublishedAt,
|
||||||
|
UpdatedAt: articleRequest.PublishedAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := repositories.CreateArticle(&article)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dto.ArticleResponse{
|
||||||
|
ID: article.ID,
|
||||||
|
Title: article.Title,
|
||||||
|
CoverImage: article.CoverImage,
|
||||||
|
Author: article.Author,
|
||||||
|
Heading: article.Heading,
|
||||||
|
Content: article.Content,
|
||||||
|
PublishedAt: article.PublishedAt,
|
||||||
|
UpdatedAt: article.UpdatedAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArticles() ([]dto.ArticleResponse, error) {
|
||||||
|
articles, err := repositories.GetArticles()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []dto.ArticleResponse
|
||||||
|
for _, article := range articles {
|
||||||
|
response = append(response, dto.ArticleResponse{
|
||||||
|
ID: article.ID,
|
||||||
|
Title: article.Title,
|
||||||
|
CoverImage: article.CoverImage,
|
||||||
|
Author: article.Author,
|
||||||
|
Heading: article.Heading,
|
||||||
|
Content: article.Content,
|
||||||
|
PublishedAt: article.PublishedAt,
|
||||||
|
UpdatedAt: article.UpdatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArticleByID(id string) (dto.ArticleResponse, error) {
|
||||||
|
article, err := repositories.GetArticleByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return dto.ArticleResponse{}, err
|
||||||
|
}
|
||||||
|
return dto.ArticleResponse{
|
||||||
|
ID: article.ID,
|
||||||
|
Title: article.Title,
|
||||||
|
CoverImage: article.CoverImage,
|
||||||
|
Author: article.Author,
|
||||||
|
Heading: article.Heading,
|
||||||
|
Content: article.Content,
|
||||||
|
PublishedAt: article.PublishedAt,
|
||||||
|
UpdatedAt: article.UpdatedAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateArticle(id string, articleUpdateRequest *dto.ArticleUpdateRequest) (*dto.ArticleResponse, error) {
|
||||||
|
|
||||||
|
article, err := repositories.GetArticleByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
article.Title = articleUpdateRequest.Title
|
||||||
|
article.CoverImage = articleUpdateRequest.CoverImage
|
||||||
|
article.Author = articleUpdateRequest.Author
|
||||||
|
article.Heading = articleUpdateRequest.Heading
|
||||||
|
article.Content = articleUpdateRequest.Content
|
||||||
|
article.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
err = repositories.UpdateArticle(&article)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dto.ArticleResponse{
|
||||||
|
ID: article.ID,
|
||||||
|
Title: article.Title,
|
||||||
|
CoverImage: article.CoverImage,
|
||||||
|
Author: article.Author,
|
||||||
|
Heading: article.Heading,
|
||||||
|
Content: article.Content,
|
||||||
|
PublishedAt: article.PublishedAt,
|
||||||
|
UpdatedAt: article.UpdatedAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteArticle(id string) error {
|
||||||
|
|
||||||
|
err := repositories.DeleteArticle(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue