fix: fire RecordSaved for tags the post API creates by name

journal-tag is a content type, but tags created on the fly from names in a
post write fired no event, so SEO and sitemap subscribers only heard of them
from a later bulk job. Each created tag now fires a RecordSaved with Created
inside the post write's transaction.
This commit is contained in:
2026-10-27 15:37:02 +01:00
parent 7a03640b88
commit a6fc7cd954
5 changed files with 76 additions and 19 deletions

View File

@@ -695,54 +695,59 @@ func asUintSlice(raw any) ([]uint, bool) {
}
}
func applyPostAssocs(ctx context.Context, db *gorm.DB, post *models.Post, body map[string]any) error {
// applyPostAssocs writes the post's categories, tags and translations the
// body submits. created are the tags the write created by name, for their
// record events.
func applyPostAssocs(ctx context.Context, db *gorm.DB, post *models.Post, body map[string]any) (created []models.Tag, err error) {
if _, has := body["categories"]; has {
ids, _ := asUintSlice(body["categories"])
if err := db.Where("post_id = ?", post.ID).Delete(&models.PostCategory{}).Error; err != nil {
return err
return nil, err
}
for _, id := range ids {
if err := db.Create(&models.PostCategory{PostID: post.ID, CategoryID: id}).Error; err != nil {
return err
return nil, err
}
}
}
if _, has := body["tags"]; has {
ids, err := resolveTagIDs(db, body["tags"])
var ids []uint
ids, created, err = resolveTagIDs(db, body["tags"])
if err != nil {
return err
return nil, err
}
if err := db.Where("post_id = ?", post.ID).Delete(&models.PostTag{}).Error; err != nil {
return err
return nil, err
}
for _, id := range ids {
if err := db.Create(&models.PostTag{PostID: post.ID, TagID: id}).Error; err != nil {
return err
return nil, err
}
}
}
if raw, has := body["translations"]; has {
if err := syncTranslations(ctx, db, post, raw); err != nil {
return err
return nil, err
}
}
return nil
return created, nil
}
func resolveTagIDs(db *gorm.DB, raw any) ([]uint, error) {
// resolveTagIDs turns the submitted tags (ids or names) into tag ids; a name
// no tag has yet creates the tag, returned in created.
func resolveTagIDs(db *gorm.DB, raw any) (ids []uint, created []models.Tag, err error) {
items, ok := raw.([]any)
if !ok {
if raw == nil {
return nil, nil
return nil, nil, nil
}
return nil, fmt.Errorf("tags must be an array")
return nil, nil, fmt.Errorf("tags must be an array")
}
var ids []uint
for _, item := range items {
if id, ok := asUint(item); ok {
var n int64
if err := db.Model(&models.Tag{}).Where("id = ?", id).Count(&n).Error; err != nil {
return nil, err
return nil, nil, err
}
if n > 0 {
ids = append(ids, id)
@@ -765,11 +770,12 @@ func resolveTagIDs(db *gorm.DB, raw any) ([]uint, error) {
}
tag = models.Tag{Name: name, Slug: slug}
if err := db.Create(&tag).Error; err != nil {
return nil, err
return nil, nil, err
}
ids = append(ids, tag.ID)
created = append(created, tag)
}
return ids, nil
return ids, created, nil
}
func syncTranslations(ctx context.Context, db *gorm.DB, post *models.Post, raw any) error {