Skip to content

Accept or decline transfer of ownership - #1025

Open
DNR500 wants to merge 3 commits into
create-and-get-ownership-transferfrom
accept-or-decline-transfer-ownership
Open

DNR500 wants to merge 3 commits into
create-and-get-ownership-transferfrom
accept-or-decline-transfer-ownership

Conversation

@DNR500

@DNR500 DNR500 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds the two endpoints that let the person being asked to take over a school actually respond — accepting it, or turning it down.

What's changed?

  • PUT /api/schools/:school_id/ownership_transfer/accept — the nominee accepts. The transfer's status becomes "completed".
  • PUT /api/schools/:school_id/ownership_transfer/decline — the nominee turns it down. The transfer's status becomes "rejected".

Both endpoints:

  • Only work for the actual person who was nominated — not the owner who sent the request, and not anyone else at the school.
  • Only work while the transfer is still waiting for a response. Trying to accept or decline something that's already been dealt with (or never existed) gets the same "not found" response either way, so no one can tell the difference between "there's nothing here" and "you're just not allowed to see it."
  • Don't need anything in the request body — the school and the logged-in user are enough to know what's being responded to.

Examples

Accepting or declining, as the nominee:

PUT /api/schools/9d9c1e3e-1e4b-4b0a-9a2e-6a2b7e6f1a10/ownership_transfer/accept
Authorization: Bearer <nominee's token>
200 OK

(empty body — the frontend already knows what happened because it made the request; it re-checks the transfer's status separately if it needs to)

If you're not the nominee, or there's nothing waiting to be responded to:

404 Not Found

Other responses: 401 (no token), 403 (you're a student — students were never allowed near this feature in the first place).

PUT /api/schools/:school_id/ownership_transfer/accept marks the
school's pending transfer as completed. Only the nominee can accept -
neither the requester nor anyone else at the school - and only while a
transfer is actually pending; anything else responds 404, matching the
same "don't reveal what you can't see" shape the show endpoint already
uses rather than distinguishing "no transfer" from "not your transfer".
PUT /api/schools/:school_id/ownership_transfer/decline marks the
school's pending transfer as rejected. Reuses accept's resolve!/
pending_ownership_transfer helpers - the two actions differ only in
which status they set - and the same authorization shape (nominee only,
pending only, 404 otherwise).
@cla-bot cla-bot Bot added the cla-signed label Sep 18, 2026
Comment thread lib/concepts/ownership_transfer/create.rb Dismissed
Comment thread lib/concepts/ownership_transfer/create.rb Dismissed
@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown

Test coverage

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

@DNR500
DNR500 changed the base branch from main to create-and-get-ownership-transfer September 18, 2026 16:19
@DNR500
DNR500 marked this pull request as ready for review September 18, 2026 16:50
@DNR500
DNR500 requested a lite review from Copilot September 18, 2026 16:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Address the concurrency, ownership-transition, and self-nomination authorization issues.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds authenticated endpoints for nominees to accept or decline school ownership transfers.

Changes:

  • Adds accept/decline routes and controller actions.
  • Restricts responses to nominated users with pending transfers.
  • Adds authorization and request coverage.
File summaries
File Summary
spec/features/ownership_transfer/declining_an_ownership_transfer_spec.rb Adds decline endpoint coverage.
spec/features/ownership_transfer/accepting_an_ownership_transfer_spec.rb Adds acceptance endpoint coverage.
config/routes.rb Registers accept and decline routes.
app/models/ability.rb Adds transfer-response permissions; self-nominations remain insufficiently restricted.
app/controllers/api/ownership_transfers_controller.rb Resolves transfers, but lacks atomic locking and does not perform the ownership transition.
Review details

Suppressed comments (1)

app/models/ability.rb:46

  • This predicate only checks the nominated ID, so an owner can nominate their own ID (the create path permits any existing owner/teacher) and then pass this authorization as both requester and nominee. That violates the endpoint contract that the requester cannot accept or decline their own request; exclude requested_by_user_id here (or reject self-nominations when creating the transfer).
    can %i[accept decline], OwnershipTransfer do |transfer|
      user.id == transfer.nominated_user_id
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread app/controllers/api/ownership_transfers_controller.rb Outdated
Comment thread app/controllers/api/ownership_transfers_controller.rb Outdated
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