merging with the last version of the master branch

This commit is contained in:
did 2011-09-14 16:44:59 +02:00
commit 5dd9481ec2
99 changed files with 1791 additions and 460 deletions

2
.gitignore vendored
View File

@ -33,4 +33,6 @@ gem_graph.png
sites/ sites/
permanent permanent
doc/bushido doc/bushido
*.swp

14
Gemfile
View File

@ -4,7 +4,7 @@ source :rubygems
gem 'rake', '0.9.2' gem 'rake', '0.9.2'
gem 'rails', '3.0.9' gem 'rails', '3.0.10'
gem 'warden' gem 'warden'
gem 'devise', '1.3.4' gem 'devise', '1.3.4'
@ -27,21 +27,21 @@ gem 'carrierwave', '0.5.6'
gem 'dragonfly', '~> 0.9.1' gem 'dragonfly', '~> 0.9.1'
gem 'rack-cache', :require => 'rack/cache' gem 'rack-cache', :require => 'rack/cache'
gem 'custom_fields', '1.0.0.beta.23' gem 'custom_fields', '1.0.0.beta.25'
gem 'cancan' gem 'cancan'
gem 'fog', '0.8.2' gem 'fog', '0.8.2'
gem 'mimetype-fu' gem 'mimetype-fu'
gem 'actionmailer-with-request', :require => 'actionmailer_with_request' gem 'actionmailer-with-request', :require => 'actionmailer_with_request'
gem 'heroku', '1.19.1' gem 'heroku', '1.19.1'
gem 'httparty', '>= 0.6.1' gem 'httparty', '>= 0.6.1'
gem 'RedCloth', '4.2.7' gem 'RedCloth', '4.2.8'
gem 'delayed_job', '2.1.4' gem 'delayed_job', '2.1.4'
gem 'delayed_job_mongoid', '1.0.2' gem 'delayed_job_mongoid', '1.0.2'
gem 'rubyzip' gem 'rubyzip'
gem 'locomotive_jammit-s3', :require => 'jammit-s3' gem 'locomotive_jammit-s3', :require => 'jammit-s3'
gem 'SystemTimer', :platforms => :ruby_18 gem 'SystemTimer', :platforms => :ruby_18
gem 'cells' gem 'cells'
gem 'sanitize'
gem 'highline' gem 'highline'
# The rest of the dependencies are for use when in the locomotive dev environment # The rest of the dependencies are for use when in the locomotive dev environment
@ -57,7 +57,7 @@ end
group :test, :development do group :test, :development do
gem 'linecache', '0.43', :platforms => :mri_18 gem 'linecache', '0.43', :platforms => :mri_18
gem 'ruby-debug', :platforms => :mri_18 gem 'ruby-debug', :platforms => :mri_18
gem 'ruby-debug19', :platforms => :mri_19 gem 'ruby-debug19', :platforms => :mri_19, :require => 'ruby-debug'
gem 'bushido_stub', '0.0.3' gem 'bushido_stub', '0.0.3'
@ -69,7 +69,7 @@ group :test do
gem 'ZenTest' gem 'ZenTest'
gem 'growl-glue' gem 'growl-glue'
gem 'rspec-rails', '2.6.1' gem 'rspec-rails', '2.6.1'
gem 'factory_girl_rails' gem 'factory_girl_rails', '~> 1.1'
gem 'pickle' gem 'pickle'
gem 'xpath', '~> 0.1.4' gem 'xpath', '~> 0.1.4'
gem 'capybara' gem 'capybara'
@ -77,7 +77,7 @@ group :test do
gem 'spork', '~> 0.9.0.rc' gem 'spork', '~> 0.9.0.rc'
gem 'launchy' gem 'launchy'
gem 'mocha', :git => 'git://github.com/floehopper/mocha.git' gem 'mocha', '0.9.12' # :git => 'git://github.com/floehopper/mocha.git'
end end
group :production do group :production do

View File

@ -1,10 +1,3 @@
GIT
remote: git://github.com/floehopper/mocha.git
revision: afa87804ca2124ff5e77f007a84a26ee0667eec8
specs:
mocha (0.9.12)
metaclass (~> 0.0.1)
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
@ -12,18 +5,18 @@ GEM
Platform (>= 0.4.0) Platform (>= 0.4.0)
open4 open4
Platform (0.4.0) Platform (0.4.0)
RedCloth (4.2.7) RedCloth (4.2.8)
SystemTimer (1.2.3) SystemTimer (1.2.3)
ZenTest (4.6.1) ZenTest (4.6.1)
abstract (1.0.0) abstract (1.0.0)
actionmailer (3.0.9) actionmailer (3.0.10)
actionpack (= 3.0.9) actionpack (= 3.0.10)
mail (~> 2.2.19) mail (~> 2.2.19)
actionmailer-with-request (0.3.0) actionmailer-with-request (0.3.0)
rails (>= 3) rails (>= 3)
actionpack (3.0.9) actionpack (3.0.10)
activemodel (= 3.0.9) activemodel (= 3.0.10)
activesupport (= 3.0.9) activesupport (= 3.0.10)
builder (~> 2.1.2) builder (~> 2.1.2)
erubis (~> 2.6.6) erubis (~> 2.6.6)
i18n (~> 0.5.0) i18n (~> 0.5.0)
@ -31,19 +24,19 @@ GEM
rack-mount (~> 0.6.14) rack-mount (~> 0.6.14)
rack-test (~> 0.5.7) rack-test (~> 0.5.7)
tzinfo (~> 0.3.23) tzinfo (~> 0.3.23)
activemodel (3.0.9) activemodel (3.0.10)
activesupport (= 3.0.9) activesupport (= 3.0.10)
builder (~> 2.1.2) builder (~> 2.1.2)
i18n (~> 0.5.0) i18n (~> 0.5.0)
activerecord (3.0.9) activerecord (3.0.10)
activemodel (= 3.0.9) activemodel (= 3.0.10)
activesupport (= 3.0.9) activesupport (= 3.0.10)
arel (~> 2.0.10) arel (~> 2.0.10)
tzinfo (~> 0.3.23) tzinfo (~> 0.3.23)
activeresource (3.0.9) activeresource (3.0.10)
activemodel (= 3.0.9) activemodel (= 3.0.10)
activesupport (= 3.0.9) activesupport (= 3.0.10)
activesupport (3.0.9) activesupport (3.0.10)
archive-tar-minitar (0.5.2) archive-tar-minitar (0.5.2)
arel (2.0.10) arel (2.0.10)
autotest (4.4.6) autotest (4.4.6)
@ -87,7 +80,11 @@ GEM
capybara (>= 1.0.0) capybara (>= 1.0.0)
cucumber (~> 1.0.0) cucumber (~> 1.0.0)
nokogiri (>= 1.4.6) nokogiri (>= 1.4.6)
<<<<<<< HEAD
custom_fields (1.0.0.beta.23) custom_fields (1.0.0.beta.23)
=======
custom_fields (1.0.0.beta.25)
>>>>>>> master
activesupport (~> 3.0.9) activesupport (~> 3.0.9)
mongoid (= 2.0.2) mongoid (= 2.0.2)
daemons (1.1.4) daemons (1.1.4)
@ -170,10 +167,10 @@ GEM
i18n (>= 0.4.0) i18n (>= 0.4.0)
mime-types (~> 1.16) mime-types (~> 1.16)
treetop (~> 1.4.8) treetop (~> 1.4.8)
metaclass (0.0.1)
mime-types (1.16) mime-types (1.16)
mimemagic (0.1.8) mimemagic (0.1.8)
mimetype-fu (0.1.2) mimetype-fu (0.1.2)
mocha (0.9.12)
mongo (1.3.1) mongo (1.3.1)
bson (>= 1.3.1) bson (>= 1.3.1)
mongoid (2.0.2) mongoid (2.0.2)
@ -199,23 +196,23 @@ GEM
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (0.5.7) rack-test (0.5.7)
rack (>= 1.0) rack (>= 1.0)
rails (3.0.9) rails (3.0.10)
actionmailer (= 3.0.9) actionmailer (= 3.0.10)
actionpack (= 3.0.9) actionpack (= 3.0.10)
activerecord (= 3.0.9) activerecord (= 3.0.10)
activeresource (= 3.0.9) activeresource (= 3.0.10)
activesupport (= 3.0.9) activesupport (= 3.0.10)
bundler (~> 1.0) bundler (~> 1.0)
railties (= 3.0.9) railties (= 3.0.10)
railties (3.0.9) railties (3.0.10)
actionpack (= 3.0.9) actionpack (= 3.0.10)
activesupport (= 3.0.9) activesupport (= 3.0.10)
rake (>= 0.8.7) rake (>= 0.8.7)
rdoc (~> 3.4) rdoc (~> 3.4)
thor (~> 0.14.4) thor (~> 0.14.4)
raindrops (0.7.0) raindrops (0.7.0)
rake (0.9.2) rake (0.9.2)
rdoc (3.9.2) rdoc (3.9.4)
responders (0.6.4) responders (0.6.4)
rest-client (1.6.3) rest-client (1.6.3)
mime-types (>= 1.16) mime-types (>= 1.16)
@ -258,6 +255,8 @@ GEM
rubyzip (0.9.4) rubyzip (0.9.4)
s3 (0.3.8) s3 (0.3.8)
proxies (~> 0.2.0) proxies (~> 0.2.0)
sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6)
sass (3.1.2) sass (3.1.2)
selenium-webdriver (2.4.0) selenium-webdriver (2.4.0)
childprocess (>= 0.2.1) childprocess (>= 0.2.1)
@ -287,7 +286,7 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
RedCloth (= 4.2.7) RedCloth (= 4.2.8)
SystemTimer SystemTimer
ZenTest ZenTest
actionmailer-with-request actionmailer-with-request
@ -300,14 +299,18 @@ DEPENDENCIES
carrierwave (= 0.5.6) carrierwave (= 0.5.6)
cells cells
cucumber-rails (= 1.0.2) cucumber-rails (= 1.0.2)
<<<<<<< HEAD
custom_fields (= 1.0.0.beta.23) custom_fields (= 1.0.0.beta.23)
=======
custom_fields (= 1.0.0.beta.25)
>>>>>>> master
database_cleaner database_cleaner
delayed_job (= 2.1.4) delayed_job (= 2.1.4)
delayed_job_mongoid (= 1.0.2) delayed_job_mongoid (= 1.0.2)
devise (= 1.3.4) devise (= 1.3.4)
devise_bushido_authenticatable (= 1.0.0.alpha10) devise_bushido_authenticatable (= 1.0.0.alpha10)
dragonfly (~> 0.9.1) dragonfly (~> 0.9.1)
factory_girl_rails factory_girl_rails (~> 1.1)
fog (= 0.8.2) fog (= 0.8.2)
formtastic (~> 1.2.3) formtastic (~> 1.2.3)
growl-glue growl-glue
@ -322,12 +325,12 @@ DEPENDENCIES
locomotive_liquid (= 2.2.2) locomotive_liquid (= 2.2.2)
locomotive_mongoid_acts_as_tree (= 0.1.5.7) locomotive_mongoid_acts_as_tree (= 0.1.5.7)
mimetype-fu mimetype-fu
mocha! mocha (= 0.9.12)
mongoid (~> 2.0.2) mongoid (~> 2.0.2)
mongoid_i18n mongoid_i18n
pickle pickle
rack-cache rack-cache
rails (= 3.0.9) rails (= 3.0.10)
rake (= 0.9.2) rake (= 0.9.2)
rmagick (= 2.12.2) rmagick (= 2.12.2)
rspec-cells rspec-cells
@ -335,6 +338,7 @@ DEPENDENCIES
ruby-debug ruby-debug
ruby-debug19 ruby-debug19
rubyzip rubyzip
sanitize
sass (= 3.1.2) sass (= 3.1.2)
spork (~> 0.9.0.rc) spork (~> 0.9.0.rc)
unicorn unicorn

View File

@ -19,8 +19,8 @@ h2. Gems
Here is a short list of main gems used in the application. Here is a short list of main gems used in the application.
* Rails 3.0.9 * Rails 3.0.10
* Mongoid 2.0.2 (with MongoDB 1.6) * Mongoid 2.0.2 (with MongoDB 1.8)
* Liquid * Liquid
* Devise * Devise
* Carrierwave * Carrierwave
@ -34,8 +34,8 @@ See the "official website":http://www.locomotivecms.com
h2. Team h2. Team
* Developers: "Didier Lafforgue":http://www.nocoffee.fr, "Jacques Crocker":http://www.railsjedi.com * Developers: "Didier Lafforgue":http://www.nocoffee.fr, "Jacques Crocker":http://www.railsjedi.com, "Mario Visic":http://www.mariovisic.com
* Contributors: "Dirk Kelly":http://www.dirkkelly.com, "Mario Visic":http://www.mariovisic.com, "Raphael Costa":http://raphaelcosta.net (Brazilian Portuguese translation), "Bernd Hauser":http://www.designhunger.de (German translation), "Andrea Frigido":http://www.frisoft.it (Italian translation), "Enrique García":https://github.com/kikito (Spanish translation), "Lars Smit":https://github.com/larssmit (Dutch translation) * Contributors: "Dirk Kelly":http://www.dirkkelly.com, "Raphael Costa":http://raphaelcosta.net (Brazilian Portuguese translation), "Bernd Hauser":http://www.designhunger.de (German translation), "Andrea Frigido":http://www.frisoft.it (Italian translation), "Enrique García":https://github.com/kikito (Spanish translation), "Lars Smit":https://github.com/larssmit (Dutch translation), "PitOn":https://github.com/GarPit (Russian translation)
* UI Designer: "Sacha Greif":http://www.sachagreif.com * UI Designer: "Sacha Greif":http://www.sachagreif.com
* IE maintainer: "Alex Sanford":https://github.com/alexsanford * IE maintainer: "Alex Sanford":https://github.com/alexsanford

View File

@ -7,6 +7,10 @@ module Admin
before_filter :set_content_type before_filter :set_content_type
before_filter :block_content_type_with_disabled_api
before_filter :sanitize_content_params, :only => :create
def create def create
@content = @content_type.contents.build(params[:content]) @content = @content_type.contents.build(params[:content])
@ -32,7 +36,23 @@ module Admin
def set_content_type def set_content_type
@content_type = current_site.content_types.where(:slug => params[:slug]).first @content_type = current_site.content_types.where(:slug => params[:slug]).first
render :json => { :error => 'Api not enabled' } and return false unless @content_type.api_enabled end
def block_content_type_with_disabled_api
unless @content_type.api_enabled?
respond_to do |format|
format.json { render :json => { :error => 'Api not enabled' }, :status => :forbidden }
format.html { render :text => 'Api not enabled', :status => :forbidden }
end
return false
end
end
def sanitize_content_params
(params[:content] || {}).each do |key, value|
next unless value.is_a?(String)
params[:content][key] = Sanitize.clean(value, Sanitize::Config::BASIC)
end
end end
end end

View File

@ -9,10 +9,10 @@ module Admin
before_filter :require_site before_filter :require_site
load_and_authorize_resource
before_filter :validate_site_membership before_filter :validate_site_membership
load_and_authorize_resource
before_filter :set_locale before_filter :set_locale
before_filter :set_site_locale before_filter :set_site_locale

View File

@ -6,10 +6,17 @@ module Admin
include Locomotive::Render include Locomotive::Render
before_filter :require_site before_filter :require_site
before_filter :authenticate_admin!, :only => [:edit]
before_filter :validate_site_membership, :only => [:edit]
def show def show
render_locomotive_page render_locomotive_page
end end
def edit
@editing = true
render_locomotive_page
end
end end
end end

View File

@ -7,7 +7,7 @@ module Admin::ContentTypesHelper
@content_types = current_site.content_types.ordered. @content_types = current_site.content_types.ordered.
limit(:contents => Locomotive.config.lastest_items_nb). limit(:contents => Locomotive.config.lastest_items_nb).
only(:name, :slug, :highlighted_field_name, :content_custom_fields_version, :order_by, :serialized_item_template).to_a only(:site_id, :name, :slug, :highlighted_field_name, :content_custom_fields_version, :order_by, :serialized_item_template, :raw_item_template).to_a
if @content_type && @content_type.persisted? && @content_types.index(@content_type) >= MAX_DISPLAYED_CONTENTS if @content_type && @content_type.persisted? && @content_types.index(@content_type) >= MAX_DISPLAYED_CONTENTS
@content_types.delete(@content_type) @content_types.delete(@content_type)

View File

@ -22,7 +22,7 @@ module Admin::CustomFieldsHelper
def options_for_highlighted_field(content_type, collection_name) def options_for_highlighted_field(content_type, collection_name)
custom_fields_collection_name = "ordered_#{collection_name.singularize}_custom_fields".to_sym custom_fields_collection_name = "ordered_#{collection_name.singularize}_custom_fields".to_sym
collection = content_type.send(custom_fields_collection_name) collection = content_type.send(custom_fields_collection_name)
collection.delete_if { |f| f.label == 'field name' || f.kind == 'file' } collection.delete_if { |f| f.label == 'field name' || %w(file has_one has_many).include?(f.kind) }
collection.map { |field| [field.label, field._name] } collection.map { |field| [field.label, field._name] }
end end
@ -40,9 +40,7 @@ module Admin::CustomFieldsHelper
end end
def options_for_association_target def options_for_association_target
current_site.content_types.collect do |c| current_site.reload.content_types.collect { |c| [c.name, c.content_klass.to_s] }
c.persisted? ? [c.name, c.content_klass.to_s] : nil
end.compact
end end
def options_for_reverse_lookups(my_content_type) def options_for_reverse_lookups(my_content_type)
@ -86,7 +84,7 @@ module Admin::CustomFieldsHelper
end end
def options_for_has_one_or_has_many(field, content = nil, &block) def options_for_has_one_or_has_many(field, content = nil, &block)
content_type = field.target.constantize._parent content_type = field.target.constantize._parent.reload
if content_type.groupable? if content_type.groupable?
grouped_contents = content_type.list_or_group_contents grouped_contents = content_type.list_or_group_contents

View File

@ -61,6 +61,8 @@ class Ability
can :point, Site can :point, Site
cannot :create, Site
can :manage, Membership can :manage, Membership
cannot :change_role, Membership do |membership| cannot :change_role, Membership do |membership|

View File

@ -9,8 +9,9 @@ class EditableElement
localized_field :default_content localized_field :default_content
field :default_attribute field :default_attribute
field :hint field :hint
field :disabled, :type => Boolean, :default => false field :priority, :type => Integer, :default => 0
field :assignable, :type => Boolean, :default => true field :disabled, :type => Boolean, :default => false
field :assignable, :type => Boolean, :default => true
field :from_parent, :type => Boolean, :default => false field :from_parent, :type => Boolean, :default => false
## associations ## ## associations ##
@ -19,6 +20,9 @@ class EditableElement
## validations ## ## validations ##
validates_presence_of :slug validates_presence_of :slug
## scopes ##
scope :by_priority, :order_by => [[:priority, :desc]]
## methods ## ## methods ##
end end

View File

@ -32,7 +32,7 @@ module Extensions
end end
def editable_elements_grouped_by_blocks def editable_elements_grouped_by_blocks
all_enabled = self.editable_elements.reject { |el| el.disabled? } all_enabled = self.editable_elements.by_priority.reject { |el| el.disabled? }
groups = all_enabled.group_by(&:block) groups = all_enabled.group_by(&:block)
groups.delete_if { |block, elements| elements.empty? } groups.delete_if { |block, elements| elements.empty? }
end end

View File

@ -75,7 +75,7 @@ class Page
if self.index? || self.not_found? if self.index? || self.not_found?
self.slug self.slug
else else
slugs = self.self_and_ancestors.map(&:slug) slugs = self.self_and_ancestors.sort_by(&:depth).map(&:slug)
slugs.shift unless slugs.size == 1 slugs.shift unless slugs.size == 1
File.join slugs File.join slugs
end end

View File

@ -9,7 +9,7 @@ class ThemeAssetUploader < CarrierWave::Uploader::Base
end end
def extension_white_list def extension_white_list
%w(jpg jpeg gif png css js swf flv eot svg ttf woff otf ico) %w(jpg jpeg gif png css js swf flv eot svg ttf woff otf ico htc)
end end
def self.url_for(site, path) def self.url_for(site, path)

View File

@ -6,10 +6,11 @@
- content_for :actions do - content_for :actions do
= render_cell 'admin/site_locale_picker', :show, :site => current_site, :locale => I18n.site_locale = render_cell 'admin/site_locale_picker', :show, :site => current_site, :locale => I18n.site_locale
- if can?(:manage, @site) - content_for :buttons do
- content_for :buttons do - if can?(:manage, @site)
= admin_button_tag :export, new_admin_export_url, :class => 'new' = admin_button_tag :export, new_admin_export_url, :class => 'new'
= admin_button_tag :import, new_admin_import_url, :class => 'new' = admin_button_tag :import, new_admin_import_url, :class => 'new'
- if can?(:create, Account)
= admin_button_tag t('.new_membership'), new_admin_membership_url, :class => 'new' = admin_button_tag t('.new_membership'), new_admin_membership_url, :class => 'new'
%p!= t('.help') %p!= t('.help')

View File

@ -1,5 +1,3 @@
- field.target.constantize.reload_parent! # to make sure all the contents from the parent are loaded
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'has-many', :required => required do = form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'has-many', :required => required do
.has-many-selector .has-many-selector

View File

@ -8,7 +8,7 @@
- if multi_sites? - if multi_sites?
- content_for :buttons do - content_for :buttons do
= admin_button_tag t('.new_site'), new_admin_site_url, :class => 'new' if can?(:manage, Site) = admin_button_tag t('.new_site'), new_admin_site_url, :class => 'new' if can?(:create, Site)
%p= t('.help') %p= t('.help')

View File

@ -15,7 +15,7 @@
%li{ :id => "block-#{index}", :class => 'block', :style => "display: #{index == 0 ? 'block' : 'none' }" } %li{ :id => "block-#{index}", :class => 'block', :style => "display: #{index == 0 ? 'block' : 'none' }" }
%fieldset.inputs %fieldset.inputs
%ol %ol
- elements.each_with_index do |el, index| - elements.each do |el|
= f.fields_for 'editable_elements', el, :child_index => el._index do |g| = f.fields_for 'editable_elements', el, :child_index => el._index do |g|
- case el - case el
- when EditableLongText - when EditableLongText

View File

@ -9,5 +9,5 @@
%span!= t('.updated_at') %span!= t('.updated_at')
%span.date= l asset.updated_at, :format => :short %span.date= l asset.updated_at, :format => :short
- if edit - if edit && can?(:destroy, asset)
= link_to image_tag('admin/list/icons/trash.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete = link_to image_tag('admin/list/icons/trash.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete

View File

@ -1,7 +1,7 @@
<% <%
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip" std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --require features --strict --tags ~@wip"
%> %>
default: <%= std_opts %> features default: <%= std_opts %> features
wip: --tags @wip:3 --wip features wip: --tags @wip:3 --wip features

View File

@ -8,6 +8,7 @@ de:
it: "Italienisch" it: "Italienisch"
nl: "Holländer" nl: "Holländer"
es: "Spanisch" es: "Spanisch"
ru: "Russisch"
buttons: buttons:
login: Einloggen login: Einloggen

View File

@ -8,6 +8,7 @@ en:
it: Italian it: Italian
nl: Dutch nl: Dutch
es: Spanish es: Spanish
ru: Russian
buttons: buttons:
login: Log in login: Log in

View File

@ -173,6 +173,7 @@ es:
it: Italiano it: Italiano
nl: holandés nl: holandés
es: Español es: Español
ru: Ruso
ask_for_name: "Por favor escriba su nuevo nombre" ask_for_name: "Por favor escriba su nuevo nombre"
theme_assets: theme_assets:

View File

@ -8,6 +8,7 @@ fr:
it: "en Italien" it: "en Italien"
nl: "en Hollandais" nl: "en Hollandais"
es: en Espagnol es: en Espagnol
ru: en Russe
errors: errors:
"500": "500":

View File

@ -173,6 +173,7 @@ it:
it: Italiano it: Italiano
nl: Olandese nl: Olandese
es: Spagnolo es: Spagnolo
ru: Russo
ask_for_name: "Prego, digita il tuo nome" ask_for_name: "Prego, digita il tuo nome"
theme_assets: theme_assets:

View File

@ -159,6 +159,7 @@ nl:
pt-BR: "Braziliaans Portugees" pt-BR: "Braziliaans Portugees"
it: Italiaans it: Italiaans
nl: Nederlands nl: Nederlands
ru: Russisch
ask_for_name: "Voer uw nieuwe naam in" ask_for_name: "Voer uw nieuwe naam in"
theme_assets: theme_assets:

View File

@ -159,6 +159,7 @@ pt-BR:
it: Italiano it: Italiano
nl: Holandês nl: Holandês
es: Espanhol es: Espanhol
ru: Russo
ask_for_name: "Por favor preencha o novo nome" ask_for_name: "Por favor preencha o novo nome"
theme_assets: theme_assets:

View File

@ -0,0 +1,303 @@
ru:
admin:
buttons:
login: Войти
send_password: Отправить
change_password: Изменить
new_item: "+ добавить"
switch_to_site: Сайт
delete: "Удалить"
messages:
confirm: Вы уверены ?
shared:
header:
welcome: Привет, %{name}
see: Сайт
switch: К другому сайту
help: Справка
logout: Выйти
menu:
contents: Содержимое
assets: Файлы
settings: Настройки
pages: Страницы
snippets: Сниппеты
account: Аккаунт
site: Сайт
theme_assets: Файлы темы
footer:
who_is_behind: "Service developed by %{development} and designed by <a href=\"http://www.sachagreif.com\">Sacha Greif</a>"
form_actions:
back: Назад без сохранения
create: Создать
update: Сохранить
send: Отправить
errors:
"500":
title: Ошибка Приложения
notice: "Мы сожалеем, но что-то пошло не так"
link: "&rarr; Назад в приложение"
"404":
title: Страница не найдена
notice: "Запрашиваемая страница не существует."
link: "&rarr; Назад в приложение"
notifications:
new_content_instance:
subject: "[%{type}] новый"
title: "Привет %{name}, просто сообщаем, что новый элемент был создан %{date}"
type: "Модель: %{type}"
sites_picker:
new: + new site
custom_fields:
edit:
title: Редактирование пользовательского поля
text_formatting:
none: None
html: HTML
edit_field:
title: Редактировать поле
edit_category:
title: Редактировать опции
help: Управляйте списком опций для поля выбора select.
collection_label: Списко опций
types:
category:
edit_categories: Редактировать опции
file:
delete_file: Удалить файл
has_many:
empty: Пусто
index:
is_required: является обязательным
default_label: Название поля
sessions:
new:
title: Войти
link: "Я забыл свой пароль"
email: "Email"
password: "Пароль"
passwords:
new:
title: Забыли пароль
link: "&rarr; Назад к странице входа"
email: "Ваш email"
edit:
title: Изменить мой пароль
link: "&rarr; Назад к странице логина"
password: "Ваш новый пароль"
password_confirmation: "Подтверждение нового пароля"
pages:
index:
title: Список страниц
help: "Страницы организованы в виде дерева. Вы можете сортировать как страницы, так и папки"
no_items: "There are no pages for now. Just click <a href=\"%{url}\">here</a> to create the first one."
new: новая страница
lastest_items: Страницы за последнее время
new:
title: Новая страница
help: "Заполните форму, приведенную ниже, для создания страницы. Будьте осторожны, по умолчанию, страница не опубликована."
page:
updated_at: обновлено
edit:
show: смотреть
help: "Заголовок страницы может быть изменен, если кликнуть на нем. Чтобы применить изменения, нажмите кнопку \"Сохранить\"."
ask_for_title: "Пожалуйста введите новое имя страницы"
form:
delete_file: Удалить файл
default_block: По умолчанию
cache_strategy:
none: Нет
simple: Простая
hour: 1 час
day: 1 день
week: 1 неделя
month: 1 месяц
snippets:
index:
title: Список сниппетов
help: "Сниппеты это куски HTML кода, которые могут быть использованы в разных местах в рамках сайта (таких, как \"футер\" к примеру)."
no_items: "Пока нет ни одного сниппета. Нажмите <a href=\"%{url}\">здесь</a> для создания первого сниппета."
new: новый сниппет
new:
title: Новый сниппет
help: "Заполните форму, приведенную ниже, для изменения сниппета."
edit:
title: Редактирование сниппета
help: "Включите ваш сниппет в шаблоны страницы с помощью следующего кода liquid : <span class='code'>{% include '%{slug}' %}</span>."
snippet:
updated_at: Обновлено
sites:
new:
title: Новый сайт
help: "Заполните форму, приведенную ниже, чтобы создать новый сайт."
current_site:
edit:
export: экспорт
import: импорт
new_membership: добавить аккаунт
help: "Название сайта может быть изменено, если кликнуть на нем. Чтобы применить изменения, нажмите кнопку \"Save\"."
ask_for_name: "Пожалуйста введите новое имя сайта"
memberships:
roles:
admin: Администратор
designer: Дизайнер
author: Автор
new:
title: Новая учетная запись
help: "Пожалуйста для добавления предоставьте email аккаунта. Если он не существует, вы будете перенаправлены на форму создания аккаунта."
accounts:
new:
title: Новый аккаунт
help: "Заполните форму, приведенную ниже, чтобы добавить новый аккаунт."
my_account:
edit:
help: "Вы можете изменить логин просто кликнув на нем. Чтобы применить изменения, нажмите кнопку \"Сохранить\"."
new_site: новый сайт
en: Английский
de: Немецкий
fr: Французский
pt-BR: "Бразильский - Португальский"
it: Итальянский
nl: Голландский
es: Испанский
ask_for_name: "Пожалуйста введите ваш новый логин"
theme_assets:
index:
title: Список файлов темы
help: "Секция файлов темы это место, где вы можете управлять файлами, необходимыми для вашего шаблона, сниппетов и т.д. Если вам необходимо управление галереей изображений, создайте новый тип контента.<br/><b>Внимание:</b> вы можете не увидеть всех файлов - в зависимости от ваших прав."
new: новый файл
snippets: Сниппеты
css_and_js: Стили и javascript
fonts: Шрифты
images: Изображения
medias: Медиа
no_items: "Пока нет ни одного файла."
asset:
updated_at: Обновлено
new:
title: Новый файл
help: "У вас есть выбор - либо загрузить файл, либо копировать/вставить стиль CSS или javascript в виде текста."
edit:
title: "Редактирование %{file}"
help: "Этот файл доступен по следующему url: <a href='%{url}'>%{url}</a>"
help_image: "Включите ваше изображение в шаблоны страницы или сниппеты с помощью следующего liquid кода : <span class='code'>{{ '%{path}' | theme_image_tag }}</span>.<br/>Your current image dimensions : <b>%{width}px x %{height}px</b>.<br/>"
help_javascript: "Включите ваш javascript файл в шаблоны страницы или сниппеты с помощью следующего кода : <span class='code'>{{ '%{path}' | javascript_tag }}</span>.<br/>"
help_stylesheet: "Включите ваш файл стилей CSS в шаблоны страницы или сниппеты с помощью следующего кода : <span class='code'>{{ '%{path}' | stylesheet_tag }}</span>.<br/>"
form:
picker_link: Вставить файл в код
choose_file: Выбрать файл
choose_plain_text: Выбрать простой текст
images:
title: Список изображений
no_items: "Пока нет ни одного файла."
assets:
new:
title: Новый файл
help: "Заполните форму, приведенную ниже, для создания файла (asset)."
edit:
title: Редактировать файл
help: "Заполните форму, приведенную ниже, для изменения файла."
content_types:
index:
new: новая модель
new:
title: Новая модель
help: "Создайте ваши собственные модели данных (Проекты, Персоны, ...и т.д.). Модель должна иметь по крайней мере одно поле. Элементы, созданные из этого типа содержимого, будут иметь первое поле как обязательное."
edit:
title: Редактирование модели
help: "Ваша модель должна иметь по крайней мере одно поле. Элементы, созданные из этого типа содержимого, будут иметь это поле как обязательное."
show_items: смотреть элементы
new_item: новый элемент
form:
order_by:
created_at: 'По дате создания'
updated_at: 'По дате обновления'
position_in_list: Вручную
order_direction:
asc: По возрастанию
desc: По убыванию
contents:
index:
title: 'Список "%{type}"'
edit: редактировать модель
destroy: удалить модель
download: скачать элементы
new: новый элемент
category_noname: "Без имени"
lastest_items: "Элементы за последнее время"
updated_at: "Обновлено"
list:
no_items: "На данный момент нет ни одного элемента. Нажмите <a href=\"%{url}\">здесь</a> для создания первого элемента."
new:
title:
default: '%{type} &mdash; новый элемент'
breadcrumb: '%{root} &raquo; %{type} &mdash; новый элемент'
edit:
title:
default: '%{type} &mdash; редактирование элемента'
breadcrumb: '%{root} &raquo; %{type} &mdash; редактирование элемента'
form:
has_many:
new_item: Новый элемент
image_picker:
link: Вставить изображение в код
cross_domain_sessions:
new:
title: Кроссдоменная аутентификация
notice: Вы будете перенаправлены на вебсайт в течение нескольких секунд.
import:
new:
title: Импортировать шаблон сайта
help: "Будьте осторожны при загрузке нового шаблона для существующего сайта, ваши текущие данные могут быть изменены или даже удалены."
show:
title: Выполняется импорт
help: "Ваш сайт обновляется из zip файла темы, который вы только что загрузили. Это займет несколько секунд."
steps:
site: Информация сайта
content_types: Пользовательские типы содержимого
assets: Файлы темы
snippets: Сниппеты
pages: Страницы
messages:
success: "Ваш сайт был успешно обновлен."
failure: "Импорт не работает."
installation:
common:
title: Первая установка Locomotive
next: Следующий шаг
step_1:
title: "Шаг 1/2 &mdash; Создайте аккаунт"
name: Логин
email: Email
password: Пароль
password_confirmation: Подтверждение пароля
done: "Вы уже добавили учетную запись:<br/><strong>%{name}</strong>, <em>%{email}</em>"
next: Создать аккаунт
step_2:
title: "Шаг 2/2 &mdash; Создайте первый сайт"
explanations: "Если вы уже загрузили шаблон сайта по умолчанию (см. инструкцию), вы можете использовать его прямо сейчас. Или вы можете загрузить шаблон сайта как zip файл (доступные бесплатные шаблоны <a href=\"http://www.locomotivecms.com/support/themes\">здесь</a>)."
back_to_default_template: "Нажмите <a href='#'>здесь</a> для выбора шаблона сайта по умолчанию"
next: Создать сайт

View File

@ -0,0 +1,4 @@
ru:
carrierwave:
errors:
integrity: 'не допустимый тип файла.'

View File

@ -1,7 +1,143 @@
nl: nl:
date: number:
format:
separator: ","
precision: 2
delimiter: .
human:
storage_units:
format: "%n %u"
units:
kb: KB
tb: TB
gb: GB
byte:
one: Byte
other: Bytes
mb: MB
currency:
format:
format: "%u %n"
unit: !binary |
4oKs
separator: .
precision: 2
delimiter: .
time:
am: "'s ochtends"
formats: formats:
default: "%m/%d/%Y" default: "%a %d %b %Y %H:%M:%S %Z"
time: "%H:%M"
short: "%d %b %H:%M"
only_second: "%S"
datetime:
formats:
default: "%d-%m-%YT%H:%M:%S%Z"
long: "%d %B %Y %H:%M"
pm: "'s middages"
date:
month_names:
-
- Januari
- Februari
- Maart
- April
- Mei
- Juni
- Juli
- Augustus
- September
- Oktober
- November
- December
abbr_day_names:
- Zon
- Maa
- Din
- Woe
- Don
- Vri
- Zat
order:
- :day
- :month
- :year
formats:
only_day: "%e"
default: "%d/%m/%Y"
short: "%e %b"
long: "%e %B %Y"
day_names:
- Zondag
- Maandag
- Dinsdag
- Woensdag
- Donderdag
- Vrijdag
- Zaterdag
abbr_month_names:
-
- Jan
- Feb
- Mar
- Apr
- Mei
- Jun
- Jul
- Aug
- Sep
- Okt
- Nov
- Dec
support:
array:
words_connector: ","
last_word_connector: ", en"
two_words_connector: en
datetime:
format:
default: "%Y-%m-%dT%H:%M:%S%Z"
prompts:
minute: Minuut
second: Seconden
month: Maand
hour: Uur
day: Dag
year: Jaar
distance_in_words:
less_than_x_minutes:
one: "minder dan \xC3\xA9\xC3\xA9n minuut"
other: minder dan {{count}} minuten
x_days:
one: 1 dag
other: "{{count}} dagen"
x_seconds:
one: 1 seconde
other: "{{count}} seconden"
about_x_hours:
one: "ongeveer \xC3\xA9\xC3\xA9n uur"
other: ongeveer {{count}} uur
less_than_x_seconds:
one: "minder dan \xC3\xA9\xC3\xA9n seconde"
other: minder dan {{count}} seconden
x_months:
one: 1 maand
other: "{{count}} maanden"
x_minutes:
one: 1 minuut
other: "{{count}} minuten"
about_x_years:
one: "ongeveer \xC3\xA9\xC3\xA9n jaar"
other: ongeveer {{count}} jaren
about_x_months:
one: "ongeveer \xC3\xA9\xC3\xA9n maand"
other: ongeveer {{count}} maanden
over_x_years:
one: "langer dan \xC3\xA9\xC3\xA9n jaar"
other: langer {{count}} jaar
half_a_minute: halve minuut
errors: errors:
messages: messages:
@ -27,7 +163,7 @@ nl:
title: "Pagina niet gevonden" title: "Pagina niet gevonden"
body: "Inhoud van de 404 pagina" body: "Inhoud van de 404 pagina"
other: other:
body: "{% breid 'parent' uit %}" body: "{% extends 'parent' %}"
pagination: pagination:
previous: "&laquo; Vorige" previous: "&laquo; Vorige"

View File

@ -0,0 +1,281 @@
ru:
errors:
messages:
domain_taken: "%{value} уже занято"
invalid_domain: "%{value} имеет неверное значение"
needs_admin_account: "Обязателен хотя бы один аккаунт администратора"
protected_page: "Вы не можете удалять стартовую или 404 страницы"
extname_changed: "Новый файл не имеет оригинального расширения"
array_too_short: "слишком мал (минимальное число элементов %{count})"
liquid_syntax: "Ошибка синтаксиса Liquid ('%{error}')"
invalid_theme_file: "не может быть пустым или не является zip файлом"
too_short: "слишком короткий (не менее %{count} символов)"
blank: "не может быть пустым"
invalid: "имеет неверное значение"
confirmation: "не совпадает с подтверждением"
page:
liquid_syntax: "Ошибка синтаксиса Liquid ('%{error}' в '%{fullpath}')"
liquid_extend: "Страница '%{fullpath}' расширяет шаблон, который не существует"
attributes:
defaults:
pages:
index:
title: "Стартовая страница"
body: "Содержимое стартовой страницы"
"404":
title: "Страница не найдена"
body: "Содержимое страницы 404"
other:
body: "{% расширяет 'parent' %}"
mongoid:
attributes:
page:
title: Имя
parent: Родитель
slug: Ссылка
templatized: Шаблонизирована
published: Опубликована
listed: Меню
redirect: Перенаправлена
redirect_url: Адрес перенаправления
cache_strategy: Стратегия кеширования
content_type:
name: Имя
description: Описание
slug: Ссылка
order_by: Сортировать по
order_direction: Направление сортировки
highlighted_field_name: Выделенное имя поля
group_by_field_name: Группировка по имени поля
api_enabled: API включен
asset:
source: Файл
account:
email: Email
name: Имя
language: Язык
password: Пароль
password_confirmation: Подтверждение пароля
snippet:
body: Код
slug: Ссылка
name: Название
theme_asset:
content_type: Тип содержимого
site:
name: Имя сайта
domain_name: Домен
subdomain: Поддомен
restricted_access: Активный ?
access_login: Имя пользователя
access_password: "Пароль"
pagination:
previous: "&laquo; Предыдущая"
next: "Следующая &raquo;"
date:
formats:
# Форматы указываются в виде, поддерживаемом strftime.
# По умолчанию используется default.
# Можно добавлять собственные форматы
#
#
# Use the strftime parameters for formats.
# When no format has been given, it uses default.
# You can provide other formats here if you like!
default: "%d.%m.%Y"
short: "%d %b"
long: "%d %B %Y"
# Названия дней недели -- контекстные и отдельностоящие
day_names: [воскресенье, понедельник, вторник, среда, четверг, пятница, суббота]
standalone_day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота]
abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб]
# Названия месяцев -- сокращенные и полные, плюс отдельностоящие.
# Не забудьте nil в начале массиве (~)
#
#
# Don't forget the nil at the beginning; there's no such thing as a 0th month
month_names: [~, января, февраля, марта, апреля, мая, июня, июля, августа, сентября, октября, ноября, декабря]
standalone_month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь]
abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.]
standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.]
# Порядок компонентов даты для хелперов
#
#
# Used in date_select and datime_select.
order:
- :day
- :month
- :year
time:
# Форматы времени
formats:
default: "%a, %d %b %Y, %H:%M:%S %z"
short: "%d %b, %H:%M"
long: "%d %B %Y, %H:%M"
# am/pm решено перевести как "утра/вечера" :)
am: "утра"
pm: "вечера"
number:
# Используется в number_with_delimiter()
# Также является установками по умолчанию для 'currency', 'percentage', 'precision', 'human'
#
# Used in number_with_delimiter()
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
format:
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
separator: "."
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
delimiter: " "
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
precision: 3
# Used in number_to_currency()
currency:
format:
# Формат отображения валюты и обозначение самой валюты
#
#
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
format: "%n %u"
unit: "руб."
# These three are to override number.format and are optional
separator: "."
delimiter: " "
precision: 2
# Used in number_to_percentage()
percentage:
format:
# These three are to override number.format and are optional
# separator:
delimiter: ""
# Used in number_to_precision()
precision:
format:
# These three are to override number.format and are optional
# separator:
delimiter: ""
# precision:
# Used in number_to_human_size()
human:
format:
# These three are to override number.format and are optional
# separator:
delimiter: ""
precision: 1
# Rails 2.2
# storage_units: [байт, КБ, МБ, ГБ, ТБ]
# Rails 2.3
storage_units:
# Storage units output formatting.
# %u is the storage unit, %n is the number (default: 2 MB)
format: "%n %u"
units:
byte:
one: "байт"
few: "байта"
many: "байт"
other: "байта"
kb: "КБ"
mb: "МБ"
gb: "ГБ"
tb: "ТБ"
# Используется в хелперах distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
#
#
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
datetime:
distance_in_words:
half_a_minute: "меньше минуты"
less_than_x_seconds:
one: "меньше %{count} секунды"
few: "меньше %{count} секунд"
many: "меньше %{count} секунд"
other: "меньше %{count} секунды"
x_seconds:
one: "%{count} секунда"
few: "%{count} секунды"
many: "%{count} секунд"
other: "%{count} секунды"
less_than_x_minutes:
one: "меньше %{count} минуты"
few: "меньше %{count} минут"
many: "меньше %{count} минут"
other: "меньше %{count} минуты"
x_minutes:
one: "%{count} минуту"
few: "%{count} минуты"
many: "%{count} минут"
other: "%{count} минуты"
about_x_hours:
one: "около %{count} часа"
few: "около %{count} часов"
many: "около %{count} часов"
other: "около %{count} часа"
x_days:
one: "%{count} день"
few: "%{count} дня"
many: "%{count} дней"
other: "%{count} дня"
about_x_months:
one: "около %{count} месяца"
few: "около %{count} месяцев"
many: "около %{count} месяцев"
other: "около %{count} месяца"
x_months:
one: "%{count} месяц"
few: "%{count} месяца"
many: "%{count} месяцев"
other: "%{count} месяца"
about_x_years:
one: "около %{count} года"
few: "около %{count} лет"
many: "около %{count} лет"
other: "около %{count} лет"
over_x_years:
one: "больше %{count} года"
few: "больше %{count} лет"
many: "больше %{count} лет"
other: "больше %{count} лет"
almost_x_years:
one: "почти %{count} год"
few: "почти %{count} года"
many: "почти %{count} лет"
other: "почти %{count} лет"
prompts:
year: "Год"
month: "Месяц"
day: "День"
hour: "Часов"
minute: "Минут"
second: "Секунд"
# Used in array.to_sentence.
support:
array:
# Rails 2.2
sentence_connector: "и"
skip_last_comma: true
# Rails 2.3
words_connector: ", "
two_words_connector: " и "
last_word_connector: " и "

View File

@ -0,0 +1,63 @@
ru:
errors:
messages:
not_found: "не найден"
already_confirmed: "был уже подтвержден"
not_locked: "не был заблокирован"
devise:
failure:
admin:
unauthenticated: 'Вам необходимо войти или зарегистрироваться перед тем, как продолжить.'
unconfirmed: 'Вы должны подтвердить аккаунт перед продолжением.'
locked: 'Ваш аккаунт заблокирован.'
invalid: 'Неверный email или пароль.'
no_membership: 'Ваш аккаунт не зарегистирован на сайте, пожалуйста обратитесь к администратору сайта для получения доступа.'
invalid_token: 'Неверный authentication token.'
timeout: 'Срок действия вашей сессии истек, пожалуйста залогиньтесь для продолжения.'
inactive: 'Ваш аккаунт еще не был активирован.'
sessions:
admin:
signed_in: 'Вход выполнен успешно.'
signed_out: 'Выход выполнен успешно.'
passwords:
admin:
send_instructions: 'Вы получите письмо с инструкциями о том, как сбросить ваш пароль, через несколько минут.'
updated: 'Ваш пароль был успешно изменен. Вы вошли в систему.'
confirmations:
admin:
send_instructions: 'Вы получите письмо с инструкциями о том, как подтвердить ваш аккаунт, через несколько минут.'
confirmed: 'Ваша учетная запись была успешно подтверждена. Вы вошли в систему.'
registrations:
admin:
signed_up: 'Вы успешно зарегистрировались.'
updated: 'Вы успешно обновили ваш аккаунт.'
destroyed: 'До свидания! Ваш аккаунт был успешно отменен. Мы надеемся скоро увидеть вас снова.'
unlocks:
admin:
send_instructions: 'Вам будет отправлено письмо с инструкциями о том, как разблокировать ваш аккаунт, в течение нескольких минут.'
unlocked: 'Ваша учетная запись была успешно разблокирована. Вы вошли в систему.'
mailer:
admin:
confirmation_instructions: 'Инструкции подтверждения'
reset_password_instructions: 'Инструкции по сбросу пароля'
unlock_instructions: 'Инструкции по разблокированию'
admin:
mailer:
common:
hello: Здравствуйте
confirmation_instructions:
you_can_confirm_your_account_through_the_link_below: "Вы можете подтвердить ваш аккаунт с помощью ссылки, расположенной ниже:"
confirm_my_account: "Подтвердить мой аккаунт"
reset_password_instructions:
reset_password_instruction: "Кто-то запросил ссылку для изменения вашего пароля, и вы можете сделать это через ссылку, приведенную ниже:"
change_my_password: "Изменить мой пароль"
wrong_request_instruction: "Если вы не запрашивали это, пожалуйста проигнорируйте это письмо."
unchange_password_message: "Ваш пароль не будет изменен до тех пор, пока вы не получите доступ к ссылке, приведенной выше, и создатите новую."
unlock_instructions:
locked_account_message: "Ваша учетная запись была заблокирована из-за чрезмерного количества безуспешных попыток входа."
unlock_account_instruction: "Нажмите ссылку ниже, чтобы разблокировать ваш аккаунт:"
unlock_my_account: "Разблокировать мой аккаунт"

106
config/locales/flash.ru.yml Normal file
View File

@ -0,0 +1,106 @@
ru:
flash:
admin:
pages:
create:
notice: "Страница успешно создана."
alert: "Страница не создана."
update:
notice: "Страница успешно обновлена."
alert: "Страница не обновлена."
sort:
notice: "Страницы успешно отсортированы."
destroy:
notice: "Страницы успешно удалены."
contents:
create:
notice: "Контент успешно создан."
alert: "Контент не создан."
update:
notice: "Контент успешно обновлен."
alert: "Контент не обновлен."
sort:
notice: "Содержимое успешно отсортировано."
destroy:
notice: "Содержимое успешно удалено."
content_types:
create:
notice: "Модель успешно создана."
alert: "Модель не создана."
update:
notice: "Модель успешно обновлена."
alert: "Модель не обновлена."
destroy:
notice: "Модель успешно удалена."
current_site:
update:
notice: "Мой сайт успешно обновлен."
alert: "Мой сайт не обновлен."
snippets:
create:
notice: "Сниппет успешно создан."
alert: "Сниппет не создан."
update:
notice: "Сниппет успешно обновлен."
alert: "Сниппет не обновлен."
destroy:
notice: "Сниппет успешно удален."
accounts:
create:
notice: "Аккаунт успешно создан."
alert: "Аккаунт не создан."
my_account:
update:
notice: "Мой аккаунт успешно обновлен."
alert: "Мой аккаунт не обновлен."
sites:
create:
notice: "Сайт успешно создан."
alert: "Сайт не создан."
destroy:
notice: "Сайт успешно удален."
memberships:
create:
notice: "Учетная запись успешно создана."
alert: "Учетная запись не создана."
already_created: "Учетная запись уже добавлена в текущий сайт."
assets:
create:
notice: "Файл успешно создан."
alert: "Файл не создан."
update:
notice: "Файл успешно обновлен."
alert: "Файл не обновлен."
theme_assets:
create:
notice: "Файл успешно создан."
alert: "Файл не создан."
update:
notice: "Файл успешно обновлен."
alert: "Файл не обновлен."
destroy:
notice: "Файл успешно удален."
custom_fields:
update:
alert: "Поле не обновлено"
cross_domain_sessions:
create:
alert: "Вам необходимо войти"
import:
create:
done: "Ваш сайт успешно обновлен"
notice: "Ваш сайт обновляется"
alert: "Импорт не завершен."

View File

@ -0,0 +1,99 @@
ru:
formtastic:
titles:
information: Основная информация
advanced_options: Дополнительные настройки
meta: SEO Metadata
seo: SEO настройки
robots_txt: Robots.txt файл
code: Код
raw_template: Шаблон
credentials: Учетная запись
language: Язык
sites: Сайты
access_points: Точки доступа
memberships: Учетные записи
membership_email: Email аккаунта
file: Файл
preview: Предпросмотр
options: Дополнительные настройки
custom_fields: Пользовательские поля
other_fields: Другая информация
presentation: Представление
attributes: Аттрибуты
upload: Загрузить
labels:
theme_asset:
plain_text_name: Имя файла
content_type: Тип файла
new:
source: Файл
edit:
source: Заменить файл
custom_fields:
field:
_alias: Алиас
import:
new:
source: Файл
samples: Копировать образцы
reset: Сбросить сайт
default_site_template: "Используйте шаблон сайта по умолчанию. Нажмите <a href='#'>здесь</a> для загрузки шаблона сайта в виде zip файла."
content_type:
item_template: Шаблон элемента
api_accounts: Уведомленные аккаунты
content_instance:
_slug: Постоянная ссылка
account:
edit:
password: Новый пароль
password_confirmation: Подтверждение нового пароля
page:
seo_title: Название
hints:
page:
published: "Только аутентифицированным пользователям разрешается просматривать неопубликованные страницы."
cache_strategy: "Кэшировать страницу для лучшей производительности. Вариант 'Простое' является хорошим компромиссом."
templatized: "Используйте страницу в качестве шаблона для определенной вами модели."
listed: "Контролируйте возможность показа страницы из сгенерированных меню."
content_type_id: "Тип содержимого, для которого эта страница будет выступать в качестве шаблона."
seo_title: "Определите заголовок страницы, который будет использоваться как значение тэга title в секции head. Оставьте пустым, если вы хотите использовать значение по умолчанию из настроек сайта."
meta_keywords: "Переопределяет meta keywords сайта, используемые внутри тэга head страницы. Они разделены запятыми."
meta_description: "Переопределяет meta description сайта, используемые внутри тэга head страницы."
snippet:
slug: "Вам необходимо знать это для вставки сниппета в страницу"
site:
seo_title: "Задайте глобальное значение здесь, которое будет использовано как значение для тэга title в секции head."
meta_keywords: "Meta keywords используются внутри тэга head страницы. Они разделяются запятыми. Требуется для SEO."
meta_description: "Meta description используются для тэга head страницы. Необходимо для SEO."
domain_name: "ex: locomotiveapp.org"
robots_txt: "Содержимое файла <span class='code'>/robots.txt</span>. См. <a href='http://www.w3.org/TR/html4/appendix/notes.html#h-B.4.1.1'>url</a> для получения большей информации."
theme_asset:
slug: "Ва не нужно добавлять расширение файла (.css or .js)"
edit:
source: "Вы можете заменить это файлом, имеющим такое же расширение"
asset:
source: "Все типы файлов приняты."
edit:
source: "Текущий файл доступен здесь %{url}"
update:
source: "Текущий файл доступен здесь %{url}"
custom_fields:
field:
_alias: "Свойство, доступное в шаблонах liquid"
hint: "Текст, отображенный в форме модели, находится ниже поля"
content_instance:
_slug: "Свойство, используемое для генерации ссылки (url) на страницу, работающей как шаблон для этого типа содержимого (ex: \"template_page/{{ your_object._permalink }})\"."
seo_title: "Значение, вводимое вами, будет заменять SEO заголовок шаблонизированной страницы, связанной с вашей моделью."
meta_keywords: "Переопределяет meta keywords сайта, используемые внутри тэга head страницы. Разделяются запятыми."
meta_description: "Переопределяет meta description сайта, используемые внутри тэга head страницы."
import:
source: "Файл zip, содержащий database.yml вместе с файлами и шаблонами"
samples: "Если включено, процесс импорта также скопирует содержимое и файлы"
reset: "Если включено, все данные вашего сайта будут уничтожены перед импортом нового сайта"
content_type:
item_template: "Вы можете задавать текст, отображаемый для каждого элемента в списке. Просто используйте Liquid. Пр.: {{ content.name }})"
api_enabled: "Это используется для того, чтобы дать людям извне возможность создавать новые экземляры (пример: сообщения в форме контакта)"
api_accounts: "Письмо с уведомлением будет отправлено на каждый аккаунт из списка выше, когда создан новый экземпляр"

View File

@ -65,6 +65,6 @@ Rails.application.routes.draw do
# magic urls # magic urls
match '/' => 'admin/rendering#show' match '/' => 'admin/rendering#show'
match '*path/edit' => 'admin/rendering#show', :defaults => { :editing => true } match '*path/edit' => 'admin/rendering#edit'
match '*path' => 'admin/rendering#show' match '*path' => 'admin/rendering#show'
end end

View File

@ -1,9 +0,0 @@
account = Account.create! :name => 'Admin', :email => 'admin@example.com', :password => 'locomotive', :password_confirmation => 'locomotive'
site = Site.new :name => 'Locomotive test website', :subdomain => 'test'
site.memberships.build :account => account, :admin => true
site.save!
puts "Your first website has been created !"
puts "Admin url: http://test.example.com:3000/admin"
puts "Crendetials: admin@example.com / locomotive"

View File

@ -70,7 +70,6 @@ BUGS:
NICE TO HAVE: NICE TO HAVE:
- export site - export site
- super_finder - super_finder
- traffic statistics - traffic statistics
- asset picker (content instance) - asset picker (content instance)

View File

@ -6,4 +6,8 @@
- Adding indexes for pages to avoid "Mongo::OperationFailure: too much data" errors (#159) - Adding indexes for pages to avoid "Mongo::OperationFailure: too much data" errors (#159)
- better spanish translations (#161, #162) - better spanish translations (#161, #162)
- fix carrierwave version to 0.5.6 (#163) - fix carrierwave version to 0.5.6 (#163)
- has_many target is not exported correctly (issue #165) + fix the import module as well - has_many target is not exported correctly (issue #165) + fix the import module as well
- XSS vulnerability when adding new content from the api_contents_controller (#170)
- small bugs: #169, #171, #179
- russian version (#188)
-

View File

@ -0,0 +1,28 @@
Feature: Account Settings
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
And I have a designer and an author
Scenario: As an unauthenticated user
Given I am not authenticated
When I go to account settings
Then I should see "Log in"
Scenario: Accessing site settings as an Admin
Given I am an authenticated "admin"
When I go to account settings
Then I should see "new site"
Scenario: Accessing site settings as a Designer
Given I am an authenticated "designer"
When I go to account settings
Then I should not see "new site"
Scenario: Accessing site settings as an Author
Given I am an authenticated "author"
When I go to account settings
Then I should not see "new site"

View File

@ -30,7 +30,7 @@ Background:
Given I am an authenticated "designer" Given I am an authenticated "designer"
When I go to site settings When I go to site settings
Then I should see "import" Then I should see "import"
And I should see "add account" And I should not see "add account"
And I should see "SEO settings" And I should see "SEO settings"
And I should see "Access points" And I should see "Access points"
And I should not see the role dropdown on myself And I should not see the role dropdown on myself

View File

@ -0,0 +1,48 @@
@javascript
Feature: Inline frontend editing
In order to ensure site content is 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
Given a page named "about" with the template:
"""
<html>
<head>{% inline_editor %}</head>
<body>Page Content</body>
</html>
"""
Scenario: As an unauthenticated user
Given I am not authenticated
When I view the rendered page at "/about"
Then I should not see "edit"
When I view the rendered page at "/about/edit"
Then I should not see "Page Content"
And I should see "Log in"
Scenario: Inline editing as an Admin
Given I am an authenticated "admin"
When I view the rendered page at "/about"
Then I should see "admin"
And I should see "edit"
When I view the rendered page at "/about/edit"
Then I should see "Page Content"
Scenario: Inline editing as a Designer
Given I am an authenticated "designer"
When I view the rendered page at "/about"
Then I should see "admin"
And I should see "edit"
When I view the rendered page at "/about/edit"
Then I should see "Page Content"
Scenario: Inline editing as an Author
Given I am an authenticated "author"
When I view the rendered page at "/about"
Then I should see "admin"
And I should see "edit"
When I view the rendered page at "/about/edit"
Then I should see "Page Content"

View File

@ -6,6 +6,7 @@ Feature: Theme Assets
Background: Background:
Given I have the site: "test site" set up Given I have the site: "test site" set up
And I have a designer and an author And I have a designer and an author
And I have an image theme asset named "dog.png"
Scenario: As an unauthenticated user Scenario: As an unauthenticated user
Given I am not authenticated Given I am not authenticated
@ -20,6 +21,8 @@ Background:
And I should see "Snippets" And I should see "Snippets"
And I should see "Style and javascript" And I should see "Style and javascript"
And I should see "Images" And I should see "Images"
And I should see "dog.png"
And I should see a delete image button
Scenario: Accessing theme assets as a Designer Scenario: Accessing theme assets as a Designer
Given I am an authenticated "designer" Given I am an authenticated "designer"
@ -29,6 +32,8 @@ Background:
And I should see "Snippets" And I should see "Snippets"
And I should see "Style and javascript" And I should see "Style and javascript"
And I should see "Images" And I should see "Images"
And I should see "dog.png"
And I should see a delete image button
Scenario: Accessing theme assets as an Author Scenario: Accessing theme assets as an Author
Given I am an authenticated "author" Given I am an authenticated "author"
@ -38,3 +43,5 @@ Background:
And I should not see "Snippets" And I should not see "Snippets"
And I should not see "Style and javascript" And I should not see "Style and javascript"
And I should see "Images" And I should see "Images"
And I should see "dog.png"
And I should not see a delete image button

View File

@ -6,16 +6,28 @@ Feature: Login
Background: Background:
Given I have the site: "test site" set up Given I have the site: "test site" set up
Scenario: Successful authentication Scenario: Successfully logging in
When I go to login When I go to login
And I fill in "Email" with "admin@locomotiveapp.org" And I fill in "Email" with "admin@locomotiveapp.org"
And I fill in "Password" with "easyone" And I fill in "Password" with "easyone"
And I press "Log in" And I press "Log in"
Then I should see "Listing pages" Then I should see "Listing pages"
Scenario: Failed authentication Scenario: Attempting to login with an invalid emai or password
When I go to login When I go to login
And I fill in "Email" with "admin@locomotiveapp.org" And I fill in "Email" with "admin@locomotiveapp.org"
And I fill in "Password" with "" And I fill in "Password" with ""
And I press "Log in" And I press "Log in"
Then I should not see "Listing pages" Then I should not see "Listing pages"
And I should see "Invalid email or password"
Scenario: Attempting to login with an account without a membership
Given the following accounts exist:
| email | password | password_confirmation |
| john@locomotiveapp.org | bluecheese | bluecheese |
When I go to login
And I fill in "Email" with "john@locomotiveapp.org"
And I fill in "Password" with "bluecheese"
And I press "Log in"
Then I should not see "Listing pages"
And I should see "not a member of this site"

View File

@ -16,21 +16,3 @@ Scenario: Simple Page
""" """
Hello World Hello World
""" """
# @wip
# Scenario: Simple Page with Admin Inline Editing
# Given a simple page named "hello-world-inline" with the body:
# """
# {% block hello %}Hello World{% endblock %}
# """
# When And I'm an admin
# And I view the rendered page at "/hello-world-inline"
# Then the rendered output shoud look like:
# """
# <div class="inline-editing" data-url="/admin/parts/XXXX" data-title="hello">Hello World</div>
# """
#
# {% block main %}Didier{% endblock %}
#
# {% block body %}{% block main %}{{ block.super }}Jacques{% endblock %}{% endblock %}
# {% block body %}Hello mister Jacques{% endblock %}

View File

@ -0,0 +1,25 @@
@javascript
Feature: Engine
As an author
In order to easily be able to modify the contents of my website
I want to be able to edit the sites content on the front end
Background:
Given I have the site: "test site" set up
And I am an authenticated "author"
Scenario: Editing a short text field
Given a page named "about" with the template:
"""
<html>
<head>{% inline_editor %}</head>
<body>{% editable_short_text 'owner' %}Tom{% endeditable_short_text %} owns this website</body>
</html>
"""
When I view the rendered page at "/about"
Then I should see "edit"
When I follow "edit"
And I type the content "Mario" into the first editable field
And I follow "save"
And I view the rendered page at "/about"
Then I should see "Mario owns this website"

View File

@ -0,0 +1,42 @@
Feature: TableRow liquid tags
As a designer
I want to be able to use the tablerow liquid tag with locomotive contents
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required |
| Name | string | true |
And I have entries for "Projects" with
| name |
| Project 1 |
| Project 2 |
| Project 3 |
Scenario: Use the tablerow tag
Given a page named "project-table" with the template:
"""
<h1>Projects</h1>
<table>
{% tablerow project in contents.projects cols: 2 %}
{{ project.name }}
{% endtablerow %}
</table>
"""
When I view the rendered page at "/project-table"
Then the rendered output should look like:
"""
<h1>Projects</h1>
<table>
<tr class="row1">
<td class="col1">
Project 1
</td><td class="col2">
Project 2
</td></tr>
<tr class="row2"><td class="col1">
Project 3
</td></tr>
</table>
"""

View File

@ -5,7 +5,7 @@ Given /^I am not authenticated$/ do
end end
Given /^I am an authenticated "([^"]*)"$/ do |role| Given /^I am an authenticated "([^"]*)"$/ do |role|
@member = Site.first.memberships.where(:role => role.downcase).first || Factory(role.downcase.to_sym, :site => Site.first) @member = Site.first.memberships.where(:role => role.downcase).first || FactoryGirl.create(role.downcase.to_sym, :site => Site.first)
Given %{I go to login} Given %{I go to login}
And %{I fill in "Email" with "#{@member.account.email}"} And %{I fill in "Email" with "#{@member.account.email}"}

View File

@ -1,6 +1,6 @@
Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields| Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
site = Site.first site = Site.first
content_type = Factory.build(:content_type, :site => site, :name => name) content_type = FactoryGirl.build(:content_type, :site => site, :name => name)
fields.hashes.each do |field| fields.hashes.each do |field|
if (target_name = field.delete('target')).present? if (target_name = field.delete('target')).present?
target_content_type = site.content_types.where(:name => target_name).first target_content_type = site.content_types.where(:name => target_name).first

View File

@ -1,7 +1,3 @@
Given /^a simple page named "([^"]*)" with the body:$/ do |page_slug, page_contents|
@page = create_content_page(page_slug, page_contents)
end
# modify an editable element # modify an editable element
Given /^the editable element "([^"]*)" in the "([^"]*)" page with the content "([^"]*)"$/ do |slug, page_slug, content| Given /^the editable element "([^"]*)" in the "([^"]*)" page with the content "([^"]*)"$/ do |slug, page_slug, content|
page = @site.pages.where(:slug => page_slug).first page = @site.pages.where(:slug => page_slug).first
@ -14,4 +10,15 @@ Given /^the editable element "([^"]*)" for the "([^"]*)" block in the "([^"]*)"
page = @site.pages.where(:slug => page_slug).first page = @site.pages.where(:slug => page_slug).first
page.find_editable_element(block, slug).content = content page.find_editable_element(block, slug).content = content
page.save! page.save!
end end
When /^I type the content "([^"]*)" into the first editable field$/ do |content|
page.execute_script %{
$(document).ready(function() {
editable = GENTICS.Aloha.editables[0];
editable.obj.text('#{content}');
editable.blur();
});
}
end

View File

@ -2,7 +2,7 @@
# 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 || Factory(:page) @home = @site.pages.where(:slug => "index").first || FactoryGirl.create(:page)
page = @site.pages.create(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :raw_template => 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 page
@ -26,7 +26,12 @@ end
# try to render a page by slug # try to render a page by slug
When /^I view the rendered page at "([^"]*)"$/ do |path| When /^I view the rendered page at "([^"]*)"$/ do |path|
visit "http://#{@site.domains.first}#{path}" # If we're running selenium then we need to use a differnt port
if Capybara.current_driver == :selenium
visit "http://#{@site.domains.first}:#{Capybara.server_port}#{path}"
else
visit "http://#{@site.domains.first}#{path}"
end
end end
# checks to see if a string is in the slug # checks to see if a string is in the slug

View File

@ -5,7 +5,7 @@
# - I have the site: "some site" set up with name: "Something", domain: "test2" # - I have the site: "some site" set up with name: "Something", domain: "test2"
# #
Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site_factory, fields| Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site_factory, fields|
@site = Factory(site_factory, parse_fields(fields)) @site = FactoryGirl.create(site_factory, parse_fields(fields))
@site.should_not be_nil @site.should_not be_nil
@admin = @site.memberships.first.account @admin = @site.memberships.first.account
@ -13,8 +13,8 @@ Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site
end end
Given /^I have a designer and an author$/ do Given /^I have a designer and an author$/ do
Factory(:designer, :site => Site.first) FactoryGirl.create(:designer, :site => Site.first)
Factory(:author, :site => Site.first) FactoryGirl.create(:author, :site => Site.first)
end end
Then /^I should be a administrator of the "([^"]*)" site$/ do |name| Then /^I should be a administrator of the "([^"]*)" site$/ do |name|

View File

@ -2,7 +2,7 @@
# helps create a theme asset # helps create a theme asset
def create_plain_text_asset(name, type) def create_plain_text_asset(name, type)
asset = Factory.build(:theme_asset, { 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',
@ -24,8 +24,23 @@ Given /^a stylesheet asset named "([^"]*)"$/ do |name|
@asset = create_plain_text_asset(name, 'stylesheet') @asset = create_plain_text_asset(name, 'stylesheet')
end end
Given /^I have an image theme asset named "([^"]*)"$/ do |name|
@asset = FactoryGirl.create(:theme_asset, :site => @site, :source => File.open(Rails.root.join('spec', 'fixtures', 'assets', '5k.png')))
@asset.source_filename = name
@asset.save!
end
# other stuff # other stuff
Then /^I should see "([^"]*)" as theme asset code$/ do |code| Then /^I should see "([^"]*)" as theme asset code$/ do |code|
find(:css, "#theme_asset_plain_text").text.should == code find(:css, "#theme_asset_plain_text").text.should == code
end end
Then /^I should see a delete image button$/ do
page.has_css?("ul.theme-assets li .more a.remove").should be_true
end
Then /^I should not see a delete image button$/ do
page.has_css?("ul.theme-assets li .more a.remove").should be_false
end

View File

@ -21,7 +21,7 @@ module Locomotive
:media => [/^video/, 'application/x-shockwave-flash', 'application/x-swf', /^audio/, 'application/ogg', 'application/x-mp3'], :media => [/^video/, 'application/x-shockwave-flash', 'application/x-swf', /^audio/, 'application/ogg', 'application/x-mp3'],
:pdf => ['application/pdf', 'application/x-pdf'], :pdf => ['application/pdf', 'application/x-pdf'],
:stylesheet => ['text/css'], :stylesheet => ['text/css'],
:javascript => ['text/javascript', 'text/js', 'application/x-javascript', 'application/javascript'], :javascript => ['text/javascript', 'text/js', 'application/x-javascript', 'application/javascript', 'text/x-component'],
:font => ['application/x-font-ttf', 'application/vnd.ms-fontobject', 'image/svg+xml', 'application/x-woff'] :font => ['application/x-font-ttf', 'application/vnd.ms-fontobject', 'image/svg+xml', 'application/x-woff']
} }
end end

View File

@ -7,8 +7,8 @@ module Locomotive
:reserved_subdomains => %w{www admin email blog webmail mail support help site sites}, :reserved_subdomains => %w{www admin email blog webmail mail support help site sites},
# :forbidden_paths => %w{layouts snippets stylesheets javascripts assets admin system api}, # :forbidden_paths => %w{layouts snippets stylesheets javascripts assets admin system api},
:reserved_slugs => %w{stylesheets javascripts assets admin images api pages edit}, :reserved_slugs => %w{stylesheets javascripts assets admin images api pages edit},
:locales => %w{en de fr pt-BR it nl es}, :locales => %w{en de fr pt-BR it nl es ru},
:site_locales => %w{en de fr pt-BR it nl es}, :site_locales => %w{en de fr pt-BR it nl es ru},
:cookie_key => '_locomotive_session', :cookie_key => '_locomotive_session',
:enable_logs => false, :enable_logs => false,
:hosting => :auto, :hosting => :auto,
@ -24,7 +24,7 @@ module Locomotive
:entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body") :entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
}, },
:devise_modules => [:database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :encryptable, { :encryptor => :sha1 }], :devise_modules => [:database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :encryptable, { :encryptor => :sha1 }],
:context_assign_extensions => { } :context_assign_extensions => {}
} }
cattr_accessor :settings cattr_accessor :settings

View File

@ -26,6 +26,7 @@ require 'dragonfly'
require 'cancan' require 'cancan'
require 'RMagick' require 'RMagick'
require 'cells' require 'cells'
require 'sanitize'
$:.unshift File.dirname(__FILE__) $:.unshift File.dirname(__FILE__)

View File

@ -29,10 +29,16 @@ module Locomotive
self.collection.each(&block) self.collection.each(&block)
end end
def each_with_index(&block)
self.collection.each_with_index(&block)
end
def size def size
self.collection.size self.collection.size
end end
alias :length :size
def empty? def empty?
self.collection.empty? self.collection.empty?
end end

View File

@ -64,6 +64,7 @@ module Locomotive
# example: 'about/myphoto.jpg' | theme_image # <img src="images/about/myphoto.jpg" /> # example: 'about/myphoto.jpg' | theme_image # <img src="images/about/myphoto.jpg" />
def theme_image_tag(input, *args) def theme_image_tag(input, *args)
image_options = inline_options(args_to_options(args)) image_options = inline_options(args_to_options(args))
"<img src=\"#{theme_image_url(input)}\" #{image_options}/>" "<img src=\"#{theme_image_url(input)}\" #{image_options}/>"
end end
@ -71,6 +72,7 @@ module Locomotive
# input: url of the image OR asset drop # input: url of the image OR asset drop
def image_tag(input, *args) def image_tag(input, *args)
image_options = inline_options(args_to_options(args)) image_options = inline_options(args_to_options(args))
"<img src=\"#{get_url_from_asset(input)}\" #{image_options}/>" "<img src=\"#{get_url_from_asset(input)}\" #{image_options}/>"
end end

View File

@ -23,15 +23,16 @@ module Locomotive
if @context[:page].present? if @context[:page].present?
@context[:page].add_or_update_editable_element({ @context[:page].add_or_update_editable_element({
:block => @context[:current_block].try(:name), :block => @context[:current_block].try(:name),
:slug => @slug, :slug => @slug,
:hint => @options[:hint], :hint => @options[:hint],
:default_attribute => @options[:default], :priority => @options[:priority] || 0,
:default_content => default_content_option, :default_attribute => @options[:default],
:assignable => @options[:assignable], :default_content => default_content_option,
:disabled => false, :assignable => @options[:assignable],
:from_parent => false, :disabled => false,
:_type => self.document_type.to_s :from_parent => false,
:_type => self.document_type.to_s
}, document_type) }, document_type)
end end
end end

View File

@ -114,7 +114,7 @@ module Locomotive
end end
end end
render :text => output, :layout => false, :status => page_status render :text => output, :layout => false, :status => page_status unless performed?
end end
def not_found_page def not_found_page
@ -122,7 +122,7 @@ module Locomotive
end end
def editing_page? def editing_page?
self.params[:editing] == true && current_admin @editing
end end
def page_status def page_status

View File

@ -17,7 +17,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = '>= 1.3.6' s.required_rubygems_version = '>= 1.3.6'
s.rubyforge_project = 'nowarning' s.rubyforge_project = 'nowarning'
s.add_dependency 'rails', '>= 3.0.9' s.add_dependency 'rails', '>= 3.0.10'
s.add_dependency 'warden' s.add_dependency 'warden'
s.add_dependency 'devise', '1.3.4' s.add_dependency 'devise', '1.3.4'
s.add_dependency 'devise_bushido_authenticatable', '1.0.0.alpha10' s.add_dependency 'devise_bushido_authenticatable', '1.0.0.alpha10'
@ -33,6 +33,8 @@ Gem::Specification.new do |s|
s.add_dependency 'formtastic', '~> 1.2.3' s.add_dependency 'formtastic', '~> 1.2.3'
s.add_dependency 'inherited_resources', '~> 1.1.2' s.add_dependency 'inherited_resources', '~> 1.1.2'
s.add_dependency 'cells' s.add_dependency 'cells'
s.add_dependency 'highline'
s.add_dependency 'sanitize'
s.add_dependency 'json_pure', '1.5.1' s.add_dependency 'json_pure', '1.5.1'
s.add_dependency 'bushido' s.add_dependency 'bushido'
@ -43,13 +45,13 @@ Gem::Specification.new do |s|
s.add_dependency 'dragonfly', '~> 0.9.1' s.add_dependency 'dragonfly', '~> 0.9.1'
s.add_dependency 'rack-cache' s.add_dependency 'rack-cache'
s.add_dependency 'custom_fields', '1.0.0.beta.22' s.add_dependency 'custom_fields', '1.0.0.beta.25'
s.add_dependency 'cancan', '~> 1.6.0' s.add_dependency 'cancan', '~> 1.6.0'
s.add_dependency 'fog', '0.8.2' s.add_dependency 'fog', '0.8.2'
s.add_dependency 'mimetype-fu' s.add_dependency 'mimetype-fu'
s.add_dependency 'actionmailer-with-request' s.add_dependency 'actionmailer-with-request'
s.add_dependency 'httparty', '>= 0.6.1' s.add_dependency 'httparty', '>= 0.6.1'
s.add_dependency 'RedCloth', '4.2.7' s.add_dependency 'RedCloth', '4.2.8'
s.add_dependency 'delayed_job', '2.1.4' s.add_dependency 'delayed_job', '2.1.4'
s.add_dependency 'delayed_job_mongoid', '1.0.2' s.add_dependency 'delayed_job_mongoid', '1.0.2'
s.add_dependency 'rubyzip' s.add_dependency 'rubyzip'

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

View File

@ -11,10 +11,10 @@ $(document).ready(function() {
if (context.data.new_item) { if (context.data.new_item) {
var newItemInfo = context.data.new_item; var newItemInfo = context.data.new_item;
var option = new Option(newItemInfo.label, newItemInfo.url, true, true); var option = makeOption(newItemInfo.label, newItemInfo.url, true, true);
context.select.append(option); context.select.append(option);
context.select.append(new Option('-'.repeat(newItemInfo.label.length), '', false, false)); context.select.append(makeOption('-'.repeat(newItemInfo.label.length), '', false, false));
} }
for (var i = 0; i < context.data.collection.length; i++) { for (var i = 0; i < context.data.collection.length; i++) {
@ -27,7 +27,7 @@ $(document).ready(function() {
for (var j = 0; j < obj.items.length; j++) { for (var j = 0; j < obj.items.length; j++) {
var innerObj = obj.items[j]; var innerObj = obj.items[j];
if ($.inArray(innerObj[1], context.data.taken_ids) == -1) { if ($.inArray(innerObj[1], context.data.taken_ids) == -1) {
optgroup.append(new Option(innerObj[0], innerObj[1], false, false)); optgroup.append(makeOption(innerObj[0], innerObj[1], false, false));
size++; size++;
} }
} }
@ -36,8 +36,7 @@ $(document).ready(function() {
} else { } else {
if ($.inArray(obj[1], context.data.taken_ids) == -1) if ($.inArray(obj[1], context.data.taken_ids) == -1)
{ {
var option = new Option("", obj[1], false, false); var option = makeOption(obj[0], obj[1], false, false);
$(option).text(obj[0]);
context.select.append(option); context.select.append(option);
} }
} }

View File

@ -121,7 +121,6 @@ var InlineEditorToolbar = {
_bindEvents: function() { _bindEvents: function() {
var self = this; var self = this;
var fullpath = $('meta[name=page-fullpath]').attr('content');
this.form.live('submit', function (e) { $(this).callRemote(); e.stopPropagation(); e.preventDefault(); this.form.live('submit', function (e) { $(this).callRemote(); e.stopPropagation(); e.preventDefault();
}).bind('ajax:complete', function() { self.resetForm(); }).bind('ajax:complete', function() { self.resetForm();
@ -146,7 +145,8 @@ var InlineEditorToolbar = {
window.location.href = window.location.href; break; window.location.href = window.location.href; break;
case 'back': // back to the non edition mode case 'back': // back to the non edition mode
window.location.href = fullpath; break; var url = window.location.href.replace(/\/edit$/, '');
window.location.href = url; break;
case 'drawer': // expand / shrink toolbar case 'drawer': // expand / shrink toolbar
self.toggle(); break; self.toggle(); break;

View File

@ -61,8 +61,6 @@ $.fn.imagepicker = function(options) {
asset.removeClass('new-asset'); asset.removeClass('new-asset');
$('.asset-picker p.no-items').hide(); $('.asset-picker p.no-items').hide();
$('.asset-picker ul').scrollTo($('li.asset:last'), 400);
} }
}); });

View File

@ -20,7 +20,7 @@ p.no-items {
ul.assets { ul.assets {
overflow: auto; overflow: auto;
height: 571px; height: 275px;
} }
ul.assets li.asset h4 a { ul.assets li.asset h4 a {

View File

@ -15,7 +15,6 @@
<script src="/javascripts/admin/plugins/plupload/plupload.html5.min.js" type="text/javascript"></script> <script src="/javascripts/admin/plugins/plupload/plupload.html5.min.js" type="text/javascript"></script>
<script src="/javascripts/admin/plugins/plupload/jquery.plupload.queue.min.js" type="text/javascript"></script> <script src="/javascripts/admin/plugins/plupload/jquery.plupload.queue.min.js" type="text/javascript"></script>
<script src="/javascripts/admin/plugins/plupload/jquery.plupload.queue.min.js" type="text/javascript"></script> <script src="/javascripts/admin/plugins/plupload/jquery.plupload.queue.min.js" type="text/javascript"></script>
<script src="/javascripts/admin/plugins/scrollTo.js" type="text/javascript"></script>
<script type="text/javascript" src="js/dialog.js"></script> <script type="text/javascript" src="js/dialog.js"></script>

View File

@ -174,8 +174,6 @@ var MediafileDialog = {
asset.removeClass('new-asset'); asset.removeClass('new-asset');
$('p.no-items').hide(); $('p.no-items').hide();
$('ul').scrollTo($('li.asset:last'), 400);
}, },
_destroyAsset: function(asset) { _destroyAsset: function(asset) {

View File

@ -51,4 +51,11 @@ Object.size = function(obj) {
if (obj.hasOwnProperty(key)) size++; if (obj.hasOwnProperty(key)) size++;
} }
return size; return size;
}; };
// Make a DOM option for a select box. This code works around a bug in IE
function makeOption(text, value, defaultSelected, selected) {
var option = new Option('', value, defaultSelected, selected);
$(option).text(text);
return option;
}

View File

@ -4,7 +4,7 @@ describe Admin::GlobalActionsCell do
render_views render_views
let(:menu) { render_cell('admin/global_actions', :show, :current_admin => Factory.build('admin user'), :current_site_url => 'http://www.yahoo.fr') } let(:menu) { render_cell('admin/global_actions', :show, :current_admin => FactoryGirl.build('admin user'), :current_site_url => 'http://www.yahoo.fr') }
describe 'show menu' do describe 'show menu' do

View File

@ -0,0 +1,91 @@
require 'spec_helper'
describe Admin::ApiContentsController do
before(:each) do
@site = FactoryGirl.create('existing site')
@site.content_types.first.tap do |content_type|
content_type.content_custom_fields.build :label => 'Name', :kind => 'string', :required => true
content_type.content_custom_fields.build :label => 'Description', :kind => 'text'
content_type.content_custom_fields.build :label => 'File', :kind => 'file'
content_type.content_custom_fields.build :label => 'Active', :kind => 'boolean'
end.save
controller.stubs(:require_site).returns(true)
controller.stubs(:current_site).returns(@site)
end
describe 'API disabled' do
it 'blocks the creation of a new instance' do
post 'create', default_post_params
response.code.should eq('403')
response.body.should == 'Api not enabled'
end
end
describe 'API enabled' do
before(:each) do
ContentType.any_instance.stubs(:api_enabled?).returns(true)
end
it 'saves a content' do
post 'create', default_post_params
response.should redirect_to('http://www.locomotivecms.com/success')
@site.reload.content_types.first.contents.size.should == 1
end
it 'does not save a content if required parameters are missing' do
post 'create', default_post_params(:content => { :name => '' })
response.should redirect_to('http://www.locomotivecms.com/failure')
@site.reload.content_types.first.contents.size.should == 0
end
describe 'XSS vulnerability' do
it 'sanitizes the params (simple example)' do
post 'create', default_post_params(:content => { :name => %(Hacking <script type="text/javascript">alert("You have been hacked")</script>) })
content = @site.reload.content_types.first.contents.first
content.name.should == "Hacking alert(\"You have been hacked\")"
end
it 'sanitizes the params (more complex example)' do
post 'create', default_post_params(:content => { :name => %(<img src=javascript:alert('Hello')><table background="javascript:alert('Hello')">Hacked) })
content = @site.reload.content_types.first.contents.first
content.name.should == "Hacked"
end
it 'does not sanitize non string params' do
lambda {
post 'create', default_post_params(:content => {
:active => true,
:file => ActionDispatch::Http::UploadedFile.new(:tempfile => FixturedAsset.open('5k.png'), :filename => '5k.png', :content_type => 'image/png')
})
}.should_not raise_exception
end
end
end
def default_post_params(options = {})
{
:slug => 'projects',
:content => { :name => 'LocomotiveCMS', :description => 'Lorem ipsum' }.merge(options.delete(:content) || {}),
:success_callback => 'http://www.locomotivecms.com/success',
:error_callback => 'http://www.locomotivecms.com/failure'
}.merge(options)
end
end

View File

@ -1,136 +1,141 @@
## Site ## FactoryGirl.define do
Factory.define :site do |s|
s.name 'Acme Website' ## Site ##
s.subdomain 'acme' factory :site do
s.created_at Time.now name 'Acme Website'
end subdomain 'acme'
created_at Time.now
factory "test site" do
name 'Locomotive test website'
subdomain 'test'
after_build do |site_test|
site_test.memberships.build :account => Account.where(:name => "Admin").first || Factory("admin user"), :role => 'admin'
end
factory "another site" do
name "Locomotive test website #2"
subdomain "test2"
end
end
factory "existing site" do
name "Locomotive site with existing models"
subdomain "models"
after_build do |site_with_models|
site_with_models.content_types.build(
:slug => 'projects',
:name => 'Existing name',
:description => 'Existing description',
:order_by => 'created_at')
end
end
factory "valid site" do
# after_build { |valid_site| valid_site.stubs(:valid?).returns(true) }
end
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"), :role => 'admin'
end end
end
Factory.define "another site", :parent => "test site" do |s| # Accounts ##
s.name "Locomotive test website #2" factory :account do
s.subdomain "test2" name 'Bart Simpson'
end email 'bart@simpson.net'
password 'easyone'
password_confirmation 'easyone'
locale 'en'
factory "admin user" do
name "Admin"
email "admin@locomotiveapp.org"
end
factory "frenchy user" do
name "Jean Claude"
email "jean@frenchy.fr"
locale 'fr'
end
factory "brazillian user" do
name "Jose Carlos"
email "jose@carlos.com.br"
locale 'pt-BR'
end
factory "italian user" do
name "Paolo Rossi"
email "paolo@paolo-rossi.it"
locale 'it'
end
Factory.define "existing site", :parent => "site" do |s|
s.name "Locomotive site with existing models"
s.subdomain "models"
s.after_build do |site_with_models|
site_with_models.content_types.build(
:slug => 'projects',
:name => 'Existing name',
:description => 'Existing description',
:order_by => 'created_at')
end end
end
Factory.define "valid site", :parent => "site" do |s| ## Memberships ##
# s.after_build { |valid_site| valid_site.stubs(:valid?).returns(true) } factory :membership do
end role 'admin'
account { Account.where(:name => "Bart Simpson").first || Factory('admin user') }
factory :admin do
role 'admin'
account { Factory('admin user', :locale => 'en') }
end
factory :designer do
role 'designer'
account { Factory('frenchy user', :locale => 'en') }
end
factory :author do
role 'author'
account { Factory('brazillian user', :locale => 'en') }
end
end
## Pages ##
factory :page do
title 'Home page'
slug 'index'
published true
site { Site.where(:subdomain => "acme").first || Factory(:site) }
factory :sub_page do
title 'Subpage'
slug 'subpage'
published true
site { Site.where(:subdomain => "acme").first || Factory(:site) }
parent { Page.where(:slug => "index").first || Factory(:page) }
end
end
## Snippets ##
factory :snippet do
name 'My website title'
slug 'header'
template %{<title>Acme</title>}
site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
# Accounts ## ## Assets ##
Factory.define :account do |a| factory :asset do
a.name 'Bart Simpson' site { Site.where(:subdomain => "acme").first || Factory(:site) }
a.email 'bart@simpson.net' end
a.password 'easyone'
a.password_confirmation 'easyone'
a.locale 'en'
end
Factory.define "admin user", :parent => :account do |a|
a.name "Admin"
a.email "admin@locomotiveapp.org"
end
Factory.define "frenchy user", :parent => :account do |a|
a.name "Jean Claude"
a.email "jean@frenchy.fr"
a.locale 'fr'
end
Factory.define "brazillian user", :parent => :account do |a|
a.name "Jose Carlos"
a.email "jose@carlos.com.br"
a.locale 'pt-BR'
end
Factory.define "italian user", :parent => :account do |a|
a.name "Paolo Rossi"
a.email "paolo@paolo-rossi.it"
a.locale 'it'
end
## Memberships ## ## Theme assets ##
Factory.define :membership do |m| factory :theme_asset do
m.role 'admin' site { Site.where(:subdomain => "acme").first || Factory(:site) }
m.account { Account.where(:name => "Bart Simpson").first || Factory('admin user') } end
end
Factory.define :admin, :parent => :membership do |m| ## Content types ##
m.role 'admin' factory :content_type do
m.account { Factory('admin user', :locale => 'en') } name 'My project'
end site { Site.where(:subdomain => "acme").first || Factory(:site) }
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
## Pages ##
Factory.define :page do |p|
p.title 'Home page'
p.slug 'index'
p.published true
p.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
Factory.define :sub_page, :parent => :page do |p|
p.title 'Subpage'
p.slug 'subpage'
p.published true
p.site { Site.where(:subdomain => "acme").first || Factory(:site) }
p.parent { Page.where(:slug => "index").first || Factory(:page) }
end
## Snippets ##
Factory.define :snippet do |s|
s.name 'My website title'
s.slug 'header'
s.template %{<title>Acme</title>}
s.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
## Assets ##
Factory.define :asset do |a|
a.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
## Theme assets ##
Factory.define :theme_asset do |a|
a.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
## Content types ##
Factory.define :content_type do |t|
t.name 'My project'
t.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
end

View File

@ -66,7 +66,7 @@ describe 'Bushido support' do
before(:each) do before(:each) do
configure_locomotive_with_bushido configure_locomotive_with_bushido
@site = Factory.build('test site') @site = FactoryGirl.build('test site')
@account = @site.memberships.first.account @account = @site.memberships.first.account
Account.stubs(:first).returns(@account) Account.stubs(:first).returns(@account)
end end
@ -83,7 +83,7 @@ describe 'Bushido support' do
before(:each) do before(:each) do
configure_locomotive_with_bushido configure_locomotive_with_bushido
@site = Factory.build('valid site') @site = FactoryGirl.build('valid site')
end end
it 'calls add_bushido_domains after saving a site' do it 'calls add_bushido_domains after saving a site' do

View File

@ -5,7 +5,7 @@ describe Locomotive::Export do
context '#content_type' do context '#content_type' do
before(:each) do before(:each) do
site = Factory.build('another site') site = FactoryGirl.build('another site')
Site.stubs(:find).returns(site) Site.stubs(:find).returns(site)
project_type = build_project_type(site) project_type = build_project_type(site)
project_type.contents.build(:title => 'Project #1', :description => 'Lorem ipsum', :active => true) project_type.contents.build(:title => 'Project #1', :description => 'Lorem ipsum', :active => true)
@ -39,7 +39,7 @@ describe Locomotive::Export do
end end
def build_project_type(site) def build_project_type(site)
Factory.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1').tap do |content_type| FactoryGirl.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1').tap do |content_type|
content_type.content_custom_fields.build :label => 'Title', :_alias => 'title', :kind => 'string' content_type.content_custom_fields.build :label => 'Title', :_alias => 'title', :kind => 'string'
content_type.content_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text' content_type.content_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text'
content_type.content_custom_fields.build :label => 'Active', :kind => 'boolean' content_type.content_custom_fields.build :label => 'Active', :kind => 'boolean'
@ -49,7 +49,7 @@ describe Locomotive::Export do
def build_team_type(site, project_type) def build_team_type(site, project_type)
Object.send(:remove_const, 'TestProject') rescue nil Object.send(:remove_const, 'TestProject') rescue nil
klass = Object.const_set('TestProject', Class.new { def self.embedded?; false; end }) klass = Object.const_set('TestProject', Class.new { def self.embedded?; false; end })
content_type = Factory.build(:content_type, :site => site, :name => 'team', :highlighted_field_name => 'custom_field_1') content_type = FactoryGirl.build(:content_type, :site => site, :name => 'team', :highlighted_field_name => 'custom_field_1')
content_type.content_custom_fields.build :label => 'Name', :_alias => 'name', :kind => 'string' content_type.content_custom_fields.build :label => 'Name', :_alias => 'name', :kind => 'string'
content_type.content_custom_fields.build :label => 'Projects', :kind => 'has_many', :_alias => 'projects', :target => 'TestProject' content_type.content_custom_fields.build :label => 'Projects', :kind => 'has_many', :_alias => 'projects', :target => 'TestProject'
content_type.content_custom_fields.build :label => 'Bio', :_alias => 'bio', :kind => 'text' content_type.content_custom_fields.build :label => 'Bio', :_alias => 'bio', :kind => 'text'
@ -62,7 +62,7 @@ describe Locomotive::Export do
context '#zipfile' do context '#zipfile' do
before(:all) do before(:all) do
@site = Factory('another site') @site = FactoryGirl.create('another site')
# first import a brand new site # first import a brand new site
self.import_it self.import_it

View File

@ -95,9 +95,7 @@ describe 'Heroku support' do
before(:each) do before(:each) do
configure_locomotive_with_heroku configure_locomotive_with_heroku
# (@site = Factory.stub(:site)).stubs(:valid?).returns(true) @site = FactoryGirl.build('valid site')
@site = Factory.build('valid site')
# (@site = Site.new(:name => 'foobar', :subdomain => 'acme')).stubs(:valid?).returns(true)
end end
it 'calls add_heroku_domains after saving a site' do it 'calls add_heroku_domains after saving a site' do

View File

@ -2,15 +2,10 @@ require 'spec_helper'
describe Locomotive::Import::Job do describe Locomotive::Import::Job do
# before(:all) do
# # Site.destroy_all
# # Locomotive.configure_for_test(true)
# end
context 'when successful' do context 'when successful' do
before(:all) do before(:all) do
@site = Factory(:site) @site = FactoryGirl.create(:site)
job = Locomotive::Import::Job.new(FixturedTheme.duplicate_and_open('default.zip'), @site, { :samples => true, :reset => true }) job = Locomotive::Import::Job.new(FixturedTheme.duplicate_and_open('default.zip'), @site, { :samples => true, :reset => true })
job.perform job.perform
@ -115,7 +110,7 @@ describe Locomotive::Import::Job do
context 'with an existing site' do context 'with an existing site' do
before(:all) do before(:all) do
@site = Factory("existing site") @site = FactoryGirl.create('existing site')
job = Locomotive::Import::Job.new(FixturedTheme.duplicate_and_open('default.zip'), @site, { :samples => true, :reset => false }) job = Locomotive::Import::Job.new(FixturedTheme.duplicate_and_open('default.zip'), @site, { :samples => true, :reset => false })
job.perform job.perform

View File

@ -3,8 +3,8 @@ require 'spec_helper'
describe Locomotive::Liquid::Drops::Content do describe Locomotive::Liquid::Drops::Content do
before(:each) do before(:each) do
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
content_type = Factory.build(:content_type) content_type = FactoryGirl.build(:content_type)
content_type.content_custom_fields.build :label => 'anything', :kind => 'string' content_type.content_custom_fields.build :label => 'anything', :kind => 'string'
content_type.content_custom_fields.build :label => 'published_at', :kind => 'date' content_type.content_custom_fields.build :label => 'published_at', :kind => 'date'
@content = content_type.contents.build({ @content = content_type.contents.build({

View File

@ -3,8 +3,11 @@ require 'spec_helper'
describe Locomotive::Liquid::Drops::Contents do describe Locomotive::Liquid::Drops::Contents do
before(:each) do before(:each) do
@site = Factory.build(:site) # Reload the file (needed for spork)
@content_type = Factory.build(:content_type, :site => @site, :slug => 'projects') load File.join(Rails.root, 'lib', 'locomotive', 'liquid', 'drops', 'contents.rb')
@site = FactoryGirl.build(:site)
@content_type = FactoryGirl.build(:content_type, :site => @site, :slug => 'projects')
end end
it 'retrieves a content type from a slug' do it 'retrieves a content type from a slug' do
@ -22,6 +25,26 @@ describe Locomotive::Liquid::Drops::Contents do
end end
describe Locomotive::Liquid::Drops::ProxyCollection do
before(:each) do
populate_content_type
@proxy_collection = Locomotive::Liquid::Drops::ProxyCollection.new(@content_type)
@proxy_collection.context = {}
end
it 'provides its size like an Array' do
@proxy_collection.size.should == @proxy_collection.length
end
it 'can be enumerated using each_with_index' do
@proxy_collection.each_with_index do |item, index|
item._slug.should == "item#{index + 1}"
end
end
end
def render_template(template = '', assigns = {}) def render_template(template = '', assigns = {})
assigns = { assigns = {
'contents' => Locomotive::Liquid::Drops::Contents.new 'contents' => Locomotive::Liquid::Drops::Contents.new
@ -30,4 +53,11 @@ describe Locomotive::Liquid::Drops::Contents do
Liquid::Template.parse(template).render(::Liquid::Context.new({}, assigns, { :site => @site })) Liquid::Template.parse(template).render(::Liquid::Context.new({}, assigns, { :site => @site }))
end end
def populate_content_type
@content_type.order_by = :_slug
@content_type.contents.build(:_slug => 'item1')
@content_type.contents.build(:_slug => 'item2')
@content_type.contents.build(:_slug => 'item3')
end
end end

View File

@ -3,8 +3,8 @@ require 'spec_helper'
describe Locomotive::Liquid::Drops::Page do describe Locomotive::Liquid::Drops::Page do
before(:each) do before(:each) do
site = Factory.build(:site) site = FactoryGirl.build(:site)
@home = Factory.build(:page, :site => site, :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") @home = FactoryGirl.build(:page, :site => site, :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.")
end end
context '#rendering tree' do context '#rendering tree' do
@ -40,24 +40,24 @@ describe Locomotive::Liquid::Drops::Page do
end end
end end
context '#parent' do context '#parent' do
before(:each) do before(:each) do
@sub_page = Factory.build(:sub_page, :meta_keywords => 'Sub Libidinous, Angsty', :meta_description => "Sub Quite the combination.") @sub_page = FactoryGirl.build(:sub_page, :meta_keywords => 'Sub Libidinous, Angsty', :meta_description => "Sub Quite the combination.")
end end
it 'renders title of parent page' do it 'renders title of parent page' do
content = render_template '{{ sub_page.parent.title }}', {'sub_page' => @sub_page} content = render_template '{{ sub_page.parent.title }}', {'sub_page' => @sub_page}
content.should == "Home page" content.should == "Home page"
end end
end end
context '#breadcrumbs' do context '#breadcrumbs' do
before(:each) do before(:each) do
@sub_page = Factory.build(:sub_page, :meta_keywords => 'Sub Libidinous, Angsty', :meta_description => "Sub Quite the combination.") @sub_page = FactoryGirl.build(:sub_page, :meta_keywords => 'Sub Libidinous, Angsty', :meta_description => "Sub Quite the combination.")
end end
it 'renders breadcrumbs of current page' do it 'renders breadcrumbs of current page' do
content = render_template '{% for crumb in sub_page.breadcrumbs %}{{ crumb.title}},{% endfor %}', {'sub_page' => @sub_page} content = render_template '{% for crumb in sub_page.breadcrumbs %}{{ crumb.title}},{% endfor %}', {'sub_page' => @sub_page}
content.should == 'Home page,Subpage,' content.should == 'Home page,Subpage,'
@ -71,7 +71,7 @@ describe Locomotive::Liquid::Drops::Page do
end end
it 'renders the content instance highlighted field instead for a templatized page' do it 'renders the content instance highlighted field instead for a templatized page' do
templatized = Factory.build(:page, :title => 'Lorem ipsum template', :templatized => true) templatized = FactoryGirl.build(:page, :title => 'Lorem ipsum template', :templatized => true)
content_instance = Locomotive::Liquid::Drops::Content.new(mock('content_instance', :highlighted_field_value => 'Locomotive rocks !')) content_instance = Locomotive::Liquid::Drops::Content.new(mock('content_instance', :highlighted_field_value => 'Locomotive rocks !'))

View File

@ -3,9 +3,9 @@ require 'spec_helper'
describe Locomotive::Liquid::Drops::Site do describe Locomotive::Liquid::Drops::Site do
before(:each) do before(:each) do
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
page_1 = Factory.build(:page, :site => @site) page_1 = FactoryGirl.build(:page, :site => @site)
page_2 = Factory.build(:page, :site => @site, :title => 'About us', :slug => 'about_us') page_2 = FactoryGirl.build(:page, :site => @site, :title => 'About us', :slug => 'about_us')
@site.stubs(:pages).returns([page_1, page_2]) @site.stubs(:pages).returns([page_1, page_2])
end end

View File

@ -99,7 +99,7 @@ describe Locomotive::Liquid::Filters::Html do
end end
it 'should return a url for a javascript file' do it 'should return a url for a javascript file' do
result = "/sites/000000000000000000000042/theme/javascripts/main.js" result = "/sites/000000000000000000000042/theme/javascripts/main.js"
javascript_url('main.js').should == result javascript_url('main.js').should == result
javascript_url('main').should == result javascript_url('main').should == result
javascript_url(nil).should == '' javascript_url(nil).should == ''
@ -233,7 +233,7 @@ describe Locomotive::Liquid::Filters::Html do
klass = Class.new klass = Class.new
klass.class_eval do klass.class_eval do
def registers def registers
{ :site => Factory.build(:site, :id => fake_bson_id(42)) } { :site => FactoryGirl.build(:site, :id => fake_bson_id(42)) }
end end
def fake_bson_id(id) def fake_bson_id(id)

View File

@ -3,10 +3,10 @@ require 'spec_helper'
describe Locomotive::Liquid::Filters::Resize do describe Locomotive::Liquid::Filters::Resize do
before :each do before :each do
@site = Factory.create(:site) @site = FactoryGirl.create(:site)
@theme_asset = Factory.create(:theme_asset, :source => FixturedAsset.open('5k.png'), :site => @site) @theme_asset = FactoryGirl.create(:theme_asset, :source => FixturedAsset.open('5k.png'), :site => @site)
@theme_asset_path = "/sites/#{@theme_asset.site_id}/theme/images/5k.png" @theme_asset_path = "/sites/#{@theme_asset.site_id}/theme/images/5k.png"
@asset = Factory.create(:asset, :source => FixturedAsset.open('5k.png'), :site => @site) @asset = FactoryGirl.create(:asset, :source => FixturedAsset.open('5k.png'), :site => @site)
@asset_url = @asset.source.url @asset_url = @asset.source.url
@asset_path = "/sites/#{@asset.site_id}/assets/#{@asset.id}/5k.png" @asset_path = "/sites/#{@asset.site_id}/assets/#{@asset.id}/5k.png"
@context = Liquid::Context.new( { }, { 'asset_url' => @asset_url, 'theme_asset' => @theme_asset.to_liquid }, { :site => @site }) @context = Liquid::Context.new( { }, { 'asset_url' => @asset_url, 'theme_asset' => @theme_asset.to_liquid }, { :site => @site })

View File

@ -15,24 +15,24 @@ describe Locomotive::Liquid::Tags::Editable::Content do
end.should_not raise_error end.should_not raise_error
end end
end end
end end
context 'output' do context 'output' do
before :each do before :each do
EditableElement.any_instance.stubs(:content).returns("test string") EditableElement.any_instance.stubs(:content).returns("test string")
end end
context 'inheriting from a parent' do context 'inheriting from a parent' do
before :each do before :each do
@parent = Factory.build(:page) @parent = FactoryGirl.build(:page)
@child = Factory.build(:page) @child = FactoryGirl.build(:page)
@child.stubs(:parent).returns(@parent) @child.stubs(:parent).returns(@parent)
end end
it 'should return the parents field if inherit is set' do it 'should return the parents field if inherit is set' do
@element = @parent.editable_elements.create(:slug => 'test') @element = @parent.editable_elements.create(:slug => 'test')
@child.stubs(:raw_template).returns("{% content test, inherit: true %}") @child.stubs(:raw_template).returns("{% content test, inherit: true %}")
@ -40,27 +40,27 @@ describe Locomotive::Liquid::Tags::Editable::Content do
text = template.render!(liquid_context(:page => @child)) text = template.render!(liquid_context(:page => @child))
text.should match /test string/ text.should match /test string/
end end
it 'should raise an exception if it cant find the field' do it 'should raise an exception if it cant find the field' do
@child.stubs(:raw_template).returns("{% content test, inherit: true %}") @child.stubs(:raw_template).returns("{% content test, inherit: true %}")
template = Liquid::Template.parse(@child.raw_template) template = Liquid::Template.parse(@child.raw_template)
lambda do lambda do
template.render!(liquid_context(:page => @child)) template.render!(liquid_context(:page => @child))
end.should raise_error end.should raise_error
end end
after :each do after :each do
@parent.editable_elements.destroy_all @parent.editable_elements.destroy_all
end end
end end
context 'reading from the same page' do context 'reading from the same page' do
before :each do before :each do
@page = Factory.build(:page) @page = FactoryGirl.build(:page)
end end
it 'should return the previously defined field' do it 'should return the previously defined field' do
@element = @page.editable_elements.create(:slug => 'test') @element = @page.editable_elements.create(:slug => 'test')
@page.stubs(:raw_template).returns("{% content test %}") @page.stubs(:raw_template).returns("{% content test %}")
@ -68,7 +68,7 @@ describe Locomotive::Liquid::Tags::Editable::Content do
text = template.render!(liquid_context(:page => @page)) text = template.render!(liquid_context(:page => @page))
text.should match /test string/ text.should match /test string/
end end
it 'should raise an exception if it wasnt defined' do it 'should raise an exception if it wasnt defined' do
@page.stubs(:raw_template).returns("{% content test %}") @page.stubs(:raw_template).returns("{% content test %}")
template = Liquid::Template.parse(@page.raw_template) template = Liquid::Template.parse(@page.raw_template)
@ -76,19 +76,19 @@ describe Locomotive::Liquid::Tags::Editable::Content do
template.render!(liquid_context(:page => @page)) template.render!(liquid_context(:page => @page))
end.should raise_error end.should raise_error
end end
after :each do after :each do
@page.editable_elements.destroy_all @page.editable_elements.destroy_all
end end
end end
end end
# ___ helpers methods ___ # # ___ helpers methods ___ #
def liquid_context(options = {}) def liquid_context(options = {})
::Liquid::Context.new({}, {}, ::Liquid::Context.new({}, {},
{ {
:page => options[:page] :page => options[:page]
}, true) }, true)

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe Locomotive::Liquid::Tags::Nav do describe Locomotive::Liquid::Tags::Nav do
before(:each) do before(:each) do
@home = Factory.build(:page) @home = FactoryGirl.build(:page)
home_children = [ home_children = [
Page.new(:title => 'Child #1', :fullpath => 'child_1', :slug => 'child_1', :published => true), Page.new(:title => 'Child #1', :fullpath => 'child_1', :slug => 'child_1', :published => true),
Page.new(:title => 'Child #2', :fullpath => 'child_2', :slug => 'child_2', :published => true) Page.new(:title => 'Child #2', :fullpath => 'child_2', :slug => 'child_2', :published => true)
@ -24,7 +24,7 @@ describe Locomotive::Liquid::Tags::Nav do
pages = [@home] pages = [@home]
pages.stubs(:root).returns(pages) pages.stubs(:root).returns(pages)
pages.stubs(:minimal_attributes).returns(pages) # iso pages.stubs(:minimal_attributes).returns(pages) # iso
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
@site.stubs(:pages).returns(pages) @site.stubs(:pages).returns(pages)
end end

View File

@ -54,7 +54,7 @@ describe Locomotive::Liquid::Tags::Paginate do
'projects' => options.has_key?(:collection) ? options[:collection] : PaginatedCollection.new(['Ruby on Rails', 'jQuery', 'mongodb', 'Liquid', 'sqlite3']), 'projects' => options.has_key?(:collection) ? options[:collection] : PaginatedCollection.new(['Ruby on Rails', 'jQuery', 'mongodb', 'Liquid', 'sqlite3']),
'current_page' => options[:page] || 1 'current_page' => options[:page] || 1
}, { }, {
:page => Factory.build(:page) :page => FactoryGirl.build(:page)
}, true) }, true)
end end

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe Locomotive::Liquid::Tags::SEO do describe Locomotive::Liquid::Tags::SEO do
let(:site) do let(:site) do
Factory.build(:site, :seo_title => 'Site title (SEO)', :meta_description => 'A short site description', :meta_keywords => 'test only cat dog') FactoryGirl.build(:site, :seo_title => 'Site title (SEO)', :meta_description => 'A short site description', :meta_keywords => 'test only cat dog')
end end
describe 'rendering' do describe 'rendering' do
@ -80,7 +80,7 @@ describe Locomotive::Liquid::Tags::SEO do
context "when content instance" do context "when content instance" do
let(:content_type) do let(:content_type) do
Factory.build(:content_type, :site => site).tap do |ct| FactoryGirl.build(:content_type, :site => site).tap do |ct|
ct.content_custom_fields.build :label => 'anything', :kind => 'String' ct.content_custom_fields.build :label => 'anything', :kind => 'String'
end end
end end

View File

@ -6,10 +6,10 @@ describe 'Locomotive rendering system' do
before(:each) do before(:each) do
@controller = Locomotive::TestController.new @controller = Locomotive::TestController.new
Site.any_instance.stubs(:create_default_pages!).returns(true) Site.any_instance.stubs(:create_default_pages!).returns(true)
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
Site.stubs(:find).returns(@site) Site.stubs(:find).returns(@site)
@controller.current_site = @site @controller.current_site = @site
@page = Factory.build(:page, :site => nil, :published => true) @page = FactoryGirl.build(:page, :site => nil, :published => true)
end end
context '#liquid_context' do context '#liquid_context' do
@ -125,7 +125,7 @@ describe 'Locomotive rendering system' do
context 'templatized page' do context 'templatized page' do
before(:each) do before(:each) do
@content_type = Factory.build(:content_type, :site => nil) @content_type = FactoryGirl.build(:content_type, :site => nil)
@content = @content_type.contents.build(:_visible => true) @content = @content_type.contents.build(:_visible => true)
@page.templatized = true @page.templatized = true
@page.content_type = @content_type @page.content_type = @content_type

View File

@ -26,7 +26,7 @@ describe Locomotive::Routing::SiteDispatcher do
before :each do before :each do
@request = Object.new @request = Object.new
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
@controller.stubs(:request).returns(@request) @controller.stubs(:request).returns(@request)
@request.stubs(:host).returns('host') @request.stubs(:host).returns('host')
@ -48,7 +48,7 @@ describe Locomotive::Routing::SiteDispatcher do
describe '#current_site' do describe '#current_site' do
before :each do before :each do
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
end end
it 'returns the current site instance if available' do it 'returns the current site instance if available' do
@ -157,8 +157,8 @@ describe Locomotive::Routing::SiteDispatcher do
describe '#validate_site_membership' do describe '#validate_site_membership' do
before :each do before :each do
@account = Factory.build(:account) @account = FactoryGirl.build(:account)
@site = Factory.build(:site) @site = FactoryGirl.build(:site)
@request = ActionDispatch::Request.new({}) @request = ActionDispatch::Request.new({})
@controller.instance_variable_set('@_response', ActionDispatch::Response.new) @controller.instance_variable_set('@_response', ActionDispatch::Response.new)

View File

@ -3,12 +3,12 @@ require 'spec_helper'
describe Ability do describe Ability do
before :each do before :each do
@site = Factory(:site) @site = FactoryGirl.create(:site)
@account = Factory(:account) @account = FactoryGirl.create(:account)
@admin = Factory(:membership, :account => Factory.stub(:account), :site => Factory.stub(:site)) @admin = FactoryGirl.create(:membership, :account => FactoryGirl.build(:account), :site => FactoryGirl.build(:site))
@designer = Factory(:membership, :account => Factory.stub(:account), :site => @site, :role => %(designer)) @designer = FactoryGirl.create(:membership, :account => FactoryGirl.build(:account), :site => @site, :role => %(designer))
@author = Factory(:membership, :account => Factory.stub(:account), :site => @site, :role => %(author)) @author = FactoryGirl.create(:membership, :account => FactoryGirl.build(:account), :site => @site, :role => %(author))
end end
context 'pages' do context 'pages' do

View File

@ -3,14 +3,14 @@ require 'spec_helper'
describe Account do describe Account do
it 'should have a valid factory' do it 'should have a valid factory' do
Factory.build(:account).should be_valid FactoryGirl.build(:account).should be_valid
end end
## Validations ## ## Validations ##
%w{name email password}.each do |attr| %w{name email password}.each do |attr|
it "should validate presence of #{attr}" do it "should validate presence of #{attr}" do
account = Factory.build(:account, attr.to_sym => nil) account = FactoryGirl.build(:account, attr.to_sym => nil)
account.should_not be_valid account.should_not be_valid
account.errors[attr.to_sym].should include("can't be blank") account.errors[attr.to_sym].should include("can't be blank")
end end
@ -22,26 +22,26 @@ describe Account do
end end
it "should validate uniqueness of email" do it "should validate uniqueness of email" do
Factory(:account) FactoryGirl.create(:account)
(account = Factory.build(:account)).should_not be_valid (account = FactoryGirl.build(:account)).should_not be_valid
account.errors[:email].should == ["is already taken"] account.errors[:email].should == ["is already taken"]
end end
## Associations ## ## Associations ##
it 'should own many sites' do it 'should own many sites' do
account = Factory(:account) account = FactoryGirl.create(:account)
site_1 = Factory(:site, :memberships => [Membership.new(:account => account)]) site_1 = FactoryGirl.create(:site, :memberships => [Membership.new(:account => account)])
site_2 = Factory(:site, :subdomain => 'foo', :memberships => [Membership.new(:account => account)]) site_2 = FactoryGirl.create(:site, :subdomain => 'foo', :memberships => [Membership.new(:account => account)])
account.reload.sites.to_a.should == [site_1, site_2] account.reload.sites.to_a.should == [site_1, site_2]
end end
describe 'deleting' do describe 'deleting' do
before(:each) do before(:each) do
@account = Factory.build(:account) @account = FactoryGirl.build(:account)
@site_1 = Factory.build(:site, :subdomain => 'foo', :memberships => [Factory.build(:membership, :account => @account)]) @site_1 = FactoryGirl.build(:site, :subdomain => 'foo', :memberships => [FactoryGirl.build(:membership, :account => @account)])
@site_2 = Factory.build(:site, :subdomain => 'bar', :memberships => [Factory.build(:membership, :account => @account)]) @site_2 = FactoryGirl.build(:site, :subdomain => 'bar', :memberships => [FactoryGirl.build(:membership, :account => @account)])
@account.stubs(:sites).returns([@site_1, @site_2]) @account.stubs(:sites).returns([@site_1, @site_2])
Site.any_instance.stubs(:save).returns(true) Site.any_instance.stubs(:save).returns(true)
end end
@ -65,7 +65,7 @@ describe Account do
describe 'cross domain authentication' do describe 'cross domain authentication' do
before(:each) do before(:each) do
@account = Factory.build(:account) @account = FactoryGirl.build(:account)
@account.stubs(:save).returns(true) @account.stubs(:save).returns(true)
end end

View File

@ -8,7 +8,7 @@ describe Asset do
before(:each) do before(:each) do
Asset.any_instance.stubs(:site_id).returns('test') Asset.any_instance.stubs(:site_id).returns('test')
@asset = Factory.build(:asset) @asset = FactoryGirl.build(:asset)
end end
it 'should process picture' do it 'should process picture' do
@ -28,7 +28,7 @@ describe Asset do
describe 'vignette' do describe 'vignette' do
before(:each) do before(:each) do
@asset = Factory.build(:asset, :source => FixturedAsset.open('5k.png')) @asset = FactoryGirl.build(:asset, :source => FixturedAsset.open('5k.png'))
end end
it 'does not resize image smaller than 50x50' do it 'does not resize image smaller than 50x50' do

View File

@ -6,7 +6,7 @@ describe ContentInstance do
before(:each) do before(:each) do
Site.any_instance.stubs(:create_default_pages!).returns(true) Site.any_instance.stubs(:create_default_pages!).returns(true)
@content_type = Factory.build(:content_type) @content_type = FactoryGirl.build(:content_type)
@content_type.content_custom_fields.build :label => 'Title', :kind => 'String' @content_type.content_custom_fields.build :label => 'Title', :kind => 'String'
@content_type.content_custom_fields.build :label => 'Description', :kind => 'Text' @content_type.content_custom_fields.build :label => 'Description', :kind => 'Text'
@content_type.content_custom_fields.build :label => 'Visible ?', :kind => 'Text', :_alias => 'visible' @content_type.content_custom_fields.build :label => 'Visible ?', :kind => 'Text', :_alias => 'visible'
@ -111,8 +111,8 @@ describe ContentInstance do
describe '#api' do describe '#api' do
before(:each) do before(:each) do
@account_1 = Factory.build('admin user', :id => fake_bson_id('1')) @account_1 = FactoryGirl.build('admin user', :id => fake_bson_id('1'))
@account_2 = Factory.build('frenchy user', :id => fake_bson_id('2')) @account_2 = FactoryGirl.build('frenchy user', :id => fake_bson_id('2'))
@content_type.api_enabled = true @content_type.api_enabled = true
@content_type.api_accounts = ['', @account_1.id, @account_2.id] @content_type.api_accounts = ['', @account_1.id, @account_2.id]

View File

@ -9,7 +9,7 @@ describe ContentType do
context 'when validating' do context 'when validating' do
it 'should have a valid factory' do it 'should have a valid factory' do
content_type = Factory.build(:content_type) content_type = FactoryGirl.build(:content_type)
content_type.content_custom_fields.build :label => 'anything', :kind => 'String' content_type.content_custom_fields.build :label => 'anything', :kind => 'String'
content_type.should be_valid content_type.should be_valid
end end
@ -18,35 +18,35 @@ describe ContentType do
%w{site name}.each do |field| %w{site name}.each do |field|
it "requires the presence of #{field}" do it "requires the presence of #{field}" do
content_type = Factory.build(:content_type, field.to_sym => nil) content_type = FactoryGirl.build(:content_type, field.to_sym => nil)
content_type.should_not be_valid content_type.should_not be_valid
content_type.errors[field.to_sym].should == ["can't be blank"] content_type.errors[field.to_sym].should == ["can't be blank"]
end end
end end
it 'requires the presence of slug' do it 'requires the presence of slug' do
content_type = Factory.build(:content_type, :name => nil, :slug => nil) content_type = FactoryGirl.build(:content_type, :name => nil, :slug => nil)
content_type.should_not be_valid content_type.should_not be_valid
content_type.errors[:slug].should == ["can't be blank"] content_type.errors[:slug].should == ["can't be blank"]
end end
it 'is not valid if slug is not unique' do it 'is not valid if slug is not unique' do
content_type = Factory.build(:content_type) content_type = FactoryGirl.build(:content_type)
content_type.content_custom_fields.build :label => 'anything', :kind => 'String' content_type.content_custom_fields.build :label => 'anything', :kind => 'String'
content_type.save content_type.save
(content_type = Factory.build(:content_type, :site => content_type.site)).should_not be_valid (content_type = FactoryGirl.build(:content_type, :site => content_type.site)).should_not be_valid
content_type.errors[:slug].should == ["is already taken"] content_type.errors[:slug].should == ["is already taken"]
end end
it 'is not valid if there is not at least one field' do it 'is not valid if there is not at least one field' do
content_type = Factory.build(:content_type) content_type = FactoryGirl.build(:content_type)
content_type.should_not be_valid content_type.should_not be_valid
content_type.errors[:content_custom_fields].should == ["is too small (minimum element number is 1)"] content_type.errors[:content_custom_fields].should == ["is too small (minimum element number is 1)"]
end end
%w(created_at updated_at).each do |_alias| %w(created_at updated_at).each do |_alias|
it "does not allow #{_alias} as alias" do it "does not allow #{_alias} as alias" do
content_type = Factory.build(:content_type) content_type = FactoryGirl.build(:content_type)
field = content_type.content_custom_fields.build :label => 'anything', :kind => 'String', :_alias => _alias field = content_type.content_custom_fields.build :label => 'anything', :kind => 'String', :_alias => _alias
field.valid?.should be_false field.valid?.should be_false
field.errors[:_alias].should == ['is reserved'] field.errors[:_alias].should == ['is reserved']
@ -58,7 +58,7 @@ describe ContentType do
context '#ordered_contents' do context '#ordered_contents' do
before(:each) do before(:each) do
@content_type = Factory.build(:content_type, :order_by => 'created_at') @content_type = FactoryGirl.build(:content_type, :order_by => 'created_at')
@content_1 = stub('content_1', :name => 'Did', :_position_in_list => 2) @content_1 = stub('content_1', :name => 'Did', :_position_in_list => 2)
@content_2 = stub('content_2', :name => 'Sacha', :_position_in_list => 1) @content_2 = stub('content_2', :name => 'Sacha', :_position_in_list => 1)
@content_type.stubs(:contents).returns([@content_1, @content_2]) @content_type.stubs(:contents).returns([@content_1, @content_2])
@ -95,9 +95,9 @@ describe ContentType do
describe 'custom fields' do describe 'custom fields' do
before(:each) do before(:each) do
site = Factory.build(:site) site = FactoryGirl.build(:site)
Site.stubs(:find).returns(site) Site.stubs(:find).returns(site)
@content_type = Factory.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1') @content_type = FactoryGirl.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1')
@content_type.content_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text' @content_type.content_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text'
@content_type.content_custom_fields.build :label => 'Active', :kind => 'boolean' @content_type.content_custom_fields.build :label => 'Active', :kind => 'boolean'
# ContentType.logger = Logger.new($stdout) # ContentType.logger = Logger.new($stdout)

View File

@ -3,14 +3,14 @@ require 'spec_helper'
describe EditableElement do describe EditableElement do
before(:each) do before(:each) do
@site = Factory(:site) @site = FactoryGirl.create(:site)
@home = @site.pages.root.first @home = @site.pages.root.first
@home.update_attributes :raw_template => "{% block body %}{% editable_short_text 'body' %}Lorem ipsum{% endeditable_short_text %}{% endblock %}" @home.update_attributes :raw_template => "{% block body %}{% editable_short_text 'body' %}Lorem ipsum{% endeditable_short_text %}{% endblock %}"
@sub_page_1 = Factory(:page, :slug => 'sub_page_1', :parent => @home, :raw_template => "{% extends 'parent' %}") @sub_page_1 = FactoryGirl.create(:page, :slug => 'sub_page_1', :parent => @home, :raw_template => "{% extends 'parent' %}")
@sub_page_2 = Factory(:page, :slug => 'sub_page_2', :parent => @home, :raw_template => "{% extends 'parent' %}") @sub_page_2 = FactoryGirl.create(:page, :slug => 'sub_page_2', :parent => @home, :raw_template => "{% extends 'parent' %}")
@sub_page_1_1 = Factory(:page, :slug => 'sub_page_1_1', :parent => @sub_page_1, :raw_template => "{% extends 'parent' %}") @sub_page_1_1 = FactoryGirl.create(:page, :slug => 'sub_page_1_1', :parent => @sub_page_1, :raw_template => "{% extends 'parent' %}")
end end
context 'in sub pages level #1' do context 'in sub pages level #1' do

View File

@ -3,19 +3,19 @@ require 'spec_helper'
describe Membership do describe Membership do
it 'should have a valid factory' do it 'should have a valid factory' do
Factory.build(:membership, :account => Factory.build(:account)).should be_valid FactoryGirl.build(:membership, :account => FactoryGirl.build(:account)).should be_valid
end end
it 'should validate presence of account' do it 'should validate presence of account' do
membership = Factory.build(:membership, :account => nil) membership = FactoryGirl.build(:membership, :account => nil)
membership.should_not be_valid membership.should_not be_valid
membership.errors[:account].should == ["can't be blank"] membership.errors[:account].should == ["can't be blank"]
end end
it 'should assign account from email' do it 'should assign account from email' do
Account.stubs(:where).returns([Factory.build(:account)]) Account.stubs(:where).returns([FactoryGirl.build(:account)])
Account.stubs(:find).returns(Factory.build(:account)) Account.stubs(:find).returns(FactoryGirl.build(:account))
membership = Factory.build(:membership, :account => nil) membership = FactoryGirl.build(:membership, :account => nil)
membership.email = 'bart@simpson.net' membership.email = 'bart@simpson.net'
membership.account.should_not be_nil membership.account.should_not be_nil
membership.account.name.should == 'Bart Simpson' membership.account.name.should == 'Bart Simpson'
@ -24,8 +24,8 @@ describe Membership do
describe 'next action to take' do describe 'next action to take' do
before(:each) do before(:each) do
@membership = Factory.build(:membership, :site => Factory.build(:site)) @membership = FactoryGirl.build(:membership, :site => FactoryGirl.build(:site))
@account = Factory.build(:account) @account = FactoryGirl.build(:account)
@account.stubs(:save).returns(true) @account.stubs(:save).returns(true)
Account.stubs(:where).returns([@account]) Account.stubs(:where).returns([@account])
Account.stubs(:find).returns(@account) Account.stubs(:find).returns(@account)
@ -53,7 +53,7 @@ describe Membership do
end end
def build_membership(account = nil) def build_membership(account = nil)
Factory.build(:membership, :site => Factory.build(:site), :account => account || Factory.build(:account)) FactoryGirl.build(:membership, :site => FactoryGirl.build(:site), :account => account || FactoryGirl.build(:account))
end end
end end

View File

@ -10,36 +10,36 @@ describe Page do
end end
it 'should have a valid factory' do it 'should have a valid factory' do
Factory.build(:page).should be_valid FactoryGirl.build(:page).should be_valid
end end
# Validations ## # Validations ##
%w{site title}.each do |field| %w{site title}.each do |field|
it "should validate presence of #{field}" do it "should validate presence of #{field}" do
page = Factory.build(:page, field.to_sym => nil) page = FactoryGirl.build(:page, field.to_sym => nil)
page.should_not be_valid page.should_not be_valid
page.errors[field.to_sym].should == ["can't be blank"] page.errors[field.to_sym].should == ["can't be blank"]
end end
end end
it 'should validate presence of slug' do it 'should validate presence of slug' do
page = Factory.build(:page, :title => nil, :slug => nil) page = FactoryGirl.build(:page, :title => nil, :slug => nil)
page.should_not be_valid page.should_not be_valid
page.errors[:slug].should == ["can't be blank"] page.errors[:slug].should == ["can't be blank"]
end end
it 'should validate uniqueness of slug' do it 'should validate uniqueness of slug' do
page = Factory(:page) page = FactoryGirl.create(:page)
(page = Factory.build(:page, :site => page.site)).should_not be_valid (page = FactoryGirl.build(:page, :site => page.site)).should_not be_valid
page.errors[:slug].should == ["is already taken"] page.errors[:slug].should == ["is already taken"]
end end
it 'should validate uniqueness of slug within a "folder"' do it 'should validate uniqueness of slug within a "folder"' do
site = Factory(:site) site = FactoryGirl.create(:site)
root = Factory(:page, :slug => 'index', :site => site) root = FactoryGirl.create(:page, :slug => 'index', :site => site)
child_1 = Factory(:page, :slug => 'first_child', :parent => root, :site => site) child_1 = FactoryGirl.create(:page, :slug => 'first_child', :parent => root, :site => site)
(page = Factory.build(:page, :slug => 'first_child', :parent => root, :site => site)).should_not be_valid (page = FactoryGirl.build(:page, :slug => 'first_child', :parent => root, :site => site)).should_not be_valid
page.errors[:slug].should == ["is already taken"] page.errors[:slug].should == ["is already taken"]
page.slug = 'index' page.slug = 'index'
@ -48,7 +48,7 @@ describe Page do
%w{admin stylesheets images javascripts}.each do |slug| %w{admin stylesheets images javascripts}.each do |slug|
it "should consider '#{slug}' as invalid" do it "should consider '#{slug}' as invalid" do
page = Factory.build(:page, :slug => slug) page = FactoryGirl.build(:page, :slug => slug)
page.should_not be_valid page.should_not be_valid
page.errors[:slug].should == ["is reserved"] page.errors[:slug].should == ["is reserved"]
end end
@ -63,22 +63,22 @@ describe Page do
describe 'once created' do describe 'once created' do
it 'should tell if the page is the index one' do it 'should tell if the page is the index one' do
Factory.build(:page, :slug => 'index', :site => nil).index?.should be_true FactoryGirl.build(:page, :slug => 'index', :site => nil).index?.should be_true
Factory.build(:page, :slug => 'index', :depth => 1, :site => nil).index?.should be_false FactoryGirl.build(:page, :slug => 'index', :depth => 1, :site => nil).index?.should be_false
end end
it 'should have normalized slug' do it 'should have normalized slug' do
page = Factory.build(:page, :slug => ' Valid ité.html ') page = FactoryGirl.build(:page, :slug => ' Valid ité.html ')
page.valid? page.valid?
page.slug.should == 'valid-ite-html' page.slug.should == 'valid-ite-html'
page = Factory.build(:page, :title => ' Valid ité.html ', :slug => nil, :site => page.site) page = FactoryGirl.build(:page, :title => ' Valid ité.html ', :slug => nil, :site => page.site)
page.should be_valid page.should be_valid
page.slug.should == 'valid-ite-html' page.slug.should == 'valid-ite-html'
end end
it 'has no cache strategy' do it 'has no cache strategy' do
page = Factory.build(:page, :site => nil) page = FactoryGirl.build(:page, :site => nil)
page.with_cache?.should == false page.with_cache?.should == false
end end
@ -87,7 +87,7 @@ describe Page do
describe '#deleting' do describe '#deleting' do
before(:each) do before(:each) do
@page = Factory.build(:page) @page = FactoryGirl.build(:page)
end end
it 'does not delete the index page' do it 'does not delete the index page' do
@ -111,27 +111,27 @@ describe Page do
describe 'acts as tree' do describe 'acts as tree' do
before(:each) do before(:each) do
@home = Factory(:page) @home = FactoryGirl.create(:page)
@child_1 = Factory(:page, :title => 'Subpage 1', :slug => 'foo', :parent_id => @home._id, :site => @home.site) @child_1 = FactoryGirl.create(:page, :title => 'Subpage 1', :slug => 'foo', :parent_id => @home._id, :site => @home.site)
end end
it 'should add root elements' do it 'should add root elements' do
page_404 = Factory(:page, :title => 'Page not found', :slug => '404', :site => @home.site) page_404 = FactoryGirl.create(:page, :title => 'Page not found', :slug => '404', :site => @home.site)
Page.roots.count.should == 2 Page.roots.count.should == 2
Page.roots.should == [@home, page_404] Page.roots.should == [@home, page_404]
end end
it 'should add sub pages' do it 'should add sub pages' do
child_2 = Factory(:page, :title => 'Subpage 2', :slug => 'bar', :parent => @home, :site => @home.site) child_2 = FactoryGirl.create(:page, :title => 'Subpage 2', :slug => 'bar', :parent => @home, :site => @home.site)
@home = Page.find(@home.id) @home = Page.find(@home.id)
@home.children.count.should == 2 @home.children.count.should == 2
@home.children.should == [@child_1, child_2] @home.children.should == [@child_1, child_2]
end end
it 'should move its children accordingly' do it 'should move its children accordingly' do
sub_child_1 = Factory(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent => @child_1, :site => @home.site) sub_child_1 = FactoryGirl.create(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent => @child_1, :site => @home.site)
archives = Factory(:page, :title => 'archives', :slug => 'archives', :parent => @home, :site => @home.site) archives = FactoryGirl.create(:page, :title => 'archives', :slug => 'archives', :parent => @home, :site => @home.site)
posts = Factory(:page, :title => 'posts', :slug => 'posts', :parent => archives, :site => @home.site) posts = FactoryGirl.create(:page, :title => 'posts', :slug => 'posts', :parent => archives, :site => @home.site)
@child_1.parent_id = archives._id @child_1.parent_id = archives._id
@child_1.save @child_1.save
@ -146,7 +146,7 @@ describe Page do
end end
it 'should destroy descendants as well' do it 'should destroy descendants as well' do
Factory(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent_id => @child_1._id, :site => @home.site) FactoryGirl.create(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent_id => @child_1._id, :site => @home.site)
@child_1.destroy @child_1.destroy
Page.where(:slug => 'bar').first.should be_nil Page.where(:slug => 'bar').first.should be_nil
end end
@ -156,10 +156,10 @@ describe Page do
describe 'acts as list' do describe 'acts as list' do
before(:each) do before(:each) do
@home = Factory(:page) @home = FactoryGirl.create(:page)
@child_1 = Factory(:page, :title => 'Subpage 1', :slug => 'foo', :parent => @home, :site => @home.site) @child_1 = FactoryGirl.create(:page, :title => 'Subpage 1', :slug => 'foo', :parent => @home, :site => @home.site)
@child_2 = Factory(:page, :title => 'Subpage 2', :slug => 'bar', :parent => @home, :site => @home.site) @child_2 = FactoryGirl.create(:page, :title => 'Subpage 2', :slug => 'bar', :parent => @home, :site => @home.site)
@child_3 = Factory(:page, :title => 'Subpage 3', :slug => 'acme', :parent => @home, :site => @home.site) @child_3 = FactoryGirl.create(:page, :title => 'Subpage 3', :slug => 'acme', :parent => @home, :site => @home.site)
end end
it 'should be at the bottom of the folder once created' do it 'should be at the bottom of the folder once created' do
@ -176,8 +176,8 @@ describe Page do
describe 'templatized extension' do describe 'templatized extension' do
before(:each) do before(:each) do
@page = Factory.build(:page, :site => nil, :templatized => true, :content_type_id => 42) @page = FactoryGirl.build(:page, :site => nil, :templatized => true, :content_type_id => 42)
ContentType.stubs(:find).returns(Factory.build(:content_type, :site => nil)) ContentType.stubs(:find).returns(FactoryGirl.build(:content_type, :site => nil))
end end
it 'is considered as a templatized page' do it 'is considered as a templatized page' do
@ -198,12 +198,12 @@ describe Page do
describe 'listed extension' do describe 'listed extension' do
it 'is considered as a visible page' do it 'is considered as a visible page' do
@page = Factory.build(:page, :site => nil, :content_type_id => 42) @page = FactoryGirl.build(:page, :site => nil, :content_type_id => 42)
@page.listed?.should be_true @page.listed?.should be_true
end end
it 'is not considered as a visible page' do it 'is not considered as a visible page' do
@page = Factory.build(:page, :site => nil, :listed => false, :content_type_id => 42) @page = FactoryGirl.build(:page, :site => nil, :listed => false, :content_type_id => 42)
@page.listed?.should be_false @page.listed?.should be_false
end end
@ -212,7 +212,7 @@ describe Page do
describe 'redirect extension' do describe 'redirect extension' do
before(:each) do before(:each) do
@page = Factory.build(:page, :site => nil, :redirect=> true, :redirect_url => 'http://www.google.com/') @page = FactoryGirl.build(:page, :site => nil, :redirect=> true, :redirect_url => 'http://www.google.com/')
end end
it 'is considered as a redirect page' do it 'is considered as a redirect page' do

View File

@ -3,61 +3,61 @@ require 'spec_helper'
describe Site do describe Site do
it 'should have a valid factory' do it 'should have a valid factory' do
Factory.build(:site).should be_valid FactoryGirl.build(:site).should be_valid
end end
## Validations ## ## Validations ##
it 'should validate presence of name' do it 'should validate presence of name' do
site = Factory.build(:site, :name => nil) site = FactoryGirl.build(:site, :name => nil)
site.should_not be_valid site.should_not be_valid
site.errors[:name].should == ["can't be blank"] site.errors[:name].should == ["can't be blank"]
end end
it 'should validate presence of subdomain' do it 'should validate presence of subdomain' do
site = Factory.build(:site, :subdomain => nil) site = FactoryGirl.build(:site, :subdomain => nil)
site.should_not be_valid site.should_not be_valid
site.errors[:subdomain].should == ["can't be blank"] site.errors[:subdomain].should == ["can't be blank"]
end end
%w{test test42 foo_bar}.each do |subdomain| %w{test test42 foo_bar}.each do |subdomain|
it "should accept subdomain like '#{subdomain}'" do it "should accept subdomain like '#{subdomain}'" do
Factory.build(:site, :subdomain => subdomain).should be_valid FactoryGirl.build(:site, :subdomain => subdomain).should be_valid
end end
end end
['-', '_test', 'test_', 't est', '42', '42test'].each do |subdomain| ['-', '_test', 'test_', 't est', '42', '42test'].each do |subdomain|
it "should not accept subdomain like '#{subdomain}'" do it "should not accept subdomain like '#{subdomain}'" do
(site = Factory.build(:site, :subdomain => subdomain)).should_not be_valid (site = FactoryGirl.build(:site, :subdomain => subdomain)).should_not be_valid
site.errors[:subdomain].should == ['is invalid'] site.errors[:subdomain].should == ['is invalid']
end end
end end
it "should not use reserved keywords as subdomain" do it "should not use reserved keywords as subdomain" do
%w{www admin email blog webmail mail support help site sites}.each do |subdomain| %w{www admin email blog webmail mail support help site sites}.each do |subdomain|
(site = Factory.build(:site, :subdomain => subdomain)).should_not be_valid (site = FactoryGirl.build(:site, :subdomain => subdomain)).should_not be_valid
site.errors[:subdomain].should == ['is reserved'] site.errors[:subdomain].should == ['is reserved']
end end
end end
it 'should validate uniqueness of subdomain' do it 'should validate uniqueness of subdomain' do
Factory(:site) FactoryGirl.create(:site)
(site = Factory.build(:site)).should_not be_valid (site = FactoryGirl.build(:site)).should_not be_valid
site.errors[:subdomain].should == ["is already taken"] site.errors[:subdomain].should == ["is already taken"]
end end
it 'should validate uniqueness of domains' do it 'should validate uniqueness of domains' do
Factory(:site, :domains => %w{www.acme.net www.acme.com}) FactoryGirl.create(:site, :domains => %w{www.acme.net www.acme.com})
(site = Factory.build(:site, :domains => %w{www.acme.com})).should_not be_valid (site = FactoryGirl.build(:site, :domains => %w{www.acme.com})).should_not be_valid
site.errors[:domains].should == ["www.acme.com is already taken"] site.errors[:domains].should == ["www.acme.com is already taken"]
(site = Factory.build(:site, :subdomain => 'foo', :domains => %w{acme.example.com})).should_not be_valid (site = FactoryGirl.build(:site, :subdomain => 'foo', :domains => %w{acme.example.com})).should_not be_valid
site.errors[:domains].should == ["acme.example.com is already taken"] site.errors[:domains].should == ["acme.example.com is already taken"]
end end
it 'should validate format of domains' do it 'should validate format of domains' do
site = Factory.build(:site, :domains => ['barformat.superlongextension', '-foo.net']) site = FactoryGirl.build(:site, :domains => ['barformat.superlongextension', '-foo.net'])
site.should_not be_valid site.should_not be_valid
site.errors[:domains].should == ['barformat.superlongextension is invalid', '-foo.net is invalid'] site.errors[:domains].should == ['barformat.superlongextension is invalid', '-foo.net is invalid']
end end
@ -65,8 +65,8 @@ describe Site do
## Named scopes ## ## Named scopes ##
it 'should retrieve sites by domain' do it 'should retrieve sites by domain' do
site_1 = Factory(:site, :domains => %w{www.acme.net}) site_1 = FactoryGirl.create(:site, :domains => %w{www.acme.net})
site_2 = Factory(:site, :subdomain => 'test', :domains => %w{www.example.com}) site_2 = FactoryGirl.create(:site, :subdomain => 'test', :domains => %w{www.example.com})
sites = Site.match_domain('www.acme.net') sites = Site.match_domain('www.acme.net')
sites.size.should == 1 sites.size.should == 1
@ -87,8 +87,8 @@ describe Site do
## Associations ## ## Associations ##
it 'should have many accounts' do it 'should have many accounts' do
site = Factory.build(:site) site = FactoryGirl.build(:site)
account_1, account_2 = Factory(:account), Factory(:account, :name => 'homer', :email => 'homer@simpson.net') account_1, account_2 = FactoryGirl.create(:account), FactoryGirl.create(:account, :name => 'homer', :email => 'homer@simpson.net')
site.memberships.build(:account => account_1, :admin => true) site.memberships.build(:account => account_1, :admin => true)
site.memberships.build(:account => account_2) site.memberships.build(:account => account_2)
site.memberships.size.should == 2 site.memberships.size.should == 2
@ -98,7 +98,7 @@ describe Site do
## Methods ## ## Methods ##
it 'should return domains without subdomain' do it 'should return domains without subdomain' do
site = Factory(:site, :domains => %w{www.acme.net www.acme.com}) site = FactoryGirl.create(:site, :domains => %w{www.acme.net www.acme.com})
site.domains.should == %w{www.acme.net www.acme.com acme.example.com} site.domains.should == %w{www.acme.net www.acme.com acme.example.com}
site.domains_without_subdomain.should == %w{www.acme.net www.acme.com} site.domains_without_subdomain.should == %w{www.acme.net www.acme.com}
end end
@ -106,7 +106,7 @@ describe Site do
describe 'once created' do describe 'once created' do
before(:each) do before(:each) do
@site = Factory(:site) @site = FactoryGirl.create(:site)
end end
it 'should create index and 404 pages' do it 'should create index and 404 pages' do
@ -119,7 +119,7 @@ describe Site do
describe 'deleting in cascade' do describe 'deleting in cascade' do
before(:each) do before(:each) do
@site = Factory(:site) @site = FactoryGirl.create(:site)
end end
it 'should also destroy pages' do it 'should also destroy pages' do

View File

@ -3,30 +3,30 @@ require 'spec_helper'
describe Snippet do describe Snippet do
it 'should have a valid factory' do it 'should have a valid factory' do
Factory.build(:snippet).should be_valid FactoryGirl.build(:snippet).should be_valid
end end
# Validations ## # Validations ##
%w{site name template}.each do |field| %w{site name template}.each do |field|
it "should validate presence of #{field}" do it "should validate presence of #{field}" do
template = Factory.build(:snippet, field.to_sym => nil) template = FactoryGirl.build(:snippet, field.to_sym => nil)
template.should_not be_valid template.should_not be_valid
template.errors[field.to_sym].should == ["can't be blank"] template.errors[field.to_sym].should == ["can't be blank"]
end end
end end
describe '#update_templates' do describe '#update_templates' do
before :each do before :each do
@site = Factory(:site, :subdomain => 'omg') @site = FactoryGirl.create(:site, :subdomain => 'omg')
@snippet = Factory(:snippet, :site => @site, :slug => 'my_test_snippet', :template => 'a testing template') @snippet = FactoryGirl.create(:snippet, :site => @site, :slug => 'my_test_snippet', :template => 'a testing template')
end end
context 'with a normal top level snippet' do context 'with a normal top level snippet' do
before :each do before :each do
@page = Factory(:page, :site => @site, :slug => 'my_page_here', :raw_template => "{% include 'my_test_snippet' %}") @page = FactoryGirl.create(:page, :site => @site, :slug => 'my_page_here', :raw_template => "{% include 'my_test_snippet' %}")
end end
it 'updates templates with the new snippet template' do it 'updates templates with the new snippet template' do
@ -39,7 +39,7 @@ describe Snippet do
context 'for snippets inside of a block' do context 'for snippets inside of a block' do
before :each do before :each do
@page = Factory(:page, :site => @site, :slug => 'my_page_here', :raw_template => "{% block main %}{% include 'my_test_snippet' %}{% endblock %}") @page = FactoryGirl.create(:page, :site => @site, :slug => 'my_page_here', :raw_template => "{% block main %}{% include 'my_test_snippet' %}{% endblock %}")
end end
it 'updates templates with the new snippet template' do it 'updates templates with the new snippet template' do

View File

@ -8,7 +8,7 @@ describe ThemeAsset do
before(:each) do before(:each) do
ThemeAsset.any_instance.stubs(:site_id).returns('test') ThemeAsset.any_instance.stubs(:site_id).returns('test')
@asset = Factory.build(:theme_asset) @asset = FactoryGirl.build(:theme_asset)
end end
describe 'file is a picture' do describe 'file is a picture' do
@ -63,7 +63,7 @@ describe ThemeAsset do
@asset.source = FixturedAsset.open('5k.png') @asset.source = FixturedAsset.open('5k.png')
@asset.save! @asset.save!
another_asset = Factory.build(:theme_asset, :site => @asset.site) another_asset = FactoryGirl.build(:theme_asset, :site => @asset.site)
another_asset.source = FixturedAsset.open('5k.png') another_asset.source = FixturedAsset.open('5k.png')
another_asset.valid?.should be_false another_asset.valid?.should be_false
another_asset.errors[:local_path].should_not be_blank another_asset.errors[:local_path].should_not be_blank
@ -94,8 +94,8 @@ describe ThemeAsset do
before(:each) do before(:each) do
ThemeAsset.any_instance.stubs(:site_id).returns('test') ThemeAsset.any_instance.stubs(:site_id).returns('test')
@asset = Factory.build(:theme_asset, { @asset = FactoryGirl.build(:theme_asset, {
:site => Factory.build(:site), :site => FactoryGirl.build(:site),
:plain_text_name => 'test', :plain_text_name => 'test',
:plain_text => 'Lorem ipsum', :plain_text => 'Lorem ipsum',
:performing_plain_text => true :performing_plain_text => true

View File

@ -86,7 +86,6 @@ end
Spork.each_run do Spork.each_run do
# This code will be run each time you run your specs. # This code will be run each time you run your specs.
Locomotive.configure_for_test(true)
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# loading ruby file directly breaks the tests # loading ruby file directly breaks the tests