feat: add image_url attribute and handle method

This commit is contained in:
Buravit Yenjit 2025-04-03 23:36:17 +07:00
parent 8af97c0150
commit 5eec21a2b1
4 changed files with 48 additions and 24 deletions

View File

@ -81,13 +81,14 @@ type GetKnowledgeArticleByIDOutput struct {
type CreateOrUpdateKnowledgeArticleInput struct {
Body struct {
UUID string `json:"uuid,omitempty"` // Optional for create, required for update
UUID string `json:"uuid,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Author string `json:"author"`
PublishDate time.Time `json:"publish_date"`
ReadTime string `json:"read_time"`
Categories []string `json:"categories"`
ImageURL string `json:"image_url"`
} `json:"body"`
}
@ -130,7 +131,7 @@ func (a *api) getAllKnowledgeArticlesHandler(ctx context.Context, input *struct{
}
func (a *api) getKnowledgeArticleByIDHandler(ctx context.Context, input *struct {
UUID string `path:"uuid" example:"550e8400-e29b-41d4-a716-446655440000"`
UUID string `path:"uuid"`
}) (*GetKnowledgeArticleByIDOutput, error) {
resp := &GetKnowledgeArticleByIDOutput{}
@ -138,8 +139,7 @@ func (a *api) getKnowledgeArticleByIDHandler(ctx context.Context, input *struct
return nil, huma.Error400BadRequest("UUID parameter is required")
}
_, err := uuid.FromString(input.UUID)
if err != nil {
if _, err := uuid.FromString(input.UUID); err != nil {
return nil, huma.Error400BadRequest("invalid UUID format")
}
@ -156,7 +156,7 @@ func (a *api) getKnowledgeArticleByIDHandler(ctx context.Context, input *struct
}
func (a *api) getKnowledgeArticlesByCategoryHandler(ctx context.Context, input *struct {
Category string `path:"category" example:"Sustainability"`
Category string `path:"category"`
}) (*GetKnowledgeArticlesOutput, error) {
resp := &GetKnowledgeArticlesOutput{}
@ -190,8 +190,7 @@ func (a *api) createOrUpdateKnowledgeArticleHandler(ctx context.Context, input *
}
if input.Body.UUID != "" {
_, err := uuid.FromString(input.Body.UUID)
if err != nil {
if _, err := uuid.FromString(input.Body.UUID); err != nil {
return nil, huma.Error400BadRequest("invalid UUID format")
}
}
@ -204,10 +203,10 @@ func (a *api) createOrUpdateKnowledgeArticleHandler(ctx context.Context, input *
PublishDate: input.Body.PublishDate,
ReadTime: input.Body.ReadTime,
Categories: input.Body.Categories,
ImageURL: input.Body.ImageURL,
}
err := a.knowledgeHubRepo.CreateOrUpdateArticle(ctx, article)
if err != nil {
if err := a.knowledgeHubRepo.CreateOrUpdateArticle(ctx, article); err != nil {
return nil, err
}
@ -216,7 +215,7 @@ func (a *api) createOrUpdateKnowledgeArticleHandler(ctx context.Context, input *
}
func (a *api) getArticleTableOfContentsHandler(ctx context.Context, input *struct {
UUID string `path:"uuid" example:"550e8400-e29b-41d4-a716-446655440000"`
UUID string `path:"uuid"`
}) (*GetTableOfContentsOutput, error) {
resp := &GetTableOfContentsOutput{}
@ -224,8 +223,7 @@ func (a *api) getArticleTableOfContentsHandler(ctx context.Context, input *struc
return nil, huma.Error400BadRequest("UUID parameter is required")
}
_, err := uuid.FromString(input.UUID)
if err != nil {
if _, err := uuid.FromString(input.UUID); err != nil {
return nil, huma.Error400BadRequest("invalid UUID format")
}
@ -242,7 +240,7 @@ func (a *api) getArticleTableOfContentsHandler(ctx context.Context, input *struc
}
func (a *api) getArticleRelatedArticlesHandler(ctx context.Context, input *struct {
UUID string `path:"uuid" example:"550e8400-e29b-41d4-a716-446655440000"`
UUID string `path:"uuid"`
}) (*GetRelatedArticlesOutput, error) {
resp := &GetRelatedArticlesOutput{}
@ -250,8 +248,7 @@ func (a *api) getArticleRelatedArticlesHandler(ctx context.Context, input *struc
return nil, huma.Error400BadRequest("UUID parameter is required")
}
_, err := uuid.FromString(input.UUID)
if err != nil {
if _, err := uuid.FromString(input.UUID); err != nil {
return nil, huma.Error400BadRequest("invalid UUID format")
}
@ -286,5 +283,5 @@ func (a *api) createRelatedArticleHandler(
return nil, huma.Error500InternalServerError("failed to create related article")
}
return nil, nil // HTTP 204 No Content
return nil, nil
}

View File

@ -2,6 +2,8 @@ package domain
import (
"context"
"fmt"
"strings"
"time"
validation "github.com/go-ozzo/ozzo-validation/v4"
@ -15,6 +17,7 @@ type KnowledgeArticle struct {
PublishDate time.Time
ReadTime string
Categories []string
ImageURL string
CreatedAt time.Time
UpdatedAt time.Time
}
@ -25,6 +28,16 @@ func (k *KnowledgeArticle) Validate() error {
validation.Field(&k.Content, validation.Required),
validation.Field(&k.Author, validation.Required),
validation.Field(&k.PublishDate, validation.Required),
validation.Field(&k.ImageURL,
validation.By(func(value interface{}) error {
if url, ok := value.(string); ok && url != "" {
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
return fmt.Errorf("must be a valid URL starting with http:// or https://")
}
}
return nil
}),
),
)
}

View File

@ -34,6 +34,7 @@ func (p *postgresKnowledgeHubRepository) fetchArticles(ctx context.Context, quer
&a.PublishDate,
&a.ReadTime,
&a.Categories,
&a.ImageURL,
&a.CreatedAt,
&a.UpdatedAt,
); err != nil {
@ -46,7 +47,7 @@ func (p *postgresKnowledgeHubRepository) fetchArticles(ctx context.Context, quer
func (p *postgresKnowledgeHubRepository) GetArticleByID(ctx context.Context, uuid string) (domain.KnowledgeArticle, error) {
query := `
SELECT uuid, title, content, author, publish_date, read_time, categories, created_at, updated_at
SELECT uuid, title, content, author, publish_date, read_time, categories, image_url, created_at, updated_at
FROM knowledge_articles
WHERE uuid = $1`
@ -62,7 +63,7 @@ func (p *postgresKnowledgeHubRepository) GetArticleByID(ctx context.Context, uui
func (p *postgresKnowledgeHubRepository) GetArticlesByCategory(ctx context.Context, category string) ([]domain.KnowledgeArticle, error) {
query := `
SELECT uuid, title, content, author, publish_date, read_time, categories, created_at, updated_at
SELECT uuid, title, content, author, publish_date, read_time, categories, image_url, created_at, updated_at
FROM knowledge_articles
WHERE $1 = ANY(categories)`
@ -71,20 +72,24 @@ func (p *postgresKnowledgeHubRepository) GetArticlesByCategory(ctx context.Conte
func (p *postgresKnowledgeHubRepository) GetAllArticles(ctx context.Context) ([]domain.KnowledgeArticle, error) {
query := `
SELECT uuid, title, content, author, publish_date, read_time, categories, created_at, updated_at
SELECT uuid, title, content, author, publish_date, read_time, categories, image_url, created_at, updated_at
FROM knowledge_articles`
return p.fetchArticles(ctx, query)
}
func (p *postgresKnowledgeHubRepository) CreateOrUpdateArticle(ctx context.Context, article *domain.KnowledgeArticle) error {
func (p *postgresKnowledgeHubRepository) CreateOrUpdateArticle(
ctx context.Context,
article *domain.KnowledgeArticle,
) error {
if strings.TrimSpace(article.UUID) == "" {
article.UUID = uuid.New().String()
}
query := `
INSERT INTO knowledge_articles (uuid, title, content, author, publish_date, read_time, categories, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
INSERT INTO knowledge_articles
(uuid, title, content, author, publish_date, read_time, categories, image_url, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
ON CONFLICT (uuid) DO UPDATE
SET title = EXCLUDED.title,
content = EXCLUDED.content,
@ -92,6 +97,7 @@ func (p *postgresKnowledgeHubRepository) CreateOrUpdateArticle(ctx context.Conte
publish_date = EXCLUDED.publish_date,
read_time = EXCLUDED.read_time,
categories = EXCLUDED.categories,
image_url = EXCLUDED.image_url,
updated_at = NOW()
RETURNING uuid, created_at, updated_at`
@ -105,6 +111,7 @@ func (p *postgresKnowledgeHubRepository) CreateOrUpdateArticle(ctx context.Conte
article.PublishDate,
article.ReadTime,
article.Categories,
article.ImageURL,
).Scan(&article.UUID, &article.CreatedAt, &article.UpdatedAt)
}
@ -188,8 +195,8 @@ func (p *postgresKnowledgeHubRepository) CreateRelatedArticle(
articleID string,
related *domain.RelatedArticle,
) error {
related.UUID = uuid.New().String() // Generate UUID
related.ArticleID = articleID // Link to main article
related.UUID = uuid.New().String()
related.ArticleID = articleID
query := `
INSERT INTO related_articles

View File

@ -0,0 +1,7 @@
-- +goose Up
ALTER TABLE knowledge_articles
ADD COLUMN image_url TEXT;
-- +goose Down
ALTER TABLE knowledge_articles
DROP COLUMN image_url;