Files
geo/server/internal/tenant/transport/kol_manage_handler.go
T

507 lines
10 KiB
Go

package transport
import (
"io"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/geo-platform/tenant-api/internal/bootstrap"
"github.com/geo-platform/tenant-api/internal/shared/auth"
"github.com/geo-platform/tenant-api/internal/shared/response"
"github.com/geo-platform/tenant-api/internal/tenant/app"
)
type KolManageHandler struct {
profileSvc *app.KolProfileService
pkgSvc *app.KolPackageService
promptSvc *app.KolPromptService
assistSvc *app.KolAssistService
assets *AssetHandler
}
func NewKolManageHandler(a *bootstrap.App, assets *AssetHandler) *KolManageHandler {
profileSvc := app.NewKolProfileService(a.KolProfiles).WithObjectStorage(a.ObjectStorage)
return &KolManageHandler{
profileSvc: profileSvc,
pkgSvc: app.NewKolPackageService(profileSvc, a.KolPackages, a.KolPrompts).WithCache(a.Cache),
promptSvc: app.NewKolPromptService(a.DB, profileSvc, a.KolPackages, a.KolPrompts, a.KolSubscriptions, a.KolPromptAsset).WithCache(a.Cache),
assistSvc: app.NewKolAssistService(profileSvc, a.KolAssists, a.LLM, a.RabbitMQ),
assets: assets,
}
}
func (h *KolManageHandler) GetProfile(c *gin.Context) {
actor, ok := actorFromRequest(c)
if !ok {
return
}
profile, err := h.profileSvc.RequireActiveKol(c.Request.Context(), actor)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, app.NewKolProfileResponse(profile))
}
type updateKolProfileRequest struct {
DisplayName string `json:"display_name"`
Bio *string `json:"bio"`
AvatarURL *string `json:"avatar_url"`
}
func (h *KolManageHandler) UpdateProfile(c *gin.Context) {
actor, ok := actorFromRequest(c)
if !ok {
return
}
var req updateKolProfileRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
profile, err := h.profileSvc.UpdateProfile(c.Request.Context(), actor, app.UpdateKolProfileServiceInput{
DisplayName: req.DisplayName,
Bio: req.Bio,
AvatarURL: req.AvatarURL,
})
if err != nil {
response.Error(c, err)
return
}
response.Success(c, app.NewKolProfileResponse(profile))
}
func (h *KolManageHandler) UploadAvatar(c *gin.Context) {
actor, ok := actorFromRequest(c)
if !ok {
return
}
fileHeader, err := c.FormFile("file")
if err != nil {
response.Error(c, response.ErrBadRequest(40004, "kol_avatar_invalid", "avatar file is required"))
return
}
f, err := fileHeader.Open()
if err != nil {
response.Error(c, response.ErrBadRequest(40004, "kol_avatar_invalid", "avatar file cannot be opened"))
return
}
defer f.Close()
content, err := io.ReadAll(f)
if err != nil {
response.Error(c, response.ErrBadRequest(40004, "kol_avatar_invalid", "avatar file cannot be read"))
return
}
result, err := h.profileSvc.UploadAvatar(c.Request.Context(), actor, fileHeader.Filename, content)
if err != nil {
response.Error(c, err)
return
}
result.URL = h.assets.BuildArticleImageURL(result.ObjectKey)
response.SuccessWithStatus(c, http.StatusCreated, result)
}
func (h *KolManageHandler) ListPackages(c *gin.Context) {
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.pkgSvc.List(c.Request.Context(), actor)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) CreatePackage(c *gin.Context) {
var req app.CreateKolPackageInput
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.pkgSvc.Create(c.Request.Context(), actor, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) UpdatePackage(c *gin.Context) {
id, ok := parseInt64Param(c, "id", "package id")
if !ok {
return
}
var req app.UpdateKolPackageInput
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.pkgSvc.Update(c.Request.Context(), actor, id, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) DeletePackage(c *gin.Context) {
id, ok := parseInt64Param(c, "id", "package id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
if err := h.pkgSvc.Delete(c.Request.Context(), actor, id); err != nil {
response.Error(c, err)
return
}
response.Success(c, nil)
}
func (h *KolManageHandler) PublishPackage(c *gin.Context) {
id, ok := parseInt64Param(c, "id", "package id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.pkgSvc.Publish(c.Request.Context(), actor, id)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) ArchivePackage(c *gin.Context) {
id, ok := parseInt64Param(c, "id", "package id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.pkgSvc.Archive(c.Request.Context(), actor, id)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) ListPrompts(c *gin.Context) {
packageID, ok := parseInt64Param(c, "id", "package id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.ListByPackage(c.Request.Context(), actor, packageID)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) CreatePrompt(c *gin.Context) {
packageID, ok := parseInt64Param(c, "id", "package id")
if !ok {
return
}
var req app.CreatePromptInput
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
req.PackageID = packageID
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.CreatePrompt(c.Request.Context(), actor, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) GetPromptLatest(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.GetForOwner(c.Request.Context(), actor, promptID)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) UpdatePromptMetadata(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
var req app.UpdateKolPromptInput
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.UpdateMetadata(c.Request.Context(), actor, promptID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) DeletePrompt(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
if err := h.promptSvc.Delete(c.Request.Context(), actor, promptID); err != nil {
response.Error(c, err)
return
}
response.Success(c, nil)
}
func (h *KolManageHandler) SavePrompt(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
var req app.PublishPromptInput
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.Save(c.Request.Context(), actor, promptID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) PublishPrompt(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
var req app.PublishPromptInput
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.Publish(c.Request.Context(), actor, promptID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) ActivatePrompt(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.Activate(c.Request.Context(), actor, promptID)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) ArchivePrompt(c *gin.Context) {
promptID, ok := parseInt64Param(c, "id", "prompt id")
if !ok {
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
data, err := h.promptSvc.Archive(c.Request.Context(), actor, promptID)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *KolManageHandler) AssistSubmit(c *gin.Context) {
var req app.AssistRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
taskID, err := h.assistSvc.Submit(c.Request.Context(), actor, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, app.KolAssistSubmitResponse{TaskID: taskID})
}
func (h *KolManageHandler) AssistGet(c *gin.Context) {
taskID := c.Param("id")
if taskID == "" {
response.Error(c, response.ErrBadRequest(40001, "invalid_id", "task id must not be empty"))
return
}
actor, ok := actorFromRequest(c)
if !ok {
return
}
task, err := h.assistSvc.Get(c.Request.Context(), actor, taskID)
if err != nil {
response.Error(c, err)
return
}
data, err := app.NewKolAssistTaskResponse(task)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func actorFromRequest(c *gin.Context) (auth.Actor, bool) {
actor, ok := auth.ActorFromCtx(c.Request.Context())
if !ok {
response.Error(c, response.ErrUnauthorized(40100, "not_authenticated", "not authenticated"))
return auth.Actor{}, false
}
return actor, true
}
func parseInt64Param(c *gin.Context, key, label string) (int64, bool) {
id, err := strconv.ParseInt(c.Param(key), 10, 64)
if err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_id", label+" must be a number"))
return 0, false
}
return id, true
}