package bookmark import ( "context" "errors" "tercul/internal/domain" ) // BookmarkCommands contains the command handlers for the bookmark aggregate. type BookmarkCommands struct { repo domain.BookmarkRepository analyticsService AnalyticsService } // AnalyticsService defines the interface for analytics operations. type AnalyticsService interface { IncrementWorkBookmarks(ctx context.Context, workID uint) error } // NewBookmarkCommands creates a new BookmarkCommands handler. func NewBookmarkCommands(repo domain.BookmarkRepository, analyticsService AnalyticsService) *BookmarkCommands { return &BookmarkCommands{ repo: repo, analyticsService: analyticsService, } } // CreateBookmarkInput represents the input for creating a new bookmark. type CreateBookmarkInput struct { UserID uint WorkID uint Name *string } // CreateBookmark creates a new bookmark. func (c *BookmarkCommands) CreateBookmark(ctx context.Context, input CreateBookmarkInput) (*domain.Bookmark, error) { if input.UserID == 0 { return nil, errors.New("user ID cannot be zero") } if input.WorkID == 0 { return nil, errors.New("work ID cannot be zero") } bookmark := &domain.Bookmark{ UserID: input.UserID, WorkID: input.WorkID, } if input.Name != nil { bookmark.Name = *input.Name } err := c.repo.Create(ctx, bookmark) if err != nil { return nil, err } // Increment analytics c.analyticsService.IncrementWorkBookmarks(ctx, bookmark.WorkID) return bookmark, nil } // DeleteBookmarkInput represents the input for deleting a bookmark. type DeleteBookmarkInput struct { ID uint UserID uint // for authorization } // DeleteBookmark deletes a bookmark by ID. func (c *BookmarkCommands) DeleteBookmark(ctx context.Context, input DeleteBookmarkInput) error { if input.ID == 0 { return errors.New("invalid bookmark ID") } // Fetch the existing bookmark bookmark, err := c.repo.GetByID(ctx, input.ID) if err != nil { return err } if bookmark == nil { return errors.New("bookmark not found") } // Check ownership if bookmark.UserID != input.UserID { return errors.New("unauthorized") } return c.repo.Delete(ctx, input.ID) }