commit
5f9c46b42c
@ -7,15 +7,13 @@ module Locomotive
|
|||||||
|
|
||||||
skip_before_filter :verify_authenticity_token
|
skip_before_filter :verify_authenticity_token
|
||||||
|
|
||||||
skip_load_and_authorize_resource
|
|
||||||
|
|
||||||
before_filter :require_account
|
before_filter :require_account
|
||||||
|
|
||||||
before_filter :require_site
|
before_filter :require_site
|
||||||
|
|
||||||
before_filter :set_locale
|
before_filter :set_locale
|
||||||
|
|
||||||
# before_filter :validate_site_membership
|
before_filter :set_current_thread_variables
|
||||||
|
|
||||||
self.responder = Locomotive::ActionController::Responder # custom responder
|
self.responder = Locomotive::ActionController::Responder # custom responder
|
||||||
|
|
||||||
@ -23,6 +21,11 @@ module Locomotive
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def set_current_thread_variables
|
||||||
|
Thread.current[:account] = current_locomotive_account
|
||||||
|
Thread.current[:site] = current_site
|
||||||
|
end
|
||||||
|
|
||||||
def current_ability
|
def current_ability
|
||||||
@current_ability ||= Ability.new(current_locomotive_account, current_site)
|
@current_ability ||= Ability.new(current_locomotive_account, current_site)
|
||||||
end
|
end
|
||||||
|
@ -2,11 +2,18 @@ module Locomotive
|
|||||||
module Api
|
module Api
|
||||||
class ContentAssetsController < BaseController
|
class ContentAssetsController < BaseController
|
||||||
|
|
||||||
|
load_and_authorize_resource :class => Locomotive::ContentAsset
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@content_assets = current_site.content_assets
|
@content_assets = current_site.content_assets
|
||||||
respond_with(@content_assets)
|
respond_with(@content_assets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@content_asset = current_site.content_assets.find(params[:id])
|
||||||
|
respond_with(@content_asset)
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@content_asset = current_site.content_assets.create(params[:content_asset])
|
@content_asset = current_site.content_assets.create(params[:content_asset])
|
||||||
respond_with @content_asset, :location => main_app.locomotive_api_content_assets_url
|
respond_with @content_asset, :location => main_app.locomotive_api_content_assets_url
|
||||||
@ -18,6 +25,12 @@ module Locomotive
|
|||||||
respond_with @content_asset, :location => main_app.locomotive_api_content_assets_url
|
respond_with @content_asset, :location => main_app.locomotive_api_content_assets_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@content_asset = current_site.content_assets.find(params[:id])
|
||||||
|
@content_asset.destroy
|
||||||
|
respond_with @content_asset
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,11 +2,18 @@ module Locomotive
|
|||||||
module Api
|
module Api
|
||||||
class ContentTypesController < BaseController
|
class ContentTypesController < BaseController
|
||||||
|
|
||||||
|
load_and_authorize_resource :class => Locomotive::ContentType
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@content_types = current_site.content_types
|
@content_types = current_site.content_types
|
||||||
respond_with(@content_types)
|
respond_with(@content_types)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@content_type = current_site.content_types.find(params[:id])
|
||||||
|
respond_with @content_type
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@content_type = current_site.content_types.create(params[:content_type])
|
@content_type = current_site.content_types.create(params[:content_type])
|
||||||
respond_with @content_type, :location => main_app.locomotive_api_content_types_url
|
respond_with @content_type, :location => main_app.locomotive_api_content_types_url
|
||||||
@ -18,6 +25,12 @@ module Locomotive
|
|||||||
respond_with @content_type, :location => main_app.locomotive_api_content_types_url
|
respond_with @content_type, :location => main_app.locomotive_api_content_types_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@content_type = current_site.content_types.find(params[:id])
|
||||||
|
@content_type.destroy
|
||||||
|
respond_with @content_type
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,7 +3,9 @@ module Locomotive
|
|||||||
class CurrentSiteController < BaseController
|
class CurrentSiteController < BaseController
|
||||||
|
|
||||||
def show
|
def show
|
||||||
respond_with(current_site)
|
@site = current_site
|
||||||
|
authorize! :show, @site
|
||||||
|
respond_with(@site)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
49
app/controllers/locomotive/api/memberships_controller.rb
Normal file
49
app/controllers/locomotive/api/memberships_controller.rb
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Api
|
||||||
|
class MembershipsController < BaseController
|
||||||
|
|
||||||
|
# It's an embedded document, so we'll just load manually
|
||||||
|
before_filter :load_membership, :only => [ :show, :update, :destroy ]
|
||||||
|
before_filter :load_memberships, :only => [ :index ]
|
||||||
|
|
||||||
|
authorize_resource :class => Locomotive::Membership
|
||||||
|
|
||||||
|
def index
|
||||||
|
respond_with(@memberships)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
respond_with(@membership)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
build_params = params[:membership].merge({ :role => 'author' }) # force author by default
|
||||||
|
@membership = current_site.memberships.create(build_params)
|
||||||
|
respond_with(@membership)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@membership.update_attributes(params[:membership])
|
||||||
|
respond_with(@membership)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@membership.destroy
|
||||||
|
respond_with(@membership)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def load_membership
|
||||||
|
@membership ||= load_memberships.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_memberships
|
||||||
|
@memberships ||= current_site.memberships
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||||||
module Api
|
module Api
|
||||||
class PagesController < BaseController
|
class PagesController < BaseController
|
||||||
|
|
||||||
|
load_and_authorize_resource :class => Locomotive::Page
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@pages = current_site.pages.order_by([[:depth, :asc], [:position, :asc]])
|
@pages = current_site.pages.order_by([[:depth, :asc], [:position, :asc]])
|
||||||
respond_with(@pages)
|
respond_with(@pages)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@page = current_site.pages.find(params[:id])
|
||||||
|
respond_with(@page)
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@page = current_site.pages.create(params[:page])
|
@page = current_site.pages.create(params[:page])
|
||||||
respond_with @page, :location => main_app.locomotive_api_pages_url
|
respond_with @page, :location => main_app.locomotive_api_pages_url
|
||||||
@ -18,6 +25,12 @@ module Locomotive
|
|||||||
respond_with @page, :location => main_app.locomotive_api_pages_url
|
respond_with @page, :location => main_app.locomotive_api_pages_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@page = current_site.pages.find(params[:id])
|
||||||
|
@page.destroy
|
||||||
|
respond_with @page
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
44
app/controllers/locomotive/api/sites_controller.rb
Normal file
44
app/controllers/locomotive/api/sites_controller.rb
Normal file
@ -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
|
||||||
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||||||
module Api
|
module Api
|
||||||
class SnippetsController < BaseController
|
class SnippetsController < BaseController
|
||||||
|
|
||||||
|
load_and_authorize_resource :class => Locomotive::Snippet
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@snippets = current_site.snippets.all
|
@snippets = current_site.snippets.all
|
||||||
respond_with(@snippets)
|
respond_with(@snippets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@snippet = current_site.snippets.find(params[:id])
|
||||||
|
respond_with @snippet
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@snippet = current_site.snippets.create(params[:snippet])
|
@snippet = current_site.snippets.create(params[:snippet])
|
||||||
respond_with @snippet, :location => main_app.locomotive_api_snippets_url
|
respond_with @snippet, :location => main_app.locomotive_api_snippets_url
|
||||||
@ -18,6 +25,12 @@ module Locomotive
|
|||||||
respond_with @snippet, :location => main_app.locomotive_api_snippets_url
|
respond_with @snippet, :location => main_app.locomotive_api_snippets_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@snippet = current_site.snippets.find(params[:id])
|
||||||
|
@snippet.destroy
|
||||||
|
respond_with @snippet
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,11 +2,18 @@ module Locomotive
|
|||||||
module Api
|
module Api
|
||||||
class ThemeAssetsController < BaseController
|
class ThemeAssetsController < BaseController
|
||||||
|
|
||||||
|
load_and_authorize_resource :class => Locomotive::ThemeAsset
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@theme_assets = current_site.theme_assets.all
|
@theme_assets = current_site.theme_assets.all
|
||||||
respond_with(@theme_assets)
|
respond_with(@theme_assets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@theme_asset = current_site.theme_assets.find(params[:id])
|
||||||
|
respond_with @theme_asset
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@theme_asset = current_site.theme_assets.create(params[:theme_asset])
|
@theme_asset = current_site.theme_assets.create(params[:theme_asset])
|
||||||
respond_with @theme_asset, :location => main_app.locomotive_api_theme_assets_url
|
respond_with @theme_asset, :location => main_app.locomotive_api_theme_assets_url
|
||||||
@ -18,6 +25,12 @@ module Locomotive
|
|||||||
respond_with @theme_asset, :location => main_app.locomotive_api_theme_assets_url
|
respond_with @theme_asset, :location => main_app.locomotive_api_theme_assets_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@theme_asset = current_site.theme_assets.find(params[:id])
|
||||||
|
@theme_asset.destroy
|
||||||
|
respond_with @theme_asset
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -37,6 +37,8 @@ module Locomotive
|
|||||||
can :touch, Site do |site|
|
can :touch, Site do |site|
|
||||||
site == @site
|
site == @site
|
||||||
end
|
end
|
||||||
|
|
||||||
|
can :read, ContentType
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_designer_permissions!
|
def setup_designer_permissions!
|
||||||
|
@ -68,6 +68,10 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
resources :content_entries, :path => 'content_types/:slug/entries'
|
resources :content_entries, :path => 'content_types/:slug/entries'
|
||||||
|
|
||||||
|
resources :sites
|
||||||
|
|
||||||
|
resources :memberships
|
||||||
|
|
||||||
resource :current_site, :controller => 'current_site'
|
resource :current_site, :controller => 'current_site'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
147
features/api/authorization/content_assets.feature
Normal file
147
features/api/authorization/content_assets.feature
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
Feature: Content Assets
|
||||||
|
In order to ensure content assets 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
|
||||||
|
And I have the following content assets:
|
||||||
|
| id | file |
|
||||||
|
| 4f832c2cb0d86d3f42fffffe | 5k.png |
|
||||||
|
| 4f832c2cb0d86d3f42ffffff | 5k_2.png |
|
||||||
|
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 content_assets.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing content assets
|
||||||
|
|
||||||
|
Scenario: Accessing content assets as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
Scenario: Accessing content assets as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
Scenario: Accessing content assets as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
# showing content asset
|
||||||
|
|
||||||
|
Scenario: Accessing content asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "filename" should be "5k.png"
|
||||||
|
|
||||||
|
Scenario: Accessing content asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "filename" should be "5k.png"
|
||||||
|
|
||||||
|
Scenario: Accessing content asset as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "filename" should be "5k.png"
|
||||||
|
|
||||||
|
# create content asset
|
||||||
|
|
||||||
|
Scenario: Creating new content asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do a multipart API POST to content_assets.json with base key "content_asset" and:
|
||||||
|
| source | assets/application.js |
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON at "2/filename" should be "application.js"
|
||||||
|
|
||||||
|
Scenario: Creating new content asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do a multipart API POST to content_assets.json with base key "content_asset" and:
|
||||||
|
| source | assets/application.js |
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON at "2/filename" should be "application.js"
|
||||||
|
|
||||||
|
Scenario: Creating new content asset as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do a multipart API POST to content_assets.json with base key "content_asset" and:
|
||||||
|
| source | assets/application.js |
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON at "2/filename" should be "application.js"
|
||||||
|
|
||||||
|
# update content asset
|
||||||
|
|
||||||
|
Scenario: Updating content asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do a multipart API PUT to content_assets/4f832c2cb0d86d3f42fffffe.json with base key "content_asset" and:
|
||||||
|
| source | assets/main.css |
|
||||||
|
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "filename" should be "main.css"
|
||||||
|
|
||||||
|
Scenario: Updating content asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do a multipart API PUT to content_assets/4f832c2cb0d86d3f42fffffe.json with base key "content_asset" and:
|
||||||
|
| source | assets/main.css |
|
||||||
|
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "filename" should be "main.css"
|
||||||
|
|
||||||
|
Scenario: Updating content asset as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do a multipart API PUT to content_assets/4f832c2cb0d86d3f42fffffe.json with base key "content_asset" and:
|
||||||
|
| source | assets/main.css |
|
||||||
|
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "filename" should be "main.css"
|
||||||
|
|
||||||
|
# destroy content asset
|
||||||
|
|
||||||
|
Scenario: Destroying content asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Destroying content asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Deleting content asset as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
202
features/api/authorization/content_entries.feature
Normal file
202
features/api/authorization/content_entries.feature
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
Feature: Content Entries
|
||||||
|
In order to ensure content entries 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
|
||||||
|
And I have a custom model named "Projects" with
|
||||||
|
| label | type | required |
|
||||||
|
| Name | string | true |
|
||||||
|
| Description | text | false |
|
||||||
|
And I have entries for "Projects" with
|
||||||
|
| id | name | description |
|
||||||
|
| 4f832c2cb0d86d3f42fffffe | Project 1 | The first project |
|
||||||
|
| 4f832c2cb0d86d3f42ffffff | Project 2 | The second project |
|
||||||
|
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 content_types/projects/entries.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing content entries
|
||||||
|
|
||||||
|
Scenario: Accessing content entries as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
Scenario: Accessing content entries as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
Scenario: Accessing content entries as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
# showing content entry
|
||||||
|
|
||||||
|
Scenario: Accessing content entry as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "Project 1"
|
||||||
|
|
||||||
|
Scenario: Accessing content entry as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "Project 1"
|
||||||
|
|
||||||
|
Scenario: Accessing content entry as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "Project 1"
|
||||||
|
|
||||||
|
# create content entry
|
||||||
|
|
||||||
|
Scenario: Creating new content entry as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API POST to content_types/projects/entries.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_entry": {
|
||||||
|
"name": "Project 3",
|
||||||
|
"description": "The third..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 2/name | "Project 3" |
|
||||||
|
| 2/description | "The third..." |
|
||||||
|
|
||||||
|
Scenario: Creating new content entry as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API POST to content_types/projects/entries.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_entry": {
|
||||||
|
"name": "Project 3",
|
||||||
|
"description": "The third..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 2/name | "Project 3" |
|
||||||
|
| 2/description | "The third..." |
|
||||||
|
|
||||||
|
Scenario: Creating new content entry as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API POST to content_types/projects/entries.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_entry": {
|
||||||
|
"name": "Project 3",
|
||||||
|
"description": "The third..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 2/name | "Project 3" |
|
||||||
|
| 2/description | "The third..." |
|
||||||
|
|
||||||
|
# update content entry
|
||||||
|
|
||||||
|
Scenario: Updating content entry as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API PUT to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_entry": {
|
||||||
|
"description": "The awesomest project ever!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "name" should be "Project 1"
|
||||||
|
And the JSON response at "description" should be "The awesomest project ever!"
|
||||||
|
|
||||||
|
Scenario: Updating content entry as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API PUT to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_entry": {
|
||||||
|
"description": "The awesomest project ever!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "name" should be "Project 1"
|
||||||
|
And the JSON response at "description" should be "The awesomest project ever!"
|
||||||
|
|
||||||
|
Scenario: Updating content entry as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API PUT to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_entry": {
|
||||||
|
"description": "The awesomest project ever!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "name" should be "Project 1"
|
||||||
|
And the JSON response at "description" should be "The awesomest project ever!"
|
||||||
|
|
||||||
|
# destroy content entry
|
||||||
|
|
||||||
|
Scenario: Destroying content entry as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Destroying content entry as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Deleting content entry as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_types/projects/entries.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
237
features/api/authorization/content_types.feature
Normal file
237
features/api/authorization/content_types.feature
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
Feature: Content Types
|
||||||
|
In order to ensure content types 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
|
||||||
|
And I have a custom model named "Projects" with id "4f832c2cb0d86d3f42fffffe" and
|
||||||
|
| label | type | required |
|
||||||
|
| Name | string | true |
|
||||||
|
| Description | text | false |
|
||||||
|
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 content_types.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing content types
|
||||||
|
|
||||||
|
Scenario: Accessing content types as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Accessing content types as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Accessing content types as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
# showing content type
|
||||||
|
|
||||||
|
Scenario: Accessing content type as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "Projects"
|
||||||
|
|
||||||
|
Scenario: Accessing content type as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "Projects"
|
||||||
|
|
||||||
|
Scenario: Accessing content type as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "Projects"
|
||||||
|
|
||||||
|
# create content type
|
||||||
|
|
||||||
|
Scenario: Creating new content type as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API POST to content_types.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_type": {
|
||||||
|
"name": "Employees",
|
||||||
|
"slug": "employees",
|
||||||
|
"entries_custom_fields": [
|
||||||
|
{
|
||||||
|
"label": "Name",
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Position",
|
||||||
|
"name": "position",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 1/name | "Employees" |
|
||||||
|
| 1/slug | "employees" |
|
||||||
|
| 1/entries_custom_fields/0/label | "Name" |
|
||||||
|
| 1/entries_custom_fields/0/name | "name" |
|
||||||
|
| 1/entries_custom_fields/0/type | "string" |
|
||||||
|
| 1/entries_custom_fields/1/label | "Position" |
|
||||||
|
| 1/entries_custom_fields/1/name | "position" |
|
||||||
|
| 1/entries_custom_fields/1/type | "string" |
|
||||||
|
|
||||||
|
Scenario: Creating new content type as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API POST to content_types.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_type": {
|
||||||
|
"name": "Employees",
|
||||||
|
"slug": "employees",
|
||||||
|
"entries_custom_fields": [
|
||||||
|
{
|
||||||
|
"label": "Name",
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Position",
|
||||||
|
"name": "position",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 1/name | "Employees" |
|
||||||
|
| 1/slug | "employees" |
|
||||||
|
| 1/entries_custom_fields/0/label | "Name" |
|
||||||
|
| 1/entries_custom_fields/0/name | "name" |
|
||||||
|
| 1/entries_custom_fields/0/type | "string" |
|
||||||
|
| 1/entries_custom_fields/1/label | "Position" |
|
||||||
|
| 1/entries_custom_fields/1/name | "position" |
|
||||||
|
| 1/entries_custom_fields/1/type | "string" |
|
||||||
|
|
||||||
|
Scenario: Creating new content type as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API POST to content_types.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_type": {
|
||||||
|
"name": "Employees",
|
||||||
|
"slug": "employees",
|
||||||
|
"entries_custom_fields": [
|
||||||
|
{
|
||||||
|
"label": "Name",
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Position",
|
||||||
|
"name": "position",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# update content type
|
||||||
|
|
||||||
|
Scenario: Updating content type as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API PUT to content_types/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_type": {
|
||||||
|
"name": "Brand new updated name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/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 content type as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API PUT to content_types/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_type": {
|
||||||
|
"name": "Brand new updated name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to content_types/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 content type as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API PUT to content_types/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"content_type": {
|
||||||
|
"name": "Brand new updated name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# destroy content type
|
||||||
|
|
||||||
|
Scenario: Destroying content type as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API DELETE to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 0 entries
|
||||||
|
|
||||||
|
Scenario: Destroying content type as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API DELETE to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 0 entries
|
||||||
|
|
||||||
|
Scenario: Deleting content type as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API GET request to content_types.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entries
|
||||||
|
When I do an API DELETE to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
30
features/api/authorization/current_site.feature
Normal file
30
features/api/authorization/current_site.feature
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Feature: Current Site
|
||||||
|
In order to ensure the current site can be viewed by all authenticated users
|
||||||
|
As an admin, designer or author
|
||||||
|
I should be able to show the current site
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given I have the site: "test site" set up
|
||||||
|
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 current_site.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# showing current site
|
||||||
|
|
||||||
|
Scenario: Accessing current site as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET to current_site.json
|
||||||
|
Then the JSON response at "name" should be "Locomotive test website"
|
||||||
|
|
||||||
|
Scenario: Accessing current site as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET to current_site.json
|
||||||
|
Then the JSON response at "name" should be "Locomotive test website"
|
||||||
|
|
||||||
|
Scenario: Accessing current site as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET to current_site.json
|
||||||
|
Then the JSON response at "name" should be "Locomotive test website"
|
225
features/api/authorization/memberships.feature
Normal file
225
features/api/authorization/memberships.feature
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
Feature: Memberships
|
||||||
|
In order to ensure memberships 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: "4f832c2cb0d86d3f42fffffb"
|
||||||
|
And I have accounts:
|
||||||
|
| email | id |
|
||||||
|
| new-user@a.com | 4f832c2cb0d86d3f42fffffc |
|
||||||
|
And I have memberships:
|
||||||
|
| email | role | id |
|
||||||
|
| admin@a.com | admin | 4f832c2cb0d86d3f42fffffd |
|
||||||
|
| designer@a.com | designer | 4f832c2cb0d86d3f42fffffe |
|
||||||
|
| author@a.com | author | 4f832c2cb0d86d3f42ffffff |
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I do an API GET to memberships.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing memberships
|
||||||
|
|
||||||
|
Scenario: Accessing memberships as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
|
||||||
|
Scenario: Accessing memberships as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
|
||||||
|
Scenario: Accessing memberships as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# showing membership
|
||||||
|
|
||||||
|
Scenario: Accessing membership as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffd.json
|
||||||
|
Then the JSON response at "email" should be "admin@a.com"
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "email" should be "designer@a.com"
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
Then the JSON response at "email" should be "author@a.com"
|
||||||
|
|
||||||
|
Scenario: Accessing membership as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffd.json
|
||||||
|
Then the JSON response at "email" should be "admin@a.com"
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "email" should be "designer@a.com"
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
Then the JSON response at "email" should be "author@a.com"
|
||||||
|
|
||||||
|
Scenario: Accessing membership as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# create membership
|
||||||
|
|
||||||
|
Scenario: Creating new membership as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API POST to memberships.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||||
|
"account_id": "4f832c2cb0d86d3f42fffffc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 5 entries
|
||||||
|
|
||||||
|
Scenario: Creating new membership as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API POST to memberships.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||||
|
"account_id": "4f832c2cb0d86d3f42fffffc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 5 entries
|
||||||
|
|
||||||
|
Scenario: Creating new membership as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API POST to memberships.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||||
|
"account_id": "4f832c2cb0d86d3f42fffffc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
Scenario: Created membership should always be Author
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API POST to memberships.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||||
|
"account_id": "4f832c2cb0d86d3f42fffffc",
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 5 entries
|
||||||
|
And the JSON at "4/role" should be "author"
|
||||||
|
|
||||||
|
# update membership
|
||||||
|
|
||||||
|
Scenario: Updating membership as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
Then the JSON response at "role" should be "admin"
|
||||||
|
|
||||||
|
Scenario: Updating membership as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
Then the JSON response at "role" should be "author"
|
||||||
|
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"role": "designer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
Then the JSON response at "role" should be "designer"
|
||||||
|
|
||||||
|
Scenario: Updating membership as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"role": "designer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"membership": {
|
||||||
|
"role": "author"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# destroy membership
|
||||||
|
|
||||||
|
Scenario: Destroying membership as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API DELETE to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
|
||||||
|
Scenario: Destroying membership as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API DELETE to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||||
|
When I do an API GET request to memberships.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
When I do an API DELETE to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
||||||
|
When I do an API DELETE to memberships/4f832c2cb0d86d3f42fffffd.json
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
Scenario: Deleting membership as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API DELETE to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
187
features/api/authorization/pages.feature
Normal file
187
features/api/authorization/pages.feature
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
Feature: Pages
|
||||||
|
In order to ensure pages 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
|
||||||
|
And I have a custom model named "Projects" with
|
||||||
|
| label | type | required |
|
||||||
|
| Name | string | true |
|
||||||
|
| Description | text | false |
|
||||||
|
And I have a designer and an author
|
||||||
|
And a page named "hello-world" with id "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And a page named "goodbye-world" with id "4f832c2cb0d86d3f42ffffff"
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I do an API GET to pages.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing pages
|
||||||
|
|
||||||
|
Scenario: Accessing pages as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
|
||||||
|
Scenario: Accessing pages as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
|
||||||
|
Scenario: Accessing pages as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
|
||||||
|
# showing page
|
||||||
|
|
||||||
|
Scenario: Accessing page as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "slug" should be "hello-world"
|
||||||
|
|
||||||
|
Scenario: Accessing page as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "slug" should be "hello-world"
|
||||||
|
|
||||||
|
Scenario: Accessing page as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "slug" should be "hello-world"
|
||||||
|
|
||||||
|
# create page
|
||||||
|
|
||||||
|
Scenario: Creating new page as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API POST to pages.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"title": "New Page",
|
||||||
|
"slug": "new-page",
|
||||||
|
"parent_id": "4f832c2cb0d86d3f42fffffe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 5 entries
|
||||||
|
|
||||||
|
Scenario: Creating new page as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API POST to pages.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"title": "New Page",
|
||||||
|
"slug": "new-page",
|
||||||
|
"parent_id": "4f832c2cb0d86d3f42fffffe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 5 entries
|
||||||
|
|
||||||
|
Scenario: Creating new page as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API POST to pages.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"title": "New Page",
|
||||||
|
"slug": "new-page",
|
||||||
|
"parent_id": "4f832c2cb0d86d3f42fffffe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# update page
|
||||||
|
|
||||||
|
Scenario: Updating page as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API PUT to pages/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"title": "Brand new updated title"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "title" should be "Brand new updated title"
|
||||||
|
|
||||||
|
Scenario: Updating page as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API PUT to pages/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"title": "Brand new updated title"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "title" should be "Brand new updated title"
|
||||||
|
|
||||||
|
Scenario: Updating page as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API PUT to pages/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"title": "Brand new updated title"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "title" should be "Brand new updated title"
|
||||||
|
|
||||||
|
# destroy page
|
||||||
|
|
||||||
|
Scenario: Destroying page as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API DELETE to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
|
||||||
|
Scenario: Destroying page as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API DELETE to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
|
||||||
|
Scenario: Deleting page as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API GET request to pages.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 4 entries
|
||||||
|
When I do an API DELETE to pages/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
206
features/api/authorization/sites.feature
Normal file
206
features/api/authorization/sites.feature
Normal file
@ -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
|
179
features/api/authorization/snippets.feature
Normal file
179
features/api/authorization/snippets.feature
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
Feature: Snippets
|
||||||
|
In order to ensure snippets 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
|
||||||
|
And a snippet named "My Snippet" with id "4f832c2cb0d86d3f42fffffe" and template:
|
||||||
|
"""
|
||||||
|
My Snippet
|
||||||
|
"""
|
||||||
|
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 snippets.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing content types
|
||||||
|
|
||||||
|
Scenario: Accessing snippets as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Accessing snippets as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
|
||||||
|
Scenario: Accessing snippets as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# showing snippet
|
||||||
|
|
||||||
|
Scenario: Accessing snippet as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "My Snippet"
|
||||||
|
|
||||||
|
Scenario: Accessing snippet as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And the JSON response at "name" should be "My Snippet"
|
||||||
|
|
||||||
|
Scenario: Accessing snippet as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# create snippet
|
||||||
|
|
||||||
|
Scenario: Creating new snippet as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API POST to snippets.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"snippet": {
|
||||||
|
"name": "Another snippet",
|
||||||
|
"template": "<h1>Another Snippet!</h1>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 1/name | "Another Snippet" |
|
||||||
|
| 1/template | "<h1>Another Snippet!</h1>" |
|
||||||
|
|
||||||
|
Scenario: Creating new snippet as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API POST to snippets.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"snippet": {
|
||||||
|
"name": "Another snippet",
|
||||||
|
"template": "<h1>Another Snippet!</h1>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 1/name | "Another Snippet" |
|
||||||
|
| 1/template | "<h1>Another Snippet!</h1>" |
|
||||||
|
|
||||||
|
Scenario: Creating new snippet as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API POST to snippets.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"snippet": {
|
||||||
|
"name": "Another snippet",
|
||||||
|
"template": "<h1>Another Snippet!</h1>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# update snippet
|
||||||
|
|
||||||
|
Scenario: Updating snippet as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API PUT to snippets/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"snippet": {
|
||||||
|
"name": "Brand new updated name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "name" should be "Brand new updated name"
|
||||||
|
|
||||||
|
Scenario: Updating snippet as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API PUT to snippets/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"snippet": {
|
||||||
|
"name": "Brand new updated name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "name" should be "Brand new updated name"
|
||||||
|
|
||||||
|
Scenario: Updating snippet as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API PUT to snippets/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"snippet": {
|
||||||
|
"name": "Brand new updated name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# destroy snippet
|
||||||
|
|
||||||
|
Scenario: Destroying snippet as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API DELETE to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 0 entries
|
||||||
|
|
||||||
|
Scenario: Destroying snippet as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entry
|
||||||
|
When I do an API DELETE to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to snippets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 0 entries
|
||||||
|
|
||||||
|
Scenario: Deleting snippet as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API DELETE to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
185
features/api/authorization/theme_assets.feature
Normal file
185
features/api/authorization/theme_assets.feature
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
Feature: Theme Assets
|
||||||
|
In order to ensure theme assets 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
|
||||||
|
And a javascript asset named "my_javascript.js" with id "4f832c2cb0d86d3f42fffffe"
|
||||||
|
And a stylesheet asset named "my_stylesheet.css" with id "4f832c2cb0d86d3f42ffffff"
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I do an API GET to theme_assets.json
|
||||||
|
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||||
|
|
||||||
|
# listing theme assets
|
||||||
|
|
||||||
|
Scenario: Accessing theme assets as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
Scenario: Accessing theme assets as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
Scenario: Accessing theme assets as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
|
||||||
|
# showing theme asset
|
||||||
|
|
||||||
|
Scenario: Accessing theme asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "local_path" should be "my_javascript.js"
|
||||||
|
|
||||||
|
Scenario: Accessing theme asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "local_path" should be "my_javascript.js"
|
||||||
|
|
||||||
|
Scenario: Accessing theme asset as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response at "local_path" should be "my_javascript.js"
|
||||||
|
|
||||||
|
# create theme asset
|
||||||
|
|
||||||
|
Scenario: Creating new theme asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API POST to theme_assets.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"theme_asset": {
|
||||||
|
"plain_text_name": "new-javascript.js",
|
||||||
|
"plain_text": "function doNothing() {}",
|
||||||
|
"plain_text_type": "javascript",
|
||||||
|
"performing_plain_text": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 2/local_path | "new-javascript.js" |
|
||||||
|
| 2/content_type | "javascript" |
|
||||||
|
|
||||||
|
Scenario: Creating new theme asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API POST to theme_assets.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"theme_asset": {
|
||||||
|
"plain_text_name": "new-javascript.js",
|
||||||
|
"plain_text": "function doNothing() {}",
|
||||||
|
"plain_text_type": "javascript",
|
||||||
|
"performing_plain_text": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 3 entries
|
||||||
|
And the JSON should have the following:
|
||||||
|
| 2/local_path | "new-javascript.js" |
|
||||||
|
| 2/content_type | "javascript" |
|
||||||
|
|
||||||
|
Scenario: Creating new theme asset as an Author
|
||||||
|
Given I have an "author" API token
|
||||||
|
When I do an API POST to theme_assets.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"theme_asset": {
|
||||||
|
"plain_text_name": "new-javascript.js",
|
||||||
|
"plain_text": "function doNothing() {}",
|
||||||
|
"plain_text_type": "javascript",
|
||||||
|
"performing_plain_text": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then an access denied error should occur
|
||||||
|
|
||||||
|
# update theme asset
|
||||||
|
|
||||||
|
Scenario: Updating theme asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API PUT to theme_assets/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"theme_asset": {
|
||||||
|
"plain_text_name": "newer-javascript.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response should have the following:
|
||||||
|
| local_path | "newer-javascript.js" |
|
||||||
|
|
||||||
|
Scenario: Updating theme asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API PUT to theme_assets/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"theme_asset": {
|
||||||
|
"plain_text_name": "newer-javascript.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response should have the following:
|
||||||
|
| local_path | "newer-javascript.js" |
|
||||||
|
|
||||||
|
Scenario: Updating theme asset as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API PUT to theme_assets/4f832c2cb0d86d3f42fffffe.json with:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"theme_asset": {
|
||||||
|
"plain_text_name": "newer-javascript.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then the JSON response should have the following:
|
||||||
|
| local_path | "newer-javascript.js" |
|
||||||
|
|
||||||
|
# destroy theme asset
|
||||||
|
|
||||||
|
Scenario: Destroying theme asset as an Admin
|
||||||
|
Given I have an "admin" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entries
|
||||||
|
|
||||||
|
Scenario: Destroying theme asset as a Designer
|
||||||
|
Given I have a "designer" API token
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 2 entries
|
||||||
|
When I do an API DELETE to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
When I do an API GET request to theme_assets.json
|
||||||
|
Then the JSON response should be an array
|
||||||
|
And the JSON response should have 1 entries
|
||||||
|
|
||||||
|
Scenario: Deleting theme asset as an Author
|
||||||
|
Given I have a "author" API token
|
||||||
|
When I do an API DELETE to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||||
|
Then an access denied error should occur
|
@ -1,3 +1,26 @@
|
|||||||
|
|
||||||
|
def api_base_url
|
||||||
|
"http://#{Locomotive::Site.first.domains.first}/locomotive/api/"
|
||||||
|
end
|
||||||
|
|
||||||
|
def do_api_request(type, url, param_string_or_hash = nil)
|
||||||
|
begin
|
||||||
|
if param_string_or_hash
|
||||||
|
if param_string_or_hash.is_a? Hash
|
||||||
|
params = param_string_or_hash
|
||||||
|
else
|
||||||
|
params = JSON.parse(param_string_or_hash)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
params = {}
|
||||||
|
end
|
||||||
|
@json_response = do_request(type, api_base_url, url,
|
||||||
|
params.merge({ 'CONTENT_TYPE' => 'application/json' }))
|
||||||
|
rescue CanCan::AccessDenied, Mongoid::Errors::DocumentNotFound
|
||||||
|
@error = $!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def last_json
|
def last_json
|
||||||
@json_response.try(:body) || page.source
|
@json_response.try(:body) || page.source
|
||||||
end
|
end
|
||||||
@ -11,13 +34,16 @@ Given /^I have an? "([^"]*)" API token$/ do |role|
|
|||||||
'password' => 'easyone'
|
'password' => 'easyone'
|
||||||
}
|
}
|
||||||
|
|
||||||
response = post("http://#{@site.domains.first}/locomotive/api/tokens.json", login_params.to_json, { 'CONTENT_TYPE' => 'application/json' })
|
response = do_request('POST', api_base_url, 'tokens.json',
|
||||||
|
login_params.merge({ 'CONTENT_TYPE' => 'application/json' }))
|
||||||
|
|
||||||
if response.status == 200
|
if response.status == 200
|
||||||
@auth_token = JSON.parse(response.body)['token']
|
@auth_token = JSON.parse(response.body)['token']
|
||||||
else
|
else
|
||||||
raise JSON.parse(response.body)['message']
|
raise JSON.parse(response.body)['message']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_default_params(:auth_token => @auth_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
Given /^I do not have an API token$/ do
|
Given /^I do not have an API token$/ do
|
||||||
@ -36,3 +62,35 @@ end
|
|||||||
When /^I post to "([^"]*)" with:$/ do |path, json_string|
|
When /^I post to "([^"]*)" with:$/ do |path, json_string|
|
||||||
@json_response = post("http://#{@site.domains.first}#{path}", json_string, { 'CONTENT_TYPE' => 'application/json' })
|
@json_response = post("http://#{@site.domains.first}#{path}", json_string, { 'CONTENT_TYPE' => 'application/json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
When /^I do an API (\w+) (?:request )?to ([\w.\/]+)$/ do |request_type, url|
|
||||||
|
do_api_request(request_type, url)
|
||||||
|
end
|
||||||
|
|
||||||
|
When /^I do an API (\w+) (?:request )?to ([\w.\/]+) with:$/ do |request_type, url, param_string|
|
||||||
|
do_api_request(request_type, url, param_string)
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^an access denied error should occur$/ do
|
||||||
|
@error.should_not be_nil
|
||||||
|
@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 = {}
|
||||||
|
params = table.rows_hash
|
||||||
|
params.each do |key, filename|
|
||||||
|
params[key] = Rack::Test::UploadedFile.new(Rails.root.join('..', 'fixtures', filename))
|
||||||
|
end
|
||||||
|
do_api_request(request_type, url, { base_key => params })
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I print the json response$/ do
|
||||||
|
puts %{JSON: "#{last_json}"}
|
||||||
|
end
|
||||||
|
12
features/step_definitions/content_assets_steps.rb
Normal file
12
features/step_definitions/content_assets_steps.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
Given /^I have the following content assets:$/ do |table|
|
||||||
|
site = Locomotive::Site.first
|
||||||
|
table.hashes.each do |asset_hash|
|
||||||
|
asset_hash['site'] = site
|
||||||
|
asset_hash['source'] = FixturedAsset.open(asset_hash['file'])
|
||||||
|
asset_hash.delete('file')
|
||||||
|
|
||||||
|
asset = FactoryGirl.build(:asset, asset_hash)
|
||||||
|
asset.save.should be_true
|
||||||
|
end
|
||||||
|
end
|
@ -1,6 +1,9 @@
|
|||||||
Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
|
def build_content_type(name)
|
||||||
site = Locomotive::Site.first
|
site = Locomotive::Site.first
|
||||||
content_type = FactoryGirl.build(:content_type, :site => site, :name => name, :order_by => '_position')
|
FactoryGirl.build(:content_type, :site => site, :name => name, :order_by => '_position')
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_custom_fields_from_table(content_type, fields)
|
||||||
fields.hashes.each do |field|
|
fields.hashes.each do |field|
|
||||||
# found a belongs_to association
|
# found a belongs_to association
|
||||||
if field['type'] == 'belongs_to'
|
if field['type'] == 'belongs_to'
|
||||||
@ -12,6 +15,19 @@ Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
|
|||||||
|
|
||||||
content_type.entries_custom_fields.build field
|
content_type.entries_custom_fields.build field
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Given %r{^I have a custom model named "([^"]*)" with id "([^"]*)" and$} do |name, id, fields|
|
||||||
|
content_type = build_content_type(name)
|
||||||
|
content_type.id = BSON::ObjectId(id)
|
||||||
|
set_custom_fields_from_table(content_type, fields)
|
||||||
|
content_type.valid?
|
||||||
|
content_type.save.should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
|
||||||
|
content_type = build_content_type(name)
|
||||||
|
set_custom_fields_from_table(content_type, fields)
|
||||||
content_type.valid?
|
content_type.valid?
|
||||||
content_type.save.should be_true
|
content_type.save.should be_true
|
||||||
end
|
end
|
||||||
|
19
features/step_definitions/membership_steps.rb
Normal file
19
features/step_definitions/membership_steps.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
Given /^I have accounts:$/ do |accounts_table|
|
||||||
|
accounts_table.hashes.each do |account_hash|
|
||||||
|
FactoryGirl.create(:account, account_hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^I have memberships:$/ do |members_table|
|
||||||
|
members_table.hashes.each do |member_hash|
|
||||||
|
email = member_hash[:email]
|
||||||
|
account = Locomotive::Account.where(:email => email).first \
|
||||||
|
|| FactoryGirl.create(:account, :email => email)
|
||||||
|
|
||||||
|
member_hash.delete(:email)
|
||||||
|
member_hash.merge!({ :account => account, :site => @site })
|
||||||
|
|
||||||
|
FactoryGirl.create(:membership, member_hash)
|
||||||
|
end
|
||||||
|
end
|
@ -2,9 +2,16 @@
|
|||||||
|
|
||||||
# helps create a simple content page (parent: "index") with a slug, contents, and template
|
# helps create a simple content page (parent: "index") with a slug, contents, and template
|
||||||
def create_content_page(page_slug, page_contents, template = nil)
|
def create_content_page(page_slug, page_contents, template = nil)
|
||||||
@home = @site.pages.where(:slug => "index").first || FactoryGirl.create(:page)
|
page = new_content_page(page_slug, page_contents, template)
|
||||||
page = @site.pages.create(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :raw_template => template)
|
|
||||||
page.should be_valid
|
page.should be_valid
|
||||||
|
page.save!
|
||||||
|
page
|
||||||
|
end
|
||||||
|
|
||||||
|
# build page without saving
|
||||||
|
def new_content_page(page_slug, page_contents, template = nil)
|
||||||
|
@home = @site.pages.where(:slug => "index").first || FactoryGirl.create(:page)
|
||||||
|
page = @site.pages.new(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :raw_template => template)
|
||||||
page
|
page
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -17,6 +24,12 @@ Given /^a page named "([^"]*)" with the template:$/ do |page_slug, template|
|
|||||||
@page = create_content_page(page_slug, '', template)
|
@page = create_content_page(page_slug, '', template)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^a page named "([^"]*)" with id "([^"]*)"$/ do |page_slug, id|
|
||||||
|
@page = new_content_page(page_slug, '')
|
||||||
|
@page.id = BSON::ObjectId(id)
|
||||||
|
@page.save!
|
||||||
|
end
|
||||||
|
|
||||||
# change the title
|
# change the title
|
||||||
When /^I change the page title to "([^"]*)"$/ do |page_title|
|
When /^I change the page title to "([^"]*)"$/ do |page_title|
|
||||||
page.evaluate_script "window.prompt = function() { return '#{page_title}'; }"
|
page.evaluate_script "window.prompt = function() { return '#{page_title}'; }"
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
### Snippets
|
### Snippets
|
||||||
|
|
||||||
# helps create a simple snippet with a slug and template
|
# helps create a simple snippet with a slug and template
|
||||||
|
def new_snippet(name, template = nil)
|
||||||
|
@site.snippets.new(:name => name, :template => template)
|
||||||
|
end
|
||||||
|
|
||||||
def create_snippet(name, template = nil)
|
def create_snippet(name, template = nil)
|
||||||
snippet = @site.snippets.create(:name => name, :template => template)
|
snippet = new_snippet(name, template)
|
||||||
snippet.should be_valid
|
snippet.save!
|
||||||
snippet
|
snippet
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -13,6 +17,12 @@ Given /^a snippet named "([^"]*)" with the template:$/ do |name, template|
|
|||||||
@snippet = create_snippet(name, template)
|
@snippet = create_snippet(name, template)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^a snippet named "([^"]*)" with id "([^"]*)" and template:$/ do |name, id, template|
|
||||||
|
@snippet = new_snippet(name, template)
|
||||||
|
@snippet.id = BSON::ObjectId(id)
|
||||||
|
@snippet.save!
|
||||||
|
end
|
||||||
|
|
||||||
When /^I change the snippet template to "([^"]*)"$/ do |code|
|
When /^I change the snippet template to "([^"]*)"$/ do |code|
|
||||||
page.evaluate_script "window.application_view.view.editor.setValue('#{code}')"
|
page.evaluate_script "window.application_view.view.editor.setValue('#{code}')"
|
||||||
end
|
end
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
### Theme assets
|
### Theme assets
|
||||||
|
|
||||||
# helps create a theme asset
|
# helps create a theme asset
|
||||||
def create_plain_text_asset(name, type)
|
def new_plain_text_asset(name, type)
|
||||||
asset = FactoryGirl.build(:theme_asset, {
|
FactoryGirl.build(:theme_asset, {
|
||||||
:site => @site,
|
:site => @site,
|
||||||
:plain_text_name => name,
|
:plain_text_name => name,
|
||||||
:plain_text => 'Lorem ipsum',
|
:plain_text => 'Lorem ipsum',
|
||||||
:plain_text_type => type,
|
:plain_text_type => type,
|
||||||
:performing_plain_text => true
|
:performing_plain_text => true
|
||||||
})
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_plain_text_asset(name, type)
|
||||||
|
asset = new_plain_text_asset(name, type)
|
||||||
asset.save!
|
asset.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -19,10 +22,22 @@ Given /^a javascript asset named "([^"]*)"$/ do |name|
|
|||||||
@asset = create_plain_text_asset(name, 'javascript')
|
@asset = create_plain_text_asset(name, 'javascript')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^a javascript asset named "([^"]*)" with id "([^"]*)"$/ do |name, id|
|
||||||
|
@asset = new_plain_text_asset(name, 'javascript')
|
||||||
|
@asset.id = BSON::ObjectId(id)
|
||||||
|
@asset.save!
|
||||||
|
end
|
||||||
|
|
||||||
Given /^a stylesheet asset named "([^"]*)"$/ do |name|
|
Given /^a stylesheet asset named "([^"]*)"$/ do |name|
|
||||||
@asset = create_plain_text_asset(name, 'stylesheet')
|
@asset = create_plain_text_asset(name, 'stylesheet')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^a stylesheet asset named "([^"]*)" with id "([^"]*)"$/ do |name, id|
|
||||||
|
@asset = new_plain_text_asset(name, 'stylesheet')
|
||||||
|
@asset.id = BSON::ObjectId(id)
|
||||||
|
@asset.save!
|
||||||
|
end
|
||||||
|
|
||||||
Given /^I have an image theme asset named "([^"]*)"$/ do |name|
|
Given /^I have an image theme asset named "([^"]*)"$/ do |name|
|
||||||
@asset = FactoryGirl.create(:theme_asset, :site => @site, :source => File.open(Rails.root.join('..', 'fixtures', 'assets', '5k.png')))
|
@asset = FactoryGirl.create(:theme_asset, :site => @site, :source => File.open(Rails.root.join('..', 'fixtures', 'assets', '5k.png')))
|
||||||
@asset.source_filename = name
|
@asset.source_filename = name
|
||||||
|
22
features/support/http.rb
Normal file
22
features/support/http.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module HTTPHelpers
|
||||||
|
|
||||||
|
attr_accessor :default_params
|
||||||
|
|
||||||
|
def add_default_params(params)
|
||||||
|
default_params.merge!(params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def do_request(type, base_url, url, params)
|
||||||
|
request_method = type.downcase.to_sym
|
||||||
|
send(request_method, "#{base_url}/#{url}", default_params.merge(params))
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def default_params
|
||||||
|
@default_params ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
World(HTTPHelpers)
|
BIN
spec/fixtures/assets/5k_2.png
vendored
Normal file
BIN
spec/fixtures/assets/5k_2.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in New Issue
Block a user