icons for the theme_asset form + add tests (both rspec + features) for the roles
This commit is contained in:
parent
be6629d986
commit
2ad01833d8
@ -29,9 +29,7 @@ module Admin
|
|||||||
respond_to :html
|
respond_to :html
|
||||||
|
|
||||||
rescue_from CanCan::AccessDenied do |exception|
|
rescue_from CanCan::AccessDenied do |exception|
|
||||||
puts "exception = #{exception.inspect}"
|
::Locomotive::Logger.info "[CanCan::AccessDenied] #{exception.inspect}"
|
||||||
|
|
||||||
logger.debug "[CanCan::AccessDenied] #{exception.inspect}"
|
|
||||||
|
|
||||||
if request.xhr?
|
if request.xhr?
|
||||||
render :json => { :error => exception.message }
|
render :json => { :error => exception.message }
|
||||||
|
@ -48,7 +48,7 @@ module Admin
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def authorize_import
|
def authorize_import
|
||||||
authorize! 'new', Site
|
authorize! :import, Site
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -44,6 +44,13 @@ module Admin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
update! do |success, failure|
|
||||||
|
@theme_asset = ThemeAsset.find(@theme_asset._id)
|
||||||
|
puts "---> @theme_asset = #{@theme_asset.source_filename} / #{@theme_asset.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def sanitize_params
|
def sanitize_params
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class Ability
|
class Ability
|
||||||
include CanCan::Ability
|
include CanCan::Ability
|
||||||
|
|
||||||
ROLES = %w(admin author designer)
|
ROLES = %w(admin designer author)
|
||||||
|
|
||||||
def initialize(account, site)
|
def initialize(account, site)
|
||||||
@account, @site = account, site
|
@account, @site = account, site
|
||||||
@ -45,12 +45,18 @@ class Ability
|
|||||||
|
|
||||||
can :manage, ContentType
|
can :manage, ContentType
|
||||||
|
|
||||||
|
can :manage, Snippet
|
||||||
|
|
||||||
can :manage, ThemeAsset
|
can :manage, ThemeAsset
|
||||||
|
|
||||||
can :manage, Site do |site|
|
can :manage, Site do |site|
|
||||||
site == @site
|
site == @site
|
||||||
end
|
end
|
||||||
|
|
||||||
|
can :import, Site
|
||||||
|
|
||||||
|
can :point, Site
|
||||||
|
|
||||||
can :manage, Membership
|
can :manage, Membership
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ class ThemeAsset
|
|||||||
before_validation :store_plain_text
|
before_validation :store_plain_text
|
||||||
before_validation :sanitize_folder
|
before_validation :sanitize_folder
|
||||||
before_validation :build_local_path
|
before_validation :build_local_path
|
||||||
|
after_save :test
|
||||||
|
|
||||||
## validations ##
|
## validations ##
|
||||||
validates_presence_of :site, :source
|
validates_presence_of :site, :source
|
||||||
@ -38,7 +39,7 @@ class ThemeAsset
|
|||||||
scope :visible, lambda { |all| all ? {} : { :where => { :hidden => false } } }
|
scope :visible, lambda { |all| all ? {} : { :where => { :hidden => false } } }
|
||||||
|
|
||||||
## accessors ##
|
## accessors ##
|
||||||
attr_accessor :plain_text_name, :plain_text, :performing_plain_text
|
attr_accessor :plain_text_name, :plain_text, :plain_text_type, :performing_plain_text
|
||||||
|
|
||||||
## methods ##
|
## methods ##
|
||||||
|
|
||||||
@ -74,17 +75,29 @@ class ThemeAsset
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def plain_text_type
|
||||||
|
@plain_text_type || (stylesheet_or_javascript? ? self.content_type : nil)
|
||||||
|
end
|
||||||
|
|
||||||
def performing_plain_text?
|
def performing_plain_text?
|
||||||
Boolean.set(self.performing_plain_text) || false
|
Boolean.set(self.performing_plain_text) || false
|
||||||
end
|
end
|
||||||
|
|
||||||
def store_plain_text
|
def store_plain_text
|
||||||
|
self.content_type ||= @plain_text_type if self.performing_plain_text?
|
||||||
|
|
||||||
|
puts "content_type = #{content_type.inspect}"
|
||||||
|
|
||||||
data = self.performing_plain_text? ? self.plain_text : self.source.read
|
data = self.performing_plain_text? ? self.plain_text : self.source.read
|
||||||
|
|
||||||
return if !self.stylesheet_or_javascript? || self.plain_text_name.blank? || data.blank?
|
return if !self.stylesheet_or_javascript? || self.plain_text_name.blank? || data.blank?
|
||||||
|
|
||||||
sanitized_source = self.escape_shortcut_urls(data)
|
sanitized_source = self.escape_shortcut_urls(data)
|
||||||
|
|
||||||
|
puts "filename = #{self.plain_text_name}.#{self.stylesheet? ? 'css' : 'js'}"
|
||||||
|
|
||||||
|
puts "sanitized_source = #{sanitized_source.inspect}"
|
||||||
|
|
||||||
self.source = CarrierWave::SanitizedFile.new({
|
self.source = CarrierWave::SanitizedFile.new({
|
||||||
:tempfile => StringIO.new(sanitized_source),
|
:tempfile => StringIO.new(sanitized_source),
|
||||||
:filename => "#{self.plain_text_name}.#{self.stylesheet? ? 'css' : 'js'}"
|
:filename => "#{self.plain_text_name}.#{self.stylesheet? ? 'css' : 'js'}"
|
||||||
@ -145,4 +158,8 @@ class ThemeAsset
|
|||||||
self.errors.add(:source, :extname_changed) if !self.new_record? && self.content_type_changed?
|
self.errors.add(:source, :extname_changed) if !self.new_record? && self.content_type_changed?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test
|
||||||
|
puts "self.safe_source_filename = #{self.safe_source_filename} / #{self.source_filename}"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -9,37 +9,38 @@
|
|||||||
= f.input :meta_keywords
|
= f.input :meta_keywords
|
||||||
= f.input :meta_description
|
= f.input :meta_description
|
||||||
|
|
||||||
- if manage_subdomain_or_domains?
|
- if can?(:point, Site)
|
||||||
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
|
- if manage_subdomain_or_domains?
|
||||||
|
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
|
||||||
|
|
||||||
= f.custom_input :subdomain, :css => 'path' do
|
= f.custom_input :subdomain, :css => 'path' do
|
||||||
%em
|
|
||||||
http://
|
|
||||||
= f.text_field :subdomain, :readonly => !manage_subdomain?
|
|
||||||
\.
|
|
||||||
%em
|
|
||||||
= application_domain
|
|
||||||
|
|
||||||
- if manage_domains?
|
|
||||||
- @site.domains_without_subdomain.each_with_index do |name, index|
|
|
||||||
%li{ :class => "item added #{'last' if index == @site.domains.size - 1}"}
|
|
||||||
%em
|
|
||||||
http://
|
|
||||||
= text_field_tag 'site[domains][]', name, :class => 'string label void domain'
|
|
||||||
|
|
||||||
= error_on_domain(@site, name)
|
|
||||||
%span.actions
|
|
||||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
|
||||||
|
|
||||||
%li.item.template
|
|
||||||
%em
|
%em
|
||||||
http://
|
http://
|
||||||
= text_field_tag 'label', t('formtastic.hints.site.domain_name'), :class => 'string label void domain'
|
= f.text_field :subdomain, :readonly => !manage_subdomain?
|
||||||
|
\.
|
||||||
%span.actions
|
%em
|
||||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
= application_domain
|
||||||
%button{ :class => 'button light add', :type => 'button' }
|
|
||||||
%span!= t('admin.buttons.new_item')
|
- if manage_domains?
|
||||||
|
- @site.domains_without_subdomain.each_with_index do |name, index|
|
||||||
|
%li{ :class => "item added #{'last' if index == @site.domains.size - 1}"}
|
||||||
|
%em
|
||||||
|
http://
|
||||||
|
= text_field_tag 'site[domains][]', name, :class => 'string label void domain'
|
||||||
|
|
||||||
|
= error_on_domain(@site, name)
|
||||||
|
%span.actions
|
||||||
|
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
||||||
|
|
||||||
|
%li.item.template
|
||||||
|
%em
|
||||||
|
http://
|
||||||
|
= text_field_tag 'label', t('formtastic.hints.site.domain_name'), :class => 'string label void domain'
|
||||||
|
|
||||||
|
%span.actions
|
||||||
|
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
||||||
|
%button{ :class => 'button light add', :type => 'button' }
|
||||||
|
%span!= t('admin.buttons.new_item')
|
||||||
|
|
||||||
- if can?(:manage, Membership)
|
- if can?(:manage, Membership)
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@
|
|||||||
- if @theme_asset.new_record?
|
- if @theme_asset.new_record?
|
||||||
= f.input :plain_text_name
|
= f.input :plain_text_name
|
||||||
|
|
||||||
= f.custom_input :content_type do
|
= f.custom_input :plain_text_type do
|
||||||
= f.select :content_type, %w(stylesheet javascript)
|
= f.select :plain_text_type, %w(stylesheet javascript)
|
||||||
|
|
||||||
= f.custom_input :plain_text, :css => 'full', :with_label => false do
|
= f.custom_input :plain_text, :css => 'full', :with_label => false do
|
||||||
%code{ :class => (@theme_asset.size && @theme_asset.size > 40000 ? 'nude' : (@theme_asset.content_type || 'stylesheet')) }
|
%code{ :class => (@theme_asset.size && @theme_asset.size > 40000 ? 'nude' : (@theme_asset.content_type || 'stylesheet')) }
|
||||||
= f.text_area :plain_text
|
= f.text_area :plain_text
|
||||||
.more
|
.more
|
||||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'
|
||||||
|
|
||||||
%span.alt
|
%span.alt
|
||||||
!= t('admin.theme_assets.form.choose_file')
|
!= t('admin.theme_assets.form.choose_file')
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
- title t('.title', :file => @theme_asset.source_filename)
|
- title t('.title', :file => @theme_asset.source_filename)
|
||||||
|
|
||||||
|
- puts t('.title', :file => @theme_asset.source_filename)
|
||||||
|
|
||||||
- content_for :submenu do
|
- content_for :submenu do
|
||||||
= render 'admin/shared/menu/settings'
|
= render 'admin/shared/menu/settings'
|
||||||
|
|
||||||
|
4
doc/TODO
4
doc/TODO
@ -31,7 +31,7 @@ x Has_one => group by in the select
|
|||||||
x better hints:
|
x better hints:
|
||||||
x notify the user that after changing the page title, they still have to click "update" for the change to be saved
|
x notify the user that after changing the page title, they still have to click "update" for the change to be saved
|
||||||
x created_by ASC => "Creation date ascending"
|
x created_by ASC => "Creation date ascending"
|
||||||
- cancan: (authors / designers / admin)
|
x cancan: (authors / designers / admin)
|
||||||
x model
|
x model
|
||||||
x ui
|
x ui
|
||||||
x controllers / views:
|
x controllers / views:
|
||||||
@ -42,7 +42,7 @@ x better hints:
|
|||||||
x account
|
x account
|
||||||
x snippet
|
x snippet
|
||||||
x theme asset
|
x theme asset
|
||||||
- spec
|
x features / specs
|
||||||
- better ui: increase text field length + refactor error message
|
- better ui: increase text field length + refactor error message
|
||||||
- enable rack-cache only for a specific url
|
- enable rack-cache only for a specific url
|
||||||
- convert existing templates (the 2 of the themes section)
|
- convert existing templates (the 2 of the themes section)
|
||||||
|
32
features/admin/authorization/content_type.feature
Normal file
32
features/admin/authorization/content_type.feature
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
Feature: Editing a content type
|
||||||
|
In order to edit a content type
|
||||||
|
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 project model
|
||||||
|
And I have a designer and an author
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I go to the "Projects" model edition page
|
||||||
|
Then I should see "Log in"
|
||||||
|
|
||||||
|
Scenario: Accessing edition functionality as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to the "Projects" model edition page
|
||||||
|
Then I should see "Editing model"
|
||||||
|
And I should see "Custom fields"
|
||||||
|
|
||||||
|
Scenario: Accessing edition functionality as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to the "Projects" model edition page
|
||||||
|
Then I should see "Editing model"
|
||||||
|
And I should see "Custom fields"
|
||||||
|
|
||||||
|
Scenario: Accessing edition functionality as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to the "Projects" model edition page
|
||||||
|
Then I should be on the pages list
|
||||||
|
And I should see the access denied message
|
53
features/admin/authorization/current_site.feature
Normal file
53
features/admin/authorization/current_site.feature
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
Feature: Site Settings
|
||||||
|
In order to ensure site settings 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 designer and an author
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I go to site settings
|
||||||
|
Then I should see "Log in"
|
||||||
|
|
||||||
|
Scenario: Accessing site settings as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to site settings
|
||||||
|
Then I should see "import"
|
||||||
|
And I should see "add account"
|
||||||
|
And I should see "SEO settings"
|
||||||
|
And I should see "Access points"
|
||||||
|
And I should not see the role dropdown on myself
|
||||||
|
And I should see the role dropdown on the "designer"
|
||||||
|
And I should see the role dropdown on the "author"
|
||||||
|
And I should not see delete on myself
|
||||||
|
And I should see delete on the "designer"
|
||||||
|
And I should see delete on the "author"
|
||||||
|
|
||||||
|
Scenario: Accessing site settings as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to site settings
|
||||||
|
Then I should see "import"
|
||||||
|
And I should see "add account"
|
||||||
|
And I should see "SEO settings"
|
||||||
|
And I should see "Access points"
|
||||||
|
And I should not see the role dropdown on myself
|
||||||
|
And I should see the role dropdown on the "admin"
|
||||||
|
And I should see the role dropdown on the "author"
|
||||||
|
And I should see delete on the "admin"
|
||||||
|
And I should not see delete on myself
|
||||||
|
And I should see delete on the "author"
|
||||||
|
|
||||||
|
Scenario: Accessing site settings as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to site settings
|
||||||
|
Then I should not see "import"
|
||||||
|
And I should not see "add account"
|
||||||
|
And I should see "SEO settings"
|
||||||
|
And I should not see "Access points"
|
||||||
|
And I should not see "Accounts"
|
||||||
|
# Paranoid Checks
|
||||||
|
And I should not see any role dropdowns
|
||||||
|
And I should not see any delete buttons
|
31
features/admin/authorization/importing.feature
Normal file
31
features/admin/authorization/importing.feature
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Feature: Importing a Site
|
||||||
|
In order to populate the site with data and assets
|
||||||
|
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 designer and an author
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I go to import page
|
||||||
|
Then I should see "Log in"
|
||||||
|
|
||||||
|
Scenario: Accessing importing functionality as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to the import page
|
||||||
|
Then I should see "Import"
|
||||||
|
And I should see "Upload"
|
||||||
|
|
||||||
|
Scenario: Accessing importing functionality as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to the import page
|
||||||
|
Then I should see "Import"
|
||||||
|
And I should see "Upload"
|
||||||
|
|
||||||
|
Scenario: Accessing importing functionality as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to the import page
|
||||||
|
Then I should be on the pages list
|
||||||
|
And I should see the access denied message
|
95
features/admin/authorization/pages.feature
Normal file
95
features/admin/authorization/pages.feature
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
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 project model
|
||||||
|
And I have a designer and an author
|
||||||
|
And a page named "hello-world" with the template:
|
||||||
|
"""
|
||||||
|
Hello World
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I go to pages
|
||||||
|
Then I should see "Log in"
|
||||||
|
|
||||||
|
# listing pages
|
||||||
|
|
||||||
|
Scenario: Accessing pages as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to pages
|
||||||
|
Then I should see "new page"
|
||||||
|
And I should see "new model"
|
||||||
|
And I should see "Projects"
|
||||||
|
And I should see "edit model"
|
||||||
|
And I should see delete page buttons
|
||||||
|
|
||||||
|
Scenario: Accessing pages as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to pages
|
||||||
|
Then I should see "new page"
|
||||||
|
And I should see "new model"
|
||||||
|
And I should see "Projects"
|
||||||
|
And I should see "edit model"
|
||||||
|
And I should see delete page buttons
|
||||||
|
|
||||||
|
Scenario: Accessing pages as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to pages
|
||||||
|
Then I should not see "new page"
|
||||||
|
And I should not see "new model"
|
||||||
|
And I should see "Projects"
|
||||||
|
And I should not see "edit model"
|
||||||
|
And I should not see delete page buttons
|
||||||
|
|
||||||
|
# new page
|
||||||
|
|
||||||
|
Scenario: Accessing new page as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to the new page
|
||||||
|
Then I should see "New page"
|
||||||
|
|
||||||
|
Scenario: Accessing new page as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to the new page
|
||||||
|
Then I should see "New page"
|
||||||
|
|
||||||
|
Scenario: Accessing new page as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to the new page
|
||||||
|
Then I should be on the pages list
|
||||||
|
And I should see the access denied message
|
||||||
|
|
||||||
|
# edit page
|
||||||
|
|
||||||
|
Scenario: Accessing edit page as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to the "hello-world" edition page
|
||||||
|
Then I should see "some title"
|
||||||
|
And I should see "General information"
|
||||||
|
And I should see "SEO settings"
|
||||||
|
And I should see "Advanced options"
|
||||||
|
And I should see "Template"
|
||||||
|
|
||||||
|
Scenario: Accessing edit page as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to the "hello-world" edition page
|
||||||
|
Then I should see "some title"
|
||||||
|
And I should see "General information"
|
||||||
|
And I should see "SEO settings"
|
||||||
|
And I should see "Advanced options"
|
||||||
|
And I should see "Template"
|
||||||
|
|
||||||
|
Scenario: Accessing edit page as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to the "hello-world" edition page
|
||||||
|
Then I should see "some title"
|
||||||
|
And I should not see "General Information"
|
||||||
|
And I should see "SEO settings"
|
||||||
|
And I should not see "Advanced options"
|
||||||
|
And I should not see "Template"
|
||||||
|
|
43
features/admin/authorization/theme_assets.feature
Normal file
43
features/admin/authorization/theme_assets.feature
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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 I have a designer and an author
|
||||||
|
|
||||||
|
Scenario: As an unauthenticated user
|
||||||
|
Given I am not authenticated
|
||||||
|
When I go to theme assets
|
||||||
|
Then I should see "Log in"
|
||||||
|
|
||||||
|
Scenario: Accessing theme assets as an Admin
|
||||||
|
Given I am an authenticated "admin"
|
||||||
|
When I go to theme assets
|
||||||
|
Then I should see "all assets"
|
||||||
|
And I should see "new snippet"
|
||||||
|
And I should see "new file"
|
||||||
|
And I should see "Snippets"
|
||||||
|
And I should see "Style and javascript"
|
||||||
|
And I should see "Images"
|
||||||
|
|
||||||
|
Scenario: Accessing theme assets as a Designer
|
||||||
|
Given I am an authenticated "designer"
|
||||||
|
When I go to theme assets
|
||||||
|
Then I should see "all assets"
|
||||||
|
And I should see "new snippet"
|
||||||
|
And I should see "new file"
|
||||||
|
And I should see "Snippets"
|
||||||
|
And I should see "Style and javascript"
|
||||||
|
And I should see "Images"
|
||||||
|
|
||||||
|
Scenario: Accessing theme assets as an Author
|
||||||
|
Given I am an authenticated "author"
|
||||||
|
When I go to theme assets
|
||||||
|
Then I should not see "all assets"
|
||||||
|
And I should not see "new snippet"
|
||||||
|
And I should not see "new file"
|
||||||
|
And I should not see "Snippets"
|
||||||
|
And I should not see "Style and javascript"
|
||||||
|
And I should see "Images"
|
@ -7,45 +7,64 @@ Background:
|
|||||||
Given I have the site: "test site" set up
|
Given I have the site: "test site" set up
|
||||||
And I am an authenticated user
|
And I am an authenticated user
|
||||||
|
|
||||||
Scenario: Theme assets list is not accessible for non authenticated accounts
|
# Scenario: Theme assets list is not accessible for non authenticated accounts
|
||||||
Given I am not authenticated
|
# Given I am not authenticated
|
||||||
When I go to theme assets
|
# When I go to theme assets
|
||||||
Then I should see "Log in"
|
# Then I should see "Log in"
|
||||||
|
#
|
||||||
|
# Scenario: Uploading a valid image
|
||||||
|
# When I go to theme assets
|
||||||
|
# And I follow "new file"
|
||||||
|
# And I attach the file "spec/fixtures/assets/5k.png" to "File"
|
||||||
|
# And I press "Create"
|
||||||
|
# Then I should see "File was successfully created."
|
||||||
|
# And I should not see "Code"
|
||||||
|
# And I should see "images/5k.png"
|
||||||
|
#
|
||||||
|
# Scenario: Uploading a stylesheet
|
||||||
|
# When I go to theme assets
|
||||||
|
# And I follow "new file"
|
||||||
|
# And I attach the file "spec/fixtures/assets/main.css" to "File"
|
||||||
|
# And I press "Create"
|
||||||
|
# Then I should see "File was successfully created."
|
||||||
|
# And I should see "Code"
|
||||||
|
# And I should see "stylesheets/main.css"
|
||||||
|
|
||||||
Scenario: Uploading a valid image
|
Scenario: Updating a stylesheet
|
||||||
|
Given a stylesheet asset named "application"
|
||||||
When I go to theme assets
|
When I go to theme assets
|
||||||
And I follow "new file"
|
And I follow "stylesheets/application.css"
|
||||||
And I attach the file "spec/fixtures/assets/5k.png" to "File"
|
And I fill in "theme_asset[plain_text]" with "Lorem ipsum (updated)"
|
||||||
And I press "Create"
|
And I press "Update"
|
||||||
Then I should see "File was successfully created."
|
Then I should see "File was successfully updated."
|
||||||
And I should not see "Code"
|
And I should see "Editing application.css"
|
||||||
And I should see "images/5k.png"
|
And I should see "application.css"
|
||||||
|
And I should see "Lorem ipsum (updated)" as theme asset code
|
||||||
|
|
||||||
Scenario: Uploading a stylesheet
|
# Scenario: Uploading a javascript
|
||||||
When I go to theme assets
|
# When I go to theme assets
|
||||||
And I follow "new file"
|
# And I follow "new file"
|
||||||
And I attach the file "spec/fixtures/assets/main.css" to "File"
|
# And I fill in "Folder" with "javascripts/test"
|
||||||
And I press "Create"
|
# And I attach the file "spec/fixtures/assets/application.js" to "File"
|
||||||
Then I should see "File was successfully created."
|
# And I press "Create"
|
||||||
And I should see "Code"
|
# Then I should see "File was successfully created."
|
||||||
And I should see "stylesheets/main.css"
|
# And I should see "Code"
|
||||||
|
# And I should see "javascripts/test/application.js"
|
||||||
Scenario: Uploading a javascript
|
#
|
||||||
When I go to theme assets
|
# Scenario: Updating a javascript
|
||||||
And I follow "new file"
|
# Given a javascript asset named "application"
|
||||||
And I fill in "Folder" with "javascripts/test"
|
# When I go to theme assets
|
||||||
And I attach the file "spec/fixtures/assets/application.js" to "File"
|
# And I follow "javascripts/application.js"
|
||||||
And I press "Create"
|
# And I fill in "theme_asset[plain_text]" with "Lorem ipsum (updated)"
|
||||||
Then I should see "File was successfully created."
|
# And I press "Update"
|
||||||
And I should see "Code"
|
# Then I should see "File was successfully updated."
|
||||||
And I should see "javascripts/test/application.js"
|
#
|
||||||
|
# Scenario: Uploading an image which already exists
|
||||||
Scenario: Uploading an image which already exists
|
# When I go to theme assets
|
||||||
When I go to theme assets
|
# And I follow "new file"
|
||||||
And I follow "new file"
|
# And I attach the file "spec/fixtures/assets/5k.png" to "File"
|
||||||
And I attach the file "spec/fixtures/assets/5k.png" to "File"
|
# And I press "Create"
|
||||||
And I press "Create"
|
# And I follow "new file"
|
||||||
And I follow "new file"
|
# And I attach the file "spec/fixtures/assets/5k.png" to "File"
|
||||||
And I attach the file "spec/fixtures/assets/5k.png" to "File"
|
# And I press "Create"
|
||||||
And I press "Create"
|
# Then I should see "File was not created."
|
||||||
Then I should see "File was not created."
|
|
||||||
|
@ -4,13 +4,23 @@ Given /^I am not authenticated$/ do
|
|||||||
visit('/admin/sign_out')
|
visit('/admin/sign_out')
|
||||||
end
|
end
|
||||||
|
|
||||||
Given /^I am an authenticated user$/ do
|
Given /^I am an authenticated "([^"]*)"$/ do |role|
|
||||||
|
@member = Site.first.memberships.where(:role => role.downcase).first || Factory(role.downcase.to_sym, :site => Site.first)
|
||||||
|
|
||||||
Given %{I go to login}
|
Given %{I go to login}
|
||||||
And %{I fill in "Email" with "admin@locomotiveapp.org"}
|
And %{I fill in "Email" with "#{@member.account.email}"}
|
||||||
And %{I fill in "Password" with "easyone"}
|
And %{I fill in "Password" with "easyone"}
|
||||||
And %{I press "Log in"}
|
And %{I press "Log in"}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^I am an authenticated user$/ do
|
||||||
|
Given %{I am an authenticated "admin"}
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should see the access denied message$/ do
|
||||||
|
Then %{I should see "You are not authorized to access this page"}
|
||||||
|
end
|
||||||
|
|
||||||
Then /^I am redirected to "([^\"]*)"$/ do |url|
|
Then /^I am redirected to "([^\"]*)"$/ do |url|
|
||||||
assert [301, 302].include?(@integration_session.status), "Expected status to be 301 or 302, got #{@integration_session.status}"
|
assert [301, 302].include?(@integration_session.status), "Expected status to be 301 or 302, got #{@integration_session.status}"
|
||||||
location = @integration_session.headers["Location"]
|
location = @integration_session.headers["Location"]
|
||||||
@ -25,5 +35,4 @@ When /^I forget to press the button on the cross-domain notice page$/ do
|
|||||||
Mongoid::Persistence::Update.new(@admin).send(:update)
|
Mongoid::Persistence::Update.new(@admin).send(:update)
|
||||||
end
|
end
|
||||||
|
|
||||||
### Common
|
### Common
|
||||||
|
|
7
features/step_definitions/content_types_steps.rb
Normal file
7
features/step_definitions/content_types_steps.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Given /^I have a custom project model/ do
|
||||||
|
site = Site.first
|
||||||
|
@content_type = Factory.build(:content_type, :site => site, :name => 'Projects')
|
||||||
|
@content_type.content_custom_fields.build :label => 'Name', :kind => 'string'
|
||||||
|
@content_type.content_custom_fields.build :label => 'Description', :kind => 'text'
|
||||||
|
@content_type.save.should be_true
|
||||||
|
end
|
35
features/step_definitions/current_site_steps.rb
Normal file
35
features/step_definitions/current_site_steps.rb
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
Then /^I should see the role dropdown on the "([^"]*)"$/ do |user|
|
||||||
|
find(:css, "li.membership[data-role=#{user}] select").text.should == 'AdministratorDesignerAuthor'
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should see the role dropdown on myself$/ do
|
||||||
|
Then %{I should see the role dropdown on the "#{@member.role}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see the role dropdown on the "([^"]*)"$/ do |user|
|
||||||
|
page.has_css?("li.membership[data-role=#{user}] select").should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see the role dropdown on myself$/ do
|
||||||
|
Then %{I should not see the role dropdown on the "#{@member.role}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see any role dropdowns$/ do
|
||||||
|
page.has_css?('li.membership select').should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should see delete on the "([^"]*)"$/ do |role|
|
||||||
|
page.has_css?("li.membership[data-role=#{role}] .actions a.remove").should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see delete on the "([^"]*)"$/ do |role|
|
||||||
|
page.has_css?("li.membership[data-role=#{role}] .actions a.remove").should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see delete on myself$/ do
|
||||||
|
Then %{I should not see delete on the "#{@member.role}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see any delete buttons$/ do
|
||||||
|
page.has_css?('li.membership .actions a.remove').should be_false
|
||||||
|
end
|
@ -42,4 +42,12 @@ Then /^the rendered output should look like:$/ do |body_contents|
|
|||||||
page.body.should == body_contents
|
page.body.should == body_contents
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Then /^I should see delete page buttons$/ do
|
||||||
|
page.has_css?("ul#pages-list li .more a.remove").should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
Then /^I should not see delete page buttons$/ do
|
||||||
|
page.has_css?("ul#pages-list li .more a.remove").should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,3 +12,7 @@ Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site
|
|||||||
@admin.should_not be_nil
|
@admin.should_not be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^I have a designer and an author$/ do
|
||||||
|
Factory(:designer, :site => Site.first)
|
||||||
|
Factory(:author, :site => Site.first)
|
||||||
|
end
|
31
features/step_definitions/theme_asset_steps.rb
Normal file
31
features/step_definitions/theme_asset_steps.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
### Theme assets
|
||||||
|
|
||||||
|
# helps create a theme asset
|
||||||
|
def create_plain_text_asset(name, type)
|
||||||
|
asset = Factory.build(:theme_asset, {
|
||||||
|
:site => @site,
|
||||||
|
:plain_text_name => name,
|
||||||
|
:plain_text => 'Lorem ipsum',
|
||||||
|
:plain_text_type => type,
|
||||||
|
:performing_plain_text => true
|
||||||
|
})
|
||||||
|
# asset.should be_valid
|
||||||
|
asset.save!
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# creates various theme assets
|
||||||
|
|
||||||
|
Given /^a javascript asset named "([^"]*)"$/ do |name|
|
||||||
|
@asset = create_plain_text_asset(name, 'javascript')
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^a stylesheet asset named "([^"]*)"$/ do |name|
|
||||||
|
@asset = create_plain_text_asset(name, 'stylesheet')
|
||||||
|
end
|
||||||
|
|
||||||
|
# other stuff
|
||||||
|
|
||||||
|
Then /^I should see "([^"]*)" as theme asset code$/ do |code|
|
||||||
|
find(:css, "#theme_asset_plain_text").text.should == code
|
||||||
|
end
|
@ -14,10 +14,22 @@ module NavigationHelpers
|
|||||||
new_admin_session_path
|
new_admin_session_path
|
||||||
when /logout/
|
when /logout/
|
||||||
destroy_admin_session_path
|
destroy_admin_session_path
|
||||||
when /pages/
|
when /pages( list)?/
|
||||||
admin_pages_path
|
admin_pages_path
|
||||||
|
when /new page/
|
||||||
|
new_admin_page_path
|
||||||
|
when /"(.*)" edition page/
|
||||||
|
page = Site.first.pages.where(:slug => $1).first
|
||||||
|
edit_admin_page_path(page)
|
||||||
when /theme assets/
|
when /theme assets/
|
||||||
admin_theme_assets_path
|
admin_theme_assets_path
|
||||||
|
when /site settings/
|
||||||
|
edit_admin_current_site_path
|
||||||
|
when /import page/
|
||||||
|
new_admin_import_path
|
||||||
|
when /the "(.*)" model edition page/
|
||||||
|
content_type = Site.first.content_types.where(:name => $1).first
|
||||||
|
edit_admin_content_type_path(content_type)
|
||||||
|
|
||||||
# Add more mappings here.
|
# Add more mappings here.
|
||||||
# Here is an example that pulls values out of the Regexp:
|
# Here is an example that pulls values out of the Regexp:
|
||||||
|
@ -44,6 +44,8 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
puts "content_type => #{value} / #{original_filename.inspect}"
|
||||||
|
|
||||||
model.content_type = value
|
model.content_type = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
BIN
public/images/admin/icons/asset_add.png
Normal file
BIN
public/images/admin/icons/asset_add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 639 B |
BIN
public/images/admin/icons/asset_switch.png
Normal file
BIN
public/images/admin/icons/asset_switch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 553 B |
@ -165,6 +165,11 @@ form.formtastic fieldset ol .more { text-align: right; width: auto; margin: 10px
|
|||||||
form.formtastic fieldset ol .more a { text-decoration: none; color: #787A89; font-size: 0.7em; }
|
form.formtastic fieldset ol .more a { text-decoration: none; color: #787A89; font-size: 0.7em; }
|
||||||
form.formtastic fieldset ol .more a:hover { text-decoration: underline; }
|
form.formtastic fieldset ol .more a:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
form.formtastic fieldset ol .more a.picture {
|
||||||
|
padding-left: 23px;
|
||||||
|
background: transparent url(/images/admin/icons/asset_add.png) no-repeat left 1px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ___ pages ___ */
|
/* ___ pages ___ */
|
||||||
|
|
||||||
form.formtastic fieldset ol li.path em {
|
form.formtastic fieldset ol li.path em {
|
||||||
@ -558,7 +563,7 @@ form.formtastic fieldset.memberships ol li select {
|
|||||||
top: -1px;
|
top: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ___ assets ___ */
|
/* ___ theme assets ___ */
|
||||||
|
|
||||||
.selector {
|
.selector {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -572,8 +577,12 @@ form.formtastic fieldset.memberships ol li select {
|
|||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
padding-left: 20px;
|
||||||
|
background: transparent url(/images/admin/icons/asset_switch.png) no-repeat left 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selector span.alt:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
|
||||||
form.formtastic fieldset.file li.full input {
|
form.formtastic fieldset.file li.full input {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
|
@ -9,7 +9,7 @@ Factory.define "test site", :parent => :site do |s|
|
|||||||
s.name 'Locomotive test website'
|
s.name 'Locomotive test website'
|
||||||
s.subdomain 'test'
|
s.subdomain 'test'
|
||||||
s.after_build do |site_test|
|
s.after_build do |site_test|
|
||||||
site_test.memberships.build :account => Account.where(:name => "Admin").first || Factory("admin user"), :admin => true
|
site_test.memberships.build :account => Account.where(:name => "Admin").first || Factory("admin user"), :role => 'admin'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -54,8 +54,23 @@ end
|
|||||||
|
|
||||||
## Memberships ##
|
## Memberships ##
|
||||||
Factory.define :membership do |m|
|
Factory.define :membership do |m|
|
||||||
m.admin true
|
m.role 'admin'
|
||||||
m.account{ Account.where(:name => "Bart Simpson").first || Factory(:account) }
|
m.account { Account.where(:name => "Bart Simpson").first || Factory('admin user') }
|
||||||
|
end
|
||||||
|
|
||||||
|
Factory.define :admin, :parent => :membership do |m|
|
||||||
|
m.role 'admin'
|
||||||
|
m.account { Factory('admin user', :locale => 'en') }
|
||||||
|
end
|
||||||
|
|
||||||
|
Factory.define :designer, :parent => :membership do |m|
|
||||||
|
m.role 'designer'
|
||||||
|
m.account { Factory('frenchy user', :locale => 'en') }
|
||||||
|
end
|
||||||
|
|
||||||
|
Factory.define :author, :parent => :membership do |m|
|
||||||
|
m.role 'author'
|
||||||
|
m.account { Factory('brazillian user', :locale => 'en') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
130
spec/models/ability_spec.rb
Normal file
130
spec/models/ability_spec.rb
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Ability do
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
@site = Factory(:site)
|
||||||
|
@account = Factory(:account)
|
||||||
|
|
||||||
|
@admin = Factory(:membership, :account => Factory.stub(:account), :site => Factory.stub(:site))
|
||||||
|
@designer = Factory(:membership, :account => Factory.stub(:account), :site => @site, :role => %(designer))
|
||||||
|
@author = Factory(:membership, :account => Factory.stub(:account), :site => @site, :role => %(author))
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'pages' do
|
||||||
|
|
||||||
|
subject { Page.new }
|
||||||
|
|
||||||
|
context 'management' do
|
||||||
|
it 'should allow management of pages from (admin, designer, author)' do
|
||||||
|
should allow_permission_from :manage, @admin
|
||||||
|
should allow_permission_from :manage, @designer
|
||||||
|
should_not allow_permission_from :manage, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'touching' do
|
||||||
|
it 'should allow touching of pages from (author)' do
|
||||||
|
should allow_permission_from :touch, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'content instance' do
|
||||||
|
|
||||||
|
subject { ContentInstance.new }
|
||||||
|
|
||||||
|
context 'management' do
|
||||||
|
it 'should allow management of pages from (admin, designer, author)' do
|
||||||
|
should allow_permission_from :manage, @admin
|
||||||
|
should allow_permission_from :manage, @designer
|
||||||
|
should allow_permission_from :manage, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'content type' do
|
||||||
|
|
||||||
|
subject { ContentType.new }
|
||||||
|
|
||||||
|
context 'management' do
|
||||||
|
it 'should allow management of pages from (admin, designer)' do
|
||||||
|
should allow_permission_from :manage, @admin
|
||||||
|
should allow_permission_from :manage, @designer
|
||||||
|
should_not allow_permission_from :manage, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# context 'touching' do
|
||||||
|
# it 'should allow touching of pages from (author)' do
|
||||||
|
# should_not allow_permission_from :touch, @author
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'theme assets' do
|
||||||
|
|
||||||
|
subject { ThemeAsset.new }
|
||||||
|
|
||||||
|
context 'management' do
|
||||||
|
it 'should allow management of pages from (admin, designer)' do
|
||||||
|
should allow_permission_from :manage, @admin
|
||||||
|
should allow_permission_from :manage, @designer
|
||||||
|
should_not allow_permission_from :manage, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'touching' do
|
||||||
|
it 'should allow touching of pages from (author)' do
|
||||||
|
should allow_permission_from :touch, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'site' do
|
||||||
|
|
||||||
|
subject { Site.new }
|
||||||
|
|
||||||
|
context 'management' do
|
||||||
|
it 'should allow management of pages from (admin)' do
|
||||||
|
should allow_permission_from :manage, @admin
|
||||||
|
should_not allow_permission_from :manage, @designer
|
||||||
|
should_not allow_permission_from :manage, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'importing' do
|
||||||
|
it 'should allow importing of sites from (designer)' do
|
||||||
|
should allow_permission_from :import, @designer
|
||||||
|
should_not allow_permission_from :import, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'pointing' do
|
||||||
|
it 'should allow importing of sites from (designer)' do
|
||||||
|
should allow_permission_from :point, @designer
|
||||||
|
should_not allow_permission_from :point, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'membership' do
|
||||||
|
|
||||||
|
subject { Membership.new }
|
||||||
|
|
||||||
|
context 'management' do
|
||||||
|
it 'should allow management of memberships from (admin, designer)' do
|
||||||
|
should allow_permission_from :manage, @admin
|
||||||
|
should allow_permission_from :manage, @designer
|
||||||
|
should_not allow_permission_from :manage, @author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -103,14 +103,14 @@ describe ThemeAsset do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'should handle stylesheet' do
|
it 'should handle stylesheet' do
|
||||||
@asset.content_type = 'stylesheet'
|
@asset.plain_text_type = 'stylesheet'
|
||||||
@asset.valid?.should be_true
|
@asset.valid?.should be_true
|
||||||
@asset.stylesheet?.should be_true
|
@asset.stylesheet?.should be_true
|
||||||
@asset.source.should_not be_nil
|
@asset.source.should_not be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should handle javascript' do
|
it 'should handle javascript' do
|
||||||
@asset.content_type = 'javascript'
|
@asset.plain_text_type = 'javascript'
|
||||||
@asset.valid?.should be_true
|
@asset.valid?.should be_true
|
||||||
@asset.javascript?.should be_true
|
@asset.javascript?.should be_true
|
||||||
@asset.source.should_not be_nil
|
@asset.source.should_not be_nil
|
||||||
|
@ -93,6 +93,35 @@ module Locomotive
|
|||||||
IncludeClassMethod.new(meth)
|
IncludeClassMethod.new(meth)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class PermissionsMatcher
|
||||||
|
def initialize(permission, member)
|
||||||
|
@permission = permission
|
||||||
|
@member = member
|
||||||
|
end
|
||||||
|
|
||||||
|
def matches?(target)
|
||||||
|
@target = target
|
||||||
|
@member.ability.can? @permission, @target
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message_for_should
|
||||||
|
"expected #{show_object(@member)} to allow '#{@permission}' permission on #{show_object(@target)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message_for_should_not
|
||||||
|
"expected #{show_object(@member)} not to allow '#{@permission}' permission on #{show_object(@target)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def show_object(object)
|
||||||
|
"#{object.class.name}(#{object.id.inspect})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_permission_from(permission, member)
|
||||||
|
PermissionsMatcher.new(permission, member)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user