Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

158 link the contribution model to osbl creation #159

Merged
merged 4 commits into from
Feb 6, 2025

Conversation

mpressen
Copy link
Contributor

@mpressen mpressen commented Feb 5, 2025

Summary by CodeRabbit

  • New Features
    • Enhanced contribution submissions with support for multiple file attachments and additional contribution types.
    • Introduced a new OsblCreation class for better management of OSBL-related contributions.
    • Added a new OsblDataTransformer class to manage logo and document uploads.
  • UX Improvements
    • Redesigned form interface with improved data validation, nested input handling, and dynamic error feedback.
    • Updated file type validation for uploads to ensure proper handling of SVG files.
  • Database Enhancements
    • Strengthened record integrity with new status and detail fields.
    • Introduced check constraints to enforce data integrity for contributions.
  • Content Updates
    • Expanded organizational data and enriched keyword options for a more comprehensive experience.

- Implemented intersection observer to dynamically show/hide bottom submit button
- Commented out unused alert and icon imports
- Added state and ref management for button visibility
- Improved form usability by providing a persistent submit action
…rmation

- Added OsblDataTransformer service to handle file uploads for logo and documents
- Created OsblCreation model to store OSBL contribution data
- Updated Contribution model to support new contributable types
- Implemented file processing using ActiveStorage for logo and document attachments
- Added database migrations for OsblCreation and contribution status
- Enhanced contributions controller to use new data transformation logic
- Updated specs to cover new contribution creation workflow
…andling

- Updated ContributionsController to handle nested contribution parameters
- Modified frontend types to support nested OSBL creation data
- Created a proxy method to handle nested form data and errors
- Updated form components to work with new nested data structure
- Improved error handling and validation for contribution form
- Added new factories for supporting models and test data
@mpressen mpressen self-assigned this Feb 5, 2025
@mpressen mpressen linked an issue Feb 5, 2025 that may be closed by this pull request
Copy link

coderabbitai bot commented Feb 5, 2025

Walkthrough

This pull request refactors and extends the contributions functionality. The controller now extracts OSBL data from a nested parameter structure and validates it before creating a Contribution. Frontend forms have been updated to use a nested data structure with improved validation and state management. On the backend, the Contribution model has been modified to support new contributable types and file attachments, and a new OsblCreation model is introduced. Several database migrations, schema updates, seed modifications, and additional tests (including factories and request specs) complete the integration, linking contributions to OSBL creation and ensuring proper file processing via a new transformation service.

Changes

File(s) Change Summary
app/controllers/users/contributions_controller.rb Updated the create method: removed direct osbl_params, now extracts from contribution_params, validates the OSBL object, transforms parameters using OsblDataTransformer, and assigns to the contributable attribute.
app/frontend/pages/Contribution/New.tsx
app/frontend/pages/Contribution/types.ts
New Form Structure & Types: In New.tsx, restructured nested form data handling and validation, added the createOsblProxy function, and implemented state management improvements; in types.ts, updated interfaces to match the new nested structure.
app/frontend/tests/forms/SignUpForm.test.tsx
app/frontend/tests/pages/auth/SignIn.test.tsx
app/frontend/tests/pages/auth/SignUp.test.tsx
Updated import and mock paths reflecting component reorganization in authentication and signup forms.
app/models/contribution.rb
app/models/osbl_creation.rb
Models: In contribution.rb, updated delegated_type by adding Feedback and FeatureRequest, removing Discussion, adding dependent: :destroy, and including has_many_attached :files; added new OsblCreation model with serialized osbl_data and status constants.
app/services/OsblDataTransformer.rb Introduced new service class that transforms OSBL parameters by processing logo and document attachments (uploading via ActiveStorage and returning signed blob IDs).
db/migrate/20250205100116_add_status_to_contribution.rb
db/migrate/20250205100704_create_osbl_creations.rb
db/schema.rb
Database Changes: Added status (integer with default 0) and body columns (with check constraints) to contributions; created new osbl_creations table; updated schema version accordingly.
db/seeds.rb Enhanced seeds by adding a new variable for Benefactorum with detailed OSBL attributes and additional keywords for extended data seeding.
spec/factories/contributions.rb
spec/factories/osbl_creations.rb
Updated the contribution factory to associate with a user and build an osbl_creation, and added a new factory for osbl_creation with preset OSBL data.
spec/models/contribution_spec.rb
spec/requests/contributions_spec.rb
Added model tests to validate factory and DB constraints (e.g., presence of body based on type) and request tests for the POST /create endpoint with nested attributes and file attachment assertions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as ContributionsController
    participant Transformer as OsblDataTransformer
    participant DB as Database

    Client->>Controller: POST /create with nested contribution.osbl data
    Controller->>Controller: Extract contribution_params & validate OSBL data
    Controller->>Transformer: Transform OSBL parameters (logo & documents)
    Transformer->>Transformer: Process logo and document attachments
    Transformer-->>Controller: Return transformed OSBL data (signed IDs)
    Controller->>DB: Create Contribution with transformed OSBL data
    DB-->>Controller: Persist record (or return error)
    Controller-->>Client: Redirect to contributions list or new contribution form with errors
Loading

Possibly related issues

Possibly related PRs

  • Osbl creation fourth panel locations #153 — Involves similar modifications in the ContributionsController (removing osbl_params and introducing contribution_params), indicating a strong code-level connection with this PR.

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 RuboCop (1.69.1)
spec/requests/contributions_spec.rb

[!] There was an error parsing Gemfile: windows is not a valid platform. The available options are: [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :mri_26, :rbx, :truffleruby, :jruby, :jruby_18, :jruby_19, :mswin, :mswin_18, :mswin_19, :mswin_20, :mswin_21, :mswin_22, :mswin_23, :mswin_24, :mswin_25, :mswin_26, :mswin64, :mswin64_19, :mswin64_20, :mswin64_21, :mswin64_22, :mswin64_23, :mswin64_24, :mswin64_25, :mswin64_26, :mingw, :mingw_18, :mingw_19, :mingw_20, :mingw_21, :mingw_22, :mingw_23, :mingw_24, :mingw_25, :mingw_26, :x64_mingw, :x64_mingw_20, :x64_mingw_21, :x64_mingw_22, :x64_mingw_23, :x64_mingw_24, :x64_mingw_25, :x64_mingw_26]. Bundler cannot continue.

from /Gemfile:17

-------------------------------------------

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem

gem "tzinfo-data", platforms: %i[windows jruby]

-------------------------------------------

/usr/lib/ruby/3.1.0/bundler/dsl.rb:357:in block in normalize_options' /usr/lib/ruby/3.1.0/bundler/dsl.rb:355:in each'
/usr/lib/ruby/3.1.0/bundler/dsl.rb:355:in normalize_options' /usr/lib/ruby/3.1.0/bundler/dsl.rb:100:in gem'
/Gemfile:17:in eval_gemfile' /usr/lib/ruby/3.1.0/bundler/dsl.rb:49:in instance_eval'
/usr/lib/ruby/3.1.0/bundler/dsl.rb:49:in eval_gemfile' /usr/lib/ruby/3.1.0/bundler/dsl.rb:12:in evaluate'
/usr/lib/ruby/3.1.0/bundler/definition.rb:38:in build' /usr/lib/ruby/3.1.0/bundler.rb:197:in definition'
/usr/lib/ruby/3.1.0/bundler.rb:180:in load' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:270:in gem_config_path'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:65:in block (2 levels) in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:63:in reverse_each'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:63:in block in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:57:in each_pair'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:57:in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader.rb:56:in load_file'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_store.rb:29:in options_config=' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:160:in act_on_options'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:47:in block in run' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:81:in profile_if_needed'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:43:in run' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/exe/rubocop:19:in <top (required)>'
/usr/local/bin/rubocop:25:in load' /usr/local/bin/rubocop:25:in

'

app/controllers/users/contributions_controller.rb

[!] There was an error parsing Gemfile: windows is not a valid platform. The available options are: [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :mri_26, :rbx, :truffleruby, :jruby, :jruby_18, :jruby_19, :mswin, :mswin_18, :mswin_19, :mswin_20, :mswin_21, :mswin_22, :mswin_23, :mswin_24, :mswin_25, :mswin_26, :mswin64, :mswin64_19, :mswin64_20, :mswin64_21, :mswin64_22, :mswin64_23, :mswin64_24, :mswin64_25, :mswin64_26, :mingw, :mingw_18, :mingw_19, :mingw_20, :mingw_21, :mingw_22, :mingw_23, :mingw_24, :mingw_25, :mingw_26, :x64_mingw, :x64_mingw_20, :x64_mingw_21, :x64_mingw_22, :x64_mingw_23, :x64_mingw_24, :x64_mingw_25, :x64_mingw_26]. Bundler cannot continue.

from /Gemfile:17

-------------------------------------------

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem

gem "tzinfo-data", platforms: %i[windows jruby]

-------------------------------------------

/usr/lib/ruby/3.1.0/bundler/dsl.rb:357:in block in normalize_options' /usr/lib/ruby/3.1.0/bundler/dsl.rb:355:in each'
/usr/lib/ruby/3.1.0/bundler/dsl.rb:355:in normalize_options' /usr/lib/ruby/3.1.0/bundler/dsl.rb:100:in gem'
/Gemfile:17:in eval_gemfile' /usr/lib/ruby/3.1.0/bundler/dsl.rb:49:in instance_eval'
/usr/lib/ruby/3.1.0/bundler/dsl.rb:49:in eval_gemfile' /usr/lib/ruby/3.1.0/bundler/dsl.rb:12:in evaluate'
/usr/lib/ruby/3.1.0/bundler/definition.rb:38:in build' /usr/lib/ruby/3.1.0/bundler.rb:197:in definition'
/usr/lib/ruby/3.1.0/bundler.rb:180:in load' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:270:in gem_config_path'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:65:in block (2 levels) in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:63:in reverse_each'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:63:in block in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:57:in each_pair'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:57:in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader.rb:56:in load_file'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_store.rb:29:in options_config=' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:160:in act_on_options'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:47:in block in run' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:81:in profile_if_needed'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:43:in run' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/exe/rubocop:19:in <top (required)>'
/usr/local/bin/rubocop:25:in load' /usr/local/bin/rubocop:25:in

'

app/models/osbl.rb

[!] There was an error parsing Gemfile: windows is not a valid platform. The available options are: [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :mri_26, :rbx, :truffleruby, :jruby, :jruby_18, :jruby_19, :mswin, :mswin_18, :mswin_19, :mswin_20, :mswin_21, :mswin_22, :mswin_23, :mswin_24, :mswin_25, :mswin_26, :mswin64, :mswin64_19, :mswin64_20, :mswin64_21, :mswin64_22, :mswin64_23, :mswin64_24, :mswin64_25, :mswin64_26, :mingw, :mingw_18, :mingw_19, :mingw_20, :mingw_21, :mingw_22, :mingw_23, :mingw_24, :mingw_25, :mingw_26, :x64_mingw, :x64_mingw_20, :x64_mingw_21, :x64_mingw_22, :x64_mingw_23, :x64_mingw_24, :x64_mingw_25, :x64_mingw_26]. Bundler cannot continue.

from /Gemfile:17

-------------------------------------------

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem

gem "tzinfo-data", platforms: %i[windows jruby]

-------------------------------------------

/usr/lib/ruby/3.1.0/bundler/dsl.rb:357:in block in normalize_options' /usr/lib/ruby/3.1.0/bundler/dsl.rb:355:in each'
/usr/lib/ruby/3.1.0/bundler/dsl.rb:355:in normalize_options' /usr/lib/ruby/3.1.0/bundler/dsl.rb:100:in gem'
/Gemfile:17:in eval_gemfile' /usr/lib/ruby/3.1.0/bundler/dsl.rb:49:in instance_eval'
/usr/lib/ruby/3.1.0/bundler/dsl.rb:49:in eval_gemfile' /usr/lib/ruby/3.1.0/bundler/dsl.rb:12:in evaluate'
/usr/lib/ruby/3.1.0/bundler/definition.rb:38:in build' /usr/lib/ruby/3.1.0/bundler.rb:197:in definition'
/usr/lib/ruby/3.1.0/bundler.rb:180:in load' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:270:in gem_config_path'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:65:in block (2 levels) in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:63:in reverse_each'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:63:in block in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:57:in each_pair'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader_resolver.rb:57:in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_loader.rb:56:in load_file'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/config_store.rb:29:in options_config=' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:160:in act_on_options'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:47:in block in run' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:81:in profile_if_needed'
/var/lib/gems/3.1.0/gems/rubocop-1.69.1/lib/rubocop/cli.rb:43:in run' /var/lib/gems/3.1.0/gems/rubocop-1.69.1/exe/rubocop:19:in <top (required)>'
/usr/local/bin/rubocop:25:in load' /usr/local/bin/rubocop:25:in

'

  • 6 others

Tip

🌐 Web search-backed reviews and chat
  • We have enabled web search-based reviews and chat for all users. This feature allows CodeRabbit to access the latest documentation and information on the web.
  • You can disable this feature by setting web_search: false in the knowledge_base settings.
  • Please share any feedback in the Discord discussion.
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (13)
app/controllers/users/contributions_controller.rb (1)

52-114: Rename :type keys to avoid confusion with Rails single-table inheritance.

Your strong parameters include attributes named :type (e.g., lines 78, 82). Rails interprets type as a special column name for STI, which can lead to subtle bugs. Consider renaming these attributes to something more descriptive like document_type or location_type to prevent conflicts.

app/frontend/pages/Contribution/New.tsx (3)

2-5: Remove commented-out imports to keep the codebase clean.

The lines commented out for Alert, AlertDescription, and GoodIdea can be safely removed if no longer needed, improving code readability and maintainability.


24-38: Double-check the error message for tax_reduction.

While the schema uses an enum for tax_reduction, your message references "Veuillez sélectionner un pourcentage," which might be confusing to users if the values are concepts like "intérêt_général" or "aide_aux_personnes_en_difficulté". Update the error message to clarify the required selection.


82-114: Provide a fallback for the Intersection Observer usage.

Older browsers without an IntersectionObserver API may need a polyfill or alternate logic. While this is often acceptable for modern browsers, you might want to confirm your user base’s requirements or add a small fallback for improved accessibility.

spec/requests/contributions_spec.rb (1)

92-147: Avoid hardcoding factory IDs to prevent collisions in parallel tests.

The test suite sets create(:cause, id: 13), etc. In parallel or large test runs, ID collisions might occur if the database already uses those IDs. Prefer letting the factory auto-generate IDs or use a sequence to ensure uniqueness.

spec/factories/osbl_creations.rb (1)

1-11: Enhance factory with sequences and traits for better test flexibility.

Consider the following improvements:

  1. Use sequence for unique names to avoid conflicts.
  2. Add traits for different tax reduction types.
  3. Add traits for different causes.

Apply this diff to enhance the factory:

 FactoryBot.define do
   factory :osbl_creation do
+    sequence(:name) { |n| "OSBL #{n}" }
+
     osbl_data do
       {
-        name: "OSBL 1",
+        name: name,
         tax_reduction: "intérêt_général",
         osbls_causes_attributes: [{cause_id: 1}]
       }
     end
+
+    trait :utilité_publique do
+      osbl_data do
+        {
+          name: name,
+          tax_reduction: "utilité_publique",
+          osbls_causes_attributes: [{cause_id: 1}]
+        }
+      end
+    end
+
+    trait :multiple_causes do
+      osbl_data do
+        {
+          name: name,
+          tax_reduction: "intérêt_général",
+          osbls_causes_attributes: [
+            {cause_id: 1},
+            {cause_id: 2}
+          ]
+        }
+      end
+    end
   end
 end
spec/factories/contributions.rb (1)

7-9: Remove redundant trait.

The :osbl_creation trait is redundant as it sets the same contributable value as the default factory definition.

Remove the redundant trait or modify it to provide different behavior:

-    trait :osbl_creation do
-      contributable { build(:osbl_creation) }
-    end

If you need traits, consider adding ones that provide different states or behaviors:

    trait :with_utilité_publique do
      contributable { build(:osbl_creation, :utilité_publique) }
    end

    trait :with_multiple_causes do
      contributable { build(:osbl_creation, :multiple_causes) }
    end
db/migrate/20250205100116_add_status_to_contribution.rb (1)

3-4: Consider adding an index on the status column.

Since the status column will likely be used for filtering and querying contributions, adding an index would improve query performance.

-    add_column :contributions, :status, :integer, default: 0
+    add_column :contributions, :status, :integer, default: 0
+    add_index :contributions, :status
app/models/contribution.rb (2)

14-14: Consider adding file validations.

The has_many_attached :files association looks good, but consider adding validations for:

  1. File size limits
  2. Allowed file types
  3. Maximum number of attachments
   has_many_attached :files
+  validates :files,
+    content_type: ['application/pdf', 'image/png', 'image/jpeg'],
+    size: { less_than: 10.megabytes },
+    limit: { max: 5 }

16-17: Remove commented validation code.

The validation is now enforced by the database constraint, so this commented code can be safely removed.

-  # db_constraints enforcing :
-  # validates :body, presence: true, if: -> { %w[Feedback FeatureRequest BugReport CorrectionRequest Other].include?(contributable_type) }
app/services/OsblDataTransformer.rb (1)

2-4: Add type checking for params.

Consider adding type checking to ensure params is a valid object that responds to to_h.

   def initialize(params)
+    raise ArgumentError, "params must respond to to_h" unless params.respond_to?(:to_h)
     @params = params.to_h
   end
spec/models/contribution_spec.rb (1)

31-39: Expand test coverage for non-required body types.

The commented code suggests osbl_update should also be tested. Consider:

  1. Uncommenting and testing osbl_update
  2. Adding edge cases for body presence
-      # %i[osbl_creation osbl_update].each do |type|
-      %i[osbl_creation].each do |type|
+      %i[osbl_creation osbl_update].each do |type|
         it "allows nil body for #{type}" do
           contribution = build(:contribution, contributable: build(type))
           expect { contribution.save }.not_to raise_error
         end
+
+        it "allows non-nil body for #{type}" do
+          contribution = build(:contribution, contributable: build(type, body: "Some content"))
+          expect { contribution.save }.not_to raise_error
+        end
       end
db/seeds.rb (1)

555-645: Consider removing commented-out code.

The benefactorum_params hash is well-structured and aligns with the TypeScript interfaces. However, there are several blocks of commented-out code related to file handling that should be addressed.

Consider either:

  1. Removing the commented-out code if it's no longer needed
  2. Implementing the file handling if it's required
  3. Adding a TODO comment explaining why the code is commented out and when it will be implemented
-  # "logo" =>
-  # {
-  #   "tempfile" => "#<File:0x00007836ee3e6f50>",
-  #   "content_type" => "image/png",
-  #   "original_filename" => "Benefactorum-Logo.png",
-  #   "headers" => "Content-Disposition: form-data; name=\"logo\"; filename=\"Benefactorum-Logo.png\"\r\nContent-Type: image/png\r\n"
-  # },
+  # TODO: Implement logo file handling in the next PR

Similarly for the document_attachments_attributes block.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db27239 and 76f7683.

📒 Files selected for processing (17)
  • app/controllers/users/contributions_controller.rb (2 hunks)
  • app/frontend/pages/Contribution/New.tsx (5 hunks)
  • app/frontend/pages/Contribution/types.ts (2 hunks)
  • app/frontend/tests/forms/SignUpForm.test.tsx (1 hunks)
  • app/frontend/tests/pages/auth/SignIn.test.tsx (1 hunks)
  • app/frontend/tests/pages/auth/SignUp.test.tsx (1 hunks)
  • app/models/contribution.rb (1 hunks)
  • app/models/osbl_creation.rb (1 hunks)
  • app/services/OsblDataTransformer.rb (1 hunks)
  • db/migrate/20250205100116_add_status_to_contribution.rb (1 hunks)
  • db/migrate/20250205100704_create_osbl_creations.rb (1 hunks)
  • db/schema.rb (3 hunks)
  • db/seeds.rb (2 hunks)
  • spec/factories/contributions.rb (1 hunks)
  • spec/factories/osbl_creations.rb (1 hunks)
  • spec/models/contribution_spec.rb (1 hunks)
  • spec/requests/contributions_spec.rb (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • app/frontend/tests/forms/SignUpForm.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: deploy
🔇 Additional comments (22)
app/frontend/tests/pages/auth/SignUp.test.tsx (1)

22-25: LGTM! Verify the component's new location.

The mock path update aligns with the component's new location in the directory structure.

Let's verify that the SignUpForm component exists at the new location:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: Verify the SignUpForm component exists at the new location.

# Test: Search for the SignUpForm component file.
fd SignUpForm.tsx -p app/frontend/components/pages/auth/signUp/

Length of output: 122


LGTM! Verified the component's new location.

The SignUpForm component exists at the expected path:

  • app/frontend/components/pages/auth/signUp/SignUpForm.tsx
app/frontend/tests/pages/auth/SignIn.test.tsx (1)

22-25: LGTM! Verify the component's new location.

The mock path update aligns with the component's new location in the directory structure.

Let's verify that the SignInForm component exists at the new location:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: Verify the SignInForm component exists at the new location.

# Test: Search for the SignInForm component file.
fd SignInForm.tsx -p app/frontend/components/pages/auth/signIn/

Length of output: 122


LGTM! Verified that the SignInForm component exists at the new location as expected.
The file is correctly located at app/frontend/components/pages/auth/signIn/SignInForm.tsx.

app/controllers/users/contributions_controller.rb (1)

28-30: Handle missing or empty osbl parameters gracefully.

If no osbl data is provided or if it's empty, osbl_params would be nil here, resulting in Osbl.new(nil). Consider defaulting to {} or adding a guard clause to avoid potential ArgumentError or undesired application behavior.

app/frontend/pages/Contribution/New.tsx (1)

49-79: Confirm handling of unmapped errors in createOsblProxy.

This function smartly reroutes nested errors but ignores those that don’t match the /^contribution\.osbl\./ pattern. If other error paths might be relevant, consider logging or surfacing them for debugging, ensuring no unexpected errors go unnoticed.

spec/requests/contributions_spec.rb (3)

66-71: The only_for_current_user shared example is consistent with security checks.

This partial ensures that only the owner can create a new contribution. The usage looks properly aligned with the rest of the codebase’s approach.


161-224: Comprehensive test coverage for nested attributes.

These lines thoroughly validate the transformed file parameters, osbl data, attachments, and nested relationships. Great job ensuring important associations (causes, keywords, documents, locations) are properly persisted and tested!


233-245: Redirect expectations are well tested.

The error scenario confirms the system redirects to the new contribution form and surfaces the expected osbls_causes attribute error. This approach ensures robust negative path coverage.

db/migrate/20250205100116_add_status_to_contribution.rb (1)

6-9: Verify the check constraint logic.

The check constraint correctly enforces body presence for specific contribution types. However, consider:

  1. Using an array-based check for better maintainability
  2. Adding a comment explaining the constraint's purpose
     add_check_constraint :contributions,
-      "NOT (contributable_type IN ('Feedback', 'FeatureRequest', 'BugReport', 'CorrectionRequest', 'Other')) OR body IS NOT NULL",
+      "NOT (contributable_type = ANY(ARRAY['Feedback', 'FeatureRequest', 'BugReport', 'CorrectionRequest', 'Other'])) OR body IS NOT NULL",
       name: "body_required_for_specific_types"
+
+    # This constraint ensures that contributions of specific types must have a body
✅ Verification successful

Error: No shell scripts or web queries found


Review Confirmation: Check Constraint Logic and Suggested Enhancements

  • The check constraint correctly forces a non‑NULL value in body when contributable_type is one of the specified types.
  • Switching from the IN operator to using ANY(ARRAY[...]) is functionally equivalent and can improve maintainability, especially if the list needs to be updated later.
  • Adding an inline comment to explain the purpose of the constraint increases code clarity.
app/models/contribution.rb (1)

4-12: Verify the impact of removing Discussion type.

The delegated_type changes look good, but ensure that:

  1. All existing Discussion contributions are migrated or handled
  2. Frontend code is updated to remove Discussion type references
✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for Discussion type references in the codebase
rg -i "discussion.*contribution" 

Length of output: 34


🏁 Script executed:

#!/bin/bash
echo "Searching for all references to 'Discussion' (case insensitive) across the repository:"
rg -i "\bdiscussion\b"

echo
echo "Searching for any references to 'Discussion' in the Contribution model (app/models/contribution.rb):"
rg -i "Discussion" app/models/contribution.rb

echo
echo "Searching for Discussion references in migration files (db/migrate):"
rg -i "discussion" db/migrate

echo
echo "Searching for Discussion references in frontend code (app/javascript and src/):"
rg -i "discussion" app/javascript
rg -i "discussion" src

Length of output: 1002


No residual Discussion dependencies detected.
After searching the entire codebase—including the Contribution model, migration directories, and potential frontend directories—there are no remaining references to the Discussion type. This indicates that the removal is safe in the code. Please ensure that any legacy Discussion contributions in the database are appropriately migrated or handled separately.

app/frontend/pages/Contribution/types.ts (9)

1-7: LGTM!

The interface correctly defines the contribution structure and aligns with the schema changes.


9-13: LGTM!

The interface correctly defines the fund record structure.


15-23: LGTM!

The interface correctly defines the annual finance structure and properly uses the FundRecord interface.


25-31: LGTM!

The interface correctly defines the document structure.


33-41: LGTM!

The interface correctly defines the address structure.


43-49: LGTM!

The interface correctly defines the location structure and properly uses the Address interface.


51-57: LGTM!

The interface correctly defines the OSBL creation data structure and properly uses the OsblData interface.


59-76: LGTM!

The interface correctly defines the OSBL data structure, properly uses other interfaces for nested attributes, and aligns with the schema changes.


78-84: LGTM!

The interface correctly defines the form props structure and properly uses the OsblData interface.

db/schema.rb (3)

13-13: LGTM!

The schema version update is correct and follows the migration timestamp format.


93-97: LGTM!

The changes to the contributions table are well-structured:

  • Added status column with a default value
  • Added body column
  • Added check constraint to ensure body is not null for specific contribution types

185-187: LGTM!

The new osbl_creations table is well-structured with a non-nullable osbl_data column and aligns with the TypeScript interfaces.

db/seeds.rb (1)

63-67: LGTM!

The new keywords are relevant to the application domain and follow the naming convention.

app/controllers/users/contributions_controller.rb Outdated Show resolved Hide resolved
app/frontend/pages/Contribution/New.tsx Outdated Show resolved Hide resolved
app/models/osbl_creation.rb Show resolved Hide resolved
app/models/osbl_creation.rb Show resolved Hide resolved
app/services/OsblDataTransformer.rb Show resolved Hide resolved
app/services/OsblDataTransformer.rb Outdated Show resolved Hide resolved
spec/models/contribution_spec.rb Show resolved Hide resolved
- Updated content type validation for SVG files from 'image/svg' to 'image/svg+xml'
- Modified logo validation in Osbl and Label models to use consistent SVG MIME type
- Adjusted frontend file input and validation to match new SVG content type
- Simplified contributions controller error handling
- Updated related specs to use new SVG MIME type
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
spec/factories/osbls.rb (1)

10-14: LGTM! Consider adding flexibility for multiple documents.

The trait implementation is clean and follows factory_bot best practices. For enhanced flexibility, you might want to consider allowing the trait to accept a count parameter for creating multiple documents.

Here's how you could enhance the trait:

 trait :with_document do
+  transient do
+    documents_count { 1 }
+  end
+
   after(:build) do |osbl|
-    osbl.documents << build(:document)
+    documents_count.times { osbl.documents << build(:document) }
   end
 end

Usage example:

create(:osbl, :with_document, documents_count: 3)
spec/models/osbl_spec.rb (1)

59-72: Add more test cases for document validations.

While the invalid document test is good, consider adding these test cases for better coverage:

  1. Valid document with file
  2. Multiple documents (both valid and invalid cases)
describe "associated documents" do
  it "osbl is valid with a valid document" do
    osbl = build(:osbl, document_attachments_attributes: [{
      document_attributes: {
        type: "Autre",
        name: "Test document",
        file: fixture_file_upload('spec/fixtures/files/test.pdf', 'application/pdf')
      }
    }])

    expect(osbl).to be_valid
  end

  it "handles multiple documents correctly" do
    osbl = build(:osbl, document_attachments_attributes: [
      {
        document_attributes: {
          type: "Autre",
          name: "Valid document",
          file: fixture_file_upload('spec/fixtures/files/test.pdf', 'application/pdf')
        }
      },
      {
        document_attributes: {
          type: "Autre",
          name: "Invalid document"
          # file missing
        }
      }
    ])

    expect(osbl).not_to be_valid
    expect(osbl.errors[:"document_attachments.document.file"]).to be_present
  end
end
app/frontend/pages/Contribution/New.tsx (2)

22-38: Consider using branded validation messages.

The validation messages are currently in French but could be moved to a localization file for better maintainability.

Consider creating a separate messages file:

// messages.ts
export const validationMessages = {
  url: 'Veuillez entrer une URL valide.',
  fileSize: 'La taille du fichier doit être inférieure à 1 MB.',
  fileType: 'Le type de fichier est invalide. Format accepté : SVG, PNG, WEBP.',
  // ... etc
}

40-70: Strengthen type safety in createOsblProxy function.

The function uses any type for the value parameter in setData, which could lead to type-related bugs.

Consider this type-safe implementation:

function createOsblProxy<T extends OsblCreationData>(
  data: T,
  setData: <K extends keyof T['contribution']['osbl']>(
    key: K,
    value: T['contribution']['osbl'][K]
  ) => void,
  errors: Record<string, string>,
  clearErrors: (field: 'contribution') => void,
  setError: (field: 'contribution', message: string) => void
): FormProps {
  // ... rest of the implementation
}
spec/requests/contributions_spec.rb (1)

169-224: Consider breaking down the large test into smaller, focused examples.

The test covers multiple aspects of contribution creation in a single example. This could make it harder to identify the source of failures.

Consider splitting into focused examples:

context "with valid parameters" do
  # ... setup ...

  it "creates a contribution with basic attributes" do
    expect { subject }.to change(Contribution, :count).by(1)
    contribution = Contribution.last
    expect(contribution.body).to eq("Je suis le créateur de Benefactorum...")
    expect(contribution.files).to be_attached
  end

  it "creates an osbl with correct attributes" do
    subject
    osbl = Osbl.create!(Contribution.last.osbl_creation.osbl_data)
    expect(osbl.name).to eq("Benefactorum")
    # ... other osbl assertions
  end

  it "creates associated records correctly" do
    subject
    osbl = Osbl.create!(Contribution.last.osbl_creation.osbl_data)
    expect(osbl.osbls_causes.count).to eq(1)
    expect(osbl.osbls_keywords.count).to eq(4)
    # ... other association assertions
  end
end
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76f7683 and adfabcc.

📒 Files selected for processing (11)
  • app/controllers/users/contributions_controller.rb (2 hunks)
  • app/frontend/components/pages/contribution/new/OsblHeader.tsx (1 hunks)
  • app/frontend/pages/Contribution/New.tsx (4 hunks)
  • app/models/label.rb (1 hunks)
  • app/models/osbl.rb (1 hunks)
  • app/models/osbl_creation.rb (1 hunks)
  • app/services/OsblDataTransformer.rb (1 hunks)
  • spec/factories/osbls.rb (1 hunks)
  • spec/models/document_spec.rb (1 hunks)
  • spec/models/osbl_spec.rb (1 hunks)
  • spec/requests/contributions_spec.rb (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/models/osbl_creation.rb
  • app/services/OsblDataTransformer.rb
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: deploy
🔇 Additional comments (4)
app/models/label.rb (1)

2-13: LGTM! Consistent validation rules.

The validation rules for the logo attachment are well-defined and consistent with the Osbl model:

  • Proper MIME types including the correct image/svg+xml
  • Reasonable 1MB file size limit
  • Appropriate file formats for logos (SVG, PNG, WEBP)
app/models/osbl.rb (1)

57-57: LGTM! Correct MIME type for SVG files.

The MIME type has been properly updated from image/svg to image/svg+xml, which is the correct MIME type for SVG files.

app/frontend/components/pages/contribution/new/OsblHeader.tsx (1)

42-42: LGTM! Frontend validation matches backend.

The file input's accept attribute correctly matches the backend validation rules, ensuring consistent file type validation across the stack.

spec/models/document_spec.rb (1)

64-64: LGTM!

The MIME type update from image/svg to image/svg+xml is correct and follows standard specifications.

@mpressen mpressen merged commit d6f75f0 into main Feb 6, 2025
11 checks passed
@mpressen mpressen deleted the 158-link-the-contribution-model-to-osbl-creation branch February 6, 2025 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Link the contribution model to Osbl creation
1 participant