spark-server/internal/transport/http/handler/admin/client.go
DESKTOP-L8OUL9F\gfl0034 c58b60419e feat(client): 接入同开发者应用墙 API 与管理端 CRUD
合并此前 stash 的 developer-apps:免登录列表、popadmin 管理与 0027 迁移。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 15:42:39 +08:00

189 lines
4.5 KiB
Go

package adminhandler
import (
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
"spark-server/internal/module/client/entity"
clientlogic "spark-server/internal/module/client/logic"
)
// ClientHandler serves popadmin legal / subscription / feedback / developer-apps ops.
type ClientHandler struct {
svc *clientlogic.Service
}
func NewClient(svc *clientlogic.Service) *ClientHandler {
return &ClientHandler{svc: svc}
}
func (h *ClientHandler) ready(c *gin.Context) bool {
if h == nil || h.svc == nil || !h.svc.Ready() {
Fail(c, http.StatusServiceUnavailable, "client 服务未就绪")
return false
}
return true
}
func (h *ClientHandler) GetLegal(c *gin.Context) {
if !h.ready(c) {
return
}
out, err := h.svc.LegalAgreements(c.Request.Context())
if err != nil {
Fail(c, http.StatusInternalServerError, err.Error())
return
}
OK(c, out)
}
func (h *ClientHandler) PutLegal(c *gin.Context) {
if !h.ready(c) {
return
}
var body entity.LegalDocument
if err := c.ShouldBindJSON(&body); err != nil {
Fail(c, http.StatusBadRequest, "无效 JSON")
return
}
if err := h.svc.UpsertLegalAdmin(c.Request.Context(), &body); err != nil {
Fail(c, http.StatusBadRequest, err.Error())
return
}
OKMsg(c, "已保存", body)
}
func (h *ClientHandler) ListPlans(c *gin.Context) {
if !h.ready(c) {
return
}
lang := c.Query("lang")
list, err := h.svc.ListPlansAdmin(c.Request.Context(), lang)
if err != nil {
Fail(c, http.StatusInternalServerError, err.Error())
return
}
OK(c, gin.H{"items": list})
}
func (h *ClientHandler) PutPlan(c *gin.Context) {
if !h.ready(c) {
return
}
var body entity.SubscriptionPlan
if err := c.ShouldBindJSON(&body); err != nil {
Fail(c, http.StatusBadRequest, "无效 JSON")
return
}
if err := h.svc.UpsertPlanAdmin(c.Request.Context(), &body); err != nil {
Fail(c, http.StatusBadRequest, err.Error())
return
}
OKMsg(c, "已保存", body)
}
func (h *ClientHandler) ListFeedback(c *gin.Context) {
if !h.ready(c) {
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "0"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "50"))
authType := strings.TrimSpace(c.Query("auth_type"))
list, total, err := h.svc.ListFeedbackAdmin(c.Request.Context(), page, size, authType)
if err != nil {
Fail(c, http.StatusInternalServerError, err.Error())
return
}
OK(c, gin.H{"list": list, "total": total, "page": page, "size": size, "auth_type": authType})
}
func (h *ClientHandler) PatchFeedback(c *gin.Context) {
if !h.ready(c) {
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil || id <= 0 {
Fail(c, http.StatusBadRequest, "无效 id")
return
}
var body struct {
Status string `json:"status"`
}
if err := c.ShouldBindJSON(&body); err != nil || body.Status == "" {
Fail(c, http.StatusBadRequest, "status 必填")
return
}
if err := h.svc.UpdateFeedbackStatus(c.Request.Context(), id, body.Status); err != nil {
Fail(c, http.StatusBadRequest, err.Error())
return
}
OKMsg(c, "已更新", gin.H{"id": id, "status": body.Status})
}
func (h *ClientHandler) ListDeveloperApps(c *gin.Context) {
if !h.ready(c) {
return
}
appCode := c.Query("appCode")
if appCode == "" {
appCode = c.Query("sourceAppCode")
}
if appCode == "" {
appCode = "spark"
}
list, err := h.svc.ListDeveloperAppsAdmin(c.Request.Context(), appCode)
if err != nil {
Fail(c, http.StatusInternalServerError, err.Error())
return
}
OK(c, list)
}
func (h *ClientHandler) CreateDeveloperApp(c *gin.Context) {
if !h.ready(c) {
return
}
var body entity.DeveloperApp
if err := c.ShouldBindJSON(&body); err != nil {
Fail(c, http.StatusBadRequest, "无效 JSON")
return
}
out, err := h.svc.CreateDeveloperAppAdmin(c.Request.Context(), body)
if err != nil {
Fail(c, http.StatusBadRequest, err.Error())
return
}
OKMsg(c, "已保存", out)
}
func (h *ClientHandler) DeleteDeveloperApp(c *gin.Context) {
if !h.ready(c) {
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil || id <= 0 {
Fail(c, http.StatusBadRequest, "无效 id")
return
}
if err := h.svc.DeleteDeveloperAppAdmin(c.Request.Context(), id); err != nil {
Fail(c, http.StatusBadRequest, err.Error())
return
}
OKMsg(c, "已删除", gin.H{"id": id})
}
func (h *ClientHandler) SyncDeveloperAppIcons(c *gin.Context) {
if !h.ready(c) {
return
}
n, err := h.svc.SyncWebsiteIconsAdmin(c.Request.Context())
if err != nil {
Fail(c, http.StatusBadRequest, err.Error())
return
}
OKMsg(c, "已同步", gin.H{"count": n})
}