package page import ( "context" "fmt" "github.com/gocql/gocql" "go.uber.org/zap" pageusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/page" ) // DeletePagesService handles page deletion operations type DeletePagesService interface { DeletePages(ctx context.Context, tenantID, siteID gocql.UUID, input *pageusecase.DeletePagesInput) (*pageusecase.DeletePagesOutput, error) DeleteAllPages(ctx context.Context, tenantID, siteID gocql.UUID) (*pageusecase.DeletePagesOutput, error) } type deletePagesService struct { // Focused usecases validateSiteUC *pageusecase.ValidateSiteForDeletionUseCase deletePagesRepoUC *pageusecase.DeletePagesFromRepoUseCase deletePagesSearchUC *pageusecase.DeletePagesFromSearchUseCase logger *zap.Logger } // NewDeletePagesService creates a new DeletePagesService func NewDeletePagesService( validateSiteUC *pageusecase.ValidateSiteForDeletionUseCase, deletePagesRepoUC *pageusecase.DeletePagesFromRepoUseCase, deletePagesSearchUC *pageusecase.DeletePagesFromSearchUseCase, logger *zap.Logger, ) DeletePagesService { return &deletePagesService{ validateSiteUC: validateSiteUC, deletePagesRepoUC: deletePagesRepoUC, deletePagesSearchUC: deletePagesSearchUC, logger: logger.Named("delete-pages-service"), } } // DeletePages orchestrates the deletion of specific pages func (s *deletePagesService) DeletePages(ctx context.Context, tenantID, siteID gocql.UUID, input *pageusecase.DeletePagesInput) (*pageusecase.DeletePagesOutput, error) { s.logger.Info("deleting pages", zap.String("tenant_id", tenantID.String()), zap.String("site_id", siteID.String()), zap.Int("page_count", len(input.PageIDs))) // Step 1: Validate 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: Delete pages from database deleteResult, err := s.deletePagesRepoUC.Execute(ctx, siteID, input.PageIDs) if err != nil { s.logger.Error("failed to delete pages from database", zap.Error(err)) return nil, err } // Step 3: Delete pages from search index (only if database delete succeeded) deindexedCount := 0 if deleteResult.DeletedCount > 0 { // Only delete pages that were successfully deleted from database successfulPageIDs := s.getSuccessfulPageIDs(input.PageIDs, deleteResult.FailedPages) if len(successfulPageIDs) > 0 { deindexedCount, _ = s.deletePagesSearchUC.Execute(ctx, siteID, successfulPageIDs) } } // Step 4: Build output message := fmt.Sprintf("Successfully deleted %d pages from database, removed %d from search index", deleteResult.DeletedCount, deindexedCount) if len(deleteResult.FailedPages) > 0 { message += fmt.Sprintf(", failed %d pages", len(deleteResult.FailedPages)) } s.logger.Info("pages deleted successfully", zap.String("site_id", siteID.String()), zap.Int("deleted", deleteResult.DeletedCount), zap.Int("deindexed", deindexedCount), zap.Int("failed", len(deleteResult.FailedPages))) return &pageusecase.DeletePagesOutput{ DeletedCount: deleteResult.DeletedCount, DeindexedCount: deindexedCount, FailedPages: deleteResult.FailedPages, Message: message, }, nil } // DeleteAllPages orchestrates the deletion of all pages for a site func (s *deletePagesService) DeleteAllPages(ctx context.Context, tenantID, siteID gocql.UUID) (*pageusecase.DeletePagesOutput, error) { s.logger.Info("deleting all pages", zap.String("tenant_id", tenantID.String()), zap.String("site_id", siteID.String())) // Step 1: Validate 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: Delete all pages from database count, err := s.deletePagesRepoUC.ExecuteDeleteAll(ctx, siteID) if err != nil { s.logger.Error("failed to delete all pages from database", zap.Error(err)) return nil, err } // Step 3: Delete all documents from search index _ = s.deletePagesSearchUC.ExecuteDeleteAll(ctx, siteID) s.logger.Info("all pages deleted successfully", zap.String("site_id", siteID.String()), zap.Int64("count", count)) return &pageusecase.DeletePagesOutput{ DeletedCount: int(count), DeindexedCount: int(count), Message: fmt.Sprintf("Successfully deleted all %d pages", count), }, nil } // Helper: Get list of page IDs that were successfully deleted (exclude failed ones) func (s *deletePagesService) getSuccessfulPageIDs(allPageIDs, failedPageIDs []string) []string { if len(failedPageIDs) == 0 { return allPageIDs } failedMap := make(map[string]bool, len(failedPageIDs)) for _, id := range failedPageIDs { failedMap[id] = true } successful := make([]string, 0, len(allPageIDs)-len(failedPageIDs)) for _, id := range allPageIDs { if !failedMap[id] { successful = append(successful, id) } } return successful }