feat(enterprise-site): add WordPress support and scheduled auto-publish to sites
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:
@@ -25,16 +25,17 @@ import (
|
||||
)
|
||||
|
||||
type PromptRuleGenerationService struct {
|
||||
pool *pgxpool.Pool
|
||||
llm llm.Client
|
||||
rabbitMQ *rabbitmq.Client
|
||||
knowledge *KnowledgeService
|
||||
streams *stream.GenerationHub
|
||||
cfg generationRuntimeConfig
|
||||
configProvider runtimeConfigProvider
|
||||
cache sharedcache.Cache
|
||||
publishJobs *PublishJobService
|
||||
logger *zap.Logger
|
||||
pool *pgxpool.Pool
|
||||
llm llm.Client
|
||||
rabbitMQ *rabbitmq.Client
|
||||
knowledge *KnowledgeService
|
||||
streams *stream.GenerationHub
|
||||
cfg generationRuntimeConfig
|
||||
configProvider runtimeConfigProvider
|
||||
cache sharedcache.Cache
|
||||
publishJobs *PublishJobService
|
||||
enterpriseSites *EnterpriseSiteService
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
type promptRuleGenerationJob struct {
|
||||
@@ -72,20 +73,21 @@ type GenerateFromRuleItem struct {
|
||||
}
|
||||
|
||||
type SchedulePromptRuleGenerationInput struct {
|
||||
ScheduleTaskID int64
|
||||
OperatorID *int64
|
||||
TenantID int64
|
||||
PromptRuleID int64
|
||||
BrandID *int64
|
||||
Name string
|
||||
WorkspaceID int64
|
||||
AutoPublish bool
|
||||
PublishAccountIDs []string
|
||||
CoverAssetURL *string
|
||||
CoverImageAssetID *int64
|
||||
EnableWebSearch bool
|
||||
GenerateCount int
|
||||
ScheduledFor time.Time
|
||||
ScheduleTaskID int64
|
||||
OperatorID *int64
|
||||
TenantID int64
|
||||
PromptRuleID int64
|
||||
BrandID *int64
|
||||
Name string
|
||||
WorkspaceID int64
|
||||
AutoPublish bool
|
||||
PublishAccountIDs []string
|
||||
PublishEnterpriseSiteTargets []ScheduleEnterpriseSiteTarget
|
||||
CoverAssetURL *string
|
||||
CoverImageAssetID *int64
|
||||
EnableWebSearch bool
|
||||
GenerateCount int
|
||||
ScheduledFor time.Time
|
||||
}
|
||||
|
||||
type promptRuleGenerationRecord struct {
|
||||
@@ -143,6 +145,11 @@ func (s *PromptRuleGenerationService) WithPublishJobService(publishJobs *Publish
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *PromptRuleGenerationService) WithEnterpriseSiteService(enterpriseSites *EnterpriseSiteService) *PromptRuleGenerationService {
|
||||
s.enterpriseSites = enterpriseSites
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *PromptRuleGenerationService) WithLogger(logger *zap.Logger) *PromptRuleGenerationService {
|
||||
s.logger = logger
|
||||
return s
|
||||
@@ -232,6 +239,7 @@ func (s *PromptRuleGenerationService) EnqueueScheduledGeneration(ctx context.Con
|
||||
if input.AutoPublish {
|
||||
extra["schedule_auto_publish"] = true
|
||||
extra["schedule_publish_account_ids"] = input.PublishAccountIDs
|
||||
extra["schedule_publish_enterprise_site_targets"] = input.PublishEnterpriseSiteTargets
|
||||
if input.CoverAssetURL != nil {
|
||||
extra["schedule_cover_asset_url"] = strings.TrimSpace(*input.CoverAssetURL)
|
||||
}
|
||||
@@ -323,6 +331,7 @@ func (s *PromptRuleGenerationService) enqueuePromptRuleGeneration(ctx context.Co
|
||||
if extractBool(extra, "schedule_auto_publish") {
|
||||
inputParams["schedule_auto_publish"] = true
|
||||
inputParams["schedule_publish_account_ids"] = extractStringList(extra["schedule_publish_account_ids"], 64)
|
||||
inputParams["schedule_publish_enterprise_site_targets"] = extractScheduleEnterpriseSiteTargets(extra["schedule_publish_enterprise_site_targets"], scheduleEnterpriseSiteTargetLimit)
|
||||
if coverURL := strings.TrimSpace(extractString(extra, "schedule_cover_asset_url")); coverURL != "" {
|
||||
inputParams["schedule_cover_asset_url"] = coverURL
|
||||
}
|
||||
@@ -635,69 +644,26 @@ func (s *PromptRuleGenerationService) executeGeneration(ctx context.Context, job
|
||||
s.streams.Complete(job.ArticleID, job.TaskID, title, content)
|
||||
}
|
||||
|
||||
s.enqueueScheduleAutoPublish(cleanupCtx, job, title)
|
||||
s.enqueueScheduleAutoPublish(job, title)
|
||||
}
|
||||
|
||||
func (s *PromptRuleGenerationService) enqueueScheduleAutoPublish(ctx context.Context, job promptRuleGenerationJob, title string) {
|
||||
if s == nil || s.publishJobs == nil || !extractBool(job.InputParams, "schedule_auto_publish") {
|
||||
func (s *PromptRuleGenerationService) enqueueScheduleAutoPublish(job promptRuleGenerationJob, title string) {
|
||||
if s == nil || !extractBool(job.InputParams, "schedule_auto_publish") {
|
||||
return
|
||||
}
|
||||
|
||||
workspaceID := int64(extractInt(job.InputParams, "workspace_id"))
|
||||
accountIDs := extractStringList(job.InputParams["schedule_publish_account_ids"], 64)
|
||||
coverURL := strings.TrimSpace(extractString(job.InputParams, "schedule_cover_asset_url"))
|
||||
if workspaceID <= 0 || job.OperatorID <= 0 || len(accountIDs) == 0 {
|
||||
s.logAutoPublishWarn("schedule auto publish skipped because configuration is incomplete", nil,
|
||||
zap.Int64("generation_task_id", job.TaskID),
|
||||
zap.Int64("article_id", job.ArticleID),
|
||||
zap.Int64("workspace_id", workspaceID),
|
||||
zap.Int("account_count", len(accountIDs)),
|
||||
zap.Bool("has_cover", coverURL != ""),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
accounts := make([]CreatePublishJobAccountRequest, 0, len(accountIDs))
|
||||
for _, accountID := range accountIDs {
|
||||
accountID = strings.TrimSpace(accountID)
|
||||
if accountID == "" {
|
||||
continue
|
||||
}
|
||||
accounts = append(accounts, CreatePublishJobAccountRequest{AccountID: accountID})
|
||||
}
|
||||
if len(accounts) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
publishTitle := strings.TrimSpace(title)
|
||||
if publishTitle == "" {
|
||||
publishTitle = "定时生成文章"
|
||||
}
|
||||
|
||||
brandID := int64(extractInt(job.InputParams, "brand_id"))
|
||||
publishCtx := ctx
|
||||
if brandID > 0 {
|
||||
publishCtx = auth.WithCurrentBrandID(ctx, brandID)
|
||||
}
|
||||
|
||||
if _, err := s.publishJobs.Create(publishCtx, auth.Actor{
|
||||
TenantID: job.TenantID,
|
||||
UserID: job.OperatorID,
|
||||
PrimaryWorkspaceID: workspaceID,
|
||||
}, CreatePublishJobRequest{
|
||||
Title: publishTitle,
|
||||
ContentRef: map[string]any{
|
||||
"article_id": job.ArticleID,
|
||||
},
|
||||
Accounts: accounts,
|
||||
}); err != nil {
|
||||
s.logAutoPublishWarn("schedule auto publish enqueue failed", err,
|
||||
zap.Int64("generation_task_id", job.TaskID),
|
||||
zap.Int64("article_id", job.ArticleID),
|
||||
zap.Int64("workspace_id", workspaceID),
|
||||
zap.Int("account_count", len(accounts)),
|
||||
)
|
||||
}
|
||||
StartScheduleAutoPublish(ScheduleAutoPublishInput{
|
||||
TenantID: job.TenantID,
|
||||
WorkspaceID: int64(extractInt(job.InputParams, "workspace_id")),
|
||||
OperatorID: job.OperatorID,
|
||||
BrandID: int64(extractInt(job.InputParams, "brand_id")),
|
||||
ArticleID: job.ArticleID,
|
||||
GenerationTaskID: job.TaskID,
|
||||
Title: title,
|
||||
InputParams: job.InputParams,
|
||||
PublishJobs: s.publishJobs,
|
||||
EnterpriseSites: s.enterpriseSites,
|
||||
Logger: s.logger,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *PromptRuleGenerationService) logAutoPublishWarn(message string, err error, fields ...zap.Field) {
|
||||
|
||||
Reference in New Issue
Block a user