diff --git a/server/internal/tenant/repository/article_repo.go b/server/internal/tenant/repository/article_repo.go index 285210a..bbe5091 100644 --- a/server/internal/tenant/repository/article_repo.go +++ b/server/internal/tenant/repository/article_repo.go @@ -8,9 +8,10 @@ import ( ) type CreateArticleInput struct { - TenantID int64 - SourceType string - TemplateID *int64 + TenantID int64 + SourceType string + TemplateID *int64 + KolPromptID *int64 } type CreateArticleVersionInput struct { @@ -41,9 +42,10 @@ func NewArticleRepository(db generated.DBTX) ArticleRepository { func (r *articleRepository) CreateArticle(ctx context.Context, input CreateArticleInput) (int64, error) { return r.q.CreateArticle(ctx, generated.CreateArticleParams{ - TenantID: input.TenantID, - SourceType: input.SourceType, - TemplateID: pgInt8(input.TemplateID), + TenantID: input.TenantID, + SourceType: input.SourceType, + TemplateID: pgInt8(input.TemplateID), + KolPromptID: pgInt8(input.KolPromptID), }) } diff --git a/server/internal/tenant/repository/audit_repo.go b/server/internal/tenant/repository/audit_repo.go index 7dac2c9..ea56163 100644 --- a/server/internal/tenant/repository/audit_repo.go +++ b/server/internal/tenant/repository/audit_repo.go @@ -27,9 +27,20 @@ type GenerationTaskInput struct { ArticleID *int64 QuotaReservationID *int64 TaskType string + RequestHash *string InputParamsJSON []byte } +type TaskRecordInput struct { + TenantID int64 + OperatorID int64 + TaskType string + ResourceType string + ResourceID int64 + Status string + ErrorMessage *string +} + type GenerationTaskStatusInput struct { ID int64 TenantID int64 @@ -42,6 +53,8 @@ type GenerationTaskStatusInput struct { type AuditRepository interface { CreateAuditLog(ctx context.Context, input AuditLogInput) 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 } @@ -80,10 +93,37 @@ func (r *auditRepository) CreateGenerationTask(ctx context.Context, input Genera ArticleID: pgInt8(input.ArticleID), QuotaReservationID: pgInt8(input.QuotaReservationID), TaskType: input.TaskType, + RequestHash: pgText(input.RequestHash), 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 { return r.q.UpdateGenerationTaskStatus(ctx, generated.UpdateGenerationTaskStatusParams{ Status: input.Status, diff --git a/server/internal/tenant/repository/generated/article.sql.go b/server/internal/tenant/repository/generated/article.sql.go index 3363ed8..69eaaa5 100644 --- a/server/internal/tenant/repository/generated/article.sql.go +++ b/server/internal/tenant/repository/generated/article.sql.go @@ -48,19 +48,25 @@ func (q *Queries) CountArticles(ctx context.Context, arg CountArticlesParams) (i } const createArticle = `-- name: CreateArticle :one -INSERT INTO articles (tenant_id, source_type, template_id, generate_status, publish_status) -VALUES ($1, $2, $3, 'pending', 'unpublished') +INSERT INTO articles (tenant_id, source_type, template_id, kol_prompt_id, generate_status, publish_status) +VALUES ($1, $2, $3, $4, 'pending', 'unpublished') RETURNING id ` type CreateArticleParams struct { - TenantID int64 `json:"tenant_id"` - SourceType string `json:"source_type"` - TemplateID pgtype.Int8 `json:"template_id"` + TenantID int64 `json:"tenant_id"` + SourceType string `json:"source_type"` + TemplateID pgtype.Int8 `json:"template_id"` + KolPromptID pgtype.Int8 `json:"kol_prompt_id"` } 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 err := row.Scan(&id) return id, err diff --git a/server/internal/tenant/repository/generated/audit.sql.go b/server/internal/tenant/repository/generated/audit.sql.go index 3befbfd..3e11b47 100644 --- a/server/internal/tenant/repository/generated/audit.sql.go +++ b/server/internal/tenant/repository/generated/audit.sql.go @@ -62,9 +62,9 @@ func (q *Queries) CreateAuditLog(ctx context.Context, arg CreateAuditLogParams) } 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, - $5, $6, 'queued') + $5, $6, $7, 'queued') RETURNING id ` @@ -74,6 +74,7 @@ type CreateGenerationTaskParams struct { ArticleID pgtype.Int8 `json:"article_id"` QuotaReservationID pgtype.Int8 `json:"quota_reservation_id"` TaskType string `json:"task_type"` + RequestHash pgtype.Text `json:"request_hash"` InputParamsJson []byte `json:"input_params_json"` } @@ -84,6 +85,7 @@ func (q *Queries) CreateGenerationTask(ctx context.Context, arg CreateGeneration arg.ArticleID, arg.QuotaReservationID, arg.TaskType, + arg.RequestHash, arg.InputParamsJson, ) var id int64 @@ -91,6 +93,36 @@ func (q *Queries) CreateGenerationTask(ctx context.Context, arg CreateGeneration 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 UPDATE generation_tasks SET status = $1, error_message = $2, started_at = $3, completed_at = $4, updated_at = NOW() @@ -117,3 +149,35 @@ func (q *Queries) UpdateGenerationTaskStatus(ctx context.Context, arg UpdateGene ) 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 +} diff --git a/server/internal/tenant/repository/generated/kol_subscription.sql.go b/server/internal/tenant/repository/generated/kol_subscription.sql.go index 5e8deda..3b10c16 100644 --- a/server/internal/tenant/repository/generated/kol_subscription.sql.go +++ b/server/internal/tenant/repository/generated/kol_subscription.sql.go @@ -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, p.name AS prompt_name, p.platform_hint, p.status AS prompt_status, 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 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 @@ -213,6 +214,7 @@ type GetSubscriptionPromptByIDRow struct { PublishedRevisionNo pgtype.Int4 `json:"published_revision_no"` PackageName string `json:"package_name"` PackageStatus string `json:"package_status"` + CreatorTenantID int64 `json:"creator_tenant_id"` } 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.PackageName, &i.PackageStatus, + &i.CreatorTenantID, ) return i, err } diff --git a/server/internal/tenant/repository/generated/querier.go b/server/internal/tenant/repository/generated/querier.go index 94cfa1c..77af5e1 100644 --- a/server/internal/tenant/repository/generated/querier.go +++ b/server/internal/tenant/repository/generated/querier.go @@ -42,6 +42,7 @@ type Querier interface { CreateQuotaReservation(ctx context.Context, arg CreateQuotaReservationParams) (int64, error) CreateScheduleTask(ctx context.Context, arg CreateScheduleTaskParams) (CreateScheduleTaskRow, error) CreateSubscriptionPrompt(ctx context.Context, arg CreateSubscriptionPromptParams) error + CreateTaskRecord(ctx context.Context, arg CreateTaskRecordParams) (int64, error) DeleteImageFolder(ctx context.Context, arg DeleteImageFolderParams) error DeleteImageReferencesByArticle(ctx context.Context, arg DeleteImageReferencesByArticleParams) error DeleteImageReferencesByArticleScope(ctx context.Context, arg DeleteImageReferencesByArticleScopeParams) error @@ -172,6 +173,7 @@ type Querier interface { UpdateQuotaReservationResource(ctx context.Context, arg UpdateQuotaReservationResourceParams) error UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error UpdateScheduleTaskStatus(ctx context.Context, arg UpdateScheduleTaskStatusParams) error + UpdateTaskRecordStatus(ctx context.Context, arg UpdateTaskRecordStatusParams) error UpsertImageReference(ctx context.Context, arg UpsertImageReferenceParams) error } diff --git a/server/internal/tenant/repository/kol_subscription_repo.go b/server/internal/tenant/repository/kol_subscription_repo.go index ee97585..2114303 100644 --- a/server/internal/tenant/repository/kol_subscription_repo.go +++ b/server/internal/tenant/repository/kol_subscription_repo.go @@ -42,6 +42,7 @@ type KolSubscriptionPrompt struct { SubscriptionEndAt *time.Time PromptStatus string PackageStatus string + CreatorTenantID int64 } type CreateAccessRowInput struct { @@ -253,6 +254,7 @@ func (r *kolSubscriptionRepository) GetSubscriptionPromptByID(ctx context.Contex SubscriptionEndAt: subEndAt, PromptStatus: row.PromptStatus, PackageStatus: row.PackageStatus, + CreatorTenantID: row.CreatorTenantID, }, nil } diff --git a/server/internal/tenant/repository/queries/article.sql b/server/internal/tenant/repository/queries/article.sql index 6bfb5a7..4760b2f 100644 --- a/server/internal/tenant/repository/queries/article.sql +++ b/server/internal/tenant/repository/queries/article.sql @@ -45,8 +45,8 @@ WHERE article_id = sqlc.arg(article_id) ORDER BY version_no DESC; -- name: CreateArticle :one -INSERT INTO articles (tenant_id, source_type, template_id, generate_status, publish_status) -VALUES (sqlc.arg(tenant_id), sqlc.arg(source_type), sqlc.arg(template_id), 'pending', 'unpublished') +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), sqlc.arg(kol_prompt_id), 'pending', 'unpublished') RETURNING id; -- name: CreateArticleVersion :one diff --git a/server/internal/tenant/repository/queries/audit.sql b/server/internal/tenant/repository/queries/audit.sql index d388b8a..8e6d61f 100644 --- a/server/internal/tenant/repository/queries/audit.sql +++ b/server/internal/tenant/repository/queries/audit.sql @@ -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)); -- 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), - 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; +-- 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 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() diff --git a/server/internal/tenant/repository/queries/kol_subscription.sql b/server/internal/tenant/repository/queries/kol_subscription.sql index 35681a9..041e0e0 100644 --- a/server/internal/tenant/repository/queries/kol_subscription.sql +++ b/server/internal/tenant/repository/queries/kol_subscription.sql @@ -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, p.name AS prompt_name, p.platform_hint, p.status AS prompt_status, 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 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