feat(enterprise-site): add WordPress support and scheduled auto-publish to sites
Frontend CI / Frontend (push) Successful in 4m17s
Backend CI / Backend (push) Failing after 6m42s

Add WordPress as an enterprise-site CMS type alongside pbootcms, and let
schedule tasks auto-publish generated articles to enterprise sites.

- WordPress connection/publisher service and tests; register wordpress
  media platform and relax cms_type CHECK constraint
- New publish_enterprise_site_targets JSONB column on schedule_tasks with
  array type constraint; thread targets through scheduler dispatch,
  prompt/KOL generation, and worker
- Admin UI: enterprise-site targets in generate/schedule/publish flows,
  KOL package form, MediaView, and i18n strings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 19:44:24 +08:00
parent 41f5623791
commit c7bad83496
30 changed files with 2946 additions and 696 deletions
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"sort"
"strconv"
"strings"
"time"
@@ -23,14 +24,16 @@ import (
const kolGenerationTaskType = "kol"
type KolGenerationWorker struct {
pool *pgxpool.Pool
llm llm.Client
knowledge *tenantapp.KnowledgeService
logger *zap.Logger
cfg config.GenerationConfig
llmCfg config.LLMConfig
provider config.Provider
cache sharedcache.Cache
pool *pgxpool.Pool
llm llm.Client
knowledge *tenantapp.KnowledgeService
logger *zap.Logger
cfg config.GenerationConfig
llmCfg config.LLMConfig
provider config.Provider
cache sharedcache.Cache
publishJobs *tenantapp.PublishJobService
enterpriseSites *tenantapp.EnterpriseSiteService
}
func NewKolGenerationWorker(
@@ -56,6 +59,16 @@ func (w *KolGenerationWorker) WithCache(c sharedcache.Cache) *KolGenerationWorke
return w
}
func (w *KolGenerationWorker) WithPublishJobService(svc *tenantapp.PublishJobService) *KolGenerationWorker {
w.publishJobs = svc
return w
}
func (w *KolGenerationWorker) WithEnterpriseSiteService(svc *tenantapp.EnterpriseSiteService) *KolGenerationWorker {
w.enterpriseSites = svc
return w
}
func (w *KolGenerationWorker) WithConfigProvider(provider config.Provider) *KolGenerationWorker {
w.provider = provider
return w
@@ -225,6 +238,19 @@ func (w *KolGenerationWorker) Process(ctx context.Context, task tenantapp.Claime
cleanupCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
tenantapp.InvalidateArticleCaches(cleanupCtx, w.cache, task.TenantID, &task.ArticleID)
tenantapp.StartScheduleAutoPublish(tenantapp.ScheduleAutoPublishInput{
TenantID: task.TenantID,
WorkspaceID: int64(kolIntInput(task.InputParams, "workspace_id")),
OperatorID: task.OperatorID,
BrandID: int64(kolIntInput(task.InputParams, "brand_id")),
ArticleID: task.ArticleID,
GenerationTaskID: task.ID,
Title: title,
InputParams: task.InputParams,
PublishJobs: w.publishJobs,
EnterpriseSites: w.enterpriseSites,
Logger: w.logger,
})
}
func (w *KolGenerationWorker) HandleTaskFailure(ctx context.Context, task tenantapp.ClaimedGenerationTask, stage string, taskErr error) {
@@ -283,6 +309,31 @@ func kolBoolInput(input map[string]interface{}, key string) bool {
return ok && enabled
}
func kolIntInput(input map[string]interface{}, key string) int {
if input == nil {
return 0
}
value, ok := input[key]
if !ok || value == nil {
return 0
}
switch typed := value.(type) {
case int:
return typed
case int32:
return int(typed)
case int64:
return int(typed)
case float64:
return int(typed)
case string:
parsed, _ := strconv.Atoi(strings.TrimSpace(typed))
return parsed
default:
return 0
}
}
func kolKnowledgeGroupIDs(value interface{}) []int64 {
switch typed := value.(type) {
case []int64: