253 lines
6.0 KiB
Go
253 lines
6.0 KiB
Go
package posts
|
|
|
|
import (
|
|
"time"
|
|
|
|
"backend/app/errorx"
|
|
"backend/app/events/publishers"
|
|
"backend/app/http/medias"
|
|
"backend/app/http/tenants"
|
|
"backend/app/http/users"
|
|
"backend/app/requests"
|
|
"backend/database/fields"
|
|
"backend/database/models/qvyun_v2/public/model"
|
|
"backend/providers/event"
|
|
"backend/providers/hashids"
|
|
"backend/providers/jwt"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"github.com/jinzhu/copier"
|
|
"github.com/samber/lo"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// @provider
|
|
type Controller struct {
|
|
event *event.PubSub
|
|
|
|
svc *Service
|
|
hashId *hashids.Hasher
|
|
userSvc *users.Service
|
|
tenantSvc *tenants.Service
|
|
mediaSvc *medias.Service
|
|
log *log.Entry `inject:"false"`
|
|
}
|
|
|
|
func (c *Controller) Prepare() error {
|
|
c.log = log.WithField("module", "posts.Controller")
|
|
return nil
|
|
}
|
|
|
|
// List show posts list
|
|
// @Router /api/v1/posts [get]
|
|
// @Bind claim local
|
|
// @Bind pagination query
|
|
// @Bind filter query
|
|
func (c *Controller) List(ctx fiber.Ctx, claim *jwt.Claims, pagination *requests.Pagination, filter *UserPostFilter) (*requests.Pager, error) {
|
|
pagination.Format()
|
|
pager := &requests.Pager{
|
|
Pagination: *pagination,
|
|
}
|
|
|
|
filter.TenantID = *claim.TenantID
|
|
filter.UserID = claim.UserID
|
|
orders, total, err := c.svc.GetPosts(ctx.Context(), pagination, filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pager.Total = total
|
|
|
|
pager.Items = lo.FilterMap(orders, func(item model.Posts, _ int) (UserPost, bool) {
|
|
var o UserPost
|
|
if err := copier.Copy(&o, item); err != nil {
|
|
return o, false
|
|
}
|
|
return o, true
|
|
})
|
|
|
|
return pager, nil
|
|
}
|
|
|
|
// ListBought show user bought posts list
|
|
// @Router /api/v1/bought-posts [get]
|
|
// @Bind claim local
|
|
// @Bind pagination query
|
|
// @Bind filter query
|
|
func (c *Controller) ListBought(ctx fiber.Ctx, claim *jwt.Claims, pagination *requests.Pagination, filter *UserPostFilter) (*requests.Pager, error) {
|
|
pagination.Format()
|
|
pager := &requests.Pager{
|
|
Pagination: *pagination,
|
|
}
|
|
|
|
filter.TenantID = *claim.TenantID
|
|
filter.UserID = claim.UserID
|
|
orders, total, err := c.svc.GetBoughtPosts(ctx.Context(), pagination, filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pager.Total = total
|
|
|
|
pager.Items = lo.FilterMap(orders, func(item model.Posts, _ int) (UserPost, bool) {
|
|
var o UserPost
|
|
if err := copier.Copy(&o, item); err != nil {
|
|
return o, false
|
|
}
|
|
return o, true
|
|
})
|
|
|
|
return pager, nil
|
|
}
|
|
|
|
// Show show posts detail
|
|
// @Router /api/v1/show/:hash [get]
|
|
// @Bind claim local
|
|
// @Bind hash path
|
|
func (c *Controller) Show(ctx fiber.Ctx, claim *jwt.Claims, hash string) (*UserPost, error) {
|
|
userPost := &UserPost{}
|
|
|
|
postId, err := c.hashId.DecodeOnlyInt64(hash)
|
|
if err != nil {
|
|
return nil, errorx.RecordNotExists
|
|
}
|
|
|
|
post, err := c.svc.GetPostByID(ctx.Context(), postId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := copier.Copy(userPost, post); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return userPost, nil
|
|
}
|
|
|
|
// @Router /api/v1/posts [post]
|
|
// @Bind claim local
|
|
// @Bind tenantSlug cookie key(tenant)
|
|
// @Bind body body
|
|
func (ctl *Controller) Create(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug string, body *PostBody) error {
|
|
user, err := ctl.userSvc.GetUserByID(ctx.Context(), claim.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tenant, err := ctl.tenantSvc.GetTenantBySlug(ctx.Context(), tenantSlug)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// check media assets exists
|
|
ids := lo.Map(body.Assets.Data, func(item fields.MediaAsset, _ int) int64 { return item.Media })
|
|
medias, err := ctl.mediaSvc.GetMediasByIDs(ctx.Context(), tenant.ID, user.ID, ids)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(medias) != len(lo.Uniq(ids)) {
|
|
return errorx.BadRequest
|
|
}
|
|
|
|
post := &model.Posts{
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
TenantID: tenant.ID,
|
|
UserID: user.ID,
|
|
Title: body.Title,
|
|
Description: body.Description,
|
|
Content: body.Content,
|
|
Price: body.Price,
|
|
Discount: body.Discount,
|
|
Assets: body.Assets,
|
|
Tags: body.Tags,
|
|
|
|
Stage: fields.PostStagePending,
|
|
Status: fields.PostStatusPending,
|
|
}
|
|
|
|
if err := ctl.svc.Create(ctx.Context(), tenant, user, post); err != nil {
|
|
return err
|
|
}
|
|
|
|
_ = ctl.event.Publish(&publishers.PostCreated{ID: post.ID})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Delete
|
|
// @Router /api/v1/posts/:hash [delete]
|
|
// @Bind claim local
|
|
// @Bind tenantSlug cookie key(tenant)
|
|
// @Bind hash path
|
|
func (c *Controller) Delete(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash string) error {
|
|
tenant, err := c.tenantSvc.GetTenantBySlug(ctx.Context(), tenantSlug)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
postId, err := c.hashId.DecodeOnlyInt64(hash)
|
|
if err != nil {
|
|
return errorx.RecordNotExists
|
|
}
|
|
|
|
if err := c.svc.Delete(ctx.Context(), tenant.ID, *&claim.UserID, postId); err != nil {
|
|
return err
|
|
}
|
|
|
|
// trigger event
|
|
_ = c.event.Publish(&publishers.PostDeleted{ID: postId})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Update
|
|
// @Router /api/v1/posts/:hash [put]
|
|
// @Bind claim local
|
|
// @Bind tenantSlug cookie key(tenant)
|
|
// @Bind hash path
|
|
// @Bind body body
|
|
func (ctl *Controller) Update(ctx fiber.Ctx, claim *jwt.Claims, hash string, body *PostBody) error {
|
|
postId, err := ctl.hashId.DecodeOnlyInt64(hash)
|
|
if err != nil {
|
|
return errorx.RecordNotExists
|
|
}
|
|
|
|
post, err := ctl.svc.GetPostByID(ctx.Context(), postId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// check media assets exists
|
|
ids := lo.Map(body.Assets.Data, func(item fields.MediaAsset, _ int) int64 { return item.Media })
|
|
medias, err := ctl.mediaSvc.GetMediasByIDs(ctx.Context(), *claim.TenantID, post.UserID, ids)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(medias) != len(lo.Uniq(ids)) {
|
|
return errorx.BadRequest
|
|
}
|
|
|
|
_ = ctl.event.Publish(&publishers.PostUpdatedEvent{ID: postId})
|
|
|
|
m := &model.Posts{
|
|
UpdatedAt: time.Now(),
|
|
Title: body.Title,
|
|
Description: body.Description,
|
|
Content: body.Content,
|
|
Price: body.Price,
|
|
Discount: body.Discount,
|
|
Assets: body.Assets,
|
|
Tags: body.Tags,
|
|
|
|
Stage: fields.PostStagePending,
|
|
Status: fields.PostStatusPending,
|
|
}
|
|
|
|
if err := ctl.svc.Update(ctx.Context(), post.TenantID, post.UserID, post.ID, m); err != nil {
|
|
return err
|
|
}
|
|
// todo: trigger event post updated
|
|
return nil
|
|
}
|