feat: Authors feature backend (and upgraded deprecated mods)

This commit is contained in:
Florian Sylvain committed 2026-10-14 17:45:00 +02:00
1 parent a11338094e
commit b34a173d83
103 files changed
+6454 -240

No files matched your search

+38 -9
View File
@@ -5,6 +5,7 @@ import (
"RenewCMS/api/pkg/claims"
validator "RenewCMS/api/pkg/validator"
domain "RenewCMS/internal/domain/article"
"RenewCMS/internal/domain/author"
"RenewCMS/internal/domain/site"
"RenewCMS/internal/infrastructure/useCases"
"encoding/json"
@@ -53,6 +54,7 @@ type articleResponse struct {
BodyFormat domain.BodyFormat `json:"body_format"`
IsOnline bool `json:"is_online"`
SiteID uint32 `json:"site_id"`
Authors []author.Byline `json:"authors"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
@@ -66,6 +68,10 @@ func toArticleResponse(article domain.Article, format domain.BodyFormat) (articl
}
body = encoded
}
authors := article.Authors
if authors == nil {
authors = []author.Byline{}
}
return articleResponse{
ID: article.ID,
Title: article.Title,
@@ -73,6 +79,7 @@ func toArticleResponse(article domain.Article, format domain.BodyFormat) (articl
BodyFormat: format,
IsOnline: article.IsOnline,
SiteID: article.SiteID,
Authors: authors,
CreatedAt: article.CreatedAt,
UpdatedAt: article.UpdatedAt,
}, nil
@@ -155,10 +162,12 @@ func (h *Handler) PostArticle(w http.ResponseWriter, r *http.Request) {
return
}
creatorId, _ := claims.UserId(r)
createdArticle, err := h.CreateUseCase.CreateArticle(r.Context(), useCases.CreateArticleCommand{
Title: localArticle.Title,
Body: localArticle.Body,
Format: format,
Title: localArticle.Title,
Body: localArticle.Body,
Format: format,
CreatedBy: creatorId,
})
if err != nil {
if errors.Is(err, domain.ErrInvalidTitle) {
@@ -181,6 +190,10 @@ func writeArticleErrorResponse(w http.ResponseWriter, err error) {
http.Error(w, apperr.SiteNotFoundErrorMessage, http.StatusNotFound)
return
}
if errors.Is(err, author.ErrAuthorNotFound) {
http.Error(w, apperr.AuthorNotFoundErrorMessage, http.StatusNotFound)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
@@ -221,11 +234,23 @@ func (h *Handler) setIsOnline(w http.ResponseWriter, r *http.Request, isOnline b
}
type UpdateArticleBody struct {
Body *string `json:"body"`
SiteID *uint32 `json:"site_id" validate:"omitempty,gte=1"`
Body *string `json:"body"`
SiteID *uint32 `json:"site_id" validate:"omitempty,gte=1"`
AuthorIDs *[]uint32 `json:"author_ids" validate:"omitempty,dive,gte=1"`
}
var updatableArticleFields = []string{"body", "site_id"}
var updatableArticleFields = []string{"body", "site_id", "author_ids"}
func hasDuplicates(ids []uint32) bool {
seen := make(map[uint32]bool, len(ids))
for _, id := range ids {
if seen[id] {
return true
}
seen[id] = true
}
return false
}
func readUpdateArticleBody(r *http.Request) (UpdateArticleBody, bool) {
raw, err := io.ReadAll(r.Body)
@@ -254,6 +279,9 @@ func readUpdateArticleBody(r *http.Request) (UpdateArticleBody, bool) {
if err := json.Unmarshal(raw, &request); err != nil {
return UpdateArticleBody{}, false
}
if request.AuthorIDs != nil && hasDuplicates(*request.AuthorIDs) {
return UpdateArticleBody{}, false
}
return request, true
}
@@ -281,9 +309,10 @@ func (h *Handler) UpdateArticleBody(w http.ResponseWriter, r *http.Request) {
}
updatedArticle, err := h.UpdateUseCase.Update(r.Context(), id, useCases.UpdateArticleCommand{
Body: request.Body,
SiteID: request.SiteID,
Format: format,
Body: request.Body,
SiteID: request.SiteID,
AuthorIDs: request.AuthorIDs,
Format: format,
})
if err != nil {
writeArticleErrorResponse(w, err)