weiro/services/posts/create.go
Leon Mika 4c2ce7272d feat: add category selection to post edit form and badges to post list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 21:45:28 +11:00

114 lines
2.5 KiB
Go

package posts
import (
"context"
"strings"
"time"
"lmika.dev/lmika/weiro/models"
"lmika.dev/lmika/weiro/providers/db"
)
type CreatePostParams struct {
GUID string `form:"guid" json:"guid"`
Title string `form:"title" json:"title"`
Body string `form:"body" json:"body"`
Action string `form:"action" json:"action"`
CategoryIDs []int64 `form:"category_ids" json:"category_ids"`
}
func (s *Service) UpdatePost(ctx context.Context, params CreatePostParams) (*models.Post, error) {
now := time.Now()
site, ok := models.GetSite(ctx)
if !ok {
return nil, models.SiteRequiredError
}
post, err := s.fetchOrCreatePost(ctx, site, params)
if err != nil {
return nil, err
}
post.Title = params.Title
post.Body = params.Body
post.UpdatedAt = now
oldState := post.State
switch strings.ToLower(params.Action) {
case "publish":
post.State = models.StatePublished
// Set the published at with the site timezone, and reset the slug, so that the date
// is in the site timezone.
renderTZ, err := time.LoadLocation(site.Timezone)
if err != nil {
renderTZ = time.UTC
}
post.PublishedAt = now.In(renderTZ)
post.Slug = post.BestSlug()
case "save draft":
post.State = models.StateDraft
post.PublishedAt = time.Time{}
default:
// Leave unchanged
}
// Use a transaction for atomicity of post save + category reassignment
tx, err := s.db.BeginTx(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()
txDB := s.db.QueriesWithTx(tx)
if err := txDB.SavePost(ctx, post); err != nil {
return nil, err
}
if err := txDB.SetPostCategories(ctx, post.ID, params.CategoryIDs); err != nil {
return nil, err
}
if err := tx.Commit(); err != nil {
return nil, err
}
if oldState != post.State || post.State == models.StatePublished {
s.publisher.Queue(site)
}
return post, nil
}
func (s *Service) fetchOrCreatePost(ctx context.Context, site models.Site, params CreatePostParams) (*models.Post, error) {
post, err := s.db.SelectPostByGUID(ctx, params.GUID)
if err == nil {
if post.SiteID != site.ID {
return nil, models.NotFoundError
}
return post, nil
} else if !db.ErrorIsNoRows(err) {
return nil, err
}
post = &models.Post{
SiteID: site.ID,
GUID: params.GUID,
Title: params.Title,
Body: params.Body,
State: models.StateDraft,
CreatedAt: time.Now(),
}
return post, nil
}
// TEMP - to move
func (s *Service) RebuildSite(ctx context.Context) error {
site, ok := models.GetSite(ctx)
if !ok {
return models.SiteRequiredError
}
s.publisher.Queue(site)
return nil
}