refactor(kol-admin): move subscription admin endpoints from tenant-api to ops-api
Approving / manually binding / revoking KOL subscriptions belonged to the operations console, not the tenant-admin role on tenant-api. Add a fresh KolSubscriptionService + repository + handlers under the ops module with its own list/manual-bind/approve/revoke routes, wire a Redis-backed cache into ops-api so admin actions can invalidate tenant prompt caches, and delete the tenant-side admin service/handler now that ops-web owns the UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/geo-platform/tenant-api/internal/ops/app"
|
||||
"github.com/geo-platform/tenant-api/internal/shared/response"
|
||||
)
|
||||
|
||||
type approveKolSubscriptionRequest struct {
|
||||
EndAt *time.Time `json:"end_at"`
|
||||
}
|
||||
|
||||
type manualBindKolSubscriptionRequest struct {
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
PackageID int64 `json:"package_id" binding:"required"`
|
||||
EndAt *time.Time `json:"end_at"`
|
||||
}
|
||||
|
||||
func listKolSubscriptionsHandler(svc *app.KolSubscriptionService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
||||
result, err := svc.List(c.Request.Context(), app.KolSubscriptionListInput{
|
||||
Keyword: c.Query("keyword"),
|
||||
Status: c.Query("status"),
|
||||
Page: page,
|
||||
Size: size,
|
||||
})
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, result)
|
||||
}
|
||||
}
|
||||
|
||||
func listKolSubscriptionPackagesHandler(svc *app.KolSubscriptionService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "50"))
|
||||
result, err := svc.ListPackages(c.Request.Context(), app.KolPackageListInput{
|
||||
Keyword: c.Query("keyword"),
|
||||
Size: size,
|
||||
})
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, result)
|
||||
}
|
||||
}
|
||||
|
||||
func manualBindKolSubscriptionHandler(svc *app.KolSubscriptionService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var body manualBindKolSubscriptionRequest
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
detail, err := svc.ManualBind(c.Request.Context(), actorFromGin(c), app.KolSubscriptionManualBindInput{
|
||||
Phone: body.Phone,
|
||||
PackageID: body.PackageID,
|
||||
EndAt: body.EndAt,
|
||||
})
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, detail)
|
||||
}
|
||||
}
|
||||
|
||||
func approveKolSubscriptionHandler(svc *app.KolSubscriptionService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
id, err := parseIDParam(c)
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
var body approveKolSubscriptionRequest
|
||||
if c.Request.ContentLength > 0 {
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
detail, err := svc.Approve(c.Request.Context(), actorFromGin(c), id, body.EndAt)
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, detail)
|
||||
}
|
||||
}
|
||||
|
||||
func revokeKolSubscriptionHandler(svc *app.KolSubscriptionService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
id, err := parseIDParam(c)
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
detail, err := svc.Revoke(c.Request.Context(), actorFromGin(c), id)
|
||||
if err != nil {
|
||||
response.Error(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, detail)
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ type Deps struct {
|
||||
Auth *app.AuthService
|
||||
Accounts *app.AccountService
|
||||
AdminUsers *app.AdminUserService
|
||||
KolSubs *app.KolSubscriptionService
|
||||
Audits *app.AuditService
|
||||
SiteDomains *app.SiteDomainMappingService
|
||||
}
|
||||
@@ -81,6 +82,12 @@ func RegisterRoutes(d Deps) {
|
||||
authed.POST("/admin-users/:id/status", setAdminUserStatusHandler(d.AdminUsers))
|
||||
authed.POST("/admin-users/:id/password", resetAdminUserPasswordHandler(d.AdminUsers))
|
||||
|
||||
authed.GET("/kol/packages", listKolSubscriptionPackagesHandler(d.KolSubs))
|
||||
authed.GET("/kol/subscriptions", listKolSubscriptionsHandler(d.KolSubs))
|
||||
authed.POST("/kol/subscriptions/manual-bind", manualBindKolSubscriptionHandler(d.KolSubs))
|
||||
authed.POST("/kol/subscriptions/:id/approve", approveKolSubscriptionHandler(d.KolSubs))
|
||||
authed.POST("/kol/subscriptions/:id/revoke", revokeKolSubscriptionHandler(d.KolSubs))
|
||||
|
||||
authed.GET("/audits", listAuditsHandler(d.Audits))
|
||||
|
||||
authed.GET("/site-domain-mappings", listSiteDomainMappingsHandler(d.SiteDomains))
|
||||
|
||||
Reference in New Issue
Block a user