package pages import ( "context" "time" "lmika.dev/lmika/weiro/models" "lmika.dev/lmika/weiro/providers/db" "lmika.dev/lmika/weiro/services/publisher" ) type CreatePageParams struct { GUID string `form:"guid" json:"guid"` Title string `form:"title" json:"title"` Slug string `form:"slug" json:"slug"` Body string `form:"body" json:"body"` PageType int `form:"page_type" json:"page_type"` ShowInNav bool `form:"show_in_nav" json:"show_in_nav"` } type Service struct { db *db.Provider publisher *publisher.Queue } func New(db *db.Provider, publisher *publisher.Queue) *Service { return &Service{db: db, publisher: publisher} } func (s *Service) ListPages(ctx context.Context) ([]*models.Page, error) { site, ok := models.GetSite(ctx) if !ok { return nil, models.SiteRequiredError } return s.db.SelectPagesOfSite(ctx, site.ID) } func (s *Service) GetPage(ctx context.Context, id int64) (*models.Page, error) { site, ok := models.GetSite(ctx) if !ok { return nil, models.SiteRequiredError } page, err := s.db.SelectPage(ctx, id) if err != nil { return nil, err } if page.SiteID != site.ID { return nil, models.NotFoundError } return page, nil } func (s *Service) CreatePage(ctx context.Context, params CreatePageParams) (*models.Page, error) { site, ok := models.GetSite(ctx) if !ok { return nil, models.SiteRequiredError } now := time.Now() slug := params.Slug if slug == "" { slug = models.GeneratePageSlug(params.Title) } // Check slug collision if _, err := s.db.SelectPageBySlugAndSite(ctx, site.ID, slug); err == nil { return nil, models.SlugConflictError } else if !db.ErrorIsNoRows(err) { return nil, err } // Determine sort order: place at end existingPages, err := s.db.SelectPagesOfSite(ctx, site.ID) if err != nil { return nil, err } sortOrder := len(existingPages) page := &models.Page{ SiteID: site.ID, GUID: params.GUID, Title: params.Title, Slug: slug, Body: params.Body, PageType: params.PageType, ShowInNav: params.ShowInNav, SortOrder: sortOrder, CreatedAt: now, UpdatedAt: now, } if page.GUID == "" { page.GUID = models.NewNanoID() } if err := s.db.SavePage(ctx, page); err != nil { return nil, err } s.publisher.Queue(site) return page, nil } func (s *Service) UpdatePage(ctx context.Context, id int64, params CreatePageParams) (*models.Page, error) { site, ok := models.GetSite(ctx) if !ok { return nil, models.SiteRequiredError } page, err := s.db.SelectPage(ctx, id) if err != nil { return nil, err } if page.SiteID != site.ID { return nil, models.NotFoundError } slug := params.Slug if slug == "" { slug = models.GeneratePageSlug(params.Title) } // Check slug collision (exclude self) if existing, err := s.db.SelectPageBySlugAndSite(ctx, site.ID, slug); err == nil && existing.ID != page.ID { return nil, models.SlugConflictError } else if err != nil && !db.ErrorIsNoRows(err) { return nil, err } page.Title = params.Title page.Slug = slug page.Body = params.Body page.PageType = params.PageType page.ShowInNav = params.ShowInNav page.UpdatedAt = time.Now() if err := s.db.SavePage(ctx, page); err != nil { return nil, err } s.publisher.Queue(site) return page, nil } func (s *Service) DeletePage(ctx context.Context, id int64) error { site, ok := models.GetSite(ctx) if !ok { return models.SiteRequiredError } page, err := s.db.SelectPage(ctx, id) if err != nil { return err } if page.SiteID != site.ID { return models.NotFoundError } if err := s.db.DeletePage(ctx, id); err != nil { return err } s.publisher.Queue(site) return nil } func (s *Service) ReorderPages(ctx context.Context, pageIDs []int64) error { site, ok := models.GetSite(ctx) if !ok { return models.SiteRequiredError } // Verify all pages belong to this site for i, id := range pageIDs { page, err := s.db.SelectPage(ctx, id) if err != nil { return err } if page.SiteID != site.ID { return models.NotFoundError } if err := s.db.UpdatePageSortOrder(ctx, id, i); err != nil { return err } } s.publisher.Queue(site) return nil }