tercul-backend/internal/data/sql/copyright_repository.go
google-labs-jules[bot] c2e9a118e2 feat(testing): Increase test coverage and fix authz bugs
This commit significantly increases the test coverage across the application and fixes several underlying bugs that were discovered while writing the new tests.

The key changes include:

- **New Tests:** Added extensive integration and unit tests for GraphQL resolvers, application services, and data repositories, substantially increasing the test coverage for packages like `graphql`, `user`, `translation`, and `analytics`.

- **Authorization Bug Fixes:**
  - Fixed a critical bug where a user creating a `Work` was not correctly associated as its author, causing subsequent permission failures.
  - Corrected the authorization logic in `authz.Service` to properly check for entity ownership by non-admin users.

- **Test Refactoring:**
  - Refactored numerous test suites to use `testify/mock` instead of manual mocks, improving test clarity and maintainability.
  - Isolated integration tests by creating a fresh admin user and token for each test run, eliminating test pollution.
  - Centralized domain errors into `internal/domain/errors.go` and updated repositories to use them, making error handling more consistent.

- **Code Quality Improvements:**
  - Replaced manual mock implementations with `testify/mock` for better consistency.
  - Cleaned up redundant and outdated test files.

These changes stabilize the test suite, improve the overall quality of the codebase, and move the project closer to the goal of 80% test coverage.
2025-10-09 07:03:45 +00:00

118 lines
5.3 KiB
Go

package sql
import (
"context"
"errors"
"tercul/internal/domain"
"tercul/internal/platform/config"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
"gorm.io/gorm"
)
type copyrightRepository struct {
*BaseRepositoryImpl[domain.Copyright]
db *gorm.DB
tracer trace.Tracer
}
// NewCopyrightRepository creates a new CopyrightRepository.
func NewCopyrightRepository(db *gorm.DB, cfg *config.Config) domain.CopyrightRepository {
return &copyrightRepository{
BaseRepositoryImpl: NewBaseRepositoryImpl[domain.Copyright](db, cfg),
db: db,
tracer: otel.Tracer("copyright.repository"),
}
}
// AddTranslation adds a translation to a copyright
func (r *copyrightRepository) AddTranslation(ctx context.Context, translation *domain.CopyrightTranslation) error {
ctx, span := r.tracer.Start(ctx, "AddTranslation")
defer span.End()
return r.db.WithContext(ctx).Create(translation).Error
}
// GetTranslations gets all translations for a copyright
func (r *copyrightRepository) GetTranslations(ctx context.Context, copyrightID uint) ([]domain.CopyrightTranslation, error) {
ctx, span := r.tracer.Start(ctx, "GetTranslations")
defer span.End()
var translations []domain.CopyrightTranslation
err := r.db.WithContext(ctx).Where("copyright_id = ?", copyrightID).Find(&translations).Error
return translations, err
}
// GetTranslationByLanguage gets a specific translation by language code
func (r *copyrightRepository) GetTranslationByLanguage(ctx context.Context, copyrightID uint, languageCode string) (*domain.CopyrightTranslation, error) {
ctx, span := r.tracer.Start(ctx, "GetTranslationByLanguage")
defer span.End()
var translation domain.CopyrightTranslation
err := r.db.WithContext(ctx).Where("copyright_id = ? AND language_code = ?", copyrightID, languageCode).First(&translation).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, domain.ErrEntityNotFound
}
return nil, err
}
return &translation, nil
}
func (r *copyrightRepository) AddCopyrightToWork(ctx context.Context, workID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "AddCopyrightToWork")
defer span.End()
return r.db.WithContext(ctx).Exec("INSERT INTO work_copyrights (work_id, copyright_id) VALUES (?, ?) ON CONFLICT DO NOTHING", workID, copyrightID).Error
}
func (r *copyrightRepository) RemoveCopyrightFromWork(ctx context.Context, workID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "RemoveCopyrightFromWork")
defer span.End()
return r.db.WithContext(ctx).Exec("DELETE FROM work_copyrights WHERE work_id = ? AND copyright_id = ?", workID, copyrightID).Error
}
func (r *copyrightRepository) AddCopyrightToAuthor(ctx context.Context, authorID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "AddCopyrightToAuthor")
defer span.End()
return r.db.WithContext(ctx).Exec("INSERT INTO author_copyrights (author_id, copyright_id) VALUES (?, ?) ON CONFLICT DO NOTHING", authorID, copyrightID).Error
}
func (r *copyrightRepository) RemoveCopyrightFromAuthor(ctx context.Context, authorID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "RemoveCopyrightFromAuthor")
defer span.End()
return r.db.WithContext(ctx).Exec("DELETE FROM author_copyrights WHERE author_id = ? AND copyright_id = ?", authorID, copyrightID).Error
}
func (r *copyrightRepository) AddCopyrightToBook(ctx context.Context, bookID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "AddCopyrightToBook")
defer span.End()
return r.db.WithContext(ctx).Exec("INSERT INTO book_copyrights (book_id, copyright_id) VALUES (?, ?) ON CONFLICT DO NOTHING", bookID, copyrightID).Error
}
func (r *copyrightRepository) RemoveCopyrightFromBook(ctx context.Context, bookID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "RemoveCopyrightFromBook")
defer span.End()
return r.db.WithContext(ctx).Exec("DELETE FROM book_copyrights WHERE book_id = ? AND copyright_id = ?", bookID, copyrightID).Error
}
func (r *copyrightRepository) AddCopyrightToPublisher(ctx context.Context, publisherID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "AddCopyrightToPublisher")
defer span.End()
return r.db.WithContext(ctx).Exec("INSERT INTO publisher_copyrights (publisher_id, copyright_id) VALUES (?, ?) ON CONFLICT DO NOTHING", publisherID, copyrightID).Error
}
func (r *copyrightRepository) RemoveCopyrightFromPublisher(ctx context.Context, publisherID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "RemoveCopyrightFromPublisher")
defer span.End()
return r.db.WithContext(ctx).Exec("DELETE FROM publisher_copyrights WHERE publisher_id = ? AND copyright_id = ?", publisherID, copyrightID).Error
}
func (r *copyrightRepository) AddCopyrightToSource(ctx context.Context, sourceID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "AddCopyrightToSource")
defer span.End()
return r.db.WithContext(ctx).Exec("INSERT INTO source_copyrights (source_id, copyright_id) VALUES (?, ?) ON CONFLICT DO NOTHING", sourceID, copyrightID).Error
}
func (r *copyrightRepository) RemoveCopyrightFromSource(ctx context.Context, sourceID uint, copyrightID uint) error {
ctx, span := r.tracer.Start(ctx, "RemoveCopyrightFromSource")
defer span.End()
return r.db.WithContext(ctx).Exec("DELETE FROM source_copyrights WHERE source_id = ? AND copyright_id = ?", sourceID, copyrightID).Error
}