feat: scope articles by brand
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
type CreateArticleInput struct {
|
||||
TenantID int64
|
||||
BrandID int64
|
||||
SourceType string
|
||||
TemplateID *int64
|
||||
KolPromptID *int64
|
||||
@@ -45,6 +46,7 @@ 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,
|
||||
BrandID: input.BrandID,
|
||||
SourceType: input.SourceType,
|
||||
TemplateID: pgInt8(input.TemplateID),
|
||||
KolPromptID: pgInt8(input.KolPromptID),
|
||||
|
||||
@@ -48,13 +48,14 @@ func (q *Queries) CountArticles(ctx context.Context, arg CountArticlesParams) (i
|
||||
}
|
||||
|
||||
const createArticle = `-- name: CreateArticle :one
|
||||
INSERT INTO articles (tenant_id, source_type, template_id, kol_prompt_id, generate_status, publish_status)
|
||||
VALUES ($1, $2, $3, $4, 'pending', 'unpublished')
|
||||
INSERT INTO articles (tenant_id, brand_id, source_type, template_id, kol_prompt_id, generate_status, publish_status)
|
||||
VALUES ($1, $2, $3, $4, $5, 'pending', 'unpublished')
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
type CreateArticleParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
BrandID int64 `json:"brand_id"`
|
||||
SourceType string `json:"source_type"`
|
||||
TemplateID pgtype.Int8 `json:"template_id"`
|
||||
KolPromptID pgtype.Int8 `json:"kol_prompt_id"`
|
||||
@@ -63,6 +64,7 @@ type CreateArticleParams struct {
|
||||
func (q *Queries) CreateArticle(ctx context.Context, arg CreateArticleParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, createArticle,
|
||||
arg.TenantID,
|
||||
arg.BrandID,
|
||||
arg.SourceType,
|
||||
arg.TemplateID,
|
||||
arg.KolPromptID,
|
||||
|
||||
@@ -56,6 +56,7 @@ type Article struct {
|
||||
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
||||
WizardStateJson []byte `json:"wizard_state_json"`
|
||||
KolPromptID pgtype.Int8 `json:"kol_prompt_id"`
|
||||
BrandID int64 `json:"brand_id"`
|
||||
}
|
||||
|
||||
type ArticleTemplate struct {
|
||||
@@ -435,6 +436,21 @@ type KnowledgeChunksMetum struct {
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
}
|
||||
|
||||
type KnowledgeDeletedCleanupEvent struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
KnowledgeItemID int64 `json:"knowledge_item_id"`
|
||||
Status string `json:"status"`
|
||||
AttemptCount int32 `json:"attempt_count"`
|
||||
AvailableAt pgtype.Timestamptz `json:"available_at"`
|
||||
LockedBy pgtype.Text `json:"locked_by"`
|
||||
LockedAt pgtype.Timestamptz `json:"locked_at"`
|
||||
LastError pgtype.Text `json:"last_error"`
|
||||
CompletedAt pgtype.Timestamptz `json:"completed_at"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
}
|
||||
|
||||
type KnowledgeGroup struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
|
||||
@@ -19,13 +19,13 @@ type Querier interface {
|
||||
ConfirmReservation(ctx context.Context, arg ConfirmReservationParams) error
|
||||
CountActiveImagesInFolder(ctx context.Context, arg CountActiveImagesInFolderParams) (int32, error)
|
||||
CountArticles(ctx context.Context, arg CountArticlesParams) (int64, error)
|
||||
CountArticlesByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountArticlesByTenantAndBrand(ctx context.Context, arg CountArticlesByTenantAndBrandParams) (int64, error)
|
||||
CountBrandsByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountImageAssets(ctx context.Context, arg CountImageAssetsParams) (int32, error)
|
||||
CountImageReferences(ctx context.Context, arg CountImageReferencesParams) (int32, error)
|
||||
CountPromptRules(ctx context.Context, arg CountPromptRulesParams) (int64, error)
|
||||
CountPromptRulesUngrouped(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountPublishedArticlesByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountPublishedArticlesByTenantAndBrand(ctx context.Context, arg CountPublishedArticlesByTenantAndBrandParams) (int64, error)
|
||||
CountScheduleTasks(ctx context.Context, arg CountScheduleTasksParams) (int64, error)
|
||||
CountUncategorizedImages(ctx context.Context, tenantID int64) (int32, error)
|
||||
CreateArticle(ctx context.Context, arg CreateArticleParams) (int64, error)
|
||||
@@ -86,7 +86,7 @@ type Querier interface {
|
||||
GetPromptRuleByID(ctx context.Context, arg GetPromptRuleByIDParams) (GetPromptRuleByIDRow, error)
|
||||
GetPublishedKolPackage(ctx context.Context, id int64) (GetPublishedKolPackageRow, error)
|
||||
GetQuotaSummary(ctx context.Context, tenantID int64) (int32, error)
|
||||
GetRecentArticles(ctx context.Context, tenantID int64) ([]GetRecentArticlesRow, error)
|
||||
GetRecentArticlesByBrand(ctx context.Context, arg GetRecentArticlesByBrandParams) ([]GetRecentArticlesByBrandRow, error)
|
||||
GetScheduleTaskByID(ctx context.Context, arg GetScheduleTaskByIDParams) (GetScheduleTaskByIDRow, error)
|
||||
GetSubscriptionPromptByID(ctx context.Context, arg GetSubscriptionPromptByIDParams) (GetSubscriptionPromptByIDRow, error)
|
||||
GetTemplateByID(ctx context.Context, arg GetTemplateByIDParams) (GetTemplateByIDRow, error)
|
||||
|
||||
@@ -11,13 +11,18 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const countArticlesByTenant = `-- name: CountArticlesByTenant :one
|
||||
const countArticlesByTenantAndBrand = `-- name: CountArticlesByTenantAndBrand :one
|
||||
SELECT COUNT(*) FROM articles
|
||||
WHERE tenant_id = $1 AND deleted_at IS NULL
|
||||
WHERE tenant_id = $1 AND brand_id = $2 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
func (q *Queries) CountArticlesByTenant(ctx context.Context, tenantID int64) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countArticlesByTenant, tenantID)
|
||||
type CountArticlesByTenantAndBrandParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
BrandID int64 `json:"brand_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CountArticlesByTenantAndBrand(ctx context.Context, arg CountArticlesByTenantAndBrandParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countArticlesByTenantAndBrand, arg.TenantID, arg.BrandID)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
@@ -35,13 +40,18 @@ func (q *Queries) CountBrandsByTenant(ctx context.Context, tenantID int64) (int6
|
||||
return count, err
|
||||
}
|
||||
|
||||
const countPublishedArticlesByTenant = `-- name: CountPublishedArticlesByTenant :one
|
||||
const countPublishedArticlesByTenantAndBrand = `-- name: CountPublishedArticlesByTenantAndBrand :one
|
||||
SELECT COUNT(*) FROM articles
|
||||
WHERE tenant_id = $1 AND publish_status = 'success' AND deleted_at IS NULL
|
||||
WHERE tenant_id = $1 AND brand_id = $2 AND publish_status = 'success' AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
func (q *Queries) CountPublishedArticlesByTenant(ctx context.Context, tenantID int64) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countPublishedArticlesByTenant, tenantID)
|
||||
type CountPublishedArticlesByTenantAndBrandParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
BrandID int64 `json:"brand_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CountPublishedArticlesByTenantAndBrand(ctx context.Context, arg CountPublishedArticlesByTenantAndBrandParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countPublishedArticlesByTenantAndBrand, arg.TenantID, arg.BrandID)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
@@ -93,8 +103,8 @@ func (q *Queries) GetQuotaSummary(ctx context.Context, tenantID int64) (int32, e
|
||||
return balance, err
|
||||
}
|
||||
|
||||
const getRecentArticles = `-- name: GetRecentArticles :many
|
||||
SELECT a.id, a.generate_status, a.publish_status, a.source_type, a.created_at,
|
||||
const getRecentArticlesByBrand = `-- name: GetRecentArticlesByBrand :many
|
||||
SELECT a.id, a.brand_id, a.generate_status, a.publish_status, a.source_type, a.created_at,
|
||||
av.title, av.markdown_content, av.word_count, av.source_label,
|
||||
t.template_name,
|
||||
COALESCE(
|
||||
@@ -111,13 +121,19 @@ LEFT JOIN LATERAL (
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
) gt ON true
|
||||
WHERE a.tenant_id = $1 AND a.deleted_at IS NULL
|
||||
WHERE a.tenant_id = $1 AND a.brand_id = $2 AND a.deleted_at IS NULL
|
||||
ORDER BY a.created_at DESC
|
||||
LIMIT 10
|
||||
`
|
||||
|
||||
type GetRecentArticlesRow struct {
|
||||
type GetRecentArticlesByBrandParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
BrandID int64 `json:"brand_id"`
|
||||
}
|
||||
|
||||
type GetRecentArticlesByBrandRow struct {
|
||||
ID int64 `json:"id"`
|
||||
BrandID int64 `json:"brand_id"`
|
||||
GenerateStatus string `json:"generate_status"`
|
||||
PublishStatus string `json:"publish_status"`
|
||||
SourceType string `json:"source_type"`
|
||||
@@ -130,17 +146,18 @@ type GetRecentArticlesRow struct {
|
||||
GenerationMode interface{} `json:"generation_mode"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetRecentArticles(ctx context.Context, tenantID int64) ([]GetRecentArticlesRow, error) {
|
||||
rows, err := q.db.Query(ctx, getRecentArticles, tenantID)
|
||||
func (q *Queries) GetRecentArticlesByBrand(ctx context.Context, arg GetRecentArticlesByBrandParams) ([]GetRecentArticlesByBrandRow, error) {
|
||||
rows, err := q.db.Query(ctx, getRecentArticlesByBrand, arg.TenantID, arg.BrandID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetRecentArticlesRow
|
||||
var items []GetRecentArticlesByBrandRow
|
||||
for rows.Next() {
|
||||
var i GetRecentArticlesRow
|
||||
var i GetRecentArticlesByBrandRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.BrandID,
|
||||
&i.GenerateStatus,
|
||||
&i.PublishStatus,
|
||||
&i.SourceType,
|
||||
|
||||
@@ -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, 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')
|
||||
INSERT INTO articles (tenant_id, brand_id, source_type, template_id, kol_prompt_id, generate_status, publish_status)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(brand_id), sqlc.arg(source_type), sqlc.arg(template_id), sqlc.arg(kol_prompt_id), 'pending', 'unpublished')
|
||||
RETURNING id;
|
||||
|
||||
-- name: CreateArticleVersion :one
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
-- name: CountArticlesByTenant :one
|
||||
-- name: CountArticlesByTenantAndBrand :one
|
||||
SELECT COUNT(*) FROM articles
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND brand_id = sqlc.arg(brand_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: CountPublishedArticlesByTenant :one
|
||||
-- name: CountPublishedArticlesByTenantAndBrand :one
|
||||
SELECT COUNT(*) FROM articles
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND publish_status = 'success' AND deleted_at IS NULL;
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND brand_id = sqlc.arg(brand_id) AND publish_status = 'success' AND deleted_at IS NULL;
|
||||
|
||||
-- name: CountBrandsByTenant :one
|
||||
SELECT COUNT(*) FROM brands
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: GetRecentArticles :many
|
||||
SELECT a.id, a.generate_status, a.publish_status, a.source_type, a.created_at,
|
||||
-- name: GetRecentArticlesByBrand :many
|
||||
SELECT a.id, a.brand_id, a.generate_status, a.publish_status, a.source_type, a.created_at,
|
||||
av.title, av.markdown_content, av.word_count, av.source_label,
|
||||
t.template_name,
|
||||
COALESCE(
|
||||
@@ -28,7 +28,7 @@ LEFT JOIN LATERAL (
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
) gt ON true
|
||||
WHERE a.tenant_id = sqlc.arg(tenant_id) AND a.deleted_at IS NULL
|
||||
WHERE a.tenant_id = sqlc.arg(tenant_id) AND a.brand_id = sqlc.arg(brand_id) AND a.deleted_at IS NULL
|
||||
ORDER BY a.created_at DESC
|
||||
LIMIT 10;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
type WorkspaceRecentArticle struct {
|
||||
ID int64
|
||||
BrandID *int64
|
||||
GenerateStatus string
|
||||
PublishStatus string
|
||||
SourceType string
|
||||
@@ -40,10 +41,10 @@ type WorkspaceKolCard struct {
|
||||
}
|
||||
|
||||
type WorkspaceRepository interface {
|
||||
CountArticlesByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountPublishedArticlesByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountArticlesByTenantAndBrand(ctx context.Context, tenantID, brandID int64) (int64, error)
|
||||
CountPublishedArticlesByTenantAndBrand(ctx context.Context, tenantID, brandID int64) (int64, error)
|
||||
CountBrandsByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
GetRecentArticles(ctx context.Context, tenantID int64) ([]WorkspaceRecentArticle, error)
|
||||
GetRecentArticlesByBrand(ctx context.Context, tenantID, brandID int64) ([]WorkspaceRecentArticle, error)
|
||||
GetQuotaSummary(ctx context.Context, tenantID int64) (int, error)
|
||||
GetActivePlanForTenant(ctx context.Context, tenantID int64) (*WorkspacePlan, error)
|
||||
ListKolCards(ctx context.Context, tenantID int64) ([]WorkspaceKolCard, error)
|
||||
@@ -57,28 +58,39 @@ func NewWorkspaceRepository(db generated.DBTX) WorkspaceRepository {
|
||||
return &workspaceRepository{q: newQuerier(db)}
|
||||
}
|
||||
|
||||
func (r *workspaceRepository) CountArticlesByTenant(ctx context.Context, tenantID int64) (int64, error) {
|
||||
return r.q.CountArticlesByTenant(ctx, tenantID)
|
||||
func (r *workspaceRepository) CountArticlesByTenantAndBrand(ctx context.Context, tenantID, brandID int64) (int64, error) {
|
||||
return r.q.CountArticlesByTenantAndBrand(ctx, generated.CountArticlesByTenantAndBrandParams{
|
||||
TenantID: tenantID,
|
||||
BrandID: brandID,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *workspaceRepository) CountPublishedArticlesByTenant(ctx context.Context, tenantID int64) (int64, error) {
|
||||
return r.q.CountPublishedArticlesByTenant(ctx, tenantID)
|
||||
func (r *workspaceRepository) CountPublishedArticlesByTenantAndBrand(ctx context.Context, tenantID, brandID int64) (int64, error) {
|
||||
return r.q.CountPublishedArticlesByTenantAndBrand(ctx, generated.CountPublishedArticlesByTenantAndBrandParams{
|
||||
TenantID: tenantID,
|
||||
BrandID: brandID,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *workspaceRepository) CountBrandsByTenant(ctx context.Context, tenantID int64) (int64, error) {
|
||||
return r.q.CountBrandsByTenant(ctx, tenantID)
|
||||
}
|
||||
|
||||
func (r *workspaceRepository) GetRecentArticles(ctx context.Context, tenantID int64) ([]WorkspaceRecentArticle, error) {
|
||||
rows, err := r.q.GetRecentArticles(ctx, tenantID)
|
||||
func (r *workspaceRepository) GetRecentArticlesByBrand(ctx context.Context, tenantID, brandID int64) ([]WorkspaceRecentArticle, error) {
|
||||
rows, err := r.q.GetRecentArticlesByBrand(ctx, generated.GetRecentArticlesByBrandParams{
|
||||
TenantID: tenantID,
|
||||
BrandID: brandID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
articles := make([]WorkspaceRecentArticle, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
brandID := row.BrandID
|
||||
articles = append(articles, WorkspaceRecentArticle{
|
||||
ID: row.ID,
|
||||
BrandID: &brandID,
|
||||
GenerateStatus: row.GenerateStatus,
|
||||
PublishStatus: row.PublishStatus,
|
||||
SourceType: row.SourceType,
|
||||
|
||||
Reference in New Issue
Block a user