93 lines
2.7 KiB
Go
93 lines
2.7 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/geo-platform/tenant-api/internal/shared/auditlog"
|
|
sharedcache "github.com/geo-platform/tenant-api/internal/shared/cache"
|
|
"github.com/geo-platform/tenant-api/internal/shared/objectstorage"
|
|
"github.com/geo-platform/tenant-api/internal/shared/response"
|
|
"github.com/geo-platform/tenant-api/internal/tenant/repository"
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type DesktopContentService struct {
|
|
articles *ArticleService
|
|
}
|
|
|
|
type DesktopArticleContentView struct {
|
|
ArticleID int64 `json:"article_id"`
|
|
Title string `json:"title"`
|
|
HTMLContent *string `json:"html_content"`
|
|
MarkdownContent *string `json:"markdown_content"`
|
|
CoverAssetURL *string `json:"cover_asset_url"`
|
|
}
|
|
|
|
func NewDesktopContentService(
|
|
pool *pgxpool.Pool,
|
|
auditLogs *auditlog.AsyncWriter,
|
|
objectStorage objectstorage.Client,
|
|
cache sharedcache.Cache,
|
|
) *DesktopContentService {
|
|
return &DesktopContentService{
|
|
articles: NewArticleService(pool, auditLogs, objectStorage).WithCache(cache),
|
|
}
|
|
}
|
|
|
|
func (s *DesktopContentService) Article(
|
|
ctx context.Context,
|
|
client *repository.DesktopClient,
|
|
articleID int64,
|
|
) (*DesktopArticleContentView, error) {
|
|
if client == nil {
|
|
return nil, response.ErrUnauthorized(40108, "desktop_client_missing", "desktop client context is required")
|
|
}
|
|
|
|
brandID, err := s.articleBrandID(ctx, client.TenantID, articleID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
detail, found, err := s.articles.loadArticleDetail(ctx, client.TenantID, brandID, articleID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !found || detail == nil {
|
|
return nil, response.ErrNotFound(40411, "article_not_found", "article not found")
|
|
}
|
|
|
|
title := ""
|
|
if detail.Title != nil {
|
|
title = *detail.Title
|
|
}
|
|
|
|
return &DesktopArticleContentView{
|
|
ArticleID: detail.ID,
|
|
Title: title,
|
|
HTMLContent: detail.HTMLContent,
|
|
MarkdownContent: detail.MarkdownContent,
|
|
CoverAssetURL: detail.CoverAssetURL,
|
|
}, nil
|
|
}
|
|
|
|
func (s *DesktopContentService) articleBrandID(ctx context.Context, tenantID, articleID int64) (int64, error) {
|
|
if s == nil || s.articles == nil || s.articles.pool == nil {
|
|
return 0, response.ErrInternal(50012, "article_lookup_unavailable", "article lookup is unavailable")
|
|
}
|
|
var brandID int64
|
|
if err := s.articles.pool.QueryRow(ctx, `
|
|
SELECT brand_id
|
|
FROM articles
|
|
WHERE id = $1
|
|
AND tenant_id = $2
|
|
AND deleted_at IS NULL
|
|
`, articleID, tenantID).Scan(&brandID); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return 0, response.ErrNotFound(40411, "article_not_found", "article not found")
|
|
}
|
|
return 0, response.ErrInternal(50010, "query_failed", "failed to load article")
|
|
}
|
|
return brandID, nil
|
|
}
|