252 lines
8.6 KiB
Go
252 lines
8.6 KiB
Go
|
|
package articles
|
||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"github.com/gin-gonic/gin"
|
||
|
|
"github.com/gothinkster/golang-gin-realworld-example-app/common"
|
||
|
|
"github.com/gothinkster/golang-gin-realworld-example-app/users"
|
||
|
|
"gorm.io/gorm"
|
||
|
|
"net/http"
|
||
|
|
"strconv"
|
||
|
|
)
|
||
|
|
|
||
|
|
func ArticlesRegister(router *gin.RouterGroup) {
|
||
|
|
router.GET("/feed", ArticleFeed)
|
||
|
|
router.POST("", ArticleCreate)
|
||
|
|
router.POST("/", ArticleCreate)
|
||
|
|
router.PUT("/:slug", ArticleUpdate)
|
||
|
|
router.PUT("/:slug/", ArticleUpdate)
|
||
|
|
router.DELETE("/:slug", ArticleDelete)
|
||
|
|
router.POST("/:slug/favorite", ArticleFavorite)
|
||
|
|
router.DELETE("/:slug/favorite", ArticleUnfavorite)
|
||
|
|
router.POST("/:slug/comments", ArticleCommentCreate)
|
||
|
|
router.DELETE("/:slug/comments/:id", ArticleCommentDelete)
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticlesAnonymousRegister(router *gin.RouterGroup) {
|
||
|
|
router.GET("", ArticleList)
|
||
|
|
router.GET("/", ArticleList)
|
||
|
|
router.GET("/:slug", ArticleRetrieve)
|
||
|
|
router.GET("/:slug/comments", ArticleCommentList)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TagsAnonymousRegister(router *gin.RouterGroup) {
|
||
|
|
router.GET("", TagList)
|
||
|
|
router.GET("/", TagList)
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleCreate(c *gin.Context) {
|
||
|
|
articleModelValidator := NewArticleModelValidator()
|
||
|
|
if err := articleModelValidator.Bind(c); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
//fmt.Println(articleModelValidator.articleModel.Author.UserModel)
|
||
|
|
|
||
|
|
if err := SaveOne(&articleModelValidator.articleModel); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticleSerializer{c, articleModelValidator.articleModel}
|
||
|
|
c.JSON(http.StatusCreated, gin.H{"article": serializer.Response()})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleList(c *gin.Context) {
|
||
|
|
//condition := ArticleModel{}
|
||
|
|
tag := c.Query("tag")
|
||
|
|
author := c.Query("author")
|
||
|
|
favorited := c.Query("favorited")
|
||
|
|
limit := c.Query("limit")
|
||
|
|
offset := c.Query("offset")
|
||
|
|
articleModels, modelCount, err := FindManyArticle(tag, author, limit, offset, favorited)
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid param")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticlesSerializer{c, articleModels}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"articles": serializer.Response(), "articlesCount": modelCount})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleFeed(c *gin.Context) {
|
||
|
|
limit := c.Query("limit")
|
||
|
|
offset := c.Query("offset")
|
||
|
|
myUserModel := c.MustGet("my_user_model").(users.UserModel)
|
||
|
|
if myUserModel.ID == 0 {
|
||
|
|
c.AbortWithError(http.StatusUnauthorized, errors.New("{error : \"Require auth!\"}"))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
articleUserModel := GetArticleUserModel(myUserModel)
|
||
|
|
articleModels, modelCount, err := articleUserModel.GetArticleFeed(limit, offset)
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid param")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticlesSerializer{c, articleModels}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"articles": serializer.Response(), "articlesCount": modelCount})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleRetrieve(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid slug")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticleSerializer{c, articleModel}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"article": serializer.Response()})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleUpdate(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid slug")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
// Check if current user is the author
|
||
|
|
myUserModel := c.MustGet("my_user_model").(users.UserModel)
|
||
|
|
articleUserModel := GetArticleUserModel(myUserModel)
|
||
|
|
if articleModel.AuthorID != articleUserModel.ID {
|
||
|
|
c.JSON(http.StatusForbidden, common.NewError("article", errors.New("you are not the author")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
articleModelValidator := NewArticleModelValidatorFillWith(articleModel)
|
||
|
|
if err := articleModelValidator.Bind(c); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
articleModelValidator.articleModel.ID = articleModel.ID
|
||
|
|
if err := articleModel.Update(articleModelValidator.articleModel); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticleSerializer{c, articleModel}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"article": serializer.Response()})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleDelete(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err == nil {
|
||
|
|
// Article exists, check authorization
|
||
|
|
myUserModel := c.MustGet("my_user_model").(users.UserModel)
|
||
|
|
articleUserModel := GetArticleUserModel(myUserModel)
|
||
|
|
if articleModel.AuthorID != articleUserModel.ID {
|
||
|
|
c.JSON(http.StatusForbidden, common.NewError("article", errors.New("you are not the author")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Delete regardless of existence (idempotent)
|
||
|
|
if err := DeleteArticleModel(&ArticleModel{Slug: slug}); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"article": "delete success"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleFavorite(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid slug")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
myUserModel := c.MustGet("my_user_model").(users.UserModel)
|
||
|
|
if err = articleModel.favoriteBy(GetArticleUserModel(myUserModel)); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticleSerializer{c, articleModel}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"article": serializer.Response()})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleUnfavorite(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid slug")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
myUserModel := c.MustGet("my_user_model").(users.UserModel)
|
||
|
|
if err = articleModel.unFavoriteBy(GetArticleUserModel(myUserModel)); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := ArticleSerializer{c, articleModel}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"article": serializer.Response()})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleCommentCreate(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("comment", errors.New("Invalid slug")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
commentModelValidator := NewCommentModelValidator()
|
||
|
|
if err := commentModelValidator.Bind(c); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
commentModelValidator.commentModel.Article = articleModel
|
||
|
|
|
||
|
|
if err := SaveOne(&commentModelValidator.commentModel); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := CommentSerializer{c, commentModelValidator.commentModel}
|
||
|
|
c.JSON(http.StatusCreated, gin.H{"comment": serializer.Response()})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleCommentDelete(c *gin.Context) {
|
||
|
|
id64, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("comment", errors.New("Invalid id")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
id := uint(id64)
|
||
|
|
commentModel, err := FindOneComment(&CommentModel{Model: gorm.Model{ID: id}})
|
||
|
|
if err == nil {
|
||
|
|
// Comment exists, check authorization
|
||
|
|
myUserModel := c.MustGet("my_user_model").(users.UserModel)
|
||
|
|
articleUserModel := GetArticleUserModel(myUserModel)
|
||
|
|
if commentModel.AuthorID != articleUserModel.ID {
|
||
|
|
c.JSON(http.StatusForbidden, common.NewError("comment", errors.New("you are not the author")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Delete regardless of existence (idempotent)
|
||
|
|
if err := DeleteCommentModel([]uint{id}); err != nil {
|
||
|
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"comment": "delete success"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func ArticleCommentList(c *gin.Context) {
|
||
|
|
slug := c.Param("slug")
|
||
|
|
articleModel, err := FindOneArticle(&ArticleModel{Slug: slug})
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("comments", errors.New("Invalid slug")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
err = articleModel.getComments()
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("comments", errors.New("Database error")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := CommentsSerializer{c, articleModel.Comments}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"comments": serializer.Response()})
|
||
|
|
}
|
||
|
|
func TagList(c *gin.Context) {
|
||
|
|
tagModels, err := getAllTags()
|
||
|
|
if err != nil {
|
||
|
|
c.JSON(http.StatusNotFound, common.NewError("articles", errors.New("Invalid param")))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
serializer := TagsSerializer{c, tagModels}
|
||
|
|
c.JSON(http.StatusOK, gin.H{"tags": serializer.Response()})
|
||
|
|
}
|