tercul-backend/internal/app/translation/commands.go
google-labs-jules[bot] f675c98e80 Fix: Correct authorization logic in integration tests
The integration tests for admin-only mutations were failing due to an authorization issue. The root cause was that the JWT token used in the tests did not reflect the user's admin role, which was being set directly in the database.

This commit fixes the issue by:
1.  Updating the `CreateAuthenticatedUser` test helper to generate a new JWT token after a user's role is changed. This ensures the token contains the correct, up-to-date role.
2.  Removing all uses of `auth.ContextWithAdminUser` from the integration tests, making the JWT token the single source of truth for authorization.

This change also removes unused imports and variables that were causing build failures after the refactoring. All integration tests now pass.
2025-10-04 23:48:44 +00:00

118 lines
3.1 KiB
Go

package translation
import (
"context"
"errors"
"fmt"
"tercul/internal/app/authz"
"tercul/internal/domain"
platform_auth "tercul/internal/platform/auth"
"gorm.io/gorm"
)
// TranslationCommands contains the command handlers for the translation aggregate.
type TranslationCommands struct {
repo domain.TranslationRepository
authzSvc *authz.Service
}
// NewTranslationCommands creates a new TranslationCommands handler.
func NewTranslationCommands(repo domain.TranslationRepository, authzSvc *authz.Service) *TranslationCommands {
return &TranslationCommands{
repo: repo,
authzSvc: authzSvc,
}
}
// CreateTranslationInput represents the input for creating a new translation.
type CreateTranslationInput struct {
Title string
Content string
Description string
Language string
Status domain.TranslationStatus
TranslatableID uint
TranslatableType string
TranslatorID *uint
IsOriginalLanguage bool
}
// CreateTranslation creates a new translation.
func (c *TranslationCommands) CreateTranslation(ctx context.Context, input CreateTranslationInput) (*domain.Translation, error) {
translation := &domain.Translation{
Title: input.Title,
Content: input.Content,
Description: input.Description,
Language: input.Language,
Status: input.Status,
TranslatableID: input.TranslatableID,
TranslatableType: input.TranslatableType,
TranslatorID: input.TranslatorID,
IsOriginalLanguage: input.IsOriginalLanguage,
}
err := c.repo.Create(ctx, translation)
if err != nil {
return nil, err
}
return translation, nil
}
// UpdateTranslationInput represents the input for updating an existing translation.
type UpdateTranslationInput struct {
ID uint
Title string
Content string
Description string
Language string
Status domain.TranslationStatus
}
// UpdateTranslation updates an existing translation.
func (c *TranslationCommands) UpdateTranslation(ctx context.Context, input UpdateTranslationInput) (*domain.Translation, error) {
userID, ok := platform_auth.GetUserIDFromContext(ctx)
if !ok {
return nil, domain.ErrUnauthorized
}
can, err := c.authzSvc.CanEditTranslation(ctx, userID, input.ID)
if err != nil {
return nil, err
}
if !can {
return nil, domain.ErrForbidden
}
translation, err := c.repo.GetByID(ctx, input.ID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("%w: translation with id %d not found", domain.ErrNotFound, input.ID)
}
return nil, err
}
translation.Title = input.Title
translation.Content = input.Content
translation.Description = input.Description
translation.Language = input.Language
translation.Status = input.Status
err = c.repo.Update(ctx, translation)
if err != nil {
return nil, err
}
return translation, nil
}
// DeleteTranslation deletes a translation by ID.
func (c *TranslationCommands) DeleteTranslation(ctx context.Context, id uint) error {
can, err := c.authzSvc.CanDeleteTranslation(ctx)
if err != nil {
return err
}
if !can {
return domain.ErrForbidden
}
return c.repo.Delete(ctx, id)
}