Add a REST API endpoint to restore a soft-deleted organization

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Add a REST API endpoint that restores a soft-deleted organization (transitions it from soft_deleted back to active) by exposing Organizations::RestoreService (from #599343 (closed)). Admin-only.

Dependency

Blocked by #599343 (closed), which provides:

  • Organizations::RestoreService (the service this endpoint calls), and
  • the :restore_organization policy ability (admin-only) used for authorize!.

The route_setting :authorization, permissions: :restore_organization also relies on the granular-token permission registry defined in #599344 (closed) (config/authz/permissions/organization/restore.yml). Whichever of #599344 (closed) / this issue lands first should add that file.

Background

The Organizations REST API (lib/api/organizations.rb) currently exposes only POST /organizations (create). There is no member route yet. The Groups API already has a direct template for this in lib/api/groups.rb — POST /groups/:id/restore calling Groups::RestoreService — which this endpoint mirrors. The find_organization! helper (lib/api/helpers.rb) already loads an organization and enforces :read_organization.

Implementation plan

1. Endpoint — lib/api/organizations.rb

Add a member route inside the existing resource :organizations block, mirroring the create action's style (route_setting :lifecycle, :experiment, route_setting :authorization, ServiceResponse handling):

desc 'Restore a soft-deleted organization' do
  detail 'This feature was introduced in GitLab 19.1.'
  success Entities::Organizations::Organization
  tags %w[organizations]
end
params do
  requires :id, type: Integer, desc: 'The ID of the organization'
end
route_setting :lifecycle, :experiment
route_setting :authorization, permissions: :restore_organization, boundary_type: :instance
post ':id/restore' do
  organization = find_organization!(params[:id])
  authorize! :restore_organization, organization

  response = ::Organizations::RestoreService
    .new(organization, current_user: current_user)
    .execute

  if response.success?
    present response[:organization], with: Entities::Organizations::Organization
  else
    render_api_error!(response.message, :bad_request)
  end
end

Notes:

  • find_organization! returns not_found! for unknown IDs and enforces :read_organization; soft-deleted organizations remain readable (no default scope hides them), and find_by_id finds them.
  • authorize! :restore_organization enforces the admin-only ability from #599343 (closed) — non-admin owners who can read the org are still rejected.
  • The existing Entities::Organizations::Organization is reused as-is for the response; no entity changes needed.

2. Documentation — doc/api/organizations.md

Add a "Restore an organization" section after "Create an organization", documenting:

  • POST /organizations/:id/restore
  • the id attribute,
  • a curl example and a sample response (the organization entity),
  • the experiment/admin-only note.

3. Request spec — spec/requests/api/organizations_spec.rb

Add describe 'POST /organizations/:id/restore' covering:

  • Unauthenticated request → 401.
  • Authenticated non-admin (e.g. org owner) → 403.
  • Unknown organization ID → 404.
  • Admin restoring a soft_deleted organization → 201/200 with the organization payload, state becomes active.
  • Admin restoring a non-soft_deleted organization → 400 with the service error message.

Out of scope

Acceptance criteria

  • POST /organizations/:id/restore exists and calls Organizations::RestoreService.
  • The endpoint is admin-only via authorize! :restore_organization and declares the matching granular-token route_setting :authorization, consistent with the create endpoint.
  • Restoring a soft-deleted organization returns the organization and transitions it to active.
  • Validation/permission failures return appropriate HTTP status codes (400/403/404).
  • The endpoint is behind the experiment lifecycle marker.
  • REST API docs (doc/api/organizations.md) document the new endpoint.
  • Request spec covers auth, success, validation failure, and not-found cases.
Edited by 🤖 GitLab Bot 🤖