fix: issues

This commit is contained in:
Rogee
2025-01-14 19:48:23 +08:00
parent b429f30916
commit 48a0a6c195
14 changed files with 1037 additions and 195 deletions

View File

@@ -61,7 +61,7 @@ func (c *OrderController) List(ctx fiber.Ctx, claim *jwt.Claims, pagination *req
// Create order // Create order
// @Router /api/v1/orders [post] // @Router /api/v1/orders [post]
// @Bind claim local // @Bind claim local
// @Bind hash path // @Bind hash
// @Bind tenantSlug cookie key(tenant) // @Bind tenantSlug cookie key(tenant)
func (c *OrderController) Create(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash string) (*UserOrder, error) { func (c *OrderController) Create(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash string) (*UserOrder, error) {
user, err := c.userSvc.GetUserByID(ctx.Context(), claim.UserID) user, err := c.userSvc.GetUserByID(ctx.Context(), claim.UserID)

View File

@@ -1,6 +1,8 @@
package orders package orders
import ( import (
"fmt"
"backend/app/errorx" "backend/app/errorx"
"backend/app/http/posts" "backend/app/http/posts"
"backend/app/http/tenants" "backend/app/http/tenants"
@@ -10,7 +12,6 @@ import (
"backend/providers/jwt" "backend/providers/jwt"
"backend/providers/pay" "backend/providers/pay"
"github.com/go-pay/gopay/wechat/v3"
"github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3"
"github.com/samber/lo" "github.com/samber/lo"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -32,10 +33,11 @@ func (c *PayController) Prepare() error {
} }
// JSPay // JSPay
// @Router /api/v1/orders/pay/:orderID/js [get] // @Router /api/v1/orders/pay/:orderID/:channel [get]
// @Bind claim local // @Bind claim local
// @Bind orderID path // @Bind orderID path
func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string) (*wechat.JSAPIPayParams, error) { // @Bind channel path
func (ctl *PayController) Pay(ctx fiber.Ctx, claim *jwt.Claims, channel, orderID string) (any, error) {
order, err := ctl.svc.GetUserOrderByOrderID(ctx.Context(), orderID, claim.UserID) order, err := ctl.svc.GetUserOrderByOrderID(ctx.Context(), orderID, claim.UserID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -58,6 +60,15 @@ func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string
return nil, errorx.BadRequest.WithMsg("未绑定微信") return nil, errorx.BadRequest.WithMsg("未绑定微信")
} }
switch channel {
case "wechat-js":
return ctl.payWechatJS(ctx, order, &oauth)
}
return nil, errorx.BadRequest.WithMsg("支付渠道错误")
}
func (ctl *PayController) payWechatJS(ctx fiber.Ctx, order *model.Orders, oauth *model.UserOauths) (any, error) {
params, err := ctl.pay.WeChat_JSApiPayRequest( params, err := ctl.pay.WeChat_JSApiPayRequest(
ctx.Context(), ctx.Context(),
oauth.OpenID, oauth.OpenID,
@@ -65,7 +76,7 @@ func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string
order.Title, order.Title,
order.Amount, order.Amount,
1, 1,
"/v1/orders/pay/wechat/notify", ctl.getNotifyURL(ctx, "wechat"),
) )
if err != nil { if err != nil {
return nil, err return nil, err
@@ -73,3 +84,13 @@ func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string
return params, nil return params, nil
} }
func (ctl *PayController) getNotifyURL(ctx fiber.Ctx, channel string) string {
return fmt.Sprintf("%s://%s/v1/orders/pay/notify/%s", ctx.Request().URI().Scheme(), ctx.Host(), channel)
}
// @Router /v1/orders/pay/notify/:channel [post]
// @Bind channel path
func (c *PayController) Notify(ctx fiber.Ctx, channel string) (any, error) {
return nil, nil
}

View File

@@ -46,9 +46,10 @@ func (r *Routes) Register(router fiber.Router) {
)) ))
// 注册路由组: PayController // 注册路由组: PayController
router.Get("/api/v1/orders/pay/:orderID/js", DataFunc2( router.Get("/api/v1/orders/pay/:orderID/:channel", DataFunc3(
r.payController.JSPay, r.payController.Pay,
Local[*jwt.Claims]("claim"), Local[*jwt.Claims]("claim"),
PathParam[string]("channel"),
PathParam[string]("orderID"), PathParam[string]("orderID"),
)) ))

View File

@@ -1,8 +1,13 @@
package posts package posts
import ( import (
"time"
"backend/app/errorx"
"backend/app/http/tenants" "backend/app/http/tenants"
"backend/app/http/users"
"backend/app/requests" "backend/app/requests"
"backend/database/fields"
"backend/database/models/qvyun_v2/public/model" "backend/database/models/qvyun_v2/public/model"
"backend/providers/jwt" "backend/providers/jwt"
@@ -10,12 +15,15 @@ import (
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
"github.com/samber/lo" "github.com/samber/lo"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/speps/go-hashids/v2"
) )
// @provider // @provider
type Controller struct { type Controller struct {
tenantSvc *tenants.Service
svc *Service svc *Service
hashIds *hashids.HashID
userSvc *users.Service
tenantSvc *tenants.Service
log *log.Entry `inject:"false"` log *log.Entry `inject:"false"`
} }
@@ -109,7 +117,16 @@ func (c *Controller) Show(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash str
return nil, err return nil, err
} }
post, err := c.svc.GetPostByHash(ctx.Context(), tenant.ID, hash) postIds, err := c.hashIds.DecodeInt64WithError(hash)
if err != nil {
return nil, errorx.RecordNotExists
}
if tenant.ID != postIds[0] {
return nil, errorx.RecordNotExists
}
post, err := c.svc.GetPostByID(ctx.Context(), postIds[1])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -120,3 +137,40 @@ func (c *Controller) Show(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash str
return userPost, nil 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
}
post := &model.Posts{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
TenantID: tenant.ID,
UserID: user.ID,
Title: body.Title,
Description: body.Description,
Content: body.Content,
PosterAssetID: 0,
Stage: fields.PostStagePending,
Status: fields.PostStatusPending,
Price: body.Price,
Discount: body.Discount,
}
if err := ctl.svc.Create(ctx.Context(), tenant, user, post); err != nil {
return err
}
return nil
}

View File

@@ -30,3 +30,11 @@ type UserPostFilter struct {
CreatedAt *time.Time `query:"created_at"` CreatedAt *time.Time `query:"created_at"`
Keyword *string `json:"title"` Keyword *string `json:"title"`
} }
type PostBody struct {
Title string
Description string
Content string
Price int64
Discount int16
}

View File

@@ -13,6 +13,7 @@ import (
. "github.com/go-jet/jet/v2/postgres" . "github.com/go-jet/jet/v2/postgres"
"github.com/samber/lo" "github.com/samber/lo"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/speps/go-hashids/v2"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0" semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
) )
@@ -20,6 +21,7 @@ import (
// @provider:except // @provider:except
type Service struct { type Service struct {
db *sql.DB db *sql.DB
hashIds *hashids.HashID
log *log.Entry `inject:"false"` log *log.Entry `inject:"false"`
} }
@@ -163,22 +165,14 @@ func (svc *Service) GetPosts(ctx context.Context, pagination *requests.Paginatio
return posts, count.Cnt, nil return posts, count.Cnt, nil
} }
// GetPostByHash // GetPostByID
func (svc *Service) GetPostByHash(ctx context.Context, tenantID int64, hash string) (*model.Posts, error) { func (svc *Service) GetPostByID(ctx context.Context, id int64) (*model.Posts, error) {
_, span := otel.Start(ctx, "users.service.GetPostByHash") _, span := otel.Start(ctx, "users.service.GetPostByID")
defer span.End() defer span.End()
span.SetAttributes( span.SetAttributes(attribute.Int64("post.id", id))
attribute.String("hash", hash),
)
tbl := table.Posts tbl := table.Posts
stmt := tbl. stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.ID.EQ(Int64(id)))
SELECT(tbl.AllColumns).
WHERE(
tbl.Hash.EQ(String(hash)).AND(
tbl.TenantID.EQ(Int64(tenantID)),
),
)
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
var post model.Posts var post model.Posts
@@ -220,3 +214,40 @@ func (svc *Service) GetUserBoughtIDs(ctx context.Context, tenantID, userID int64
return item.PostID return item.PostID
}), nil }), nil
} }
// Create
func (svc *Service) Create(ctx context.Context, tenant *model.Tenants, user *model.Users, post *model.Posts) error {
_, span := otel.Start(ctx, "users.service.Create")
defer span.End()
tbl := table.Posts
stmt := tbl.INSERT(tbl.MutableColumns).MODEL(post)
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
if _, err := stmt.ExecContext(ctx, svc.db); err != nil {
return err
}
return nil
}
// GetPostByHash
func (svc *Service) GetPostByHash(ctx context.Context, tenantID int64, hash string) (*model.Posts, error) {
_, span := otel.Start(ctx, "users.service.GetPostByHash")
defer span.End()
span.SetAttributes(
attribute.Int64("tenant.id", tenantID),
attribute.String("hash", hash),
)
postIDs, err := svc.hashIds.DecodeInt64WithError(hash)
if err != nil {
return nil, err
}
if tenantID != postIDs[0] {
return nil, nil
}
return svc.GetPostByID(ctx, postIDs[1])
}

View File

@@ -0,0 +1,241 @@
// Code generated by go-enum DO NOT EDIT.
// Version: -
// Revision: -
// Build Date: -
// Built By: -
package fields
import (
"database/sql/driver"
"errors"
"fmt"
"strconv"
"strings"
)
const (
// UserStatusPending is a UserStatus of type Pending.
UserStatusPending UserStatus = iota
// UserStatusVerified is a UserStatus of type Verified.
UserStatusVerified
// UserStatusBlocked is a UserStatus of type Blocked.
UserStatusBlocked
)
var ErrInvalidUserStatus = fmt.Errorf("not a valid UserStatus, try [%s]", strings.Join(_UserStatusNames, ", "))
const _UserStatusName = "PendingVerifiedBlocked"
var _UserStatusNames = []string{
_UserStatusName[0:7],
_UserStatusName[7:15],
_UserStatusName[15:22],
}
// UserStatusNames returns a list of possible string values of UserStatus.
func UserStatusNames() []string {
tmp := make([]string, len(_UserStatusNames))
copy(tmp, _UserStatusNames)
return tmp
}
// UserStatusValues returns a list of the values for UserStatus
func UserStatusValues() []UserStatus {
return []UserStatus{
UserStatusPending,
UserStatusVerified,
UserStatusBlocked,
}
}
var _UserStatusMap = map[UserStatus]string{
UserStatusPending: _UserStatusName[0:7],
UserStatusVerified: _UserStatusName[7:15],
UserStatusBlocked: _UserStatusName[15:22],
}
// String implements the Stringer interface.
func (x UserStatus) String() string {
if str, ok := _UserStatusMap[x]; ok {
return str
}
return fmt.Sprintf("UserStatus(%d)", x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x UserStatus) IsValid() bool {
_, ok := _UserStatusMap[x]
return ok
}
var _UserStatusValue = map[string]UserStatus{
_UserStatusName[0:7]: UserStatusPending,
_UserStatusName[7:15]: UserStatusVerified,
_UserStatusName[15:22]: UserStatusBlocked,
}
// ParseUserStatus attempts to convert a string to a UserStatus.
func ParseUserStatus(name string) (UserStatus, error) {
if x, ok := _UserStatusValue[name]; ok {
return x, nil
}
return UserStatus(0), fmt.Errorf("%s is %w", name, ErrInvalidUserStatus)
}
var errUserStatusNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *UserStatus) Scan(value interface{}) (err error) {
if value == nil {
*x = UserStatus(0)
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case int64:
*x = UserStatus(v)
case string:
*x, err = ParseUserStatus(v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(v); verr == nil {
*x, err = UserStatus(val), nil
}
}
case []byte:
*x, err = ParseUserStatus(string(v))
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(string(v)); verr == nil {
*x, err = UserStatus(val), nil
}
}
case UserStatus:
*x = v
case int:
*x = UserStatus(v)
case *UserStatus:
if v == nil {
return errUserStatusNilPtr
}
*x = *v
case uint:
*x = UserStatus(v)
case uint64:
*x = UserStatus(v)
case *int:
if v == nil {
return errUserStatusNilPtr
}
*x = UserStatus(*v)
case *int64:
if v == nil {
return errUserStatusNilPtr
}
*x = UserStatus(*v)
case float64: // json marshals everything as a float64 if it's a number
*x = UserStatus(v)
case *float64: // json marshals everything as a float64 if it's a number
if v == nil {
return errUserStatusNilPtr
}
*x = UserStatus(*v)
case *uint:
if v == nil {
return errUserStatusNilPtr
}
*x = UserStatus(*v)
case *uint64:
if v == nil {
return errUserStatusNilPtr
}
*x = UserStatus(*v)
case *string:
if v == nil {
return errUserStatusNilPtr
}
*x, err = ParseUserStatus(*v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(*v); verr == nil {
*x, err = UserStatus(val), nil
}
}
}
return
}
// Value implements the driver Valuer interface.
func (x UserStatus) Value() (driver.Value, error) {
return int64(x), nil
}
// Set implements the Golang flag.Value interface func.
func (x *UserStatus) Set(val string) error {
v, err := ParseUserStatus(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *UserStatus) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *UserStatus) Type() string {
return "UserStatus"
}
type NullUserStatus struct {
UserStatus UserStatus
Valid bool
}
func NewNullUserStatus(val interface{}) (x NullUserStatus) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Scan implements the Scanner interface.
func (x *NullUserStatus) Scan(value interface{}) (err error) {
if value == nil {
x.UserStatus, x.Valid = UserStatus(0), false
return
}
err = x.UserStatus.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullUserStatus) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return int64(x.UserStatus), nil
}
type NullUserStatusStr struct {
NullUserStatus
}
func NewNullUserStatusStr(val interface{}) (x NullUserStatusStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullUserStatusStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.UserStatus.String(), nil
}

View File

@@ -0,0 +1,5 @@
package fields
// swagger:enum UserStatus
// ENUM( Pending, Verified, Blocked)
type UserStatus int16

View File

@@ -15,81 +15,87 @@ import (
) )
const ( const (
// UserStatusPending is a UserStatus of type Pending. // PostStagePending is a PostStage of type Pending.
UserStatusPending UserStatus = iota PostStagePending PostStage = iota
// UserStatusVerified is a UserStatus of type Verified. // PostStageProcessing is a PostStage of type Processing.
UserStatusVerified PostStageProcessing
// UserStatusBlocked is a UserStatus of type Blocked. // PostStageCompleted is a PostStage of type Completed.
UserStatusBlocked PostStageCompleted
// PostStageDeleted is a PostStage of type Deleted.
PostStageDeleted
) )
var ErrInvalidUserStatus = fmt.Errorf("not a valid UserStatus, try [%s]", strings.Join(_UserStatusNames, ", ")) var ErrInvalidPostStage = fmt.Errorf("not a valid PostStage, try [%s]", strings.Join(_PostStageNames, ", "))
const _UserStatusName = "PendingVerifiedBlocked" const _PostStageName = "PendingProcessingCompletedDeleted"
var _UserStatusNames = []string{ var _PostStageNames = []string{
_UserStatusName[0:7], _PostStageName[0:7],
_UserStatusName[7:15], _PostStageName[7:17],
_UserStatusName[15:22], _PostStageName[17:26],
_PostStageName[26:33],
} }
// UserStatusNames returns a list of possible string values of UserStatus. // PostStageNames returns a list of possible string values of PostStage.
func UserStatusNames() []string { func PostStageNames() []string {
tmp := make([]string, len(_UserStatusNames)) tmp := make([]string, len(_PostStageNames))
copy(tmp, _UserStatusNames) copy(tmp, _PostStageNames)
return tmp return tmp
} }
// UserStatusValues returns a list of the values for UserStatus // PostStageValues returns a list of the values for PostStage
func UserStatusValues() []UserStatus { func PostStageValues() []PostStage {
return []UserStatus{ return []PostStage{
UserStatusPending, PostStagePending,
UserStatusVerified, PostStageProcessing,
UserStatusBlocked, PostStageCompleted,
PostStageDeleted,
} }
} }
var _UserStatusMap = map[UserStatus]string{ var _PostStageMap = map[PostStage]string{
UserStatusPending: _UserStatusName[0:7], PostStagePending: _PostStageName[0:7],
UserStatusVerified: _UserStatusName[7:15], PostStageProcessing: _PostStageName[7:17],
UserStatusBlocked: _UserStatusName[15:22], PostStageCompleted: _PostStageName[17:26],
PostStageDeleted: _PostStageName[26:33],
} }
// String implements the Stringer interface. // String implements the Stringer interface.
func (x UserStatus) String() string { func (x PostStage) String() string {
if str, ok := _UserStatusMap[x]; ok { if str, ok := _PostStageMap[x]; ok {
return str return str
} }
return fmt.Sprintf("UserStatus(%d)", x) return fmt.Sprintf("PostStage(%d)", x)
} }
// IsValid provides a quick way to determine if the typed value is // IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values // part of the allowed enumerated values
func (x UserStatus) IsValid() bool { func (x PostStage) IsValid() bool {
_, ok := _UserStatusMap[x] _, ok := _PostStageMap[x]
return ok return ok
} }
var _UserStatusValue = map[string]UserStatus{ var _PostStageValue = map[string]PostStage{
_UserStatusName[0:7]: UserStatusPending, _PostStageName[0:7]: PostStagePending,
_UserStatusName[7:15]: UserStatusVerified, _PostStageName[7:17]: PostStageProcessing,
_UserStatusName[15:22]: UserStatusBlocked, _PostStageName[17:26]: PostStageCompleted,
_PostStageName[26:33]: PostStageDeleted,
} }
// ParseUserStatus attempts to convert a string to a UserStatus. // ParsePostStage attempts to convert a string to a PostStage.
func ParseUserStatus(name string) (UserStatus, error) { func ParsePostStage(name string) (PostStage, error) {
if x, ok := _UserStatusValue[name]; ok { if x, ok := _PostStageValue[name]; ok {
return x, nil return x, nil
} }
return UserStatus(0), fmt.Errorf("%s is %w", name, ErrInvalidUserStatus) return PostStage(0), fmt.Errorf("%s is %w", name, ErrInvalidPostStage)
} }
var errUserStatusNilPtr = errors.New("value pointer is nil") // one per type for package clashes var errPostStageNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface. // Scan implements the Scanner interface.
func (x *UserStatus) Scan(value interface{}) (err error) { func (x *PostStage) Scan(value interface{}) (err error) {
if value == nil { if value == nil {
*x = UserStatus(0) *x = PostStage(0)
return return
} }
@@ -97,72 +103,72 @@ func (x *UserStatus) Scan(value interface{}) (err error) {
// driver.Value values at the top of the list for expediency // driver.Value values at the top of the list for expediency
switch v := value.(type) { switch v := value.(type) {
case int64: case int64:
*x = UserStatus(v) *x = PostStage(v)
case string: case string:
*x, err = ParseUserStatus(v) *x, err = ParsePostStage(v)
if err != nil { if err != nil {
// try parsing the integer value as a string // try parsing the integer value as a string
if val, verr := strconv.Atoi(v); verr == nil { if val, verr := strconv.Atoi(v); verr == nil {
*x, err = UserStatus(val), nil *x, err = PostStage(val), nil
} }
} }
case []byte: case []byte:
*x, err = ParseUserStatus(string(v)) *x, err = ParsePostStage(string(v))
if err != nil { if err != nil {
// try parsing the integer value as a string // try parsing the integer value as a string
if val, verr := strconv.Atoi(string(v)); verr == nil { if val, verr := strconv.Atoi(string(v)); verr == nil {
*x, err = UserStatus(val), nil *x, err = PostStage(val), nil
} }
} }
case UserStatus: case PostStage:
*x = v *x = v
case int: case int:
*x = UserStatus(v) *x = PostStage(v)
case *UserStatus: case *PostStage:
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x = *v *x = *v
case uint: case uint:
*x = UserStatus(v) *x = PostStage(v)
case uint64: case uint64:
*x = UserStatus(v) *x = PostStage(v)
case *int: case *int:
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x = UserStatus(*v) *x = PostStage(*v)
case *int64: case *int64:
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x = UserStatus(*v) *x = PostStage(*v)
case float64: // json marshals everything as a float64 if it's a number case float64: // json marshals everything as a float64 if it's a number
*x = UserStatus(v) *x = PostStage(v)
case *float64: // json marshals everything as a float64 if it's a number case *float64: // json marshals everything as a float64 if it's a number
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x = UserStatus(*v) *x = PostStage(*v)
case *uint: case *uint:
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x = UserStatus(*v) *x = PostStage(*v)
case *uint64: case *uint64:
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x = UserStatus(*v) *x = PostStage(*v)
case *string: case *string:
if v == nil { if v == nil {
return errUserStatusNilPtr return errPostStageNilPtr
} }
*x, err = ParseUserStatus(*v) *x, err = ParsePostStage(*v)
if err != nil { if err != nil {
// try parsing the integer value as a string // try parsing the integer value as a string
if val, verr := strconv.Atoi(*v); verr == nil { if val, verr := strconv.Atoi(*v); verr == nil {
*x, err = UserStatus(val), nil *x, err = PostStage(val), nil
} }
} }
} }
@@ -171,71 +177,529 @@ func (x *UserStatus) Scan(value interface{}) (err error) {
} }
// Value implements the driver Valuer interface. // Value implements the driver Valuer interface.
func (x UserStatus) Value() (driver.Value, error) { func (x PostStage) Value() (driver.Value, error) {
return int64(x), nil return int64(x), nil
} }
// Set implements the Golang flag.Value interface func. // Set implements the Golang flag.Value interface func.
func (x *UserStatus) Set(val string) error { func (x *PostStage) Set(val string) error {
v, err := ParseUserStatus(val) v, err := ParsePostStage(val)
*x = v *x = v
return err return err
} }
// Get implements the Golang flag.Getter interface func. // Get implements the Golang flag.Getter interface func.
func (x *UserStatus) Get() interface{} { func (x *PostStage) Get() interface{} {
return *x return *x
} }
// Type implements the github.com/spf13/pFlag Value interface. // Type implements the github.com/spf13/pFlag Value interface.
func (x *UserStatus) Type() string { func (x *PostStage) Type() string {
return "UserStatus" return "PostStage"
} }
type NullUserStatus struct { type NullPostStage struct {
UserStatus UserStatus PostStage PostStage
Valid bool Valid bool
} }
func NewNullUserStatus(val interface{}) (x NullUserStatus) { func NewNullPostStage(val interface{}) (x NullPostStage) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value. x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return return
} }
// Scan implements the Scanner interface. // Scan implements the Scanner interface.
func (x *NullUserStatus) Scan(value interface{}) (err error) { func (x *NullPostStage) Scan(value interface{}) (err error) {
if value == nil { if value == nil {
x.UserStatus, x.Valid = UserStatus(0), false x.PostStage, x.Valid = PostStage(0), false
return return
} }
err = x.UserStatus.Scan(value) err = x.PostStage.Scan(value)
x.Valid = (err == nil) x.Valid = (err == nil)
return return
} }
// Value implements the driver Valuer interface. // Value implements the driver Valuer interface.
func (x NullUserStatus) Value() (driver.Value, error) { func (x NullPostStage) Value() (driver.Value, error) {
if !x.Valid { if !x.Valid {
return nil, nil return nil, nil
} }
// driver.Value accepts int64 for int values. // driver.Value accepts int64 for int values.
return int64(x.UserStatus), nil return int64(x.PostStage), nil
} }
type NullUserStatusStr struct { type NullPostStageStr struct {
NullUserStatus NullPostStage
} }
func NewNullUserStatusStr(val interface{}) (x NullUserStatusStr) { func NewNullPostStageStr(val interface{}) (x NullPostStageStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value. x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return return
} }
// Value implements the driver Valuer interface. // Value implements the driver Valuer interface.
func (x NullUserStatusStr) Value() (driver.Value, error) { func (x NullPostStageStr) Value() (driver.Value, error) {
if !x.Valid { if !x.Valid {
return nil, nil return nil, nil
} }
return x.UserStatus.String(), nil return x.PostStage.String(), nil
}
const (
// PostStatusPending is a PostStatus of type Pending.
PostStatusPending PostStatus = iota
// PostStatusVerified is a PostStatus of type Verified.
PostStatusVerified
// PostStatusBlocked is a PostStatus of type Blocked.
PostStatusBlocked
)
var ErrInvalidPostStatus = fmt.Errorf("not a valid PostStatus, try [%s]", strings.Join(_PostStatusNames, ", "))
const _PostStatusName = "PendingVerifiedBlocked"
var _PostStatusNames = []string{
_PostStatusName[0:7],
_PostStatusName[7:15],
_PostStatusName[15:22],
}
// PostStatusNames returns a list of possible string values of PostStatus.
func PostStatusNames() []string {
tmp := make([]string, len(_PostStatusNames))
copy(tmp, _PostStatusNames)
return tmp
}
// PostStatusValues returns a list of the values for PostStatus
func PostStatusValues() []PostStatus {
return []PostStatus{
PostStatusPending,
PostStatusVerified,
PostStatusBlocked,
}
}
var _PostStatusMap = map[PostStatus]string{
PostStatusPending: _PostStatusName[0:7],
PostStatusVerified: _PostStatusName[7:15],
PostStatusBlocked: _PostStatusName[15:22],
}
// String implements the Stringer interface.
func (x PostStatus) String() string {
if str, ok := _PostStatusMap[x]; ok {
return str
}
return fmt.Sprintf("PostStatus(%d)", x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x PostStatus) IsValid() bool {
_, ok := _PostStatusMap[x]
return ok
}
var _PostStatusValue = map[string]PostStatus{
_PostStatusName[0:7]: PostStatusPending,
_PostStatusName[7:15]: PostStatusVerified,
_PostStatusName[15:22]: PostStatusBlocked,
}
// ParsePostStatus attempts to convert a string to a PostStatus.
func ParsePostStatus(name string) (PostStatus, error) {
if x, ok := _PostStatusValue[name]; ok {
return x, nil
}
return PostStatus(0), fmt.Errorf("%s is %w", name, ErrInvalidPostStatus)
}
var errPostStatusNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *PostStatus) Scan(value interface{}) (err error) {
if value == nil {
*x = PostStatus(0)
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case int64:
*x = PostStatus(v)
case string:
*x, err = ParsePostStatus(v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(v); verr == nil {
*x, err = PostStatus(val), nil
}
}
case []byte:
*x, err = ParsePostStatus(string(v))
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(string(v)); verr == nil {
*x, err = PostStatus(val), nil
}
}
case PostStatus:
*x = v
case int:
*x = PostStatus(v)
case *PostStatus:
if v == nil {
return errPostStatusNilPtr
}
*x = *v
case uint:
*x = PostStatus(v)
case uint64:
*x = PostStatus(v)
case *int:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *int64:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case float64: // json marshals everything as a float64 if it's a number
*x = PostStatus(v)
case *float64: // json marshals everything as a float64 if it's a number
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *uint:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *uint64:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *string:
if v == nil {
return errPostStatusNilPtr
}
*x, err = ParsePostStatus(*v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(*v); verr == nil {
*x, err = PostStatus(val), nil
}
}
}
return
}
// Value implements the driver Valuer interface.
func (x PostStatus) Value() (driver.Value, error) {
return int64(x), nil
}
// Set implements the Golang flag.Value interface func.
func (x *PostStatus) Set(val string) error {
v, err := ParsePostStatus(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *PostStatus) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *PostStatus) Type() string {
return "PostStatus"
}
type NullPostStatus struct {
PostStatus PostStatus
Valid bool
}
func NewNullPostStatus(val interface{}) (x NullPostStatus) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Scan implements the Scanner interface.
func (x *NullPostStatus) Scan(value interface{}) (err error) {
if value == nil {
x.PostStatus, x.Valid = PostStatus(0), false
return
}
err = x.PostStatus.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullPostStatus) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return int64(x.PostStatus), nil
}
type NullPostStatusStr struct {
NullPostStatus
}
func NewNullPostStatusStr(val interface{}) (x NullPostStatusStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullPostStatusStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.PostStatus.String(), nil
}
const (
// PostTypeArticle is a PostType of type Article.
PostTypeArticle PostType = iota
// PostTypePicture is a PostType of type Picture.
PostTypePicture
// PostTypeVideo is a PostType of type Video.
PostTypeVideo
// PostTypeAudio is a PostType of type Audio.
PostTypeAudio
)
var ErrInvalidPostType = fmt.Errorf("not a valid PostType, try [%s]", strings.Join(_PostTypeNames, ", "))
const _PostTypeName = "ArticlePictureVideoAudio"
var _PostTypeNames = []string{
_PostTypeName[0:7],
_PostTypeName[7:14],
_PostTypeName[14:19],
_PostTypeName[19:24],
}
// PostTypeNames returns a list of possible string values of PostType.
func PostTypeNames() []string {
tmp := make([]string, len(_PostTypeNames))
copy(tmp, _PostTypeNames)
return tmp
}
// PostTypeValues returns a list of the values for PostType
func PostTypeValues() []PostType {
return []PostType{
PostTypeArticle,
PostTypePicture,
PostTypeVideo,
PostTypeAudio,
}
}
var _PostTypeMap = map[PostType]string{
PostTypeArticle: _PostTypeName[0:7],
PostTypePicture: _PostTypeName[7:14],
PostTypeVideo: _PostTypeName[14:19],
PostTypeAudio: _PostTypeName[19:24],
}
// String implements the Stringer interface.
func (x PostType) String() string {
if str, ok := _PostTypeMap[x]; ok {
return str
}
return fmt.Sprintf("PostType(%d)", x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x PostType) IsValid() bool {
_, ok := _PostTypeMap[x]
return ok
}
var _PostTypeValue = map[string]PostType{
_PostTypeName[0:7]: PostTypeArticle,
_PostTypeName[7:14]: PostTypePicture,
_PostTypeName[14:19]: PostTypeVideo,
_PostTypeName[19:24]: PostTypeAudio,
}
// ParsePostType attempts to convert a string to a PostType.
func ParsePostType(name string) (PostType, error) {
if x, ok := _PostTypeValue[name]; ok {
return x, nil
}
return PostType(0), fmt.Errorf("%s is %w", name, ErrInvalidPostType)
}
var errPostTypeNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *PostType) Scan(value interface{}) (err error) {
if value == nil {
*x = PostType(0)
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case int64:
*x = PostType(v)
case string:
*x, err = ParsePostType(v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(v); verr == nil {
*x, err = PostType(val), nil
}
}
case []byte:
*x, err = ParsePostType(string(v))
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(string(v)); verr == nil {
*x, err = PostType(val), nil
}
}
case PostType:
*x = v
case int:
*x = PostType(v)
case *PostType:
if v == nil {
return errPostTypeNilPtr
}
*x = *v
case uint:
*x = PostType(v)
case uint64:
*x = PostType(v)
case *int:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *int64:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case float64: // json marshals everything as a float64 if it's a number
*x = PostType(v)
case *float64: // json marshals everything as a float64 if it's a number
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *uint:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *uint64:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *string:
if v == nil {
return errPostTypeNilPtr
}
*x, err = ParsePostType(*v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(*v); verr == nil {
*x, err = PostType(val), nil
}
}
}
return
}
// Value implements the driver Valuer interface.
func (x PostType) Value() (driver.Value, error) {
return int64(x), nil
}
// Set implements the Golang flag.Value interface func.
func (x *PostType) Set(val string) error {
v, err := ParsePostType(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *PostType) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *PostType) Type() string {
return "PostType"
}
type NullPostType struct {
PostType PostType
Valid bool
}
func NewNullPostType(val interface{}) (x NullPostType) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Scan implements the Scanner interface.
func (x *NullPostType) Scan(value interface{}) (err error) {
if value == nil {
x.PostType, x.Valid = PostType(0), false
return
}
err = x.PostType.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullPostType) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return int64(x.PostType), nil
}
type NullPostTypeStr struct {
NullPostType
}
func NewNullPostTypeStr(val interface{}) (x NullPostTypeStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullPostTypeStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.PostType.String(), nil
} }

View File

@@ -1,5 +1,13 @@
package fields package fields
// swagger:enum UserStatus // swagger:enum PostStage
// ENUM( Pending, Processing, Completed, Deleted)
type PostStage int16
// swagger:enum PostStatus
// ENUM( Pending, Verified, Blocked) // ENUM( Pending, Verified, Blocked)
type UserStatus int16 type PostStatus int16
// swagger:enum PostType
// ENUM( Article, Picture, Video, Audio)
type PostType int16

View File

@@ -8,16 +8,17 @@ CREATE TABLE
updated_at timestamp NOT NULL default now(), updated_at timestamp NOT NULL default now(),
deleted_at timestamp, deleted_at timestamp,
type INT2 NOT NULL default 0,
stage INT2 NOT NULL default 0,
status INT2 NOT NULL default 0,
tenant_id INT8 NOT NULL, tenant_id INT8 NOT NULL,
user_id INT8 NOT NULL, user_id INT8 NOT NULL,
hash VARCHAR(128) NOT NULL UNIQUE,
title VARCHAR(128) NOT NULL, title VARCHAR(128) NOT NULL,
description VARCHAR(256) NOT NULL, description VARCHAR(256) NOT NULL,
poster VARCHAR(128) NOT NULL, poster_asset_id INT8 NOT NULL,
content TEXT NOT NULL, content TEXT NOT NULL,
stage INT2 NOT NULL default 0,
status INT2 NOT NULL default 0,
price INT8 NOT NULL default 0, price INT8 NOT NULL default 0,
discount INT2 NOT NULL default 100, discount INT2 NOT NULL default 100,
views INT8 NOT NULL default 0, views INT8 NOT NULL default 0,
@@ -26,6 +27,7 @@ CREATE TABLE
assets jsonb default '{}'::jsonb assets jsonb default '{}'::jsonb
); );
-- create indexes -- create indexes
CREATE INDEX posts_type_index ON posts (type);
CREATE INDEX posts_tenant_id_index ON posts (tenant_id); CREATE INDEX posts_tenant_id_index ON posts (tenant_id);
CREATE INDEX posts_user_id_index ON posts (user_id); CREATE INDEX posts_user_id_index ON posts (user_id);
CREATE INDEX posts_title_index ON posts (title); CREATE INDEX posts_title_index ON posts (title);
@@ -55,4 +57,5 @@ CREATE INDEX user_bought_posts_post_id_index ON user_bought_posts (post_id);
-- +goose Down -- +goose Down
-- +goose StatementBegin -- +goose StatementBegin
DROP TABLE posts; DROP TABLE posts;
DROP TABLE user_bought_posts;
-- +goose StatementEnd -- +goose StatementEnd

View File

@@ -8,6 +8,7 @@
package model package model
import ( import (
"backend/database/fields"
"time" "time"
) )
@@ -16,15 +17,15 @@ type Posts struct {
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"` DeletedAt *time.Time `json:"deleted_at"`
Type fields.PostType `json:"type"`
Stage fields.PostStage `json:"stage"`
Status fields.PostStatus `json:"status"`
TenantID int64 `json:"tenant_id"` TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
Hash string `json:"hash"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Poster string `json:"poster"` PosterAssetID int64 `json:"poster_asset_id"`
Content string `json:"content"` Content string `json:"content"`
Stage int16 `json:"stage"`
Status int16 `json:"status"`
Price int64 `json:"price"` Price int64 `json:"price"`
Discount int16 `json:"discount"` Discount int16 `json:"discount"`
Views int64 `json:"views"` Views int64 `json:"views"`

View File

@@ -21,15 +21,15 @@ type postsTable struct {
CreatedAt postgres.ColumnTimestamp CreatedAt postgres.ColumnTimestamp
UpdatedAt postgres.ColumnTimestamp UpdatedAt postgres.ColumnTimestamp
DeletedAt postgres.ColumnTimestamp DeletedAt postgres.ColumnTimestamp
TenantID postgres.ColumnInteger Type postgres.ColumnInteger
UserID postgres.ColumnInteger
Hash postgres.ColumnString
Title postgres.ColumnString
Description postgres.ColumnString
Poster postgres.ColumnString
Content postgres.ColumnString
Stage postgres.ColumnInteger Stage postgres.ColumnInteger
Status postgres.ColumnInteger Status postgres.ColumnInteger
TenantID postgres.ColumnInteger
UserID postgres.ColumnInteger
Title postgres.ColumnString
Description postgres.ColumnString
PosterAssetID postgres.ColumnInteger
Content postgres.ColumnString
Price postgres.ColumnInteger Price postgres.ColumnInteger
Discount postgres.ColumnInteger Discount postgres.ColumnInteger
Views postgres.ColumnInteger Views postgres.ColumnInteger
@@ -80,23 +80,23 @@ func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
CreatedAtColumn = postgres.TimestampColumn("created_at") CreatedAtColumn = postgres.TimestampColumn("created_at")
UpdatedAtColumn = postgres.TimestampColumn("updated_at") UpdatedAtColumn = postgres.TimestampColumn("updated_at")
DeletedAtColumn = postgres.TimestampColumn("deleted_at") DeletedAtColumn = postgres.TimestampColumn("deleted_at")
TenantIDColumn = postgres.IntegerColumn("tenant_id") TypeColumn = postgres.IntegerColumn("type")
UserIDColumn = postgres.IntegerColumn("user_id")
HashColumn = postgres.StringColumn("hash")
TitleColumn = postgres.StringColumn("title")
DescriptionColumn = postgres.StringColumn("description")
PosterColumn = postgres.StringColumn("poster")
ContentColumn = postgres.StringColumn("content")
StageColumn = postgres.IntegerColumn("stage") StageColumn = postgres.IntegerColumn("stage")
StatusColumn = postgres.IntegerColumn("status") StatusColumn = postgres.IntegerColumn("status")
TenantIDColumn = postgres.IntegerColumn("tenant_id")
UserIDColumn = postgres.IntegerColumn("user_id")
TitleColumn = postgres.StringColumn("title")
DescriptionColumn = postgres.StringColumn("description")
PosterAssetIDColumn = postgres.IntegerColumn("poster_asset_id")
ContentColumn = postgres.StringColumn("content")
PriceColumn = postgres.IntegerColumn("price") PriceColumn = postgres.IntegerColumn("price")
DiscountColumn = postgres.IntegerColumn("discount") DiscountColumn = postgres.IntegerColumn("discount")
ViewsColumn = postgres.IntegerColumn("views") ViewsColumn = postgres.IntegerColumn("views")
LikesColumn = postgres.IntegerColumn("likes") LikesColumn = postgres.IntegerColumn("likes")
MetaColumn = postgres.StringColumn("meta") MetaColumn = postgres.StringColumn("meta")
AssetsColumn = postgres.StringColumn("assets") AssetsColumn = postgres.StringColumn("assets")
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, TenantIDColumn, UserIDColumn, HashColumn, TitleColumn, DescriptionColumn, PosterColumn, ContentColumn, StageColumn, StatusColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, MetaColumn, AssetsColumn} allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, TypeColumn, StageColumn, StatusColumn, TenantIDColumn, UserIDColumn, TitleColumn, DescriptionColumn, PosterAssetIDColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, MetaColumn, AssetsColumn}
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, TenantIDColumn, UserIDColumn, HashColumn, TitleColumn, DescriptionColumn, PosterColumn, ContentColumn, StageColumn, StatusColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, MetaColumn, AssetsColumn} mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, TypeColumn, StageColumn, StatusColumn, TenantIDColumn, UserIDColumn, TitleColumn, DescriptionColumn, PosterAssetIDColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, MetaColumn, AssetsColumn}
) )
return postsTable{ return postsTable{
@@ -107,15 +107,15 @@ func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
CreatedAt: CreatedAtColumn, CreatedAt: CreatedAtColumn,
UpdatedAt: UpdatedAtColumn, UpdatedAt: UpdatedAtColumn,
DeletedAt: DeletedAtColumn, DeletedAt: DeletedAtColumn,
TenantID: TenantIDColumn, Type: TypeColumn,
UserID: UserIDColumn,
Hash: HashColumn,
Title: TitleColumn,
Description: DescriptionColumn,
Poster: PosterColumn,
Content: ContentColumn,
Stage: StageColumn, Stage: StageColumn,
Status: StatusColumn, Status: StatusColumn,
TenantID: TenantIDColumn,
UserID: UserIDColumn,
Title: TitleColumn,
Description: DescriptionColumn,
PosterAssetID: PosterAssetIDColumn,
Content: ContentColumn,
Price: PriceColumn, Price: PriceColumn,
Discount: DiscountColumn, Discount: DiscountColumn,
Views: ViewsColumn, Views: ViewsColumn,

View File

@@ -15,6 +15,11 @@ types:
storages: storages:
type: StorageType type: StorageType
posts:
stage: PostStage
status: PostStatus
type: PostType
orders: orders:
type: OrderType type: OrderType
status: OrderStatus status: OrderStatus