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
// @Router /api/v1/orders [post]
// @Bind claim local
// @Bind hash path
// @Bind hash
// @Bind tenantSlug cookie key(tenant)
func (c *OrderController) Create(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash string) (*UserOrder, error) {
user, err := c.userSvc.GetUserByID(ctx.Context(), claim.UserID)

View File

@@ -1,6 +1,8 @@
package orders
import (
"fmt"
"backend/app/errorx"
"backend/app/http/posts"
"backend/app/http/tenants"
@@ -10,7 +12,6 @@ import (
"backend/providers/jwt"
"backend/providers/pay"
"github.com/go-pay/gopay/wechat/v3"
"github.com/gofiber/fiber/v3"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
@@ -32,10 +33,11 @@ func (c *PayController) Prepare() error {
}
// JSPay
// @Router /api/v1/orders/pay/:orderID/js [get]
// @Router /api/v1/orders/pay/:orderID/:channel [get]
// @Bind claim local
// @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)
if err != nil {
return nil, err
@@ -58,6 +60,15 @@ func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string
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(
ctx.Context(),
oauth.OpenID,
@@ -65,7 +76,7 @@ func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string
order.Title,
order.Amount,
1,
"/v1/orders/pay/wechat/notify",
ctl.getNotifyURL(ctx, "wechat"),
)
if err != nil {
return nil, err
@@ -73,3 +84,13 @@ func (ctl *PayController) JSPay(ctx fiber.Ctx, claim *jwt.Claims, orderID string
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
router.Get("/api/v1/orders/pay/:orderID/js", DataFunc2(
r.payController.JSPay,
router.Get("/api/v1/orders/pay/:orderID/:channel", DataFunc3(
r.payController.Pay,
Local[*jwt.Claims]("claim"),
PathParam[string]("channel"),
PathParam[string]("orderID"),
))

View File

@@ -1,8 +1,13 @@
package posts
import (
"time"
"backend/app/errorx"
"backend/app/http/tenants"
"backend/app/http/users"
"backend/app/requests"
"backend/database/fields"
"backend/database/models/qvyun_v2/public/model"
"backend/providers/jwt"
@@ -10,12 +15,15 @@ import (
"github.com/jinzhu/copier"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
"github.com/speps/go-hashids/v2"
)
// @provider
type Controller struct {
tenantSvc *tenants.Service
svc *Service
hashIds *hashids.HashID
userSvc *users.Service
tenantSvc *tenants.Service
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
}
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 {
return nil, err
}
@@ -120,3 +137,40 @@ func (c *Controller) Show(ctx fiber.Ctx, claim *jwt.Claims, tenantSlug, hash str
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"`
Keyword *string `json:"title"`
}
type PostBody struct {
Title string
Description string
Content string
Price int64
Discount int16
}

View File

@@ -13,14 +13,16 @@ import (
. "github.com/go-jet/jet/v2/postgres"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
"github.com/speps/go-hashids/v2"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
// @provider:except
type Service struct {
db *sql.DB
log *log.Entry `inject:"false"`
db *sql.DB
hashIds *hashids.HashID
log *log.Entry `inject:"false"`
}
func (svc *Service) Prepare() error {
@@ -163,22 +165,14 @@ func (svc *Service) GetPosts(ctx context.Context, pagination *requests.Paginatio
return posts, count.Cnt, nil
}
// GetPostByHash
func (svc *Service) GetPostByHash(ctx context.Context, tenantID int64, hash string) (*model.Posts, error) {
_, span := otel.Start(ctx, "users.service.GetPostByHash")
// GetPostByID
func (svc *Service) GetPostByID(ctx context.Context, id int64) (*model.Posts, error) {
_, span := otel.Start(ctx, "users.service.GetPostByID")
defer span.End()
span.SetAttributes(
attribute.String("hash", hash),
)
span.SetAttributes(attribute.Int64("post.id", id))
tbl := table.Posts
stmt := tbl.
SELECT(tbl.AllColumns).
WHERE(
tbl.Hash.EQ(String(hash)).AND(
tbl.TenantID.EQ(Int64(tenantID)),
),
)
stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.ID.EQ(Int64(id)))
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
var post model.Posts
@@ -220,3 +214,40 @@ func (svc *Service) GetUserBoughtIDs(ctx context.Context, tenantID, userID int64
return item.PostID
}), 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 (
// 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
// PostStagePending is a PostStage of type Pending.
PostStagePending PostStage = iota
// PostStageProcessing is a PostStage of type Processing.
PostStageProcessing
// PostStageCompleted is a PostStage of type Completed.
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{
_UserStatusName[0:7],
_UserStatusName[7:15],
_UserStatusName[15:22],
var _PostStageNames = []string{
_PostStageName[0:7],
_PostStageName[7:17],
_PostStageName[17:26],
_PostStageName[26:33],
}
// UserStatusNames returns a list of possible string values of UserStatus.
func UserStatusNames() []string {
tmp := make([]string, len(_UserStatusNames))
copy(tmp, _UserStatusNames)
// PostStageNames returns a list of possible string values of PostStage.
func PostStageNames() []string {
tmp := make([]string, len(_PostStageNames))
copy(tmp, _PostStageNames)
return tmp
}
// UserStatusValues returns a list of the values for UserStatus
func UserStatusValues() []UserStatus {
return []UserStatus{
UserStatusPending,
UserStatusVerified,
UserStatusBlocked,
// PostStageValues returns a list of the values for PostStage
func PostStageValues() []PostStage {
return []PostStage{
PostStagePending,
PostStageProcessing,
PostStageCompleted,
PostStageDeleted,
}
}
var _UserStatusMap = map[UserStatus]string{
UserStatusPending: _UserStatusName[0:7],
UserStatusVerified: _UserStatusName[7:15],
UserStatusBlocked: _UserStatusName[15:22],
var _PostStageMap = map[PostStage]string{
PostStagePending: _PostStageName[0:7],
PostStageProcessing: _PostStageName[7:17],
PostStageCompleted: _PostStageName[17:26],
PostStageDeleted: _PostStageName[26:33],
}
// String implements the Stringer interface.
func (x UserStatus) String() string {
if str, ok := _UserStatusMap[x]; ok {
func (x PostStage) String() string {
if str, ok := _PostStageMap[x]; ok {
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
// part of the allowed enumerated values
func (x UserStatus) IsValid() bool {
_, ok := _UserStatusMap[x]
func (x PostStage) IsValid() bool {
_, ok := _PostStageMap[x]
return ok
}
var _UserStatusValue = map[string]UserStatus{
_UserStatusName[0:7]: UserStatusPending,
_UserStatusName[7:15]: UserStatusVerified,
_UserStatusName[15:22]: UserStatusBlocked,
var _PostStageValue = map[string]PostStage{
_PostStageName[0:7]: PostStagePending,
_PostStageName[7:17]: PostStageProcessing,
_PostStageName[17:26]: PostStageCompleted,
_PostStageName[26:33]: PostStageDeleted,
}
// ParseUserStatus attempts to convert a string to a UserStatus.
func ParseUserStatus(name string) (UserStatus, error) {
if x, ok := _UserStatusValue[name]; ok {
// ParsePostStage attempts to convert a string to a PostStage.
func ParsePostStage(name string) (PostStage, error) {
if x, ok := _PostStageValue[name]; ok {
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.
func (x *UserStatus) Scan(value interface{}) (err error) {
func (x *PostStage) Scan(value interface{}) (err error) {
if value == nil {
*x = UserStatus(0)
*x = PostStage(0)
return
}
@@ -97,72 +103,72 @@ func (x *UserStatus) Scan(value interface{}) (err error) {
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case int64:
*x = UserStatus(v)
*x = PostStage(v)
case string:
*x, err = ParseUserStatus(v)
*x, err = ParsePostStage(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
*x, err = PostStage(val), nil
}
}
case []byte:
*x, err = ParseUserStatus(string(v))
*x, err = ParsePostStage(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
*x, err = PostStage(val), nil
}
}
case UserStatus:
case PostStage:
*x = v
case int:
*x = UserStatus(v)
case *UserStatus:
*x = PostStage(v)
case *PostStage:
if v == nil {
return errUserStatusNilPtr
return errPostStageNilPtr
}
*x = *v
case uint:
*x = UserStatus(v)
*x = PostStage(v)
case uint64:
*x = UserStatus(v)
*x = PostStage(v)
case *int:
if v == nil {
return errUserStatusNilPtr
return errPostStageNilPtr
}
*x = UserStatus(*v)
*x = PostStage(*v)
case *int64:
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
*x = UserStatus(v)
*x = PostStage(v)
case *float64: // json marshals everything as a float64 if it's a number
if v == nil {
return errUserStatusNilPtr
return errPostStageNilPtr
}
*x = UserStatus(*v)
*x = PostStage(*v)
case *uint:
if v == nil {
return errUserStatusNilPtr
return errPostStageNilPtr
}
*x = UserStatus(*v)
*x = PostStage(*v)
case *uint64:
if v == nil {
return errUserStatusNilPtr
return errPostStageNilPtr
}
*x = UserStatus(*v)
*x = PostStage(*v)
case *string:
if v == nil {
return errUserStatusNilPtr
return errPostStageNilPtr
}
*x, err = ParseUserStatus(*v)
*x, err = ParsePostStage(*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
*x, err = PostStage(val), nil
}
}
}
@@ -171,71 +177,529 @@ func (x *UserStatus) Scan(value interface{}) (err error) {
}
// Value implements the driver Valuer interface.
func (x UserStatus) Value() (driver.Value, error) {
func (x PostStage) 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)
func (x *PostStage) Set(val string) error {
v, err := ParsePostStage(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *UserStatus) Get() interface{} {
func (x *PostStage) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *UserStatus) Type() string {
return "UserStatus"
func (x *PostStage) Type() string {
return "PostStage"
}
type NullUserStatus struct {
UserStatus UserStatus
Valid bool
type NullPostStage struct {
PostStage PostStage
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.
return
}
// Scan implements the Scanner interface.
func (x *NullUserStatus) Scan(value interface{}) (err error) {
func (x *NullPostStage) Scan(value interface{}) (err error) {
if value == nil {
x.UserStatus, x.Valid = UserStatus(0), false
x.PostStage, x.Valid = PostStage(0), false
return
}
err = x.UserStatus.Scan(value)
err = x.PostStage.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullUserStatus) Value() (driver.Value, error) {
func (x NullPostStage) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return int64(x.UserStatus), nil
return int64(x.PostStage), nil
}
type NullUserStatusStr struct {
NullUserStatus
type NullPostStageStr struct {
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.
return
}
// Value implements the driver Valuer interface.
func (x NullUserStatusStr) Value() (driver.Value, error) {
func (x NullPostStageStr) Value() (driver.Value, error) {
if !x.Valid {
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
// swagger:enum UserStatus
// swagger:enum PostStage
// ENUM( Pending, Processing, Completed, Deleted)
type PostStage int16
// swagger:enum PostStatus
// 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(),
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,
user_id INT8 NOT NULL,
hash VARCHAR(128) NOT NULL UNIQUE,
title VARCHAR(128) NOT NULL,
description VARCHAR(256) NOT NULL,
poster VARCHAR(128) NOT NULL,
poster_asset_id INT8 NOT NULL,
content TEXT NOT NULL,
stage INT2 NOT NULL default 0,
status INT2 NOT NULL default 0,
price INT8 NOT NULL default 0,
discount INT2 NOT NULL default 100,
views INT8 NOT NULL default 0,
@@ -26,6 +27,7 @@ CREATE TABLE
assets jsonb default '{}'::jsonb
);
-- create indexes
CREATE INDEX posts_type_index ON posts (type);
CREATE INDEX posts_tenant_id_index ON posts (tenant_id);
CREATE INDEX posts_user_id_index ON posts (user_id);
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 StatementBegin
DROP TABLE posts;
DROP TABLE user_bought_posts;
-- +goose StatementEnd

View File

@@ -8,27 +8,28 @@
package model
import (
"backend/database/fields"
"time"
)
type Posts struct {
ID int64 `sql:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
Hash string `json:"hash"`
Title string `json:"title"`
Description string `json:"description"`
Poster string `json:"poster"`
Content string `json:"content"`
Stage int16 `json:"stage"`
Status int16 `json:"status"`
Price int64 `json:"price"`
Discount int16 `json:"discount"`
Views int64 `json:"views"`
Likes int64 `json:"likes"`
Meta *string `json:"meta"`
Assets *string `json:"assets"`
ID int64 `sql:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_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"`
UserID int64 `json:"user_id"`
Title string `json:"title"`
Description string `json:"description"`
PosterAssetID int64 `json:"poster_asset_id"`
Content string `json:"content"`
Price int64 `json:"price"`
Discount int16 `json:"discount"`
Views int64 `json:"views"`
Likes int64 `json:"likes"`
Meta *string `json:"meta"`
Assets *string `json:"assets"`
}

View File

@@ -17,25 +17,25 @@ type postsTable struct {
postgres.Table
// Columns
ID postgres.ColumnInteger
CreatedAt postgres.ColumnTimestamp
UpdatedAt postgres.ColumnTimestamp
DeletedAt postgres.ColumnTimestamp
TenantID postgres.ColumnInteger
UserID postgres.ColumnInteger
Hash postgres.ColumnString
Title postgres.ColumnString
Description postgres.ColumnString
Poster postgres.ColumnString
Content postgres.ColumnString
Stage postgres.ColumnInteger
Status postgres.ColumnInteger
Price postgres.ColumnInteger
Discount postgres.ColumnInteger
Views postgres.ColumnInteger
Likes postgres.ColumnInteger
Meta postgres.ColumnString
Assets postgres.ColumnString
ID postgres.ColumnInteger
CreatedAt postgres.ColumnTimestamp
UpdatedAt postgres.ColumnTimestamp
DeletedAt postgres.ColumnTimestamp
Type postgres.ColumnInteger
Stage 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
Discount postgres.ColumnInteger
Views postgres.ColumnInteger
Likes postgres.ColumnInteger
Meta postgres.ColumnString
Assets postgres.ColumnString
AllColumns postgres.ColumnList
MutableColumns postgres.ColumnList
@@ -76,52 +76,52 @@ func newPostsTable(schemaName, tableName, alias string) *PostsTable {
func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
var (
IDColumn = postgres.IntegerColumn("id")
CreatedAtColumn = postgres.TimestampColumn("created_at")
UpdatedAtColumn = postgres.TimestampColumn("updated_at")
DeletedAtColumn = postgres.TimestampColumn("deleted_at")
TenantIDColumn = postgres.IntegerColumn("tenant_id")
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")
StatusColumn = postgres.IntegerColumn("status")
PriceColumn = postgres.IntegerColumn("price")
DiscountColumn = postgres.IntegerColumn("discount")
ViewsColumn = postgres.IntegerColumn("views")
LikesColumn = postgres.IntegerColumn("likes")
MetaColumn = postgres.StringColumn("meta")
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}
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, TenantIDColumn, UserIDColumn, HashColumn, TitleColumn, DescriptionColumn, PosterColumn, ContentColumn, StageColumn, StatusColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, MetaColumn, AssetsColumn}
IDColumn = postgres.IntegerColumn("id")
CreatedAtColumn = postgres.TimestampColumn("created_at")
UpdatedAtColumn = postgres.TimestampColumn("updated_at")
DeletedAtColumn = postgres.TimestampColumn("deleted_at")
TypeColumn = postgres.IntegerColumn("type")
StageColumn = postgres.IntegerColumn("stage")
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")
DiscountColumn = postgres.IntegerColumn("discount")
ViewsColumn = postgres.IntegerColumn("views")
LikesColumn = postgres.IntegerColumn("likes")
MetaColumn = postgres.StringColumn("meta")
AssetsColumn = postgres.StringColumn("assets")
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, TypeColumn, StageColumn, StatusColumn, TenantIDColumn, UserIDColumn, TitleColumn, DescriptionColumn, PosterAssetIDColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, MetaColumn, AssetsColumn}
)
return postsTable{
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ID: IDColumn,
CreatedAt: CreatedAtColumn,
UpdatedAt: UpdatedAtColumn,
DeletedAt: DeletedAtColumn,
TenantID: TenantIDColumn,
UserID: UserIDColumn,
Hash: HashColumn,
Title: TitleColumn,
Description: DescriptionColumn,
Poster: PosterColumn,
Content: ContentColumn,
Stage: StageColumn,
Status: StatusColumn,
Price: PriceColumn,
Discount: DiscountColumn,
Views: ViewsColumn,
Likes: LikesColumn,
Meta: MetaColumn,
Assets: AssetsColumn,
ID: IDColumn,
CreatedAt: CreatedAtColumn,
UpdatedAt: UpdatedAtColumn,
DeletedAt: DeletedAtColumn,
Type: TypeColumn,
Stage: StageColumn,
Status: StatusColumn,
TenantID: TenantIDColumn,
UserID: UserIDColumn,
Title: TitleColumn,
Description: DescriptionColumn,
PosterAssetID: PosterAssetIDColumn,
Content: ContentColumn,
Price: PriceColumn,
Discount: DiscountColumn,
Views: ViewsColumn,
Likes: LikesColumn,
Meta: MetaColumn,
Assets: AssetsColumn,
AllColumns: allColumns,
MutableColumns: mutableColumns,

View File

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