icons for the theme_asset form + add tests (both rspec + features) for the roles

This commit is contained in:
did 2011-06-27 08:27:07 -07:00
parent be6629d986
commit 2ad01833d8
30 changed files with 684 additions and 89 deletions

View File

@ -29,9 +29,7 @@ module Admin
respond_to :html
rescue_from CanCan::AccessDenied do |exception|
puts "exception = #{exception.inspect}"
logger.debug "[CanCan::AccessDenied] #{exception.inspect}"
::Locomotive::Logger.info "[CanCan::AccessDenied] #{exception.inspect}"
if request.xhr?
render :json => { :error => exception.message }

View File

@ -48,7 +48,7 @@ module Admin
protected
def authorize_import
authorize! 'new', Site
authorize! :import, Site
end
end

View File

@ -44,6 +44,13 @@ module Admin
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
def sanitize_params

View File

@ -1,7 +1,7 @@
class Ability
include CanCan::Ability
ROLES = %w(admin author designer)
ROLES = %w(admin designer author)
def initialize(account, site)
@account, @site = account, site
@ -45,12 +45,18 @@ class Ability
can :manage, ContentType
can :manage, Snippet
can :manage, ThemeAsset
can :manage, Site do |site|
site == @site
end
can :import, Site
can :point, Site
can :manage, Membership
end

View File

@ -26,6 +26,7 @@ class ThemeAsset
before_validation :store_plain_text
before_validation :sanitize_folder
before_validation :build_local_path
after_save :test
## validations ##
validates_presence_of :site, :source
@ -38,7 +39,7 @@ class ThemeAsset
scope :visible, lambda { |all| all ? {} : { :where => { :hidden => false } } }
## 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 ##
@ -74,17 +75,29 @@ class ThemeAsset
end
end
def plain_text_type
@plain_text_type || (stylesheet_or_javascript? ? self.content_type : nil)
end
def performing_plain_text?
Boolean.set(self.performing_plain_text) || false
end
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
return if !self.stylesheet_or_javascript? || self.plain_text_name.blank? || data.blank?
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({
:tempfile => StringIO.new(sanitized_source),
: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?
end
def test
puts "self.safe_source_filename = #{self.safe_source_filename} / #{self.source_filename}"
end
end

View File

@ -9,37 +9,38 @@
= f.input :meta_keywords
= f.input :meta_description
- if manage_subdomain_or_domains?
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
- if can?(:point, Site)
- if manage_subdomain_or_domains?
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' 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
= f.custom_input :subdomain, :css => 'path' do
%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')
= 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
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)

View File

@ -19,14 +19,14 @@
- if @theme_asset.new_record?
= f.input :plain_text_name
= f.custom_input :content_type do
= f.select :content_type, %w(stylesheet javascript)
= f.custom_input :plain_text_type do
= f.select :plain_text_type, %w(stylesheet javascript)
= 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')) }
= f.text_area :plain_text
.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
!= t('admin.theme_assets.form.choose_file')

View File

@ -1,5 +1,7 @@
- title t('.title', :file => @theme_asset.source_filename)
- puts t('.title', :file => @theme_asset.source_filename)
- content_for :submenu do
= render 'admin/shared/menu/settings'

View File

@ -31,7 +31,7 @@ x Has_one => group by in the select
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 created_by ASC => "Creation date ascending"
- cancan: (authors / designers / admin)
x cancan: (authors / designers / admin)
x model
x ui
x controllers / views:
@ -42,7 +42,7 @@ x better hints:
x account
x snippet
x theme asset
- spec
x features / specs
- better ui: increase text field length + refactor error message
- enable rack-cache only for a specific url
- convert existing templates (the 2 of the themes section)

View 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

View 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

View 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

View 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"

View 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"

View File

@ -7,45 +7,64 @@ Background:
Given I have the site: "test site" set up
And I am an authenticated user
Scenario: Theme assets list is not accessible for non authenticated accounts
Given I am not authenticated
When I go to theme assets
Then I should see "Log in"
# Scenario: Theme assets list is not accessible for non authenticated accounts
# Given I am not authenticated
# When I go to theme assets
# 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
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"
And I follow "stylesheets/application.css"
And I fill in "theme_asset[plain_text]" with "Lorem ipsum (updated)"
And I press "Update"
Then I should see "File was successfully updated."
And I should see "Editing application.css"
And I should see "application.css"
And I should see "Lorem ipsum (updated)" as theme asset code
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 javascript
When I go to theme assets
And I follow "new file"
And I fill in "Folder" with "javascripts/test"
And I attach the file "spec/fixtures/assets/application.js" to "File"
And I press "Create"
Then I should see "File was successfully created."
And I should see "Code"
And I should see "javascripts/test/application.js"
Scenario: Uploading an image which already exists
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"
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 not created."
# Scenario: Uploading a javascript
# When I go to theme assets
# And I follow "new file"
# And I fill in "Folder" with "javascripts/test"
# And I attach the file "spec/fixtures/assets/application.js" to "File"
# And I press "Create"
# Then I should see "File was successfully created."
# And I should see "Code"
# And I should see "javascripts/test/application.js"
#
# Scenario: Updating a javascript
# Given a javascript asset named "application"
# When I go to theme assets
# And I follow "javascripts/application.js"
# And I fill in "theme_asset[plain_text]" with "Lorem ipsum (updated)"
# And I press "Update"
# Then I should see "File was successfully updated."
#
# Scenario: Uploading an image which already exists
# 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"
# 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 not created."

View File

@ -4,13 +4,23 @@ Given /^I am not authenticated$/ do
visit('/admin/sign_out')
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}
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 press "Log in"}
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|
assert [301, 302].include?(@integration_session.status), "Expected status to be 301 or 302, got #{@integration_session.status}"
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)
end
### Common
### Common

View 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

View 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

View File

@ -42,4 +42,12 @@ Then /^the rendered output should look like:$/ do |body_contents|
page.body.should == body_contents
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

View File

@ -12,3 +12,7 @@ Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site
@admin.should_not be_nil
end
Given /^I have a designer and an author$/ do
Factory(:designer, :site => Site.first)
Factory(:author, :site => Site.first)
end

View 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

View File

@ -14,10 +14,22 @@ module NavigationHelpers
new_admin_session_path
when /logout/
destroy_admin_session_path
when /pages/
when /pages( list)?/
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/
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.
# Here is an example that pulls values out of the Regexp:

View File

@ -44,6 +44,8 @@ module Locomotive
end
end
puts "content_type => #{value} / #{original_filename.inspect}"
model.content_type = value
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

View File

@ -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: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 ___ */
form.formtastic fieldset ol li.path em {
@ -558,7 +563,7 @@ form.formtastic fieldset.memberships ol li select {
top: -1px;
}
/* ___ assets ___ */
/* ___ theme assets ___ */
.selector {
position: relative;
@ -572,8 +577,12 @@ form.formtastic fieldset.memberships ol li select {
font-size: 0.7em;
text-decoration: none;
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 {
margin-left: 20px;

View File

@ -9,7 +9,7 @@ Factory.define "test site", :parent => :site do |s|
s.name 'Locomotive test website'
s.subdomain '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
@ -54,8 +54,23 @@ end
## Memberships ##
Factory.define :membership do |m|
m.admin true
m.account{ Account.where(:name => "Bart Simpson").first || Factory(:account) }
m.role 'admin'
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

130
spec/models/ability_spec.rb Normal file
View 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

View File

@ -103,14 +103,14 @@ describe ThemeAsset do
end
it 'should handle stylesheet' do
@asset.content_type = 'stylesheet'
@asset.plain_text_type = 'stylesheet'
@asset.valid?.should be_true
@asset.stylesheet?.should be_true
@asset.source.should_not be_nil
end
it 'should handle javascript' do
@asset.content_type = 'javascript'
@asset.plain_text_type = 'javascript'
@asset.valid?.should be_true
@asset.javascript?.should be_true
@asset.source.should_not be_nil

View File

@ -93,6 +93,35 @@ module Locomotive
IncludeClassMethod.new(meth)
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