feat(kol): repo support for cross-tenant revision lookup

This commit is contained in:
2026-04-17 14:51:54 +08:00
parent d0747825e6
commit 26bc8a3749
10 changed files with 156 additions and 20 deletions
@@ -8,9 +8,10 @@ import (
) )
type CreateArticleInput struct { type CreateArticleInput struct {
TenantID int64 TenantID int64
SourceType string SourceType string
TemplateID *int64 TemplateID *int64
KolPromptID *int64
} }
type CreateArticleVersionInput struct { type CreateArticleVersionInput struct {
@@ -41,9 +42,10 @@ func NewArticleRepository(db generated.DBTX) ArticleRepository {
func (r *articleRepository) CreateArticle(ctx context.Context, input CreateArticleInput) (int64, error) { func (r *articleRepository) CreateArticle(ctx context.Context, input CreateArticleInput) (int64, error) {
return r.q.CreateArticle(ctx, generated.CreateArticleParams{ return r.q.CreateArticle(ctx, generated.CreateArticleParams{
TenantID: input.TenantID, TenantID: input.TenantID,
SourceType: input.SourceType, SourceType: input.SourceType,
TemplateID: pgInt8(input.TemplateID), TemplateID: pgInt8(input.TemplateID),
KolPromptID: pgInt8(input.KolPromptID),
}) })
} }
@@ -27,9 +27,20 @@ type GenerationTaskInput struct {
ArticleID *int64 ArticleID *int64
QuotaReservationID *int64 QuotaReservationID *int64
TaskType string TaskType string
RequestHash *string
InputParamsJSON []byte InputParamsJSON []byte
} }
type TaskRecordInput struct {
TenantID int64
OperatorID int64
TaskType string
ResourceType string
ResourceID int64
Status string
ErrorMessage *string
}
type GenerationTaskStatusInput struct { type GenerationTaskStatusInput struct {
ID int64 ID int64
TenantID int64 TenantID int64
@@ -42,6 +53,8 @@ type GenerationTaskStatusInput struct {
type AuditRepository interface { type AuditRepository interface {
CreateAuditLog(ctx context.Context, input AuditLogInput) error CreateAuditLog(ctx context.Context, input AuditLogInput) error
CreateGenerationTask(ctx context.Context, input GenerationTaskInput) (int64, error) CreateGenerationTask(ctx context.Context, input GenerationTaskInput) (int64, error)
CreateTaskRecord(ctx context.Context, input TaskRecordInput) (int64, error)
UpdateTaskRecordStatus(ctx context.Context, input TaskRecordInput) error
UpdateGenerationTaskStatus(ctx context.Context, input GenerationTaskStatusInput) error UpdateGenerationTaskStatus(ctx context.Context, input GenerationTaskStatusInput) error
} }
@@ -80,10 +93,37 @@ func (r *auditRepository) CreateGenerationTask(ctx context.Context, input Genera
ArticleID: pgInt8(input.ArticleID), ArticleID: pgInt8(input.ArticleID),
QuotaReservationID: pgInt8(input.QuotaReservationID), QuotaReservationID: pgInt8(input.QuotaReservationID),
TaskType: input.TaskType, TaskType: input.TaskType,
RequestHash: pgText(input.RequestHash),
InputParamsJson: input.InputParamsJSON, InputParamsJson: input.InputParamsJSON,
}) })
} }
func (r *auditRepository) CreateTaskRecord(ctx context.Context, input TaskRecordInput) (int64, error) {
var operatorID *int64
if input.OperatorID > 0 {
operatorID = &input.OperatorID
}
return r.q.CreateTaskRecord(ctx, generated.CreateTaskRecordParams{
TenantID: input.TenantID,
OperatorID: pgInt8(operatorID),
TaskType: input.TaskType,
ResourceType: input.ResourceType,
ResourceID: input.ResourceID,
Status: input.Status,
})
}
func (r *auditRepository) UpdateTaskRecordStatus(ctx context.Context, input TaskRecordInput) error {
return r.q.UpdateTaskRecordStatus(ctx, generated.UpdateTaskRecordStatusParams{
Status: input.Status,
ErrorMessage: pgText(input.ErrorMessage),
TenantID: input.TenantID,
TaskType: input.TaskType,
ResourceType: input.ResourceType,
ResourceID: input.ResourceID,
})
}
func (r *auditRepository) UpdateGenerationTaskStatus(ctx context.Context, input GenerationTaskStatusInput) error { func (r *auditRepository) UpdateGenerationTaskStatus(ctx context.Context, input GenerationTaskStatusInput) error {
return r.q.UpdateGenerationTaskStatus(ctx, generated.UpdateGenerationTaskStatusParams{ return r.q.UpdateGenerationTaskStatus(ctx, generated.UpdateGenerationTaskStatusParams{
Status: input.Status, Status: input.Status,
@@ -48,19 +48,25 @@ func (q *Queries) CountArticles(ctx context.Context, arg CountArticlesParams) (i
} }
const createArticle = `-- name: CreateArticle :one const createArticle = `-- name: CreateArticle :one
INSERT INTO articles (tenant_id, source_type, template_id, generate_status, publish_status) INSERT INTO articles (tenant_id, source_type, template_id, kol_prompt_id, generate_status, publish_status)
VALUES ($1, $2, $3, 'pending', 'unpublished') VALUES ($1, $2, $3, $4, 'pending', 'unpublished')
RETURNING id RETURNING id
` `
type CreateArticleParams struct { type CreateArticleParams struct {
TenantID int64 `json:"tenant_id"` TenantID int64 `json:"tenant_id"`
SourceType string `json:"source_type"` SourceType string `json:"source_type"`
TemplateID pgtype.Int8 `json:"template_id"` TemplateID pgtype.Int8 `json:"template_id"`
KolPromptID pgtype.Int8 `json:"kol_prompt_id"`
} }
func (q *Queries) CreateArticle(ctx context.Context, arg CreateArticleParams) (int64, error) { func (q *Queries) CreateArticle(ctx context.Context, arg CreateArticleParams) (int64, error) {
row := q.db.QueryRow(ctx, createArticle, arg.TenantID, arg.SourceType, arg.TemplateID) row := q.db.QueryRow(ctx, createArticle,
arg.TenantID,
arg.SourceType,
arg.TemplateID,
arg.KolPromptID,
)
var id int64 var id int64
err := row.Scan(&id) err := row.Scan(&id)
return id, err return id, err
@@ -62,9 +62,9 @@ func (q *Queries) CreateAuditLog(ctx context.Context, arg CreateAuditLogParams)
} }
const createGenerationTask = `-- name: CreateGenerationTask :one const createGenerationTask = `-- name: CreateGenerationTask :one
INSERT INTO generation_tasks (tenant_id, operator_id, article_id, quota_reservation_id, task_type, input_params_json, status) INSERT INTO generation_tasks (tenant_id, operator_id, article_id, quota_reservation_id, task_type, request_hash, input_params_json, status)
VALUES ($1, $2, $3, $4, VALUES ($1, $2, $3, $4,
$5, $6, 'queued') $5, $6, $7, 'queued')
RETURNING id RETURNING id
` `
@@ -74,6 +74,7 @@ type CreateGenerationTaskParams struct {
ArticleID pgtype.Int8 `json:"article_id"` ArticleID pgtype.Int8 `json:"article_id"`
QuotaReservationID pgtype.Int8 `json:"quota_reservation_id"` QuotaReservationID pgtype.Int8 `json:"quota_reservation_id"`
TaskType string `json:"task_type"` TaskType string `json:"task_type"`
RequestHash pgtype.Text `json:"request_hash"`
InputParamsJson []byte `json:"input_params_json"` InputParamsJson []byte `json:"input_params_json"`
} }
@@ -84,6 +85,7 @@ func (q *Queries) CreateGenerationTask(ctx context.Context, arg CreateGeneration
arg.ArticleID, arg.ArticleID,
arg.QuotaReservationID, arg.QuotaReservationID,
arg.TaskType, arg.TaskType,
arg.RequestHash,
arg.InputParamsJson, arg.InputParamsJson,
) )
var id int64 var id int64
@@ -91,6 +93,36 @@ func (q *Queries) CreateGenerationTask(ctx context.Context, arg CreateGeneration
return id, err return id, err
} }
const createTaskRecord = `-- name: CreateTaskRecord :one
INSERT INTO task_records (tenant_id, operator_id, task_type, resource_type, resource_id, status)
VALUES ($1, $2, $3,
$4, $5, $6)
RETURNING id
`
type CreateTaskRecordParams struct {
TenantID int64 `json:"tenant_id"`
OperatorID pgtype.Int8 `json:"operator_id"`
TaskType string `json:"task_type"`
ResourceType string `json:"resource_type"`
ResourceID int64 `json:"resource_id"`
Status string `json:"status"`
}
func (q *Queries) CreateTaskRecord(ctx context.Context, arg CreateTaskRecordParams) (int64, error) {
row := q.db.QueryRow(ctx, createTaskRecord,
arg.TenantID,
arg.OperatorID,
arg.TaskType,
arg.ResourceType,
arg.ResourceID,
arg.Status,
)
var id int64
err := row.Scan(&id)
return id, err
}
const updateGenerationTaskStatus = `-- name: UpdateGenerationTaskStatus :exec const updateGenerationTaskStatus = `-- name: UpdateGenerationTaskStatus :exec
UPDATE generation_tasks SET status = $1, error_message = $2, UPDATE generation_tasks SET status = $1, error_message = $2,
started_at = $3, completed_at = $4, updated_at = NOW() started_at = $3, completed_at = $4, updated_at = NOW()
@@ -117,3 +149,35 @@ func (q *Queries) UpdateGenerationTaskStatus(ctx context.Context, arg UpdateGene
) )
return err return err
} }
const updateTaskRecordStatus = `-- name: UpdateTaskRecordStatus :exec
UPDATE task_records
SET status = $1,
error_message = $2,
updated_at = NOW()
WHERE tenant_id = $3
AND task_type = $4
AND resource_type = $5
AND resource_id = $6
`
type UpdateTaskRecordStatusParams struct {
Status string `json:"status"`
ErrorMessage pgtype.Text `json:"error_message"`
TenantID int64 `json:"tenant_id"`
TaskType string `json:"task_type"`
ResourceType string `json:"resource_type"`
ResourceID int64 `json:"resource_id"`
}
func (q *Queries) UpdateTaskRecordStatus(ctx context.Context, arg UpdateTaskRecordStatusParams) error {
_, err := q.db.Exec(ctx, updateTaskRecordStatus,
arg.Status,
arg.ErrorMessage,
arg.TenantID,
arg.TaskType,
arg.ResourceType,
arg.ResourceID,
)
return err
}
@@ -182,7 +182,8 @@ SELECT sp.id, sp.tenant_id, sp.subscription_id, sp.package_id, sp.prompt_id,
s.status AS subscription_status, s.end_at AS subscription_end_at, s.status AS subscription_status, s.end_at AS subscription_end_at,
p.name AS prompt_name, p.platform_hint, p.status AS prompt_status, p.name AS prompt_name, p.platform_hint, p.status AS prompt_status,
p.published_revision_no, p.published_revision_no,
k.name AS package_name, k.status AS package_status k.name AS package_name, k.status AS package_status,
k.tenant_id AS creator_tenant_id
FROM kol_subscription_prompts sp FROM kol_subscription_prompts sp
JOIN kol_subscriptions s ON s.id = sp.subscription_id JOIN kol_subscriptions s ON s.id = sp.subscription_id
JOIN kol_prompts p ON p.id = sp.prompt_id AND p.deleted_at IS NULL JOIN kol_prompts p ON p.id = sp.prompt_id AND p.deleted_at IS NULL
@@ -213,6 +214,7 @@ type GetSubscriptionPromptByIDRow struct {
PublishedRevisionNo pgtype.Int4 `json:"published_revision_no"` PublishedRevisionNo pgtype.Int4 `json:"published_revision_no"`
PackageName string `json:"package_name"` PackageName string `json:"package_name"`
PackageStatus string `json:"package_status"` PackageStatus string `json:"package_status"`
CreatorTenantID int64 `json:"creator_tenant_id"`
} }
func (q *Queries) GetSubscriptionPromptByID(ctx context.Context, arg GetSubscriptionPromptByIDParams) (GetSubscriptionPromptByIDRow, error) { func (q *Queries) GetSubscriptionPromptByID(ctx context.Context, arg GetSubscriptionPromptByIDParams) (GetSubscriptionPromptByIDRow, error) {
@@ -235,6 +237,7 @@ func (q *Queries) GetSubscriptionPromptByID(ctx context.Context, arg GetSubscrip
&i.PublishedRevisionNo, &i.PublishedRevisionNo,
&i.PackageName, &i.PackageName,
&i.PackageStatus, &i.PackageStatus,
&i.CreatorTenantID,
) )
return i, err return i, err
} }
@@ -42,6 +42,7 @@ type Querier interface {
CreateQuotaReservation(ctx context.Context, arg CreateQuotaReservationParams) (int64, error) CreateQuotaReservation(ctx context.Context, arg CreateQuotaReservationParams) (int64, error)
CreateScheduleTask(ctx context.Context, arg CreateScheduleTaskParams) (CreateScheduleTaskRow, error) CreateScheduleTask(ctx context.Context, arg CreateScheduleTaskParams) (CreateScheduleTaskRow, error)
CreateSubscriptionPrompt(ctx context.Context, arg CreateSubscriptionPromptParams) error CreateSubscriptionPrompt(ctx context.Context, arg CreateSubscriptionPromptParams) error
CreateTaskRecord(ctx context.Context, arg CreateTaskRecordParams) (int64, error)
DeleteImageFolder(ctx context.Context, arg DeleteImageFolderParams) error DeleteImageFolder(ctx context.Context, arg DeleteImageFolderParams) error
DeleteImageReferencesByArticle(ctx context.Context, arg DeleteImageReferencesByArticleParams) error DeleteImageReferencesByArticle(ctx context.Context, arg DeleteImageReferencesByArticleParams) error
DeleteImageReferencesByArticleScope(ctx context.Context, arg DeleteImageReferencesByArticleScopeParams) error DeleteImageReferencesByArticleScope(ctx context.Context, arg DeleteImageReferencesByArticleScopeParams) error
@@ -172,6 +173,7 @@ type Querier interface {
UpdateQuotaReservationResource(ctx context.Context, arg UpdateQuotaReservationResourceParams) error UpdateQuotaReservationResource(ctx context.Context, arg UpdateQuotaReservationResourceParams) error
UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error
UpdateScheduleTaskStatus(ctx context.Context, arg UpdateScheduleTaskStatusParams) error UpdateScheduleTaskStatus(ctx context.Context, arg UpdateScheduleTaskStatusParams) error
UpdateTaskRecordStatus(ctx context.Context, arg UpdateTaskRecordStatusParams) error
UpsertImageReference(ctx context.Context, arg UpsertImageReferenceParams) error UpsertImageReference(ctx context.Context, arg UpsertImageReferenceParams) error
} }
@@ -42,6 +42,7 @@ type KolSubscriptionPrompt struct {
SubscriptionEndAt *time.Time SubscriptionEndAt *time.Time
PromptStatus string PromptStatus string
PackageStatus string PackageStatus string
CreatorTenantID int64
} }
type CreateAccessRowInput struct { type CreateAccessRowInput struct {
@@ -253,6 +254,7 @@ func (r *kolSubscriptionRepository) GetSubscriptionPromptByID(ctx context.Contex
SubscriptionEndAt: subEndAt, SubscriptionEndAt: subEndAt,
PromptStatus: row.PromptStatus, PromptStatus: row.PromptStatus,
PackageStatus: row.PackageStatus, PackageStatus: row.PackageStatus,
CreatorTenantID: row.CreatorTenantID,
}, nil }, nil
} }
@@ -45,8 +45,8 @@ WHERE article_id = sqlc.arg(article_id)
ORDER BY version_no DESC; ORDER BY version_no DESC;
-- name: CreateArticle :one -- name: CreateArticle :one
INSERT INTO articles (tenant_id, source_type, template_id, generate_status, publish_status) INSERT INTO articles (tenant_id, source_type, template_id, kol_prompt_id, generate_status, publish_status)
VALUES (sqlc.arg(tenant_id), sqlc.arg(source_type), sqlc.arg(template_id), 'pending', 'unpublished') VALUES (sqlc.arg(tenant_id), sqlc.arg(source_type), sqlc.arg(template_id), sqlc.arg(kol_prompt_id), 'pending', 'unpublished')
RETURNING id; RETURNING id;
-- name: CreateArticleVersion :one -- name: CreateArticleVersion :one
@@ -17,11 +17,27 @@ VALUES (sqlc.arg(operator_id), sqlc.arg(tenant_id), sqlc.arg(module), sqlc.arg(a
sqlc.arg(before_json), sqlc.arg(after_json), sqlc.arg(result), sqlc.arg(error_message)); sqlc.arg(before_json), sqlc.arg(after_json), sqlc.arg(result), sqlc.arg(error_message));
-- name: CreateGenerationTask :one -- name: CreateGenerationTask :one
INSERT INTO generation_tasks (tenant_id, operator_id, article_id, quota_reservation_id, task_type, input_params_json, status) INSERT INTO generation_tasks (tenant_id, operator_id, article_id, quota_reservation_id, task_type, request_hash, input_params_json, status)
VALUES (sqlc.arg(tenant_id), sqlc.arg(operator_id), sqlc.arg(article_id), sqlc.arg(quota_reservation_id), VALUES (sqlc.arg(tenant_id), sqlc.arg(operator_id), sqlc.arg(article_id), sqlc.arg(quota_reservation_id),
sqlc.arg(task_type), sqlc.arg(input_params_json), 'queued') sqlc.arg(task_type), sqlc.arg(request_hash), sqlc.arg(input_params_json), 'queued')
RETURNING id; RETURNING id;
-- name: CreateTaskRecord :one
INSERT INTO task_records (tenant_id, operator_id, task_type, resource_type, resource_id, status)
VALUES (sqlc.arg(tenant_id), sqlc.arg(operator_id), sqlc.arg(task_type),
sqlc.arg(resource_type), sqlc.arg(resource_id), sqlc.arg(status))
RETURNING id;
-- name: UpdateTaskRecordStatus :exec
UPDATE task_records
SET status = sqlc.arg(status),
error_message = sqlc.arg(error_message),
updated_at = NOW()
WHERE tenant_id = sqlc.arg(tenant_id)
AND task_type = sqlc.arg(task_type)
AND resource_type = sqlc.arg(resource_type)
AND resource_id = sqlc.arg(resource_id);
-- name: UpdateGenerationTaskStatus :exec -- name: UpdateGenerationTaskStatus :exec
UPDATE generation_tasks SET status = sqlc.arg(status), error_message = sqlc.arg(error_message), UPDATE generation_tasks SET status = sqlc.arg(status), error_message = sqlc.arg(error_message),
started_at = sqlc.arg(started_at), completed_at = sqlc.arg(completed_at), updated_at = NOW() started_at = sqlc.arg(started_at), completed_at = sqlc.arg(completed_at), updated_at = NOW()
@@ -94,7 +94,8 @@ SELECT sp.id, sp.tenant_id, sp.subscription_id, sp.package_id, sp.prompt_id,
s.status AS subscription_status, s.end_at AS subscription_end_at, s.status AS subscription_status, s.end_at AS subscription_end_at,
p.name AS prompt_name, p.platform_hint, p.status AS prompt_status, p.name AS prompt_name, p.platform_hint, p.status AS prompt_status,
p.published_revision_no, p.published_revision_no,
k.name AS package_name, k.status AS package_status k.name AS package_name, k.status AS package_status,
k.tenant_id AS creator_tenant_id
FROM kol_subscription_prompts sp FROM kol_subscription_prompts sp
JOIN kol_subscriptions s ON s.id = sp.subscription_id JOIN kol_subscriptions s ON s.id = sp.subscription_id
JOIN kol_prompts p ON p.id = sp.prompt_id AND p.deleted_at IS NULL JOIN kol_prompts p ON p.id = sp.prompt_id AND p.deleted_at IS NULL