package contribution import ( "context" "tercul/internal/app/authz" "tercul/internal/domain" platform_auth "tercul/internal/platform/auth" "github.com/google/uuid" ) // Commands contains the command handlers for the contribution aggregate. type Commands struct { repo domain.ContributionRepository authzSvc *authz.Service } // NewCommands creates a new Commands handler. func NewCommands(repo domain.ContributionRepository, authzSvc *authz.Service) *Commands { return &Commands{ repo: repo, authzSvc: authzSvc, } } // CreateContributionInput represents the input for creating a new contribution. type CreateContributionInput struct { Name string Status string WorkID *uuid.UUID TranslationID *uuid.UUID } // CreateContribution creates a new contribution. func (c *Commands) CreateContribution(ctx context.Context, input CreateContributionInput) (*domain.Contribution, error) { actorID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, domain.ErrUnauthorized } // TODO: Add authorization check using authzSvc if necessary contribution := &domain.Contribution{ Name: input.Name, Status: input.Status, UserID: actorID, WorkID: input.WorkID, TranslationID: input.TranslationID, } err := c.repo.Create(ctx, contribution) if err != nil { return nil, err } return contribution, nil } // UpdateContributionInput represents the input for updating a contribution. type UpdateContributionInput struct { ID uuid.UUID UserID uuid.UUID Name *string Status *string } // UpdateContribution updates an existing contribution. func (c *Commands) UpdateContribution(ctx context.Context, input UpdateContributionInput) (*domain.Contribution, error) { contribution, err := c.repo.GetByID(ctx, input.ID) if err != nil { return nil, err } // Authorization check: only the user who created the contribution can update it. if contribution.UserID != input.UserID { return nil, domain.ErrForbidden } if input.Name != nil { contribution.Name = *input.Name } if input.Status != nil { contribution.Status = *input.Status } if err := c.repo.Update(ctx, contribution); err != nil { return nil, err } return contribution, nil } // DeleteContribution deletes a contribution. func (c *Commands) DeleteContribution(ctx context.Context, contributionID uuid.UUID, userID uuid.UUID) error { contribution, err := c.repo.GetByID(ctx, contributionID) if err != nil { return err } // Authorization check: only the user who created the contribution can delete it. if contribution.UserID != userID { return domain.ErrForbidden } return c.repo.Delete(ctx, contributionID) } // ReviewContributionInput represents the input for reviewing a contribution. type ReviewContributionInput struct { ID uuid.UUID Status string Feedback *string } // ReviewContribution reviews a contribution, updating its status and adding feedback. func (c *Commands) ReviewContribution(ctx context.Context, input ReviewContributionInput) (*domain.Contribution, error) { // Authorization check: for now, let's assume only admins/editors/reviewers can review. claims, ok := platform_auth.GetClaimsFromContext(ctx) if !ok { return nil, domain.ErrUnauthorized } if claims.Role != string(domain.UserRoleAdmin) && claims.Role != string(domain.UserRoleEditor) && claims.Role != string(domain.UserRoleReviewer) { return nil, domain.ErrForbidden } contribution, err := c.repo.GetByID(ctx, input.ID) if err != nil { return nil, err } contribution.Status = input.Status // Note: The feedback handling is not fully implemented. // In a real application, this might create a new comment associated with the contribution. if err := c.repo.Update(ctx, contribution); err != nil { return nil, err } return contribution, nil }