feat(desktop): drop parked review flow, add publish management
SaaS 侧人工审核后才创建 publish job,desktop 不再做二次审核:移除 manual/waiting_user/parked/from_parked 状态机与 LeaseFromParked 查询, desktop client 只执行发布并新增"发布管理"页(待发布队列 / 历史 / 再次 发送)。同时抽离 @geo/publisher-platforms 共享适配器包、新增 Redis-based desktop_presence 与 publish_record_support,刷新 admin-web 发布弹窗与 媒体库;plan A / spec 文档同步口径。
This commit is contained in:
@@ -468,51 +468,40 @@ func (s *MediaService) CreatePublishBatch(ctx context.Context, articleID int64,
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
var articleExists bool
|
||||
var generateStatus string
|
||||
if err := tx.QueryRow(ctx, `
|
||||
SELECT EXISTS(SELECT 1 FROM articles WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL),
|
||||
COALESCE((SELECT generate_status FROM articles WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL), '')
|
||||
`, articleID, actor.TenantID).Scan(&articleExists, &generateStatus); err != nil {
|
||||
return nil, response.ErrInternal(50037, "article_check_failed", "failed to validate article")
|
||||
}
|
||||
if !articleExists {
|
||||
return nil, response.ErrNotFound(40411, "article_not_found", "article not found")
|
||||
}
|
||||
if generateStatus != "completed" {
|
||||
return nil, response.ErrConflict(40913, "article_not_publishable", "only completed articles can be published")
|
||||
articleMeta, err := loadPublishableArticleMeta(ctx, tx, actor.TenantID, articleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accountSeeds, err := loadPlatformAccountsForPublish(ctx, tx, actor.TenantID, req.PlatformAccountIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if publishBatchRequiresCover(accountSeeds) && strings.TrimSpace(pointerStringValue(req.CoverAssetURL)) == "" {
|
||||
coverAssetURL := normalizeStringPointer(req.CoverAssetURL)
|
||||
if publishBatchRequiresCover(accountSeeds) && strings.TrimSpace(pointerStringValue(coverAssetURL)) == "" {
|
||||
return nil, response.ErrBadRequest(40044, "publish_cover_required", "baijiahao publishing requires a cover image")
|
||||
}
|
||||
|
||||
var publishBatchID int64
|
||||
if err := tx.QueryRow(ctx, `
|
||||
INSERT INTO publish_batches (tenant_id, article_id, initiator_user_id, status, publish_type, cover_asset_url)
|
||||
VALUES ($1, $2, $3, 'publishing', $4, $5)
|
||||
RETURNING id
|
||||
`, actor.TenantID, articleID, actor.UserID, publishType, normalizeStringPointer(req.CoverAssetURL)).Scan(&publishBatchID); err != nil {
|
||||
return nil, response.ErrInternal(50038, "publish_batch_create_failed", "failed to create publish batch")
|
||||
if coverAssetURL == nil {
|
||||
coverAssetURL = articleMeta.CoverAssetURL
|
||||
}
|
||||
|
||||
publishBatchID, publishRecordIDs, err := createPublishBatchRecords(
|
||||
ctx,
|
||||
tx,
|
||||
actor.TenantID,
|
||||
actor.UserID,
|
||||
articleID,
|
||||
publishType,
|
||||
coverAssetURL,
|
||||
accountSeeds,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tasks := make([]PublishBatchTask, 0, len(accountSeeds))
|
||||
for _, account := range accountSeeds {
|
||||
var publishRecordID int64
|
||||
if err := tx.QueryRow(ctx, `
|
||||
INSERT INTO publish_records (
|
||||
tenant_id, publish_batch_id, article_id, platform_account_id, platform_id, status
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, 'queued')
|
||||
RETURNING id
|
||||
`, actor.TenantID, publishBatchID, articleID, account.ID, account.PlatformID).Scan(&publishRecordID); err != nil {
|
||||
return nil, response.ErrInternal(50039, "publish_record_create_failed", "failed to create publish record")
|
||||
}
|
||||
|
||||
token, tokenErr := newSessionToken()
|
||||
if tokenErr != nil {
|
||||
return nil, response.ErrInternal(50034, "session_token_failed", "failed to generate plugin session token")
|
||||
@@ -527,12 +516,12 @@ func (s *MediaService) CreatePublishBatch(ctx context.Context, articleID int64,
|
||||
)
|
||||
VALUES ($1, $2, $3, 'publish', 'publish_record', $4, $5, $6, $7, $8, 'pending')
|
||||
RETURNING id
|
||||
`, actor.TenantID, actor.UserID, req.PluginInstallationID, publishRecordID, account.ID, account.PlatformID, token, expireAt).Scan(&pluginSessionID); err != nil {
|
||||
`, actor.TenantID, actor.UserID, req.PluginInstallationID, publishRecordIDs[account.ID], account.ID, account.PlatformID, token, expireAt).Scan(&pluginSessionID); err != nil {
|
||||
return nil, response.ErrInternal(50040, "publish_session_create_failed", "failed to create publish session")
|
||||
}
|
||||
|
||||
tasks = append(tasks, PublishBatchTask{
|
||||
PublishRecordID: publishRecordID,
|
||||
PublishRecordID: publishRecordIDs[account.ID],
|
||||
PlatformAccountID: account.ID,
|
||||
PlatformID: account.PlatformID,
|
||||
PlatformName: account.PlatformName,
|
||||
@@ -544,14 +533,6 @@ func (s *MediaService) CreatePublishBatch(ctx context.Context, articleID int64,
|
||||
})
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(ctx, `
|
||||
UPDATE articles
|
||||
SET publish_status = 'publishing', updated_at = NOW()
|
||||
WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
|
||||
`, articleID, actor.TenantID); err != nil {
|
||||
return nil, response.ErrInternal(50041, "article_publish_status_failed", "failed to update article publish status")
|
||||
}
|
||||
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return nil, response.ErrInternal(50042, "publish_batch_commit_failed", "failed to commit publish batch")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user