package comment import ( "context" "errors" "fmt" "tercul/internal/app/authz" "tercul/internal/domain" platform_auth "tercul/internal/platform/auth" "gorm.io/gorm" ) // CommentCommands contains the command handlers for the comment aggregate. type CommentCommands struct { repo domain.CommentRepository authzSvc *authz.Service } // NewCommentCommands creates a new CommentCommands handler. func NewCommentCommands(repo domain.CommentRepository, authzSvc *authz.Service) *CommentCommands { return &CommentCommands{ repo: repo, authzSvc: authzSvc, } } // CreateCommentInput represents the input for creating a new comment. type CreateCommentInput struct { Text string UserID uint WorkID *uint TranslationID *uint ParentID *uint } // CreateComment creates a new comment. func (c *CommentCommands) CreateComment(ctx context.Context, input CreateCommentInput) (*domain.Comment, error) { comment := &domain.Comment{ Text: input.Text, UserID: input.UserID, WorkID: input.WorkID, TranslationID: input.TranslationID, ParentID: input.ParentID, } err := c.repo.Create(ctx, comment) if err != nil { return nil, err } return comment, nil } // UpdateCommentInput represents the input for updating an existing comment. type UpdateCommentInput struct { ID uint Text string } // UpdateComment updates an existing comment after an authorization check. func (c *CommentCommands) UpdateComment(ctx context.Context, input UpdateCommentInput) (*domain.Comment, error) { userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, domain.ErrUnauthorized } comment, err := c.repo.GetByID(ctx, input.ID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("%w: comment with id %d not found", domain.ErrNotFound, input.ID) } return nil, err } can, err := c.authzSvc.CanDeleteComment(ctx, userID, comment) // Using CanDeleteComment for editing as well if err != nil { return nil, err } if !can { return nil, domain.ErrForbidden } comment.Text = input.Text err = c.repo.Update(ctx, comment) if err != nil { return nil, err } return comment, nil } // DeleteComment deletes a comment by ID after an authorization check. func (c *CommentCommands) DeleteComment(ctx context.Context, id uint) error { userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return domain.ErrUnauthorized } comment, err := c.repo.GetByID(ctx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("%w: comment with id %d not found", domain.ErrNotFound, id) } return err } can, err := c.authzSvc.CanDeleteComment(ctx, userID, comment) if err != nil { return err } if !can { return domain.ErrForbidden } return c.repo.Delete(ctx, id) }