143 lines
4.4 KiB
Go
143 lines
4.4 KiB
Go
package page
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gocql/gocql"
|
|
"go.uber.org/zap"
|
|
|
|
domainpage "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/page"
|
|
pageusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/page"
|
|
)
|
|
|
|
// SyncPagesService handles page synchronization operations
|
|
type SyncPagesService interface {
|
|
SyncPages(ctx context.Context, tenantID, siteID gocql.UUID, input *pageusecase.SyncPagesInput) (*pageusecase.SyncPagesOutput, error)
|
|
}
|
|
|
|
type syncPagesService struct {
|
|
// Focused usecases
|
|
validateSiteUC *pageusecase.ValidateSiteUseCase
|
|
ensureIndexUC *pageusecase.EnsureSearchIndexUseCase
|
|
createPageUC *pageusecase.CreatePageEntityUseCase
|
|
upsertPageUC *pageusecase.UpsertPageUseCase
|
|
indexPageUC *pageusecase.IndexPageToSearchUseCase
|
|
updateUsageUC *pageusecase.UpdateSiteUsageUseCase
|
|
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewSyncPagesService creates a new SyncPagesService
|
|
func NewSyncPagesService(
|
|
validateSiteUC *pageusecase.ValidateSiteUseCase,
|
|
ensureIndexUC *pageusecase.EnsureSearchIndexUseCase,
|
|
createPageUC *pageusecase.CreatePageEntityUseCase,
|
|
upsertPageUC *pageusecase.UpsertPageUseCase,
|
|
indexPageUC *pageusecase.IndexPageToSearchUseCase,
|
|
updateUsageUC *pageusecase.UpdateSiteUsageUseCase,
|
|
logger *zap.Logger,
|
|
) SyncPagesService {
|
|
return &syncPagesService{
|
|
validateSiteUC: validateSiteUC,
|
|
ensureIndexUC: ensureIndexUC,
|
|
createPageUC: createPageUC,
|
|
upsertPageUC: upsertPageUC,
|
|
indexPageUC: indexPageUC,
|
|
updateUsageUC: updateUsageUC,
|
|
logger: logger.Named("sync-pages-service"),
|
|
}
|
|
}
|
|
|
|
// SyncPages orchestrates the page synchronization workflow
|
|
func (s *syncPagesService) SyncPages(ctx context.Context, tenantID, siteID gocql.UUID, input *pageusecase.SyncPagesInput) (*pageusecase.SyncPagesOutput, error) {
|
|
s.logger.Info("syncing pages",
|
|
zap.String("tenant_id", tenantID.String()),
|
|
zap.String("site_id", siteID.String()),
|
|
zap.Int("page_count", len(input.Pages)))
|
|
|
|
// Step 1: Validate site (no quota check - usage-based billing)
|
|
site, err := s.validateSiteUC.Execute(ctx, tenantID, siteID)
|
|
if err != nil {
|
|
s.logger.Error("failed to validate site", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Step 2: Ensure search index exists
|
|
if err := s.ensureIndexUC.Execute(ctx, siteID); err != nil {
|
|
s.logger.Error("failed to ensure search index", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Step 3: Process pages (create, save, prepare for indexing)
|
|
syncedCount, failedPages, pagesToIndex := s.processPages(ctx, siteID, site.TenantID, input.Pages)
|
|
|
|
// Step 4: Bulk index pages to search
|
|
indexedCount, err := s.indexPageUC.Execute(ctx, siteID, pagesToIndex)
|
|
if err != nil {
|
|
s.logger.Error("failed to index pages", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Step 5: Update site usage tracking (for billing)
|
|
if indexedCount > 0 {
|
|
if err := s.updateUsageUC.Execute(ctx, site, indexedCount); err != nil {
|
|
s.logger.Warn("failed to update usage (non-fatal)", zap.Error(err))
|
|
// Don't fail the whole operation
|
|
}
|
|
}
|
|
|
|
// Step 6: Build output
|
|
message := fmt.Sprintf("Successfully synced %d pages, indexed %d pages", syncedCount, indexedCount)
|
|
if len(failedPages) > 0 {
|
|
message += fmt.Sprintf(", failed %d pages", len(failedPages))
|
|
}
|
|
|
|
s.logger.Info("pages synced successfully",
|
|
zap.String("site_id", siteID.String()),
|
|
zap.Int("synced", syncedCount),
|
|
zap.Int("indexed", indexedCount),
|
|
zap.Int("failed", len(failedPages)))
|
|
|
|
return &pageusecase.SyncPagesOutput{
|
|
SyncedCount: syncedCount,
|
|
IndexedCount: indexedCount,
|
|
FailedPages: failedPages,
|
|
Message: message,
|
|
}, nil
|
|
}
|
|
|
|
// Helper: Process pages - create entities, save to DB, collect pages to index
|
|
func (s *syncPagesService) processPages(
|
|
ctx context.Context,
|
|
siteID, tenantID gocql.UUID,
|
|
pages []pageusecase.SyncPageInput,
|
|
) (int, []string, []*domainpage.Page) {
|
|
syncedCount := 0
|
|
var failedPages []string
|
|
var pagesToIndex []*domainpage.Page
|
|
|
|
for _, pageInput := range pages {
|
|
// Create page entity (usecase)
|
|
page, err := s.createPageUC.Execute(siteID, tenantID, pageInput)
|
|
if err != nil {
|
|
failedPages = append(failedPages, pageInput.PageID)
|
|
continue
|
|
}
|
|
|
|
// Save to database (usecase)
|
|
if err := s.upsertPageUC.Execute(ctx, page); err != nil {
|
|
failedPages = append(failedPages, pageInput.PageID)
|
|
continue
|
|
}
|
|
|
|
syncedCount++
|
|
|
|
// Collect pages that should be indexed
|
|
if page.ShouldIndex() {
|
|
pagesToIndex = append(pagesToIndex, page)
|
|
}
|
|
}
|
|
|
|
return syncedCount, failedPages, pagesToIndex
|
|
}
|