feat: add tenant membership flow
This commit is contained in:
@@ -29,6 +29,46 @@ func (c *Creator) Apply(ctx fiber.Ctx, user *models.User, form *dto.ApplyForm) e
|
||||
return services.Creator.Apply(ctx, tenantID, user.ID, form)
|
||||
}
|
||||
|
||||
// Review join request
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/creator/members/:id<int>/review [post]
|
||||
// @Summary Review join request
|
||||
// @Description Approve or reject a tenant join request
|
||||
// @Tags CreatorCenter
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Join request ID"
|
||||
// @Param form body dto.TenantJoinReviewForm true "Review form"
|
||||
// @Success 200 {string} string "Reviewed"
|
||||
// @Bind user local key(__ctx_user)
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (c *Creator) ReviewMember(ctx fiber.Ctx, user *models.User, id int64, form *dto.TenantJoinReviewForm) error {
|
||||
tenantID := getTenantID(ctx)
|
||||
return services.Tenant.ReviewJoin(ctx, tenantID, user.ID, id, form)
|
||||
}
|
||||
|
||||
// Create member invite
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/creator/members/invite [post]
|
||||
// @Summary Create member invite
|
||||
// @Description Create an invite for tenant members
|
||||
// @Tags CreatorCenter
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param form body dto.TenantInviteCreateForm true "Invite form"
|
||||
// @Success 200 {object} dto.TenantInviteItem
|
||||
// @Bind user local key(__ctx_user)
|
||||
// @Bind form body
|
||||
func (c *Creator) CreateMemberInvite(
|
||||
ctx fiber.Ctx,
|
||||
user *models.User,
|
||||
form *dto.TenantInviteCreateForm,
|
||||
) (*dto.TenantInviteItem, error) {
|
||||
tenantID := getTenantID(ctx)
|
||||
return services.Tenant.CreateInvite(ctx, tenantID, user.ID, form)
|
||||
}
|
||||
|
||||
// Get creator dashboard stats
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/creator/dashboard [get]
|
||||
|
||||
46
backend/app/http/v1/dto/tenant_member.go
Normal file
46
backend/app/http/v1/dto/tenant_member.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package dto
|
||||
|
||||
type TenantJoinApplyForm struct {
|
||||
// Reason 申请加入原因(可选,空值会使用默认文案)。
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type TenantJoinReviewForm struct {
|
||||
// Action 审核动作(approve/reject)。
|
||||
Action string `json:"action"`
|
||||
// Reason 审核说明(可选,用于展示驳回原因或备注)。
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type TenantInviteCreateForm struct {
|
||||
// MaxUses 最大可使用次数(<=0 默认 1)。
|
||||
MaxUses int32 `json:"max_uses"`
|
||||
// ExpiresAt 过期时间(RFC3339,可选,空值使用默认过期时间)。
|
||||
ExpiresAt *string `json:"expires_at"`
|
||||
// Remark 备注说明(可选)。
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type TenantInviteAcceptForm struct {
|
||||
// Code 邀请码(必填)。
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
type TenantInviteItem struct {
|
||||
// ID 邀请记录ID。
|
||||
ID int64 `json:"id"`
|
||||
// Code 邀请码。
|
||||
Code string `json:"code"`
|
||||
// Status 邀请状态(active/disabled/expired)。
|
||||
Status string `json:"status"`
|
||||
// MaxUses 最大可使用次数。
|
||||
MaxUses int32 `json:"max_uses"`
|
||||
// UsedCount 已使用次数。
|
||||
UsedCount int32 `json:"used_count"`
|
||||
// ExpiresAt 过期时间(RFC3339,空字符串表示不限制)。
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// Remark 备注说明。
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
@@ -208,6 +208,19 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
Local[*models.User]("__ctx_user"),
|
||||
Body[dto.ContentCreateForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/creator/members/:id<int>/review -> creator.ReviewMember")
|
||||
router.Post("/t/:tenantCode/v1/creator/members/:id<int>/review"[len(r.Path()):], Func3(
|
||||
r.creator.ReviewMember,
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.TenantJoinReviewForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/creator/members/invite -> creator.CreateMemberInvite")
|
||||
router.Post("/t/:tenantCode/v1/creator/members/invite"[len(r.Path()):], DataFunc2(
|
||||
r.creator.CreateMemberInvite,
|
||||
Local[*models.User]("__ctx_user"),
|
||||
Body[dto.TenantInviteCreateForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/creator/orders/:id<int>/refund -> creator.Refund")
|
||||
router.Post("/t/:tenantCode/v1/creator/orders/:id<int>/refund"[len(r.Path()):], Func3(
|
||||
r.creator.Refund,
|
||||
@@ -260,6 +273,11 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Delete /t/:tenantCode/v1/tenants/:id<int>/join -> tenant.CancelJoin")
|
||||
router.Delete("/t/:tenantCode/v1/tenants/:id<int>/join"[len(r.Path()):], Func1(
|
||||
r.tenant.CancelJoin,
|
||||
PathParam[int64]("id"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /t/:tenantCode/v1/creators/:id<int>/contents -> tenant.ListContents")
|
||||
router.Get("/t/:tenantCode/v1/creators/:id<int>/contents"[len(r.Path()):], DataFunc2(
|
||||
r.tenant.ListContents,
|
||||
@@ -283,6 +301,18 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/tenants/:id<int>/invites/accept -> tenant.AcceptInvite")
|
||||
router.Post("/t/:tenantCode/v1/tenants/:id<int>/invites/accept"[len(r.Path()):], Func2(
|
||||
r.tenant.AcceptInvite,
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.TenantInviteAcceptForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/tenants/:id<int>/join -> tenant.ApplyJoin")
|
||||
router.Post("/t/:tenantCode/v1/tenants/:id<int>/join"[len(r.Path()):], Func2(
|
||||
r.tenant.ApplyJoin,
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.TenantJoinApplyForm]("form"),
|
||||
))
|
||||
// Register routes for controller: Transaction
|
||||
r.log.Debugf("Registering route: Get /t/:tenantCode/v1/orders/:id<int>/status -> transaction.Status")
|
||||
router.Get("/t/:tenantCode/v1/orders/:id<int>/status"[len(r.Path()):], DataFunc2(
|
||||
|
||||
@@ -120,3 +120,67 @@ func (t *Tenant) Unfollow(ctx fiber.Ctx, user *models.User, id int64) error {
|
||||
}
|
||||
return services.Tenant.Unfollow(ctx, tenantID, user.ID)
|
||||
}
|
||||
|
||||
// Apply to join a tenant
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/tenants/:id<int>/join [post]
|
||||
// @Summary Apply to join tenant
|
||||
// @Description Submit join request for a tenant
|
||||
// @Tags TenantPublic
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Tenant ID"
|
||||
// @Param form body dto.TenantJoinApplyForm true "Join form"
|
||||
// @Success 200 {string} string "Applied"
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (t *Tenant) ApplyJoin(ctx fiber.Ctx, id int64, form *dto.TenantJoinApplyForm) error {
|
||||
tenantID := getTenantID(ctx)
|
||||
if tenantID > 0 && id != tenantID {
|
||||
return errorx.ErrForbidden.WithMsg("租户不匹配")
|
||||
}
|
||||
userID := getUserID(ctx)
|
||||
return services.Tenant.ApplyJoin(ctx, id, userID, form)
|
||||
}
|
||||
|
||||
// Cancel join request
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/tenants/:id<int>/join [delete]
|
||||
// @Summary Cancel join request
|
||||
// @Description Cancel join request for a tenant
|
||||
// @Tags TenantPublic
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Tenant ID"
|
||||
// @Success 200 {string} string "Canceled"
|
||||
// @Bind id path
|
||||
func (t *Tenant) CancelJoin(ctx fiber.Ctx, id int64) error {
|
||||
tenantID := getTenantID(ctx)
|
||||
if tenantID > 0 && id != tenantID {
|
||||
return errorx.ErrForbidden.WithMsg("租户不匹配")
|
||||
}
|
||||
userID := getUserID(ctx)
|
||||
return services.Tenant.CancelJoin(ctx, id, userID)
|
||||
}
|
||||
|
||||
// Accept tenant invite
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/tenants/:id<int>/invites/accept [post]
|
||||
// @Summary Accept tenant invite
|
||||
// @Description Accept a tenant invite by code
|
||||
// @Tags TenantPublic
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Tenant ID"
|
||||
// @Param form body dto.TenantInviteAcceptForm true "Invite form"
|
||||
// @Success 200 {string} string "Accepted"
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (t *Tenant) AcceptInvite(ctx fiber.Ctx, id int64, form *dto.TenantInviteAcceptForm) error {
|
||||
tenantID := getTenantID(ctx)
|
||||
if tenantID > 0 && id != tenantID {
|
||||
return errorx.ErrForbidden.WithMsg("租户不匹配")
|
||||
}
|
||||
userID := getUserID(ctx)
|
||||
return services.Tenant.AcceptInvite(ctx, id, userID, form)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user