merge Did master

This commit is contained in:
Kev Zettler 2011-07-06 13:41:27 -07:00
commit e78726caa4
293 changed files with 6150 additions and 3056 deletions

1
.rspec Normal file
View File

@ -0,0 +1 @@
--colour

43
Gemfile
View File

@ -2,28 +2,32 @@ source :rubygems
# add in all the runtime dependencies
gem 'rake', '0.8.7'
gem 'rake', '0.9.2'
gem 'rails', '>= 3.0.7'
gem 'rails', '3.0.9'
gem 'warden'
gem 'devise', '= 1.1.3'
gem 'devise', '1.3.4'
gem 'mongoid', '~> 2.0.2'
gem 'bson_ext', '~> 1.3.0'
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.7', :require => 'mongoid_acts_as_tree'
gem 'will_paginate'
gem 'haml', '3.0.25'
gem 'haml', '3.1.2'
gem 'sass', '3.1.2'
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
gem 'formtastic', '~> 1.2.3'
gem 'inherited_resources', '~> 1.1.2'
gem 'rmagick', '2.12.2'
gem 'locomotive_carrierwave', '0.5.0.1.beta3', :require => 'carrierwave'
gem 'locomotive_carrierwave', '0.5.4.beta3'
gem 'dragonfly', '~> 0.9.1'
gem 'rack-cache', :require => 'rack/cache'
gem 'custom_fields', '1.0.0.beta.15'
gem 'fog', '0.3.7'
gem 'custom_fields', '1.0.0.beta.21'
gem 'cancan'
gem 'fog', '0.8.2'
gem 'mimetype-fu'
gem 'actionmailer-with-request', :require => 'actionmailer_with_request'
gem 'heroku', '1.19.1'
@ -38,37 +42,38 @@ gem 'SystemTimer', :platforms => :ruby_18
# The rest of the dependencies are for use when in the locomotive dev environment
group :development do
# Using unicorn_rails instead of webrick (default server)
gem 'unicorn'
gem 'unicorn' # Using unicorn_rails instead of webrick (default server)
gem 'rspec-rails', '2.6.1' # in order to have rspec tasks and generators
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 'bushido_stub', :git => 'git://github.com/did/bushido_stub.git'
# :path => '../gems/bushido_stub'
# gem 'bushido'
end
group :production do
gem 'bushido'
gem 'cucumber-rails', '1.0.2'
end
group :test do
gem 'autotest'
gem 'ZenTest'
gem 'growl-glue'
gem 'rspec-rails', '2.3.1'
gem 'rspec-rails', '2.6.1'
gem 'factory_girl_rails'
gem 'pickle'
gem 'xpath', :git => 'https://github.com/wunderbread/xpath.git'
gem 'xpath', '~> 0.1.4'
gem 'capybara'
gem 'database_cleaner'
gem 'cucumber', '0.8.5'
gem 'cucumber-rails'
gem 'spork'
gem 'launchy'
gem 'mocha', :git => 'git://github.com/floehopper/mocha.git'
end
group :production do
gem 'bushido'
end

View File

@ -7,17 +7,10 @@ GIT
GIT
remote: git://github.com/floehopper/mocha.git
revision: 6da1242f26b12a24c4fcf67bf5921a25bc1bc88d
revision: d03843e763f4e5ceadb66bcb4c530d6c5d0cb293
specs:
mocha (0.9.12.20110213002255)
GIT
remote: https://github.com/wunderbread/xpath.git
revision: d04da707886287e7dfe82705fda5b3d4f65e94c3
specs:
xpath (0.1.2)
nokogiri (~> 1.4)
GEM
remote: http://rubygems.org/
specs:
@ -29,14 +22,14 @@ GEM
SystemTimer (1.2.3)
ZenTest (4.5.0)
abstract (1.0.0)
actionmailer (3.0.7)
actionpack (= 3.0.7)
mail (~> 2.2.15)
actionmailer (3.0.9)
actionpack (= 3.0.9)
mail (~> 2.2.19)
actionmailer-with-request (0.3.0)
rails (>= 3)
actionpack (3.0.7)
activemodel (= 3.0.7)
activesupport (= 3.0.7)
actionpack (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
builder (~> 2.1.2)
erubis (~> 2.6.6)
i18n (~> 0.5.0)
@ -44,19 +37,19 @@ GEM
rack-mount (~> 0.6.14)
rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
activemodel (3.0.7)
activesupport (= 3.0.7)
activemodel (3.0.9)
activesupport (= 3.0.9)
builder (~> 2.1.2)
i18n (~> 0.5.0)
activerecord (3.0.7)
activemodel (= 3.0.7)
activesupport (= 3.0.7)
arel (~> 2.0.2)
activerecord (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
arel (~> 2.0.10)
tzinfo (~> 0.3.23)
activeresource (3.0.7)
activemodel (= 3.0.7)
activesupport (= 3.0.7)
activesupport (3.0.7)
activeresource (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
activesupport (3.0.9)
archive-tar-minitar (0.5.2)
arel (2.0.10)
autotest (4.4.6)
@ -65,39 +58,37 @@ GEM
bson (1.3.1)
bson_ext (1.3.1)
builder (2.1.2)
bushido (0.0.17)
bushido (0.0.29)
highline (>= 1.6.1)
json (>= 1.4.6)
rest-client (>= 1.6.1)
capybara (0.4.0)
celerity (>= 0.7.9)
culerity (>= 0.2.4)
cancan (1.6.5)
capybara (1.0.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
selenium-webdriver (>= 0.0.27)
xpath (~> 0.1.2)
celerity (0.8.9)
selenium-webdriver (~> 0.2.0)
xpath (~> 0.1.4)
childprocess (0.1.9)
ffi (~> 1.0.6)
columnize (0.3.2)
configuration (1.2.0)
columnize (0.3.3)
configuration (1.3.1)
crack (0.1.8)
cucumber (0.8.5)
builder (~> 2.1.2)
diff-lcs (~> 1.1.2)
gherkin (~> 2.1.4)
json_pure (~> 1.4.3)
term-ansicolor (~> 1.0.4)
cucumber-rails (0.3.2)
cucumber (>= 0.8.0)
culerity (0.2.15)
custom_fields (1.0.0.beta.15)
activesupport (>= 3.0.7)
locomotive_carrierwave
cucumber (1.0.0)
builder (>= 2.1.2)
diff-lcs (>= 1.1.2)
gherkin (~> 2.4.1)
json (>= 1.4.6)
term-ansicolor (>= 1.0.5)
cucumber-rails (1.0.2)
capybara (>= 1.0.0)
cucumber (~> 1.0.0)
nokogiri (>= 1.4.6)
custom_fields (1.0.0.beta.21)
activesupport (~> 3.0.9)
mongoid (= 2.0.2)
daemons (1.1.3)
daemons (1.1.4)
database_cleaner (0.6.7)
delayed_job (2.1.4)
activesupport (~> 3.0)
@ -105,10 +96,13 @@ GEM
delayed_job_mongoid (1.0.2)
delayed_job (~> 2.1.1)
mongoid (~> 2.0.0.rc)
devise (1.1.3)
devise (1.3.4)
bcrypt-ruby (~> 2.1.2)
warden (~> 0.10.7)
orm_adapter (~> 0.0.3)
warden (~> 1.0.3)
diff-lcs (1.1.2)
dragonfly (0.9.4)
rack
erubis (2.6.6)
abstract (>= 1.0.0)
excon (0.6.3)
@ -117,29 +111,29 @@ GEM
factory_girl (~> 1.3)
railties (>= 3.0.0)
ffi (1.0.9)
fog (0.3.7)
fog (0.8.2)
builder
excon (>= 0.2.3)
formatador (>= 0.0.15)
excon (~> 0.6.1)
formatador (>= 0.1.3)
json
mime-types
net-ssh (~> 2.0.23)
nokogiri (~> 1.4.3.1)
net-ssh (>= 2.1.3)
nokogiri (>= 1.4.4)
ruby-hmac
formatador (0.1.4)
formtastic (1.2.4)
actionpack (>= 2.3.7)
activesupport (>= 2.3.7)
i18n (~> 0.4)
gherkin (2.1.5)
trollop (~> 1.16.2)
gherkin (2.4.1)
json (>= 1.4.6)
growl-glue (1.0.7)
haml (3.0.25)
haml (3.1.2)
has_scope (0.5.0)
heroku (1.19.1)
activesupport (>= 2.1.0)
launchy (~> 0.3.2)
rest-client (>= 1.4.0, < 1.7.0)
rest-client (< 1.7.0, >= 1.4.0)
highline (1.6.2)
httparty (0.7.8)
crack (= 0.1.8)
@ -149,16 +143,16 @@ GEM
responders (~> 0.6.0)
jammit (0.6.3)
yui-compressor (>= 0.9.3)
json (1.5.1)
json_pure (1.4.6)
kgio (2.4.1)
json (1.5.3)
json_pure (1.5.3)
kgio (2.5.0)
launchy (0.3.7)
configuration (>= 0.0.5)
rake (>= 0.8.1)
linecache (0.43)
linecache19 (0.5.12)
ruby_core_source (>= 0.1.4)
locomotive_carrierwave (0.5.0.1.beta3)
locomotive_carrierwave (0.5.4.beta3)
activesupport (~> 3.0)
locomotive_jammit-s3 (0.5.4.4)
jammit (>= 0.5.4)
@ -181,50 +175,56 @@ GEM
activemodel (~> 3.0)
mongo (~> 1.3)
tzinfo (~> 0.3.22)
net-ssh (2.0.24)
nokogiri (1.4.3.1)
open4 (1.0.1)
net-ssh (2.1.4)
nokogiri (1.5.0)
open4 (1.1.0)
orm_adapter (0.0.5)
pickle (0.4.7)
cucumber (>= 0.8)
rake
polyglot (0.3.1)
proxies (0.2.1)
rack (1.2.3)
rack-cache (1.0.2)
rack (>= 0.4)
rack-mount (0.6.14)
rack (>= 1.0.0)
rack-test (0.5.7)
rack (>= 1.0)
rails (3.0.7)
actionmailer (= 3.0.7)
actionpack (= 3.0.7)
activerecord (= 3.0.7)
activeresource (= 3.0.7)
activesupport (= 3.0.7)
rails (3.0.9)
actionmailer (= 3.0.9)
actionpack (= 3.0.9)
activerecord (= 3.0.9)
activeresource (= 3.0.9)
activesupport (= 3.0.9)
bundler (~> 1.0)
railties (= 3.0.7)
railties (3.0.7)
actionpack (= 3.0.7)
activesupport (= 3.0.7)
railties (= 3.0.9)
railties (3.0.9)
actionpack (= 3.0.9)
activesupport (= 3.0.9)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (~> 0.14.4)
rake (0.8.7)
raindrops (0.7.0)
rake (0.9.2)
rdoc (3.8)
responders (0.6.4)
rest-client (1.6.3)
mime-types (>= 1.16)
rmagick (2.12.2)
rspec (2.3.0)
rspec-core (~> 2.3.0)
rspec-expectations (~> 2.3.0)
rspec-mocks (~> 2.3.0)
rspec-core (2.3.1)
rspec-expectations (2.3.0)
rspec (2.6.0)
rspec-core (~> 2.6.0)
rspec-expectations (~> 2.6.0)
rspec-mocks (~> 2.6.0)
rspec-core (2.6.4)
rspec-expectations (2.6.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.3.0)
rspec-rails (2.3.1)
rspec-mocks (2.6.0)
rspec-rails (2.6.1)
actionpack (~> 3.0)
activesupport (~> 3.0)
railties (~> 3.0)
rspec (~> 2.3.0)
rspec (~> 2.6.0)
ruby-debug (0.10.4)
columnize (>= 0.1)
ruby-debug-base (~> 0.10.4.0)
@ -244,8 +244,9 @@ GEM
rubyzip (0.9.4)
s3 (0.3.8)
proxies (~> 0.2.0)
selenium-webdriver (0.2.1)
childprocess (>= 0.1.7)
sass (3.1.2)
selenium-webdriver (0.2.2)
childprocess (>= 0.1.9)
ffi (>= 1.0.7)
json_pure
rubyzip
@ -254,14 +255,16 @@ GEM
thor (0.14.6)
treetop (1.4.9)
polyglot (>= 0.3.1)
trollop (1.16.2)
tzinfo (0.3.27)
unicorn (3.6.2)
kgio (~> 2.3)
tzinfo (0.3.29)
unicorn (4.0.1)
kgio (~> 2.4)
rack
warden (0.10.7)
rack (>= 1.0.0)
raindrops (~> 0.6)
warden (1.0.4)
rack (>= 1.0)
will_paginate (2.3.15)
xpath (0.1.4)
nokogiri (~> 1.3)
yui-compressor (0.9.6)
POpen4 (>= 0.1.4)
@ -277,24 +280,26 @@ DEPENDENCIES
bson_ext (~> 1.3.0)
bushido
bushido_stub!
cancan
capybara
cucumber (= 0.8.5)
cucumber-rails
custom_fields (= 1.0.0.beta.15)
cucumber-rails (= 1.0.2)
custom_fields (= 1.0.0.beta.21)
database_cleaner
delayed_job (= 2.1.4)
delayed_job_mongoid (= 1.0.2)
devise (= 1.1.3)
devise (= 1.3.4)
dragonfly (~> 0.9.1)
factory_girl_rails
fog (= 0.3.7)
fog (= 0.8.2)
formtastic (~> 1.2.3)
growl-glue
haml (= 3.0.25)
haml (= 3.1.2)
heroku (= 1.19.1)
httparty (>= 0.6.1)
inherited_resources (~> 1.1.2)
launchy
locomotive_carrierwave (= 0.5.0.1.beta3)
linecache (= 0.43)
locomotive_carrierwave (= 0.5.4.beta3)
locomotive_jammit-s3
locomotive_liquid (= 2.2.2)
locomotive_mongoid_acts_as_tree (= 0.1.5.7)
@ -302,15 +307,17 @@ DEPENDENCIES
mocha!
mongoid (~> 2.0.2)
pickle
rails (>= 3.0.7)
rake (= 0.8.7)
rack-cache
rails (= 3.0.9)
rake (= 0.9.2)
rmagick (= 2.12.2)
rspec-rails (= 2.3.1)
rspec-rails (= 2.6.1)
ruby-debug
ruby-debug19
rubyzip
sass (= 3.1.2)
spork
unicorn
warden
will_paginate
xpath!
xpath (~> 0.1.4)

View File

@ -19,7 +19,7 @@ h2. Gems
Here is a short list of main gems used in the application.
* Rails 3.0.7
* Rails 3.0.9
* Mongoid 2.0.2 (with MongoDB 1.6)
* Liquid
* Devise
@ -35,7 +35,7 @@ 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)
* 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)
* UI Designer: "Sacha Greif":http://www.sachagreif.com
h2. Support
@ -53,3 +53,4 @@ h2. Contact
Feel free to contact me at didier at nocoffee dot fr.
Copyright (c) 2011 NoCoffee, released under the MIT license
...

View File

@ -1,20 +1,21 @@
require File.expand_path('../config/application', __FILE__)
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'
require 'rdoc/task'
require 'rubygems/package_task'
Locomotive::Application.load_tasks
gemspec = eval(File.read('locomotive_cms.gemspec'))
Rake::GemPackageTask.new(gemspec) do |pkg|
Gem::PackageTask.new(gemspec) do |pkg|
pkg.gem_spec = gemspec
end
desc "build the gem and release it to rubygems.org"
desc 'build the gem and release it to rubygems.org'
task :release => :gem do
sh "gem push pkg/locomotive_cms-#{gemspec.version}.gem"
sh "gem push pkg/custom_fields-#{gemspec.version}.gem"
end
task :default => [:spec, :cucumber]
task :default => [:spec, :cucumber]

View File

@ -1,25 +0,0 @@
module Admin
class AssetCollectionsController < BaseController
sections 'assets'
before_filter :set_collections
def index
if not @asset_collections.empty?
redirect_to(edit_admin_asset_collection_url(@asset_collections.first)) and return
end
end
def show
@asset_collection = current_site.asset_collections.find(params[:id])
render :action => 'edit'
end
protected
def set_collections
@asset_collections = current_site.asset_collections.not_internal.order_by([[:name, :asc]])
end
end
end

View File

@ -1,29 +1,55 @@
module Admin
class AssetsController < BaseController
sections 'assets'
include ActionView::Helpers::SanitizeHelper
include ActionView::Helpers::TextHelper
before_filter :set_collections_and_current_collection
respond_to :json, :only => [:index, :create, :destroy]
respond_to :json, :only => :update
def create
create! { edit_admin_asset_collection_url(@asset_collection) }
def index
index! do |response|
response.json do
render :json => { :assets => @assets.collect { |asset| asset_to_json(asset) } }
end
end
end
def update
update! { edit_admin_asset_collection_url(@asset_collection) }
def create
@asset = current_site.assets.build(:name => params[:name], :source => params[:file])
create! do |success, failure|
success.json do
render :json => asset_to_json(@asset)
end
failure.json do
render :json => { :status => 'error' }
end
end
rescue Exception => e
render :json => { :status => 'error', :message => e.message }
end
protected
def begin_of_association_chain
@asset_collection
def collection
if params[:image]
@assets ||= begin_of_association_chain.assets.only_image
else
@assets ||= begin_of_association_chain.assets
end
end
def set_collections_and_current_collection
@asset_collections = current_site.asset_collections.not_internal.order_by([[:name, :asc]])
@asset_collection = current_site.asset_collections.find(params[:collection_id])
def asset_to_json(asset)
{
:status => 'success',
:filename => asset.source_filename,
:short_name => truncate(asset.name, :length => 15),
:extname => truncate(asset.extname, :length => 3),
:content_type => asset.content_type,
:url => asset.source.url,
:vignette_url => asset.vignette_url,
:destroy_url => admin_asset_url(asset, :json)
}
end
end

View File

@ -9,11 +9,13 @@ module Admin
before_filter :require_site
load_and_authorize_resource
before_filter :validate_site_membership
before_filter :set_locale
helper_method :sections, :current_site_url, :site_url, :page_url
helper_method :sections, :current_site_url, :site_url, :page_url, :current_ability
# https://rails.lighthouseapp.com/projects/8994/tickets/1905-apphelpers-within-plugin-not-being-mixed-in
Dir[File.dirname(__FILE__) + "/../../helpers/**/*_helper.rb"].each do |file|
@ -26,8 +28,24 @@ module Admin
respond_to :html
rescue_from CanCan::AccessDenied do |exception|
::Locomotive::Logger.info "[CanCan::AccessDenied] #{exception.inspect}"
if request.xhr?
render :json => { :error => exception.message }
else
flash[:alert] = exception.message
redirect_to admin_pages_url
end
end
protected
def current_ability
@current_ability ||= Ability.new(current_admin, current_site)
end
def require_admin
authenticate_admin!
end

View File

@ -5,7 +5,11 @@ module Admin
before_filter :set_content_type
respond_to :json, :only => :update
respond_to :json, :only => [:update, :sort]
skip_load_and_authorize_resource
before_filter :authorize_content
def index
@contents = @content_type.list_or_group_contents
@ -20,7 +24,7 @@ module Admin
end
def sort
@content_type.sort_contents!(params[:order])
@content_type.sort_contents!(params[:children])
respond_with(@content_type, :location => admin_contents_url(@content_type.slug))
end
@ -39,5 +43,9 @@ module Admin
set_content_type
end
def authorize_content
authorize! params[:action].to_sym, ContentInstance
end
end
end

View File

@ -9,6 +9,8 @@ module Admin
before_filter :require_admin, :only => :new
skip_load_and_authorize_resource
def new
if site = current_admin.sites.detect { |s| s._id.to_s == params[:target_id] }
if Rails.env == 'development'

View File

@ -1,5 +1,5 @@
module Admin
class CurrentSitesController < BaseController
class CurrentSiteController < BaseController
defaults :instance_name => 'site'
@ -7,6 +7,10 @@ module Admin
actions :edit, :update
skip_load_and_authorize_resource
load_and_authorize_resource :class => 'Site'
respond_to :json, :only => :update
def update

View File

@ -5,6 +5,8 @@ module Admin
before_filter :set_parent_and_fields
skip_load_and_authorize_resource
def edit
@field = @fields.find(params[:id])
render :action => "edit_#{@field.kind.downcase}"
@ -23,13 +25,8 @@ module Admin
protected
def set_parent_and_fields
if params[:parent] == 'asset_collection'
@parent = current_site.asset_collections.where(:slug => params[:slug]).first
@fields = @parent.asset_custom_fields
else
@parent = current_site.content_types.where(:slug => params[:slug]).first
@fields = @parent.content_custom_fields
end
@parent = current_site.content_types.where(:slug => params[:slug]).first
@fields = @parent.content_custom_fields
end
end

View File

@ -0,0 +1,20 @@
module Admin
class ExportController < BaseController
skip_load_and_authorize_resource
before_filter :authorize_export
def new
zipfile = ::Locomotive::Export.run!(current_site, current_site.name.parameterize)
send_file zipfile, :type => 'application/zip', :disposition => 'attachment'
end
protected
def authorize_export
authorize! :export, Site
end
end
end

View File

@ -1,55 +0,0 @@
module Admin
class ImagesController < BaseController
include ActionView::Helpers::SanitizeHelper
include ActionView::Helpers::TextHelper
defaults :collection_name => 'assets', :instance_name => 'asset'
respond_to :json, :only => [:index, :create, :destroy]
def index
index! do |response|
response.json do
render :json => { :images => @assets.collect { |image| image_to_json(image) } }
end
end
end
def create
params[:asset] = { :name => params[:name], :source => params[:file] } if params[:file]
create! do |success, failure|
success.json do
render :json => image_to_json(@asset)
end
failure.json do
render :json => { :status => 'error' }
end
end
rescue Exception => e
render :json => { :status => 'error', :message => e.message }
end
protected
def collection
@assets ||= begin_of_association_chain.assets
end
def begin_of_association_chain
@asset_collection ||= AssetCollection.find_or_create_internal(current_site)
end
def image_to_json(image)
{
:status => 'success',
:name => truncate(image.name, :length => 15),
:url => image.source.url,
:vignette_url => image.vignette_url,
:destroy_url => admin_image_url(image, :json)
}
end
end
end

View File

@ -1,10 +1,14 @@
module Admin
class ImportsController < BaseController
class ImportController < BaseController
sections 'settings', 'site'
actions :show, :new, :create
skip_load_and_authorize_resource
before_filter :authorize_import
def show
@job = Delayed::Job.where({ :job_type => 'import', :site_id => current_site.id }).last
@ -28,7 +32,7 @@ module Admin
:reset => Boolean.set(params[:reset])
})
flash[:notice] = t("flash.admin.imports.create.#{Locomotive.config.delayed_job ? 'notice' : 'done'}")
flash[:notice] = t("flash.admin.import.create.#{Locomotive.config.delayed_job ? 'notice' : 'done'}")
redirect_to Locomotive.config.delayed_job ? admin_import_url : new_admin_import_url
rescue Exception => e
@ -41,5 +45,11 @@ module Admin
end
end
protected
def authorize_import
authorize! :import, Site
end
end
end

View File

@ -15,6 +15,8 @@ module Admin
before_filter :allow_installation?
skip_load_and_authorize_resource
def show
request.get? ? self.handle_get : self.handle_post
end

View File

@ -5,6 +5,7 @@ module Admin
def create
@membership = current_site.memberships.build(params[:membership])
@membership.role = 'author' # force author by default
case @membership.process!
when :create_account
@ -13,7 +14,7 @@ module Admin
respond_with @membership, :location => edit_admin_current_site_url
when :error
respond_with @membership, :flash => true
when :nothing
when :already_created
respond_with @membership, :alert => t('flash.admin.memberships.create.already_created'), :location => edit_admin_current_site_url
end
end

View File

@ -1,5 +1,5 @@
module Admin
class MyAccountsController < BaseController
class MyAccountController < BaseController
sections 'settings', 'account'
@ -7,6 +7,8 @@ module Admin
respond_to :json, :only => :update
skip_load_and_authorize_resource
def update
update! { edit_admin_my_account_url }
end

View File

@ -33,7 +33,7 @@ module Admin
end
def get_path
page = current_site.pages.build(:parent => current_site.pages.find(params[:parent_id]), :slug => params[:slug].slugify)
page = current_site.pages.build(:parent => current_site.pages.find(params[:parent_id]), :slug => params[:slug].permalink)
render :json => { :url => page_url(page), :slug => page.slug }
end

View File

@ -0,0 +1,18 @@
module Admin
class RobotsController < ActionController::Base
include Locomotive::Routing::SiteDispatcher
include Locomotive::Render
before_filter :require_site
respond_to :txt
def show
template = Liquid::Template.parse(current_site.robots_txt)
render :text => template.render('request_host' => self.request.host.downcase)
end
end
end

View File

@ -7,6 +7,8 @@ module Admin
respond_to :xml
skip_load_and_authorize_resource
def show
@pages = current_site.pages.published
end

View File

@ -7,7 +7,7 @@ module Admin
def create
@site = Site.new(params[:site])
@site.memberships.build :account => @current_admin, :admin => true
@site.memberships.build :account => @current_admin, :role => 'admin'
create! { edit_admin_my_account_url }
end

View File

@ -13,7 +13,7 @@ module Admin
before_filter :sanitize_params, :only => [:create, :update]
def index
@assets = ThemeAsset.all_grouped_by_folder(current_site, params[:all])
@assets = ThemeAsset.all_grouped_by_folder(current_site)
@js_and_css_assets = (@assets[:javascripts] || []) + (@assets[:stylesheets] || [])
if request.xhr?
@ -48,9 +48,6 @@ module Admin
def sanitize_params
params[:theme_asset] = { :source => params[:file] } if params[:file]
performing_plain_text = params[:theme_asset][:performing_plain_text]
params[:theme_asset].delete(:content_type) if performing_plain_text.blank? || performing_plain_text == 'false'
end
end

View File

@ -1,7 +1,7 @@
module Admin::AccountsHelper
def admin_on?(site = current_site)
site.memberships.detect { |a| a.admin? && a.account == current_admin }
site.memberships.detect { |m| m.admin? && m.account == current_admin }
end
end

View File

@ -39,6 +39,10 @@ module Admin::BaseHelper
end
end
def admin_item_toggler(object)
image_tag("admin/list/icons/node_#{(cookies["folder-#{object._id}"] != 'none') ? 'open' : 'closed'}.png", :class => 'toggler')
end
def collection_to_js(collection, options = {})
js = collection.collect { |object| object.to_json }

View File

@ -45,15 +45,43 @@ module Admin::CustomFieldsHelper
end.compact
end
def options_for_has_one(field)
target_contents_from_field(field).collect { |c| [c._label, c._id] }
def options_for_has_one(field, value)
self.options_for_has_one_or_has_many(field) do |groups|
grouped_options_for_select(groups.collect do |g|
if g[:items].empty?
nil
else
[g[:name], g[:items].collect { |c| [c._label, c._id] }]
end
end.compact, value)
end
end
alias :options_for_has_many :options_for_has_one
def options_for_has_many(field)
self.options_for_has_one_or_has_many(field)
end
def target_contents_from_field(field)
def options_for_has_one_or_has_many(field, &block)
content_type = field.target.constantize._parent
content_type.ordered_contents
if content_type.groupable?
grouped_contents = content_type.list_or_group_contents
if block_given?
block.call(grouped_contents)
else
grouped_contents.collect do |g|
if g[:items].empty?
nil
else
{ :name => g[:name], :items => g[:items].collect { |c| [c._label, c._id] } }
end
end.compact
end
else
contents = content_type.ordered_contents
contents.collect { |c| [c._label, c._id] }
end
end
end

77
app/models/ability.rb Normal file
View File

@ -0,0 +1,77 @@
class Ability
include CanCan::Ability
ROLES = %w(admin designer author)
def initialize(account, site)
@account, @site = account, site
alias_action :index, :show, :edit, :update, :to => :touch
@membership = @site.memberships.where(:account_id => @account.id).first
return false if @membership.blank?
if @membership.admin?
setup_admin_permissions!
else
setup_default_permissions!
setup_designer_permissions! if @membership.designer?
setup_author_permissions! if @membership.author?
end
end
def setup_default_permissions!
cannot :manage, :all
end
def setup_author_permissions!
can :touch, [Page, ThemeAsset]
can :sort, Page
can :manage, [ContentInstance, Asset]
can :touch, Site do |site|
site == @site
end
end
def setup_designer_permissions!
can :manage, Page
can :manage, ContentInstance
can :manage, ContentType
can :manage, Snippet
can :manage, ThemeAsset
can :manage, Site do |site|
site == @site
end
can :import, Site
can :export, Site
can :point, Site
can :manage, Membership
cannot :change_role, Membership do |membership|
@membership.account_id == membership.account_id || # can not edit myself
membership.admin? # can not modify an administrator
end
end
def setup_admin_permissions!
can :manage, :all
cannot :change_role, Membership do |membership|
@membership.account_id == membership.account_id # can not edit myself
end
end
end

View File

@ -5,9 +5,7 @@ class Account
include Locomotive::Mongoid::Document
# devise modules
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
# attr_accessible :email, :password, :password_confirmation # TODO
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :encryptable, :encryptor => :sha1
## attributes ##
field :name

View File

@ -3,12 +3,11 @@ class Asset
include Mongoid::Document
include Mongoid::Timestamps
## Extensions ##
## extensions ##
include Extensions::Asset::Types
include Extensions::Asset::Vignette
include CustomFields::ProxyClassEnabler
## fields ##
field :name, :type => String
field :content_type, :type => String
field :width, :type => Integer
field :height, :type => Integer
@ -17,32 +16,24 @@ class Asset
mount_uploader :source, AssetUploader
## associations ##
embedded_in :collection, :class_name => 'AssetCollection', :inverse_of => :assets
referenced_in :site
## validations ##
validates_presence_of :name, :source
validates_presence_of :source
## behaviours ##
## methods ##
%w{image stylesheet javascript pdf media}.each do |type|
define_method("#{type}?") do
self.content_type.to_s == type
end
end
alias :name :source_filename
def extname
return nil unless self.source?
File.extname(self.source_filename).gsub(/^\./, '')
end
def site_id # needed by the uploader of custom fields
self.collection.site_id
end
def to_liquid
Locomotive::Liquid::Drops::Asset.new(self)
{ :url => self.source.url }.merge(self.attributes).stringify_keys
end
end

View File

@ -1,81 +0,0 @@
class AssetCollection
include Locomotive::Mongoid::Document
## fields ##
field :name
field :slug
field :internal, :type => Boolean, :default => false
## associations ##
referenced_in :site
embeds_many :assets, :validate => false
## behaviours ##
custom_fields_for :assets
liquid_methods :name, :ordered_assets
## callbacks ##
before_validation :normalize_slug
before_save :store_asset_positions!
after_destroy :remove_uploaded_files
## validations ##
validates_presence_of :site, :name, :slug
validates_uniqueness_of :slug, :scope => :site_id
## named scopes ##
scope :internal, :where => { :internal => true }
scope :not_internal, :where => { :internal => false }
## methods ##
def ordered_assets
self.assets.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
end
def assets_order
self.ordered_assets.collect(&:id).join(',')
end
def assets_order=(order)
@assets_order = order
end
def self.find_or_create_internal(site)
site.asset_collections.internal.first || site.asset_collections.create(:name => 'system', :slug => 'system', :internal => true)
end
protected
def normalize_slug
self.slug = self.name.clone if self.slug.blank? && self.name.present?
self.slug.slugify! if self.slug.present?
end
def store_asset_positions!
return if @assets_order.nil?
ids = @assets_order.split(',').collect { |id| BSON::ObjectId(id) }
ids.each_with_index do |asset_id, index|
self.assets.find(asset_id).position = index
end
self.assets.clone.each do |asset|
if !ids.include?(asset._id)
self.assets.delete(asset)
asset.send(:delete)
end
end
end
def remove_uploaded_files # callbacks are not called on each asset so we do it manually
self.assets.each do |asset|
self.asset_custom_fields.each do |field|
asset.send(:"remove_#{field._name}!") if field.kind == 'file'
end
end
end
end

View File

@ -14,12 +14,14 @@ class ContentInstance
## validations ##
validate :require_highlighted_field
validate :validate_uniqueness_of_slug
validates_presence_of :_slug
## associations ##
embedded_in :content_type, :inverse_of => :contents
## callbacks ##
before_save :set_slug
before_validation :set_slug
before_save :set_visibility
before_create :add_to_list_bottom
after_create :send_notifications
@ -67,8 +69,8 @@ class ContentInstance
protected
def set_slug
_alias = self.highlighted_field_alias
self._slug = self.send(_alias).parameterize('_')
self._slug = self.highlighted_field_value.clone if self._slug.blank? && self.highlighted_field_value.present?
self._slug.permalink! if self._slug.present?
end
def set_visibility
@ -77,7 +79,6 @@ class ContentInstance
end
def add_to_list_bottom
Rails.logger.debug "add_to_list_bottom"
self._position_in_list = self.content_type.contents.size
end
@ -88,6 +89,12 @@ class ContentInstance
end
end
def validate_uniqueness_of_slug
if self._parent.contents.any? { |c| c._id != self._id && c._slug == self._slug }
self.errors.add(:_slug, :taken)
end
end
def highlighted_field_alias
self.content_type.highlighted_field._alias.to_sym
end

View File

@ -107,8 +107,8 @@ class ContentType
self.asc_order? ? list : list.reverse
end
def sort_contents!(order)
order.split(',').each_with_index do |id, position|
def sort_contents!(ids)
ids.each_with_index do |id, position|
self.contents.find(BSON::ObjectId(id))._position_in_list = position
end
self.save
@ -131,7 +131,7 @@ class ContentType
def normalize_slug
self.slug = self.name.clone if self.slug.blank? && self.name.present?
self.slug.slugify! if self.slug.present?
self.slug.permalink! if self.slug.present?
end
def remove_uploaded_files # callbacks are not called on each content so we do it manually

View File

@ -0,0 +1,19 @@
module Extensions
module Asset
module Types
extend ActiveSupport::Concern
included do
%w{media image stylesheet javascript font pdf}.each do |type|
scope :"only_#{type}", where(:content_type => type)
define_method("#{type}?") do
self.content_type.to_s == type
end
end
end
end
end
end

View File

@ -7,11 +7,11 @@ module Extensions
if self.width < 80 && self.height < 80
self.source.url
else
self.source.url(:medium)
Locomotive::Dragonfly.resize_url(self.source, '80x80#')
end
end
end
end
end
end
end

View File

@ -42,14 +42,6 @@ module Extensions
@item_parsing_errors.try(:each) { |msg| self.errors.add :item_template, msg }
end
# def item_template
# self.read_attribute(:default_item_template) || self.default_item_template
# end
#
# def default_item_template
# '{{ content.highlighted_field_value }}'
# end
end
end

View File

@ -28,9 +28,9 @@ module Extensions
module ClassMethods
# Warning: used only in read-only
def quick_tree(site)
pages = site.pages.minimal_attributes.order_by([[:depth, :asc], [:position, :asc]]).to_a
# Warning: should be used only in read-only
def quick_tree(site, minimal_attributes = true)
pages = (minimal_attributes ? site.pages.minimal_attributes : site.pages).order_by([[:depth, :asc], [:position, :asc]]).to_a
tmp = []

View File

@ -4,10 +4,11 @@ module Extensions
extend ActiveSupport::Concern
included do
field :seo_title, :type => String
field :meta_keywords, :type => String
field :meta_description, :type => String
end
end # Seo
end # Shared
end # Extensions

View File

@ -6,7 +6,7 @@ module Extensions
def create_first_one(attributes)
site = self.new(attributes)
site.memberships.build :account => Account.first, :admin => true
site.memberships.build :account => Account.first, :role => 'admin'
site.save
@ -27,7 +27,7 @@ module Extensions
begin
Locomotive::Import::Job.run!(source, site, { :samples => true })
rescue Exception => e
logger.error "The import of the site template failed because of #{e.message}"
Rails.logger.error "The import of the site template failed because of #{e.message}"
end
end

View File

@ -3,7 +3,7 @@ class Membership
include Locomotive::Mongoid::Document
## fields ##
field :admin, :type => Boolean, :default => false
field :role, :default => 'author'
## associations ##
referenced_in :account, :validate => false
@ -12,8 +12,17 @@ class Membership
## validations ##
validates_presence_of :account
## callbacks ##
before_save :define_role
## methods ##
Ability::ROLES.each do |_role|
define_method("#{_role}?") do
self.role == _role
end
end
def email; @email; end
def email=(email)
@ -27,13 +36,23 @@ class Membership
:error
elsif self.account.blank?
:create_account
elsif self.site.memberships.find_all { |m| m.account_id == self.account_id }.size > 1
elsif self.site.memberships.any? { |m| m.account_id == self.account_id && m._id != self._id }
self.errors.add(:base, 'Already created')
:nothing
:already_created
else
self.save
:save_it
end
end
def ability
@ability ||= Ability.new(self.account, self.site)
end
protected
def define_role
self.role = Ability::ROLES.include?(role.downcase) ? role.downcase : Ability::ROLES.first
end
end

View File

@ -97,7 +97,7 @@ class Page
def normalize_slug
self.slug = self.title.clone if self.slug.blank? && self.title.present?
self.slug.slugify!(:without_extension => true) if self.slug.present?
self.slug.permalink! if self.slug.present?
end
def set_default_raw_template

View File

@ -5,17 +5,18 @@ class Site
## Extensions ##
extend Extensions::Site::SubdomainDomains
extend Extensions::Site::FirstInstallation
extend Extensions::Site::FirstInstallation
include Extensions::Shared::Seo
## fields ##
field :name
field :meta_keywords
field :meta_description
field :robots_txt
## associations ##
references_many :pages, :validate => false
references_many :snippets, :dependent => :destroy, :validate => false
references_many :theme_assets, :dependent => :destroy, :validate => false
references_many :asset_collections, :dependent => :destroy, :validate => false
references_many :assets, :dependent => :destroy, :validate => false
references_many :content_types, :dependent => :destroy, :validate => false
embeds_many :memberships
@ -28,6 +29,7 @@ class Site
## behaviours ##
enable_subdomain_n_domains_if_multi_sites
accepts_nested_attributes_for :memberships
## methods ##

View File

@ -26,7 +26,7 @@ class Snippet
def normalize_slug
# TODO: refactor it
self.slug = self.name.clone if self.slug.blank? && self.name.present?
self.slug.slugify!(:without_extension => true, :downcase => true) if self.slug.present?
self.slug.permalink! if self.slug.present?
end
def update_templates

View File

@ -2,6 +2,9 @@ class ThemeAsset
include Locomotive::Mongoid::Document
## extensions ##
include Extensions::Asset::Types
## fields ##
field :local_path
field :content_type
@ -9,7 +12,6 @@ class ThemeAsset
field :height, :type => Integer
field :size, :type => Integer
field :folder, :default => nil
field :hidden, :type => Boolean, :default => false
mount_uploader :source, ThemeAssetUploader
## associations ##
@ -32,19 +34,12 @@ class ThemeAsset
validate :content_type_can_not_changed
## named scopes ##
scope :visible, lambda { |all| all ? {} : { :where => { :hidden => false } } }
## accessors ##
attr_accessor :plain_text_name, :plain_text, :performing_plain_text
attr_accessor :plain_text_name, :plain_text, :plain_text_type, :performing_plain_text
## methods ##
%w{media image stylesheet javascript font}.each do |type|
define_method("#{type}?") do
self.content_type.to_s == type
end
end
def stylesheet_or_javascript?
self.stylesheet? || self.javascript?
end
@ -77,11 +72,17 @@ class ThemeAsset
end
end
def plain_text_type
@plain_text_type || (stylesheet_or_javascript? ? self.content_type : nil)
end
def performing_plain_text?
Boolean.set(self.performing_plain_text) || false
end
def store_plain_text
self.content_type ||= @plain_text_type if self.performing_plain_text?
data = self.performing_plain_text? ? self.plain_text : self.source.read
return if !self.stylesheet_or_javascript? || self.plain_text_name.blank? || data.blank?
@ -95,11 +96,11 @@ class ThemeAsset
end
def to_liquid
{ :url => self.source.url }.merge(self.attributes)
{ :url => self.source.url }.merge(self.attributes).stringify_keys
end
def self.all_grouped_by_folder(site, include_all = true)
assets = site.theme_assets.visible(include_all).order_by([[:slug, :asc]])
def self.all_grouped_by_folder(site)
assets = site.theme_assets.order_by([[:slug, :asc]])
assets.group_by { |a| a.folder.split('/').first.to_sym }
end

View File

@ -2,72 +2,10 @@
class AssetUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
include Locomotive::CarrierWave::Uploader::Asset
def store_dir
self.build_store_dir('sites', model.collection.site_id, 'assets', model.id)
end
version :thumb, :if => :image? do
process :resize_to_fill => [50, 50]
process :convert => 'png'
end
version :medium, :if => :image? do
process :resize_to_fill => [80, 80]
process :convert => 'png'
end
version :preview, :if => :image? do
process :resize_to_fit => [880, 1100]
process :convert => 'png'
end
process :set_content_type
process :set_size
process :set_width_and_height
def set_content_type(*args)
value = :other
content_type = file.content_type == 'application/octet-stream' ? File.mime_type?(original_filename) : file.content_type
self.class.content_types.each_pair do |type, rules|
rules.each do |rule|
case rule
when String then value = type if content_type == rule
when Regexp then value = type if (content_type =~ rule) == 0
end
end
end
model.content_type = value
end
def set_size(*args)
model.size = file.size
end
def set_width_and_height
if model.image?
magick = ::Magick::Image.read(current_path).first
model.width, model.height = magick.columns, magick.rows
end
end
def image?
model.image?
end
def self.content_types
{
:image => ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg', 'image/x-icon'],
: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'],
:font => ['application/x-font-ttf', 'application/vnd.ms-fontobject', 'image/svg+xml', 'application/x-woff']
}
self.build_store_dir('sites', model.site_id, 'assets', model.id)
end
end

View File

@ -4,8 +4,4 @@ class EditableFileUploader < ::CarrierWave::Uploader::Base
self.build_store_dir('sites', model.page.site_id, 'pages', model.page.id, 'files')
end
# def cache_dir
# "#{Rails.root}/tmp/uploads"
# end
end

View File

@ -1,17 +1,11 @@
# encoding: utf-8
class ThemeAssetUploader < AssetUploader
class ThemeAssetUploader < CarrierWave::Uploader::Base
process :set_content_type
process :set_size
process :set_width_and_height
include Locomotive::CarrierWave::Uploader::Asset
def store_dir
self.build_store_dir('sites', (model.site_id_was || model.site_id).to_s, 'theme', model.folder_was || model.folder)
end
def stale_model?
!model.new_record? && model.folder_changed?
self.build_store_dir('sites', model.site_id, 'theme', model.folder)
end
def extension_white_list

View File

@ -1,36 +0,0 @@
- title link_to(@asset_collection.name.blank? ? @asset_collection.name_was : @asset_collection.name, '#', :rel => 'asset_collection_name', :title => t('.ask_for_name'), :class => 'editable')
- content_for :head do
= include_javascripts :asset_collections
= include_stylesheets :fancybox
- content_for :submenu do
= render 'admin/shared/menu/assets'
- content_for :actions do
= render 'admin/shared/actions/assets'
%p!= t('.help')
- content_for :buttons do
= admin_button_tag :add_asset, new_admin_asset_url(@asset_collection), :class => 'new'
%p.no-items{ :style => "#{'display: none' unless @asset_collection.assets.empty? }" }
!= t('.no_items', :url => new_admin_asset_url(@asset_collection))
%ul#assets.assets.sortable
= render :partial => 'asset', :collection => @asset_collection.ordered_assets
%li.clear
= semantic_form_for @asset_collection, :url => admin_asset_collection_url(@asset_collection), :html => { :multipart => true } do |f|
= f.hidden_field :assets_order
= f.foldable_inputs :name => :options do
= f.input :name
= f.input :slug, :required => false
= render 'admin/custom_fields/index', :form => f, :collection_name => 'assets'
= render 'admin/shared/form_actions', :delete_button => link_to(content_tag(:em, escape_once('&nbsp;')) + t('.destroy'), admin_asset_collection_url(@asset_collection), :confirm => t('admin.messages.confirm'), :method => :delete, :class => 'button small remove'), :button_label => :update
= render 'admin/custom_fields/edit_field'

View File

@ -1,11 +0,0 @@
- title t('.title')
- content_for :submenu do
= render 'admin/shared/menu/assets'
- content_for :actions do
= render 'admin/shared/actions/assets'
%p!= t('.help')
%p.no-items!= t('.no_items', :url => new_admin_asset_collection_url)

View File

@ -1,20 +0,0 @@
- title t('.title')
- content_for :head do
= include_javascripts :asset_collections
- content_for :submenu do
= render 'admin/shared/menu/assets'
- content_for :actions do
= render 'admin/shared/actions/assets'
%p!= t('.help')
= semantic_form_for @asset_collection, :url => admin_asset_collections_url do |f|
= f.inputs :name => :information do
= f.input :name
= f.input :slug, :required => false
= render 'admin/shared/form_actions', :back_url => admin_asset_collections_url, :button_label => :create

View File

@ -1,5 +1,5 @@
%li{ :id => "asset-#{asset.id}", :class => "asset #{'last' if (asset_counter + 1) % 6 == 0}"}
%h4= link_to truncate(asset.name, :length => 17), edit_admin_asset_path(@asset_collection, asset)
%h4= link_to truncate(asset.name, :length => 17), edit_admin_asset_path(asset)
= vignette_tag(asset)
.actions
= link_to image_tag('admin/list/icons/cross.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')

View File

@ -1,17 +0,0 @@
- content_for :head do
= include_javascripts :edit_custom_fields, :assets
= include_stylesheets :fancybox
= f.inputs :name => :information do
= f.input :name
= f.input :source, :hint_options => @asset.persisted? ? { :url => link_to(@asset.source_filename, @asset.source.url), :escaping => false } : {}
- unless @asset.custom_fields.blank?
= render 'admin/custom_fields/custom_form', :form => f, :title => :other_fields, :parent => @asset_collection
- if @asset.image? && @asset.valid?
= f.foldable_inputs :name => "#{t('formtastic.titles.preview')} #{image_dimensions_and_size(@asset)}", :class => 'preview' do
%li
.image
.inside
= image_tag(@asset.source.url(:preview))

View File

@ -1,18 +0,0 @@
- title t('.title')
- content_for :submenu do
= render 'admin/shared/menu/assets'
- content_for :actions do
= render 'admin/shared/actions/assets'
- content_for :buttons do
= admin_button_tag t('admin.asset_collections.edit.add_asset'), new_admin_asset_url(@asset_collection), :class => 'new'
%p!= t('.help')
= semantic_form_for @asset, :url => admin_asset_url(@asset_collection, @asset), :html => { :multipart => true, :class => 'save-with-shortcut' } do |form|
= render 'form', :f => form
= render 'admin/shared/form_actions', :back_url => edit_admin_asset_collection_url(@asset_collection), :button_label => :update

View File

@ -1,15 +0,0 @@
- title t('.title')
- content_for :submenu do
= render 'admin/shared/menu/assets'
- content_for :actions do
= render 'admin/shared/actions/assets'
%p!= t('.help')
= semantic_form_for @asset, :url => admin_assets_url(@asset_collection), :html => { :multipart => true } do |form|
= render 'form', :f => form
= render 'admin/shared/form_actions', :back_url => edit_admin_asset_collection_url(@asset_collection), :button_label => :create

View File

@ -3,7 +3,7 @@
= include_stylesheets :fancybox
= f.inputs :name => :information do
= f.input :name
= f.input :name, :wrapper_html => { :class => 'highlighted' }
= f.input :slug
= f.input :description
@ -13,10 +13,9 @@
= f.foldable_inputs :name => :presentation, :class => 'switchable' do
= f.input :highlighted_field_name, :as => :select, :collection => options_for_highlighted_field(f.object, 'contents'), :include_blank => false
= f.input :group_by_field_name, :as => :select, :collection => options_for_group_by_field(f.object, 'contents')
= f.custom_input :raw_item_template, :css => 'small-code' do
= f.custom_input :item_template, :css => 'small-code' do
%code{ :class => 'html' }
= f.text_area :raw_item_template, :class => 'small'
= f.errors_on :item_template
= f.foldable_inputs :name => :options, :class => 'switchable' do
= f.input :order_by, :as => :select, :collection => options_for_order_by(f.object, 'contents'), :include_blank => false

View File

@ -7,8 +7,8 @@
= render 'admin/shared/actions/contents'
- content_for :buttons do
= admin_button_tag :show_items, admin_contents_url(@content_type.slug), :class => 'show'
= admin_button_tag :new_item, new_admin_content_url(@content_type.slug), :class => 'new'
= admin_button_tag :show_items, admin_contents_url(@content_type.slug_was), :class => 'show'
= admin_button_tag :new_item, new_admin_content_url(@content_type.slug_was), :class => 'new'
%p!= t('.help')
@ -16,6 +16,6 @@
= render 'form', :f => f
= render 'admin/shared/form_actions', :back_url => admin_contents_url(@content_type.slug), :button_label => :update
= render 'admin/shared/form_actions', :back_url => admin_contents_url(@content_type.slug_was), :button_label => :update
= render 'admin/custom_fields/edit_field'

View File

@ -2,9 +2,11 @@
= include_javascripts :edit_custom_fields, :contents
= include_stylesheets :fancybox
= f.foldable_inputs :name => :meta do
= render 'admin/custom_fields/custom_form', :form => f, :title => :attributes, :parent => @content_type
= f.foldable_inputs :name => :advanced_options do
= f.input :_slug
= f.input :seo_title
= f.input :meta_keywords
= f.input :meta_description
= render 'admin/custom_fields/custom_form', :form => f, :title => :attributes, :parent => @content_type

View File

@ -1,7 +1,7 @@
- if contents.empty?
%p.no-items!= t('.no_items', :url => new_admin_content_url(@content_type.slug))
- else
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}", :'data-url' => sort_admin_contents_path(@content_type.slug, :json) }
- contents.each do |content|
%li.content{ :id => "content-#{content._id}" }
%em
@ -12,4 +12,4 @@
!= t('admin.contents.index.updated_at')
= l content.updated_at, :format => :short rescue 'n/a'
= link_to image_tag('admin/list/icons/trash.png'), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
= link_to image_tag('admin/list/icons/trash.png', :alt => t('admin.buttons.delete')), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete

View File

@ -1,13 +1,15 @@
- title t('.title', :type => @content_type.name.capitalize)
- content_for :submenu do
= render 'admin/shared/menu/contents'
- content_for :actions do
= render 'admin/shared/actions/contents'
- content_for :buttons do
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
- if can?(:manage, ContentType)
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
= admin_button_tag t('admin.contents.index.new'), new_admin_content_url(@content_type.slug), :class => 'new'
%p= @content_type.description

View File

@ -10,7 +10,9 @@
= include_javascripts :contents
- content_for :buttons do
= admin_button_tag :edit, edit_admin_content_type_url(@content_type), :class => 'edit'
- if can?(:manage, ContentType)
= admin_button_tag :edit, edit_admin_content_type_url(@content_type), :class => 'edit'
= admin_button_tag :new, new_admin_content_url(@content_type.slug), :class => 'new'
- if @content_type.description.present?
@ -24,7 +26,7 @@
- else
= render 'list', :contents => @contents
= form_tag sort_admin_contents_path(@content_type.slug), :method => :put, :class => 'formtastic' do
= hidden_field_tag :order
= render 'admin/shared/form_actions', :delete_button => link_to(content_tag(:em, escape_once('&nbsp;')) + t('.destroy'), admin_content_type_url(@content_type), :confirm => t('admin.messages.confirm'), :method => :delete, :class => 'button small remove'), :button_label => :update
- if can?(:manage, ContentType)
#local-actions-bottom-bar
%p.tleft
= link_to(content_tag(:em, escape_once('&nbsp;')) + t('.destroy'), admin_content_type_url(@content_type), :confirm => t('admin.messages.confirm'), :method => :delete, :class => 'button small remove')

View File

@ -6,8 +6,9 @@
- content_for :actions do
= render 'admin/shared/actions/contents'
- content_for :buttons do
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
- if can?(:manage, ContentType)
- content_for :buttons do
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
%p= @content_type.description

View File

@ -0,0 +1,76 @@
- content_for :head do
= include_javascripts :site
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
= f.input :name, :required => false
= f.foldable_inputs :name => :seo do
= f.input :seo_title
= f.input :meta_keywords
= f.input :meta_description
- if can?(:point, Site)
- if manage_subdomain_or_domains?
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
= f.custom_input :subdomain, :css => 'path' do
%em
http://
= f.text_field :subdomain, :readonly => !manage_subdomain?
\.
%em
= application_domain
- if manage_domains?
- @site.domains_without_subdomain.each_with_index do |name, index|
%li{ :class => "item added #{'last' if index == @site.domains.size - 1}"}
%em
http://
= text_field_tag 'site[domains][]', name, :class => 'string label void domain'
&nbsp;
= error_on_domain(@site, name)
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
%li.item.template
%em
http://
= text_field_tag 'label', t('formtastic.hints.site.domain_name'), :class => 'string label void domain'
&nbsp;
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
%button{ :class => 'button light add', :type => 'button' }
%span!= t('admin.buttons.new_item')
- if can?(:index, Membership)
= f.foldable_inputs :name => :memberships, :class => 'memberships off' do
= f.semantic_fields_for :memberships do |fm|
- membership, account = fm.object, fm.object.account
%li.item.membership{ :'data-role' => membership.role }
%strong= account.name
%em.email= account.email
- if can?(:change_role, membership)
.role
%em.editable= t("admin.memberships.roles.#{membership.role}")
= fm.select :role, Ability::ROLES.collect { |r| [t("admin.memberships.roles.#{r}"), r] }, :include_blank => false
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), admin_membership_url(membership), :class => 'remove first', :confirm =>t('admin.messages.confirm'), :method => :delete
- else
.role
%em.locked= t("admin.memberships.roles.#{membership.role}")
- if can?(:manage, current_site)
= f.foldable_inputs :name => :robots_txt do
= f.custom_input :robots_txt, :css => 'code full', :with_label => false do
= f.label :robots_txt
%code{ :class => 'html' }
= f.text_area :robots_txt, :class => 'small'

View File

@ -3,9 +3,11 @@
- content_for :submenu do
= render 'admin/shared/menu/settings'
- content_for :buttons do
= admin_button_tag :import, new_admin_import_url, :class => 'new'
= admin_button_tag t('.new_membership'), new_admin_membership_url, :class => 'new'
- if can?(:manage, @site)
- content_for :buttons do
= admin_button_tag :export, new_admin_export_url, :class => 'new'
= admin_button_tag :import, new_admin_import_url, :class => 'new'
= admin_button_tag t('.new_membership'), new_admin_membership_url, :class => 'new'
%p!= t('.help')

View File

@ -1,52 +0,0 @@
- content_for :head do
= include_javascripts :site
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
= f.input :name, :required => false
= f.foldable_inputs :name => :meta do
= f.input :meta_keywords
= f.input :meta_description
- if manage_subdomain_or_domains?
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
= f.custom_input :subdomain, :css => 'path' do
%em
http://
= f.text_field :subdomain, :readonly => !manage_subdomain?
\.
%em
= application_domain
- if manage_domains?
- @site.domains_without_subdomain.each_with_index do |name, index|
%li{ :class => "item added #{'last' if index == @site.domains.size - 1}"}
%em
http://
= text_field_tag 'site[domains][]', name, :class => 'string label void domain'
&nbsp;
= error_on_domain(@site, name)
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
%li.item.template
%em
http://
= text_field_tag 'label', t('formtastic.hints.site.domain_name'), :class => 'string label void domain'
&nbsp;
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
%button{ :class => 'button light add', :type => 'button' }
%span!= t('admin.buttons.new_item')
= f.foldable_inputs :name => :memberships, :class => 'memberships' do
- @site.memberships.each_with_index do |membership, index|
- account = membership.account
%li{ :class => "item #{'last' if index == @site.memberships.size - 1}" }
%strong= account.name
%em= account.email
- if account != current_admin
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), admin_membership_url(membership), :class => 'remove first', :confirm => t('admin.messages.confirm'), :method => :delete

View File

@ -2,8 +2,9 @@
= form.inputs :name => title || :attributes do
- form.object.custom_fields.each do |field|
- required = highlighted_field_name == field._name || field.required
- highlighted = highlighted_field_name == field._name
- required = highlighted || field.required
= render "/admin/custom_fields/types/#{field.kind}", :form => form, :parent => parent, :field => field, :required => required
= render "/admin/custom_fields/types/#{field.kind}", :form => form, :parent => parent, :field => field, :required => required, :highlighted => highlighted
= render '/admin/custom_fields/category_tmpl'

View File

@ -29,7 +29,7 @@
&mdash;
%em {{kind_name}}
%em.editable {{kind_name}}
= select_tag '{{base_name}}[kind]', options_for_select(options_for_field_kind), :'data-field' => 'kind'

View File

@ -1,2 +1,2 @@
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle', :required => required do
= form.check_box field._alias.to_sym

View File

@ -1,4 +1,4 @@
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle', :required => required do
= form.select field._name.to_sym, field.ordered_category_items.collect { |item| [item.name, item.id] }
%button.button.light.edit-categories-link{ :type => 'button', :'data-url' => edit_admin_custom_field_path(parent.class.model_name.underscore, parent.slug, field) }
%span!= t('.edit_categories')

View File

@ -1 +1 @@
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'date' }
= form.input :"formatted_#{field._alias}", :label => field.label, :hint => field.hint, :input_html => { :class => 'date' }, :wrapper_html => { :class => 'date' }, :required => required

View File

@ -1,4 +1,4 @@
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'file' do
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'file', :required => required do
= form.file_field field._name.to_sym
- if form.object.send(:"#{field._name}?")
%p.remove

View File

@ -1,6 +1,6 @@
- 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' do
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'has-many', :required => required do
.has-many-selector

View File

@ -1,4 +1,6 @@
- field.target.constantize.reload_parent! # to make sure all the contents from the parent are loaded
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'has_one' }, :as => :select, :collection => options_for_has_one(field), :selected => form.object.send(field._alias.to_sym).try(:_id)
- selected_id = form.object.send(field._alias.to_sym).try(:_id)
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'has_one' }, :as => :select, :collection => options_for_has_one(field, selected_id), :selected => selected_id, :required => required

View File

@ -1 +1 @@
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :required => required
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :required => required, :wrapper_html => { :class => "#{'highlighted' if highlighted}" }

View File

@ -15,7 +15,8 @@
= label_tag 'zipfile', t('formtastic.labels.import.new.source')
= file_field_tag 'zipfile'
- if @error
%p.inline-errors= @error
.inline-errors
%p= @error
%p.inline-hints= t('formtastic.hints.import.source')
%li.input.toggle

View File

@ -9,7 +9,7 @@
%p!= t('.help')
%ul{ :id => 'import-steps', :class => 'list', :'data-url' => admin_import_url(:json), :'data-success-message' => t('.messages.success'), :'data-failure-message' => t('.messages.failure') }
- %w(site content_types assets asset_collections snippets pages).each do |step|
- %w(site content_types assets snippets pages).each do |step|
%li{ :id => "#{step}-step" }
%em
%strong

View File

@ -13,7 +13,7 @@
#submenu
%ul
= yield :submenu
- if content_for? :actions
.action
= yield :actions

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'
= admin_button_tag t('.new_site'), new_admin_site_url, :class => 'new' if can?(:manage, Site)
%p= t('.help')
@ -37,10 +37,11 @@
= f.custom_input :language, { :css => 'full', :with_label => false } do
- Locomotive.config.locales.each do |locale|
%span
%label
= f.radio_button :locale, locale
%label{ :for => "my_account_locale_#{locale.downcase}" }
= image_tag "admin/icons/flags/#{locale}.png"
= f.radio_button :locale, locale
&nbsp;
= t(".#{locale}")
/ &nbsp;
= render 'admin/shared/form_actions', :button_label => :update

View File

@ -2,47 +2,53 @@
= include_javascripts :image_picker, :edit_page
= include_stylesheets :editable_elements, :fancybox
= f.foldable_inputs :name => :information do
- if can?(:manage, @page)
= f.input :title
= f.foldable_inputs :name => :information do
- if not @page.index? and not @page.not_found?
= f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
= f.input :title, :wrapper_html => { :class => 'highlighted' }
= f.input :slug, :required => false, :hint => @page.slug.blank? ? '&nbsp;' : page_url(@page), :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}; height: 50px" }
- if not @page.index? and not @page.not_found?
= f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
= f.foldable_inputs :name => :meta do
= f.input :meta_keywords
= f.input :meta_description
= f.foldable_inputs :name => :advanced_options do
= f.input :content_type_id, :as => :select, :collection => current_site.content_types.all.to_a, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}; height: 50px" }
= f.custom_input :templatized, :css => 'toggle', :style => "#{'display: none' if @page.redirect?}" do
= f.check_box :templatized
= f.custom_input :published, :css => 'toggle' do
= f.check_box :published
= f.custom_input :listed, :css => 'toggle' do
= f.check_box :listed
= f.custom_input :redirect, :css => 'toggle', :style => "#{'display: none' if @page.templatized?}" do
= f.check_box :redirect
= f.input :cache_strategy, :as => :select, :collection => options_for_page_cache_strategy, :include_blank => false, :wrapper_html => { :style => "#{'display: none' if @page.redirect?}" }
= f.input :redirect_url, :required => true, :wrapper_html => { :style => "#{'display: none' unless @page.redirect?}" }
= f.input :slug, :required => false, :hint => @page.slug.blank? ? '&nbsp;' : page_url(@page), :input_html => { :'data-url' => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?};" }
= render 'editable_elements', :page => @page
= f.foldable_inputs :name => :raw_template do
= f.custom_input :value, :css => 'code full', :with_label => false do
= f.label :raw_template
%code{ :class => 'html' }
= f.text_area :raw_template
= f.errors_on :template
.more
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
= f.foldable_inputs :name => :seo do
= f.input :seo_title
= f.input :meta_keywords
= f.input :meta_description
- if can?(:manage, @page)
= f.foldable_inputs :name => :advanced_options, :id => 'advanced-options' do
= f.input :content_type_id, :as => :select, :collection => current_site.content_types.all.to_a, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" }
= f.custom_input :templatized, :css => 'toggle', :style => "#{'display: none' if @page.redirect?}" do
= f.check_box :templatized
= f.custom_input :published, :css => 'toggle' do
= f.check_box :published
= f.custom_input :listed, :css => 'toggle' do
= f.check_box :listed
= f.custom_input :redirect, :css => 'toggle', :style => "#{'display: none' if @page.templatized?}" do
= f.check_box :redirect
= f.input :cache_strategy, :as => :select, :collection => options_for_page_cache_strategy, :include_blank => false, :wrapper_html => { :style => "#{'display: none' if @page.redirect?}" }
= f.input :redirect_url, :required => true, :wrapper_html => { :style => "#{'display: none' unless @page.redirect?}" }
= f.foldable_inputs :name => :raw_template do
= f.custom_input :value, :css => 'code full', :with_label => false do
= f.label :raw_template
%code{ :class => 'html' }
= f.text_area :raw_template
= f.errors_on :template
.more
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'

View File

@ -1,8 +1,12 @@
%li{ :id => "item-#{page.id}", :class => "#{'not-found' if page.not_found? } #{'templatized' if page.templatized?}"}
- with_children = !page.children.empty?
- children = can?(:manage, page) ? page.children : page.children.find_all { |p| !p.templatized? }
- with_children = !children.empty?
- if not page.index? and with_children
= image_tag 'admin/list/icons/node_closed.png', :class => 'toggler'
= admin_item_toggler(page)
%em
%strong= link_to truncate(page.title, :length => 80), edit_admin_page_url(page)
@ -10,9 +14,10 @@
%span!= t('.updated_at')
= l page.updated_at, :format => :short
- if not page.index? and not page.not_found?
- if !page.index_or_not_found? && can?(:manage, page)
= link_to image_tag('admin/list/icons/trash.png'), admin_page_url(page), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
- if with_children
%ul{ :id => "folder-#{page._id}", :class => "folder depth-#{(page.depth || 0) + 1}", :data_url => sort_admin_page_url(page), :style => "display: #{cookies["folder-#{page._id}"] || 'block'}" }
= render page.children
%ul{ :id => "folder-#{page._id}", :class => "folder depth-#{(page.depth || 0) + 1}", :'data-url' => sort_admin_page_url(page), :style => "display: #{cookies["folder-#{page._id}"] || 'block'}" }
= render children

View File

@ -5,12 +5,13 @@
- content_for :submenu do
= render 'admin/shared/menu/contents'
- content_for :actions do
= render 'admin/shared/actions/contents'
- content_for :buttons do
= admin_button_tag :new, new_admin_page_url, :class => 'new'
- if can? :create, Page
- content_for :buttons do
= admin_button_tag :new, new_admin_page_url, :class => 'new'
%p!= t('.help')

View File

@ -1,4 +1,4 @@
.actions
#local-actions-bottom-bar
.span-12
%p
- if defined?(back_url)

View File

@ -1,14 +1,25 @@
%h1
- if current_admin.sites.size > 1
= form_tag new_admin_cross_domain_session_url, :method => 'get' do
= select_tag 'target_id', options_for_select(current_admin.sites.collect { |site| [truncate(site.name, :length => 32), site.id] }, current_site.id), :id => 'site-selector'
= submit_tag 'Switch', :style => 'display: none'
- else
= link_to current_site.name, admin_pages_url, :class => 'single'
= link_to current_site.name, admin_pages_url, :class => 'single'
#global-actions-bar
!= t('.welcome', :name => link_to(current_admin.name, edit_admin_my_account_url))
%span= '|'
= link_to t('.see'), current_site_url
- if multi_sites? && current_admin.sites.size > 1
%span= '|'
= link_to t('.switch'), '#', :id => 'sites-picker-link'
%span= '|'
= link_to t('.logout'), destroy_admin_session_url, :confirm => t('admin.messages.confirm')
= link_to t('.logout'), destroy_admin_session_url, :confirm => t('admin.messages.confirm')
- if multi_sites? && current_admin.sites.size > 1
#sites-picker{ :style => 'display: none' }
%ul
- current_admin.sites.each do |site|
- unless current_site._id == site._id
%li
= link_to site.name, new_admin_cross_domain_session_url(:target_id => site._id)
- if can?(:manage, Site)
%p.action
= link_to t('admin.sites_picker.new'), new_admin_site_url

View File

@ -1,5 +1,4 @@
%ul#menu
= admin_menu_item('contents', admin_pages_url)
= admin_menu_item('assets', admin_asset_collections_url)
= admin_menu_item('settings', edit_admin_current_site_url)
%li.clear

View File

@ -1 +0,0 @@
= link_to content_tag(:span, t('admin.asset_collections.index.new')), new_admin_asset_collection_url

View File

@ -1 +1,2 @@
= link_to content_tag(:em) + content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url
- if can? :manage, ContentType
= link_to content_tag(:em) + content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url

View File

@ -1,3 +0,0 @@
- @asset_collections.each do |c|
%li
= link_to content_tag(:span, truncate(c.name, :length => 20)), edit_admin_asset_collection_url(c), :class => "#{'on' if @asset_collection.id == c.id}"

View File

@ -1,6 +1,7 @@
= admin_submenu_item 'pages', admin_pages_url do
.header
%p= link_to t('admin.pages.index.new'), new_admin_page_url
- if can? :manage, @page
.header
%p= link_to t('admin.pages.index.new'), new_admin_page_url
.inner
%h2!= t('admin.pages.index.lastest_items')
%ul
@ -12,6 +13,10 @@
- each_content_type_menu_item do |content_type|
.header
%p= link_to t('admin.contents.index.new'), new_admin_content_url(content_type.slug)
- if can? :manage, content_type
%p.edit= link_to t('admin.contents.index.edit'), edit_admin_content_type_url(content_type)
.inner
%h2!= t('admin.contents.index.lastest_items')
%ul

View File

@ -3,7 +3,7 @@
= include_stylesheets :fancybox
= f.inputs :name => :information do
= f.input :name
= f.input :name, :wrapper_html => { :class => 'highlighted' }
= f.input :slug, :required => false
= f.inputs :name => :code do
@ -11,4 +11,4 @@
%code{ :class => 'html' }
= f.text_area :template
.more
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'

View File

@ -6,7 +6,7 @@
- content_for :buttons do
= admin_button_tag t('admin.snippets.index.new'), new_admin_snippet_url, :class => 'new'
%p!= t('.help')
%p!= t('.help', :slug => @snippet.slug)
= semantic_form_for @snippet, :url => admin_snippet_url(@snippet), :html => { :class => 'save-with-shortcut' } do |form|

View File

@ -1,6 +1,6 @@
- edit = local_assigns.key?(:edit) ? edit : true
%li{ :class => "#{asset.new_record? ? 'new-asset' : 'asset'} #{'hidden' if asset.hidden?}" }
%li{ :class => (asset.new_record? ? 'new-asset' : 'asset') }
%em
%strong= link_to asset.local_path(!edit), edit ? edit_admin_theme_asset_path(asset) : asset.source.url, :'data-local-path' => asset.local_path
.more

View File

@ -19,19 +19,17 @@
- if @theme_asset.new_record?
= f.input :plain_text_name
= f.custom_input :content_type do
= f.select :content_type, %w(stylesheet javascript)
= f.custom_input :plain_text_type do
= f.select :plain_text_type, %w(stylesheet javascript)
= f.custom_input :plain_text, :css => 'full', :with_label => false do
%code{ :class => (@theme_asset.size && @theme_asset.size > 40000 ? 'nude' : (@theme_asset.content_type || 'stylesheet')) }
= f.text_area :plain_text
.more
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'
%span.alt
!= t('admin.theme_assets.form.choose_file')
= f.foldable_inputs :name => :options do
= f.input :folder
= f.custom_input :hidden, :css => 'toggle' do
= f.check_box :hidden
= f.input :folder

View File

@ -3,10 +3,16 @@
- content_for :submenu do
= render 'admin/shared/menu/settings'
- content_for :buttons do
= admin_button_tag t('admin.theme_assets.index.new'), new_admin_theme_asset_url, :class => 'new'
- if can?(:manage, ThemeAsset)
- content_for :buttons do
= admin_button_tag t('admin.theme_assets.index.new'), new_admin_theme_asset_url, :class => 'new'
%p
- if %w(image javascript stylesheet).include?(@theme_asset.content_type.to_s)
!= t(".help_#{@theme_asset.content_type}", :path => @theme_asset.local_path(true), :width => @theme_asset.width, :height => @theme_asset.height)
!= t('.help', :url => @theme_asset.source.url)
%p!= t('.help', :url => @theme_asset.source.url)
= semantic_form_for @theme_asset, :url => admin_theme_asset_url(@theme_asset), :html => { :multipart => true, :class => 'save-with-shortcut' } do |form|

View File

@ -4,29 +4,30 @@
= render 'admin/shared/menu/settings'
- content_for :buttons do
= admin_button_tag t('admin.theme_assets.index.all'), all_admin_theme_assets_url, :class => 'show'
= admin_button_tag t('admin.snippets.index.new'), new_admin_snippet_url, :class => 'new'
= admin_button_tag :new, new_admin_theme_asset_url, :class => 'new'
= admin_button_tag t('admin.snippets.index.new'), new_admin_snippet_url, :class => 'new' if can?(:manage, Snippet)
= admin_button_tag :new, new_admin_theme_asset_url, :class => 'new' if can?(:manage, ThemeAsset)
%p!= t('.help')
%h3!= t('.snippets')
- if @snippets.empty?
%p.no-items!= t('admin.snippets.index.no_items', :url => new_admin_snippet_url)
- else
%ul.list.theme-assets
= render @snippets
- if can?(:manage, Snippet)
%h3!= t('.snippets')
- if @snippets.empty?
%p.no-items!= t('admin.snippets.index.no_items', :url => new_admin_snippet_url)
- else
%ul.list.theme-assets
= render @snippets
%br
%br
%h3!= t('.css_and_js')
- if @js_and_css_assets.empty?
%p.no-items!= t('.no_items', :url => new_admin_theme_asset_url)
- else
%ul.list.theme-assets
= render :partial => 'asset', :collection => @js_and_css_assets
- if can?(:manage, ThemeAsset)
%h3!= t('.css_and_js')
- if @js_and_css_assets.empty?
%p.no-items!= t('.no_items', :url => new_admin_theme_asset_url)
- else
%ul.list.theme-assets
= render :partial => 'asset', :collection => @js_and_css_assets
%br
%br
%h3!= t('.images')
- if @assets[:images].nil?
@ -35,12 +36,13 @@
%ul.list.theme-assets
= render :partial => 'asset', :collection => @assets[:images]
- if @assets[:fonts]
%br
- if can?(:manage, ThemeAsset)
- if @assets[:fonts]
%br
%h3!= t('.fonts')
%ul.list.theme-assets
= render :partial => 'asset', :collection => @assets[:fonts]
%h3!= t('.fonts')
%ul.list.theme-assets
= render :partial => 'asset', :collection => @assets[:fonts]
- if @assets[:medias]
%br

View File

@ -45,7 +45,5 @@ module Locomotive
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters << :password
config.middleware.insert_after Rack::Lock, '::Locomotive::Middlewares::Fonts', :path => %r{^/fonts}
end
end
end

View File

@ -21,7 +21,6 @@ javascripts:
- public/javascripts/admin/plugins/toggle.js
- public/javascripts/admin/plugins/growl.js
- public/javascripts/admin/plugins/cookie.js
- public/javascripts/admin/plugins/selectmenu.js
- public/javascripts/admin/locales/datepicker_de.js
- public/javascripts/admin/locales/datepicker_fr.js
- public/javascripts/admin/locales/datepicker_pt-BR.js
@ -38,13 +37,6 @@ javascripts:
- public/javascripts/admin/plugins/mustache.js
- public/javascripts/admin/custom_fields/category.js
- public/javascripts/admin/custom_fields/has_many.js
asset_collections:
- public/javascripts/admin/plugins/fancybox.js
- public/javascripts/admin/plugins/mustache.js
- public/javascripts/admin/custom_fields.js
- public/javascripts/admin/asset_collections.js
assets:
- public/javascripts/admin/assets.js
contents:
- public/javascripts/admin/plugins/tiny_mce/tinymce.js
- public/javascripts/admin/contents.js
@ -53,6 +45,7 @@ javascripts:
- public/javascripts/admin/content_types.js
site:
- public/javascripts/admin/site.js
- public/javascripts/admin/plugins/codemirror/codemirror.min.js
import:
- public/javascripts/admin/plugins/json2.js
- public/javascripts/admin/plugins/smartupdater.js
@ -61,6 +54,7 @@ javascripts:
- public/javascripts/admin/account.js
pages:
- public/javascripts/admin/pages.js
- public/javascripts/admin/plugins/menu_toggler.js
edit_page:
- public/javascripts/admin/plugins/tiny_mce/tinymce.js
- public/javascripts/admin/editable_elements.js
@ -89,12 +83,12 @@ stylesheets:
- public/stylesheets/admin/layout.css
- public/stylesheets/admin/jquery/ui.css
- public/stylesheets/admin/plugins/toggle.css
- public/stylesheets/admin/plugins/selectmenu.css
- public/stylesheets/admin/menu.css
- public/stylesheets/admin/buttons.css
- public/stylesheets/admin/formtastic.css
- public/stylesheets/admin/formtastic_changes.css
- public/stylesheets/admin/assets.css
- public/stylesheets/admin/sites_picker.css
- public/stylesheets/admin/application.css
- public/stylesheets/admin/safari.css
fancybox:

View File

@ -1,2 +1,8 @@
default: features --require features --format pretty --color --tags ~@wip
wip: features --require features --tags @wip
<%
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"
%>
default: <%= std_opts %> features
wip: --tags @wip:3 --wip features
rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip

View File

@ -38,4 +38,4 @@ Locomotive::Application.configure do
# 'BUSHIDO_CLAIMED' => 'true',
# 'BUSHIDO_METRICS_TOKEN' => 'foobar'
# }
end
end

View File

@ -1,90 +1,104 @@
require 'locomotive'
## patches ##
module Devise
module Models
class << self
def hook(base)
if base.is_a?(Module)
base.class_eval do
attr_accessor :devise_modules
def devise_modules
@devise_modules ||= []
end
end
else
base.class_eval do
class_attribute :devise_modules, :instance_writer => false
self.devise_modules ||= []
end
end
end
alias :included :hook
alias :extended :hook
end
end
end
# Use this hook to configure devise mailer, warden hooks and so forth. The first
# four configuration values can also be set straight in your models.
Devise.setup do |config|
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = Locomotive.config.mailer_sender
# Configure the class responsible to send e-mails.
# config.mailer = "Devise::Mailer"
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
# available as additional gems.
require 'devise/orm/mongoid'
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating an user. By default is
# Configure which keys are used when authenticating a user. The default is
# just :email. You can configure it to use [:username, :subdomain], so for
# authenticating an user, both parameters are required. Remember that those
# authenticating a user, both parameters are required. Remember that those
# parameters are used only when authenticating and not when retrieving from
# session. If you need permissions, you should implement that in a before filter.
# You can also supply a hash where the value is a boolean determining whether
# or not authentication should be aborted when the value is not present.
# config.authentication_keys = [ :email ]
# Configure parameters from the request object used for authentication. Each entry
# given should be a request method and it will automatically be passed to the
# find_for_authentication method and considered in your model lookup. For instance,
# if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
# The same considerations mentioned for authentication_keys also apply to request_keys.
# config.request_keys = []
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
config.case_insensitive_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true
# Tell if authentication through HTTP Basic Auth is enabled. True by default.
# config.http_authenticatable = true
# Tell if authentication through HTTP Basic Auth is enabled. False by default.
# config.http_authenticatable = false
# The realm used in Http Basic Authentication
# If http headers should be returned for AJAX requests. True by default.
# config.http_authenticatable_on_xhr = true
# The realm used in Http Basic Authentication. "Application" by default.
# config.http_authentication_realm = "Application"
# ==> Configuration for :database_authenticatable
# Invoke `rake secret` and use the printed value to setup a pepper to generate
# the encrypted password. By default no pepper is used.
# config.pepper = "rake secret output"
# For bcrypt, this is the cost for hashing the password and defaults to 10. If
# using other encryptors, it sets how many times you want the password re-encrypted.
config.stretches = 10
# Configure how many times you want the password is reencrypted. Default is 10.
# config.stretches = 10
# Define which will be the encryption algorithm. Supported algorithms are :sha1
# (default), :sha512 and :bcrypt. Devise also supports encryptors from others
# authentication tools as :clearance_sha1, :authlogic_sha512 (then you should set
# stretches above to 20 for default behavior) and :restful_authentication_sha1
# (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
config.encryptor = :sha1
# Setup a pepper to generate the encrypted password.
# config.pepper = "de368d6a1517489510a2ae145328ff1c238f03b02da8f57032936a353835e2ca20561decfb5f7bfafad095fa73cee55b101ed11a0d0f913429d3d9bd114d810e"
# ==> Configuration for :confirmable
# The time you want give to your user to confirm his account. During this time
# he will be able to access your application without confirming. Default is nil.
# The time you want to give your user to confirm his account. During this time
# he will be able to access your application without confirming. Default is 0.days
# When confirm_within is zero, the user won't be able to sign in without confirming.
# You can use this to let your user access some features of your application
# without confirming the account, but blocking it after a certain period
# (ie 2 days).
# config.confirm_within = 2.days
# Defines which key will be used when confirming an account
# config.confirmation_keys = [ :email ]
# ==> Configuration for :rememberable
# The time the user will be remembered without asking for credentials again.
# config.remember_for = 2.weeks
config.remember_for = 2.weeks
# If true, a valid remember token can be re-used between multiple browsers.
# config.remember_across_browsers = true
# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
# If true, uses the password salt as remember token. This should be turned
# to false if you are not using database authenticatable.
config.use_salt_as_remember_token = true
# Options to be passed to the created cookie. For instance, you can set
# :secure => true in order to force SSL only cookies.
# config.cookie_options = {}
# ==> Configuration for :validatable
# Range for password length
# config.password_length = 6..20
# Range for password length. Default is 6..128.
# config.password_length = 6..128
# Regex to use to validate the email address
# config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
# config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again.
# config.timeout_in = 10.minutes
# time the user will be asked for credentials again. Default is 30 minutes.
# config.timeout_in = 30.minutes
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
@ -92,9 +106,12 @@ Devise.setup do |config|
# :none = No lock strategy. You should handle locking by yourself.
# config.lock_strategy = :failed_attempts
# Defines which key will be used when locking and unlocking an account
# config.unlock_keys = [ :email ]
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Reanables login after a certain ammount of time (see :unlock_in below)
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
# :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself.
# config.unlock_strategy = :both
@ -106,35 +123,74 @@ Devise.setup do |config|
# Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour
# ==> Configuration for :recoverable
#
# Defines which key will be used when recovering the password for an account
# config.reset_password_keys = [ :email ]
# Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to
# change their passwords.
config.reset_password_within = 2.hours
# ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
# :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
# :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
# and :restful_authentication_sha1 (then you should set stretches to 10, and copy
# REST_AUTH_SITE_KEY to pepper)
# config.encryptor = :sha1
# ==> Configuration for :token_authenticatable
# Defines name of the authentication token params key
# config.token_authentication_key = :auth_token
# ==> General configuration
# Load and configure the ORM. Supports :active_record (default), :mongoid
# and :data_mapper (experimental).
require 'active_support/core_ext/class/attribute'
require 'devise/orm/mongoid'
# If true, authentication through token does not store user in session and needs
# to be supplied on each request. Useful if you are using the token as API token.
# config.stateless_token = false
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "sessions/users/new". It's turned off by default because it's slower if you
# "users/sessions/new". It's turned off by default because it's slower if you
# are using only default views.
config.scoped_views = true
# Configure the default scope used by Devise. By default it's the first devise
# role declared in your routes.
# Configure the default scope given to Warden. By default it's the first
# devise role declared in your routes (usually :user).
config.default_scope = :account
# If you want to use other strategies, that are not (yet) supported by Devise,
# you can configure them inside the config.warden block. The example below
# allows you to setup OAuth, using http://github.com/roman/warden_oauth
# Configure sign_out behavior.
# Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope).
# The default is true, which means any logout action will sign out all active scopes.
# config.sign_out_all_scopes = true
# ==> Navigation configuration
# Lists the formats that should be treated as navigational. Formats like
# :html, should redirect to the sign in page when the user does not have
# access, but formats like :xml or :json, should return 401.
#
# If you have any extra navigational formats, like :iphone or :mobile, you
# should add them to the navigational formats lists.
#
# The :"*/*" and "*/*" formats below is required to match Internet
# Explorer requests.
# config.navigational_formats = [:"*/*", "*/*", :html]
# The default HTTP method used to sign out a resource. Default is :get.
# config.sign_out_via = :get
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
# change the failure app, you can configure them inside the config.warden block.
#
# config.warden do |manager|
# manager.oauth(:twitter) do |twitter|
# twitter.consumer_secret = <YOUR CONSUMER SECRET>
# twitter.consumer_key = <YOUR CONSUMER KEY>
# twitter.options :site => 'http://twitter.com'
# end
# manager.default_strategies(:scope => :user).unshift :twitter_oauth
# manager.failure_app = AnotherApp
# manager.intercept_401 = false
# manager.default_strategies(:scope => :user).unshift :some_external_strategy
# end
end

View File

@ -0,0 +1,31 @@
require 'locomotive'
unless Locomotive.engine?
require 'dragonfly'
## initialize Dragonfly ##
app = Dragonfly[:images]
app.configure_with(:rails)
app.configure_with(:imagemagick)
## configure it ##
Dragonfly[:images].configure do |c|
# Convert absolute location needs to be specified
# to avoid issues with Phusion Passenger not using $PATH
convert = `which convert`.strip.presence || "/usr/local/bin/convert"
c.convert_command = convert
c.identify_command = convert
c.allow_fetch_url = true
c.allow_fetch_file = true
c.url_format = '/images/dynamic/:job/:basename.:format'
end
end

View File

@ -62,4 +62,16 @@ Locomotive.configure do |config|
# config.mailer_sender = 'support'
# # => 'support@heroku.com' (Heroku), 'support@bushi.do' (Bushido), 'support@example.com' (Dev) or 'support@<your_hosting_platform>' (Multi-sites)
config.mailer_sender = 'support'
# Rack-cache settings, mainly used for the inline resizing image module. Default options:
# config.rack_cache = {
# :verbose => true,
# :metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), # URI encoded in case of spaces
# :entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
# }
# If you do want to disable it for good, just use the following syntax
# config.rack_cache = false
#
# Note: by default, rack/cache is disabled in the Heroku platform
end unless Locomotive.engine? || Rails.env.test?

View File

@ -6,4 +6,5 @@ require 'digest/sha1'
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
token = ENV['BUSHIDO_SALT'] || 'aa84844b97e90edda8e005a686d82c3bef1f8e20a1255301f1d0886fc592a45ef2393d64b0c3d3ea858b1f6406ad6f15305666264716a79fcfa17de93ad0d69d'
Rails.application.config.secret_token = Digest::SHA1.hexdigest(token)

Some files were not shown because too many files have changed in this diff Show More