Skip to content

Commit

Permalink
Add a new endpoint to unreserve a path
Browse files Browse the repository at this point in the history
This adds a new command to unreserve (destroy) a PathReservation,
provided the reservation exists and matches the given publishing app.

As we migrate formats from Whitehall to Content Publisher, users
sometimes need to revert to Whitehall if certain features aren't
available. Because Whitehall assumes it is authoritative for all paths
in a format, we need to be able to cleanup the Publishing API in order
for the user to re-create their content in Whitehall and re-use a path.
  • Loading branch information
Ben Thorner committed Mar 18, 2019
1 parent 0b1cdab commit 8014783
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 0 deletions.
30 changes: 30 additions & 0 deletions app/commands/unreserve_path.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module Commands
class UnreservePath < BaseCommand
def call
reservation = lookup_reservation
check_is_owned_by_app(reservation)
reservation.destroy
Success.new(payload)
end

private

def lookup_reservation
PathReservation.find_by!(
base_path: payload[:base_path]
)
rescue ActiveRecord::RecordNotFound
msg = "#{payload[:base_path]} is not reserved"
raise CommandError.new(code: 404, message: msg)
end

def check_is_owned_by_app(reservation)
publishing_app = payload[:publishing_app]
base_path = payload[:base_path]
return if reservation.publishing_app == publishing_app

msg = "#{base_path} is reserved by #{reservation.publishing_app}"
raise CommandError.new(code: 422, message: msg)
end
end
end
5 changes: 5 additions & 0 deletions app/controllers/path_reservations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ def reserve_path
render status: response.code, json: response
end

def unreserve_path
response = Commands::UnreservePath.call(path_item)
render status: response.code, json: response
end

private

def path_item
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def content_id_constraint(request)
delete "/publish-intent(/*base_path)", to: "publish_intents#destroy"

put "/paths(/*base_path)", to: "path_reservations#reserve_path"
delete "/paths(/*base_path)", to: "path_reservations#unreserve_path"

post '/lookup-by-base-path', to: 'lookups#by_base_path'

Expand Down
24 changes: 24 additions & 0 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ message queue for other apps (e.g. `email-alert-service`) to consume.
- [`POST /v2/links/by-content-id`](#post-v2linksby-content-id)
- [`POST /lookup-by-base-path`](#post-lookup-by-base-path)
- [`PUT /paths/:base_path`](#put-pathsbase_path)
- [`DELETE /paths/:base_path`](#delete-pathsbase_path)
- [`GET /debug/:content_id`](#get-debugcontent_id)

### Optimistic locking (`previous_version`)
Expand Down Expand Up @@ -718,6 +719,29 @@ Reserves a path for a publishing application. Returns success or failure only.
publishing_app, and `override_existing` is true, the existing reservation will
be updated to the supplied publishing_app.

## `DELETE /paths/:base_path`

[Request/response detail][unreserve-path-pact]

Unreserves a path for a publishing application. Returns success or failure only.

### Path parameters

- `base_path`
- Identifies the path that will be unreserved

### JSON parameters:

- `publishing_app` *(required)*
- The name of the application making this request, words separated with hyphens.

### State changes

- If no path reservation for the supplied base_path is present, the command will
fail.
- If a path reservation exists for the supplied base_path but a different
publishing_app, the command will fail.

## `GET /debug/:content_id`

Displays debug information for `content_id`.
Expand Down
40 changes: 40 additions & 0 deletions spec/commands/unreserve_path_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require "rails_helper"

RSpec.describe Commands::UnreservePath do
describe "#call" do
context "when the path is owned by the app" do
it "successfully removes the reservation" do
payload = { publishing_app: "foo", base_path: "/bar" }
create(:path_reservation, payload)
described_class.call(payload)
expect(PathReservation.count).to be_zero
end
end

context "when the path is not owned by the app" do
it "returns an error" do
payload = { base_path: "/bar", publishing_app: "foo" }

create(:path_reservation,
base_path: "/bar",
publishing_app: "bar")

expect { described_class.call(payload) }
.to raise_error(
CommandError, /is reserved/
)
end
end

context "when the path has not been reserved" do
it "returns an error" do
payload = { base_path: "/bar" }

expect { described_class.call(payload) }
.to raise_error(
CommandError, /is not reserved/
)
end
end
end
end
27 changes: 27 additions & 0 deletions spec/controllers/path_reservations_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,31 @@
end
end
end

describe "unreserve_path" do
let(:payload) { { publishing_app: "foo" } }

context "with a valid path unreservation request" do
it "responds successfuly" do
create(:path_reservation, base_path: "/bar", publishing_app: "foo")
delete :unreserve_path, params: { base_path: "bar" }, body: payload.to_json
expect(response.status).to eq(200)
end
end

context "with an invalid path unreservation request" do
it "responds with status 422" do
create(:path_reservation, base_path: "/bar")
delete :unreserve_path, params: { base_path: "bar" }, body: payload.to_json
expect(response.status).to eq(422)
end
end

context "with a non-existant path unreservation request" do
it "responds with status 404" do
delete :unreserve_path, params: { base_path: "bar" }, body: payload.to_json
expect(response.status).to eq(404)
end
end
end
end
32 changes: 32 additions & 0 deletions spec/requests/unreserve_path_requests_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require "rails_helper"

RSpec.describe "DELETE /paths", type: :request do
let(:request_body) { payload.to_json }

def do_request(body: request_body, headers: {})
delete request_path, params: body, headers: headers
end

context "with path /vat-rates" do
let(:request_path) { "/paths#{base_path}" }
let(:payload) { { publishing_app: "publisher" } }

before do
create(:path_reservation,
base_path: base_path,
publishing_app: "publisher")
end

it "responds successfully" do
do_request

expect(response.status).to eq(200)
end

it "unreserves the path" do
expect {
do_request
}.to change(PathReservation, :count).by(-1)
end
end
end

0 comments on commit 8014783

Please sign in to comment.