diff --git a/app/controllers/locomotive/api/sites_controller.rb b/app/controllers/locomotive/api/sites_controller.rb new file mode 100644 index 00000000..11469abe --- /dev/null +++ b/app/controllers/locomotive/api/sites_controller.rb @@ -0,0 +1,44 @@ +module Locomotive + module Api + class SitesController < BaseController + + load_and_authorize_resource :class => Locomotive::Site + + # FIXME: the auto-loaded site won't pass authorization for show, update, or destroy + skip_load_and_authorize_resource :only => [ :show, :update, :destroy ] + + def index + @sites = Locomotive::Site.all + respond_with(@sites) + end + + def show + @site = Locomotive::Site.find(params[:id]) + authorize! :show, @site + respond_with(@site) + end + + def create + @site = Locomotive::Site.create(params[:site]) + respond_with(@site) + end + + def update + @site = Locomotive::Site.find(params[:id]) + authorize! :update, @site + @site.update_attributes(params[:site]) + respond_with @site + end + + def destroy + @site = Locomotive::Site.find(params[:id]) + authorize! :destroy, @site + @site.destroy + respond_with @site + end + + end + + end +end + diff --git a/config/routes.rb b/config/routes.rb index f69a9e31..3c16bf32 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -68,6 +68,8 @@ Rails.application.routes.draw do resources :content_entries, :path => 'content_types/:slug/entries' + resources :sites + resource :current_site, :controller => 'current_site' end diff --git a/features/api/authorization/sites.feature b/features/api/authorization/sites.feature new file mode 100644 index 00000000..bb7b393a --- /dev/null +++ b/features/api/authorization/sites.feature @@ -0,0 +1,206 @@ +Feature: Sites + In order to ensure sites are not tampered with + As an admin, designer or author + I will be restricted based on my role + + Background: + Given I have the site: "test site" set up with id: "4f832c2cb0d86d3f42fffffe" + And I have the site: "another site" set up with id: "4f832c2cb0d86d3f42ffffff" + And I have a designer and an author + + Scenario: As an unauthenticated user + Given I am not authenticated + When I do an API GET to sites.json + Then the JSON response at "error" should be "You need to sign in or sign up before continuing." + + # listing sites + + Scenario: Accessing sites as an Admin + Given I have an "admin" API token + When I do an API GET request to sites.json + Then the JSON response should be an array + And the JSON response should have 2 entries + + Scenario: Accessing sites as a Designer + Given I have a "designer" API token + When I do an API GET request to sites.json + Then an access denied error should occur + + Scenario: Accessing sites as an Author + Given I have an "author" API token + When I do an API GET request to sites.json + Then an access denied error should occur + + # showing site + + Scenario: Accessing site as an Admin + Given I have an "admin" API token + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then the JSON response at "name" should be "Locomotive test website" + + Scenario: Accessing my site as a Designer + Given I have a "designer" API token + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then the JSON response at "name" should be "Locomotive test website" + + Scenario: Accessing other site as a Designer + Given I have a "designer" API token + When I do an API GET request to sites/4f832c2cb0d86d3f42ffffff.json + Then an access denied error should occur + + Scenario: Accessing my site as an Author + Given I have an "author" API token + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then the JSON response at "name" should be "Locomotive test website" + + Scenario: Accessing other site as an Author + Given I have an "author" API token + When I do an API GET request to sites/4f832c2cb0d86d3f42ffffff.json + Then an access denied error should occur + + # create site + + Scenario: Creating new site as an Admin + Given I have an "admin" API token + When I do an API GET request to sites.json + Then the JSON response should be an array + And the JSON response should have 2 entries + When I do an API POST to sites.json with: + """ + { + "site": { + "name": "New site", + "subdomain": "new-site" + } + } + """ + When I do an API GET request to sites.json + Then the JSON response should be an array + And the JSON response should have 3 entries + + Scenario: Creating new site as a Designer + Given I have a "designer" API token + When I do an API POST to sites.json with: + """ + { + "site": { + "name": "New site", + "subdomain": "new-site" + } + } + """ + Then an access denied error should occur + + Scenario: Creating new site as an Author + Given I have an "author" API token + When I do an API POST to sites.json with: + """ + { + "site": { + "name": "New site", + "subdomain": "new-site" + } + } + """ + Then an access denied error should occur + + # update site + + Scenario: Updating site as an Admin + Given I have an "admin" API token + When I do an API PUT to sites/4f832c2cb0d86d3f42fffffe.json with: + """ + { + "site": { + "name": "Brand new updated name" + } + } + """ + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe" + And the JSON response at "name" should be "Brand new updated name" + + Scenario: Updating my site as a Designer + Given I have a "designer" API token + When I do an API PUT to sites/4f832c2cb0d86d3f42fffffe.json with: + """ + { + "site": { + "name": "Brand new updated name" + } + } + """ + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe" + And the JSON response at "name" should be "Brand new updated name" + + Scenario: Updating other site as a Designer + Given I have a "designer" API token + When I do an API PUT to sites/4f832c2cb0d86d3f42ffffff.json with: + """ + { + "site": { + "name": "Brand new updated name" + } + } + """ + Then an access denied error should occur + + Scenario: Updating my site as an Author + Given I have a "author" API token + When I do an API PUT to sites/4f832c2cb0d86d3f42fffffe.json with: + """ + { + "site": { + "name": "Brand new updated name" + } + } + """ + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe" + And the JSON response at "name" should be "Brand new updated name" + + Scenario: Updating other site as an Author + Given I have a "author" API token + When I do an API PUT to sites/4f832c2cb0d86d3f42ffffff.json with: + """ + { + "site": { + "name": "Brand new updated name" + } + } + """ + Then an access denied error should occur + + # destroy site + + Scenario: Destroying site as an Admin + Given I have an "admin" API token + When I do an API GET request to sites.json + Then the JSON response should be an array + And the JSON response should have 2 entries + When I do an API DELETE to sites/4f832c2cb0d86d3f42fffffe.json + When I do an API GET request to sites.json + Then the JSON response should be an array + And the JSON response should have 1 entries + + Scenario: Destroying my site as a Designer + Given I have a "designer" API token + When I do an API DELETE to sites/4f832c2cb0d86d3f42fffffe.json + When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json + Then it should not exist + + Scenario: Deleting other site as a Designer + Given I have a "designer" API token + When I do an API DELETE to sites/4f832c2cb0d86d3f42ffffff.json + Then an access denied error should occur + + Scenario: Deleting my site as an Author + Given I have a "author" API token + When I do an API DELETE to sites/4f832c2cb0d86d3f42fffffe.json + Then an access denied error should occur + + Scenario: Deleting other site as an Author + Given I have a "author" API token + When I do an API DELETE to sites/4f832c2cb0d86d3f42ffffff.json + Then an access denied error should occur diff --git a/features/step_definitions/api_steps.rb b/features/step_definitions/api_steps.rb index 92745a03..0d3ad2fb 100644 --- a/features/step_definitions/api_steps.rb +++ b/features/step_definitions/api_steps.rb @@ -1,6 +1,6 @@ def api_base_url - "http://#{@site.domains.first}/locomotive/api/" + "http://#{Locomotive::Site.first.domains.first}/locomotive/api/" end def do_api_request(type, url, param_string_or_hash = nil) @@ -16,7 +16,7 @@ def do_api_request(type, url, param_string_or_hash = nil) end @json_response = do_request(type, api_base_url, url, params.merge({ 'CONTENT_TYPE' => 'application/json' })) - rescue CanCan::AccessDenied + rescue CanCan::AccessDenied, Mongoid::Errors::DocumentNotFound @error = $! end end @@ -76,6 +76,11 @@ Then /^an access denied error should occur$/ do @error.is_a?(CanCan::AccessDenied).should be_true end +Then /^it should not exist$/ do + @error.should_not be_nil + @error.is_a?(Mongoid::Errors::DocumentNotFound).should be_true +end + When /^I do a multipart API (\w+) (?:request )?to ([\w.\/]+) with base key "([^"]*)" and:$/ \ do |request_type, url, base_key, table| params = {} @@ -85,3 +90,7 @@ When /^I do a multipart API (\w+) (?:request )?to ([\w.\/]+) with base key "([^" end do_api_request(request_type, url, { base_key => params }) end + +Then /^I print the json response$/ do + puts %{JSON: "#{last_json}"} +end