Skip to content

Issues/1263 scope assets to project in scratch#783

Open
abcampo-iry wants to merge 4 commits intomainfrom
issues/1263-scope-assets-to-project-in-scratch
Open

Issues/1263 scope assets to project in scratch#783
abcampo-iry wants to merge 4 commits intomainfrom
issues/1263-scope-assets-to-project-in-scratch

Conversation

@abcampo-iry
Copy link
Copy Markdown
Contributor

@abcampo-iry abcampo-iry commented Apr 14, 2026

Status

  • Closes partially 1256

What’s changed?

Scratch assets are now scoped by project and uploader instead of being treated as globally shared.

  • scratch_assets now stores:
  • project_id
  • uploaded_user_id

That changes ownership like this:

  • global Scratch library assets remain global: project_id = nil, uploaded_user_id = nil
  • project-scoped assets are unique per (project_id, uploaded_user_id, filename)
  • different projects can upload the same asset filename
  • different users on the same teacher project can upload the same filename without colliding

Scratch asset reads and uploads

The Scratch asset endpoints now behave like this:

  • X-Project-ID is required
  • reads and uploads are authorized against that active Scratch project
  • uploads always write to the active project from the header, with uploaded_user_id = current_user.id
  • asset endpoints no longer create or reuse remixes

Asset lookup now resolves in this order:

  • the current user’s asset on the active project
  • the active project owner’s/shared asset
  • the current user’s asset on ancestor projects
  • ancestor owner/shared assets
  • the global library asset

This means:

  • a project can load its own assets
  • remixes can still load assets from ancestor projects
  • Scratch library assets still work as global assets

For SVGs:

  • project SVG assets are served as application/octet-stream
  • only global library SVG assets are served as image/svg+xml

Scratch remix behavior

Remix creation still reuses an existing remix for the same user and original project instead of creating duplicates.
The tricky case is when a student adds a Scratch asset before pressing Save for the first time:

  • the asset is stored on the original project, but with uploaded_user_id = student.id
  • that makes it visible only to that student while they are still working from the original project
  • when the student does the first explicit remix save, the remix is created or reused
  • after that, those uploaded assets are reassigned from the original project to the remix
  • later saves keep using that same remix

This keeps remix logic inside the remix flow, instead of mixing remix creation into the asset endpoints.

@cla-bot cla-bot bot added the cla-signed label Apr 14, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 14, 2026

Test coverage

89.47% line coverage reported by SimpleCov.
Run: https://github.com/RaspberryPiFoundation/editor-api/actions/runs/24577912262

@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch from ef4870e to ddfaa05 Compare April 14, 2026 16:15
@raspberrypiherokubot raspberrypiherokubot temporarily deployed to editor-api-p-issues-126-edxmgm April 14, 2026 16:15 Inactive
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch 2 times, most recently from 5ef7e67 to d2dd13c Compare April 15, 2026 11:02
@abcampo-iry abcampo-iry marked this pull request as ready for review April 15, 2026 11:20
Copilot AI review requested due to automatic review settings April 15, 2026 11:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Scopes Scratch assets to projects (via project_id) so assets are no longer globally shared by default, while preserving remix lineage access and keeping library assets usable as global fallbacks. It also tightens Scratch project access control and avoids duplicate remix creation.

Changes:

  • Added project_id to scratch_assets (with partial unique indexes) and a migration to backfill legacy assets onto referencing projects while reusing blobs.
  • Updated Scratch asset endpoints to require X-Project-ID, enforce project/remix visibility, and adjust SVG content-type behavior (trusted only for global/library SVGs).
  • Updated Scratch project endpoints to authorize access and to reuse an existing remix instead of creating duplicates.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
app/controllers/api/scratch/assets_controller.rb Requires X-Project-ID, enforces authorization, scopes asset reads/writes to project/remix visibility, and can auto-create a remix for uploads.
app/controllers/api/scratch/projects_controller.rb Adds explicit authorization for show/update and reuses an existing remix on remix create.
app/controllers/concerns/scratch_remix_creation.rb New concern to create a remix with fallback Scratch content when needed (e.g., asset upload before first save).
app/models/scratch_asset.rb Introduces project scoping, global/project scopes, lineage-based asset lookup, and SVG content-type policy.
app/models/project.rb Adds self_and_ancestor_ids to support remix-lineage asset resolution.
db/migrate/20260410110000_scope_scratch_assets_to_projects.rb Adds project_id, removes old uniqueness, backfills legacy assets to projects, and adds partial unique indexes.
db/schema.rb Reflects scratch_assets.project_id and new indexes/foreign key.
lib/scratch_asset_importer.rb Ensures imports only short-circuit on existing global assets and creates imported assets as global (project_id: nil).
spec/factories/scratch_assets.rb Sets default project: nil for assets in tests.
spec/lib/scratch_asset_importer_spec.rb Adds expectations around global imports and filename collisions with project assets.
spec/features/scratch/creating_and_showing_a_scratch_asset_spec.rb Expands coverage for X-Project-ID, project scoping, remix/ancestor fallback, SVG content-type policy, and concurrent/idempotent uploads.
spec/features/scratch/creating_a_scratch_asset_spec.rb Updates request headers/tests for X-Project-ID requirement.
spec/features/scratch/creating_a_scratch_project_spec.rb Updates authorization expectations and tests remix reuse behavior.
spec/features/scratch/showing_a_scratch_project_spec.rb Adds private-project access control tests (unauthenticated vs owner).
spec/features/scratch/updating_a_scratch_project_spec.rb Updates cat_mode setup and adds “forbidden when cannot update” coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/models/scratch_asset.rb Outdated
Comment thread app/controllers/api/scratch/assets_controller.rb Outdated
Comment thread db/migrate/20260410110000_scope_scratch_assets_to_projects.rb Outdated
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch 3 times, most recently from aa15b2d to 9c7b3e6 Compare April 15, 2026 13:58
@abcampo-iry abcampo-iry requested a review from Copilot April 15, 2026 14:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/services/scratch_asset_project_backfill_service.rb Outdated
Comment thread app/services/scratch_asset_project_backfill_service.rb Outdated
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch 5 times, most recently from 939c90e to 3ce43b4 Compare April 16, 2026 15:43
@abcampo-iry abcampo-iry marked this pull request as draft April 16, 2026 15:46
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch 2 times, most recently from a5d5dd9 to ef6a5ac Compare April 16, 2026 15:49
@raspberrypiherokubot raspberrypiherokubot temporarily deployed to editor-api-p-issues-126-ru3uo4 April 16, 2026 15:49 Inactive
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch 2 times, most recently from e218a2d to 0effe97 Compare April 16, 2026 15:59
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch from 0effe97 to 5cb0c28 Compare April 16, 2026 16:24
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch from 5cb0c28 to 10ee4a0 Compare April 17, 2026 14:31
@abcampo-iry abcampo-iry marked this pull request as ready for review April 17, 2026 14:59
@abcampo-iry abcampo-iry marked this pull request as draft April 17, 2026 15:11
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch from 10ee4a0 to 1b8ce23 Compare April 17, 2026 16:41
@abcampo-iry abcampo-iry force-pushed the issues/1263-scope-assets-to-project-in-scratch branch from 1b8ce23 to f502f28 Compare April 17, 2026 16:47
@abcampo-iry abcampo-iry marked this pull request as ready for review April 19, 2026 22:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants