namespace controllers, models, ...etc (wip)
This commit is contained in:
parent
9f8d2e4146
commit
99e442673c
2
.gitignore
vendored
2
.gitignore
vendored
@ -34,5 +34,5 @@ sites/
|
|||||||
permanent
|
permanent
|
||||||
doc/bushido
|
doc/bushido
|
||||||
*.swp
|
*.swp
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
4
Gemfile
4
Gemfile
@ -11,7 +11,7 @@ gem 'cancan', '~> 1.6.7'
|
|||||||
|
|
||||||
gem 'mongoid', '~> 2.3.2'
|
gem 'mongoid', '~> 2.3.2'
|
||||||
gem 'bson_ext', '~> 1.3.1'
|
gem 'bson_ext', '~> 1.3.1'
|
||||||
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.7', :require => 'mongoid_acts_as_tree'
|
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.7', :require => 'mongoid_acts_as_tree', :path => '../gems/acts_as_tree' # TODO: REPLACE IT
|
||||||
gem 'custom_fields', '~> 1.1.0.rc1'
|
gem 'custom_fields', '~> 1.1.0.rc1'
|
||||||
gem 'will_paginate', '~> 3.0.2'
|
gem 'will_paginate', '~> 3.0.2'
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ gem 'rubyzip'
|
|||||||
|
|
||||||
gem 'actionmailer-with-request', '~> 0.3.0', :require => 'actionmailer_with_request'
|
gem 'actionmailer-with-request', '~> 0.3.0', :require => 'actionmailer_with_request'
|
||||||
gem 'httparty', '~> 0.8.1'
|
gem 'httparty', '~> 0.8.1'
|
||||||
gem 'delayed_job', '~> 3.0.0.pre2'
|
gem 'delayed_job', '~> 2.1.1'
|
||||||
gem 'delayed_job_mongoid', '~> 1.0.4'
|
gem 'delayed_job_mongoid', '~> 1.0.4'
|
||||||
gem 'SystemTimer', :platforms => :ruby_18
|
gem 'SystemTimer', :platforms => :ruby_18
|
||||||
|
|
||||||
|
348
Gemfile.lock
348
Gemfile.lock
@ -1,58 +1,75 @@
|
|||||||
|
GIT
|
||||||
|
remote: git://github.com/chriseppstein/compass.git
|
||||||
|
revision: 22e2458b77519e8eb8463170c1a1fe4bab105f3e
|
||||||
|
branch: rails31
|
||||||
|
specs:
|
||||||
|
compass (0.12.0.alpha.0.22e2458)
|
||||||
|
chunky_png (~> 1.2)
|
||||||
|
fssm (>= 0.2.7)
|
||||||
|
sass (~> 3.1)
|
||||||
|
|
||||||
|
GIT
|
||||||
|
remote: git://github.com/yabawock/handlebars-rails.git
|
||||||
|
revision: a09077aa91f10e08403af84586b2f2f0b38d9e2f
|
||||||
|
specs:
|
||||||
|
handlebars-rails (0.9.1)
|
||||||
|
|
||||||
|
PATH
|
||||||
|
remote: ../gems/acts_as_tree
|
||||||
|
specs:
|
||||||
|
locomotive_mongoid_acts_as_tree (0.1.5.7)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: http://rubygems.org/
|
remote: http://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
POpen4 (0.1.4)
|
|
||||||
Platform (>= 0.4.0)
|
|
||||||
open4
|
|
||||||
Platform (0.4.0)
|
|
||||||
RedCloth (4.2.8)
|
RedCloth (4.2.8)
|
||||||
SystemTimer (1.2.3)
|
SystemTimer (1.2.3)
|
||||||
ZenTest (4.6.2)
|
ZenTest (4.6.2)
|
||||||
abstract (1.0.0)
|
actionmailer (3.1.1)
|
||||||
actionmailer (3.0.10)
|
actionpack (= 3.1.1)
|
||||||
actionpack (= 3.0.10)
|
mail (~> 2.3.0)
|
||||||
mail (~> 2.2.19)
|
|
||||||
actionmailer-with-request (0.3.0)
|
actionmailer-with-request (0.3.0)
|
||||||
rails (>= 3)
|
rails (>= 3)
|
||||||
actionpack (3.0.10)
|
actionpack (3.1.1)
|
||||||
activemodel (= 3.0.10)
|
activemodel (= 3.1.1)
|
||||||
activesupport (= 3.0.10)
|
activesupport (= 3.1.1)
|
||||||
builder (~> 2.1.2)
|
builder (~> 3.0.0)
|
||||||
erubis (~> 2.6.6)
|
erubis (~> 2.7.0)
|
||||||
i18n (~> 0.5.0)
|
i18n (~> 0.6)
|
||||||
rack (~> 1.2.1)
|
rack (~> 1.3.2)
|
||||||
rack-mount (~> 0.6.14)
|
rack-cache (~> 1.1)
|
||||||
rack-test (~> 0.5.7)
|
rack-mount (~> 0.8.2)
|
||||||
tzinfo (~> 0.3.23)
|
rack-test (~> 0.6.1)
|
||||||
activemodel (3.0.10)
|
sprockets (~> 2.0.2)
|
||||||
activesupport (= 3.0.10)
|
activemodel (3.1.1)
|
||||||
builder (~> 2.1.2)
|
activesupport (= 3.1.1)
|
||||||
i18n (~> 0.5.0)
|
builder (~> 3.0.0)
|
||||||
activerecord (3.0.10)
|
i18n (~> 0.6)
|
||||||
activemodel (= 3.0.10)
|
activerecord (3.1.1)
|
||||||
activesupport (= 3.0.10)
|
activemodel (= 3.1.1)
|
||||||
arel (~> 2.0.10)
|
activesupport (= 3.1.1)
|
||||||
tzinfo (~> 0.3.23)
|
arel (~> 2.2.1)
|
||||||
activeresource (3.0.10)
|
tzinfo (~> 0.3.29)
|
||||||
activemodel (= 3.0.10)
|
activeresource (3.1.1)
|
||||||
activesupport (= 3.0.10)
|
activemodel (= 3.1.1)
|
||||||
activesupport (3.0.10)
|
activesupport (= 3.1.1)
|
||||||
|
activesupport (3.1.1)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
addressable (2.2.6)
|
||||||
archive-tar-minitar (0.5.2)
|
archive-tar-minitar (0.5.2)
|
||||||
arel (2.0.10)
|
arel (2.2.1)
|
||||||
autotest (4.4.6)
|
autotest (4.4.6)
|
||||||
ZenTest (>= 4.4.1)
|
ZenTest (>= 4.4.1)
|
||||||
bcrypt-ruby (2.1.4)
|
bcrypt-ruby (3.0.1)
|
||||||
bson (1.4.0)
|
bson (1.4.1)
|
||||||
bson_ext (1.4.0)
|
bson_ext (1.3.1)
|
||||||
builder (2.1.2)
|
builder (3.0.0)
|
||||||
bushido (0.0.35)
|
bushido (0.0.35)
|
||||||
highline (>= 1.6.1)
|
highline (>= 1.6.1)
|
||||||
json (>= 1.4.6)
|
json (>= 1.4.6)
|
||||||
orm_adapter (~> 0.0.3)
|
orm_adapter (~> 0.0.3)
|
||||||
rest-client (>= 1.6.1)
|
rest-client (>= 1.6.1)
|
||||||
bushido_stub (0.0.3)
|
cancan (1.6.7)
|
||||||
activesupport (>= 3.0.7)
|
|
||||||
cancan (1.6.5)
|
|
||||||
capybara (1.1.1)
|
capybara (1.1.1)
|
||||||
mime-types (>= 1.16)
|
mime-types (>= 1.16)
|
||||||
nokogiri (>= 1.3.3)
|
nokogiri (>= 1.3.3)
|
||||||
@ -60,16 +77,22 @@ GEM
|
|||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.5.4)
|
||||||
selenium-webdriver (~> 2.0)
|
selenium-webdriver (~> 2.0)
|
||||||
xpath (~> 0.1.4)
|
xpath (~> 0.1.4)
|
||||||
carrierwave (0.5.6)
|
carrierwave (0.5.7)
|
||||||
activesupport (~> 3.0)
|
activesupport (~> 3.0)
|
||||||
cells (3.6.6)
|
carrierwave-mongoid (0.1.3)
|
||||||
|
carrierwave (>= 0.5.6)
|
||||||
|
mongoid (~> 2.1)
|
||||||
|
cells (3.7.0)
|
||||||
actionpack (~> 3.0)
|
actionpack (~> 3.0)
|
||||||
railties (~> 3.0)
|
railties (~> 3.0)
|
||||||
childprocess (0.2.2)
|
childprocess (0.2.2)
|
||||||
ffi (~> 1.0.6)
|
ffi (~> 1.0.6)
|
||||||
|
chunky_png (1.2.5)
|
||||||
|
coffee-script (2.2.0)
|
||||||
|
coffee-script-source
|
||||||
|
execjs
|
||||||
|
coffee-script-source (1.1.2)
|
||||||
columnize (0.3.4)
|
columnize (0.3.4)
|
||||||
configuration (1.3.1)
|
|
||||||
crack (0.1.8)
|
|
||||||
cucumber (1.1.0)
|
cucumber (1.1.0)
|
||||||
builder (>= 2.1.2)
|
builder (>= 2.1.2)
|
||||||
diff-lcs (>= 1.1.2)
|
diff-lcs (>= 1.1.2)
|
||||||
@ -80,133 +103,134 @@ GEM
|
|||||||
capybara (>= 1.1.1)
|
capybara (>= 1.1.1)
|
||||||
cucumber (>= 1.1.0)
|
cucumber (>= 1.1.0)
|
||||||
nokogiri (>= 1.5.0)
|
nokogiri (>= 1.5.0)
|
||||||
custom_fields (1.0.0.beta.25)
|
custom_fields (1.1.0.rc1)
|
||||||
activesupport (~> 3.0.9)
|
activesupport (~> 3.1.1)
|
||||||
mongoid (= 2.0.2)
|
carrierwave-mongoid (~> 0.1.3)
|
||||||
|
mongoid (= 2.3.2)
|
||||||
daemons (1.1.4)
|
daemons (1.1.4)
|
||||||
database_cleaner (0.6.7)
|
database_cleaner (0.6.7)
|
||||||
delayed_job (2.1.4)
|
delayed_job (2.1.4)
|
||||||
activesupport (~> 3.0)
|
activesupport (~> 3.0)
|
||||||
daemons
|
daemons
|
||||||
delayed_job_mongoid (1.0.2)
|
delayed_job_mongoid (1.0.4)
|
||||||
delayed_job (~> 2.1.1)
|
delayed_job (~> 2.1.1)
|
||||||
mongoid (~> 2.0.0.rc)
|
mongoid (>= 2.0)
|
||||||
devise (1.3.4)
|
devise (1.4.9)
|
||||||
bcrypt-ruby (~> 2.1.2)
|
bcrypt-ruby (~> 3.0)
|
||||||
orm_adapter (~> 0.0.3)
|
orm_adapter (~> 0.0.3)
|
||||||
warden (~> 1.0.3)
|
warden (~> 1.0.3)
|
||||||
devise_bushido_authenticatable (1.0.0.alpha10)
|
|
||||||
devise
|
|
||||||
devise (>= 1.0.6)
|
|
||||||
rubycas-client (>= 2.2.1)
|
|
||||||
diff-lcs (1.1.3)
|
diff-lcs (1.1.3)
|
||||||
dragonfly (0.9.8)
|
dragonfly (0.9.8)
|
||||||
rack
|
rack
|
||||||
erubis (2.6.6)
|
ejs (1.0.0)
|
||||||
abstract (>= 1.0.0)
|
erubis (2.7.0)
|
||||||
excon (0.6.6)
|
excon (0.7.6)
|
||||||
factory_girl (2.1.2)
|
execjs (1.2.9)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
factory_girl (2.2.0)
|
||||||
activesupport
|
activesupport
|
||||||
factory_girl_rails (1.2.0)
|
factory_girl_rails (1.3.0)
|
||||||
factory_girl (~> 2.1.0)
|
factory_girl (~> 2.2.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
ffi (1.0.9)
|
ffi (1.0.9)
|
||||||
fog (0.8.2)
|
fog (1.0.0)
|
||||||
builder
|
builder
|
||||||
excon (~> 0.6.1)
|
excon (~> 0.7.3)
|
||||||
formatador (>= 0.1.3)
|
formatador (~> 0.2.0)
|
||||||
json
|
|
||||||
mime-types
|
mime-types
|
||||||
net-ssh (>= 2.1.3)
|
multi_json (~> 1.0.3)
|
||||||
nokogiri (>= 1.4.4)
|
net-scp (~> 1.0.4)
|
||||||
|
net-ssh (~> 2.1.4)
|
||||||
|
nokogiri (~> 1.5.0)
|
||||||
ruby-hmac
|
ruby-hmac
|
||||||
formatador (0.2.1)
|
formatador (0.2.1)
|
||||||
formtastic (1.2.4)
|
formtastic (1.2.4)
|
||||||
actionpack (>= 2.3.7)
|
actionpack (>= 2.3.7)
|
||||||
activesupport (>= 2.3.7)
|
activesupport (>= 2.3.7)
|
||||||
i18n (~> 0.4)
|
i18n (~> 0.4)
|
||||||
gherkin (2.5.2)
|
fssm (0.2.7)
|
||||||
|
gherkin (2.5.4)
|
||||||
json (>= 1.4.6)
|
json (>= 1.4.6)
|
||||||
growl-glue (1.0.7)
|
growl-glue (1.0.7)
|
||||||
haml (3.1.2)
|
haml (3.1.3)
|
||||||
has_scope (0.5.1)
|
has_scope (0.5.1)
|
||||||
heroku (1.19.1)
|
|
||||||
activesupport (>= 2.1.0)
|
|
||||||
launchy (~> 0.3.2)
|
|
||||||
rest-client (>= 1.4.0, < 1.7.0)
|
|
||||||
highline (1.6.2)
|
highline (1.6.2)
|
||||||
httparty (0.7.8)
|
hike (1.2.1)
|
||||||
crack (= 0.1.8)
|
httparty (0.8.1)
|
||||||
i18n (0.5.0)
|
multi_json
|
||||||
inherited_resources (1.1.2)
|
multi_xml
|
||||||
|
i18n (0.6.0)
|
||||||
|
inherited_resources (1.3.0)
|
||||||
has_scope (~> 0.5.0)
|
has_scope (~> 0.5.0)
|
||||||
responders (~> 0.6.0)
|
responders (~> 0.6.0)
|
||||||
jammit (0.6.3)
|
jquery-rails (1.0.16)
|
||||||
yui-compressor (>= 0.9.3)
|
railties (~> 3.0)
|
||||||
|
thor (~> 0.14)
|
||||||
json (1.6.1)
|
json (1.6.1)
|
||||||
json_pure (1.6.1)
|
json_pure (1.6.1)
|
||||||
kgio (2.6.0)
|
kgio (2.6.0)
|
||||||
launchy (0.3.7)
|
launchy (2.0.5)
|
||||||
configuration (>= 0.0.5)
|
addressable (~> 2.2.6)
|
||||||
rake (>= 0.8.1)
|
|
||||||
linecache (0.43)
|
linecache (0.43)
|
||||||
linecache19 (0.5.12)
|
linecache19 (0.5.12)
|
||||||
ruby_core_source (>= 0.1.4)
|
ruby_core_source (>= 0.1.4)
|
||||||
locomotive_jammit-s3 (0.5.4.4)
|
|
||||||
jammit (>= 0.5.4)
|
|
||||||
mimemagic (>= 0.1.7)
|
|
||||||
s3 (>= 0.3.7)
|
|
||||||
locomotive_liquid (2.2.2)
|
locomotive_liquid (2.2.2)
|
||||||
locomotive_mongoid_acts_as_tree (0.1.5.7)
|
mail (2.3.0)
|
||||||
mongoid (= 2.0.2)
|
|
||||||
mail (2.2.19)
|
|
||||||
activesupport (>= 2.3.6)
|
|
||||||
i18n (>= 0.4.0)
|
i18n (>= 0.4.0)
|
||||||
mime-types (~> 1.16)
|
mime-types (~> 1.16)
|
||||||
treetop (~> 1.4.8)
|
treetop (~> 1.4.8)
|
||||||
mime-types (1.16)
|
mime-types (1.17.2)
|
||||||
mimemagic (0.1.8)
|
|
||||||
mimetype-fu (0.1.2)
|
mimetype-fu (0.1.2)
|
||||||
mocha (0.9.12)
|
mocha (0.9.12)
|
||||||
mongo (1.4.0)
|
mongo (1.4.1)
|
||||||
bson (= 1.4.0)
|
bson (= 1.4.1)
|
||||||
mongoid (2.0.2)
|
mongoid (2.3.2)
|
||||||
activemodel (~> 3.0)
|
activemodel (~> 3.1)
|
||||||
mongo (~> 1.3)
|
mongo (~> 1.4)
|
||||||
tzinfo (~> 0.3.22)
|
tzinfo (~> 0.3.22)
|
||||||
net-ssh (2.2.1)
|
multi_json (1.0.3)
|
||||||
|
multi_xml (0.4.1)
|
||||||
|
net-scp (1.0.4)
|
||||||
|
net-ssh (>= 1.99.1)
|
||||||
|
net-ssh (2.1.4)
|
||||||
nokogiri (1.5.0)
|
nokogiri (1.5.0)
|
||||||
open4 (1.1.0)
|
|
||||||
orm_adapter (0.0.5)
|
orm_adapter (0.0.5)
|
||||||
pickle (0.4.10)
|
pickle (0.4.10)
|
||||||
cucumber (>= 0.8)
|
cucumber (>= 0.8)
|
||||||
rake
|
rake
|
||||||
polyglot (0.3.2)
|
polyglot (0.3.2)
|
||||||
proxies (0.2.1)
|
rack (1.3.5)
|
||||||
rack (1.2.4)
|
|
||||||
rack-cache (1.1)
|
rack-cache (1.1)
|
||||||
rack (>= 0.4)
|
rack (>= 0.4)
|
||||||
rack-mount (0.6.14)
|
rack-mount (0.8.3)
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
rack-test (0.5.7)
|
rack-ssl (1.3.2)
|
||||||
|
rack
|
||||||
|
rack-test (0.6.1)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (3.0.10)
|
rails (3.1.1)
|
||||||
actionmailer (= 3.0.10)
|
actionmailer (= 3.1.1)
|
||||||
actionpack (= 3.0.10)
|
actionpack (= 3.1.1)
|
||||||
activerecord (= 3.0.10)
|
activerecord (= 3.1.1)
|
||||||
activeresource (= 3.0.10)
|
activeresource (= 3.1.1)
|
||||||
activesupport (= 3.0.10)
|
activesupport (= 3.1.1)
|
||||||
bundler (~> 1.0)
|
bundler (~> 1.0)
|
||||||
railties (= 3.0.10)
|
railties (= 3.1.1)
|
||||||
railties (3.0.10)
|
rails-backbone (0.5.4)
|
||||||
actionpack (= 3.0.10)
|
coffee-script (~> 2.2.0)
|
||||||
activesupport (= 3.0.10)
|
ejs (~> 1.0.0)
|
||||||
|
rails (~> 3.1.0)
|
||||||
|
railties (3.1.1)
|
||||||
|
actionpack (= 3.1.1)
|
||||||
|
activesupport (= 3.1.1)
|
||||||
|
rack-ssl (~> 1.3.2)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
rdoc (~> 3.4)
|
rdoc (~> 3.4)
|
||||||
thor (~> 0.14.4)
|
thor (~> 0.14.6)
|
||||||
raindrops (0.7.0)
|
raindrops (0.8.0)
|
||||||
rake (0.9.2)
|
rake (0.9.2)
|
||||||
rdoc (3.9.4)
|
rdoc (3.11)
|
||||||
|
json (~> 1.4)
|
||||||
responders (0.6.4)
|
responders (0.6.4)
|
||||||
rest-client (1.6.7)
|
rest-client (1.6.7)
|
||||||
mime-types (>= 1.16)
|
mime-types (>= 1.16)
|
||||||
@ -215,8 +239,7 @@ GEM
|
|||||||
rspec-core (~> 2.6.0)
|
rspec-core (~> 2.6.0)
|
||||||
rspec-expectations (~> 2.6.0)
|
rspec-expectations (~> 2.6.0)
|
||||||
rspec-mocks (~> 2.6.0)
|
rspec-mocks (~> 2.6.0)
|
||||||
rspec-cells (0.0.5)
|
rspec-cells (0.1.0)
|
||||||
cells (~> 3.4)
|
|
||||||
rails (~> 3.0)
|
rails (~> 3.0)
|
||||||
rspec-rails (~> 2.2)
|
rspec-rails (~> 2.2)
|
||||||
rspec-core (2.6.4)
|
rspec-core (2.6.4)
|
||||||
@ -244,82 +267,91 @@ GEM
|
|||||||
ruby-hmac (0.4.0)
|
ruby-hmac (0.4.0)
|
||||||
ruby_core_source (0.1.5)
|
ruby_core_source (0.1.5)
|
||||||
archive-tar-minitar (>= 0.5.2)
|
archive-tar-minitar (>= 0.5.2)
|
||||||
rubycas-client (2.2.1)
|
|
||||||
activesupport
|
|
||||||
rubyzip (0.9.4)
|
rubyzip (0.9.4)
|
||||||
s3 (0.3.8)
|
|
||||||
proxies (~> 0.2.0)
|
|
||||||
sanitize (2.0.3)
|
sanitize (2.0.3)
|
||||||
nokogiri (>= 1.4.4, < 1.6)
|
nokogiri (< 1.6, >= 1.4.4)
|
||||||
sass (3.1.2)
|
sass (3.1.10)
|
||||||
selenium-webdriver (2.8.0)
|
sass-rails (3.1.4)
|
||||||
|
actionpack (~> 3.1.0)
|
||||||
|
railties (~> 3.1.0)
|
||||||
|
sass (>= 3.1.4)
|
||||||
|
sprockets (~> 2.0.0)
|
||||||
|
tilt (~> 1.3.2)
|
||||||
|
selenium-webdriver (2.10.0)
|
||||||
childprocess (>= 0.2.1)
|
childprocess (>= 0.2.1)
|
||||||
ffi (>= 1.0.7)
|
ffi (= 1.0.9)
|
||||||
json_pure
|
json_pure
|
||||||
rubyzip
|
rubyzip
|
||||||
spork (0.9.0.rc9)
|
spork (0.9.0.rc9)
|
||||||
|
sprockets (2.0.3)
|
||||||
|
hike (~> 1.2)
|
||||||
|
rack (~> 1.0)
|
||||||
|
tilt (!= 1.3.0, ~> 1.1)
|
||||||
term-ansicolor (1.0.7)
|
term-ansicolor (1.0.7)
|
||||||
thor (0.14.6)
|
thor (0.14.6)
|
||||||
|
tilt (1.3.3)
|
||||||
treetop (1.4.10)
|
treetop (1.4.10)
|
||||||
polyglot
|
polyglot
|
||||||
polyglot (>= 0.3.1)
|
polyglot (>= 0.3.1)
|
||||||
tzinfo (0.3.29)
|
tzinfo (0.3.30)
|
||||||
|
uglifier (1.0.4)
|
||||||
|
execjs (>= 0.3.0)
|
||||||
|
multi_json (>= 1.0.2)
|
||||||
unicorn (4.1.1)
|
unicorn (4.1.1)
|
||||||
kgio (~> 2.4)
|
kgio (~> 2.4)
|
||||||
rack
|
rack
|
||||||
raindrops (~> 0.6)
|
raindrops (~> 0.6)
|
||||||
warden (1.0.5)
|
warden (1.0.6)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
will_paginate (3.0.2)
|
will_paginate (3.0.2)
|
||||||
xpath (0.1.4)
|
xpath (0.1.4)
|
||||||
nokogiri (~> 1.3)
|
nokogiri (~> 1.3)
|
||||||
yui-compressor (0.9.6)
|
|
||||||
POpen4 (>= 0.1.4)
|
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
RedCloth (= 4.2.8)
|
RedCloth (~> 4.2.8)
|
||||||
SystemTimer
|
SystemTimer
|
||||||
ZenTest
|
ZenTest
|
||||||
actionmailer-with-request
|
actionmailer-with-request (~> 0.3.0)
|
||||||
autotest
|
autotest
|
||||||
bson_ext (~> 1.4.0)
|
bson_ext (~> 1.3.1)
|
||||||
bushido (= 0.0.35)
|
bushido (= 0.0.35)
|
||||||
bushido_stub (= 0.0.3)
|
cancan (~> 1.6.7)
|
||||||
cancan
|
|
||||||
capybara
|
capybara
|
||||||
carrierwave (= 0.5.6)
|
carrierwave-mongoid (~> 0.1.3)
|
||||||
cells
|
cells (~> 3.7.0)
|
||||||
|
coffee-script (~> 2.2.0)
|
||||||
|
compass!
|
||||||
cucumber-rails
|
cucumber-rails
|
||||||
custom_fields (= 1.0.0.beta.25)
|
custom_fields (~> 1.1.0.rc1)
|
||||||
database_cleaner
|
database_cleaner
|
||||||
delayed_job (= 2.1.4)
|
delayed_job (~> 2.1.1)
|
||||||
delayed_job_mongoid (= 1.0.2)
|
delayed_job_mongoid (~> 1.0.4)
|
||||||
devise (= 1.3.4)
|
devise (~> 1.4.9)
|
||||||
devise_bushido_authenticatable (= 1.0.0.alpha10)
|
dragonfly (~> 0.9.8)
|
||||||
dragonfly (~> 0.9.1)
|
|
||||||
factory_girl_rails (~> 1.1)
|
factory_girl_rails (~> 1.1)
|
||||||
fog (= 0.8.2)
|
fog (~> 1.0.0)
|
||||||
formtastic (~> 1.2.3)
|
formtastic (~> 1.2.3)
|
||||||
growl-glue
|
growl-glue
|
||||||
haml (= 3.1.2)
|
haml (~> 3.1.3)
|
||||||
heroku (= 1.19.1)
|
handlebars-rails!
|
||||||
highline
|
highline (~> 1.6.2)
|
||||||
httparty (= 0.7.8)
|
httparty (~> 0.8.1)
|
||||||
inherited_resources (~> 1.1.2)
|
inherited_resources (~> 1.3.0)
|
||||||
|
jquery-rails (~> 1.0.16)
|
||||||
launchy
|
launchy
|
||||||
linecache (= 0.43)
|
linecache (= 0.43)
|
||||||
locomotive_jammit-s3
|
|
||||||
locomotive_liquid (= 2.2.2)
|
locomotive_liquid (= 2.2.2)
|
||||||
locomotive_mongoid_acts_as_tree (= 0.1.5.7)
|
locomotive_mongoid_acts_as_tree (= 0.1.5.7)!
|
||||||
mimetype-fu
|
mimetype-fu (~> 0.1.2)
|
||||||
mocha (= 0.9.12)
|
mocha (= 0.9.12)
|
||||||
mongoid (~> 2.0.2)
|
mongoid (~> 2.3.2)
|
||||||
pickle
|
pickle
|
||||||
rack-cache
|
rack-cache (~> 1.1)
|
||||||
rails (= 3.0.10)
|
rails (~> 3.1.1)
|
||||||
|
rails-backbone (= 0.5.4)
|
||||||
rake (= 0.9.2)
|
rake (= 0.9.2)
|
||||||
rmagick (= 2.12.2)
|
rmagick (= 2.12.2)
|
||||||
rspec-cells
|
rspec-cells
|
||||||
@ -327,10 +359,10 @@ DEPENDENCIES
|
|||||||
ruby-debug
|
ruby-debug
|
||||||
ruby-debug19
|
ruby-debug19
|
||||||
rubyzip
|
rubyzip
|
||||||
sanitize
|
sanitize (~> 2.0.3)
|
||||||
sass (= 3.1.2)
|
sass-rails (~> 3.1.4)
|
||||||
spork (~> 0.9.0.rc)
|
spork (~> 0.9.0.rc)
|
||||||
|
uglifier (~> 1.0.4)
|
||||||
unicorn
|
unicorn
|
||||||
warden
|
will_paginate (~> 3.0.2)
|
||||||
will_paginate (~> 3.0.0)
|
|
||||||
xpath (~> 0.1.4)
|
xpath (~> 0.1.4)
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
class Admin::GlobalActionsCell < ::Admin::MenuCell
|
|
||||||
|
|
||||||
attr_reader :current_admin, :current_site_url
|
|
||||||
|
|
||||||
def show(args)
|
|
||||||
@current_admin = args[:current_admin]
|
|
||||||
@current_site_url = args[:current_site_url]
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def build_list
|
|
||||||
add :welcome, :url => edit_admin_my_account_url, :i18n_options => {
|
|
||||||
:key => 'admin.shared.header.welcome',
|
|
||||||
:arg => :name,
|
|
||||||
:value => @current_admin.name
|
|
||||||
}
|
|
||||||
|
|
||||||
add :see, :url => current_site_url, :id => 'viewsite', :target => '_blank'
|
|
||||||
|
|
||||||
if Locomotive.config.multi_sites? && current_admin.sites.size > 1
|
|
||||||
add :switch, :url => '#', :id => 'sites-picker-link'
|
|
||||||
end
|
|
||||||
|
|
||||||
add :help, :url => '#', :class => 'tutorial', :id => 'help'
|
|
||||||
add :logout, :url => destroy_admin_session_url, :confirm => t('admin.messages.confirm')
|
|
||||||
end
|
|
||||||
|
|
||||||
def localize_label(label, options = {})
|
|
||||||
I18n.t("admin.shared.header.#{label}", options)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,10 +0,0 @@
|
|||||||
class Admin::MainMenuCell < ::Admin::MenuCell
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def build_list
|
|
||||||
add :contents, :url => admin_pages_url
|
|
||||||
add :settings, :url => edit_admin_current_site_url
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,17 +0,0 @@
|
|||||||
class Admin::SettingsMenuCell < ::Admin::SubMenuCell #::Admin::MenuCell
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def build_list
|
|
||||||
add :site, :url => edit_admin_current_site_url
|
|
||||||
add :theme_assets, :url => admin_theme_assets_url
|
|
||||||
add :account, :url => edit_admin_my_account_url
|
|
||||||
end
|
|
||||||
|
|
||||||
# def build_item(name, attributes)
|
|
||||||
# item = super
|
|
||||||
# enhanced_class = "#{'on' if name.to_s == sections(:sub)} #{item[:class]}"
|
|
||||||
# item.merge(:class => enhanced_class)
|
|
||||||
# end
|
|
||||||
|
|
||||||
end
|
|
34
app/cells/locomotive/global_actions_cell.rb
Normal file
34
app/cells/locomotive/global_actions_cell.rb
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
class Locomotive::GlobalActionsCell < ::Locomotive::MenuCell
|
||||||
|
|
||||||
|
attr_reader :current_account, :current_site_url
|
||||||
|
|
||||||
|
def show(args)
|
||||||
|
@current_account = args[:current_account]
|
||||||
|
@current_site_url = args[:current_site_url]
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def build_list
|
||||||
|
add :welcome, :url => edit_locomotive_my_account_url, :i18n_options => {
|
||||||
|
:key => 'locomotive.shared.header.welcome',
|
||||||
|
:arg => :name,
|
||||||
|
:value => @current_account.name
|
||||||
|
}
|
||||||
|
|
||||||
|
add :see, :url => current_site_url, :id => 'viewsite', :target => '_blank'
|
||||||
|
|
||||||
|
if Locomotive.config.multi_sites? && current_account.sites.size > 1
|
||||||
|
add :switch, :url => '#', :id => 'sites-picker-link'
|
||||||
|
end
|
||||||
|
|
||||||
|
add :help, :url => '#', :class => 'tutorial', :id => 'help'
|
||||||
|
add :logout, :url => destroy_locomotive_session_url, :confirm => t('locomotive.messages.confirm')
|
||||||
|
end
|
||||||
|
|
||||||
|
def localize_label(label, options = {})
|
||||||
|
I18n.t("locomotive.shared.header.#{label}", options)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
10
app/cells/locomotive/main_menu_cell.rb
Normal file
10
app/cells/locomotive/main_menu_cell.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class Locomotive::MainMenuCell < ::Locomotive::MenuCell
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def build_list
|
||||||
|
add :contents, :url => locomotive_pages_url
|
||||||
|
add :settings, :url => edit_locomotive_current_site_url
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -1,4 +1,4 @@
|
|||||||
class Admin::MenuCell < Cell::Base
|
class Locomotive::MenuCell < Cell::Base
|
||||||
|
|
||||||
include ::Rails.application.routes.url_helpers
|
include ::Rails.application.routes.url_helpers
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ class Admin::MenuCell < Cell::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def localize_label(label)
|
def localize_label(label)
|
||||||
I18n.t("admin.shared.menu.#{label}")
|
I18n.t("locomotive.shared.menu.#{label}")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
11
app/cells/locomotive/settings_menu_cell.rb
Normal file
11
app/cells/locomotive/settings_menu_cell.rb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
class Locomotive::SettingsMenuCell < ::Locomotive::SubMenuCell
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def build_list
|
||||||
|
add :site, :url => edit_locomotive_current_site_url
|
||||||
|
add :theme_assets, :url => locomotive_theme_assets_url
|
||||||
|
add :account, :url => edit_locomotive_my_account_url
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -1,4 +1,4 @@
|
|||||||
class Admin::SubMenuCell < ::Admin::MenuCell
|
class Locomotive::SubMenuCell < ::Locomotive::MenuCell
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
class ApplicationController < ActionController::Base
|
|
||||||
protect_from_forgery
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
# rescue_from Exception, :with => :render_error
|
|
||||||
#
|
|
||||||
# def render_error
|
|
||||||
# render :template => "/admin/errors/500", :layout => '/admin/layouts/box', :status => 500
|
|
||||||
# end
|
|
||||||
end
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class AccountsController < BaseController
|
class AccountsController < BaseController
|
||||||
|
|
||||||
sections 'settings'
|
sections 'settings'
|
||||||
@ -11,7 +11,7 @@ module Admin
|
|||||||
@account = Account.create(params[:account])
|
@account = Account.create(params[:account])
|
||||||
current_site.memberships.create(:account => @account) if @account.errors.empty?
|
current_site.memberships.create(:account => @account) if @account.errors.empty?
|
||||||
|
|
||||||
respond_with @account, :location => edit_admin_current_site_url
|
respond_with @account, :location => edit_locomotive_current_site_url
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class ApiContentsController < ActionController::Base
|
class ApiContentsController < ActionController::Base
|
||||||
|
|
||||||
include Locomotive::Routing::SiteDispatcher
|
include Locomotive::Routing::SiteDispatcher
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class AssetsController < BaseController
|
class AssetsController < BaseController
|
||||||
|
|
||||||
include ActionView::Helpers::SanitizeHelper
|
include ActionView::Helpers::SanitizeHelper
|
||||||
@ -48,7 +48,7 @@ module Admin
|
|||||||
:content_type => asset.content_type,
|
:content_type => asset.content_type,
|
||||||
:url => asset.source.url,
|
:url => asset.source.url,
|
||||||
:vignette_url => asset.vignette_url,
|
:vignette_url => asset.vignette_url,
|
||||||
:destroy_url => admin_asset_url(asset, :json)
|
:destroy_url => locomotive_asset_url(asset, :json)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class BaseController < InheritedResources::Base
|
class BaseController < InheritedResources::Base
|
||||||
|
|
||||||
include Locomotive::Routing::SiteDispatcher
|
include Locomotive::Routing::SiteDispatcher
|
||||||
|
|
||||||
layout '/admin/layouts/application'
|
layout '/locomotive/layouts/application'
|
||||||
|
|
||||||
before_filter :require_admin
|
before_filter :require_account
|
||||||
|
|
||||||
before_filter :require_site
|
before_filter :require_site
|
||||||
|
|
||||||
@ -21,12 +21,12 @@ module Admin
|
|||||||
|
|
||||||
# https://rails.lighthouseapp.com/projects/8994/tickets/1905-apphelpers-within-plugin-not-being-mixed-in
|
# 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|
|
Dir[File.dirname(__FILE__) + "/../../helpers/**/*_helper.rb"].each do |file|
|
||||||
helper "admin/#{File.basename(file, '.rb').gsub(/_helper$/, '')}"
|
helper "locomotive/#{File.basename(file, '.rb').gsub(/_helper$/, '')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
self.responder = Locomotive::AdminResponder # custom responder
|
self.responder = Locomotive::AdminResponder # custom responder
|
||||||
|
|
||||||
defaults :route_prefix => 'admin'
|
defaults :route_prefix => 'locomotive'
|
||||||
|
|
||||||
respond_to :html
|
respond_to :html
|
||||||
|
|
||||||
@ -38,23 +38,23 @@ module Admin
|
|||||||
else
|
else
|
||||||
flash[:alert] = exception.message
|
flash[:alert] = exception.message
|
||||||
|
|
||||||
redirect_to admin_pages_url
|
redirect_to locomotive_pages_url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def set_current_thread_variables
|
def set_current_thread_variables
|
||||||
Thread.current[:admin] = current_admin
|
Thread.current[:account] = current_account
|
||||||
Thread.current[:site] = current_site
|
Thread.current[:site] = current_site
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_ability
|
def current_ability
|
||||||
@current_ability ||= Ability.new(current_admin, current_site)
|
@current_ability ||= Ability.new(current_account, current_site)
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_admin
|
def require_account
|
||||||
authenticate_admin!
|
authenticate_account!
|
||||||
end
|
end
|
||||||
|
|
||||||
def begin_of_association_chain
|
def begin_of_association_chain
|
||||||
@ -78,7 +78,7 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_locale
|
def set_locale
|
||||||
I18n.locale = current_admin.locale rescue Locomotive.config.default_locale
|
I18n.locale = current_account.locale rescue Locomotive.config.default_locale
|
||||||
end
|
end
|
||||||
|
|
||||||
# ___ site/page urls builder ___
|
# ___ site/page urls builder ___
|
@ -1,10 +1,10 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class ContentTypesController < BaseController
|
class ContentTypesController < BaseController
|
||||||
|
|
||||||
sections 'contents'
|
sections 'contents'
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
destroy! { admin_pages_url }
|
destroy! { locomotive_pages_url }
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class ContentsController < BaseController
|
class ContentsController < BaseController
|
||||||
|
|
||||||
sections 'contents'
|
sections 'contents'
|
||||||
@ -36,11 +36,11 @@ module Admin
|
|||||||
def sort
|
def sort
|
||||||
@content_type.sort_contents!(params[:children])
|
@content_type.sort_contents!(params[:children])
|
||||||
|
|
||||||
respond_with(@content_type, :location => admin_contents_url(@content_type.slug))
|
respond_with(@content_type, :location => locomotive_contents_url(@content_type.slug))
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
destroy! { admin_contents_url(@content_type.slug) }
|
destroy! { locomotive_contents_url(@content_type.slug) }
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
@ -55,7 +55,7 @@ module Admin
|
|||||||
|
|
||||||
def after_create_or_update_url
|
def after_create_or_update_url
|
||||||
if params[:breadcrumb_alias].blank?
|
if params[:breadcrumb_alias].blank?
|
||||||
edit_admin_content_url(@content_type.slug, @content.id)
|
edit_locomotive_content_url(@content_type.slug, @content.id)
|
||||||
else
|
else
|
||||||
self.breadcrumb_url
|
self.breadcrumb_url
|
||||||
end
|
end
|
||||||
@ -72,11 +72,11 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def breadcrumb_url
|
def breadcrumb_url
|
||||||
edit_admin_content_url(self.breadcrumb_root._parent.slug, self.breadcrumb_root)
|
edit_locomotive_content_url(self.breadcrumb_root._parent.slug, self.breadcrumb_root)
|
||||||
end
|
end
|
||||||
|
|
||||||
def back_url
|
def back_url
|
||||||
self.breadcrumb_root ? self.breadcrumb_url : admin_contents_url(@content_type.slug)
|
self.breadcrumb_root ? self.breadcrumb_url : locomotive_contents_url(@content_type.slug)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,25 +1,25 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class CrossDomainSessionsController < BaseController
|
class CrossDomainSessionsController < BaseController
|
||||||
|
|
||||||
layout '/admin/layouts/box'
|
layout '/locomotive/layouts/box'
|
||||||
|
|
||||||
skip_before_filter :verify_authenticity_token
|
skip_before_filter :verify_authenticity_token
|
||||||
|
|
||||||
skip_before_filter :validate_site_membership
|
skip_before_filter :validate_site_membership
|
||||||
|
|
||||||
before_filter :require_admin, :only => :new
|
before_filter :require_account, :only => :new
|
||||||
|
|
||||||
skip_load_and_authorize_resource
|
skip_load_and_authorize_resource
|
||||||
|
|
||||||
def new
|
def new
|
||||||
if site = current_admin.sites.detect { |s| s._id.to_s == params[:target_id] }
|
if site = current_account.sites.detect { |s| s._id.to_s == params[:target_id] }
|
||||||
if Rails.env == 'development'
|
if Rails.env == 'development'
|
||||||
@target = site.full_subdomain
|
@target = site.full_subdomain
|
||||||
else
|
else
|
||||||
@target = site.domains_without_subdomain.first || site.full_subdomain
|
@target = site.domains_without_subdomain.first || site.full_subdomain
|
||||||
end
|
end
|
||||||
|
|
||||||
current_admin.reset_switch_site_token!
|
current_account.reset_switch_site_token!
|
||||||
else
|
else
|
||||||
redirect_to admin_pages_path
|
redirect_to admin_pages_path
|
||||||
end
|
end
|
||||||
@ -31,7 +31,7 @@ module Admin
|
|||||||
sign_in(account)
|
sign_in(account)
|
||||||
redirect_to admin_pages_path
|
redirect_to admin_pages_path
|
||||||
else
|
else
|
||||||
redirect_to new_admin_session_path, :alert => t('flash.admin.cross_domain_sessions.create.alert')
|
redirect_to new_admin_session_path, :alert => t('fash.locomotive.cross_domain_sessions.create.alert')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class CurrentSiteController < BaseController
|
class CurrentSiteController < BaseController
|
||||||
|
|
||||||
defaults :instance_name => 'site'
|
defaults :instance_name => 'site'
|
||||||
@ -15,7 +15,7 @@ module Admin
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
update! do |success, failure|
|
update! do |success, failure|
|
||||||
success.html { redirect_to edit_admin_current_site_url(new_host_if_subdomain_changed) }
|
success.html { redirect_to edit_locomotive_current_site_url(new_host_if_subdomain_changed) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class CustomFieldsController < BaseController
|
class CustomFieldsController < BaseController
|
||||||
|
|
||||||
layout false
|
layout false
|
||||||
@ -18,7 +18,7 @@ module Admin
|
|||||||
if @field.update_attributes(params[:custom_field])
|
if @field.update_attributes(params[:custom_field])
|
||||||
render :json => @field.to_json
|
render :json => @field.to_json
|
||||||
else
|
else
|
||||||
render :json => { :error => t('flash.admin.custom_fields.update.alert') }
|
render :json => { :error => t('flash.locomotive.custom_fields.update.alert') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class ExportController < BaseController
|
class ExportController < BaseController
|
||||||
|
|
||||||
skip_load_and_authorize_resource
|
skip_load_and_authorize_resource
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class ImportController < BaseController
|
class ImportController < BaseController
|
||||||
|
|
||||||
sections 'settings', 'site'
|
sections 'settings', 'site'
|
||||||
@ -14,7 +14,7 @@ module Admin
|
|||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
redirect_to new_admin_import_url if @job.nil?
|
redirect_to new_locomotive_import_url if @job.nil?
|
||||||
end
|
end
|
||||||
format.json { render :json => {
|
format.json { render :json => {
|
||||||
:step => @job.nil? ? 'done' : @job.step,
|
:step => @job.nil? ? 'done' : @job.step,
|
||||||
@ -32,14 +32,14 @@ module Admin
|
|||||||
:reset => Boolean.set(params[:reset])
|
:reset => Boolean.set(params[:reset])
|
||||||
})
|
})
|
||||||
|
|
||||||
flash[:notice] = t("flash.admin.import.create.#{Locomotive.config.delayed_job ? 'notice' : 'done'}")
|
flash[:notice] = t("fash.locomotive.import.create.#{Locomotive.config.delayed_job ? 'notice' : 'done'}")
|
||||||
|
|
||||||
redirect_to Locomotive.config.delayed_job ? admin_import_url : new_admin_import_url
|
redirect_to Locomotive.config.delayed_job ? locomotive_import_url : new_locomotive_import_url
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
logger.error "[Locomotive import] #{e.message} / #{e.backtrace}"
|
logger.error "[Locomotive import] #{e.message} / #{e.backtrace}"
|
||||||
|
|
||||||
@error = e.message
|
@error = e.message
|
||||||
flash[:alert] = t('flash.admin.import.create.alert')
|
flash[:alert] = t('fash.locomotive.import.create.alert')
|
||||||
|
|
||||||
render 'new'
|
render 'new'
|
||||||
end
|
end
|
@ -1,11 +1,11 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class InstallationController < BaseController
|
class InstallationController < BaseController
|
||||||
|
|
||||||
layout '/admin/layouts/box'
|
layout '/locomotive/layouts/box'
|
||||||
|
|
||||||
skip_before_filter :require_site
|
skip_before_filter :require_site
|
||||||
|
|
||||||
skip_before_filter :require_admin
|
skip_before_filter :require_account
|
||||||
|
|
||||||
skip_before_filter :verify_authenticity_token
|
skip_before_filter :verify_authenticity_token
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ module Admin
|
|||||||
when 1 # create account
|
when 1 # create account
|
||||||
@account = Account.create(params[:account])
|
@account = Account.create(params[:account])
|
||||||
if @account.valid?
|
if @account.valid?
|
||||||
redirect_to admin_installation_step_url(2)
|
redirect_to locomotive_installation_step_url(2)
|
||||||
else
|
else
|
||||||
render 'step_1'
|
render 'step_1'
|
||||||
end
|
end
|
||||||
@ -58,7 +58,7 @@ module Admin
|
|||||||
case params[:step].to_i
|
case params[:step].to_i
|
||||||
when 1 # already an account in db
|
when 1 # already an account in db
|
||||||
if account = Account.first
|
if account = Account.first
|
||||||
@step_done = I18n.t('admin.installation.step_1.done', :name => account.name, :email => account.email)
|
@step_done = I18n.t('locomotive.installation.step_1.done', :name => account.name, :email => account.email)
|
||||||
render 'step_1' and return false
|
render 'step_1' and return false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -67,14 +67,14 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def allow_installation?
|
def allow_installation?
|
||||||
redirect_to admin_pages_url if Site.count > 0 && Account.count > 0
|
redirect_to locomotive_pages_url if Site.count > 0 && Account.count > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def last_url
|
def last_url
|
||||||
if Locomotive.config.manage_domains?
|
if Locomotive.config.manage_domains?
|
||||||
admin_session_url(:host => Site.first.domains.first, :port => request.port)
|
locomotive_session_url(:host => Site.first.domains.first, :port => request.port)
|
||||||
else
|
else
|
||||||
admin_session_url
|
locomotive_session_url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class MembershipsController < BaseController
|
class MembershipsController < BaseController
|
||||||
|
|
||||||
sections 'settings'
|
sections 'settings'
|
||||||
@ -8,18 +8,18 @@ module Admin
|
|||||||
|
|
||||||
case resource.process!
|
case resource.process!
|
||||||
when :create_account
|
when :create_account
|
||||||
redirect_to new_admin_account_url(:email => resource.email)
|
redirect_to new_locomotive_account_url(:email => resource.email)
|
||||||
when :save_it
|
when :save_it
|
||||||
respond_with resource, :location => edit_admin_current_site_url
|
respond_with resource, :location => edit_locomotive_current_site_url
|
||||||
when :error
|
when :error
|
||||||
respond_with resource, :flash => true
|
respond_with resource, :flash => true
|
||||||
when :already_created
|
when :already_created
|
||||||
respond_with resource, :alert => t('flash.admin.memberships.create.already_created'), :location => edit_admin_current_site_url
|
respond_with resource, :alert => t('flash.locomotive.memberships.create.already_created'), :location => edit_locomotive_current_site_url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
destroy! { edit_admin_current_site_url }
|
destroy! { edit_locomotive_current_site_url }
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class MyAccountController < BaseController
|
class MyAccountController < BaseController
|
||||||
|
|
||||||
sections 'settings', 'account'
|
sections 'settings', 'account'
|
||||||
@ -10,13 +10,13 @@ module Admin
|
|||||||
skip_load_and_authorize_resource
|
skip_load_and_authorize_resource
|
||||||
|
|
||||||
def update
|
def update
|
||||||
update! { edit_admin_my_account_url }
|
update! { edit_locomotive_my_account_url }
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def resource
|
def resource
|
||||||
@account = current_admin
|
@account = current_account
|
||||||
end
|
end
|
||||||
|
|
||||||
def begin_of_association_chain; nil; end # not related directly to current_site
|
def begin_of_association_chain; nil; end # not related directly to current_site
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class PagesController < BaseController
|
class PagesController < BaseController
|
||||||
|
|
||||||
sections 'contents'
|
sections 'contents'
|
||||||
@ -17,9 +17,9 @@ module Admin
|
|||||||
update! do |success, failure|
|
update! do |success, failure|
|
||||||
success.json do
|
success.json do
|
||||||
render :json => {
|
render :json => {
|
||||||
:notice => t('flash.admin.pages.update.notice'),
|
:notice => t('flash.locomotive.pages.update.notice'),
|
||||||
:editable_elements => @page.template_changed ?
|
:editable_elements => @page.template_changed ?
|
||||||
render_to_string(:partial => 'admin/pages/editable_elements.html.haml') : ''
|
render_to_string(:partial => 'locomotive/pages/editable_elements.html.haml') : ''
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,13 +1,13 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class PasswordsController < Devise::PasswordsController
|
class PasswordsController < Devise::PasswordsController
|
||||||
|
|
||||||
include Locomotive::Routing::SiteDispatcher
|
include Locomotive::Routing::SiteDispatcher
|
||||||
|
|
||||||
layout '/admin/layouts/box'
|
layout '/locomotive/layouts/box'
|
||||||
|
|
||||||
before_filter :require_site
|
before_filter :require_site
|
||||||
|
|
||||||
helper 'admin/base', 'admin/box'
|
helper 'locomotive/base', 'locomotive/box'
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class RenderingController < ActionController::Base
|
class RenderingController < ActionController::Base
|
||||||
|
|
||||||
include Locomotive::Routing::SiteDispatcher
|
include Locomotive::Routing::SiteDispatcher
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class RobotsController < ActionController::Base
|
class RobotsController < ActionController::Base
|
||||||
|
|
||||||
include Locomotive::Routing::SiteDispatcher
|
include Locomotive::Routing::SiteDispatcher
|
@ -1,18 +1,18 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class SessionsController < Devise::SessionsController
|
class SessionsController < Devise::SessionsController
|
||||||
|
|
||||||
include Locomotive::Routing::SiteDispatcher
|
include Locomotive::Routing::SiteDispatcher
|
||||||
|
|
||||||
layout '/admin/layouts/box'
|
layout '/locomotive/layouts/box'
|
||||||
|
|
||||||
before_filter :require_site
|
before_filter :require_site
|
||||||
|
|
||||||
helper 'admin/base', 'admin/box'
|
helper 'locomotive/base', 'locomotive/box'
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def after_sign_in_path_for(resource)
|
def after_sign_in_path_for(resource)
|
||||||
admin_pages_url
|
locomotive_pages_url
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_sign_out_path_for(resource)
|
def after_sign_out_path_for(resource)
|
@ -1,7 +1,7 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class SitemapsController < BaseController
|
class SitemapsController < BaseController
|
||||||
|
|
||||||
skip_before_filter :require_admin, :validate_site_membership, :set_locale
|
skip_before_filter :require_account, :validate_site_membership, :set_locale
|
||||||
|
|
||||||
before_filter :require_site
|
before_filter :require_site
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class SitesController < BaseController
|
class SitesController < BaseController
|
||||||
|
|
||||||
defaults :instance_name => 'site'
|
defaults :instance_name => 'site'
|
||||||
@ -7,13 +7,13 @@ module Admin
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
@site = Site.new(params[:site])
|
@site = Site.new(params[:site])
|
||||||
@site.memberships.build :account => @current_admin, :role => 'admin'
|
@site.memberships.build :account => @current_account, :role => 'admin'
|
||||||
|
|
||||||
create! { edit_admin_my_account_url }
|
create! { edit_locomotive_my_account_url }
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@site = current_admin.sites.find(params[:id])
|
@site = current_account.sites.find(params[:id])
|
||||||
|
|
||||||
if @site != current_site
|
if @site != current_site
|
||||||
@site.destroy
|
@site.destroy
|
||||||
@ -21,7 +21,7 @@ module Admin
|
|||||||
@site.errors.add(:base, 'Can not destroy the site you are logging in now')
|
@site.errors.add(:base, 'Can not destroy the site you are logging in now')
|
||||||
end
|
end
|
||||||
|
|
||||||
respond_with @site, :location => edit_admin_my_account_url
|
respond_with @site, :location => edit_locomotive_my_account_url
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class SnippetsController < BaseController
|
class SnippetsController < BaseController
|
||||||
|
|
||||||
sections 'settings', 'theme_assets'
|
sections 'settings', 'theme_assets'
|
||||||
@ -7,7 +7,7 @@ module Admin
|
|||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
destroy! do |format|
|
destroy! do |format|
|
||||||
format.html { redirect_to admin_theme_assets_url }
|
format.html { redirect_to locomotive_theme_assets_url }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class ThemeAssetsController < BaseController
|
class ThemeAssetsController < BaseController
|
||||||
|
|
||||||
include ActionView::Helpers::SanitizeHelper
|
include ActionView::Helpers::SanitizeHelper
|
@ -1,7 +1,7 @@
|
|||||||
module Admin::AccountsHelper
|
module Locomotive::AccountsHelper
|
||||||
|
|
||||||
def admin_on?(site = current_site)
|
def admin_on?(site = current_site)
|
||||||
site.memberships.detect { |m| m.admin? && m.account == current_admin }
|
site.memberships.detect { |m| m.admin? && m.account == current_account }
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::AssetsHelper
|
module Locomotive::AssetsHelper
|
||||||
|
|
||||||
def vignette_tag(asset)
|
def vignette_tag(asset)
|
||||||
if asset.image?
|
if asset.image?
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::BaseHelper
|
module Locomotive::BaseHelper
|
||||||
|
|
||||||
def title(title = nil)
|
def title(title = nil)
|
||||||
if title.nil?
|
if title.nil?
|
||||||
@ -15,7 +15,7 @@ module Admin::BaseHelper
|
|||||||
|
|
||||||
css = "#{'on' if name == sections(:sub)} #{options[:css]}"
|
css = "#{'on' if name == sections(:sub)} #{options[:css]}"
|
||||||
|
|
||||||
label_link = default_options[:i18n] ? t("admin.shared.menu.#{name}") : name
|
label_link = default_options[:i18n] ? t("locomotive.shared.menu.#{name}") : name
|
||||||
if block_given?
|
if block_given?
|
||||||
popup = content_tag(:div, capture(&block), :class => 'popup', :style => 'display: none')
|
popup = content_tag(:div, capture(&block), :class => 'popup', :style => 'display: none')
|
||||||
link = link_to(content_tag(:span, preserve(label_link) + content_tag(:em)) + content_tag(:em), url, :class => css)
|
link = link_to(content_tag(:span, preserve(label_link) + content_tag(:em)) + content_tag(:em), url, :class => css)
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::BoxHelper
|
module Locomotive::BoxHelper
|
||||||
|
|
||||||
def box_flash_message
|
def box_flash_message
|
||||||
if not flash.empty?
|
if not flash.empty?
|
||||||
@ -15,7 +15,7 @@ module Admin::BoxHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def next_installation_step_link(step = 1, label = nil)
|
def next_installation_step_link(step = 1, label = nil)
|
||||||
link_to(content_tag(:span, label || t('admin.installation.common.next')), admin_installation_step_url(step), :class => 'button')
|
link_to(content_tag(:span, label || t('locomotive.installation.common.next')), locomotive_installation_step_url(step), :class => 'button')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::ContentTypesHelper
|
module Locomotive::ContentTypesHelper
|
||||||
|
|
||||||
MAX_DISPLAYED_CONTENTS = 4
|
MAX_DISPLAYED_CONTENTS = 4
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ module Admin::ContentTypesHelper
|
|||||||
item_on = (content_type.slug == @content_type.slug) rescue nil
|
item_on = (content_type.slug == @content_type.slug) rescue nil
|
||||||
|
|
||||||
label = truncate(content_type.name, :length => 15)
|
label = truncate(content_type.name, :length => 15)
|
||||||
url = admin_contents_url(content_type.slug)
|
url = locomotive_contents_url(content_type.slug)
|
||||||
css = @content_type && content_type.slug == @content_type.slug ? 'on' : ''
|
css = @content_type && content_type.slug == @content_type.slug ? 'on' : ''
|
||||||
|
|
||||||
html = admin_content_menu_item(label, url, :i18n => false, :css => css) do
|
html = admin_content_menu_item(label, url, :i18n => false, :css => css) do
|
||||||
@ -79,7 +79,7 @@ module Admin::ContentTypesHelper
|
|||||||
registers = {
|
registers = {
|
||||||
:controller => self,
|
:controller => self,
|
||||||
:site => current_site,
|
:site => current_site,
|
||||||
:current_admin => current_admin
|
:current_account => current_account
|
||||||
}
|
}
|
||||||
|
|
||||||
preserve(content._parent.item_template.render(::Liquid::Context.new({}, assigns, registers)))
|
preserve(content._parent.item_template.render(::Liquid::Context.new({}, assigns, registers)))
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::CustomFieldsHelper
|
module Locomotive::CustomFieldsHelper
|
||||||
|
|
||||||
def options_for_field_kind
|
def options_for_field_kind
|
||||||
%w(string text category boolean date file has_one has_many).map do |kind|
|
%w(string text category boolean date file has_one has_many).map do |kind|
|
||||||
@ -8,14 +8,14 @@ module Admin::CustomFieldsHelper
|
|||||||
|
|
||||||
def options_for_order_by(content_type, collection_name)
|
def options_for_order_by(content_type, collection_name)
|
||||||
options = %w{created_at updated_at _position_in_list}.map do |type|
|
options = %w{created_at updated_at _position_in_list}.map do |type|
|
||||||
[t("admin.content_types.form.order_by.#{type.gsub(/^_/, '')}"), type]
|
[t("locomotive.content_types.form.order_by.#{type.gsub(/^_/, '')}"), type]
|
||||||
end
|
end
|
||||||
options + options_for_highlighted_field(content_type, collection_name)
|
options + options_for_highlighted_field(content_type, collection_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def options_for_order_direction
|
def options_for_order_direction
|
||||||
%w(asc desc).map do |direction|
|
%w(asc desc).map do |direction|
|
||||||
[t("admin.content_types.form.order_direction.#{direction}"), direction]
|
[t("locomotive.content_types.form.order_direction.#{direction}"), direction]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ module Admin::CustomFieldsHelper
|
|||||||
|
|
||||||
def options_for_text_formatting
|
def options_for_text_formatting
|
||||||
options = %w(none html).map do |option|
|
options = %w(none html).map do |option|
|
||||||
[t("admin.custom_fields.text_formatting.#{option}"), option]
|
[t("locomotive.custom_fields.text_formatting.#{option}"), option]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -128,10 +128,10 @@ module Admin::CustomFieldsHelper
|
|||||||
|
|
||||||
options.merge!(
|
options.merge!(
|
||||||
:new_item => {
|
:new_item => {
|
||||||
:label => t('admin.contents.form.has_many.new_item'),
|
:label => t('locomotive.contents.form.has_many.new_item'),
|
||||||
:url => new_admin_content_url(field.target_klass._parent.slug, url_options)
|
:url => new_locomotive_content_url(field.target_klass._parent.slug, url_options)
|
||||||
},
|
},
|
||||||
:edit_item_url => edit_admin_content_url(field.target_klass._parent.slug, 42, url_options)
|
:edit_item_url => edit_locomotive_content_url(field.target_klass._parent.slug, 42, url_options)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::PagesHelper
|
module Locomotive::PagesHelper
|
||||||
|
|
||||||
def parent_pages_options
|
def parent_pages_options
|
||||||
roots = current_site.pages.roots.where(:slug.ne => '404').and(:_id.ne => @page.id)
|
roots = current_site.pages.roots.where(:slug.ne => '404').and(:_id.ne => @page.id)
|
@ -1,4 +1,4 @@
|
|||||||
module Admin::SitesHelper
|
module Locomotive::SitesHelper
|
||||||
|
|
||||||
def application_domain
|
def application_domain
|
||||||
domain = Locomotive.config.domain
|
domain = Locomotive.config.domain
|
@ -1,4 +1,4 @@
|
|||||||
module Admin
|
module Locomotive
|
||||||
class Notifications < ActionMailer::Base
|
class Notifications < ActionMailer::Base
|
||||||
|
|
||||||
default :from => Locomotive.config.mailer_sender
|
default :from => Locomotive.config.mailer_sender
|
||||||
@ -6,7 +6,7 @@ module Admin
|
|||||||
def new_content_instance(account, content)
|
def new_content_instance(account, content)
|
||||||
@account, @content = account, content
|
@account, @content = account, content
|
||||||
|
|
||||||
subject = t('admin.notifications.new_content_instance.subject', :type => content.content_type.name, :locale => account.locale)
|
subject = t('locomotive.notifications.new_content_instance.subject', :type => content.content_type.name, :locale => account.locale)
|
||||||
|
|
||||||
mail :subject => subject, :to => account.email
|
mail :subject => subject, :to => account.email
|
||||||
end
|
end
|
@ -1,83 +0,0 @@
|
|||||||
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, Asset
|
|
||||||
|
|
||||||
can :manage, Site do |site|
|
|
||||||
site == @site
|
|
||||||
end
|
|
||||||
|
|
||||||
can :import, Site
|
|
||||||
|
|
||||||
can :export, Site
|
|
||||||
|
|
||||||
can :point, Site
|
|
||||||
|
|
||||||
cannot :create, Site
|
|
||||||
|
|
||||||
can :manage, Membership
|
|
||||||
|
|
||||||
cannot :grant_admin, Membership
|
|
||||||
|
|
||||||
cannot [:update, :destroy], 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 [:update, :destroy], Membership do |membership|
|
|
||||||
@membership.account_id == membership.account_id # can not edit myself
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,60 +0,0 @@
|
|||||||
require 'digest'
|
|
||||||
|
|
||||||
class Account
|
|
||||||
|
|
||||||
include Locomotive::Mongoid::Document
|
|
||||||
|
|
||||||
devise *Locomotive.config.devise_modules
|
|
||||||
|
|
||||||
## attributes ##
|
|
||||||
field :name
|
|
||||||
field :locale, :default => Locomotive.config.default_locale.to_s or 'en'
|
|
||||||
field :switch_site_token
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :name
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
before_destroy :remove_memberships!
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
def sites
|
|
||||||
@sites ||= Site.where({ 'memberships.account_id' => self._id })
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_switch_site_token!
|
|
||||||
self.switch_site_token = ActiveSupport::SecureRandom.base64(8).gsub("/", "_").gsub(/=+$/, "")
|
|
||||||
self.save
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.find_using_switch_site_token(token, age = 1.minute)
|
|
||||||
return if token.blank?
|
|
||||||
self.where(:switch_site_token => token, :updated_at.gt => age.ago.utc).first
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.find_using_switch_site_token!(token, age = 1.minute)
|
|
||||||
self.find_using_switch_site_token(token, age) || raise(Mongoid::Errors::DocumentNotFound.new(self, token))
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def password_required?
|
|
||||||
!persisted? || !password.blank? || !password_confirmation.blank?
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_memberships!
|
|
||||||
self.sites.each do |site|
|
|
||||||
membership = site.memberships.where(:account_id => self._id).first
|
|
||||||
|
|
||||||
if site.admin_memberships.size == 1 && membership.admin?
|
|
||||||
raise I18n.t('errors.messages.needs_admin_account')
|
|
||||||
else
|
|
||||||
membership.destroy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,39 +0,0 @@
|
|||||||
class Asset
|
|
||||||
|
|
||||||
include Mongoid::Document
|
|
||||||
include Mongoid::Timestamps
|
|
||||||
|
|
||||||
## extensions ##
|
|
||||||
include Extensions::Asset::Types
|
|
||||||
include Extensions::Asset::Vignette
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :content_type, :type => String
|
|
||||||
field :width, :type => Integer
|
|
||||||
field :height, :type => Integer
|
|
||||||
field :size, :type => Integer
|
|
||||||
field :position, :type => Integer, :default => 0
|
|
||||||
mount_uploader :source, AssetUploader
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
referenced_in :site
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :source
|
|
||||||
|
|
||||||
## behaviours ##
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
alias :name :source_filename
|
|
||||||
|
|
||||||
def extname
|
|
||||||
return nil unless self.source?
|
|
||||||
File.extname(self.source_filename).gsub(/^\./, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_liquid
|
|
||||||
{ :url => self.source.url }.merge(self.attributes).stringify_keys
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,125 +0,0 @@
|
|||||||
class ContentInstance
|
|
||||||
|
|
||||||
include Mongoid::Document
|
|
||||||
include Mongoid::Timestamps
|
|
||||||
|
|
||||||
## extensions ##
|
|
||||||
include CustomFields::ProxyClassEnabler
|
|
||||||
include Extensions::Shared::Seo
|
|
||||||
|
|
||||||
## fields (dynamic fields) ##
|
|
||||||
field :_slug
|
|
||||||
field :_position_in_list, :type => Integer, :default => 0
|
|
||||||
field :_visible, :type => Boolean, :default => true
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validate :require_highlighted_field
|
|
||||||
validate :validate_uniqueness_of_slug
|
|
||||||
validates_presence_of :_slug
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
embedded_in :content_type, :inverse_of => :contents
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
before_validation :set_slug
|
|
||||||
before_save :set_visibility
|
|
||||||
before_create :add_to_list_bottom
|
|
||||||
after_create :send_notifications
|
|
||||||
|
|
||||||
## named scopes ##
|
|
||||||
scope :latest_updated, :order_by => :updated_at.desc, :limit => Locomotive.config.lastest_items_nb
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
delegate :site, :to => :content_type
|
|
||||||
|
|
||||||
alias :visible? :_visible?
|
|
||||||
alias :_permalink :_slug
|
|
||||||
alias :_permalink= :_slug=
|
|
||||||
|
|
||||||
def site_id # needed by the uploader of custom fields
|
|
||||||
self.content_type.site_id
|
|
||||||
end
|
|
||||||
|
|
||||||
def highlighted_field_value
|
|
||||||
self.send(self.content_type.highlighted_field_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
alias :_label :highlighted_field_value
|
|
||||||
|
|
||||||
def visible?
|
|
||||||
self._visible || self._visible.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def next
|
|
||||||
content_type.contents.where(:_position_in_list => _position_in_list + 1).first()
|
|
||||||
end
|
|
||||||
|
|
||||||
def previous
|
|
||||||
content_type.contents.where(:_position_in_list => _position_in_list - 1).first()
|
|
||||||
end
|
|
||||||
|
|
||||||
def errors_to_hash
|
|
||||||
Hash.new.replace(self.errors)
|
|
||||||
end
|
|
||||||
|
|
||||||
def reload_parent!
|
|
||||||
self.class.reload_parent!
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.reload_parent!
|
|
||||||
self._parent = self._parent.reload
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_liquid
|
|
||||||
Locomotive::Liquid::Drops::Content.new(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def set_slug
|
|
||||||
self._slug = self.highlighted_field_value.dup if self._slug.blank? && self.highlighted_field_value.present?
|
|
||||||
self._slug.permalink! if self._slug.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_visibility
|
|
||||||
field = self.content_type.content_custom_fields.detect { |f| %w{visible active}.include?(f._alias) }
|
|
||||||
self._visible = self.send(field._name) rescue true
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_to_list_bottom
|
|
||||||
self._position_in_list = self.content_type.contents.size
|
|
||||||
end
|
|
||||||
|
|
||||||
def require_highlighted_field
|
|
||||||
_alias = self.highlighted_field_alias
|
|
||||||
if self.send(_alias).blank?
|
|
||||||
self.errors.add(_alias, :blank)
|
|
||||||
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
|
|
||||||
|
|
||||||
def send_notifications
|
|
||||||
return unless self.content_type.api_enabled? && !self.content_type.api_accounts.blank?
|
|
||||||
|
|
||||||
accounts = self.content_type.site.accounts.to_a
|
|
||||||
|
|
||||||
self.content_type.api_accounts.each do |account_id|
|
|
||||||
next if account_id.blank?
|
|
||||||
|
|
||||||
account = accounts.detect { |a| a.id.to_s == account_id.to_s }
|
|
||||||
|
|
||||||
Admin::Notifications.new_content_instance(account, self).deliver
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,145 +0,0 @@
|
|||||||
class ContentType
|
|
||||||
|
|
||||||
include Locomotive::Mongoid::Document
|
|
||||||
|
|
||||||
## extensions ##
|
|
||||||
include Extensions::ContentType::ItemTemplate
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :name
|
|
||||||
field :description
|
|
||||||
field :slug
|
|
||||||
field :order_by
|
|
||||||
field :order_direction, :default => 'asc'
|
|
||||||
field :highlighted_field_name
|
|
||||||
field :group_by_field_name
|
|
||||||
field :api_enabled, :type => Boolean, :default => false
|
|
||||||
field :api_accounts, :type => Array
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
referenced_in :site
|
|
||||||
embeds_many :contents, :class_name => 'ContentInstance', :validate => false do
|
|
||||||
def visible
|
|
||||||
@target.find_all { |c| c.visible? }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
## named scopes ##
|
|
||||||
scope :ordered, :order_by => :updated_at.desc
|
|
||||||
|
|
||||||
## indexes ##
|
|
||||||
index [[:site_id, Mongo::ASCENDING], [:slug, Mongo::ASCENDING]]
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
before_validation :normalize_slug
|
|
||||||
before_save :set_default_values
|
|
||||||
after_destroy :remove_uploaded_files
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :site, :name, :slug
|
|
||||||
validates_uniqueness_of :slug, :scope => :site_id
|
|
||||||
validates_size_of :content_custom_fields, :minimum => 1, :message => :array_too_short
|
|
||||||
|
|
||||||
## behaviours ##
|
|
||||||
custom_fields_for :contents
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
def groupable?
|
|
||||||
self.group_by_field && group_by_field.category?
|
|
||||||
end
|
|
||||||
|
|
||||||
def order_manually?
|
|
||||||
self.order_by == '_position_in_list'
|
|
||||||
end
|
|
||||||
|
|
||||||
def asc_order?
|
|
||||||
self.order_direction.blank? || self.order_direction == 'asc'
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_or_group_contents
|
|
||||||
if self.groupable?
|
|
||||||
groups = self.contents.klass.send(:"group_by_#{self.group_by_field._alias}", :ordered_contents)
|
|
||||||
|
|
||||||
# look for items with no category or unknown ones
|
|
||||||
items_without_category = self.contents.find_all { |c| !self.group_by_field.category_ids.include?(c.send(self.group_by_field_name)) }
|
|
||||||
if not items_without_category.empty?
|
|
||||||
groups << { :name => nil, :items => items_without_category }
|
|
||||||
else
|
|
||||||
groups
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.ordered_contents
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def latest_updated_contents
|
|
||||||
self.contents.latest_updated.reject { |c| !c.persisted? }
|
|
||||||
end
|
|
||||||
|
|
||||||
def ordered_contents(conditions = {})
|
|
||||||
column = self.order_by.to_sym
|
|
||||||
|
|
||||||
list = (if conditions.nil? || conditions.empty?
|
|
||||||
self.contents
|
|
||||||
else
|
|
||||||
conditions_with_names = {}
|
|
||||||
|
|
||||||
conditions.each do |key, value|
|
|
||||||
# convert alias (key) to name
|
|
||||||
field = self.content_custom_fields.detect { |f| f._alias == key }
|
|
||||||
|
|
||||||
case field.kind.to_sym
|
|
||||||
when :category
|
|
||||||
if (category_item = field.category_items.where(:name => value).first).present?
|
|
||||||
conditions_with_names[field._name.to_sym] = category_item._id
|
|
||||||
end
|
|
||||||
else
|
|
||||||
conditions_with_names[field._name.to_sym] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self.contents.where(conditions_with_names)
|
|
||||||
end).sort { |a, b| (a.send(column) || 0) <=> (b.send(column) || 0) }
|
|
||||||
|
|
||||||
return list if self.order_manually?
|
|
||||||
|
|
||||||
self.asc_order? ? list : list.reverse
|
|
||||||
end
|
|
||||||
|
|
||||||
def sort_contents!(ids)
|
|
||||||
ids.each_with_index do |id, position|
|
|
||||||
self.contents.find(BSON::ObjectId(id))._position_in_list = position
|
|
||||||
end
|
|
||||||
self.save
|
|
||||||
end
|
|
||||||
|
|
||||||
def highlighted_field
|
|
||||||
self.content_custom_fields.detect { |f| f._name == self.highlighted_field_name }
|
|
||||||
end
|
|
||||||
|
|
||||||
def group_by_field
|
|
||||||
@group_by_field ||= self.content_custom_fields.detect { |f| f._name == self.group_by_field_name }
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def set_default_values
|
|
||||||
self.order_by ||= 'created_at'
|
|
||||||
self.highlighted_field_name ||= self.content_custom_fields.first._name
|
|
||||||
end
|
|
||||||
|
|
||||||
def normalize_slug
|
|
||||||
self.slug = self.name.clone if self.slug.blank? && self.name.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
|
|
||||||
self.contents.each do |content|
|
|
||||||
self.content_custom_fields.each do |field|
|
|
||||||
content.send(:"remove_#{field._name}!") if field.kind == 'file'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,27 +0,0 @@
|
|||||||
class EditableElement
|
|
||||||
|
|
||||||
include Mongoid::Document
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :slug
|
|
||||||
field :block
|
|
||||||
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
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
embedded_in :page, :inverse_of => :editable_elements
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :slug
|
|
||||||
|
|
||||||
## scopes ##
|
|
||||||
scope :by_priority, :order_by => [[:priority, :desc]]
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
end
|
|
@ -1,9 +0,0 @@
|
|||||||
class EditableFile < EditableElement
|
|
||||||
|
|
||||||
mount_uploader :source, EditableFileUploader
|
|
||||||
|
|
||||||
def content
|
|
||||||
self.source? ? self.source.url : self.default_content
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,3 +0,0 @@
|
|||||||
class EditableLongText < EditableShortText
|
|
||||||
|
|
||||||
end
|
|
@ -1,12 +0,0 @@
|
|||||||
class EditableShortText < EditableElement
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :content
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
def content
|
|
||||||
self.read_attribute(:content).blank? ? self.default_content : self.read_attribute(:content)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,19 +0,0 @@
|
|||||||
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
|
|
@ -1,17 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Asset
|
|
||||||
module Vignette
|
|
||||||
|
|
||||||
def vignette_url
|
|
||||||
if self.image?
|
|
||||||
if self.width < 80 && self.height < 80
|
|
||||||
self.source.url
|
|
||||||
else
|
|
||||||
Locomotive::Dragonfly.resize_url(self.source, '80x80#')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,49 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module ContentType
|
|
||||||
module ItemTemplate
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
field :raw_item_template
|
|
||||||
field :serialized_item_template, :type => Binary
|
|
||||||
|
|
||||||
before_validation :serialize_item_template
|
|
||||||
|
|
||||||
validate :item_template_must_be_valid
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
|
|
||||||
def item_template
|
|
||||||
@item_template ||= Marshal.load(read_attribute(:serialized_item_template).to_s) rescue nil
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def serialize_item_template
|
|
||||||
if self.new_record? || self.raw_item_template_changed?
|
|
||||||
@item_parsing_errors = []
|
|
||||||
|
|
||||||
begin
|
|
||||||
self._parse_and_serialize_item_template
|
|
||||||
rescue ::Liquid::SyntaxError => error
|
|
||||||
@item_parsing_errors << I18n.t(:liquid_syntax, :error => error.to_s, :scope => [:errors, :messages])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _parse_and_serialize_item_template
|
|
||||||
item_template = ::Liquid::Template.parse(self.raw_item_template, {})
|
|
||||||
self.serialized_item_template = BSON::Binary.new(Marshal.dump(item_template))
|
|
||||||
end
|
|
||||||
|
|
||||||
def item_template_must_be_valid
|
|
||||||
@item_parsing_errors.try(:each) { |msg| self.errors.add :item_template, msg }
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,118 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module EditableElements
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
embeds_many :editable_elements
|
|
||||||
|
|
||||||
after_save :remove_disabled_editable_elements
|
|
||||||
|
|
||||||
# editable file callbacks
|
|
||||||
after_save :store_file_sources!
|
|
||||||
before_save :write_file_source_identifiers
|
|
||||||
after_destroy :remove_file_sources!
|
|
||||||
|
|
||||||
accepts_nested_attributes_for :editable_elements
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
|
|
||||||
def disable_parent_editable_elements(block)
|
|
||||||
self.editable_elements.each { |el| el.disabled = true if el.from_parent? && el.block == block }
|
|
||||||
end
|
|
||||||
|
|
||||||
def disable_all_editable_elements
|
|
||||||
self.editable_elements.each { |el| el.disabled = true }
|
|
||||||
end
|
|
||||||
|
|
||||||
def editable_element_blocks
|
|
||||||
self.editable_elements.collect(&:block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def editable_elements_grouped_by_blocks
|
|
||||||
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
|
|
||||||
|
|
||||||
def find_editable_element(block, slug)
|
|
||||||
self.editable_elements.detect { |el| el.block == block && el.slug == slug }
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_editable_files
|
|
||||||
self.editable_elements.find_all { |el| el.respond_to?(:source) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_or_update_editable_element(attributes, type)
|
|
||||||
element = self.find_editable_element(attributes[:block], attributes[:slug])
|
|
||||||
|
|
||||||
if element
|
|
||||||
element.attributes = attributes
|
|
||||||
else
|
|
||||||
self.editable_elements.build(attributes, type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def enable_editable_elements(block)
|
|
||||||
self.editable_elements.each { |el| el.disabled = false if el.block == block }
|
|
||||||
end
|
|
||||||
|
|
||||||
def merge_editable_elements_from_page(source)
|
|
||||||
source.editable_elements.each do |el|
|
|
||||||
next if el.disabled? or !el.assignable?
|
|
||||||
|
|
||||||
existing_el = self.find_editable_element(el.block, el.slug)
|
|
||||||
|
|
||||||
if existing_el.nil? # new one from parents
|
|
||||||
new_attributes = el.attributes.merge(:from_parent => true)
|
|
||||||
|
|
||||||
if new_attributes['default_attribute'].present?
|
|
||||||
new_attributes['default_content'] = self.send(new_attributes['default_attribute']) || el.content
|
|
||||||
else
|
|
||||||
if el.respond_to?(:content) # only for text
|
|
||||||
new_attributes['default_content'] = el.content
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self.editable_elements.build(new_attributes, el.class)
|
|
||||||
elsif existing_el.default_attribute.nil?
|
|
||||||
existing_el.attributes = { :disabled => false, :default_content => el.content }
|
|
||||||
else
|
|
||||||
existing_el.attributes = { :disabled => false }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_disabled_editable_elements
|
|
||||||
return unless self.editable_elements.any? { |el| el.disabled? }
|
|
||||||
|
|
||||||
# super fast way to remove useless elements all in once (TODO callbacks)
|
|
||||||
self.collection.update(self._selector, '$pull' => { 'editable_elements' => { 'disabled' => true } })
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
## callbacks for editable files
|
|
||||||
|
|
||||||
# equivalent to "after_save :store_source!" in EditableFile
|
|
||||||
def store_file_sources!
|
|
||||||
self.find_editable_files.collect(&:store_source!)
|
|
||||||
end
|
|
||||||
|
|
||||||
# equivalent to "before_save :write_source_identifier" in EditableFile
|
|
||||||
def write_file_source_identifiers
|
|
||||||
self.find_editable_files.collect(&:write_source_identifier)
|
|
||||||
end
|
|
||||||
|
|
||||||
# equivalent to "after_destroy :remove_source!" in EditableFile
|
|
||||||
def remove_file_sources!
|
|
||||||
self.find_editable_files.collect(&:remove_source!)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,15 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module Listed
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
|
|
||||||
field :listed, :type => Boolean, :default => true
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,111 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module Parse
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
field :serialized_template, :type => Binary
|
|
||||||
field :template_dependencies, :type => Array, :default => []
|
|
||||||
field :snippet_dependencies, :type => Array, :default => []
|
|
||||||
|
|
||||||
attr_reader :template_changed
|
|
||||||
|
|
||||||
before_validation :serialize_template
|
|
||||||
after_save :update_template_descendants
|
|
||||||
|
|
||||||
validate :template_must_be_valid
|
|
||||||
|
|
||||||
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
|
|
||||||
def template
|
|
||||||
@template ||= Marshal.load(read_attribute(:serialized_template).to_s) rescue nil
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def serialize_template
|
|
||||||
if self.new_record? || self.raw_template_changed?
|
|
||||||
@template_changed = true
|
|
||||||
|
|
||||||
@parsing_errors = []
|
|
||||||
|
|
||||||
begin
|
|
||||||
self._parse_and_serialize_template
|
|
||||||
rescue ::Liquid::SyntaxError => error
|
|
||||||
@parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s, :scope => [:errors, :messages, :page])
|
|
||||||
rescue ::Locomotive::Liquid::PageNotFound => error
|
|
||||||
@parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath, :scope => [:errors, :messages, :page])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _parse_and_serialize_template(context = {})
|
|
||||||
self.parse(context)
|
|
||||||
self._serialize_template
|
|
||||||
end
|
|
||||||
|
|
||||||
def _serialize_template
|
|
||||||
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse(context = {})
|
|
||||||
self.disable_all_editable_elements
|
|
||||||
|
|
||||||
default_context = { :site => self.site, :page => self, :templates => [], :snippets => [] }
|
|
||||||
|
|
||||||
context = default_context.merge(context)
|
|
||||||
|
|
||||||
@template = ::Liquid::Template.parse(self.raw_template, context)
|
|
||||||
|
|
||||||
self.template_dependencies = context[:templates]
|
|
||||||
self.snippet_dependencies = context[:snippets]
|
|
||||||
|
|
||||||
@template.root.context.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def template_must_be_valid
|
|
||||||
@parsing_errors.try(:each) { |msg| self.errors.add :template, msg }
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_template_descendants
|
|
||||||
return unless @template_changed == true
|
|
||||||
|
|
||||||
# we admit at this point that the current template is up-to-date
|
|
||||||
template_descendants = self.site.pages.any_in(:template_dependencies => [self.id]).to_a
|
|
||||||
|
|
||||||
# group them by fullpath for better performance
|
|
||||||
cached = template_descendants.inject({}) { |memo, page| memo[page.fullpath] = page; memo }
|
|
||||||
|
|
||||||
self._update_direct_template_descendants(template_descendants.clone, cached)
|
|
||||||
|
|
||||||
# finally save them all
|
|
||||||
::Page.without_callback(:save, :after, :update_template_descendants) do
|
|
||||||
template_descendants.each do |page|
|
|
||||||
page.save(:validate => false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _update_direct_template_descendants(template_descendants, cached)
|
|
||||||
direct_descendants = template_descendants.select do |page|
|
|
||||||
((self.template_dependencies || []) + [self._id]) == (page.template_dependencies || [])
|
|
||||||
end
|
|
||||||
|
|
||||||
direct_descendants.each do |page|
|
|
||||||
page.send(:_parse_and_serialize_template, { :cached_parent => self, :cached_pages => cached })
|
|
||||||
|
|
||||||
template_descendants.delete(page) # no need to loop over it next time
|
|
||||||
|
|
||||||
page.send(:_update_direct_template_descendants, template_descendants, cached) # move down
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,21 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module Redirect
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
|
|
||||||
field :redirect, :type => Boolean, :default => false
|
|
||||||
|
|
||||||
field :redirect_url, :type => String
|
|
||||||
|
|
||||||
validates_presence_of :redirect_url, :if => :redirect
|
|
||||||
|
|
||||||
validates_format_of :redirect_url, :with => Locomotive::Regexps::URL, :allow_blank => true
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,11 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module Render
|
|
||||||
|
|
||||||
def render(context)
|
|
||||||
self.template.render(context)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,28 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module Templatized
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
|
|
||||||
referenced_in :content_type
|
|
||||||
|
|
||||||
field :templatized, :type => Boolean, :default => false
|
|
||||||
|
|
||||||
field :content_type_visible_column
|
|
||||||
|
|
||||||
before_validation :set_slug_if_templatized
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
|
|
||||||
def set_slug_if_templatized
|
|
||||||
self.slug = 'content_type_template' if self.templatized?
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,158 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Page
|
|
||||||
module Tree
|
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
include Mongoid::Acts::Tree
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :position, :type => Integer
|
|
||||||
|
|
||||||
## indexes ##
|
|
||||||
index :position
|
|
||||||
index [[:depth, :asc], [:position, :asc]]
|
|
||||||
|
|
||||||
## behaviours ##
|
|
||||||
acts_as_tree :order => ['position', 'asc']
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
before_validation :reset_parent
|
|
||||||
before_save { |p| p.send(:write_attribute, :parent_id, nil) if p.parent_id.blank? }
|
|
||||||
before_save :change_parent
|
|
||||||
before_create { |p| p.send(:fix_position, false) }
|
|
||||||
before_create :add_to_list_bottom
|
|
||||||
before_destroy :remove_from_list
|
|
||||||
|
|
||||||
# Fixme (Didier L.): Instances methods are defined before the include itself
|
|
||||||
alias :fix_position :hacked_fix_position
|
|
||||||
alias :descendants :hacked_descendants
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
|
|
||||||
# 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 = []
|
|
||||||
|
|
||||||
while !pages.empty?
|
|
||||||
tmp << _quick_tree(pages.delete_at(0), pages)
|
|
||||||
end
|
|
||||||
|
|
||||||
tmp
|
|
||||||
end
|
|
||||||
|
|
||||||
def _quick_tree(current_page, pages)
|
|
||||||
i, children = 0, []
|
|
||||||
|
|
||||||
while !pages.empty?
|
|
||||||
page = pages[i]
|
|
||||||
|
|
||||||
break if page.nil?
|
|
||||||
|
|
||||||
if page.parent_id == current_page.id
|
|
||||||
page = pages.delete_at(i)
|
|
||||||
|
|
||||||
children << _quick_tree(page, pages)
|
|
||||||
else
|
|
||||||
i += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
current_page.instance_eval do
|
|
||||||
def children=(list); @children = list; end
|
|
||||||
def children; @children || []; end
|
|
||||||
end
|
|
||||||
|
|
||||||
current_page.children = children
|
|
||||||
|
|
||||||
current_page
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
|
|
||||||
def children?
|
|
||||||
self.class.where(self.parent_id_field => self.id).count
|
|
||||||
end
|
|
||||||
|
|
||||||
def children_with_minimal_attributes
|
|
||||||
self.class.where(self.parent_id_field => self.id).
|
|
||||||
order_by(self.tree_order).
|
|
||||||
minimal_attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
def sort_children!(ids)
|
|
||||||
ids.each_with_index do |id, position|
|
|
||||||
child = self.children.detect { |p| p._id == BSON::ObjectId(id) }
|
|
||||||
child.position = position
|
|
||||||
child.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parent=(owner) # missing in acts_as_tree
|
|
||||||
@_parent = owner
|
|
||||||
self.fix_position(false)
|
|
||||||
self.instance_variable_set :@_will_move, true
|
|
||||||
end
|
|
||||||
|
|
||||||
def hacked_descendants
|
|
||||||
return [] if new_record?
|
|
||||||
self.class.all_in(path_field => [self._id]).order_by tree_order
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def change_parent
|
|
||||||
if self.parent_id_changed?
|
|
||||||
self.fix_position(false)
|
|
||||||
|
|
||||||
unless self.parent_id_was.nil?
|
|
||||||
self.position = nil # make it move to bottom
|
|
||||||
self.add_to_list_bottom
|
|
||||||
end
|
|
||||||
|
|
||||||
self.instance_variable_set :@_will_move, true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def hacked_fix_position(perform_save = true)
|
|
||||||
if parent.nil?
|
|
||||||
self.write_attribute parent_id_field, nil
|
|
||||||
self[path_field] = []
|
|
||||||
self[depth_field] = 0
|
|
||||||
else
|
|
||||||
self.write_attribute parent_id_field, parent._id
|
|
||||||
self[path_field] = parent[path_field] + [parent._id]
|
|
||||||
self[depth_field] = parent[depth_field] + 1
|
|
||||||
self.save if perform_save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_parent
|
|
||||||
if self.parent_id_changed?
|
|
||||||
@_parent = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_to_list_bottom
|
|
||||||
self.position ||= (::Page.where(:_id.ne => self._id).and(:parent_id => self.parent_id).max(:position) || 0) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_from_list
|
|
||||||
return if (self.site rescue nil).nil?
|
|
||||||
|
|
||||||
::Page.where(:parent_id => self.parent_id).and(:position.gt => self.position).each do |p|
|
|
||||||
p.position -= 1
|
|
||||||
p.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,14 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Shared
|
|
||||||
module Seo
|
|
||||||
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
|
|
@ -1,36 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Site
|
|
||||||
module FirstInstallation
|
|
||||||
|
|
||||||
# only called during the installation workflow, just after the admin account has been created
|
|
||||||
def create_first_one(attributes)
|
|
||||||
site = self.new(attributes)
|
|
||||||
|
|
||||||
site.memberships.build :account => Account.first, :role => 'admin'
|
|
||||||
|
|
||||||
site.save
|
|
||||||
|
|
||||||
site
|
|
||||||
end
|
|
||||||
|
|
||||||
def install_template(site, options = {})
|
|
||||||
default_template = Boolean.set(options.delete(:default_site_template)) || false
|
|
||||||
|
|
||||||
zipfile = options.delete(:zipfile)
|
|
||||||
|
|
||||||
# do not try to process anything if said so
|
|
||||||
return unless default_template || zipfile.present?
|
|
||||||
|
|
||||||
# default template options has a higher priority than the zipfile
|
|
||||||
source = default_template ? Locomotive.default_site_template_path : zipfile
|
|
||||||
|
|
||||||
begin
|
|
||||||
Locomotive::Import::Job.run!(source, site, { :samples => true })
|
|
||||||
rescue Exception => e
|
|
||||||
Rails.logger.error "The import of the site template failed because of #{e.message}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,84 +0,0 @@
|
|||||||
module Extensions
|
|
||||||
module Site
|
|
||||||
module SubdomainDomains
|
|
||||||
|
|
||||||
def enable_subdomain_n_domains_if_multi_sites
|
|
||||||
# puts "multi_sites? #{Locomotive.config.multi_sites?} / manage_domains? #{Locomotive.config.manage_domains?} / heroku? #{Locomotive.heroku?} / bushido? #{Locomotive.bushido?}"
|
|
||||||
|
|
||||||
if Locomotive.config.multi_sites? || Locomotive.config.manage_domains?
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :subdomain
|
|
||||||
field :domains, :type => Array, :default => []
|
|
||||||
|
|
||||||
## indexes
|
|
||||||
index :domains
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :subdomain
|
|
||||||
validates_uniqueness_of :subdomain
|
|
||||||
validates_exclusion_of :subdomain, :in => Locomotive.config.reserved_subdomains
|
|
||||||
validates_format_of :subdomain, :with => Locomotive::Regexps::SUBDOMAIN, :allow_blank => true
|
|
||||||
validate :domains_must_be_valid_and_unique
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
before_save :add_subdomain_to_domains
|
|
||||||
|
|
||||||
## named scopes ##
|
|
||||||
scope :match_domain, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
|
||||||
scope :match_domain_with_exclusion_of, lambda { |domain, site|
|
|
||||||
{ :any_in => { :domains => [*domain] }, :where => { :_id.ne => site.id } }
|
|
||||||
}
|
|
||||||
|
|
||||||
send :include, InstanceMethods
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
|
|
||||||
def domains=(array)
|
|
||||||
array = [] if array.blank?; super(array)
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_subdomain_to_domains
|
|
||||||
self.domains ||= []
|
|
||||||
(self.domains << self.full_subdomain).uniq!
|
|
||||||
end
|
|
||||||
|
|
||||||
def domains_without_subdomain
|
|
||||||
(self.domains || []) - [self.full_subdomain_was] - [self.full_subdomain]
|
|
||||||
end
|
|
||||||
|
|
||||||
def domains_with_subdomain
|
|
||||||
((self.domains || []) + [self.full_subdomain]).uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
def full_subdomain
|
|
||||||
"#{self.subdomain}.#{Locomotive.config.domain}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def full_subdomain_was
|
|
||||||
"#{self.subdomain_was}.#{Locomotive.config.domain}"
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def domains_must_be_valid_and_unique
|
|
||||||
return if self.domains.empty?
|
|
||||||
|
|
||||||
self.domains_without_subdomain.each do |domain|
|
|
||||||
if self.class.match_domain_with_exclusion_of(domain, self).any?
|
|
||||||
self.errors.add(:domains, :domain_taken, :value => domain)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not domain =~ Locomotive::Regexps::DOMAIN
|
|
||||||
self.errors.add(:domains, :invalid_domain, :value => domain)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
85
app/models/locomotive/ability.rb
Normal file
85
app/models/locomotive/ability.rb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
Locomotive
|
||||||
|
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, Asset
|
||||||
|
|
||||||
|
can :manage, Site do |site|
|
||||||
|
site == @site
|
||||||
|
end
|
||||||
|
|
||||||
|
can :import, Site
|
||||||
|
|
||||||
|
can :export, Site
|
||||||
|
|
||||||
|
can :point, Site
|
||||||
|
|
||||||
|
cannot :create, Site
|
||||||
|
|
||||||
|
can :manage, Membership
|
||||||
|
|
||||||
|
cannot :grant_admin, Membership
|
||||||
|
|
||||||
|
cannot [:update, :destroy], 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 [:update, :destroy], Membership do |membership|
|
||||||
|
@membership.account_id == membership.account_id # can not edit myself
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
62
app/models/locomotive/account.rb
Normal file
62
app/models/locomotive/account.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
require 'digest'
|
||||||
|
|
||||||
|
module Locomotive
|
||||||
|
class Account
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
devise *Locomotive.config.devise_modules
|
||||||
|
|
||||||
|
## attributes ##
|
||||||
|
field :name
|
||||||
|
field :locale, :default => Locomotive.config.default_locale.to_s or 'en'
|
||||||
|
field :switch_site_token
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :name
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_destroy :remove_memberships!
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
def sites
|
||||||
|
@sites ||= Site.where({ 'memberships.account_id' => self._id })
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_switch_site_token!
|
||||||
|
self.switch_site_token = ActiveSupport::SecureRandom.base64(8).gsub("/", "_").gsub(/=+$/, "")
|
||||||
|
self.save
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find_using_switch_site_token(token, age = 1.minute)
|
||||||
|
return if token.blank?
|
||||||
|
self.where(:switch_site_token => token, :updated_at.gt => age.ago.utc).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find_using_switch_site_token!(token, age = 1.minute)
|
||||||
|
self.find_using_switch_site_token(token, age) || raise(Mongoid::Errors::DocumentNotFound.new(self, token))
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def password_required?
|
||||||
|
!persisted? || !password.blank? || !password_confirmation.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_memberships!
|
||||||
|
self.sites.each do |site|
|
||||||
|
membership = site.memberships.where(:account_id => self._id).first
|
||||||
|
|
||||||
|
if site.admin_memberships.size == 1 && membership.admin?
|
||||||
|
raise I18n.t('errors.messages.needs_admin_account')
|
||||||
|
else
|
||||||
|
membership.destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
41
app/models/locomotive/asset.rb
Normal file
41
app/models/locomotive/asset.rb
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
module Locomotive
|
||||||
|
class Asset
|
||||||
|
|
||||||
|
include Mongoid::Document
|
||||||
|
include Mongoid::Timestamps
|
||||||
|
|
||||||
|
## extensions ##
|
||||||
|
include Extensions::Asset::Types
|
||||||
|
include Extensions::Asset::Vignette
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :content_type, :type => String
|
||||||
|
field :width, :type => Integer
|
||||||
|
field :height, :type => Integer
|
||||||
|
field :size, :type => Integer
|
||||||
|
field :position, :type => Integer, :default => 0
|
||||||
|
mount_uploader :source, AssetUploader
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
referenced_in :site
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :source
|
||||||
|
|
||||||
|
## behaviours ##
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
alias :name :source_filename
|
||||||
|
|
||||||
|
def extname
|
||||||
|
return nil unless self.source?
|
||||||
|
File.extname(self.source_filename).gsub(/^\./, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
{ :url => self.source.url }.merge(self.attributes).stringify_keys
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
127
app/models/locomotive/content_instance.rb
Normal file
127
app/models/locomotive/content_instance.rb
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
module Locomotive
|
||||||
|
class ContentInstance
|
||||||
|
|
||||||
|
include Mongoid::Document
|
||||||
|
include Mongoid::Timestamps
|
||||||
|
|
||||||
|
## extensions ##
|
||||||
|
include CustomFields::ProxyClassEnabler
|
||||||
|
include Extensions::Shared::Seo
|
||||||
|
|
||||||
|
## fields (dynamic fields) ##
|
||||||
|
field :_slug
|
||||||
|
field :_position_in_list, :type => Integer, :default => 0
|
||||||
|
field :_visible, :type => Boolean, :default => true
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validate :require_highlighted_field
|
||||||
|
validate :validate_uniqueness_of_slug
|
||||||
|
validates_presence_of :_slug
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
embedded_in :content_type, :inverse_of => :contents
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_validation :set_slug
|
||||||
|
before_save :set_visibility
|
||||||
|
before_create :add_to_list_bottom
|
||||||
|
after_create :send_notifications
|
||||||
|
|
||||||
|
## named scopes ##
|
||||||
|
scope :latest_updated, :order_by => :updated_at.desc, :limit => Locomotive.config.lastest_items_nb
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
delegate :site, :to => :content_type
|
||||||
|
|
||||||
|
alias :visible? :_visible?
|
||||||
|
alias :_permalink :_slug
|
||||||
|
alias :_permalink= :_slug=
|
||||||
|
|
||||||
|
def site_id # needed by the uploader of custom fields
|
||||||
|
self.content_type.site_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def highlighted_field_value
|
||||||
|
self.send(self.content_type.highlighted_field_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
alias :_label :highlighted_field_value
|
||||||
|
|
||||||
|
def visible?
|
||||||
|
self._visible || self._visible.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def next
|
||||||
|
content_type.contents.where(:_position_in_list => _position_in_list + 1).first()
|
||||||
|
end
|
||||||
|
|
||||||
|
def previous
|
||||||
|
content_type.contents.where(:_position_in_list => _position_in_list - 1).first()
|
||||||
|
end
|
||||||
|
|
||||||
|
def errors_to_hash
|
||||||
|
Hash.new.replace(self.errors)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reload_parent!
|
||||||
|
self.class.reload_parent!
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.reload_parent!
|
||||||
|
self._parent = self._parent.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
Locomotive::Liquid::Drops::Content.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def set_slug
|
||||||
|
self._slug = self.highlighted_field_value.dup if self._slug.blank? && self.highlighted_field_value.present?
|
||||||
|
self._slug.permalink! if self._slug.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_visibility
|
||||||
|
field = self.content_type.content_custom_fields.detect { |f| %w{visible active}.include?(f._alias) }
|
||||||
|
self._visible = self.send(field._name) rescue true
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_to_list_bottom
|
||||||
|
self._position_in_list = self.content_type.contents.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_highlighted_field
|
||||||
|
_alias = self.highlighted_field_alias
|
||||||
|
if self.send(_alias).blank?
|
||||||
|
self.errors.add(_alias, :blank)
|
||||||
|
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
|
||||||
|
|
||||||
|
def send_notifications
|
||||||
|
return unless self.content_type.api_enabled? && !self.content_type.api_accounts.blank?
|
||||||
|
|
||||||
|
accounts = self.content_type.site.accounts.to_a
|
||||||
|
|
||||||
|
self.content_type.api_accounts.each do |account_id|
|
||||||
|
next if account_id.blank?
|
||||||
|
|
||||||
|
account = accounts.detect { |a| a.id.to_s == account_id.to_s }
|
||||||
|
|
||||||
|
Locomotive::Notifications.new_content_instance(account, self).deliver
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
147
app/models/locomotive/content_type.rb
Normal file
147
app/models/locomotive/content_type.rb
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
module Locomotive
|
||||||
|
class ContentType
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
## extensions ##
|
||||||
|
include Extensions::ContentType::ItemTemplate
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :name
|
||||||
|
field :description
|
||||||
|
field :slug
|
||||||
|
field :order_by
|
||||||
|
field :order_direction, :default => 'asc'
|
||||||
|
field :highlighted_field_name
|
||||||
|
field :group_by_field_name
|
||||||
|
field :api_enabled, :type => Boolean, :default => false
|
||||||
|
field :api_accounts, :type => Array
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
referenced_in :site
|
||||||
|
embeds_many :contents, :class_name => 'Locomotive::ContentInstance', :validate => false do
|
||||||
|
def visible
|
||||||
|
@target.find_all { |c| c.visible? }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
## named scopes ##
|
||||||
|
scope :ordered, :order_by => :updated_at.desc
|
||||||
|
|
||||||
|
## indexes ##
|
||||||
|
index [[:site_id, Mongo::ASCENDING], [:slug, Mongo::ASCENDING]]
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_validation :normalize_slug
|
||||||
|
before_save :set_default_values
|
||||||
|
after_destroy :remove_uploaded_files
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :site, :name, :slug
|
||||||
|
validates_uniqueness_of :slug, :scope => :site_id
|
||||||
|
validates_size_of :content_custom_fields, :minimum => 1, :message => :array_too_short
|
||||||
|
|
||||||
|
## behaviours ##
|
||||||
|
custom_fields_for :contents
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
def groupable?
|
||||||
|
self.group_by_field && group_by_field.category?
|
||||||
|
end
|
||||||
|
|
||||||
|
def order_manually?
|
||||||
|
self.order_by == '_position_in_list'
|
||||||
|
end
|
||||||
|
|
||||||
|
def asc_order?
|
||||||
|
self.order_direction.blank? || self.order_direction == 'asc'
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_or_group_contents
|
||||||
|
if self.groupable?
|
||||||
|
groups = self.contents.klass.send(:"group_by_#{self.group_by_field._alias}", :ordered_contents)
|
||||||
|
|
||||||
|
# look for items with no category or unknown ones
|
||||||
|
items_without_category = self.contents.find_all { |c| !self.group_by_field.category_ids.include?(c.send(self.group_by_field_name)) }
|
||||||
|
if not items_without_category.empty?
|
||||||
|
groups << { :name => nil, :items => items_without_category }
|
||||||
|
else
|
||||||
|
groups
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.ordered_contents
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def latest_updated_contents
|
||||||
|
self.contents.latest_updated.reject { |c| !c.persisted? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def ordered_contents(conditions = {})
|
||||||
|
column = self.order_by.to_sym
|
||||||
|
|
||||||
|
list = (if conditions.nil? || conditions.empty?
|
||||||
|
self.contents
|
||||||
|
else
|
||||||
|
conditions_with_names = {}
|
||||||
|
|
||||||
|
conditions.each do |key, value|
|
||||||
|
# convert alias (key) to name
|
||||||
|
field = self.content_custom_fields.detect { |f| f._alias == key }
|
||||||
|
|
||||||
|
case field.kind.to_sym
|
||||||
|
when :category
|
||||||
|
if (category_item = field.category_items.where(:name => value).first).present?
|
||||||
|
conditions_with_names[field._name.to_sym] = category_item._id
|
||||||
|
end
|
||||||
|
else
|
||||||
|
conditions_with_names[field._name.to_sym] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.contents.where(conditions_with_names)
|
||||||
|
end).sort { |a, b| (a.send(column) || 0) <=> (b.send(column) || 0) }
|
||||||
|
|
||||||
|
return list if self.order_manually?
|
||||||
|
|
||||||
|
self.asc_order? ? list : list.reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_contents!(ids)
|
||||||
|
ids.each_with_index do |id, position|
|
||||||
|
self.contents.find(BSON::ObjectId(id))._position_in_list = position
|
||||||
|
end
|
||||||
|
self.save
|
||||||
|
end
|
||||||
|
|
||||||
|
def highlighted_field
|
||||||
|
self.content_custom_fields.detect { |f| f._name == self.highlighted_field_name }
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_by_field
|
||||||
|
@group_by_field ||= self.content_custom_fields.detect { |f| f._name == self.group_by_field_name }
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def set_default_values
|
||||||
|
self.order_by ||= 'created_at'
|
||||||
|
self.highlighted_field_name ||= self.content_custom_fields.first._name
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_slug
|
||||||
|
self.slug = self.name.clone if self.slug.blank? && self.name.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
|
||||||
|
self.contents.each do |content|
|
||||||
|
self.content_custom_fields.each do |field|
|
||||||
|
content.send(:"remove_#{field._name}!") if field.kind == 'file'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
29
app/models/locomotive/editable_element.rb
Normal file
29
app/models/locomotive/editable_element.rb
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module Locomotive
|
||||||
|
class EditableElement
|
||||||
|
|
||||||
|
include Mongoid::Document
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :slug
|
||||||
|
field :block
|
||||||
|
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
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
embedded_in :page, :inverse_of => :editable_elements
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :slug
|
||||||
|
|
||||||
|
## scopes ##
|
||||||
|
scope :by_priority, :order_by => [[:priority, :desc]]
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
11
app/models/locomotive/editable_file.rb
Normal file
11
app/models/locomotive/editable_file.rb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module Locomotive
|
||||||
|
class EditableFile < EditableElement
|
||||||
|
|
||||||
|
mount_uploader :source, EditableFileUploader
|
||||||
|
|
||||||
|
def content
|
||||||
|
self.source? ? self.source.url : self.default_content
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
5
app/models/locomotive/editable_long_text.rb
Normal file
5
app/models/locomotive/editable_long_text.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module Locomotive
|
||||||
|
class EditableLongText < EditableShortText
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
14
app/models/locomotive/editable_short_text.rb
Normal file
14
app/models/locomotive/editable_short_text.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module Locomotive
|
||||||
|
class EditableShortText < EditableElement
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :content
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
def content
|
||||||
|
self.read_attribute(:content).blank? ? self.default_content : self.read_attribute(:content)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
21
app/models/locomotive/extensions/asset/types.rb
Normal file
21
app/models/locomotive/extensions/asset/types.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
module Locomotive
|
||||||
|
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
|
||||||
|
end
|
19
app/models/locomotive/extensions/asset/vignette.rb
Normal file
19
app/models/locomotive/extensions/asset/vignette.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Asset
|
||||||
|
module Vignette
|
||||||
|
|
||||||
|
def vignette_url
|
||||||
|
if self.image?
|
||||||
|
if self.width < 80 && self.height < 80
|
||||||
|
self.source.url
|
||||||
|
else
|
||||||
|
Locomotive::Dragonfly.resize_url(self.source, '80x80#')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,51 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module ContentType
|
||||||
|
module ItemTemplate
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
field :raw_item_template
|
||||||
|
field :serialized_item_template, :type => Binary
|
||||||
|
|
||||||
|
before_validation :serialize_item_template
|
||||||
|
|
||||||
|
validate :item_template_must_be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
def item_template
|
||||||
|
@item_template ||= Marshal.load(read_attribute(:serialized_item_template).to_s) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def serialize_item_template
|
||||||
|
if self.new_record? || self.raw_item_template_changed?
|
||||||
|
@item_parsing_errors = []
|
||||||
|
|
||||||
|
begin
|
||||||
|
self._parse_and_serialize_item_template
|
||||||
|
rescue ::Liquid::SyntaxError => error
|
||||||
|
@item_parsing_errors << I18n.t(:liquid_syntax, :error => error.to_s, :scope => [:errors, :messages])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def _parse_and_serialize_item_template
|
||||||
|
item_template = ::Liquid::Template.parse(self.raw_item_template, {})
|
||||||
|
self.serialized_item_template = BSON::Binary.new(Marshal.dump(item_template))
|
||||||
|
end
|
||||||
|
|
||||||
|
def item_template_must_be_valid
|
||||||
|
@item_parsing_errors.try(:each) { |msg| self.errors.add :item_template, msg }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
120
app/models/locomotive/extensions/page/editable_elements.rb
Normal file
120
app/models/locomotive/extensions/page/editable_elements.rb
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module EditableElements
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
embeds_many :editable_elements
|
||||||
|
|
||||||
|
after_save :remove_disabled_editable_elements
|
||||||
|
|
||||||
|
# editable file callbacks
|
||||||
|
after_save :store_file_sources!
|
||||||
|
before_save :write_file_source_identifiers
|
||||||
|
after_destroy :remove_file_sources!
|
||||||
|
|
||||||
|
accepts_nested_attributes_for :editable_elements
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
def disable_parent_editable_elements(block)
|
||||||
|
self.editable_elements.each { |el| el.disabled = true if el.from_parent? && el.block == block }
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable_all_editable_elements
|
||||||
|
self.editable_elements.each { |el| el.disabled = true }
|
||||||
|
end
|
||||||
|
|
||||||
|
def editable_element_blocks
|
||||||
|
self.editable_elements.collect(&:block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def editable_elements_grouped_by_blocks
|
||||||
|
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
|
||||||
|
|
||||||
|
def find_editable_element(block, slug)
|
||||||
|
self.editable_elements.detect { |el| el.block == block && el.slug == slug }
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_editable_files
|
||||||
|
self.editable_elements.find_all { |el| el.respond_to?(:source) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_or_update_editable_element(attributes, type)
|
||||||
|
element = self.find_editable_element(attributes[:block], attributes[:slug])
|
||||||
|
|
||||||
|
if element
|
||||||
|
element.attributes = attributes
|
||||||
|
else
|
||||||
|
self.editable_elements.build(attributes, type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable_editable_elements(block)
|
||||||
|
self.editable_elements.each { |el| el.disabled = false if el.block == block }
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge_editable_elements_from_page(source)
|
||||||
|
source.editable_elements.each do |el|
|
||||||
|
next if el.disabled? or !el.assignable?
|
||||||
|
|
||||||
|
existing_el = self.find_editable_element(el.block, el.slug)
|
||||||
|
|
||||||
|
if existing_el.nil? # new one from parents
|
||||||
|
new_attributes = el.attributes.merge(:from_parent => true)
|
||||||
|
|
||||||
|
if new_attributes['default_attribute'].present?
|
||||||
|
new_attributes['default_content'] = self.send(new_attributes['default_attribute']) || el.content
|
||||||
|
else
|
||||||
|
if el.respond_to?(:content) # only for text
|
||||||
|
new_attributes['default_content'] = el.content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.editable_elements.build(new_attributes, el.class)
|
||||||
|
elsif existing_el.default_attribute.nil?
|
||||||
|
existing_el.attributes = { :disabled => false, :default_content => el.content }
|
||||||
|
else
|
||||||
|
existing_el.attributes = { :disabled => false }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_disabled_editable_elements
|
||||||
|
return unless self.editable_elements.any? { |el| el.disabled? }
|
||||||
|
|
||||||
|
# super fast way to remove useless elements all in once (TODO callbacks)
|
||||||
|
self.collection.update(self._selector, '$pull' => { 'editable_elements' => { 'disabled' => true } })
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
## callbacks for editable files
|
||||||
|
|
||||||
|
# equivalent to "after_save :store_source!" in EditableFile
|
||||||
|
def store_file_sources!
|
||||||
|
self.find_editable_files.collect(&:store_source!)
|
||||||
|
end
|
||||||
|
|
||||||
|
# equivalent to "before_save :write_source_identifier" in EditableFile
|
||||||
|
def write_file_source_identifiers
|
||||||
|
self.find_editable_files.collect(&:write_source_identifier)
|
||||||
|
end
|
||||||
|
|
||||||
|
# equivalent to "after_destroy :remove_source!" in EditableFile
|
||||||
|
def remove_file_sources!
|
||||||
|
self.find_editable_files.collect(&:remove_source!)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
17
app/models/locomotive/extensions/page/listed.rb
Normal file
17
app/models/locomotive/extensions/page/listed.rb
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module Listed
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
|
||||||
|
field :listed, :type => Boolean, :default => true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
113
app/models/locomotive/extensions/page/parse.rb
Normal file
113
app/models/locomotive/extensions/page/parse.rb
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module Parse
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
field :serialized_template, :type => Binary
|
||||||
|
field :template_dependencies, :type => Array, :default => []
|
||||||
|
field :snippet_dependencies, :type => Array, :default => []
|
||||||
|
|
||||||
|
attr_reader :template_changed
|
||||||
|
|
||||||
|
before_validation :serialize_template
|
||||||
|
after_save :update_template_descendants
|
||||||
|
|
||||||
|
validate :template_must_be_valid
|
||||||
|
|
||||||
|
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
def template
|
||||||
|
@template ||= Marshal.load(read_attribute(:serialized_template).to_s) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def serialize_template
|
||||||
|
if self.new_record? || self.raw_template_changed?
|
||||||
|
@template_changed = true
|
||||||
|
|
||||||
|
@parsing_errors = []
|
||||||
|
|
||||||
|
begin
|
||||||
|
self._parse_and_serialize_template
|
||||||
|
rescue ::Liquid::SyntaxError => error
|
||||||
|
@parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s, :scope => [:errors, :messages, :page])
|
||||||
|
rescue ::Locomotive::Liquid::PageNotFound => error
|
||||||
|
@parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath, :scope => [:errors, :messages, :page])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def _parse_and_serialize_template(context = {})
|
||||||
|
self.parse(context)
|
||||||
|
self._serialize_template
|
||||||
|
end
|
||||||
|
|
||||||
|
def _serialize_template
|
||||||
|
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(context = {})
|
||||||
|
self.disable_all_editable_elements
|
||||||
|
|
||||||
|
default_context = { :site => self.site, :page => self, :templates => [], :snippets => [] }
|
||||||
|
|
||||||
|
context = default_context.merge(context)
|
||||||
|
|
||||||
|
@template = ::Liquid::Template.parse(self.raw_template, context)
|
||||||
|
|
||||||
|
self.template_dependencies = context[:templates]
|
||||||
|
self.snippet_dependencies = context[:snippets]
|
||||||
|
|
||||||
|
@template.root.context.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def template_must_be_valid
|
||||||
|
@parsing_errors.try(:each) { |msg| self.errors.add :template, msg }
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_template_descendants
|
||||||
|
return unless @template_changed == true
|
||||||
|
|
||||||
|
# we admit at this point that the current template is up-to-date
|
||||||
|
template_descendants = self.site.pages.any_in(:template_dependencies => [self.id]).to_a
|
||||||
|
|
||||||
|
# group them by fullpath for better performance
|
||||||
|
cached = template_descendants.inject({}) { |memo, page| memo[page.fullpath] = page; memo }
|
||||||
|
|
||||||
|
self._update_direct_template_descendants(template_descendants.clone, cached)
|
||||||
|
|
||||||
|
# finally save them all
|
||||||
|
::Page.without_callback(:save, :after, :update_template_descendants) do
|
||||||
|
template_descendants.each do |page|
|
||||||
|
page.save(:validate => false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def _update_direct_template_descendants(template_descendants, cached)
|
||||||
|
direct_descendants = template_descendants.select do |page|
|
||||||
|
((self.template_dependencies || []) + [self._id]) == (page.template_dependencies || [])
|
||||||
|
end
|
||||||
|
|
||||||
|
direct_descendants.each do |page|
|
||||||
|
page.send(:_parse_and_serialize_template, { :cached_parent => self, :cached_pages => cached })
|
||||||
|
|
||||||
|
template_descendants.delete(page) # no need to loop over it next time
|
||||||
|
|
||||||
|
page.send(:_update_direct_template_descendants, template_descendants, cached) # move down
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
app/models/locomotive/extensions/page/redirect.rb
Normal file
23
app/models/locomotive/extensions/page/redirect.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module Redirect
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
|
||||||
|
field :redirect, :type => Boolean, :default => false
|
||||||
|
|
||||||
|
field :redirect_url, :type => String
|
||||||
|
|
||||||
|
validates_presence_of :redirect_url, :if => :redirect
|
||||||
|
|
||||||
|
validates_format_of :redirect_url, :with => Locomotive::Regexps::URL, :allow_blank => true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
app/models/locomotive/extensions/page/render.rb
Normal file
13
app/models/locomotive/extensions/page/render.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module Render
|
||||||
|
|
||||||
|
def render(context)
|
||||||
|
self.template.render(context)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
30
app/models/locomotive/extensions/page/templatized.rb
Normal file
30
app/models/locomotive/extensions/page/templatized.rb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module Templatized
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
|
||||||
|
referenced_in :content_type
|
||||||
|
|
||||||
|
field :templatized, :type => Boolean, :default => false
|
||||||
|
|
||||||
|
field :content_type_visible_column
|
||||||
|
|
||||||
|
before_validation :set_slug_if_templatized
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
def set_slug_if_templatized
|
||||||
|
self.slug = 'content_type_template' if self.templatized?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
160
app/models/locomotive/extensions/page/tree.rb
Normal file
160
app/models/locomotive/extensions/page/tree.rb
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Page
|
||||||
|
module Tree
|
||||||
|
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
include ::Mongoid::Acts::Tree
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :position, :type => Integer
|
||||||
|
|
||||||
|
## indexes ##
|
||||||
|
index :position
|
||||||
|
index [[:depth, :asc], [:position, :asc]]
|
||||||
|
|
||||||
|
## behaviours ##
|
||||||
|
acts_as_tree :order => ['position', 'asc']
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_validation :reset_parent
|
||||||
|
before_save { |p| p.send(:write_attribute, :parent_id, nil) if p.parent_id.blank? }
|
||||||
|
before_save :change_parent
|
||||||
|
before_create { |p| p.send(:fix_position, false) }
|
||||||
|
before_create :add_to_list_bottom
|
||||||
|
before_destroy :remove_from_list
|
||||||
|
|
||||||
|
# Fixme (Didier L.): Instances methods are defined before the include itself
|
||||||
|
alias :fix_position :hacked_fix_position
|
||||||
|
alias :descendants :hacked_descendants
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
# 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 = []
|
||||||
|
|
||||||
|
while !pages.empty?
|
||||||
|
tmp << _quick_tree(pages.delete_at(0), pages)
|
||||||
|
end
|
||||||
|
|
||||||
|
tmp
|
||||||
|
end
|
||||||
|
|
||||||
|
def _quick_tree(current_page, pages)
|
||||||
|
i, children = 0, []
|
||||||
|
|
||||||
|
while !pages.empty?
|
||||||
|
page = pages[i]
|
||||||
|
|
||||||
|
break if page.nil?
|
||||||
|
|
||||||
|
if page.parent_id == current_page.id
|
||||||
|
page = pages.delete_at(i)
|
||||||
|
|
||||||
|
children << _quick_tree(page, pages)
|
||||||
|
else
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
current_page.instance_eval do
|
||||||
|
def children=(list); @children = list; end
|
||||||
|
def children; @children || []; end
|
||||||
|
end
|
||||||
|
|
||||||
|
current_page.children = children
|
||||||
|
|
||||||
|
current_page
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
def children?
|
||||||
|
self.class.where(self.parent_id_field => self.id).count
|
||||||
|
end
|
||||||
|
|
||||||
|
def children_with_minimal_attributes
|
||||||
|
self.class.where(self.parent_id_field => self.id).
|
||||||
|
order_by(self.tree_order).
|
||||||
|
minimal_attributes
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_children!(ids)
|
||||||
|
ids.each_with_index do |id, position|
|
||||||
|
child = self.children.detect { |p| p._id == BSON::ObjectId(id) }
|
||||||
|
child.position = position
|
||||||
|
child.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent=(owner) # missing in acts_as_tree
|
||||||
|
@_parent = owner
|
||||||
|
self.fix_position(false)
|
||||||
|
self.instance_variable_set :@_will_move, true
|
||||||
|
end
|
||||||
|
|
||||||
|
def hacked_descendants
|
||||||
|
return [] if new_record?
|
||||||
|
self.class.all_in(path_field => [self._id]).order_by tree_order
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def change_parent
|
||||||
|
if self.parent_id_changed?
|
||||||
|
self.fix_position(false)
|
||||||
|
|
||||||
|
unless self.parent_id_was.nil?
|
||||||
|
self.position = nil # make it move to bottom
|
||||||
|
self.add_to_list_bottom
|
||||||
|
end
|
||||||
|
|
||||||
|
self.instance_variable_set :@_will_move, true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def hacked_fix_position(perform_save = true)
|
||||||
|
if parent.nil?
|
||||||
|
self.write_attribute parent_id_field, nil
|
||||||
|
self[path_field] = []
|
||||||
|
self[depth_field] = 0
|
||||||
|
else
|
||||||
|
self.write_attribute parent_id_field, parent._id
|
||||||
|
self[path_field] = parent[path_field] + [parent._id]
|
||||||
|
self[depth_field] = parent[depth_field] + 1
|
||||||
|
self.save if perform_save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_parent
|
||||||
|
if self.parent_id_changed?
|
||||||
|
@_parent = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_to_list_bottom
|
||||||
|
self.position ||= (::Page.where(:_id.ne => self._id).and(:parent_id => self.parent_id).max(:position) || 0) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_from_list
|
||||||
|
return if (self.site rescue nil).nil?
|
||||||
|
|
||||||
|
::Page.where(:parent_id => self.parent_id).and(:position.gt => self.position).each do |p|
|
||||||
|
p.position -= 1
|
||||||
|
p.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
16
app/models/locomotive/extensions/shared/seo.rb
Normal file
16
app/models/locomotive/extensions/shared/seo.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Shared
|
||||||
|
module Seo
|
||||||
|
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
|
||||||
|
end # Locomotive
|
38
app/models/locomotive/extensions/site/first_installation.rb
Normal file
38
app/models/locomotive/extensions/site/first_installation.rb
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Site
|
||||||
|
module FirstInstallation
|
||||||
|
|
||||||
|
# only called during the installation workflow, just after the admin account has been created
|
||||||
|
def create_first_one(attributes)
|
||||||
|
site = self.new(attributes)
|
||||||
|
|
||||||
|
site.memberships.build :account => Account.first, :role => 'admin'
|
||||||
|
|
||||||
|
site.save
|
||||||
|
|
||||||
|
site
|
||||||
|
end
|
||||||
|
|
||||||
|
def install_template(site, options = {})
|
||||||
|
default_template = Boolean.set(options.delete(:default_site_template)) || false
|
||||||
|
|
||||||
|
zipfile = options.delete(:zipfile)
|
||||||
|
|
||||||
|
# do not try to process anything if said so
|
||||||
|
return unless default_template || zipfile.present?
|
||||||
|
|
||||||
|
# default template options has a higher priority than the zipfile
|
||||||
|
source = default_template ? Locomotive.default_site_template_path : zipfile
|
||||||
|
|
||||||
|
begin
|
||||||
|
Locomotive::Import::Job.run!(source, site, { :samples => true })
|
||||||
|
rescue Exception => e
|
||||||
|
Rails.logger.error "The import of the site template failed because of #{e.message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
86
app/models/locomotive/extensions/site/subdomain_domains.rb
Normal file
86
app/models/locomotive/extensions/site/subdomain_domains.rb
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Extensions
|
||||||
|
module Site
|
||||||
|
module SubdomainDomains
|
||||||
|
|
||||||
|
def enable_subdomain_n_domains_if_multi_sites
|
||||||
|
# puts "multi_sites? #{Locomotive.config.multi_sites?} / manage_domains? #{Locomotive.config.manage_domains?} / heroku? #{Locomotive.heroku?} / bushido? #{Locomotive.bushido?}"
|
||||||
|
|
||||||
|
if Locomotive.config.multi_sites? || Locomotive.config.manage_domains?
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :subdomain
|
||||||
|
field :domains, :type => Array, :default => []
|
||||||
|
|
||||||
|
## indexes
|
||||||
|
index :domains
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :subdomain
|
||||||
|
validates_uniqueness_of :subdomain
|
||||||
|
validates_exclusion_of :subdomain, :in => Locomotive.config.reserved_subdomains
|
||||||
|
validates_format_of :subdomain, :with => Locomotive::Regexps::SUBDOMAIN, :allow_blank => true
|
||||||
|
validate :domains_must_be_valid_and_unique
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_save :add_subdomain_to_domains
|
||||||
|
|
||||||
|
## named scopes ##
|
||||||
|
scope :match_domain, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||||
|
scope :match_domain_with_exclusion_of, lambda { |domain, site|
|
||||||
|
{ :any_in => { :domains => [*domain] }, :where => { :_id.ne => site.id } }
|
||||||
|
}
|
||||||
|
|
||||||
|
send :include, InstanceMethods
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
def domains=(array)
|
||||||
|
array = [] if array.blank?; super(array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_subdomain_to_domains
|
||||||
|
self.domains ||= []
|
||||||
|
(self.domains << self.full_subdomain).uniq!
|
||||||
|
end
|
||||||
|
|
||||||
|
def domains_without_subdomain
|
||||||
|
(self.domains || []) - [self.full_subdomain_was] - [self.full_subdomain]
|
||||||
|
end
|
||||||
|
|
||||||
|
def domains_with_subdomain
|
||||||
|
((self.domains || []) + [self.full_subdomain]).uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_subdomain
|
||||||
|
"#{self.subdomain}.#{Locomotive.config.domain}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_subdomain_was
|
||||||
|
"#{self.subdomain_was}.#{Locomotive.config.domain}"
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def domains_must_be_valid_and_unique
|
||||||
|
return if self.domains.empty?
|
||||||
|
|
||||||
|
self.domains_without_subdomain.each do |domain|
|
||||||
|
if self.class.match_domain_with_exclusion_of(domain, self).any?
|
||||||
|
self.errors.add(:domains, :domain_taken, :value => domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not domain =~ Locomotive::Regexps::DOMAIN
|
||||||
|
self.errors.add(:domains, :invalid_domain, :value => domain)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
75
app/models/locomotive/membership.rb
Normal file
75
app/models/locomotive/membership.rb
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
module Locomotive
|
||||||
|
class Membership
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :role, :default => 'author'
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
referenced_in :account, :validate => false
|
||||||
|
embedded_in :site, :inverse_of => :memberships
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :account
|
||||||
|
validate :can_change_role, :if => :role_changed?
|
||||||
|
|
||||||
|
## 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)
|
||||||
|
@email = email
|
||||||
|
self.account = Account.where(:email => email).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def process!
|
||||||
|
if @email.blank?
|
||||||
|
self.errors.add_on_blank(:email)
|
||||||
|
:error
|
||||||
|
elsif self.account.blank?
|
||||||
|
:create_account
|
||||||
|
elsif self.site.memberships.any? { |m| m.account_id == self.account_id && m._id != self._id }
|
||||||
|
self.errors.add(:base, 'Already created')
|
||||||
|
: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
|
||||||
|
|
||||||
|
# Users should not be able to set the role of another user to be higher than
|
||||||
|
# their own. A designer for example should not be able to set another user to
|
||||||
|
# be an administrator
|
||||||
|
def can_change_role
|
||||||
|
current_site = Thread.current[:site]
|
||||||
|
current_membership = current_site.memberships.where(:account_id => Thread.current[:account].id).first if current_site.present?
|
||||||
|
|
||||||
|
if current_membership.present?
|
||||||
|
# The role cannot be set higher than the current one (we use the index in
|
||||||
|
# the roles array to check role presidence)
|
||||||
|
errors.add(:role, :invalid) if Ability::ROLES.index(role) < Ability::ROLES.index(current_membership.role)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
109
app/models/locomotive/page.rb
Normal file
109
app/models/locomotive/page.rb
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
module Locomotive
|
||||||
|
class Page
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
## Extensions ##
|
||||||
|
include Extensions::Page::Tree
|
||||||
|
include Extensions::Page::EditableElements
|
||||||
|
include Extensions::Page::Parse
|
||||||
|
include Extensions::Page::Render
|
||||||
|
include Extensions::Page::Templatized
|
||||||
|
include Extensions::Page::Redirect
|
||||||
|
include Extensions::Page::Listed
|
||||||
|
include Extensions::Shared::Seo
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :title
|
||||||
|
field :slug
|
||||||
|
field :fullpath
|
||||||
|
field :raw_template
|
||||||
|
field :published, :type => Boolean, :default => false
|
||||||
|
field :cache_strategy, :default => 'none'
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
referenced_in :site
|
||||||
|
|
||||||
|
## indexes ##
|
||||||
|
index :site_id
|
||||||
|
index :parent_id
|
||||||
|
index [[:fullpath, Mongo::ASCENDING], [:site_id, Mongo::ASCENDING]]
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
after_initialize :set_default_raw_template
|
||||||
|
before_validation :normalize_slug
|
||||||
|
before_save { |p| p.fullpath = p.fullpath(true) }
|
||||||
|
before_destroy :do_not_remove_index_and_404_pages
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :site, :title, :slug
|
||||||
|
validates_uniqueness_of :slug, :scope => [:site_id, :parent_id]
|
||||||
|
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth == 0 }
|
||||||
|
|
||||||
|
## named scopes ##
|
||||||
|
scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
|
||||||
|
scope :root, :where => { :slug => 'index', :depth => 0 }
|
||||||
|
scope :not_found, :where => { :slug => '404', :depth => 0 }
|
||||||
|
scope :published, :where => { :published => true }
|
||||||
|
scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } }
|
||||||
|
scope :minimal_attributes, :only => %w(title slug fullpath position depth published templatized redirect listed parent_id created_at updated_at)
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
def index?
|
||||||
|
self.slug == 'index' && self.depth.to_i == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_found?
|
||||||
|
self.slug == '404' && self.depth.to_i == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def index_or_not_found?
|
||||||
|
self.index? || self.not_found?
|
||||||
|
end
|
||||||
|
|
||||||
|
def fullpath(force = false)
|
||||||
|
if read_attribute(:fullpath).present? && !force
|
||||||
|
return read_attribute(:fullpath)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.index? || self.not_found?
|
||||||
|
self.slug
|
||||||
|
else
|
||||||
|
slugs = self.self_and_ancestors.sort_by(&:depth).map(&:slug)
|
||||||
|
slugs.shift unless slugs.size == 1
|
||||||
|
File.join slugs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_cache?
|
||||||
|
self.cache_strategy != 'none'
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
Locomotive::Liquid::Drops::Page.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def do_not_remove_index_and_404_pages
|
||||||
|
return if self.site.nil? || self.site.destroyed?
|
||||||
|
|
||||||
|
if self.index? || self.not_found?
|
||||||
|
self.errors[:base] << I18n.t('errors.messages.protected_page')
|
||||||
|
end
|
||||||
|
|
||||||
|
self.errors.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_slug
|
||||||
|
self.slug = self.title.clone if self.slug.blank? && self.title.present?
|
||||||
|
self.slug.permalink! if self.slug.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_default_raw_template
|
||||||
|
self.raw_template ||= I18n.t('attributes.defaults.pages.other.body')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
71
app/models/locomotive/site.rb
Normal file
71
app/models/locomotive/site.rb
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
module Locomotive
|
||||||
|
class Site
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
## Extensions ##
|
||||||
|
extend Extensions::Site::SubdomainDomains
|
||||||
|
extend Extensions::Site::FirstInstallation
|
||||||
|
include Extensions::Shared::Seo
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :name
|
||||||
|
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 :assets, :dependent => :destroy, :validate => false
|
||||||
|
references_many :content_types, :dependent => :destroy, :validate => false
|
||||||
|
embeds_many :memberships
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :name
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
after_create :create_default_pages!
|
||||||
|
after_destroy :destroy_pages
|
||||||
|
|
||||||
|
## behaviours ##
|
||||||
|
enable_subdomain_n_domains_if_multi_sites
|
||||||
|
accepts_nested_attributes_for :memberships
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
def all_pages_in_once
|
||||||
|
Page.quick_tree(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def accounts
|
||||||
|
Account.criteria.in(:_id => self.memberships.collect(&:account_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def admin_memberships
|
||||||
|
self.memberships.find_all { |m| m.admin? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
Locomotive::Liquid::Drops::Site.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def create_default_pages!
|
||||||
|
%w{index 404}.each do |slug|
|
||||||
|
self.pages.create({
|
||||||
|
:slug => slug,
|
||||||
|
:title => I18n.t("attributes.defaults.pages.#{slug}.title"),
|
||||||
|
:raw_template => I18n.t("attributes.defaults.pages.#{slug}.body"),
|
||||||
|
:published => true
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_pages
|
||||||
|
# pages is a tree so we just need to delete the root (as well as the page not found page)
|
||||||
|
self.pages.root.first.try(:destroy) && self.pages.not_found.first.try(:destroy)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
65
app/models/locomotive/snippet.rb
Normal file
65
app/models/locomotive/snippet.rb
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
module
|
||||||
|
class Snippet
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :name
|
||||||
|
field :slug
|
||||||
|
field :template
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
referenced_in :site
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_validation :normalize_slug
|
||||||
|
after_save :update_templates
|
||||||
|
after_destroy :update_templates
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :site, :name, :slug, :template
|
||||||
|
validates_uniqueness_of :slug, :scope => :site_id
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def normalize_slug
|
||||||
|
# TODO: refactor it
|
||||||
|
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||||
|
self.slug.permalink! if self.slug.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_templates
|
||||||
|
return unless (self.site rescue false) # not run if the site is being destroyed
|
||||||
|
|
||||||
|
pages = self.site.pages.any_in(:snippet_dependencies => [self.slug]).to_a
|
||||||
|
|
||||||
|
pages.each do |page|
|
||||||
|
self._change_snippet_inside_template(page.template.root)
|
||||||
|
|
||||||
|
page.send(:_serialize_template)
|
||||||
|
|
||||||
|
Page.without_callback(:save, :after, :update_template_descendants) do
|
||||||
|
page.save(:validate => false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def _change_snippet_inside_template(node)
|
||||||
|
case node
|
||||||
|
when Locomotive::Liquid::Tags::Snippet
|
||||||
|
node.refresh(self) if node.slug == self.slug
|
||||||
|
when Locomotive::Liquid::Tags::InheritedBlock
|
||||||
|
_change_snippet_inside_template(node.parent) if node.parent
|
||||||
|
end
|
||||||
|
# Walk the children of this entry if they're available.
|
||||||
|
if node.respond_to?(:nodelist)
|
||||||
|
(node.nodelist || []).each do |child|
|
||||||
|
self._change_snippet_inside_template(child)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
154
app/models/locomotive/theme_asset.rb
Normal file
154
app/models/locomotive/theme_asset.rb
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
module Locomotive
|
||||||
|
class ThemeAsset
|
||||||
|
|
||||||
|
include Locomotive::Mongoid::Document
|
||||||
|
|
||||||
|
## extensions ##
|
||||||
|
include Extensions::Asset::Types
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :local_path
|
||||||
|
field :content_type
|
||||||
|
field :width, :type => Integer
|
||||||
|
field :height, :type => Integer
|
||||||
|
field :size, :type => Integer
|
||||||
|
field :folder, :default => nil
|
||||||
|
mount_uploader :source, ThemeAssetUploader
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
referenced_in :site
|
||||||
|
|
||||||
|
## indexes ##
|
||||||
|
index :site_id
|
||||||
|
index [[:site_id, Mongo::ASCENDING], [:local_path, Mongo::ASCENDING]]
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_validation :store_plain_text
|
||||||
|
before_validation :sanitize_folder
|
||||||
|
before_validation :build_local_path
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validates_presence_of :site, :source
|
||||||
|
validates_presence_of :plain_text_name, :if => Proc.new { |a| a.performing_plain_text? }
|
||||||
|
validates_uniqueness_of :local_path, :scope => :site_id
|
||||||
|
validates_integrity_of :source
|
||||||
|
validate :content_type_can_not_changed
|
||||||
|
|
||||||
|
## named scopes ##
|
||||||
|
|
||||||
|
## accessors ##
|
||||||
|
attr_accessor :plain_text_name, :plain_text, :plain_text_type, :performing_plain_text
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
def stylesheet_or_javascript?
|
||||||
|
self.stylesheet? || self.javascript?
|
||||||
|
end
|
||||||
|
|
||||||
|
def local_path(short = false)
|
||||||
|
if short
|
||||||
|
self.read_attribute(:local_path).gsub(/^#{self.content_type.to_s.pluralize}\//, '')
|
||||||
|
else
|
||||||
|
self.read_attribute(:local_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def plain_text_name
|
||||||
|
if not @plain_text_name_changed
|
||||||
|
@plain_text_name ||= self.safe_source_filename
|
||||||
|
end
|
||||||
|
@plain_text_name.gsub(/(\.[a-z0-9A-Z]+)$/, '') rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def plain_text_name=(name)
|
||||||
|
@plain_text_name_changed = true
|
||||||
|
@plain_text_name = name
|
||||||
|
end
|
||||||
|
|
||||||
|
def plain_text
|
||||||
|
if RUBY_VERSION =~ /1\.9/
|
||||||
|
@plain_text ||= (self.source.read.force_encoding('UTF-8') rescue nil)
|
||||||
|
else
|
||||||
|
@plain_text ||= self.source.read
|
||||||
|
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?
|
||||||
|
|
||||||
|
sanitized_source = self.escape_shortcut_urls(data)
|
||||||
|
|
||||||
|
self.source = CarrierWave::SanitizedFile.new({
|
||||||
|
:tempfile => StringIO.new(sanitized_source),
|
||||||
|
:filename => "#{self.plain_text_name}.#{self.stylesheet? ? 'css' : 'js'}"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
{ :url => self.source.url }.merge(self.attributes).stringify_keys
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def safe_source_filename
|
||||||
|
self.source_filename || self.source.send(:original_filename) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def sanitize_folder
|
||||||
|
self.folder = self.content_type.to_s.pluralize if self.folder.blank?
|
||||||
|
|
||||||
|
# no accents, no spaces, no leading and ending trails
|
||||||
|
self.folder = ActiveSupport::Inflector.transliterate(self.folder).gsub(/(\s)+/, '_').gsub(/^\//, '').gsub(/\/$/, '')
|
||||||
|
|
||||||
|
# folder should begin by a root folder
|
||||||
|
if (self.folder =~ /^(stylesheets|javascripts|images|medias|fonts)/).nil?
|
||||||
|
self.folder = File.join(self.content_type.to_s.pluralize, self.folder)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_local_path
|
||||||
|
if filename = self.safe_source_filename
|
||||||
|
self.local_path = File.join(self.folder, filename)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def escape_shortcut_urls(text)
|
||||||
|
return if text.blank?
|
||||||
|
|
||||||
|
text.gsub(/[("'](\/(stylesheets|javascripts|images|medias)\/(([^;.]+)\/)*([a-z_\-0-9]+)\.[a-z]{2,3})[)"']/) do |path|
|
||||||
|
|
||||||
|
sanitized_path = path.gsub(/[("')]/, '').gsub(/^\//, '')
|
||||||
|
|
||||||
|
if asset = self.site.theme_assets.where(:local_path => sanitized_path).first
|
||||||
|
"#{path.first}#{asset.source.url}#{path.last}"
|
||||||
|
else
|
||||||
|
path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_type_can_not_changed
|
||||||
|
self.errors.add(:source, :extname_changed) if !self.new_record? && self.content_type_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
@ -1,73 +0,0 @@
|
|||||||
class Membership
|
|
||||||
|
|
||||||
include Locomotive::Mongoid::Document
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :role, :default => 'author'
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
referenced_in :account, :validate => false
|
|
||||||
embedded_in :site, :inverse_of => :memberships
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :account
|
|
||||||
validate :can_change_role, :if => :role_changed?
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
@email = email
|
|
||||||
self.account = Account.where(:email => email).first
|
|
||||||
end
|
|
||||||
|
|
||||||
def process!
|
|
||||||
if @email.blank?
|
|
||||||
self.errors.add_on_blank(:email)
|
|
||||||
:error
|
|
||||||
elsif self.account.blank?
|
|
||||||
:create_account
|
|
||||||
elsif self.site.memberships.any? { |m| m.account_id == self.account_id && m._id != self._id }
|
|
||||||
self.errors.add(:base, 'Already created')
|
|
||||||
: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
|
|
||||||
|
|
||||||
# Users should not be able to set the role of another user to be higher than
|
|
||||||
# their own. A designer for example should not be able to set another user to
|
|
||||||
# be an administrator
|
|
||||||
def can_change_role
|
|
||||||
current_site = Thread.current[:site]
|
|
||||||
current_membership = current_site.memberships.where(:account_id => Thread.current[:admin].id).first if current_site.present?
|
|
||||||
|
|
||||||
if current_membership.present?
|
|
||||||
# The role cannot be set higher than the current one (we use the index in
|
|
||||||
# the roles array to check role presidence)
|
|
||||||
errors.add(:role, :invalid) if Ability::ROLES.index(role) < Ability::ROLES.index(current_membership.role)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,107 +0,0 @@
|
|||||||
class Page
|
|
||||||
|
|
||||||
include Locomotive::Mongoid::Document
|
|
||||||
|
|
||||||
## Extensions ##
|
|
||||||
include Extensions::Page::Tree
|
|
||||||
include Extensions::Page::EditableElements
|
|
||||||
include Extensions::Page::Parse
|
|
||||||
include Extensions::Page::Render
|
|
||||||
include Extensions::Page::Templatized
|
|
||||||
include Extensions::Page::Redirect
|
|
||||||
include Extensions::Page::Listed
|
|
||||||
include Extensions::Shared::Seo
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :title
|
|
||||||
field :slug
|
|
||||||
field :fullpath
|
|
||||||
field :raw_template
|
|
||||||
field :published, :type => Boolean, :default => false
|
|
||||||
field :cache_strategy, :default => 'none'
|
|
||||||
|
|
||||||
## associations ##
|
|
||||||
referenced_in :site
|
|
||||||
|
|
||||||
## indexes ##
|
|
||||||
index :site_id
|
|
||||||
index :parent_id
|
|
||||||
index [[:fullpath, Mongo::ASCENDING], [:site_id, Mongo::ASCENDING]]
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
after_initialize :set_default_raw_template
|
|
||||||
before_validation :normalize_slug
|
|
||||||
before_save { |p| p.fullpath = p.fullpath(true) }
|
|
||||||
before_destroy :do_not_remove_index_and_404_pages
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :site, :title, :slug
|
|
||||||
validates_uniqueness_of :slug, :scope => [:site_id, :parent_id]
|
|
||||||
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth == 0 }
|
|
||||||
|
|
||||||
## named scopes ##
|
|
||||||
scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
|
|
||||||
scope :root, :where => { :slug => 'index', :depth => 0 }
|
|
||||||
scope :not_found, :where => { :slug => '404', :depth => 0 }
|
|
||||||
scope :published, :where => { :published => true }
|
|
||||||
scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } }
|
|
||||||
scope :minimal_attributes, :only => %w(title slug fullpath position depth published templatized redirect listed parent_id created_at updated_at)
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
def index?
|
|
||||||
self.slug == 'index' && self.depth.to_i == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def not_found?
|
|
||||||
self.slug == '404' && self.depth.to_i == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def index_or_not_found?
|
|
||||||
self.index? || self.not_found?
|
|
||||||
end
|
|
||||||
|
|
||||||
def fullpath(force = false)
|
|
||||||
if read_attribute(:fullpath).present? && !force
|
|
||||||
return read_attribute(:fullpath)
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.index? || self.not_found?
|
|
||||||
self.slug
|
|
||||||
else
|
|
||||||
slugs = self.self_and_ancestors.sort_by(&:depth).map(&:slug)
|
|
||||||
slugs.shift unless slugs.size == 1
|
|
||||||
File.join slugs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def with_cache?
|
|
||||||
self.cache_strategy != 'none'
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_liquid
|
|
||||||
Locomotive::Liquid::Drops::Page.new(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def do_not_remove_index_and_404_pages
|
|
||||||
return if self.site.nil? || self.site.destroyed?
|
|
||||||
|
|
||||||
if self.index? || self.not_found?
|
|
||||||
self.errors[:base] << I18n.t('errors.messages.protected_page')
|
|
||||||
end
|
|
||||||
|
|
||||||
self.errors.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
def normalize_slug
|
|
||||||
self.slug = self.title.clone if self.slug.blank? && self.title.present?
|
|
||||||
self.slug.permalink! if self.slug.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_default_raw_template
|
|
||||||
self.raw_template ||= I18n.t('attributes.defaults.pages.other.body')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,69 +0,0 @@
|
|||||||
class Site
|
|
||||||
|
|
||||||
include Locomotive::Mongoid::Document
|
|
||||||
|
|
||||||
## Extensions ##
|
|
||||||
extend Extensions::Site::SubdomainDomains
|
|
||||||
extend Extensions::Site::FirstInstallation
|
|
||||||
include Extensions::Shared::Seo
|
|
||||||
|
|
||||||
## fields ##
|
|
||||||
field :name
|
|
||||||
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 :assets, :dependent => :destroy, :validate => false
|
|
||||||
references_many :content_types, :dependent => :destroy, :validate => false
|
|
||||||
embeds_many :memberships
|
|
||||||
|
|
||||||
## validations ##
|
|
||||||
validates_presence_of :name
|
|
||||||
|
|
||||||
## callbacks ##
|
|
||||||
after_create :create_default_pages!
|
|
||||||
after_destroy :destroy_pages
|
|
||||||
|
|
||||||
## behaviours ##
|
|
||||||
enable_subdomain_n_domains_if_multi_sites
|
|
||||||
accepts_nested_attributes_for :memberships
|
|
||||||
|
|
||||||
## methods ##
|
|
||||||
|
|
||||||
def all_pages_in_once
|
|
||||||
Page.quick_tree(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
def accounts
|
|
||||||
Account.criteria.in(:_id => self.memberships.collect(&:account_id))
|
|
||||||
end
|
|
||||||
|
|
||||||
def admin_memberships
|
|
||||||
self.memberships.find_all { |m| m.admin? }
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_liquid
|
|
||||||
Locomotive::Liquid::Drops::Site.new(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def create_default_pages!
|
|
||||||
%w{index 404}.each do |slug|
|
|
||||||
self.pages.create({
|
|
||||||
:slug => slug,
|
|
||||||
:title => I18n.t("attributes.defaults.pages.#{slug}.title"),
|
|
||||||
:raw_template => I18n.t("attributes.defaults.pages.#{slug}.body"),
|
|
||||||
:published => true
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy_pages
|
|
||||||
# pages is a tree so we just need to delete the root (as well as the page not found page)
|
|
||||||
self.pages.root.first.try(:destroy) && self.pages.not_found.first.try(:destroy)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user