♻️ Use the universal post api replace some duplicated apis
This commit is contained in:
parent
1e366af3b8
commit
69ced62715
20
pkg/models/feed.go
Normal file
20
pkg/models/feed.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type Feed struct {
|
||||||
|
BaseModel
|
||||||
|
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
ModelType string `json:"model_type"`
|
||||||
|
|
||||||
|
CommentCount int64 `json:"comment_count"`
|
||||||
|
ReactionCount int64 `json:"reaction_count"`
|
||||||
|
|
||||||
|
AuthorID uint `json:"author_id"`
|
||||||
|
RealmID *uint `json:"realm_id"`
|
||||||
|
|
||||||
|
Author Account `json:"author" gorm:"embedded"`
|
||||||
|
ReactionList map[string]int64 `json:"reaction_list" gorm:"-"`
|
||||||
|
}
|
@ -9,81 +9,18 @@ import (
|
|||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/samber/lo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func contextArticle() *services.PostTypeContext[*models.Article] {
|
func contextArticle() *services.PostTypeContext {
|
||||||
return &services.PostTypeContext[*models.Article]{
|
return &services.PostTypeContext{
|
||||||
Tx: database.C,
|
Tx: database.C,
|
||||||
TypeName: "Article",
|
TableName: "articles",
|
||||||
|
ColumnName: "article",
|
||||||
CanReply: false,
|
CanReply: false,
|
||||||
CanRepost: false,
|
CanRepost: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getArticle(c *fiber.Ctx) error {
|
|
||||||
alias := c.Params("articleId")
|
|
||||||
|
|
||||||
mx := contextArticle().FilterPublishedAt(time.Now())
|
|
||||||
|
|
||||||
item, err := mx.GetViaAlias(alias)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
item.ReactionList, err = mx.CountReactions(item.ID)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listArticle(c *fiber.Ctx) error {
|
|
||||||
take := c.QueryInt("take", 0)
|
|
||||||
offset := c.QueryInt("offset", 0)
|
|
||||||
realmId := c.QueryInt("realmId", 0)
|
|
||||||
|
|
||||||
mx := contextArticle().
|
|
||||||
FilterPublishedAt(time.Now()).
|
|
||||||
FilterRealm(uint(realmId)).
|
|
||||||
SortCreatedAt("desc")
|
|
||||||
|
|
||||||
var author models.Account
|
|
||||||
if len(c.Query("authorId")) > 0 {
|
|
||||||
if err := database.C.Where(&models.Account{Name: c.Query("authorId")}).First(&author).Error; err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
mx = mx.FilterAuthor(author.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.Query("category")) > 0 {
|
|
||||||
mx = mx.FilterWithCategory(c.Query("category"))
|
|
||||||
}
|
|
||||||
if len(c.Query("tag")) > 0 {
|
|
||||||
mx = mx.FilterWithTag(c.Query("tag"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.QueryBool("reply", true) {
|
|
||||||
mx = mx.FilterReply(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := mx.Count()
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
items, err := mx.List(take, offset)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(fiber.Map{
|
|
||||||
"count": count,
|
|
||||||
"data": items,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func createArticle(c *fiber.Ctx) error {
|
func createArticle(c *fiber.Ctx) error {
|
||||||
user := c.Locals("principal").(models.Account)
|
user := c.Locals("principal").(models.Account)
|
||||||
|
|
||||||
@ -105,8 +42,6 @@ func createArticle(c *fiber.Ctx) error {
|
|||||||
data.Alias = strings.ReplaceAll(uuid.NewString(), "-", "")
|
data.Alias = strings.ReplaceAll(uuid.NewString(), "-", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
mx := contextArticle()
|
|
||||||
|
|
||||||
item := &models.Article{
|
item := &models.Article{
|
||||||
PostBase: models.PostBase{
|
PostBase: models.PostBase{
|
||||||
Alias: data.Alias,
|
Alias: data.Alias,
|
||||||
@ -131,12 +66,11 @@ func createArticle(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := mx.New(item)
|
if item, err := services.NewPost(item); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
} else {
|
||||||
|
|
||||||
return c.JSON(item)
|
return c.JSON(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func editArticle(c *fiber.Ctx) error {
|
func editArticle(c *fiber.Ctx) error {
|
||||||
@ -158,10 +92,13 @@ func editArticle(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mx := contextArticle().FilterAuthor(user.ID)
|
var item *models.Article
|
||||||
|
if err := database.C.Where(models.Article{
|
||||||
item, err := mx.Get(uint(id))
|
PostBase: models.PostBase{
|
||||||
if err != nil {
|
BaseModel: models.BaseModel{ID: uint(id)},
|
||||||
|
AuthorID: user.ID,
|
||||||
|
},
|
||||||
|
}).First(&item).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,61 +111,28 @@ func editArticle(c *fiber.Ctx) error {
|
|||||||
item.Categories = data.Categories
|
item.Categories = data.Categories
|
||||||
item.Attachments = data.Attachments
|
item.Attachments = data.Attachments
|
||||||
|
|
||||||
item, err = mx.Edit(item)
|
if item, err := services.EditPost(item); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func reactArticle(c *fiber.Ctx) error {
|
|
||||||
user := c.Locals("principal").(models.Account)
|
|
||||||
id, _ := c.ParamsInt("articleId", 0)
|
|
||||||
|
|
||||||
var data struct {
|
|
||||||
Symbol string `json:"symbol" validate:"required"`
|
|
||||||
Attitude models.ReactionAttitude `json:"attitude" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := BindAndValidate(c, &data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mx := contextArticle()
|
|
||||||
|
|
||||||
item, err := mx.Get(uint(id), true)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
reaction := models.Reaction{
|
|
||||||
Symbol: data.Symbol,
|
|
||||||
Attitude: data.Attitude,
|
|
||||||
AccountID: user.ID,
|
|
||||||
ArticleID: &item.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
if positive, reaction, err := mx.React(reaction); err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
} else {
|
} else {
|
||||||
return c.Status(lo.Ternary(positive, fiber.StatusCreated, fiber.StatusNoContent)).JSON(reaction)
|
return c.JSON(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteArticle(c *fiber.Ctx) error {
|
func deleteArticle(c *fiber.Ctx) error {
|
||||||
user := c.Locals("principal").(models.Account)
|
user := c.Locals("principal").(models.Account)
|
||||||
id, _ := c.ParamsInt("articleId", 0)
|
id, _ := c.ParamsInt("articleId", 0)
|
||||||
|
|
||||||
mx := contextArticle().FilterAuthor(user.ID)
|
var item *models.Article
|
||||||
|
if err := database.C.Where(models.Article{
|
||||||
item, err := mx.Get(uint(id), true)
|
PostBase: models.PostBase{
|
||||||
if err != nil {
|
BaseModel: models.BaseModel{ID: uint(id)},
|
||||||
|
AuthorID: user.ID,
|
||||||
|
},
|
||||||
|
}).First(&item).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mx.Delete(item); err != nil {
|
if err := services.DeletePost(item); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,81 +10,18 @@ import (
|
|||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/samber/lo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func contextComment() *services.PostTypeContext[*models.Comment] {
|
func contextComment() *services.PostTypeContext {
|
||||||
return &services.PostTypeContext[*models.Comment]{
|
return &services.PostTypeContext{
|
||||||
Tx: database.C,
|
Tx: database.C,
|
||||||
TypeName: "Comment",
|
TableName: "comments",
|
||||||
|
ColumnName: "comment",
|
||||||
CanReply: false,
|
CanReply: false,
|
||||||
CanRepost: true,
|
CanRepost: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getComment(c *fiber.Ctx) error {
|
|
||||||
alias := c.Params("commentId")
|
|
||||||
|
|
||||||
mx := contextComment().FilterPublishedAt(time.Now())
|
|
||||||
|
|
||||||
item, err := mx.GetViaAlias(alias)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
item.ReactionList, err = mx.CountReactions(item.ID)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listComment(c *fiber.Ctx) error {
|
|
||||||
take := c.QueryInt("take", 0)
|
|
||||||
offset := c.QueryInt("offset", 0)
|
|
||||||
realmId := c.QueryInt("realmId", 0)
|
|
||||||
|
|
||||||
mx := contextComment().
|
|
||||||
FilterPublishedAt(time.Now()).
|
|
||||||
FilterRealm(uint(realmId)).
|
|
||||||
SortCreatedAt("desc")
|
|
||||||
|
|
||||||
var author models.Account
|
|
||||||
if len(c.Query("authorId")) > 0 {
|
|
||||||
if err := database.C.Where(&models.Account{Name: c.Query("authorId")}).First(&author).Error; err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
mx = mx.FilterAuthor(author.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.Query("category")) > 0 {
|
|
||||||
mx = mx.FilterWithCategory(c.Query("category"))
|
|
||||||
}
|
|
||||||
if len(c.Query("tag")) > 0 {
|
|
||||||
mx = mx.FilterWithTag(c.Query("tag"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.QueryBool("reply", true) {
|
|
||||||
mx = mx.FilterReply(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := mx.Count()
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
items, err := mx.List(take, offset)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(fiber.Map{
|
|
||||||
"count": count,
|
|
||||||
"data": items,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func createComment(c *fiber.Ctx) error {
|
func createComment(c *fiber.Ctx) error {
|
||||||
user := c.Locals("principal").(models.Account)
|
user := c.Locals("principal").(models.Account)
|
||||||
|
|
||||||
@ -106,8 +43,6 @@ func createComment(c *fiber.Ctx) error {
|
|||||||
data.Alias = strings.ReplaceAll(uuid.NewString(), "-", "")
|
data.Alias = strings.ReplaceAll(uuid.NewString(), "-", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
mx := contextComment()
|
|
||||||
|
|
||||||
item := &models.Comment{
|
item := &models.Comment{
|
||||||
PostBase: models.PostBase{
|
PostBase: models.PostBase{
|
||||||
Alias: data.Alias,
|
Alias: data.Alias,
|
||||||
@ -142,7 +77,7 @@ func createComment(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := mx.New(item)
|
item, err := services.NewPost(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
@ -167,10 +102,13 @@ func editComment(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mx := contextComment().FilterAuthor(user.ID)
|
var item *models.Comment
|
||||||
|
if err := database.C.Where(models.Comment{
|
||||||
item, err := mx.Get(uint(id))
|
PostBase: models.PostBase{
|
||||||
if err != nil {
|
BaseModel: models.BaseModel{ID: uint(id)},
|
||||||
|
AuthorID: user.ID,
|
||||||
|
},
|
||||||
|
}).First(&item).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,61 +119,28 @@ func editComment(c *fiber.Ctx) error {
|
|||||||
item.Categories = data.Categories
|
item.Categories = data.Categories
|
||||||
item.Attachments = data.Attachments
|
item.Attachments = data.Attachments
|
||||||
|
|
||||||
item, err = mx.Edit(item)
|
if item, err := services.EditPost(item); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func reactComment(c *fiber.Ctx) error {
|
|
||||||
user := c.Locals("principal").(models.Account)
|
|
||||||
id, _ := c.ParamsInt("commentId", 0)
|
|
||||||
|
|
||||||
var data struct {
|
|
||||||
Symbol string `json:"symbol" validate:"required"`
|
|
||||||
Attitude models.ReactionAttitude `json:"attitude" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := BindAndValidate(c, &data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mx := contextComment()
|
|
||||||
|
|
||||||
item, err := mx.Get(uint(id), true)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
reaction := models.Reaction{
|
|
||||||
Symbol: data.Symbol,
|
|
||||||
Attitude: data.Attitude,
|
|
||||||
AccountID: user.ID,
|
|
||||||
CommentID: &item.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
if positive, reaction, err := mx.React(reaction); err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
} else {
|
} else {
|
||||||
return c.Status(lo.Ternary(positive, fiber.StatusCreated, fiber.StatusNoContent)).JSON(reaction)
|
return c.JSON(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteComment(c *fiber.Ctx) error {
|
func deleteComment(c *fiber.Ctx) error {
|
||||||
user := c.Locals("principal").(models.Account)
|
user := c.Locals("principal").(models.Account)
|
||||||
id, _ := c.ParamsInt("commentId", 0)
|
id, _ := c.ParamsInt("commentId", 0)
|
||||||
|
|
||||||
mx := contextComment().FilterAuthor(user.ID)
|
var item *models.Comment
|
||||||
|
if err := database.C.Where(models.Comment{
|
||||||
item, err := mx.Get(uint(id), true)
|
PostBase: models.PostBase{
|
||||||
if err != nil {
|
BaseModel: models.BaseModel{ID: uint(id)},
|
||||||
|
AuthorID: user.ID,
|
||||||
|
},
|
||||||
|
}).First(&item).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mx.Delete(item); err != nil {
|
if err := services.DeletePost(item); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import "C"
|
|
||||||
import (
|
import (
|
||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
|
||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
|
||||||
@ -10,23 +9,6 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FeedItem struct {
|
|
||||||
models.BaseModel
|
|
||||||
|
|
||||||
Alias string `json:"alias"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Content string `json:"content"`
|
|
||||||
ModelType string `json:"model_type"`
|
|
||||||
CommentCount int64 `json:"comment_count"`
|
|
||||||
ReactionCount int64 `json:"reaction_count"`
|
|
||||||
AuthorID uint `json:"author_id"`
|
|
||||||
RealmID *uint `json:"realm_id"`
|
|
||||||
|
|
||||||
Author models.Account `json:"author" gorm:"embedded"`
|
|
||||||
ReactionList map[string]int64 `json:"reaction_list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
queryArticle = "id, created_at, updated_at, alias, title, NULL as content, description, realm_id, author_id, 'article' as model_type"
|
queryArticle = "id, created_at, updated_at, alias, title, NULL as content, description, realm_id, author_id, 'article' as model_type"
|
||||||
queryMoment = "id, created_at, updated_at, alias, NULL as title, content, NULL as description, realm_id, author_id, 'moment' as model_type"
|
queryMoment = "id, created_at, updated_at, alias, NULL as title, content, NULL as description, realm_id, author_id, 'moment' as model_type"
|
||||||
@ -58,7 +40,7 @@ func listFeed(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []*FeedItem
|
var result []*models.Feed
|
||||||
|
|
||||||
userTable := viper.GetString("database.prefix") + "accounts"
|
userTable := viper.GetString("database.prefix") + "accounts"
|
||||||
commentTable := viper.GetString("database.prefix") + "comments"
|
commentTable := viper.GetString("database.prefix") + "comments"
|
||||||
@ -94,15 +76,15 @@ func listFeed(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
revertReaction := func(dataset string) error {
|
revertReaction := func(dataset string) error {
|
||||||
itemMap := lo.SliceToMap(lo.FilterMap(result, func(item *FeedItem, index int) (*FeedItem, bool) {
|
itemMap := lo.SliceToMap(lo.FilterMap(result, func(item *models.Feed, index int) (*models.Feed, bool) {
|
||||||
return item, item.ModelType == dataset
|
return item, item.ModelType == dataset
|
||||||
}), func(item *FeedItem) (uint, *FeedItem) {
|
}), func(item *models.Feed) (uint, *models.Feed) {
|
||||||
return item.ID, item
|
return item.ID, item
|
||||||
})
|
})
|
||||||
|
|
||||||
idx := lo.Map(lo.Filter(result, func(item *FeedItem, index int) bool {
|
idx := lo.Map(lo.Filter(result, func(item *models.Feed, index int) bool {
|
||||||
return item.ModelType == dataset
|
return item.ModelType == dataset
|
||||||
}), func(item *FeedItem, index int) uint {
|
}), func(item *models.Feed, index int) uint {
|
||||||
return item.ID
|
return item.ID
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -9,81 +9,18 @@ import (
|
|||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/samber/lo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func contextMoment() *services.PostTypeContext[*models.Moment] {
|
func contextMoment() *services.PostTypeContext {
|
||||||
return &services.PostTypeContext[*models.Moment]{
|
return &services.PostTypeContext{
|
||||||
Tx: database.C,
|
Tx: database.C,
|
||||||
TypeName: "Moment",
|
TableName: "moments",
|
||||||
|
ColumnName: "moment",
|
||||||
CanReply: false,
|
CanReply: false,
|
||||||
CanRepost: true,
|
CanRepost: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMoment(c *fiber.Ctx) error {
|
|
||||||
alias := c.Params("momentId")
|
|
||||||
|
|
||||||
mx := contextMoment().FilterPublishedAt(time.Now())
|
|
||||||
|
|
||||||
item, err := mx.GetViaAlias(alias)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
item.ReactionList, err = mx.CountReactions(item.ID)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listMoment(c *fiber.Ctx) error {
|
|
||||||
take := c.QueryInt("take", 0)
|
|
||||||
offset := c.QueryInt("offset", 0)
|
|
||||||
realmId := c.QueryInt("realmId", 0)
|
|
||||||
|
|
||||||
mx := contextMoment().
|
|
||||||
FilterPublishedAt(time.Now()).
|
|
||||||
FilterRealm(uint(realmId)).
|
|
||||||
SortCreatedAt("desc")
|
|
||||||
|
|
||||||
var author models.Account
|
|
||||||
if len(c.Query("authorId")) > 0 {
|
|
||||||
if err := database.C.Where(&models.Account{Name: c.Query("authorId")}).First(&author).Error; err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
mx = mx.FilterAuthor(author.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.Query("category")) > 0 {
|
|
||||||
mx = mx.FilterWithCategory(c.Query("category"))
|
|
||||||
}
|
|
||||||
if len(c.Query("tag")) > 0 {
|
|
||||||
mx = mx.FilterWithTag(c.Query("tag"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.QueryBool("reply", true) {
|
|
||||||
mx = mx.FilterReply(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := mx.Count()
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
items, err := mx.List(take, offset)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(fiber.Map{
|
|
||||||
"count": count,
|
|
||||||
"data": items,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func createMoment(c *fiber.Ctx) error {
|
func createMoment(c *fiber.Ctx) error {
|
||||||
user := c.Locals("principal").(models.Account)
|
user := c.Locals("principal").(models.Account)
|
||||||
|
|
||||||
@ -104,8 +41,6 @@ func createMoment(c *fiber.Ctx) error {
|
|||||||
data.Alias = strings.ReplaceAll(uuid.NewString(), "-", "")
|
data.Alias = strings.ReplaceAll(uuid.NewString(), "-", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
mx := contextMoment()
|
|
||||||
|
|
||||||
item := &models.Moment{
|
item := &models.Moment{
|
||||||
PostBase: models.PostBase{
|
PostBase: models.PostBase{
|
||||||
Alias: data.Alias,
|
Alias: data.Alias,
|
||||||
@ -140,7 +75,7 @@ func createMoment(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := mx.New(item)
|
item, err := services.NewPost(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
@ -165,10 +100,13 @@ func editMoment(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mx := contextMoment().FilterAuthor(user.ID)
|
var item *models.Moment
|
||||||
|
if err := database.C.Where(models.Comment{
|
||||||
item, err := mx.Get(uint(id))
|
PostBase: models.PostBase{
|
||||||
if err != nil {
|
BaseModel: models.BaseModel{ID: uint(id)},
|
||||||
|
AuthorID: user.ID,
|
||||||
|
},
|
||||||
|
}).First(&item).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,61 +117,28 @@ func editMoment(c *fiber.Ctx) error {
|
|||||||
item.Categories = data.Categories
|
item.Categories = data.Categories
|
||||||
item.Attachments = data.Attachments
|
item.Attachments = data.Attachments
|
||||||
|
|
||||||
item, err = mx.Edit(item)
|
if item, err := services.EditPost(item); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func reactMoment(c *fiber.Ctx) error {
|
|
||||||
user := c.Locals("principal").(models.Account)
|
|
||||||
id, _ := c.ParamsInt("momentId", 0)
|
|
||||||
|
|
||||||
var data struct {
|
|
||||||
Symbol string `json:"symbol" validate:"required"`
|
|
||||||
Attitude models.ReactionAttitude `json:"attitude" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := BindAndValidate(c, &data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mx := contextMoment()
|
|
||||||
|
|
||||||
item, err := mx.Get(uint(id), true)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
reaction := models.Reaction{
|
|
||||||
Symbol: data.Symbol,
|
|
||||||
Attitude: data.Attitude,
|
|
||||||
AccountID: user.ID,
|
|
||||||
MomentID: &item.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
if positive, reaction, err := mx.React(reaction); err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
} else {
|
} else {
|
||||||
return c.Status(lo.Ternary(positive, fiber.StatusCreated, fiber.StatusNoContent)).JSON(reaction)
|
return c.JSON(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteMoment(c *fiber.Ctx) error {
|
func deleteMoment(c *fiber.Ctx) error {
|
||||||
user := c.Locals("principal").(models.Account)
|
user := c.Locals("principal").(models.Account)
|
||||||
id, _ := c.ParamsInt("momentId", 0)
|
id, _ := c.ParamsInt("momentId", 0)
|
||||||
|
|
||||||
mx := contextMoment().FilterAuthor(user.ID)
|
var item *models.Moment
|
||||||
|
if err := database.C.Where(models.Comment{
|
||||||
item, err := mx.Get(uint(id), true)
|
PostBase: models.PostBase{
|
||||||
if err != nil {
|
BaseModel: models.BaseModel{ID: uint(id)},
|
||||||
|
AuthorID: user.ID,
|
||||||
|
},
|
||||||
|
}).First(&item).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mx.Delete(item); err != nil {
|
if err := services.DeletePost(item); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
126
pkg/server/posts_api.go
Normal file
126
pkg/server/posts_api.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
|
||||||
|
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
|
||||||
|
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var postContextKey = "ptx"
|
||||||
|
|
||||||
|
func useDynamicContext(c *fiber.Ctx) error {
|
||||||
|
postType := c.Params("postType")
|
||||||
|
switch postType {
|
||||||
|
case "articles":
|
||||||
|
c.Locals(postContextKey, contextArticle())
|
||||||
|
case "moments":
|
||||||
|
c.Locals(postContextKey, contextMoment())
|
||||||
|
case "comments":
|
||||||
|
c.Locals(postContextKey, contextComment())
|
||||||
|
default:
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid dataset")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPost(c *fiber.Ctx) error {
|
||||||
|
alias := c.Params("postId")
|
||||||
|
|
||||||
|
mx := c.Locals(postContextKey).(*services.PostTypeContext)
|
||||||
|
|
||||||
|
item, err := mx.GetViaAlias(alias)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
item.ReactionList, err = mx.CountReactions(item.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listPost(c *fiber.Ctx) error {
|
||||||
|
take := c.QueryInt("take", 0)
|
||||||
|
offset := c.QueryInt("offset", 0)
|
||||||
|
realmId := c.QueryInt("realmId", 0)
|
||||||
|
|
||||||
|
mx := c.Locals(postContextKey).(*services.PostTypeContext).
|
||||||
|
FilterPublishedAt(time.Now()).
|
||||||
|
FilterRealm(uint(realmId)).
|
||||||
|
SortCreatedAt("desc")
|
||||||
|
|
||||||
|
var author models.Account
|
||||||
|
if len(c.Query("authorId")) > 0 {
|
||||||
|
if err := database.C.Where(&models.Account{Name: c.Query("authorId")}).First(&author).Error; err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
|
}
|
||||||
|
mx = mx.FilterAuthor(author.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Query("category")) > 0 {
|
||||||
|
mx = mx.FilterWithCategory(c.Query("category"))
|
||||||
|
}
|
||||||
|
if len(c.Query("tag")) > 0 {
|
||||||
|
mx = mx.FilterWithTag(c.Query("tag"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.QueryBool("reply", true) {
|
||||||
|
mx = mx.FilterReply(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := mx.Count()
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
items, err := mx.List(take, offset)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"count": count,
|
||||||
|
"data": items,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func reactPost(c *fiber.Ctx) error {
|
||||||
|
user := c.Locals("principal").(models.Account)
|
||||||
|
id, _ := c.ParamsInt("articleId", 0)
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Symbol string `json:"symbol" validate:"required"`
|
||||||
|
Attitude models.ReactionAttitude `json:"attitude" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := BindAndValidate(c, &data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mx := c.Locals(postContextKey).(*services.PostTypeContext)
|
||||||
|
|
||||||
|
item, err := mx.Get(uint(id), true)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction := models.Reaction{
|
||||||
|
Symbol: data.Symbol,
|
||||||
|
Attitude: data.Attitude,
|
||||||
|
AccountID: user.ID,
|
||||||
|
ArticleID: &item.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if positive, reaction, err := mx.React(reaction); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
} else {
|
||||||
|
return c.Status(lo.Ternary(positive, fiber.StatusCreated, fiber.StatusNoContent)).JSON(reaction)
|
||||||
|
}
|
||||||
|
}
|
@ -71,32 +71,30 @@ func NewServer() {
|
|||||||
|
|
||||||
api.Get("/feed", listFeed)
|
api.Get("/feed", listFeed)
|
||||||
|
|
||||||
|
posts := api.Group("/p/:postType").Use(useDynamicContext).Name("Dataset Universal API")
|
||||||
|
{
|
||||||
|
posts.Get("/", listPost)
|
||||||
|
posts.Get("/:postId", getPost)
|
||||||
|
posts.Post("/:postId/react", authMiddleware, reactPost)
|
||||||
|
}
|
||||||
|
|
||||||
moments := api.Group("/moments").Name("Moments API")
|
moments := api.Group("/moments").Name("Moments API")
|
||||||
{
|
{
|
||||||
moments.Get("/", listMoment)
|
|
||||||
moments.Get("/:momentId", getMoment)
|
|
||||||
moments.Post("/", authMiddleware, createMoment)
|
moments.Post("/", authMiddleware, createMoment)
|
||||||
moments.Post("/:momentId/react", authMiddleware, reactMoment)
|
|
||||||
moments.Put("/:momentId", authMiddleware, editMoment)
|
moments.Put("/:momentId", authMiddleware, editMoment)
|
||||||
moments.Delete("/:momentId", authMiddleware, deleteMoment)
|
moments.Delete("/:momentId", authMiddleware, deleteMoment)
|
||||||
}
|
}
|
||||||
|
|
||||||
articles := api.Group("/articles").Name("Articles API")
|
articles := api.Group("/p/articles").Name("Articles API")
|
||||||
{
|
{
|
||||||
articles.Get("/", listArticle)
|
|
||||||
articles.Get("/:articleId", getArticle)
|
|
||||||
articles.Post("/", authMiddleware, createArticle)
|
articles.Post("/", authMiddleware, createArticle)
|
||||||
articles.Post("/:articleId/react", authMiddleware, reactArticle)
|
|
||||||
articles.Put("/:articleId", authMiddleware, editArticle)
|
articles.Put("/:articleId", authMiddleware, editArticle)
|
||||||
articles.Delete("/:articleId", authMiddleware, deleteArticle)
|
articles.Delete("/:articleId", authMiddleware, deleteArticle)
|
||||||
}
|
}
|
||||||
|
|
||||||
comments := api.Group("/comments").Name("Comments API")
|
comments := api.Group("/p/comments").Name("Comments API")
|
||||||
{
|
{
|
||||||
comments.Get("/", listComment)
|
|
||||||
comments.Get("/:commentId", getComment)
|
|
||||||
comments.Post("/", authMiddleware, createComment)
|
comments.Post("/", authMiddleware, createComment)
|
||||||
comments.Post("/:commentId/react", authMiddleware, reactComment)
|
|
||||||
comments.Put("/:commentId", authMiddleware, editComment)
|
comments.Put("/:commentId", authMiddleware, editComment)
|
||||||
comments.Delete("/:commentId", authMiddleware, deleteComment)
|
comments.Delete("/:commentId", authMiddleware, deleteComment)
|
||||||
}
|
}
|
||||||
|
@ -1,81 +1,50 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import "C"
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.smartsheep.studio/hydrogen/identity/pkg/grpc/proto"
|
"code.smartsheep.studio/hydrogen/identity/pkg/grpc/proto"
|
||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
|
||||||
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
|
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
pluralize "github.com/gertd/go-pluralize"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PostTypeContext[T models.PostInterface] struct {
|
type PostTypeContext struct {
|
||||||
Tx *gorm.DB
|
Tx *gorm.DB
|
||||||
|
|
||||||
TypeName string
|
TableName string
|
||||||
|
ColumnName string
|
||||||
CanReply bool
|
CanReply bool
|
||||||
CanRepost bool
|
CanRepost bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var pluralizeHelper = pluralize.NewClient()
|
func (v *PostTypeContext) FilterWithCategory(alias string) *PostTypeContext {
|
||||||
|
name := v.ColumnName
|
||||||
func (v *PostTypeContext[T]) GetTableName(plural ...bool) string {
|
v.Tx.Joins(fmt.Sprintf("JOIN %s_categories ON %s.id = %s_categories.%s_id", name, v.TableName, name, name)).
|
||||||
if len(plural) <= 0 || !plural[0] {
|
Joins(fmt.Sprintf("JOIN %s_categories ON %s_categories.id = %s_categories.category_id", name, name, name)).
|
||||||
return strings.ToLower(v.TypeName)
|
Where(name+"_categories.alias = ?", alias)
|
||||||
} else {
|
|
||||||
return pluralizeHelper.Plural(strings.ToLower(v.TypeName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) Preload(noComments ...bool) *PostTypeContext[T] {
|
|
||||||
v.Tx.Preload("Author").
|
|
||||||
Preload("Attachments").
|
|
||||||
Preload("Categories").
|
|
||||||
Preload("Hashtags")
|
|
||||||
|
|
||||||
if len(noComments) <= 0 || !noComments[0] {
|
|
||||||
v.Tx = v.Tx.Preload("Comments")
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.CanReply {
|
|
||||||
v.Tx.Preload("ReplyTo")
|
|
||||||
}
|
|
||||||
if v.CanRepost {
|
|
||||||
v.Tx.Preload("RepostTo")
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) FilterWithCategory(alias string) *PostTypeContext[T] {
|
func (v *PostTypeContext) FilterWithTag(alias string) *PostTypeContext {
|
||||||
table := v.GetTableName()
|
name := v.ColumnName
|
||||||
v.Tx.Joins(fmt.Sprintf("JOIN %s_categories ON %s.id = %s_categories.%s_id", table, v.GetTableName(true), table, v.GetTableName())).
|
v.Tx.Joins(fmt.Sprintf("JOIN %s_tags ON %s.id = %s_tags.%s_id", name, v.TableName, name, name)).
|
||||||
Joins(fmt.Sprintf("JOIN %s_categories ON %s_categories.id = %s_categories.category_id", table, table, table)).
|
Joins(fmt.Sprintf("JOIN %s_tags ON %s_tags.id = %s_tags.category_id", name, name, name)).
|
||||||
Where(table+"_categories.alias = ?", alias)
|
Where(name+"_tags.alias = ?", alias)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) FilterWithTag(alias string) *PostTypeContext[T] {
|
func (v *PostTypeContext) FilterPublishedAt(date time.Time) *PostTypeContext {
|
||||||
table := v.GetTableName()
|
|
||||||
v.Tx.Joins(fmt.Sprintf("JOIN %s_tags ON %s.id = %s_tags.%s_id", table, v.GetTableName(true), table, v.GetTableName())).
|
|
||||||
Joins(fmt.Sprintf("JOIN %s_tags ON %s_tags.id = %s_tags.category_id", table, table, table)).
|
|
||||||
Where(table+"_tags.alias = ?", alias)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) FilterPublishedAt(date time.Time) *PostTypeContext[T] {
|
|
||||||
v.Tx.Where("published_at <= ? AND published_at IS NULL", date)
|
v.Tx.Where("published_at <= ? AND published_at IS NULL", date)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) FilterRealm(id uint) *PostTypeContext[T] {
|
func (v *PostTypeContext) FilterRealm(id uint) *PostTypeContext {
|
||||||
if id > 0 {
|
if id > 0 {
|
||||||
v.Tx = v.Tx.Where("realm_id = ?", id)
|
v.Tx = v.Tx.Where("realm_id = ?", id)
|
||||||
} else {
|
} else {
|
||||||
@ -84,12 +53,12 @@ func (v *PostTypeContext[T]) FilterRealm(id uint) *PostTypeContext[T] {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) FilterAuthor(id uint) *PostTypeContext[T] {
|
func (v *PostTypeContext) FilterAuthor(id uint) *PostTypeContext {
|
||||||
v.Tx = v.Tx.Where("author_id = ?", id)
|
v.Tx = v.Tx.Where("author_id = ?", id)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) FilterReply(condition bool) *PostTypeContext[T] {
|
func (v *PostTypeContext) FilterReply(condition bool) *PostTypeContext {
|
||||||
if condition {
|
if condition {
|
||||||
v.Tx = v.Tx.Where("reply_id IS NOT NULL")
|
v.Tx = v.Tx.Where("reply_id IS NOT NULL")
|
||||||
} else {
|
} else {
|
||||||
@ -98,32 +67,34 @@ func (v *PostTypeContext[T]) FilterReply(condition bool) *PostTypeContext[T] {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) SortCreatedAt(order string) *PostTypeContext[T] {
|
func (v *PostTypeContext) SortCreatedAt(order string) *PostTypeContext {
|
||||||
v.Tx.Order(fmt.Sprintf("created_at %s", order))
|
v.Tx.Order(fmt.Sprintf("created_at %s", order))
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) GetViaAlias(alias string, noComments ...bool) (T, error) {
|
func (v *PostTypeContext) GetViaAlias(alias string, noComments ...bool) (models.Feed, error) {
|
||||||
var item T
|
var item models.Feed
|
||||||
if err := v.Preload(noComments...).Tx.Where("alias = ?", alias).First(&item).Error; err != nil {
|
if err := v.Tx.Where("alias = ?", alias).First(&item).Error; err != nil {
|
||||||
return item, err
|
return item, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) Get(id uint, noComments ...bool) (T, error) {
|
func (v *PostTypeContext) Get(id uint, noComments ...bool) (models.Feed, error) {
|
||||||
var item T
|
var item models.Feed
|
||||||
if err := v.Preload(noComments...).Tx.Where("id = ?", id).First(&item).Error; err != nil {
|
if err := v.Tx.
|
||||||
|
Select("*, ? as model_type", v.ColumnName).
|
||||||
|
Where("id = ?", id).First(&item).Error; err != nil {
|
||||||
return item, err
|
return item, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) Count() (int64, error) {
|
func (v *PostTypeContext) Count() (int64, error) {
|
||||||
var count int64
|
var count int64
|
||||||
table := viper.GetString("database.prefix") + v.GetTableName(true)
|
table := viper.GetString("database.prefix") + v.TableName
|
||||||
if err := v.Tx.Table(table).Count(&count).Error; err != nil {
|
if err := v.Tx.Table(table).Count(&count).Error; err != nil {
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
@ -131,7 +102,7 @@ func (v *PostTypeContext[T]) Count() (int64, error) {
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) CountReactions(id uint) (map[string]int64, error) {
|
func (v *PostTypeContext) CountReactions(id uint) (map[string]int64, error) {
|
||||||
var reactions []struct {
|
var reactions []struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
Count int64
|
Count int64
|
||||||
@ -139,7 +110,7 @@ func (v *PostTypeContext[T]) CountReactions(id uint) (map[string]int64, error) {
|
|||||||
|
|
||||||
if err := database.C.Model(&models.Reaction{}).
|
if err := database.C.Model(&models.Reaction{}).
|
||||||
Select("symbol, COUNT(id) as count").
|
Select("symbol, COUNT(id) as count").
|
||||||
Where(strings.ToLower(v.TypeName)+"_id = ?", id).
|
Where(v.ColumnName+"_id = ?", id).
|
||||||
Group("symbol").
|
Group("symbol").
|
||||||
Scan(&reactions).Error; err != nil {
|
Scan(&reactions).Error; err != nil {
|
||||||
return map[string]int64{}, err
|
return map[string]int64{}, err
|
||||||
@ -148,23 +119,26 @@ func (v *PostTypeContext[T]) CountReactions(id uint) (map[string]int64, error) {
|
|||||||
return lo.SliceToMap(reactions, func(item struct {
|
return lo.SliceToMap(reactions, func(item struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
Count int64
|
Count int64
|
||||||
}) (string, int64) {
|
},
|
||||||
|
) (string, int64) {
|
||||||
return item.Symbol, item.Count
|
return item.Symbol, item.Count
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, error) {
|
func (v *PostTypeContext) List(take int, offset int, noReact ...bool) ([]*models.Feed, error) {
|
||||||
if take > 20 {
|
if take > 20 {
|
||||||
take = 20
|
take = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
var items []T
|
var items []*models.Feed
|
||||||
if err := v.Preload().Tx.Limit(take).Offset(offset).Find(&items).Error; err != nil {
|
if err := v.Tx.
|
||||||
|
Select("*, ? as model_type", v.ColumnName).
|
||||||
|
Limit(take).Offset(offset).Find(&items).Error; err != nil {
|
||||||
return items, err
|
return items, err
|
||||||
}
|
}
|
||||||
|
|
||||||
idx := lo.Map(items, func(item T, index int) uint {
|
idx := lo.Map(items, func(item *models.Feed, index int) uint {
|
||||||
return item.GetID()
|
return item.ID
|
||||||
})
|
})
|
||||||
|
|
||||||
if len(noReact) <= 0 || !noReact[0] {
|
if len(noReact) <= 0 || !noReact[0] {
|
||||||
@ -175,15 +149,15 @@ func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := database.C.Model(&models.Reaction{}).
|
if err := database.C.Model(&models.Reaction{}).
|
||||||
Select(strings.ToLower(v.TypeName)+"_id as post_id, symbol, COUNT(id) as count").
|
Select(v.ColumnName+"_id as post_id, symbol, COUNT(id) as count").
|
||||||
Where(strings.ToLower(v.TypeName)+"_id IN (?)", idx).
|
Where(v.ColumnName+"_id IN (?)", idx).
|
||||||
Group("post_id, symbol").
|
Group("post_id, symbol").
|
||||||
Scan(&reactions).Error; err != nil {
|
Scan(&reactions).Error; err != nil {
|
||||||
return items, err
|
return items, err
|
||||||
}
|
}
|
||||||
|
|
||||||
itemMap := lo.SliceToMap(items, func(item T) (uint, T) {
|
itemMap := lo.SliceToMap(items, func(item *models.Feed) (uint, *models.Feed) {
|
||||||
return item.GetID(), item
|
return item.ID, item
|
||||||
})
|
})
|
||||||
|
|
||||||
list := map[uint]map[string]int64{}
|
list := map[uint]map[string]int64{}
|
||||||
@ -196,7 +170,7 @@ func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, e
|
|||||||
|
|
||||||
for k, v := range list {
|
for k, v := range list {
|
||||||
if post, ok := itemMap[k]; ok {
|
if post, ok := itemMap[k]; ok {
|
||||||
post.SetReactionList(v)
|
post.ReactionList = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,7 +178,7 @@ func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, e
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) MapCategoriesAndTags(item T) (T, error) {
|
func MapCategoriesAndTags[T models.PostInterface](item T) (T, error) {
|
||||||
var err error
|
var err error
|
||||||
categories := item.GetCategories()
|
categories := item.GetCategories()
|
||||||
for idx, category := range categories {
|
for idx, category := range categories {
|
||||||
@ -225,8 +199,8 @@ func (v *PostTypeContext[T]) MapCategoriesAndTags(item T) (T, error) {
|
|||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) New(item T) (T, error) {
|
func NewPost[T models.PostInterface](item T) (T, error) {
|
||||||
item, err := v.MapCategoriesAndTags(item)
|
item, err := MapCategoriesAndTags(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return item, err
|
return item, err
|
||||||
}
|
}
|
||||||
@ -294,8 +268,8 @@ func (v *PostTypeContext[T]) New(item T) (T, error) {
|
|||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) Edit(item T) (T, error) {
|
func EditPost[T models.PostInterface](item T) (T, error) {
|
||||||
item, err := v.MapCategoriesAndTags(item)
|
item, err := MapCategoriesAndTags(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return item, err
|
return item, err
|
||||||
}
|
}
|
||||||
@ -305,11 +279,11 @@ func (v *PostTypeContext[T]) Edit(item T) (T, error) {
|
|||||||
return item, err
|
return item, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) Delete(item T) error {
|
func DeletePost[T models.PostInterface](item T) error {
|
||||||
return database.C.Delete(&item).Error
|
return database.C.Delete(&item).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PostTypeContext[T]) React(reaction models.Reaction) (bool, models.Reaction, error) {
|
func (v *PostTypeContext) React(reaction models.Reaction) (bool, models.Reaction, error) {
|
||||||
if err := database.C.Where(reaction).First(&reaction).Error; err != nil {
|
if err := database.C.Where(reaction).First(&reaction).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return true, reaction, database.C.Save(&reaction).Error
|
return true, reaction, database.C.Save(&reaction).Error
|
||||||
|
@ -14,7 +14,7 @@ function parseContent(src: string): string {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.prose.prose-moment, p {
|
.prose.prose-moment p {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user