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/
permanent
doc/bushido
*.swp

14
Gemfile
View File

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

View File

@ -19,8 +19,8 @@ h2. Gems
Here is a short list of main gems used in the application.
* Rails 3.0.9
* Mongoid 2.0.2 (with MongoDB 1.6)
* Rails 3.0.10
* Mongoid 2.0.2 (with MongoDB 1.8)
* Liquid
* Devise
* Carrierwave
@ -34,8 +34,8 @@ See the "official website":http://www.locomotivecms.com
h2. Team
* Developers: "Didier Lafforgue":http://www.nocoffee.fr, "Jacques Crocker":http://www.railsjedi.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)
* 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, "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
* IE maintainer: "Alex Sanford":https://github.com/alexsanford

View File

@ -7,6 +7,10 @@ module Admin
before_filter :set_content_type
before_filter :block_content_type_with_disabled_api
before_filter :sanitize_content_params, :only => :create
def create
@content = @content_type.contents.build(params[:content])
@ -32,7 +36,23 @@ module Admin
def set_content_type
@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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ module Admin::ContentTypesHelper
@content_types = current_site.content_types.ordered.
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
@content_types.delete(@content_type)

View File

@ -22,7 +22,7 @@ module Admin::CustomFieldsHelper
def options_for_highlighted_field(content_type, collection_name)
custom_fields_collection_name = "ordered_#{collection_name.singularize}_custom_fields".to_sym
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] }
end
@ -40,9 +40,7 @@ module Admin::CustomFieldsHelper
end
def options_for_association_target
current_site.content_types.collect do |c|
c.persisted? ? [c.name, c.content_klass.to_s] : nil
end.compact
current_site.reload.content_types.collect { |c| [c.name, c.content_klass.to_s] }
end
def options_for_reverse_lookups(my_content_type)
@ -86,7 +84,7 @@ module Admin::CustomFieldsHelper
end
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?
grouped_contents = content_type.list_or_group_contents

View File

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

View File

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

View File

@ -32,7 +32,7 @@ module Extensions
end
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.delete_if { |block, elements| elements.empty? }
end

View File

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

View File

@ -9,7 +9,7 @@ class ThemeAssetUploader < CarrierWave::Uploader::Base
end
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
def self.url_for(site, path)

View File

@ -6,10 +6,11 @@
- content_for :actions do
= 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 :import, new_admin_import_url, :class => 'new'
- if can?(:create, Account)
= admin_button_tag t('.new_membership'), new_admin_membership_url, :class => 'new'
%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
.has-many-selector

View File

@ -8,7 +8,7 @@
- if multi_sites?
- 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')

View File

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

View File

@ -9,5 +9,5 @@
%span!= t('.updated_at')
%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

View File

@ -1,7 +1,7 @@
<%
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}"
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
wip: --tags @wip:3 --wip features

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -159,6 +159,7 @@ pt-BR:
it: Italiano
nl: Holandês
es: Espanhol
ru: Russo
ask_for_name: "Por favor preencha o novo nome"
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:
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:
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:
messages:
@ -27,7 +163,7 @@ nl:
title: "Pagina niet gevonden"
body: "Inhoud van de 404 pagina"
other:
body: "{% breid 'parent' uit %}"
body: "{% extends 'parent' %}"
pagination:
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
match '/' => 'admin/rendering#show'
match '*path/edit' => 'admin/rendering#show', :defaults => { :editing => true }
match '*path/edit' => 'admin/rendering#edit'
match '*path' => 'admin/rendering#show'
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:
- export site
- super_finder
- traffic statistics
- asset picker (content instance)

View File

@ -7,3 +7,7 @@
- better spanish translations (#161, #162)
- fix carrierwave version to 0.5.6 (#163)
- 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"
When I go to site settings
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 "Access points"
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:
Given I have the site: "test site" set up
And I have a designer and an author
And I have an image theme asset named "dog.png"
Scenario: As an unauthenticated user
Given I am not authenticated
@ -20,6 +21,8 @@ Background:
And I should see "Snippets"
And I should see "Style and javascript"
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
Given I am an authenticated "designer"
@ -29,6 +32,8 @@ Background:
And I should see "Snippets"
And I should see "Style and javascript"
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
Given I am an authenticated "author"
@ -38,3 +43,5 @@ Background:
And I should not see "Snippets"
And I should not see "Style and javascript"
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:
Given I have the site: "test site" set up
Scenario: Successful authentication
Scenario: Successfully logging in
When I go to login
And I fill in "Email" with "admin@locomotiveapp.org"
And I fill in "Password" with "easyone"
And I press "Log in"
Then I should see "Listing pages"
Scenario: Failed authentication
Scenario: Attempting to login with an invalid emai or password
When I go to login
And I fill in "Email" with "admin@locomotiveapp.org"
And I fill in "Password" with ""
And I press "Log in"
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
"""
# @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
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}
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|
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|
if (target_name = field.delete('target')).present?
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
Given /^the editable element "([^"]*)" in the "([^"]*)" page with the content "([^"]*)"$/ do |slug, page_slug, content|
page = @site.pages.where(:slug => page_slug).first
@ -15,3 +11,14 @@ Given /^the editable element "([^"]*)" for the "([^"]*)" block in the "([^"]*)"
page.find_editable_element(block, slug).content = content
page.save!
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
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.should be_valid
page
@ -26,7 +26,12 @@ end
# try to render a page by slug
When /^I view the rendered page at "([^"]*)"$/ do |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
# 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"
#
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
@admin = @site.memberships.first.account
@ -13,8 +13,8 @@ Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site
end
Given /^I have a designer and an author$/ do
Factory(:designer, :site => Site.first)
Factory(:author, :site => Site.first)
FactoryGirl.create(:designer, :site => Site.first)
FactoryGirl.create(:author, :site => Site.first)
end
Then /^I should be a administrator of the "([^"]*)" site$/ do |name|

View File

@ -2,7 +2,7 @@
# helps create a theme asset
def create_plain_text_asset(name, type)
asset = Factory.build(:theme_asset, {
asset = FactoryGirl.build(:theme_asset, {
:site => @site,
:plain_text_name => name,
:plain_text => 'Lorem ipsum',
@ -24,8 +24,23 @@ Given /^a stylesheet asset named "([^"]*)"$/ do |name|
@asset = create_plain_text_asset(name, 'stylesheet')
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
Then /^I should see "([^"]*)" as theme asset code$/ do |code|
find(:css, "#theme_asset_plain_text").text.should == code
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'],
:pdf => ['application/pdf', 'application/x-pdf'],
: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']
}
end

View File

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

View File

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

View File

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

View File

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

View File

@ -26,6 +26,7 @@ module Locomotive
:block => @context[:current_block].try(:name),
:slug => @slug,
:hint => @options[:hint],
:priority => @options[:priority] || 0,
:default_attribute => @options[:default],
:default_content => default_content_option,
:assignable => @options[:assignable],

View File

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

View File

@ -17,7 +17,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = '>= 1.3.6'
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 'devise', '1.3.4'
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 'inherited_resources', '~> 1.1.2'
s.add_dependency 'cells'
s.add_dependency 'highline'
s.add_dependency 'sanitize'
s.add_dependency 'json_pure', '1.5.1'
s.add_dependency 'bushido'
@ -43,13 +45,13 @@ Gem::Specification.new do |s|
s.add_dependency 'dragonfly', '~> 0.9.1'
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 'fog', '0.8.2'
s.add_dependency 'mimetype-fu'
s.add_dependency 'actionmailer-with-request'
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_mongoid', '1.0.2'
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) {
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(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++) {
@ -27,7 +27,7 @@ $(document).ready(function() {
for (var j = 0; j < obj.items.length; j++) {
var innerObj = obj.items[j];
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++;
}
}
@ -36,8 +36,7 @@ $(document).ready(function() {
} else {
if ($.inArray(obj[1], context.data.taken_ids) == -1)
{
var option = new Option("", obj[1], false, false);
$(option).text(obj[0]);
var option = makeOption(obj[0], obj[1], false, false);
context.select.append(option);
}
}

View File

@ -121,7 +121,6 @@ var InlineEditorToolbar = {
_bindEvents: function() {
var self = this;
var fullpath = $('meta[name=page-fullpath]').attr('content');
this.form.live('submit', function (e) { $(this).callRemote(); e.stopPropagation(); e.preventDefault();
}).bind('ajax:complete', function() { self.resetForm();
@ -146,7 +145,8 @@ var InlineEditorToolbar = {
window.location.href = window.location.href; break;
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
self.toggle(); break;

View File

@ -61,8 +61,6 @@ $.fn.imagepicker = function(options) {
asset.removeClass('new-asset');
$('.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 {
overflow: auto;
height: 571px;
height: 275px;
}
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/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>

View File

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

View File

@ -52,3 +52,10 @@ Object.size = function(obj) {
}
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
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

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 ##
Factory.define :site do |s|
s.name 'Acme Website'
s.subdomain 'acme'
s.created_at Time.now
end
FactoryGirl.define do
Factory.define "test site", :parent => :site do |s|
s.name 'Locomotive test website'
s.subdomain 'test'
s.after_build do |site_test|
## Site ##
factory :site do
name 'Acme Website'
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
end
Factory.define "another site", :parent => "test site" do |s|
s.name "Locomotive test website #2"
s.subdomain "test2"
end
factory "another site" do
name "Locomotive test website #2"
subdomain "test2"
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|
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
end
# Accounts ##
factory :account do
name 'Bart Simpson'
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
end
## Memberships ##
factory :membership do
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
## Assets ##
factory :asset do
site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
## Theme assets ##
factory :theme_asset do
site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
## Content types ##
factory :content_type do
name 'My project'
site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
end
Factory.define "valid site", :parent => "site" do |s|
# s.after_build { |valid_site| valid_site.stubs(:valid?).returns(true) }
end
# Accounts ##
Factory.define :account do |a|
a.name 'Bart Simpson'
a.email 'bart@simpson.net'
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 ##
Factory.define :membership do |m|
m.role 'admin'
m.account { Account.where(:name => "Bart Simpson").first || Factory('admin user') }
end
Factory.define :admin, :parent => :membership do |m|
m.role 'admin'
m.account { Factory('admin user', :locale => 'en') }
end
Factory.define :designer, :parent => :membership do |m|
m.role 'designer'
m.account { Factory('frenchy user', :locale => 'en') }
end
Factory.define :author, :parent => :membership do |m|
m.role 'author'
m.account { Factory('brazillian user', :locale => 'en') }
end
## 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

View File

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

View File

@ -5,7 +5,7 @@ describe Locomotive::Export do
context '#content_type' do
before(:each) do
site = Factory.build('another site')
site = FactoryGirl.build('another site')
Site.stubs(:find).returns(site)
project_type = build_project_type(site)
project_type.contents.build(:title => 'Project #1', :description => 'Lorem ipsum', :active => true)
@ -39,7 +39,7 @@ describe Locomotive::Export do
end
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 => 'My Description', :_alias => 'description', :kind => 'text'
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)
Object.send(:remove_const, 'TestProject') rescue nil
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 => 'Projects', :kind => 'has_many', :_alias => 'projects', :target => 'TestProject'
content_type.content_custom_fields.build :label => 'Bio', :_alias => 'bio', :kind => 'text'
@ -62,7 +62,7 @@ describe Locomotive::Export do
context '#zipfile' do
before(:all) do
@site = Factory('another site')
@site = FactoryGirl.create('another site')
# first import a brand new site
self.import_it

View File

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

View File

@ -2,15 +2,10 @@ require 'spec_helper'
describe Locomotive::Import::Job do
# before(:all) do
# # Site.destroy_all
# # Locomotive.configure_for_test(true)
# end
context 'when successful' 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.perform
@ -115,7 +110,7 @@ describe Locomotive::Import::Job do
context 'with an existing site' 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.perform

View File

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

View File

@ -3,8 +3,11 @@ require 'spec_helper'
describe Locomotive::Liquid::Drops::Contents do
before(:each) do
@site = Factory.build(:site)
@content_type = Factory.build(:content_type, :site => @site, :slug => 'projects')
# Reload the file (needed for spork)
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
it 'retrieves a content type from a slug' do
@ -22,6 +25,26 @@ describe Locomotive::Liquid::Drops::Contents do
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 = {})
assigns = {
'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 }))
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

View File

@ -3,8 +3,8 @@ require 'spec_helper'
describe Locomotive::Liquid::Drops::Page do
before(:each) do
site = Factory.build(:site)
@home = Factory.build(:page, :site => site, :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.")
site = FactoryGirl.build(:site)
@home = FactoryGirl.build(:page, :site => site, :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.")
end
context '#rendering tree' do
@ -43,7 +43,7 @@ describe Locomotive::Liquid::Drops::Page do
context '#parent' 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
it 'renders title of parent page' do
@ -55,7 +55,7 @@ describe Locomotive::Liquid::Drops::Page do
context '#breadcrumbs' 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
it 'renders breadcrumbs of current page' do
@ -71,7 +71,7 @@ describe Locomotive::Liquid::Drops::Page do
end
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 !'))

View File

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

View File

@ -233,7 +233,7 @@ describe Locomotive::Liquid::Filters::Html do
klass = Class.new
klass.class_eval do
def registers
{ :site => Factory.build(:site, :id => fake_bson_id(42)) }
{ :site => FactoryGirl.build(:site, :id => fake_bson_id(42)) }
end
def fake_bson_id(id)

View File

@ -3,10 +3,10 @@ require 'spec_helper'
describe Locomotive::Liquid::Filters::Resize do
before :each do
@site = Factory.create(:site)
@theme_asset = Factory.create(:theme_asset, :source => FixturedAsset.open('5k.png'), :site => @site)
@site = FactoryGirl.create(: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"
@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_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 })

View File

@ -27,8 +27,8 @@ describe Locomotive::Liquid::Tags::Editable::Content do
context 'inheriting from a parent' do
before :each do
@parent = Factory.build(:page)
@child = Factory.build(:page)
@parent = FactoryGirl.build(:page)
@child = FactoryGirl.build(:page)
@child.stubs(:parent).returns(@parent)
end
@ -58,7 +58,7 @@ describe Locomotive::Liquid::Tags::Editable::Content do
context 'reading from the same page' do
before :each do
@page = Factory.build(:page)
@page = FactoryGirl.build(:page)
end
it 'should return the previously defined field' do

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe Locomotive::Liquid::Tags::Nav do
before(:each) do
@home = Factory.build(:page)
@home = FactoryGirl.build(:page)
home_children = [
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)
@ -24,7 +24,7 @@ describe Locomotive::Liquid::Tags::Nav do
pages = [@home]
pages.stubs(:root).returns(pages)
pages.stubs(:minimal_attributes).returns(pages) # iso
@site = Factory.build(:site)
@site = FactoryGirl.build(:site)
@site.stubs(:pages).returns(pages)
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']),
'current_page' => options[:page] || 1
}, {
:page => Factory.build(:page)
:page => FactoryGirl.build(:page)
}, true)
end

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe Locomotive::Liquid::Tags::SEO 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
describe 'rendering' do
@ -80,7 +80,7 @@ describe Locomotive::Liquid::Tags::SEO do
context "when content instance" 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'
end
end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ describe ContentInstance do
before(:each) do
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 => 'Description', :kind => 'Text'
@content_type.content_custom_fields.build :label => 'Visible ?', :kind => 'Text', :_alias => 'visible'
@ -111,8 +111,8 @@ describe ContentInstance do
describe '#api' do
before(:each) do
@account_1 = Factory.build('admin user', :id => fake_bson_id('1'))
@account_2 = Factory.build('frenchy user', :id => fake_bson_id('2'))
@account_1 = FactoryGirl.build('admin user', :id => fake_bson_id('1'))
@account_2 = FactoryGirl.build('frenchy user', :id => fake_bson_id('2'))
@content_type.api_enabled = true
@content_type.api_accounts = ['', @account_1.id, @account_2.id]

View File

@ -9,7 +9,7 @@ describe ContentType do
context 'when validating' 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.should be_valid
end
@ -18,35 +18,35 @@ describe ContentType do
%w{site name}.each do |field|
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.errors[field.to_sym].should == ["can't be blank"]
end
end
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.errors[:slug].should == ["can't be blank"]
end
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.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"]
end
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.errors[:content_custom_fields].should == ["is too small (minimum element number is 1)"]
end
%w(created_at updated_at).each do |_alias|
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.valid?.should be_false
field.errors[:_alias].should == ['is reserved']
@ -58,7 +58,7 @@ describe ContentType do
context '#ordered_contents' 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_2 = stub('content_2', :name => 'Sacha', :_position_in_list => 1)
@content_type.stubs(:contents).returns([@content_1, @content_2])
@ -95,9 +95,9 @@ describe ContentType do
describe 'custom fields' do
before(:each) do
site = Factory.build(:site)
site = FactoryGirl.build(: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 => 'Active', :kind => 'boolean'
# ContentType.logger = Logger.new($stdout)

View File

@ -3,14 +3,14 @@ require 'spec_helper'
describe EditableElement do
before(:each) do
@site = Factory(:site)
@site = FactoryGirl.create(:site)
@home = @site.pages.root.first
@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_2 = Factory(:page, :slug => 'sub_page_2', :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 = 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
context 'in sub pages level #1' do

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -86,7 +86,6 @@ end
Spork.each_run do
# 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 }
# loading ruby file directly breaks the tests