Compare commits
76 Commits
Author | SHA1 | Date |
---|---|---|
Didier Lafforgue | fbcda9cdd6 | |
Didier Lafforgue | 6350652e4b | |
Paul Sponagl | a6ba124a9e | |
Paul Sponagl | 702283322d | |
Didier Lafforgue | ef66f88f5a | |
Didier Lafforgue | bae2fe4432 | |
Didier Lafforgue | 50204b6556 | |
did | 11c4f98efc | |
did | 55b7d4dbf2 | |
Didier Lafforgue | 2bd9e254c8 | |
did | 3f1380408e | |
Didier Lafforgue | 5f9c46b42c | |
Didier Lafforgue | b4dd590f9a | |
Didier Lafforgue | 34ba62c15c | |
did | acd46f1c10 | |
Manfred Klaffenboeck | 30557ef8b0 | |
Alex Sanford | 6f5eec18c6 | |
Didier Lafforgue | bc63cd8acf | |
Manfred Klaffenboeck | b993b4f0ca | |
Manfred Klaffenboeck | 590c4bb048 | |
did | 2bec96e9f1 | |
did | 2568510f01 | |
did | f8725ede67 | |
did | f4ee99b72b | |
did | 763fe5215f | |
did | 261575eb94 | |
Didier Lafforgue | b706d50bdf | |
did | 3a4654e8f7 | |
Bjørn Trondsen | a662366637 | |
Bjørn Trondsen | 6ac3d72aed | |
Bjørn Trondsen | 8b56ee5889 | |
Didier Lafforgue | b751e3d990 | |
Didier Lafforgue | ae16661286 | |
Didier Lafforgue | da2d689bdc | |
Didier Lafforgue | 2ac74c9a50 | |
Didier Lafforgue | 24ae75c6f5 | |
Didier Lafforgue | c58075b7c3 | |
Didier Lafforgue | 662e359acb | |
Mario Visic | 8be23f1cc2 | |
Mario Visic | fbef06f103 | |
Mario Visic | 38098e93da | |
Mario Visic | 3a27845fe5 | |
Mario Visic | 4c5d6c92d0 | |
Mario Visic | 817ee8b0e5 | |
Mario Visic | 13b4d8c606 | |
did | 6342b94ede | |
did | d3e219018b | |
Mario Visic | 415817e20b | |
did | 04d9fe17f8 | |
did | d90123e321 | |
waynegerard | 2fa81112fc | |
waynegerard | be26ae3059 | |
Mario Visic | 7e0fcb62ee | |
Will Cosgrove | c0627bf8a7 | |
Didier Lafforgue | e225ad2278 | |
did | a939629cbf | |
Didier Lafforgue | f42fb1afe1 | |
did | 03d13d92d0 | |
Alex Sanford | 24e5eb855a | |
Alex Sanford | 9c15f1cbab | |
Alex Sanford | 06e493477c | |
Alex Sanford | 96007174cb | |
Alex Sanford | a921c44ce9 | |
Alex Sanford | 37f87e694c | |
Alex Sanford | 4e6c106772 | |
Alex Sanford | d2da4b659e | |
Alex Sanford | 44aadb8926 | |
Alex Sanford | 75e694a6f0 | |
Alex Sanford | 7dcc1ba3f6 | |
Alex Sanford | 1344463222 | |
Alex Sanford | bf65fa47f3 | |
Alex Sanford | f53ab18f90 | |
Alex Sanford | 494e3c9b51 | |
Alex Sanford | edd236b202 | |
Alex Sanford | 97edb0e4b7 | |
Alex Sanford | 4f12c2cd10 |
10
Gemfile
10
Gemfile
|
@ -22,9 +22,8 @@ end
|
|||
group :assets do
|
||||
gem 'sass-rails', '~> 3.2.4'
|
||||
gem 'coffee-rails', '~> 3.2.2'
|
||||
gem 'uglifier', '~> 1.2.3'
|
||||
gem 'compass', :git => 'git://github.com/chriseppstein/compass.git', :branch => 'no_rails_integration'
|
||||
gem 'compass-rails', :git => 'git://github.com/Compass/compass-rails.git'
|
||||
gem 'uglifier', '~> 1.2.4'
|
||||
gem 'compass-rails'
|
||||
end
|
||||
|
||||
group :test do
|
||||
|
@ -36,6 +35,7 @@ group :test do
|
|||
# gem 'growl-glue'
|
||||
|
||||
gem 'cucumber-rails', :require => false
|
||||
gem 'poltergeist'
|
||||
gem 'rspec-rails', '~> 2.8.0'
|
||||
gem 'shoulda-matchers'
|
||||
|
||||
|
@ -50,4 +50,6 @@ group :test do
|
|||
gem 'json_spec'
|
||||
|
||||
gem 'database_cleaner'
|
||||
end
|
||||
|
||||
# gem 'debugger', :git => 'git://github.com/cldwalker/debugger.git'
|
||||
end
|
||||
|
|
188
Gemfile.lock
188
Gemfile.lock
|
@ -1,42 +1,25 @@
|
|||
GIT
|
||||
remote: git://github.com/Compass/compass-rails.git
|
||||
revision: 47d889ad8dabdab1e9f44da4447f94846c089c50
|
||||
specs:
|
||||
compass-rails (1.0.0.rc.3)
|
||||
compass (~> 0.12.rc.0)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/chriseppstein/compass.git
|
||||
revision: 0f96e881019c364aa6124845cbd83b1fd75c4ffe
|
||||
branch: no_rails_integration
|
||||
specs:
|
||||
compass (0.12.rc.4.0f96e88)
|
||||
chunky_png (~> 1.2)
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.1)
|
||||
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
locomotive_cms (2.0.0.rc7)
|
||||
locomotive_cms (2.0.0.rc8)
|
||||
RedCloth (~> 4.2.8)
|
||||
actionmailer-with-request (~> 0.3.0)
|
||||
bson_ext (~> 1.5.2)
|
||||
cancan (~> 1.6.7)
|
||||
carrierwave (~> 0.6.0)
|
||||
carrierwave-mongoid (~> 0.1.3)
|
||||
carrierwave-mongoid (~> 0.2.1)
|
||||
cells (~> 3.8.0)
|
||||
codemirror-rails (~> 2.21)
|
||||
custom_fields (~> 2.0.0.rc10)
|
||||
devise (~> 1.5.3)
|
||||
custom_fields (~> 2.0.0.rc12)
|
||||
devise (~> 2.1.0)
|
||||
devise-encryptable (~> 0.1.1)
|
||||
dragonfly (~> 0.9.8)
|
||||
flash_cookie_session (~> 1.1.1)
|
||||
fog (~> 1.3.1)
|
||||
formtastic (~> 2.0.2)
|
||||
haml (~> 3.1.4)
|
||||
haml (~> 3.1.6)
|
||||
highline (~> 1.6.2)
|
||||
httparty (~> 0.8.1)
|
||||
jquery-rails (~> 1.0.16)
|
||||
jquery-rails (~> 1.0.19)
|
||||
kaminari (~> 0.13.0)
|
||||
locomotive-aloha-rails (~> 0.20.1.4)
|
||||
locomotive-mongoid-tree (~> 0.6.2)
|
||||
|
@ -45,9 +28,9 @@ PATH
|
|||
mimetype-fu (~> 0.1.2)
|
||||
mongo (~> 1.5.2)
|
||||
mongoid (~> 2.4.9)
|
||||
multi_json (= 1.2.0)
|
||||
multi_json (~> 1.3.4)
|
||||
rack-cache (~> 1.1)
|
||||
rails (~> 3.2.3)
|
||||
rails (~> 3.2.5)
|
||||
rails-backbone (~> 0.6.1)
|
||||
rake (~> 0.9.2)
|
||||
responders (~> 0.6.4)
|
||||
|
@ -59,36 +42,36 @@ GEM
|
|||
remote: http://rubygems.org/
|
||||
specs:
|
||||
RedCloth (4.2.9)
|
||||
actionmailer (3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
actionmailer (3.2.5)
|
||||
actionpack (= 3.2.5)
|
||||
mail (~> 2.4.4)
|
||||
actionmailer-with-request (0.3.0)
|
||||
rails (>= 3)
|
||||
actionpack (3.2.3)
|
||||
activemodel (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
actionpack (3.2.5)
|
||||
activemodel (= 3.2.5)
|
||||
activesupport (= 3.2.5)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.1)
|
||||
rack (~> 1.4.0)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.1.2)
|
||||
activemodel (3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
sprockets (~> 2.1.3)
|
||||
activemodel (3.2.5)
|
||||
activesupport (= 3.2.5)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.3)
|
||||
activemodel (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
activerecord (3.2.5)
|
||||
activemodel (= 3.2.5)
|
||||
activesupport (= 3.2.5)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.3)
|
||||
activemodel (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
activesupport (3.2.3)
|
||||
activeresource (3.2.5)
|
||||
activemodel (= 3.2.5)
|
||||
activesupport (= 3.2.5)
|
||||
activesupport (3.2.5)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
addressable (2.2.7)
|
||||
addressable (2.2.8)
|
||||
arel (3.0.2)
|
||||
bcrypt-ruby (3.0.1)
|
||||
bson (1.5.2)
|
||||
|
@ -106,13 +89,13 @@ GEM
|
|||
carrierwave (0.6.2)
|
||||
activemodel (>= 3.2.0)
|
||||
activesupport (>= 3.2.0)
|
||||
carrierwave-mongoid (0.1.3)
|
||||
carrierwave (>= 0.5.6)
|
||||
carrierwave-mongoid (0.2.1)
|
||||
carrierwave (~> 0.6.1)
|
||||
mongoid (~> 2.1)
|
||||
cells (3.8.3)
|
||||
cells (3.8.5)
|
||||
actionpack (~> 3.0)
|
||||
railties (~> 3.0)
|
||||
childprocess (0.3.1)
|
||||
childprocess (0.3.2)
|
||||
ffi (~> 1.0.6)
|
||||
chunky_png (1.2.5)
|
||||
codemirror-rails (2.24)
|
||||
|
@ -123,39 +106,50 @@ GEM
|
|||
coffee-script (2.2.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.3.1)
|
||||
cucumber (1.1.9)
|
||||
coffee-script-source (1.3.3)
|
||||
compass (0.12.1)
|
||||
chunky_png (~> 1.2)
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.1)
|
||||
compass-rails (1.0.2)
|
||||
compass (>= 0.12.0, < 0.14)
|
||||
cucumber (1.2.1)
|
||||
builder (>= 2.1.2)
|
||||
diff-lcs (>= 1.1.2)
|
||||
gherkin (~> 2.9.0)
|
||||
diff-lcs (>= 1.1.3)
|
||||
gherkin (~> 2.11.0)
|
||||
json (>= 1.4.6)
|
||||
term-ansicolor (>= 1.0.6)
|
||||
cucumber-rails (1.3.0)
|
||||
capybara (>= 1.1.2)
|
||||
cucumber (>= 1.1.8)
|
||||
nokogiri (>= 1.5.0)
|
||||
custom_fields (2.0.0.rc10)
|
||||
custom_fields (2.0.0.rc12)
|
||||
activesupport (~> 3.2.1)
|
||||
carrierwave-mongoid (~> 0.1.3)
|
||||
mongoid (~> 2.4.7)
|
||||
database_cleaner (0.7.2)
|
||||
devise (1.5.3)
|
||||
carrierwave-mongoid (~> 0.2.1)
|
||||
mongoid (~> 2.4.9)
|
||||
database_cleaner (0.8.0)
|
||||
devise (2.1.0)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.0.3)
|
||||
warden (~> 1.1)
|
||||
orm_adapter (~> 0.0.7)
|
||||
railties (~> 3.1)
|
||||
warden (~> 1.1.1)
|
||||
devise-encryptable (0.1.1)
|
||||
devise (>= 2.1.0.rc)
|
||||
diff-lcs (1.1.3)
|
||||
dragonfly (0.9.12)
|
||||
rack
|
||||
ejs (1.0.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (0.12.10)
|
||||
excon (0.13.4)
|
||||
execjs (1.3.0)
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
factory_girl (2.5.2)
|
||||
activesupport (>= 2.3.9)
|
||||
factory_girl_rails (1.6.0)
|
||||
factory_girl (~> 2.5.0)
|
||||
railties (>= 3.0.0)
|
||||
faye-websocket (0.4.5)
|
||||
eventmachine (>= 0.12.0)
|
||||
ffi (1.0.11)
|
||||
flash_cookie_session (1.1.3)
|
||||
rails (~> 3.0)
|
||||
|
@ -169,15 +163,16 @@ GEM
|
|||
net-ssh (>= 2.1.3)
|
||||
nokogiri (~> 1.5.0)
|
||||
ruby-hmac
|
||||
formatador (0.2.1)
|
||||
formatador (0.2.3)
|
||||
formtastic (2.0.2)
|
||||
rails (~> 3.0)
|
||||
fssm (0.2.9)
|
||||
gherkin (2.9.3)
|
||||
gherkin (2.11.0)
|
||||
json (>= 1.4.6)
|
||||
haml (3.1.4)
|
||||
highline (1.6.11)
|
||||
haml (3.1.6)
|
||||
highline (1.6.12)
|
||||
hike (1.2.1)
|
||||
http_parser.rb (0.5.3)
|
||||
httparty (0.8.3)
|
||||
multi_json (~> 1.0)
|
||||
multi_xml
|
||||
|
@ -186,8 +181,8 @@ GEM
|
|||
jquery-rails (1.0.19)
|
||||
railties (~> 3.0)
|
||||
thor (~> 0.14)
|
||||
json (1.6.6)
|
||||
json_spec (1.0.0)
|
||||
json (1.7.3)
|
||||
json_spec (1.0.3)
|
||||
multi_json (~> 1.0)
|
||||
rspec (~> 2.0)
|
||||
kaminari (0.13.0)
|
||||
|
@ -215,20 +210,26 @@ GEM
|
|||
mocha (0.9.12)
|
||||
mongo (1.5.2)
|
||||
bson (= 1.5.2)
|
||||
mongoid (2.4.9)
|
||||
mongoid (2.4.11)
|
||||
activemodel (~> 3.1)
|
||||
mongo (~> 1.3)
|
||||
mongo (<= 1.6.2)
|
||||
tzinfo (~> 0.3.22)
|
||||
multi_json (1.2.0)
|
||||
multi_xml (0.4.4)
|
||||
multi_json (1.3.6)
|
||||
multi_xml (0.5.1)
|
||||
net-scp (1.0.4)
|
||||
net-ssh (>= 1.99.1)
|
||||
net-ssh (2.3.0)
|
||||
nokogiri (1.5.2)
|
||||
net-ssh (2.5.2)
|
||||
nokogiri (1.5.3)
|
||||
orm_adapter (0.0.7)
|
||||
pickle (0.4.10)
|
||||
cucumber (>= 0.8)
|
||||
rake
|
||||
poltergeist (0.6.0)
|
||||
capybara (~> 1.0)
|
||||
childprocess (~> 0.3)
|
||||
faye-websocket (~> 0.4, >= 0.4.4)
|
||||
http_parser.rb (~> 0.5.3)
|
||||
multi_json (~> 1.0)
|
||||
polyglot (0.3.3)
|
||||
rack (1.4.1)
|
||||
rack-cache (1.2)
|
||||
|
@ -237,26 +238,26 @@ GEM
|
|||
rack
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.3)
|
||||
actionmailer (= 3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
activerecord (= 3.2.3)
|
||||
activeresource (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
rails (3.2.5)
|
||||
actionmailer (= 3.2.5)
|
||||
actionpack (= 3.2.5)
|
||||
activerecord (= 3.2.5)
|
||||
activeresource (= 3.2.5)
|
||||
activesupport (= 3.2.5)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.3)
|
||||
railties (= 3.2.5)
|
||||
rails-backbone (0.6.1)
|
||||
coffee-script (~> 2.2.0)
|
||||
ejs (~> 1.0.0)
|
||||
railties (>= 3.1.0)
|
||||
railties (3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
railties (3.2.5)
|
||||
actionpack (= 3.2.5)
|
||||
activesupport (= 3.2.5)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (~> 0.14.6)
|
||||
raindrops (0.8.0)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
raindrops (0.9.0)
|
||||
rake (0.9.2.2)
|
||||
rdoc (3.12)
|
||||
json (~> 1.4)
|
||||
|
@ -280,28 +281,27 @@ GEM
|
|||
railties (>= 3.0)
|
||||
rspec (~> 2.8.0)
|
||||
ruby-hmac (0.4.0)
|
||||
rubyzip (0.9.7)
|
||||
rubyzip (0.9.8)
|
||||
sanitize (2.0.3)
|
||||
nokogiri (>= 1.4.4, < 1.6)
|
||||
sass (3.1.15)
|
||||
sass (3.1.19)
|
||||
sass-rails (3.2.5)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
selenium-webdriver (2.21.1)
|
||||
selenium-webdriver (2.22.2)
|
||||
childprocess (>= 0.2.5)
|
||||
ffi (~> 1.0)
|
||||
libwebsocket (~> 0.1.3)
|
||||
multi_json (< 1.3)
|
||||
multi_json (~> 1.0)
|
||||
rubyzip
|
||||
shoulda-matchers (1.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sprockets (2.1.2)
|
||||
sprockets (2.1.3)
|
||||
hike (~> 1.2)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
term-ansicolor (1.0.7)
|
||||
thor (0.14.6)
|
||||
thor (0.15.2)
|
||||
tilt (1.3.3)
|
||||
treetop (1.4.10)
|
||||
polyglot
|
||||
|
@ -310,7 +310,7 @@ GEM
|
|||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
unicorn (4.2.1)
|
||||
unicorn (4.3.1)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
|
@ -326,8 +326,7 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
capybara
|
||||
coffee-rails (~> 3.2.2)
|
||||
compass!
|
||||
compass-rails!
|
||||
compass-rails
|
||||
cucumber-rails
|
||||
database_cleaner
|
||||
factory_girl_rails (~> 1.6.0)
|
||||
|
@ -336,10 +335,11 @@ DEPENDENCIES
|
|||
locomotive_cms!
|
||||
mocha (= 0.9.12)
|
||||
pickle
|
||||
poltergeist
|
||||
rspec-cells
|
||||
rspec-rails (~> 2.8.0)
|
||||
sass-rails (~> 3.2.4)
|
||||
shoulda-matchers
|
||||
uglifier (~> 1.2.3)
|
||||
uglifier (~> 1.2.4)
|
||||
unicorn
|
||||
xpath (~> 0.1.4)
|
||||
|
|
|
@ -24,8 +24,8 @@ h2. Gems
|
|||
|
||||
Here is a short list of main gems / technologies used in the application.
|
||||
|
||||
* Rails 3.2.3
|
||||
* Mongoid 2.4.6 (with MongoDB 2.0)
|
||||
* Rails 3.2.5
|
||||
* Mongoid 2.4.9 (with MongoDB 2.0)
|
||||
* Liquid
|
||||
* Devise
|
||||
* Carrierwave
|
||||
|
@ -46,7 +46,7 @@ h2. Community
|
|||
|
||||
* Get help or discuss locomotive CMS at the "LocomotiveCMS Google group":https://groups.google.com/forum/?fromgroups#!forum/locomotivecms or the "LocomotiveCMS Discussion Forums":http://locomotive.vanillaforums.com/ (deprecated)
|
||||
* Join us on IRC "#locomotivecms at irc.freenode.net!":http://webchat.freenode.net/
|
||||
* "Follow us on twitter":http://twitter.com/locomotiveapp
|
||||
* "Follow us on twitter":http://twitter.com/locomotivecms
|
||||
|
||||
h2. Contributing to Locomotive
|
||||
|
||||
|
@ -55,6 +55,7 @@ Locomotive CMS is an open source project, we encourage contributions. If you hav
|
|||
* Install ruby and mongoDB
|
||||
* Clone the project <code>git clone git@github.com:locomotivecms/engine.git</code>
|
||||
* Setup a virtual host entry for <code>test.example.com</code> to point to localhost
|
||||
* Install PhantomJS (Required for the cucumber suite See: https://github.com/jonleighton/poltergeist)
|
||||
* Run the tests <code>rake</code>
|
||||
* Write your failing tests
|
||||
* Make the tests pass
|
||||
|
|
Before Width: | Height: | Size: 611 B After Width: | Height: | Size: 611 B |
|
@ -25,7 +25,7 @@ define(
|
|||
picker.close();
|
||||
}
|
||||
|
||||
picker.render()
|
||||
picker.fetch_assets();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -69,5 +69,7 @@
|
|||
doc.head.appendChild(stylesheet);
|
||||
}
|
||||
|
||||
$.ui.dialog.prototype.overlayEl = function() { return this.overlay.$el; }
|
||||
|
||||
})();
|
||||
|
||||
|
|
|
@ -83,3 +83,10 @@ class Locomotive.Views.ApplicationView extends Backbone.View
|
|||
locale = $(@).attr('data-locale')
|
||||
window.addParameterToURL 'content_locale', locale
|
||||
|
||||
unique_dialog_zindex: ->
|
||||
# returns the number of jQuery UI modals created in order to set a valid zIndex for each of them.
|
||||
# Each modal window should have a different zIndex, otherwise there will be conflicts between them.
|
||||
window.Locomotive.jQueryModals ||= 0
|
||||
|
||||
998 + window.Locomotive.jQueryModals++
|
||||
|
||||
|
|
|
@ -12,7 +12,10 @@ class Locomotive.Views.ContentAssets.PickerView extends Locomotive.Views.Shared.
|
|||
ich.content_asset_picker
|
||||
|
||||
fetch_assets: ->
|
||||
@collection.fetch()
|
||||
@_reset()
|
||||
@collection.fetch
|
||||
success: () =>
|
||||
@open()
|
||||
|
||||
build_uploader: (el, link) ->
|
||||
link.bind 'click', (event) ->
|
||||
|
|
|
@ -50,11 +50,13 @@ class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.F
|
|||
settings = _.extend {}, @tinyMCE_settings(),
|
||||
oninit: ((editor) =>
|
||||
$.cmd 'S', (() =>
|
||||
$(textarea).val(editor.getBody().innerHTML).trigger('change')
|
||||
editor.save()
|
||||
$(textarea).trigger('changeSilently')
|
||||
@$('form').trigger('submit')
|
||||
), [], ignoreCase: true, document: editor.dom.doc),
|
||||
onchange_callback: (editor) =>
|
||||
$(textarea).val(editor.getBody().innerHTML).trigger('change')
|
||||
editor.save()
|
||||
$(textarea).trigger('changeSilently')
|
||||
|
||||
$(textarea).tinymce(settings)
|
||||
|
||||
|
|
|
@ -26,11 +26,9 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
|
|||
@dialog = $(@el).dialog
|
||||
autoOpen: false
|
||||
modal: true
|
||||
zIndex: 998
|
||||
zIndex: window.application_view.unique_dialog_zindex()
|
||||
width: 770,
|
||||
create: (event, ui) =>
|
||||
$('.ui-widget-overlay').bind 'click', => @close()
|
||||
|
||||
$(@el).prev().find('.ui-dialog-title').html(@$('h2').html())
|
||||
@$('h2').remove()
|
||||
actions = @$('.dialog-actions').appendTo($(@el).parent()).addClass('ui-dialog-buttonpane ui-widget-content ui-helper-clearfix')
|
||||
|
@ -39,6 +37,7 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
|
|||
actions.find('input[type=submit]').click (event) => @save(event)
|
||||
|
||||
open: (event, ui, extra) =>
|
||||
$(@el).dialog('overlayEl').bind 'click', => @close()
|
||||
# nothing to do
|
||||
|
||||
open: ->
|
||||
|
@ -57,6 +56,7 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
|
|||
close: (event) ->
|
||||
event.stopPropagation() & event.preventDefault() if event?
|
||||
@clear_errors()
|
||||
$(@el).dialog('overlayEl').unbind('click')
|
||||
$(@el).dialog('close')
|
||||
|
||||
center: ->
|
||||
|
@ -71,6 +71,9 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
|
|||
else
|
||||
@refresh()
|
||||
|
||||
slugify_label_field: ->
|
||||
# disabled in a popup form
|
||||
|
||||
enable_has_many_fields: ->
|
||||
# disabled in a popup form
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@ class Locomotive.Views.ContentTypes.FormView extends Locomotive.Views.Shared.For
|
|||
initialize: ->
|
||||
@model = new Locomotive.Models.ContentType(@options.content_type)
|
||||
|
||||
window.foo = @model
|
||||
|
||||
Backbone.ModelBinding.bind @
|
||||
|
||||
render: ->
|
||||
|
|
|
@ -58,11 +58,18 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
|||
fetch_inverse_of_list: ->
|
||||
@$('li.input.inverse-of select option').remove()
|
||||
|
||||
_.each @inverse_of_list[@model.get('type')], (data) =>
|
||||
list = @inverse_of_list[@model.get('type')] || []
|
||||
|
||||
_.each list, (data) =>
|
||||
if data.class_name == @model.get('class_name')
|
||||
option = new Option(data.label, data.name, data.class_name == @model.get('inverse_of') || @inverse_of_list.length == 1)
|
||||
option = new Option(data.label, data.name, data.name == @model.get('inverse_of') || list.length == 1)
|
||||
@$('li.input.inverse-of select').append(option)
|
||||
|
||||
# by default, select the first option
|
||||
if !@model.get('inverse_of')? && list.length > 0
|
||||
@model.set
|
||||
inverse_of: list[0].name
|
||||
|
||||
render_select_options_view: ->
|
||||
@select_options_view = new Locomotive.Views.ContentTypes.SelectOptionsView
|
||||
model: @model
|
||||
|
|
|
@ -15,8 +15,6 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
|
|||
|
||||
Backbone.ModelBinding.bind @, checkbox: 'class'
|
||||
|
||||
window.foo = @model
|
||||
|
||||
render: ->
|
||||
super()
|
||||
|
||||
|
@ -57,15 +55,16 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
|
|||
@$('#site_memberships_input').append(@memberships_view.render().el)
|
||||
|
||||
enable_liquid_editing: ->
|
||||
input = @$('#site_robots_txt')
|
||||
@editor = CodeMirror.fromTextArea input.get()[0],
|
||||
mode: 'liquid'
|
||||
autoMatchParens: false
|
||||
lineNumbers: false
|
||||
passDelay: 50
|
||||
tabMode: 'shift'
|
||||
theme: 'default'
|
||||
onChange: (editor) => @model.set(robots_txt: editor.getValue())
|
||||
if($('#site_robots_txt').length)
|
||||
input = @$('#site_robots_txt')
|
||||
@editor = CodeMirror.fromTextArea input.get()[0],
|
||||
mode: 'liquid'
|
||||
autoMatchParens: false
|
||||
lineNumbers: false
|
||||
passDelay: 50
|
||||
tabMode: 'shift'
|
||||
theme: 'default'
|
||||
onChange: (editor) => @model.set(robots_txt: editor.getValue())
|
||||
|
||||
save: (event) ->
|
||||
if @model.includes_domain(window.location.host)
|
||||
|
|
|
@ -24,6 +24,8 @@ class Locomotive.Views.InlineEditor.ApplicationView extends Backbone.View
|
|||
|
||||
@toolbar_view.render()
|
||||
|
||||
@content_assets_picker_view.render()
|
||||
|
||||
enable_iframe_autoheight: ->
|
||||
iframe = @iframe
|
||||
|
||||
|
@ -89,6 +91,13 @@ class Locomotive.Views.InlineEditor.ApplicationView extends Backbone.View
|
|||
toolbar_view.show_status 'loading'
|
||||
window.history.pushState('Object', 'Title', link.attr('href').replace('_edit', '_admin'))
|
||||
|
||||
unique_dialog_zindex: ->
|
||||
# returns the number of jQuery UI modals created in order to set a valid zIndex for each of them.
|
||||
# Each modal window should have a different zIndex, otherwise there will be conflicts between them.
|
||||
window.Locomotive.jQueryModals ||= 0
|
||||
|
||||
1050 + window.Locomotive.jQueryModals++
|
||||
|
||||
_$: (selector) ->
|
||||
$(selector, @iframe[0].contentWindow.document)
|
||||
|
||||
|
|
|
@ -16,14 +16,14 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
|
|||
|
||||
@model = new Locomotive.Models.Page(@options.page)
|
||||
|
||||
window.foo = @model
|
||||
|
||||
@touched_url = false
|
||||
|
||||
@image_picker_view = new Locomotive.Views.ThemeAssets.ImagePickerView
|
||||
collection: new Locomotive.Models.ThemeAssetsCollection()
|
||||
on_select: @insert_image
|
||||
|
||||
@image_picker_view.render()
|
||||
|
||||
Backbone.ModelBinding.bind @
|
||||
|
||||
@editable_elements_view = new Locomotive.Views.EditableElements.EditAllView(collection: @model.get('editable_elements'))
|
||||
|
@ -58,7 +58,7 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
|
|||
open_image_picker: (event) ->
|
||||
event.stopPropagation() & event.preventDefault()
|
||||
@image_picker_view.editor = @editor
|
||||
@image_picker_view.render()
|
||||
@image_picker_view.fetch_assets()
|
||||
|
||||
insert_image: (path) ->
|
||||
text = "{{ '#{path}' | theme_image_url }}"
|
||||
|
|
|
@ -11,11 +11,9 @@ class Locomotive.Views.Shared.AssetPickerView extends Backbone.View
|
|||
@collection.bind('remove', @remove_asset)
|
||||
|
||||
render: ->
|
||||
@_reset()
|
||||
|
||||
$(@el).html(@template()())
|
||||
|
||||
@fetch_assets()
|
||||
@create_dialog()
|
||||
|
||||
return @
|
||||
|
||||
|
@ -29,33 +27,32 @@ class Locomotive.Views.Shared.AssetPickerView extends Backbone.View
|
|||
# please overide build_uploader
|
||||
|
||||
create_dialog: ->
|
||||
@dialog = $(@el).dialog
|
||||
@dialog ||= $(@el).dialog
|
||||
autoOpen: false
|
||||
modal: true
|
||||
zIndex: 998
|
||||
zIndex: window.application_view.unique_dialog_zindex()
|
||||
width: 650,
|
||||
create: (event, ui) =>
|
||||
$('.ui-widget-overlay').bind 'click', => @close()
|
||||
|
||||
$(@el).prev().find('.ui-dialog-title').html(@$('h2').html())
|
||||
@$('h2').remove()
|
||||
actions = @$('.dialog-actions').appendTo($(@el).parent()).addClass('ui-dialog-buttonpane ui-widget-content ui-helper-clearfix')
|
||||
|
||||
actions.find('#close-link').click (event) => @close(event)
|
||||
|
||||
input = actions.find('input[type=file]')
|
||||
link = actions.find('#upload-link')
|
||||
|
||||
@build_uploader(input, link)
|
||||
|
||||
open: (event, ui, extra) =>
|
||||
actions = $(@el).parent().find('.ui-dialog-buttonpane')
|
||||
el = actions.find('input[type=file]')
|
||||
link = actions.find('#upload-link')
|
||||
|
||||
@build_uploader(el, link)
|
||||
|
||||
@open()
|
||||
$(@el).dialog('overlayEl').bind 'click', => @close()
|
||||
|
||||
open: ->
|
||||
$(@el).dialog('open')
|
||||
|
||||
close: (event) ->
|
||||
event.stopPropagation() & event.preventDefault() if event?
|
||||
$(@el).dialog('overlayEl').unbind('click')
|
||||
$(@el).dialog('close')
|
||||
|
||||
shake: ->
|
||||
|
@ -70,8 +67,6 @@ class Locomotive.Views.Shared.AssetPickerView extends Backbone.View
|
|||
|
||||
@_refresh()
|
||||
|
||||
setTimeout (=> @create_dialog()), 30 # disable flickering
|
||||
|
||||
add_asset: (asset, first) ->
|
||||
# please overide add_asset (the 'first' param is to know if it comes from the first collection fetch)
|
||||
|
||||
|
@ -94,6 +89,4 @@ class Locomotive.Views.Shared.AssetPickerView extends Backbone.View
|
|||
_on_refresh: ->
|
||||
|
||||
_reset: ->
|
||||
$('.ui-widget-overlay').unbind 'click'
|
||||
@$('.actions input[type=file]').remove()
|
||||
@dialog.dialog('destroy') if @dialog?
|
||||
# for nothing to do
|
||||
|
|
|
@ -36,7 +36,8 @@ class Locomotive.Views.Shared.FormView extends Backbone.View
|
|||
previous_attributes = _.clone @model.attributes
|
||||
|
||||
@model.save {},
|
||||
headers: options.headers
|
||||
headers: options.headers
|
||||
silent: true # since we pass an empty hash above, no need to trigger the callbacks
|
||||
success: (model, response, xhr) =>
|
||||
form.trigger('ajax:complete')
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ class Locomotive.Views.Snippets.FormView extends Locomotive.Views.Shared.FormVie
|
|||
collection: new Locomotive.Models.ThemeAssetsCollection()
|
||||
on_select: @insert_image
|
||||
|
||||
@image_picker_view.render()
|
||||
|
||||
Backbone.ModelBinding.bind @
|
||||
|
||||
render: ->
|
||||
|
@ -38,7 +40,7 @@ class Locomotive.Views.Snippets.FormView extends Locomotive.Views.Shared.FormVie
|
|||
open_image_picker: (event) ->
|
||||
event.stopPropagation() & event.preventDefault()
|
||||
@image_picker_view.editor = @editor
|
||||
@image_picker_view.render()
|
||||
@image_picker_view.fetch_assets()
|
||||
|
||||
insert_image: (path) ->
|
||||
text = "{{ '#{path}' | theme_image_url }}"
|
||||
|
|
|
@ -15,10 +15,10 @@ class Locomotive.Views.ThemeAssets.FormView extends Locomotive.Views.Shared.Form
|
|||
|
||||
@model = new Locomotive.Models.ThemeAsset(@options.theme_asset)
|
||||
|
||||
window.foo = @model
|
||||
|
||||
@image_picker_view = new Locomotive.Views.ThemeAssets.ImagePickerView on_select: @insert_image
|
||||
|
||||
@image_picker_view.render()
|
||||
|
||||
Backbone.ModelBinding.bind @
|
||||
|
||||
render: ->
|
||||
|
@ -72,10 +72,10 @@ class Locomotive.Views.ThemeAssets.FormView extends Locomotive.Views.Shared.Form
|
|||
open_image_picker: (event) ->
|
||||
event.stopPropagation() & event.preventDefault()
|
||||
@image_picker_view.editor = @editor
|
||||
@image_picker_view.render()
|
||||
@image_picker_view.fetch_assets()
|
||||
|
||||
insert_image: (path) ->
|
||||
text = "{{ '#{path}' | theme_image_url }}"
|
||||
text = "'#{path}'"
|
||||
@editor.replaceSelection(text)
|
||||
@image_picker_view.close()
|
||||
|
||||
|
|
|
@ -15,7 +15,12 @@ class Locomotive.Views.ThemeAssets.ImagePickerView extends Locomotive.Views.Shar
|
|||
ich.theme_image_picker
|
||||
|
||||
fetch_assets: ->
|
||||
@collection.fetch data: { content_type: 'image' }
|
||||
@_reset()
|
||||
@collection.fetch
|
||||
data:
|
||||
content_type: 'image'
|
||||
success: () =>
|
||||
@open()
|
||||
|
||||
build_uploader: (el, link) ->
|
||||
link.bind 'click', (event) ->
|
||||
|
@ -37,4 +42,7 @@ class Locomotive.Views.ThemeAssets.ImagePickerView extends Locomotive.Views.Shar
|
|||
|
||||
add_asset: (asset) ->
|
||||
@$('ul.list').append(ich.theme_asset(asset.toJSON()))
|
||||
@_refresh()
|
||||
@_refresh()
|
||||
|
||||
_reset: ->
|
||||
@$('ul.list').empty()
|
|
@ -43,13 +43,16 @@
|
|||
'collection': new Locomotive.Models.ContentAssetsCollection()
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
// Register commands
|
||||
ed.addCommand('locomotiveMedia', function() {
|
||||
view.options.on_select = function(asset) {
|
||||
insertImage(ed, asset);
|
||||
view.close();
|
||||
}
|
||||
view.render();
|
||||
|
||||
view.fetch_assets();
|
||||
});
|
||||
|
||||
// Register buttons
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
line-height: 15px;
|
||||
|
||||
@include background-image(linear-gradient(top, #f0f0f0, #f9f9f9 4px, #f9f9f9 4px, #ffffff 12px, #ffffff));
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
.ui-dialog-content {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
z-index: 1200;
|
||||
|
||||
text-align: left;
|
||||
|
||||
|
@ -124,14 +124,14 @@
|
|||
top: 8px;
|
||||
right: 10px;
|
||||
|
||||
z-index: 1003;
|
||||
z-index: 1203;
|
||||
|
||||
a, input[type=submit] {
|
||||
@include light-button;
|
||||
}
|
||||
|
||||
input[type=file] {
|
||||
z-index: 1003;
|
||||
z-index: 1203;
|
||||
}
|
||||
|
||||
} // .button-wrapper
|
||||
|
|
|
@ -421,8 +421,10 @@ form.formtastic {
|
|||
}
|
||||
|
||||
&.no-label {
|
||||
padding-top: 12px;
|
||||
|
||||
> textarea, .CodeMirror, .CodeMirror-scroll {
|
||||
margin-top: 12px;
|
||||
margin-top: 0px;
|
||||
width: 868px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ module Locomotive
|
|||
add :switch, :url => '#', :id => 'sites-picker-link'
|
||||
end
|
||||
|
||||
add :help, :url => '#', :class => 'tutorial', :id => 'help'
|
||||
add :help, :url => 'http://doc.locomotivecms.com/templates/basics', :class => 'tutorial', :id => 'help'
|
||||
add :logout, :url => destroy_locomotive_session_url, :confirm => t('locomotive.messages.confirm'), :method => :delete
|
||||
end
|
||||
|
||||
|
|
|
@ -7,15 +7,13 @@ module Locomotive
|
|||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
before_filter :require_account
|
||||
|
||||
before_filter :require_site
|
||||
|
||||
before_filter :set_locale
|
||||
|
||||
# before_filter :validate_site_membership
|
||||
before_filter :set_current_thread_variables
|
||||
|
||||
self.responder = Locomotive::ActionController::Responder # custom responder
|
||||
|
||||
|
@ -23,6 +21,11 @@ module Locomotive
|
|||
|
||||
protected
|
||||
|
||||
def set_current_thread_variables
|
||||
Thread.current[:account] = current_locomotive_account
|
||||
Thread.current[:site] = current_site
|
||||
end
|
||||
|
||||
def current_ability
|
||||
@current_ability ||= Ability.new(current_locomotive_account, current_site)
|
||||
end
|
||||
|
@ -40,4 +43,4 @@ module Locomotive
|
|||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||
module Api
|
||||
class ContentAssetsController < BaseController
|
||||
|
||||
load_and_authorize_resource :class => Locomotive::ContentAsset
|
||||
|
||||
def index
|
||||
@content_assets = current_site.content_assets
|
||||
respond_with(@content_assets)
|
||||
end
|
||||
|
||||
def show
|
||||
@content_asset = current_site.content_assets.find(params[:id])
|
||||
respond_with(@content_asset)
|
||||
end
|
||||
|
||||
def create
|
||||
@content_asset = current_site.content_assets.create(params[:content_asset])
|
||||
respond_with @content_asset, :location => main_app.locomotive_api_content_assets_url
|
||||
|
@ -18,6 +25,12 @@ module Locomotive
|
|||
respond_with @content_asset, :location => main_app.locomotive_api_content_assets_url
|
||||
end
|
||||
|
||||
def destroy
|
||||
@content_asset = current_site.content_assets.find(params[:id])
|
||||
@content_asset.destroy
|
||||
respond_with @content_asset
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||
module Api
|
||||
class ContentTypesController < BaseController
|
||||
|
||||
load_and_authorize_resource :class => Locomotive::ContentType
|
||||
|
||||
def index
|
||||
@content_types = current_site.content_types
|
||||
@content_types = current_site.content_types.order_by([[:name, :asc]])
|
||||
respond_with(@content_types)
|
||||
end
|
||||
|
||||
def show
|
||||
@content_type = current_site.content_types.find(params[:id])
|
||||
respond_with @content_type
|
||||
end
|
||||
|
||||
def create
|
||||
@content_type = current_site.content_types.create(params[:content_type])
|
||||
respond_with @content_type, :location => main_app.locomotive_api_content_types_url
|
||||
|
@ -18,6 +25,12 @@ module Locomotive
|
|||
respond_with @content_type, :location => main_app.locomotive_api_content_types_url
|
||||
end
|
||||
|
||||
def destroy
|
||||
@content_type = current_site.content_types.find(params[:id])
|
||||
@content_type.destroy
|
||||
respond_with @content_type
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,9 @@ module Locomotive
|
|||
class CurrentSiteController < BaseController
|
||||
|
||||
def show
|
||||
respond_with(current_site)
|
||||
@site = current_site
|
||||
authorize! :show, @site
|
||||
respond_with(@site)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
module Locomotive
|
||||
module Api
|
||||
class MembershipsController < BaseController
|
||||
|
||||
# It's an embedded document, so we'll just load manually
|
||||
before_filter :load_membership, :only => [ :show, :update, :destroy ]
|
||||
before_filter :load_memberships, :only => [ :index ]
|
||||
|
||||
authorize_resource :class => Locomotive::Membership
|
||||
|
||||
def index
|
||||
respond_with(@memberships)
|
||||
end
|
||||
|
||||
def show
|
||||
respond_with(@membership)
|
||||
end
|
||||
|
||||
def create
|
||||
build_params = params[:membership].merge({ :role => 'author' }) # force author by default
|
||||
@membership = current_site.memberships.create(build_params)
|
||||
respond_with(@membership)
|
||||
end
|
||||
|
||||
def update
|
||||
@membership.update_attributes(params[:membership])
|
||||
respond_with(@membership)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@membership.destroy
|
||||
respond_with(@membership)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def load_membership
|
||||
@membership ||= load_memberships.find(params[:id])
|
||||
end
|
||||
|
||||
def load_memberships
|
||||
@memberships ||= current_site.memberships
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||
module Api
|
||||
class PagesController < BaseController
|
||||
|
||||
load_and_authorize_resource :class => Locomotive::Page
|
||||
|
||||
def index
|
||||
@pages = current_site.pages.all
|
||||
@pages = current_site.pages.order_by([[:depth, :asc], [:position, :asc]])
|
||||
respond_with(@pages)
|
||||
end
|
||||
|
||||
def show
|
||||
@page = current_site.pages.find(params[:id])
|
||||
respond_with(@page)
|
||||
end
|
||||
|
||||
def create
|
||||
@page = current_site.pages.create(params[:page])
|
||||
respond_with @page, :location => main_app.locomotive_api_pages_url
|
||||
|
@ -18,6 +25,12 @@ module Locomotive
|
|||
respond_with @page, :location => main_app.locomotive_api_pages_url
|
||||
end
|
||||
|
||||
def destroy
|
||||
@page = current_site.pages.find(params[:id])
|
||||
@page.destroy
|
||||
respond_with @page
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
module Locomotive
|
||||
module Api
|
||||
class SitesController < BaseController
|
||||
|
||||
load_and_authorize_resource :class => Locomotive::Site
|
||||
|
||||
# FIXME: the auto-loaded site won't pass authorization for show, update, or destroy
|
||||
skip_load_and_authorize_resource :only => [ :show, :update, :destroy ]
|
||||
|
||||
def index
|
||||
@sites = Locomotive::Site.all
|
||||
respond_with(@sites)
|
||||
end
|
||||
|
||||
def show
|
||||
@site = Locomotive::Site.find(params[:id])
|
||||
authorize! :show, @site
|
||||
respond_with(@site)
|
||||
end
|
||||
|
||||
def create
|
||||
@site = Locomotive::Site.create(params[:site])
|
||||
respond_with(@site)
|
||||
end
|
||||
|
||||
def update
|
||||
@site = Locomotive::Site.find(params[:id])
|
||||
authorize! :update, @site
|
||||
@site.update_attributes(params[:site])
|
||||
respond_with @site
|
||||
end
|
||||
|
||||
def destroy
|
||||
@site = Locomotive::Site.find(params[:id])
|
||||
authorize! :destroy, @site
|
||||
@site.destroy
|
||||
respond_with @site
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||
module Api
|
||||
class SnippetsController < BaseController
|
||||
|
||||
load_and_authorize_resource :class => Locomotive::Snippet
|
||||
|
||||
def index
|
||||
@snippets = current_site.snippets.all
|
||||
@snippets = current_site.snippets.order_by([[:name, :asc]])
|
||||
respond_with(@snippets)
|
||||
end
|
||||
|
||||
def show
|
||||
@snippet = current_site.snippets.find(params[:id])
|
||||
respond_with @snippet
|
||||
end
|
||||
|
||||
def create
|
||||
@snippet = current_site.snippets.create(params[:snippet])
|
||||
respond_with @snippet, :location => main_app.locomotive_api_snippets_url
|
||||
|
@ -18,6 +25,12 @@ module Locomotive
|
|||
respond_with @snippet, :location => main_app.locomotive_api_snippets_url
|
||||
end
|
||||
|
||||
def destroy
|
||||
@snippet = current_site.snippets.find(params[:id])
|
||||
@snippet.destroy
|
||||
respond_with @snippet
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,11 +2,18 @@ module Locomotive
|
|||
module Api
|
||||
class ThemeAssetsController < BaseController
|
||||
|
||||
load_and_authorize_resource :class => Locomotive::ThemeAsset
|
||||
|
||||
def index
|
||||
@theme_assets = current_site.theme_assets.all
|
||||
respond_with(@theme_assets)
|
||||
end
|
||||
|
||||
def show
|
||||
@theme_asset = current_site.theme_assets.find(params[:id])
|
||||
respond_with @theme_asset
|
||||
end
|
||||
|
||||
def create
|
||||
@theme_asset = current_site.theme_assets.create(params[:theme_asset])
|
||||
respond_with @theme_asset, :location => main_app.locomotive_api_theme_assets_url
|
||||
|
@ -18,6 +25,12 @@ module Locomotive
|
|||
respond_with @theme_asset, :location => main_app.locomotive_api_theme_assets_url
|
||||
end
|
||||
|
||||
def destroy
|
||||
@theme_asset = current_site.theme_assets.find(params[:id])
|
||||
@theme_asset.destroy
|
||||
respond_with @theme_asset
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,8 +6,6 @@ module Locomotive
|
|||
|
||||
before_filter :sanitize_entry_params, :only => :create
|
||||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
self.responder = Locomotive::ActionController::PublicResponder # custom responder
|
||||
|
@ -17,7 +15,6 @@ module Locomotive
|
|||
def create
|
||||
@entry = @content_type.entries.create(params[:entry] || params[:content])
|
||||
flash[@content_type.slug.singularize] = @entry.to_presenter(:include_errors => true).as_json
|
||||
Rails.logger.debug @entry.to_presenter(:include_errors => true).as_json
|
||||
respond_with @entry, :location => self.callback_url
|
||||
end
|
||||
|
||||
|
@ -48,6 +45,13 @@ module Locomotive
|
|||
end
|
||||
end
|
||||
|
||||
def handle_unverified_request
|
||||
if Locomotive.config.csrf_protection
|
||||
reset_session
|
||||
redirect_to '/', :status => 302
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,6 +37,8 @@ module Locomotive
|
|||
can :touch, Site do |site|
|
||||
site == @site
|
||||
end
|
||||
|
||||
can :read, ContentType
|
||||
end
|
||||
|
||||
def setup_designer_permissions!
|
||||
|
|
|
@ -5,6 +5,20 @@ module Locomotive
|
|||
|
||||
devise *Locomotive.config.devise_modules
|
||||
|
||||
## devise fields (need to be declared since 2.x) ##
|
||||
field :remember_created_at, :type => Time
|
||||
field :email, :type => String, :null => false
|
||||
field :encrypted_password, :type => String, :null => false
|
||||
field :authentication_token, :type => String
|
||||
field :reset_password_token, :type => String
|
||||
field :reset_password_sent_at, :type => Time
|
||||
field :password_salt, :type => String
|
||||
field :sign_in_count, :type => Integer
|
||||
field :current_sign_in_at, :type => Time
|
||||
field :last_sign_in_at, :type => Time
|
||||
field :current_sign_in_ip, :type => String
|
||||
field :last_sign_in_ip, :type => String
|
||||
|
||||
## attributes ##
|
||||
field :name
|
||||
field :locale, :default => Locomotive.config.default_locale.to_s or 'en'
|
||||
|
|
|
@ -45,9 +45,11 @@ module Locomotive
|
|||
self.send((type || self.content_type).label_field_name.to_sym)
|
||||
end
|
||||
|
||||
value.respond_to?(:to_label) ? value.to_label : value
|
||||
value.respond_to?(:to_label) ? value.to_label : value.to_s
|
||||
end
|
||||
|
||||
alias :to_label :_label
|
||||
|
||||
def translated?
|
||||
if self.respond_to?(:"#{self._label_field_name}_translations")
|
||||
self.send(:"#{self._label_field_name}_translations").key?(::Mongoid::Fields::I18n.locale.to_s) #rescue false
|
||||
|
|
|
@ -84,6 +84,13 @@ module Locomotive
|
|||
self.class.class_name_to_content_type(class_name, self.site)
|
||||
end
|
||||
|
||||
def label_field_id=(value)
|
||||
# update the label_field_name if the label_field_id is changed
|
||||
new_label_field_name = self.entries_custom_fields.where(:_id => value).first.try(:name)
|
||||
self.label_field_name = new_label_field_name
|
||||
super(value)
|
||||
end
|
||||
|
||||
def label_field_name=(value)
|
||||
# mandatory if we allow the API to set the label field name without an id of the field
|
||||
@new_label_field_name = value unless value.blank?
|
||||
|
|
|
@ -27,7 +27,7 @@ module Locomotive
|
|||
|
||||
def set_label_field
|
||||
if @new_label_field_name.present?
|
||||
self.label_field_id = self.entries_custom_fields.detect { |f| f.name == @new_label_field_name.underscore }._id
|
||||
self.label_field_id = self.entries_custom_fields.detect { |f| f.name == @new_label_field_name.underscore }.try(:_id)
|
||||
end
|
||||
|
||||
# unknown label_field_name, get the first one instead
|
||||
|
|
|
@ -9,7 +9,7 @@ module Locomotive
|
|||
|
||||
## fields ##
|
||||
field :redirect, :type => Boolean, :default => false
|
||||
field :redirect_url, :type => String
|
||||
field :redirect_url, :type => String, :localize => true
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :redirect_url, :if => :redirect
|
||||
|
|
|
@ -26,7 +26,7 @@ module Locomotive
|
|||
|
||||
module ClassMethods
|
||||
|
||||
# Returns the pages tree from the site with the most minimal amount of queries.
|
||||
# Returns the tree of pages from the site with the most minimal amount of queries.
|
||||
# This method should only be used for read-only purpose since
|
||||
# the mongodb returns the minimal set of required attributes to build
|
||||
# the tree.
|
||||
|
|
|
@ -145,7 +145,7 @@ module Locomotive
|
|||
def escape_shortcut_urls(text)
|
||||
return if text.blank?
|
||||
|
||||
text.gsub(/[("'](\/(stylesheets|javascripts|images|media)\/(([^;.]+)\/)*([a-z_\-0-9]+)\.[a-z]{2,3})[)"']/) do |path|
|
||||
text.gsub(/[("'](\/(stylesheets|javascripts|images|media)\/(([^;.]+)\/)*([a-zA-Z_\-0-9]+)\.[a-z]{2,3})[)"']/) do |path|
|
||||
|
||||
sanitized_path = path.gsub(/[("')]/, '').gsub(/^\//, '')
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
= link_to t('locomotive.buttons.close'), '#', :id => 'close-link'
|
||||
|
||||
.button-wrapper.upload
|
||||
= form_tag theme_assets_url(:json), :class => 'quick-upload' do
|
||||
= file_field_tag 'theme_asset[source]', :multiple => 'multiple'
|
||||
= link_to t('locomotive.theme_assets.image_picker.upload'), theme_assets_url(:json), :class => 'new', :id => 'upload-link'
|
||||
= form_tag content_assets_url(:json), :class => 'quick-upload' do
|
||||
= file_field_tag 'content_asset[source]', :multiple => 'multiple'
|
||||
= link_to t('locomotive.content_assets.image_picker.upload'), content_assets_url(:json), :class => 'new', :id => 'upload-link'
|
||||
|
||||
%script{ :type => 'text/html', :id => 'content_asset' }
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
content_entry: #{@content_entry.to_json}
|
||||
content_entry: #{j @content_entry.to_json.html_safe}
|
||||
|
||||
= f.inputs :name => :attributes do
|
||||
- @content_type.ordered_entries_custom_fields.each_with_index do |field, index|
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
content_type: #{@content_type.persisted? ? @content_type.to_json : 'null'},
|
||||
inverse_of_list: #{options_for_content_type_inverse_of.to_json}
|
||||
content_type: #{j @content_type.persisted? ? @content_type.to_json.html_safe : 'null'},
|
||||
inverse_of_list: #{j options_for_content_type_inverse_of.to_json.html_safe}
|
||||
|
||||
= f.inputs :name => :information do
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
site: #{@site.to_json(:current_account => current_locomotive_account, :current_site => current_site)},
|
||||
site: #{j @site.to_json(:current_account => current_locomotive_account, :current_site => current_site).html_safe},
|
||||
errors: #{@site.errors.to_json}
|
||||
|
||||
= f.inputs :name => :information do
|
||||
|
|
|
@ -38,4 +38,4 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
, all_#{name}_entries: #{target_content_type.list_or_group_entries.to_json(:depth => 1)}
|
||||
, all_#{name}_entries: #{j target_content_type.list_or_group_entries.to_json(:depth => 1).html_safe}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
account: #{@account.to_json}
|
||||
account: #{j @account.to_json.html_safe}
|
||||
|
||||
- content_for :submenu do
|
||||
= render_cell 'locomotive/settings_menu', :show
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
page: #{@page.to_presenter.as_json_for_html_view.to_json}
|
||||
page: #{j @page.to_presenter.as_json_for_html_view.to_json.html_safe}
|
||||
|
||||
- if can?(:manage, @page)
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
window.content_locale = '#{::Mongoid::Fields::I18n.locale}';
|
||||
|
||||
Locomotive.mounted_on = '#{Locomotive.mounted_on}';
|
||||
Locomotive.current_site = new Locomotive.Models.Site(#{current_site.to_json});
|
||||
Locomotive.current_account = new Locomotive.Models.Account(#{current_locomotive_account.to_json});
|
||||
Locomotive.current_site = new Locomotive.Models.Site(#{j current_site.to_json.html_safe});
|
||||
Locomotive.current_account = new Locomotive.Models.Account(#{j current_locomotive_account.to_json.html_safe});
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
|
|
|
@ -11,14 +11,14 @@ xml.urlset "xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9" do
|
|||
if page.templatized?
|
||||
page.content_type.entries.visible.each do |c|
|
||||
xml.url do
|
||||
xml.loc page_url(page, { :content => c, :host => true })
|
||||
xml.loc page_url(page, { :content => c })
|
||||
xml.lastmod c.updated_at.to_date.to_s('%Y-%m-%d')
|
||||
xml.priority 0.9
|
||||
end
|
||||
end
|
||||
else
|
||||
xml.url do
|
||||
xml.loc page_url(page, { :host => true })
|
||||
xml.loc page_url(page)
|
||||
xml.lastmod page.updated_at.to_date.to_s('%Y-%m-%d')
|
||||
xml.priority 0.9
|
||||
end
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
.span-12.last
|
||||
%p
|
||||
= submit_tag button_label.is_a?(Symbol) ? t(".#{button_label}") : button_label, :disable_with => t('.disable_with'), :'data-sending-form-message' => t('locomotive.messages.sending_form')
|
||||
= submit_tag button_label.is_a?(Symbol) ? t(".#{button_label}") : button_label, :'data-disable-with' => t('.disable_with'), :'data-sending-form-message' => t('locomotive.messages.sending_form')
|
||||
|
||||
.clear
|
|
@ -19,8 +19,8 @@
|
|||
window.locale = '#{I18n.locale}';
|
||||
window.content_locale = '#{::Mongoid::Fields::I18n.locale}';
|
||||
|
||||
Locomotive.current_site = new Locomotive.Models.Site(#{current_site.to_presenter.as_json_for_html_view.to_json});
|
||||
Locomotive.current_account = new Locomotive.Models.Account(#{current_locomotive_account.to_json});
|
||||
Locomotive.current_site = new Locomotive.Models.Site(#{j current_site.to_presenter.as_json_for_html_view.to_json.html_safe});
|
||||
Locomotive.current_account = new Locomotive.Models.Account(#{j current_locomotive_account.to_json.html_safe});
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
snippet: #{@snippet.persisted? ? @snippet.to_presenter.as_json_for_html_view.to_json : 'null'}
|
||||
snippet: #{j @snippet.persisted? ? @snippet.to_presenter.as_json_for_html_view.to_json.html_safe : 'null'}
|
||||
|
||||
= f.inputs :name => :information do
|
||||
= f.input :name, :wrapper_html => { :class => 'highlighted' }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
theme_asset: #{@theme_asset.persisted? ? @theme_asset.to_json : 'null'}
|
||||
theme_asset: #{j @theme_asset.persisted? ? @theme_asset.to_json.html_safe : 'null'}
|
||||
|
||||
= f.hidden_field :performing_plain_text
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
- content_for :backbone_view_data do
|
||||
:plain
|
||||
snippets: #{can?(:manage, Locomotive::Snippet) ? @snippets.map { |snippet| snippet.to_presenter.as_json_for_html_view }.to_json : 'null'},
|
||||
images: #{theme_assets_to_json(@assets[:images])},
|
||||
media: #{theme_assets_to_json(@assets[:media])},
|
||||
js_and_css_assets: #{can?(:manage, Locomotive::ThemeAsset) ? theme_assets_to_json(@js_and_css_assets) : 'null'},
|
||||
fonts: #{can?(:manage, Locomotive::ThemeAsset) ? theme_assets_to_json(@assets[:fonts]) : 'null'}
|
||||
snippets: #{j can?(:manage, Locomotive::Snippet) ? @snippets.map { |snippet| snippet.to_presenter.as_json_for_html_view }.to_json.html_safe : 'null'},
|
||||
images: #{j theme_assets_to_json(@assets[:images]).html_safe},
|
||||
media: #{j theme_assets_to_json(@assets[:media]).html_safe},
|
||||
js_and_css_assets: #{j can?(:manage, Locomotive::ThemeAsset) ? theme_assets_to_json(@js_and_css_assets).html_safe : 'null'},
|
||||
fonts: #{j can?(:manage, Locomotive::ThemeAsset) ? theme_assets_to_json(@assets[:fonts]).html_safe : 'null'}
|
||||
|
||||
- content_for :submenu do
|
||||
= render_cell 'locomotive/settings_menu', :show
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
de:
|
||||
locomotive:
|
||||
errors:
|
||||
"500":
|
||||
title: Anwendungs-Fehler
|
||||
notice: "Entschuldigung, irgendetwas ist hier schief gelaufen."
|
||||
link: "→ Zurück zur Anwendung"
|
||||
"404":
|
||||
title: Seite nicht gefunden
|
||||
notice: "Die angefragte Seite existiert nicht."
|
||||
link: "→ Zurück zur Anwendung"
|
||||
|
||||
locales:
|
||||
en: Englisch
|
||||
de: Deutsch
|
||||
fr: Französisch
|
||||
pt-BR: "Bras. Portugiesisch"
|
||||
it: Italienisch
|
||||
nl: Niederländisch
|
||||
nb: Norwegisch
|
||||
es: Spanisch
|
||||
ru: Russisch
|
||||
|
||||
buttons:
|
||||
login: Einloggen
|
||||
send_password: Senden
|
||||
|
@ -9,19 +30,9 @@ de:
|
|||
delete: "Löschen"
|
||||
close: "Schließen"
|
||||
|
||||
locales:
|
||||
en: Englisch
|
||||
de: Deutsch
|
||||
fr: Französisch
|
||||
pt-BR: "Bras. Portugiesisch"
|
||||
it: Italienisch
|
||||
nl: Niederländisch
|
||||
"no": Norwegisch
|
||||
es: Spanisch
|
||||
ru: Russisch
|
||||
|
||||
messages:
|
||||
confirm: Sind Sie sicher ?
|
||||
sending_form: "Formular wird gesendet"
|
||||
|
||||
shared:
|
||||
header:
|
||||
|
@ -39,8 +50,10 @@ de:
|
|||
account: Mein Zugang
|
||||
site: Webseite
|
||||
theme_assets: Dateien
|
||||
list:
|
||||
untranslated: "Nicht übersetzt"
|
||||
form:
|
||||
change_file: Ändern
|
||||
change_file: ändern
|
||||
delete_file: Löschen
|
||||
cancel: Abbrechen
|
||||
form_actions:
|
||||
|
@ -48,24 +61,14 @@ de:
|
|||
create: Neu
|
||||
update: Speichern
|
||||
send: Senden
|
||||
disable_with: "locomotive.disable_with.form_actions"
|
||||
disable_with: "Transfer..."
|
||||
footer:
|
||||
who_is_behind: "Dienst entwickelt von %{development} und entworfen von <a href=\"http://www.sachagreif.com\">Sacha Greif</a> — <small>version</small> %{version}"
|
||||
|
||||
errors:
|
||||
"500":
|
||||
title: Anwendungs-Fehler
|
||||
notice: "Entschuldigung, irgendetwas ist hier schief gelaufen."
|
||||
link: "→ Zurück zur Anwendung"
|
||||
"404":
|
||||
title: Seite nicht gefunden
|
||||
notice: "Die angefragte Seite existiert nicht."
|
||||
link: "→ Zurück zur Anwendung"
|
||||
who_is_behind: "LocomitveCMS - entwickelt von %{development} und entworfen von <a href=\"http://www.sachagreif.com\">Sacha Greif</a> — <small>version</small> %{version}"
|
||||
|
||||
notifications:
|
||||
new_content_entry:
|
||||
subject: "[%{type}] neu"
|
||||
title: "Hi %{name}, nur damit Sie Bescheid wissen! Am %{date} wurde folgende neue Instanz erstellt."
|
||||
title: "Hi %{name}, nur damit Sie Bescheid wissen, am %{date} wurde eine neue Instanz erstellt."
|
||||
type: "Model: %{type}"
|
||||
|
||||
sites_picker:
|
||||
|
@ -157,16 +160,16 @@ de:
|
|||
|
||||
sites:
|
||||
new:
|
||||
title: Neuer Webseite
|
||||
help: "Fülle das folgende Formular aus, um einen neuen Webseiteen zu erstellen."
|
||||
title: Neue Webseite
|
||||
help: "Füllen Sie das folgende Formular aus, um eine neue Webseite zu erstellen."
|
||||
domains:
|
||||
empty: "Bisher sind keine Domains/Hostnamen an diese Seite gebunden. Wenn Sie unten Domains/Hostnamen angeben, achten Sie bitte darauf <b>Ihren DNS Server zu prüfen/aktualisieren.</b>"
|
||||
|
||||
current_site:
|
||||
edit:
|
||||
new_membership: Account hinzufügen
|
||||
help: "Der Name des Webseiteen kann durch einen Klick auf den Namen bearbeitet werden."
|
||||
ask_for_name: "Bitte geben Sie den neuen Namen der Webseite an"
|
||||
help: "Der Name der Webseiten kann durch einen Klick auf den Namen bearbeitet werden."
|
||||
ask_for_name: "Bitte geben Sie den neuen Namen der Webseite ein"
|
||||
|
||||
memberships:
|
||||
roles:
|
||||
|
@ -195,10 +198,11 @@ de:
|
|||
new: neue Datei
|
||||
snippets: Snippets
|
||||
css_and_js: Style und Javascript
|
||||
fonts: Fonts
|
||||
images: Bilder
|
||||
media: Medien
|
||||
fonts: Fonts
|
||||
no_items: "Momentan gibt es keine Dateien. Klicken Sie einfach <a href='%{url}'>hier</a>, um die erste Datei zu erstellen."
|
||||
quick_upload: Schneller Upload
|
||||
asset:
|
||||
updated_at: Aktualisiert am
|
||||
new:
|
||||
|
@ -291,13 +295,15 @@ de:
|
|||
explanations: "Es ist fast geschafft. Bitte geben Sie Ihrer ersten Webseite einen Namen und wählen Sie eine Sprache aus."
|
||||
default_site_locale: Sprachauswahl
|
||||
default_site_locales_hints: Sie können später weitere Sprachen im Einstellungsdialog vornehmen.
|
||||
next: Webseite erstellen
|
||||
next: Webseite erstellen
|
||||
back_to_default_template: "Klicken Sie <a href='#'>hier</a> um die Standardeinstellungen wieder herzustellen"
|
||||
|
||||
|
||||
public:
|
||||
pages:
|
||||
show_toolbar:
|
||||
statuses:
|
||||
loading: "Lade...."
|
||||
loading: "Laden..."
|
||||
disabled: "Inline Editor deaktiviert"
|
||||
labels:
|
||||
save_changes: "Änderungen speichern: "
|
||||
|
|
|
@ -16,7 +16,7 @@ en:
|
|||
pt-BR: "Brazilian Portuguese"
|
||||
it: Italian
|
||||
nl: Dutch
|
||||
"no": Norwegian
|
||||
nb: Norwegian
|
||||
es: Spanish
|
||||
ru: Russian
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ es:
|
|||
|
||||
messages:
|
||||
confirm: Por favor confirme
|
||||
sending_form: "locomotive.messages.sending_form"
|
||||
|
||||
shared:
|
||||
header:
|
||||
|
@ -165,7 +166,7 @@ es:
|
|||
pt-BR: "Portugués (Brasil)"
|
||||
it: Italiano
|
||||
nl: holandés
|
||||
"no": Noruego
|
||||
nb: Noruego
|
||||
es: Español
|
||||
ru: Ruso
|
||||
ask_for_name: "Por favor escriba su nuevo nombre"
|
||||
|
|
|
@ -17,7 +17,7 @@ fr:
|
|||
pt-BR: "Portugais"
|
||||
it: "Italien"
|
||||
nl: "Hollandais"
|
||||
"no": "Norvégien"
|
||||
nb: "Norvégien"
|
||||
es: Espagnol
|
||||
ru: Russe
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ it:
|
|||
|
||||
messages:
|
||||
confirm: Sicuro?
|
||||
sending_form: "locomotive.messages.sending_form"
|
||||
|
||||
shared:
|
||||
header:
|
||||
|
@ -165,7 +166,7 @@ it:
|
|||
pt-BR: "Portoghese Brasiliano"
|
||||
it: Italiano
|
||||
nl: Olandese
|
||||
"no": Norvegese
|
||||
nb: Norvegese
|
||||
es: Spagnolo
|
||||
ru: Russo
|
||||
ask_for_name: "Prego, digita il tuo nome"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"no":
|
||||
nb:
|
||||
locomotive:
|
||||
buttons:
|
||||
login: Logg inn
|
||||
|
@ -6,10 +6,23 @@
|
|||
change_password: Endre
|
||||
new_item: "+ ny"
|
||||
switch_to_site: Vis
|
||||
delete: "Slett"
|
||||
delete: Slett
|
||||
close: Lukk
|
||||
|
||||
locales:
|
||||
en: Engelsk
|
||||
de: Tysk
|
||||
fr: Fransk
|
||||
pt-BR: "Brazilian Portuguese"
|
||||
it: Italiensk
|
||||
nl: Nederlandsk
|
||||
nb: Norsk
|
||||
es: Spansk
|
||||
ru: Russisk
|
||||
|
||||
messages:
|
||||
confirm: Er du sikker?
|
||||
sending_form: Skjemaet blir sendt
|
||||
|
||||
shared:
|
||||
header:
|
||||
|
@ -27,14 +40,20 @@
|
|||
account: Min konto
|
||||
site: Siden
|
||||
theme_assets: Temafiler
|
||||
footer:
|
||||
who_is_behind: "Tjenesten utviklet av %{development} og designet av <a href=\"http://www.sachagreif.com\">Sacha Greif</a>"
|
||||
form:
|
||||
change_file: Endre
|
||||
delete_file: Slett
|
||||
cancel: Avbryt
|
||||
form_actions:
|
||||
back: Tilbake uten å lagre
|
||||
create: Opprett
|
||||
update: Lagre
|
||||
send: Send
|
||||
disable_with: "locomotive.disable_with.form_actions"
|
||||
disable_with: "Vent litt.."
|
||||
list:
|
||||
untranslated: ikke oversatt
|
||||
footer:
|
||||
who_is_behind: "LocomotiveCMS er utviklet av %{development} og designet av <a href=\"http://www.sachagreif.com\">Sacha Greif</a> — <small>versjon</small> %{version}"
|
||||
|
||||
errors:
|
||||
"500":
|
||||
|
@ -66,9 +85,16 @@
|
|||
delete_file: Slett fil
|
||||
has_many:
|
||||
empty: Tom
|
||||
index:
|
||||
is_required: er nødvendig
|
||||
new_entry: + Legg til ny
|
||||
many_to_many:
|
||||
empty: Listen er tom. Legg til ny fra listen nedenfor.
|
||||
|
||||
form:
|
||||
required: Nødvendig
|
||||
optional: Valgfri
|
||||
default_label: Feltnavn
|
||||
select_options:
|
||||
ask_name: "Skriv inn etiketten for dette valget"
|
||||
|
||||
sessions:
|
||||
new:
|
||||
|
@ -105,7 +131,9 @@
|
|||
help: "Tittelen til siden kan oppdateres ved å klikke på den. For å lagre endringene, klikk på \"Lagre\" -knappen."
|
||||
ask_for_title: "Endre tittelen"
|
||||
form:
|
||||
delete_file: Slett fil
|
||||
change_file: endre
|
||||
delete_file: slett fil
|
||||
cancel: avbryt
|
||||
default_block: Standard
|
||||
cache_strategy:
|
||||
none: Ingen
|
||||
|
@ -134,14 +162,14 @@
|
|||
new:
|
||||
title: Ny nettside
|
||||
help: "Fyll ut skjemaet nedenfor for å opprette en ny nettside."
|
||||
domains:
|
||||
empty: "Det er ingen domener tilknyttet denne siden ennå. Legg til domenene dine nedenfor. <b>Ikke glem å oppdatere DNS-pekerene.</b>"
|
||||
|
||||
current_site:
|
||||
edit:
|
||||
export: eksporter
|
||||
import: importer
|
||||
new_membership: nytt medlemskap
|
||||
new_membership: legg til konto
|
||||
help: "Navnet på siden kan oppdateres ved å trykke på det. For å lagre endringen, trykk på \"Lagre\" -knappen."
|
||||
ask_for_name: "Rediger navnet"
|
||||
ask_for_name: "Skriv inn det nye navnet"
|
||||
|
||||
memberships:
|
||||
roles:
|
||||
|
@ -161,21 +189,13 @@
|
|||
edit:
|
||||
help: "Navnet ditt kan endres ved å trykke på det. For å lagre endringen, trykk på \"Lagre\" -knappen."
|
||||
new_site: ny nettside
|
||||
en: Engelsk
|
||||
de: Tysk
|
||||
fr: Fransk
|
||||
pt-BR: "Brasiliansk Portugisisk"
|
||||
it: Italiensk
|
||||
nl: Nederlandsk
|
||||
"no": Norsk
|
||||
es: Spansk
|
||||
ru: Russisk
|
||||
ask_for_name: "Rediger navnet ditt"
|
||||
|
||||
theme_assets:
|
||||
index:
|
||||
title: Temafiler
|
||||
help: "I denne seksjonen kan du håndtere alle layout-relaterte filer. Hvis du trenger et bildegalleri så opprett en ny innholdstype i stedet.<br/><b>Advarsel:</b> hvis det er enkelte filer du ikke ser så kan dette skyldes manglende rettigheter."
|
||||
quick_upload: Hurtigopplasting
|
||||
new: ny fil
|
||||
snippets: HTML-snutter
|
||||
css_and_js: Stilark og javascript
|
||||
|
@ -198,29 +218,29 @@
|
|||
picker_link: Sett inn en fil i koden
|
||||
choose_file: Velg fil
|
||||
choose_plain_text: Velg klartekst
|
||||
images:
|
||||
title: Bilder
|
||||
no_items: "Det er ingen filer her ennå."
|
||||
image_picker:
|
||||
title: "Sett inn bilde"
|
||||
no_items: "Det finnes ingen bilder foreløpig."
|
||||
upload: "Last opp bilder"
|
||||
|
||||
assets:
|
||||
new:
|
||||
title: New asset
|
||||
help: "Fill in the form below to create your asset."
|
||||
edit:
|
||||
title: Edit asset
|
||||
help: "Fill in the form below to update your asset."
|
||||
content_assets:
|
||||
picker:
|
||||
title: "Sett inn media"
|
||||
no_items: "Det finnes ingen media foreløpig."
|
||||
upload: "Last opp media"
|
||||
|
||||
content_types:
|
||||
index:
|
||||
new: Ny modell
|
||||
edit: Rediger modell
|
||||
new:
|
||||
title: Ny modell
|
||||
help: "Lag din egen datamodell (Prosjekter, Ansatte, ...etc). Modellen må ha minst ett felt. Det første feltet vil være obligatorisk for elementer som opprettes av denne innholdstypen."
|
||||
edit:
|
||||
title: Rediger modellen
|
||||
title: Redigerer modell
|
||||
help: "Modellen må ha minst ett felt. Det første feltet vil være obligatorisk for elementer som opprettes av denne innholdstypen."
|
||||
show_items: vis elementer
|
||||
new_item: nytt element
|
||||
show_entries: vis elementer
|
||||
new_entry: nytt element
|
||||
form:
|
||||
order_by:
|
||||
created_at: 'Etter dato opprettet'
|
||||
|
@ -241,7 +261,7 @@
|
|||
latest_entries: "Siste elementer"
|
||||
updated_at: "Sist oppdatert"
|
||||
list:
|
||||
no_entries: "Det har ikke blitt opprettet noen elementer her ennå. Klikk <a href=\"%{url}\">her</a> for å opprette det første."
|
||||
no_entries: "Det finnes ingen elementer her ennå. Klikk <a href=\"%{url}\">her</a> for å opprette det første."
|
||||
new:
|
||||
title: '%{type} — nytt element'
|
||||
edit:
|
||||
|
@ -258,25 +278,6 @@
|
|||
title: Cross-domain authentication
|
||||
notice: Du blir sendt videre til nettsiden i løpet av noen få sekunder.
|
||||
|
||||
import:
|
||||
new:
|
||||
title: Importer en mal for siden
|
||||
help: "Be careful when you upload a new template for your existing website, your current data could be modified or even removed."
|
||||
help: "Vær forsiktig hvis du laster opp en ny mal til en ekisterende side. Dataene dine kan bli slettet eller endret."
|
||||
show:
|
||||
title: Import pågår
|
||||
help: "Your site is being updated from the theme zip file you have just uploaded. It lasts a couple of seconds."
|
||||
help: "Siden blir oppdatert fra temafilen som ble lastet opp. Dette vil ta noen sekunder."
|
||||
steps:
|
||||
site: Sideinformasjon
|
||||
content_types: Tilpassede innholdstyper
|
||||
assets: Temafiler
|
||||
snippets: HTML-snutter
|
||||
pages: Sider
|
||||
messages:
|
||||
success: "Importen var velykket og siden har blitt oppdatert."
|
||||
failure: "Importen kunne ikke gjennomføres."
|
||||
|
||||
installation:
|
||||
common:
|
||||
title: Locomotive førstegangsoppsett
|
||||
|
@ -292,5 +293,21 @@
|
|||
step_2:
|
||||
title: "Steg 2/2 — Lag din første nettside"
|
||||
explanations: "Hvis du allerede har lastet opp standardmalen (se instruksjoner), så kan du bruke denne med en gang. Du kan også laste opp en sidemal som en zip-fil (gratis maler finnes <a href=\"http://www.locomotivecms.com/support/themes\">her</a>)."
|
||||
back_to_default_template: "Trykk <a href='#'>her</a> for å velge standardmalen i stedet"
|
||||
default_site_locale: Språk
|
||||
default_site_locales_hints: Du kan legge til flere språk under Innstilinger senere
|
||||
next: Opprett side
|
||||
|
||||
public:
|
||||
pages:
|
||||
show_toolbar:
|
||||
statuses:
|
||||
loading: "Vent litt...."
|
||||
disabled: "Inline Editor disabled"
|
||||
labels:
|
||||
save_changes: "Lagre endringer: "
|
||||
editing_mode: "Redigeringsmodus: "
|
||||
lang: "Språk: "
|
||||
buttons:
|
||||
back: Tilbake til admin-siden
|
||||
confirm: Bekreft
|
||||
cancel: Avbryt
|
|
@ -9,6 +9,7 @@ nl:
|
|||
|
||||
messages:
|
||||
confirm: Weet u het zeker ?
|
||||
sending_form: "locomotive.messages.sending_form"
|
||||
|
||||
shared:
|
||||
header:
|
||||
|
@ -153,7 +154,7 @@ nl:
|
|||
pt-BR: "Braziliaans Portugees"
|
||||
it: Italiaans
|
||||
nl: Nederlands
|
||||
"no": Noors
|
||||
nb: Noors
|
||||
ru: Russisch
|
||||
ask_for_name: "Voer uw nieuwe naam in"
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ pt-BR:
|
|||
|
||||
messages:
|
||||
confirm: Você tem certeza ?
|
||||
sending_form: "locomotive.messages.sending_form"
|
||||
|
||||
shared:
|
||||
header:
|
||||
|
@ -151,7 +152,7 @@ pt-BR:
|
|||
pt-BR: "Português do Brasil"
|
||||
it: Italiano
|
||||
nl: Holandês
|
||||
"no": Norueguês
|
||||
nb: Norueguês
|
||||
es: Espanhol
|
||||
ru: Russo
|
||||
ask_for_name: "Por favor preencha o novo nome"
|
||||
|
|
|
@ -16,7 +16,7 @@ ru:
|
|||
pt-BR: "Браз. - Португальский"
|
||||
it: Итальянский
|
||||
nl: Голландский
|
||||
"no": Норвежский
|
||||
nb: Норвежский
|
||||
es: Испанский
|
||||
ru: Русский
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"no":
|
||||
nb:
|
||||
carrierwave:
|
||||
errors:
|
||||
integrity: 'er ikke en tillatt filtype.'
|
|
@ -34,10 +34,13 @@ de:
|
|||
array_too_short: "ist zu kurz (minimale Element-Zahl ist %{count})"
|
||||
liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax ('%{error}')"
|
||||
invalid_theme_file: "darf nicht leer sein oder ist keine zip-Datei"
|
||||
security: "stellt ein Sicherheitproblem dar"
|
||||
site:
|
||||
default_locale_removed: Die vorige Standard-Spracheinstellung kann noch nicht gelöscht werden
|
||||
page:
|
||||
liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax ('%{error}'/'%{fullpath}')"
|
||||
liquid_extend: "Die Seite '%{fullpath}' verwendet eine Vorlage, die gar nicht existiert"
|
||||
|
||||
liquid_translation: "Die Seite '%{fullpath}' erweitert eine Vorlage die noch nicht übersetzt wurde"
|
||||
|
||||
attributes:
|
||||
defaults:
|
||||
|
@ -52,17 +55,24 @@ de:
|
|||
body: "{% extends 'parent' %}"
|
||||
|
||||
mongoid:
|
||||
errors:
|
||||
messages:
|
||||
blank_on_locale: "darf nicht leer sein"
|
||||
|
||||
attributes:
|
||||
page:
|
||||
title: Titel
|
||||
parent: Parent
|
||||
parent: Elternprozess
|
||||
pared_id: Elternprozess
|
||||
slug: Slug
|
||||
listed: Im Menü
|
||||
templatized: Templatized
|
||||
published: Veröffentlicht
|
||||
listed: Im Menü
|
||||
redirect: Umleitung
|
||||
redirect_url: Umleitungs-URL
|
||||
cache_strategy: Cache
|
||||
response_type: Antworttyp
|
||||
seo_title: SEO-Titel
|
||||
content_type:
|
||||
name: Name
|
||||
description: Beschreibung
|
||||
|
|
|
@ -3,6 +3,11 @@ en:
|
|||
formats:
|
||||
default: "%m/%d/%Y"
|
||||
|
||||
mongoid:
|
||||
errors:
|
||||
messages:
|
||||
blank_on_locale: "can't be blank"
|
||||
|
||||
errors:
|
||||
messages:
|
||||
domain_taken: "%{value} is already taken"
|
||||
|
|
|
@ -53,6 +53,10 @@ fr:
|
|||
body: "{% extends 'parent' %}"
|
||||
|
||||
mongoid:
|
||||
errors:
|
||||
messages:
|
||||
blank_on_locale: "doit être rempli(e)"
|
||||
|
||||
attributes:
|
||||
locomotive/page:
|
||||
title: Titre
|
||||
|
|
|
@ -1,4 +1,46 @@
|
|||
"no":
|
||||
nb:
|
||||
date:
|
||||
formats:
|
||||
default: "%d.%m.%Y"
|
||||
|
||||
mongoid:
|
||||
errors:
|
||||
messages:
|
||||
blank_on_locale: "må fylles ut"
|
||||
|
||||
errors:
|
||||
messages:
|
||||
domain_taken: "%{value} er alerede tatt"
|
||||
invalid_domain: "%{value} er ugyldig"
|
||||
needs_admin_account: "Det må være minst en admin-konto"
|
||||
protected_page: "Du kan ikke fjerne index eller 404 sidene"
|
||||
extname_changed: "Den nye filen har ikke det opprinnelige filetternavnet"
|
||||
array_too_short: "er for liten (minimum elementnummer er %{count})"
|
||||
invalid_theme_file: "må være en zip-fil"
|
||||
site:
|
||||
default_locale_removed: Forrige standardspråk kan ikke fjernes før nytt er valgt.
|
||||
page:
|
||||
liquid_syntax: "Liquid Syntax error ('%{error}' on '%{fullpath}')"
|
||||
liquid_extend: "The page '%{fullpath}' extends a template which does not exist"
|
||||
liquid_translation: "The page '%{fullpath}' extends a template which is not translated"
|
||||
too_few_custom_fields: "At least, one custom field is required"
|
||||
security: "presents a security problem"
|
||||
|
||||
attributes:
|
||||
defaults:
|
||||
pages:
|
||||
index:
|
||||
title: "Startside"
|
||||
body: "Startsidens innholds"
|
||||
"404":
|
||||
title: "Siden finnes ikke"
|
||||
body: "Sidens innhold"
|
||||
other:
|
||||
body: "{% extends 'parent' %}"
|
||||
|
||||
pagination:
|
||||
previous: "« Previous"
|
||||
next: "Next »"
|
||||
support:
|
||||
array:
|
||||
words_connector: ", "
|
|
@ -1,4 +1,4 @@
|
|||
"no":
|
||||
nb:
|
||||
errors:
|
||||
messages:
|
||||
not_found: "finnes ikke"
|
||||
|
@ -7,7 +7,7 @@
|
|||
|
||||
devise:
|
||||
failure:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
unauthenticated: 'Du må logge inn eller registrere deg før du kan fortsette.'
|
||||
unconfirmed: 'Kontoen må aktiveres før du kan fortsette.'
|
||||
locked: 'Brukerkontoen er sperret.'
|
||||
|
@ -17,34 +17,34 @@
|
|||
timeout: 'Innloggingen har utløpt. Logg inn på nytt for å fortsette.'
|
||||
inactive: 'Kontoen din er ikke aktivert ennå.'
|
||||
sessions:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
signed_in: 'Du er nå logget inn.'
|
||||
signed_out: 'Du har blitt logget ut.'
|
||||
passwords:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
send_instructions: 'Du vil motta en epost med instruksjoner for hvordan du kan tilbakestille passordet i løpet av kort tid.'
|
||||
updated: 'Passordendringen var vellykket. Du er nå logget inn.'
|
||||
confirmations:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
send_instructions: 'Du vil motta en epost med instrusksjoner for hvordan brukerkontoen aktiveres i løpet av kort tid.'
|
||||
confirmed: 'Aktiveringen av brukerkontoen var vellykket. Du er nå logget inn.'
|
||||
registrations:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
signed_up: 'Registreringen var vellykket.'
|
||||
updated: 'Oppdateringen av kontoen var vellykket'
|
||||
destroyed: 'Kontoen din har blitt kansellert. Vi håper å se deg igjen en annen gang.'
|
||||
unlocks:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
send_instructions: 'Du vil motta en epost med instruksjoner for hvordan du kan åpne kontoen i løpet av kort tid.'
|
||||
unlocked: 'Kontoen har blitt åpnet og du er nå logget inn.'
|
||||
mailer:
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
confirmation_instructions: 'Bekreftelsesinstrukser'
|
||||
reset_password_instructions: 'Instrukser for tilbakestilling av passord'
|
||||
unlock_instructions: 'Instrukser for åpning'
|
||||
|
||||
|
||||
locomotive:
|
||||
locomotive_account:
|
||||
mailer:
|
||||
common:
|
||||
hello: Hallo
|
|
@ -1,4 +1,4 @@
|
|||
"no":
|
||||
nb:
|
||||
flash:
|
||||
locomotive:
|
||||
pages:
|
|
@ -1,4 +1,4 @@
|
|||
"no":
|
||||
nb:
|
||||
formtastic:
|
||||
titles:
|
||||
information: Generell informasjon
|
||||
|
@ -33,37 +33,40 @@
|
|||
custom_fields:
|
||||
field:
|
||||
name: Alias
|
||||
import:
|
||||
new:
|
||||
source: Fil
|
||||
samples: Kopier testdata
|
||||
reset: Reset side
|
||||
default_site_template: "Bruk standardmalen. Klikk <a href='#'>her</a> for å laste opp en mal fra en zip-fil i stedet."
|
||||
content_type:
|
||||
item_template: Elementmal
|
||||
api_accounts: Varslede kontoer
|
||||
raw_item_template: Elementmal
|
||||
public_submission_enabled: Kan opprettes utenfra
|
||||
public_submission_accounts: Kontoer som varsles
|
||||
"custom_fields/field":
|
||||
select_options: "Valg"
|
||||
content_entry:
|
||||
_slug: Permalink
|
||||
account:
|
||||
edit:
|
||||
locale: Språk
|
||||
password: Nytt passord
|
||||
password_confirmation: Bekreft nytt passord
|
||||
page:
|
||||
seo_title: Tittel
|
||||
target_klass_name: Modell
|
||||
site:
|
||||
locales: Språk
|
||||
|
||||
hints:
|
||||
page:
|
||||
handle: "En unik ID for å hente siden fra en ekstern controller"
|
||||
published: "Kun autoriserte kontoer kan se ikke-publiserte sider"
|
||||
cache_strategy: "Buffre siden for å bedre ytelsen. \"Enkel\" er et bra kompromiss."
|
||||
templatized: "Bruk denne siden som mal for en modell."
|
||||
listed: "Styr om siden skal vises i de genererte menyene."
|
||||
content_type_id: "Innholdstypen denne siden skal være mal for."
|
||||
target_klass_name: "Innholdstypen denne siden skal være mal for."
|
||||
seo_title: "Definer en egen tittel for siden. Denne blir benyttet av nettleseren. Hvis denne står tom blir standardverdien fra sideinnstillingene benyttet."
|
||||
meta_keywords: "Overstyr søkemotor-metadata for denne siden. Separer med komma."
|
||||
meta_description: "Overstyr søkemotorbeskrivelsen for denne siden."
|
||||
snippet:
|
||||
slug: "Denne brukes for å inkludere HTML-snutten i en side."
|
||||
site:
|
||||
locales: "Dra et flagg til første posisjon for å sette som standard."
|
||||
seo_title: "Definer en global verdi her som brukes som verdi for titteltaggen i sidens head-seksjon."
|
||||
meta_keywords: "Meta-nøkkelord blir brukt i head-seksjonen og leses av søkemotorer. Separeres med komma."
|
||||
meta_description: "Meta-beskrivelse brukes i head-seksjonen og leses av søkemotorer."
|
||||
|
@ -79,10 +82,6 @@
|
|||
source: "Filen er tilgjengelig her: %{url}"
|
||||
update:
|
||||
source: "Filen er tilgjengelig her: %{url}"
|
||||
custom_fields:
|
||||
field:
|
||||
name: "Verdi tilgjengelig i liquid-maler"
|
||||
hint: "Tekst som vises i skjemaet rett under feltet"
|
||||
content_entry:
|
||||
_slug: "Verdien brukes til å generere en url for en side som fungerer som en mal for denne innholdstypen (f.eks: \"template_page/{{ your_object._permalink }})\"."
|
||||
seo_title: "Verdien benyttes til å erstatte sidetittelen for malen knyttet til modellen. Leses av søkemotorer."
|
||||
|
@ -93,7 +92,12 @@
|
|||
samples: "Vil gjøre at importen kopierer innhold og assets"
|
||||
reset: "Vil gjøre at alle data slettes for den nye siden importeres."
|
||||
content_type:
|
||||
item_template: "Du kan justere teksten som vises for hvert element i listen. Bruk liquid, f.eks: {{ entry.name }}"
|
||||
api_enabled: "Brukes for å la sidebrukere opprette ny elementer (f.eks: meldinger i et kontaktskjema)"
|
||||
api_accounts: "En varslingsepost vil bli sendt til alle kontoene ovenfor når et nytt element blir opprettet."
|
||||
name: "Vi foreslår at du bruker flertals form (E.G: Personer)"
|
||||
slug: "It will be used as the name of the collection in the liquid templates. Ex: <span class='code'>{{ contents.my_projects }}</span>"
|
||||
raw_item_template: "You can customize the text displayed for each item in the list. Simply use Liquid. Ex: <span class='code'>{{ entry.name }})</span>"
|
||||
public_submission_enabled: "It is used to let people from outside to create new entries (example: messages in a contact form)"
|
||||
public_submission_accounts: "If the public submission option is enabled and for each entry created, sends a notification email to the accounts listed above."
|
||||
"custom_fields/field":
|
||||
name: "Name of the property for liquid templates. Ex: <span class='code'>{{ your_object.<name_of_your_field> }}</span>"
|
||||
hint: "Text displayed in the model form just below the field"
|
||||
|
|
@ -6,7 +6,9 @@ Locomotive::Engine.routes.draw do
|
|||
:path => '',
|
||||
:path_prefix => nil,
|
||||
:failure_app => 'Locomotive::Devise::FailureApp',
|
||||
:controllers => { :sessions => 'locomotive/sessions', :passwords => 'locomotive/passwords' } do
|
||||
:controllers => { :sessions => 'locomotive/sessions', :passwords => 'locomotive/passwords' }
|
||||
|
||||
devise_scope :locomotive_account do
|
||||
match '/' => 'sessions#new'
|
||||
delete 'signout' => 'sessions#destroy', :as => :destroy_locomotive_session
|
||||
end
|
||||
|
@ -68,6 +70,10 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :content_entries, :path => 'content_types/:slug/entries'
|
||||
|
||||
resources :sites
|
||||
|
||||
resources :memberships
|
||||
|
||||
resource :current_site, :controller => 'current_site'
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
Feature: Content Assets
|
||||
In order to ensure content assets are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have the following content assets:
|
||||
| id | file |
|
||||
| 4f832c2cb0d86d3f42fffffe | 5k.png |
|
||||
| 4f832c2cb0d86d3f42ffffff | 5k_2.png |
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to content_assets.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing content assets
|
||||
|
||||
Scenario: Accessing content assets as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing content assets as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing content assets as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
# showing content asset
|
||||
|
||||
Scenario: Accessing content asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "filename" should be "5k.png"
|
||||
|
||||
Scenario: Accessing content asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "filename" should be "5k.png"
|
||||
|
||||
Scenario: Accessing content asset as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "filename" should be "5k.png"
|
||||
|
||||
# create content asset
|
||||
|
||||
Scenario: Creating new content asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do a multipart API POST to content_assets.json with base key "content_asset" and:
|
||||
| source | assets/application.js |
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON at "2/filename" should be "application.js"
|
||||
|
||||
Scenario: Creating new content asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do a multipart API POST to content_assets.json with base key "content_asset" and:
|
||||
| source | assets/application.js |
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON at "2/filename" should be "application.js"
|
||||
|
||||
Scenario: Creating new content asset as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do a multipart API POST to content_assets.json with base key "content_asset" and:
|
||||
| source | assets/application.js |
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON at "2/filename" should be "application.js"
|
||||
|
||||
# update content asset
|
||||
|
||||
Scenario: Updating content asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do a multipart API PUT to content_assets/4f832c2cb0d86d3f42fffffe.json with base key "content_asset" and:
|
||||
| source | assets/main.css |
|
||||
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "filename" should be "main.css"
|
||||
|
||||
Scenario: Updating content asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do a multipart API PUT to content_assets/4f832c2cb0d86d3f42fffffe.json with base key "content_asset" and:
|
||||
| source | assets/main.css |
|
||||
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "filename" should be "main.css"
|
||||
|
||||
Scenario: Updating content asset as an Author
|
||||
Given I have a "author" API token
|
||||
When I do a multipart API PUT to content_assets/4f832c2cb0d86d3f42fffffe.json with base key "content_asset" and:
|
||||
| source | assets/main.css |
|
||||
When I do an API GET request to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "filename" should be "main.css"
|
||||
|
||||
# destroy content asset
|
||||
|
||||
Scenario: Destroying content asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Destroying content asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Deleting content asset as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to content_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
|
@ -0,0 +1,202 @@
|
|||
Feature: Content Entries
|
||||
In order to ensure content entries are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom model named "Projects" with
|
||||
| label | type | required |
|
||||
| Name | string | true |
|
||||
| Description | text | false |
|
||||
And I have entries for "Projects" with
|
||||
| id | name | description |
|
||||
| 4f832c2cb0d86d3f42fffffe | Project 1 | The first project |
|
||||
| 4f832c2cb0d86d3f42ffffff | Project 2 | The second project |
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to content_types/projects/entries.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing content entries
|
||||
|
||||
Scenario: Accessing content entries as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing content entries as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing content entries as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
# showing content entry
|
||||
|
||||
Scenario: Accessing content entry as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Project 1"
|
||||
|
||||
Scenario: Accessing content entry as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Project 1"
|
||||
|
||||
Scenario: Accessing content entry as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Project 1"
|
||||
|
||||
# create content entry
|
||||
|
||||
Scenario: Creating new content entry as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API POST to content_types/projects/entries.json with:
|
||||
"""
|
||||
{
|
||||
"content_entry": {
|
||||
"name": "Project 3",
|
||||
"description": "The third..."
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON should have the following:
|
||||
| 2/name | "Project 3" |
|
||||
| 2/description | "The third..." |
|
||||
|
||||
Scenario: Creating new content entry as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API POST to content_types/projects/entries.json with:
|
||||
"""
|
||||
{
|
||||
"content_entry": {
|
||||
"name": "Project 3",
|
||||
"description": "The third..."
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON should have the following:
|
||||
| 2/name | "Project 3" |
|
||||
| 2/description | "The third..." |
|
||||
|
||||
Scenario: Creating new content entry as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API POST to content_types/projects/entries.json with:
|
||||
"""
|
||||
{
|
||||
"content_entry": {
|
||||
"name": "Project 3",
|
||||
"description": "The third..."
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON should have the following:
|
||||
| 2/name | "Project 3" |
|
||||
| 2/description | "The third..." |
|
||||
|
||||
# update content entry
|
||||
|
||||
Scenario: Updating content entry as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"content_entry": {
|
||||
"description": "The awesomest project ever!"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Project 1"
|
||||
And the JSON response at "description" should be "The awesomest project ever!"
|
||||
|
||||
Scenario: Updating content entry as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"content_entry": {
|
||||
"description": "The awesomest project ever!"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Project 1"
|
||||
And the JSON response at "description" should be "The awesomest project ever!"
|
||||
|
||||
Scenario: Updating content entry as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"content_entry": {
|
||||
"description": "The awesomest project ever!"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Project 1"
|
||||
And the JSON response at "description" should be "The awesomest project ever!"
|
||||
|
||||
# destroy content entry
|
||||
|
||||
Scenario: Destroying content entry as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Destroying content entry as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Deleting content entry as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to content_types/projects/entries/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_types/projects/entries.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
|
@ -0,0 +1,237 @@
|
|||
Feature: Content Types
|
||||
In order to ensure content types are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom model named "Projects" with id "4f832c2cb0d86d3f42fffffe" and
|
||||
| label | type | required |
|
||||
| Name | string | true |
|
||||
| Description | text | false |
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to content_types.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing content types
|
||||
|
||||
Scenario: Accessing content types as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Accessing content types as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Accessing content types as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
# showing content type
|
||||
|
||||
Scenario: Accessing content type as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Projects"
|
||||
|
||||
Scenario: Accessing content type as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Projects"
|
||||
|
||||
Scenario: Accessing content type as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Projects"
|
||||
|
||||
# create content type
|
||||
|
||||
Scenario: Creating new content type as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API POST to content_types.json with:
|
||||
"""
|
||||
{
|
||||
"content_type": {
|
||||
"name": "Employees",
|
||||
"slug": "employees",
|
||||
"entries_custom_fields": [
|
||||
{
|
||||
"label": "Name",
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"label": "Position",
|
||||
"name": "position",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
And the JSON should have the following:
|
||||
| 0/name | "Employees" |
|
||||
| 0/slug | "employees" |
|
||||
| 0/entries_custom_fields/0/label | "Name" |
|
||||
| 0/entries_custom_fields/0/name | "name" |
|
||||
| 0/entries_custom_fields/0/type | "string" |
|
||||
| 0/entries_custom_fields/1/label | "Position" |
|
||||
| 0/entries_custom_fields/1/name | "position" |
|
||||
| 0/entries_custom_fields/1/type | "string" |
|
||||
|
||||
Scenario: Creating new content type as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API POST to content_types.json with:
|
||||
"""
|
||||
{
|
||||
"content_type": {
|
||||
"name": "Employees",
|
||||
"slug": "employees",
|
||||
"entries_custom_fields": [
|
||||
{
|
||||
"label": "Name",
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"label": "Position",
|
||||
"name": "position",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
And the JSON should have the following:
|
||||
| 0/name | "Employees" |
|
||||
| 0/slug | "employees" |
|
||||
| 0/entries_custom_fields/0/label | "Name" |
|
||||
| 0/entries_custom_fields/0/name | "name" |
|
||||
| 0/entries_custom_fields/0/type | "string" |
|
||||
| 0/entries_custom_fields/1/label | "Position" |
|
||||
| 0/entries_custom_fields/1/name | "position" |
|
||||
| 0/entries_custom_fields/1/type | "string" |
|
||||
|
||||
Scenario: Creating new content type as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API POST to content_types.json with:
|
||||
"""
|
||||
{
|
||||
"content_type": {
|
||||
"name": "Employees",
|
||||
"slug": "employees",
|
||||
"entries_custom_fields": [
|
||||
{
|
||||
"label": "Name",
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"label": "Position",
|
||||
"name": "position",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# update content type
|
||||
|
||||
Scenario: Updating content type as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to content_types/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"content_type": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating content type as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to content_types/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"content_type": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating content type as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to content_types/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"content_type": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# destroy content type
|
||||
|
||||
Scenario: Destroying content type as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API DELETE to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 0 entries
|
||||
|
||||
Scenario: Destroying content type as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API DELETE to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 0 entries
|
||||
|
||||
Scenario: Deleting content type as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API GET request to content_types.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entries
|
||||
When I do an API DELETE to content_types/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
|
@ -0,0 +1,30 @@
|
|||
Feature: Current Site
|
||||
In order to ensure the current site can be viewed by all authenticated users
|
||||
As an admin, designer or author
|
||||
I should be able to show the current site
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to current_site.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# showing current site
|
||||
|
||||
Scenario: Accessing current site as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET to current_site.json
|
||||
Then the JSON response at "name" should be "Locomotive test website"
|
||||
|
||||
Scenario: Accessing current site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET to current_site.json
|
||||
Then the JSON response at "name" should be "Locomotive test website"
|
||||
|
||||
Scenario: Accessing current site as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET to current_site.json
|
||||
Then the JSON response at "name" should be "Locomotive test website"
|
|
@ -0,0 +1,225 @@
|
|||
Feature: Memberships
|
||||
In order to ensure memberships are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up with id: "4f832c2cb0d86d3f42fffffb"
|
||||
And I have accounts:
|
||||
| email | id |
|
||||
| new-user@a.com | 4f832c2cb0d86d3f42fffffc |
|
||||
And I have memberships:
|
||||
| email | role | id |
|
||||
| admin@a.com | admin | 4f832c2cb0d86d3f42fffffd |
|
||||
| designer@a.com | designer | 4f832c2cb0d86d3f42fffffe |
|
||||
| author@a.com | author | 4f832c2cb0d86d3f42ffffff |
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to memberships.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing memberships
|
||||
|
||||
Scenario: Accessing memberships as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
|
||||
Scenario: Accessing memberships as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
|
||||
Scenario: Accessing memberships as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to memberships.json
|
||||
Then an access denied error should occur
|
||||
|
||||
# showing membership
|
||||
|
||||
Scenario: Accessing membership as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffd.json
|
||||
Then the JSON response at "email" should be "admin@a.com"
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "email" should be "designer@a.com"
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
Then the JSON response at "email" should be "author@a.com"
|
||||
|
||||
Scenario: Accessing membership as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffd.json
|
||||
Then the JSON response at "email" should be "admin@a.com"
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "email" should be "designer@a.com"
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
Then the JSON response at "email" should be "author@a.com"
|
||||
|
||||
Scenario: Accessing membership as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
||||
|
||||
# create membership
|
||||
|
||||
Scenario: Creating new membership as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API POST to memberships.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||
"account_id": "4f832c2cb0d86d3f42fffffc"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 5 entries
|
||||
|
||||
Scenario: Creating new membership as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API POST to memberships.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||
"account_id": "4f832c2cb0d86d3f42fffffc"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 5 entries
|
||||
|
||||
Scenario: Creating new membership as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API POST to memberships.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||
"account_id": "4f832c2cb0d86d3f42fffffc"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Created membership should always be Author
|
||||
Given I have an "admin" API token
|
||||
When I do an API POST to memberships.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"site_id": "4f832c2cb0d86d3f42fffffb",
|
||||
"account_id": "4f832c2cb0d86d3f42fffffc",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 5 entries
|
||||
And the JSON at "4/role" should be "author"
|
||||
|
||||
# update membership
|
||||
|
||||
Scenario: Updating membership as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
Then the JSON response at "role" should be "admin"
|
||||
|
||||
Scenario: Updating membership as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
Then the JSON response at "role" should be "author"
|
||||
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"role": "designer"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
Then the JSON response at "role" should be "designer"
|
||||
|
||||
Scenario: Updating membership as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"role": "designer"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
When I do an API PUT to memberships/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"membership": {
|
||||
"role": "author"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# destroy membership
|
||||
|
||||
Scenario: Destroying membership as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API DELETE to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
|
||||
Scenario: Destroying membership as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API DELETE to memberships/4f832c2cb0d86d3f42ffffff.json
|
||||
When I do an API GET request to memberships.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
When I do an API DELETE to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
||||
When I do an API DELETE to memberships/4f832c2cb0d86d3f42fffffd.json
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Deleting membership as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API DELETE to memberships/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
|
@ -0,0 +1,187 @@
|
|||
Feature: Pages
|
||||
In order to ensure pages are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom model named "Projects" with
|
||||
| label | type | required |
|
||||
| Name | string | true |
|
||||
| Description | text | false |
|
||||
And I have a designer and an author
|
||||
And a page named "hello-world" with id "4f832c2cb0d86d3f42fffffe"
|
||||
And a page named "goodbye-world" with id "4f832c2cb0d86d3f42ffffff"
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to pages.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing pages
|
||||
|
||||
Scenario: Accessing pages as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
|
||||
Scenario: Accessing pages as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
|
||||
Scenario: Accessing pages as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
|
||||
# showing page
|
||||
|
||||
Scenario: Accessing page as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "slug" should be "hello-world"
|
||||
|
||||
Scenario: Accessing page as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "slug" should be "hello-world"
|
||||
|
||||
Scenario: Accessing page as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "slug" should be "hello-world"
|
||||
|
||||
# create page
|
||||
|
||||
Scenario: Creating new page as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API POST to pages.json with:
|
||||
"""
|
||||
{
|
||||
"page": {
|
||||
"title": "New Page",
|
||||
"slug": "new-page",
|
||||
"parent_id": "4f832c2cb0d86d3f42fffffe"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 5 entries
|
||||
|
||||
Scenario: Creating new page as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API POST to pages.json with:
|
||||
"""
|
||||
{
|
||||
"page": {
|
||||
"title": "New Page",
|
||||
"slug": "new-page",
|
||||
"parent_id": "4f832c2cb0d86d3f42fffffe"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 5 entries
|
||||
|
||||
Scenario: Creating new page as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API POST to pages.json with:
|
||||
"""
|
||||
{
|
||||
"page": {
|
||||
"title": "New Page",
|
||||
"slug": "new-page",
|
||||
"parent_id": "4f832c2cb0d86d3f42fffffe"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# update page
|
||||
|
||||
Scenario: Updating page as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to pages/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"page": {
|
||||
"title": "Brand new updated title"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "title" should be "Brand new updated title"
|
||||
|
||||
Scenario: Updating page as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to pages/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"page": {
|
||||
"title": "Brand new updated title"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "title" should be "Brand new updated title"
|
||||
|
||||
Scenario: Updating page as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to pages/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"page": {
|
||||
"title": "Brand new updated title"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "title" should be "Brand new updated title"
|
||||
|
||||
# destroy page
|
||||
|
||||
Scenario: Destroying page as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API DELETE to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
|
||||
Scenario: Destroying page as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API DELETE to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
|
||||
Scenario: Deleting page as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API GET request to pages.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 4 entries
|
||||
When I do an API DELETE to pages/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
|
@ -0,0 +1,206 @@
|
|||
Feature: Sites
|
||||
In order to ensure sites are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up with id: "4f832c2cb0d86d3f42fffffe"
|
||||
And I have the site: "another site" set up with id: "4f832c2cb0d86d3f42ffffff"
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to sites.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing sites
|
||||
|
||||
Scenario: Accessing sites as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to sites.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing sites as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to sites.json
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Accessing sites as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to sites.json
|
||||
Then an access denied error should occur
|
||||
|
||||
# showing site
|
||||
|
||||
Scenario: Accessing site as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Locomotive test website"
|
||||
|
||||
Scenario: Accessing my site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Locomotive test website"
|
||||
|
||||
Scenario: Accessing other site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42ffffff.json
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Accessing my site as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Locomotive test website"
|
||||
|
||||
Scenario: Accessing other site as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42ffffff.json
|
||||
Then an access denied error should occur
|
||||
|
||||
# create site
|
||||
|
||||
Scenario: Creating new site as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to sites.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API POST to sites.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "New site",
|
||||
"subdomain": "new-site"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to sites.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
|
||||
Scenario: Creating new site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API POST to sites.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "New site",
|
||||
"subdomain": "new-site"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Creating new site as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API POST to sites.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "New site",
|
||||
"subdomain": "new-site"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# update site
|
||||
|
||||
Scenario: Updating site as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to sites/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating my site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to sites/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating other site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to sites/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Updating my site as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to sites/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating other site as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to sites/4f832c2cb0d86d3f42ffffff.json with:
|
||||
"""
|
||||
{
|
||||
"site": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# destroy site
|
||||
|
||||
Scenario: Destroying site as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to sites.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to sites.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entries
|
||||
|
||||
Scenario: Destroying my site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API DELETE to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then it should not exist
|
||||
|
||||
Scenario: Deleting other site as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API DELETE to sites/4f832c2cb0d86d3f42ffffff.json
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Deleting my site as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API DELETE to sites/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
||||
|
||||
Scenario: Deleting other site as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API DELETE to sites/4f832c2cb0d86d3f42ffffff.json
|
||||
Then an access denied error should occur
|
|
@ -0,0 +1,179 @@
|
|||
Feature: Snippets
|
||||
In order to ensure snippets are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And a snippet named "My Snippet" with id "4f832c2cb0d86d3f42fffffe" and template:
|
||||
"""
|
||||
My Snippet
|
||||
"""
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to snippets.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing content types
|
||||
|
||||
Scenario: Accessing snippets as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Accessing snippets as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
|
||||
Scenario: Accessing snippets as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then an access denied error should occur
|
||||
|
||||
# showing snippet
|
||||
|
||||
Scenario: Accessing snippet as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "My Snippet"
|
||||
|
||||
Scenario: Accessing snippet as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "id" should be "4f832c2cb0d86d3f42fffffe"
|
||||
And the JSON response at "name" should be "My Snippet"
|
||||
|
||||
Scenario: Accessing snippet as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
||||
|
||||
# create snippet
|
||||
|
||||
Scenario: Creating new snippet as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API POST to snippets.json with:
|
||||
"""
|
||||
{
|
||||
"snippet": {
|
||||
"name": "Another snippet",
|
||||
"template": "<h1>Another Snippet!</h1>"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
And the JSON should have the following:
|
||||
| 0/name | "Another Snippet" |
|
||||
| 0/template | "<h1>Another Snippet!</h1>" |
|
||||
|
||||
Scenario: Creating new snippet as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API POST to snippets.json with:
|
||||
"""
|
||||
{
|
||||
"snippet": {
|
||||
"name": "Another snippet",
|
||||
"template": "<h1>Another Snippet!</h1>"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
And the JSON should have the following:
|
||||
| 0/name | "Another Snippet" |
|
||||
| 0/template | "<h1>Another Snippet!</h1>" |
|
||||
|
||||
Scenario: Creating new snippet as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API POST to snippets.json with:
|
||||
"""
|
||||
{
|
||||
"snippet": {
|
||||
"name": "Another snippet",
|
||||
"template": "<h1>Another Snippet!</h1>"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# update snippet
|
||||
|
||||
Scenario: Updating snippet as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to snippets/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"snippet": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating snippet as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to snippets/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"snippet": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "name" should be "Brand new updated name"
|
||||
|
||||
Scenario: Updating snippet as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to snippets/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"snippet": {
|
||||
"name": "Brand new updated name"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# destroy snippet
|
||||
|
||||
Scenario: Destroying snippet as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API DELETE to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 0 entries
|
||||
|
||||
Scenario: Destroying snippet as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entry
|
||||
When I do an API DELETE to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to snippets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 0 entries
|
||||
|
||||
Scenario: Deleting snippet as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API DELETE to snippets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
|
@ -0,0 +1,185 @@
|
|||
Feature: Theme Assets
|
||||
In order to ensure theme assets are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And a javascript asset named "my_javascript.js" with id "4f832c2cb0d86d3f42fffffe"
|
||||
And a stylesheet asset named "my_stylesheet.css" with id "4f832c2cb0d86d3f42ffffff"
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I do an API GET to theme_assets.json
|
||||
Then the JSON response at "error" should be "You need to sign in or sign up before continuing."
|
||||
|
||||
# listing theme assets
|
||||
|
||||
Scenario: Accessing theme assets as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing theme assets as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
Scenario: Accessing theme assets as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
|
||||
# showing theme asset
|
||||
|
||||
Scenario: Accessing theme asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "local_path" should be "my_javascript.js"
|
||||
|
||||
Scenario: Accessing theme asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "local_path" should be "my_javascript.js"
|
||||
|
||||
Scenario: Accessing theme asset as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response at "local_path" should be "my_javascript.js"
|
||||
|
||||
# create theme asset
|
||||
|
||||
Scenario: Creating new theme asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API POST to theme_assets.json with:
|
||||
"""
|
||||
{
|
||||
"theme_asset": {
|
||||
"plain_text_name": "new-javascript.js",
|
||||
"plain_text": "function doNothing() {}",
|
||||
"plain_text_type": "javascript",
|
||||
"performing_plain_text": "true"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON should have the following:
|
||||
| 2/local_path | "new-javascript.js" |
|
||||
| 2/content_type | "javascript" |
|
||||
|
||||
Scenario: Creating new theme asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API POST to theme_assets.json with:
|
||||
"""
|
||||
{
|
||||
"theme_asset": {
|
||||
"plain_text_name": "new-javascript.js",
|
||||
"plain_text": "function doNothing() {}",
|
||||
"plain_text_type": "javascript",
|
||||
"performing_plain_text": "true"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 3 entries
|
||||
And the JSON should have the following:
|
||||
| 2/local_path | "new-javascript.js" |
|
||||
| 2/content_type | "javascript" |
|
||||
|
||||
Scenario: Creating new theme asset as an Author
|
||||
Given I have an "author" API token
|
||||
When I do an API POST to theme_assets.json with:
|
||||
"""
|
||||
{
|
||||
"theme_asset": {
|
||||
"plain_text_name": "new-javascript.js",
|
||||
"plain_text": "function doNothing() {}",
|
||||
"plain_text_type": "javascript",
|
||||
"performing_plain_text": "true"
|
||||
}
|
||||
}
|
||||
"""
|
||||
Then an access denied error should occur
|
||||
|
||||
# update theme asset
|
||||
|
||||
Scenario: Updating theme asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API PUT to theme_assets/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"theme_asset": {
|
||||
"plain_text_name": "newer-javascript.js"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response should have the following:
|
||||
| local_path | "newer-javascript.js" |
|
||||
|
||||
Scenario: Updating theme asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API PUT to theme_assets/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"theme_asset": {
|
||||
"plain_text_name": "newer-javascript.js"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response should have the following:
|
||||
| local_path | "newer-javascript.js" |
|
||||
|
||||
Scenario: Updating theme asset as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API PUT to theme_assets/4f832c2cb0d86d3f42fffffe.json with:
|
||||
"""
|
||||
{
|
||||
"theme_asset": {
|
||||
"plain_text_name": "newer-javascript.js"
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I do an API GET request to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then the JSON response should have the following:
|
||||
| local_path | "newer-javascript.js" |
|
||||
|
||||
# destroy theme asset
|
||||
|
||||
Scenario: Destroying theme asset as an Admin
|
||||
Given I have an "admin" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entries
|
||||
|
||||
Scenario: Destroying theme asset as a Designer
|
||||
Given I have a "designer" API token
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 2 entries
|
||||
When I do an API DELETE to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
When I do an API GET request to theme_assets.json
|
||||
Then the JSON response should be an array
|
||||
And the JSON response should have 1 entries
|
||||
|
||||
Scenario: Deleting theme asset as an Author
|
||||
Given I have a "author" API token
|
||||
When I do an API DELETE to theme_assets/4f832c2cb0d86d3f42fffffe.json
|
||||
Then an access denied error should occur
|
|
@ -4,6 +4,7 @@ Feature: Contact form
|
|||
I want to be able to send them a message
|
||||
|
||||
Background:
|
||||
Given I enable the CSRF protection for public submission requests
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom model named "Messages" with
|
||||
| label | type | required |
|
||||
|
@ -16,6 +17,7 @@ Feature: Contact form
|
|||
<head></head>
|
||||
<body>
|
||||
<form action="{{ contents.messages.public_submission_url }}" method="post">
|
||||
{% csrf_param %}
|
||||
<input type="hidden" value="/success" name="success_callback" />
|
||||
<input type="hidden" value="/contact" name="error_callback" />
|
||||
<label for="email">E-Mail Address</label>
|
||||
|
@ -55,6 +57,20 @@ Feature: Contact form
|
|||
And I press "Submit"
|
||||
Then I should see "Thanks did@locomotivecms.com"
|
||||
|
||||
Scenario: Can not send a message if the csrf tag is missing
|
||||
Given I delete the following code "{% csrf_param %}" from the "contact" page
|
||||
When I view the rendered page at "/contact"
|
||||
And I press "Submit"
|
||||
Then I should see "Content of the home page"
|
||||
|
||||
Scenario: Can send a message if the csrf protection is disabled
|
||||
Given I disable the CSRF protection for public submission requests
|
||||
And I view the rendered page at "/contact"
|
||||
And I fill in "E-Mail Address" with "did@locomotivecms.com"
|
||||
And I fill in "Message" with "LocomotiveCMS rocks"
|
||||
And I press "Submit"
|
||||
Then I should see "Thanks did@locomotivecms.com"
|
||||
|
||||
Scenario: Display errors
|
||||
When I view the rendered page at "/contact"
|
||||
And I fill in "Message" with "LocomotiveCMS rocks"
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
|
||||
def api_base_url
|
||||
"http://#{Locomotive::Site.first.domains.first}/locomotive/api/"
|
||||
end
|
||||
|
||||
def do_api_request(type, url, param_string_or_hash = nil)
|
||||
begin
|
||||
if param_string_or_hash
|
||||
if param_string_or_hash.is_a? Hash
|
||||
params = param_string_or_hash
|
||||
else
|
||||
params = JSON.parse(param_string_or_hash)
|
||||
end
|
||||
else
|
||||
params = {}
|
||||
end
|
||||
@json_response = do_request(type, api_base_url, url,
|
||||
params.merge({ 'CONTENT_TYPE' => 'application/json' }))
|
||||
rescue CanCan::AccessDenied, Mongoid::Errors::DocumentNotFound
|
||||
@error = $!
|
||||
end
|
||||
end
|
||||
|
||||
def last_json
|
||||
@json_response.try(:body) || page.source
|
||||
end
|
||||
|
@ -11,13 +34,16 @@ Given /^I have an? "([^"]*)" API token$/ do |role|
|
|||
'password' => 'easyone'
|
||||
}
|
||||
|
||||
response = post("http://#{@site.domains.first}/locomotive/api/tokens.json", login_params.to_json, { 'CONTENT_TYPE' => 'application/json' })
|
||||
response = do_request('POST', api_base_url, 'tokens.json',
|
||||
login_params.merge({ 'CONTENT_TYPE' => 'application/json' }))
|
||||
|
||||
if response.status == 200
|
||||
@auth_token = JSON.parse(response.body)['token']
|
||||
else
|
||||
raise JSON.parse(response.body)['message']
|
||||
end
|
||||
|
||||
add_default_params(:auth_token => @auth_token)
|
||||
end
|
||||
|
||||
Given /^I do not have an API token$/ do
|
||||
|
@ -35,4 +61,36 @@ end
|
|||
|
||||
When /^I post to "([^"]*)" with:$/ do |path, json_string|
|
||||
@json_response = post("http://#{@site.domains.first}#{path}", json_string, { 'CONTENT_TYPE' => 'application/json' })
|
||||
end
|
||||
end
|
||||
|
||||
When /^I do an API (\w+) (?:request )?to ([\w.\/]+)$/ do |request_type, url|
|
||||
do_api_request(request_type, url)
|
||||
end
|
||||
|
||||
When /^I do an API (\w+) (?:request )?to ([\w.\/]+) with:$/ do |request_type, url, param_string|
|
||||
do_api_request(request_type, url, param_string)
|
||||
end
|
||||
|
||||
Then /^an access denied error should occur$/ do
|
||||
@error.should_not be_nil
|
||||
@error.is_a?(CanCan::AccessDenied).should be_true
|
||||
end
|
||||
|
||||
Then /^it should not exist$/ do
|
||||
@error.should_not be_nil
|
||||
@error.is_a?(Mongoid::Errors::DocumentNotFound).should be_true
|
||||
end
|
||||
|
||||
When /^I do a multipart API (\w+) (?:request )?to ([\w.\/]+) with base key "([^"]*)" and:$/ \
|
||||
do |request_type, url, base_key, table|
|
||||
params = {}
|
||||
params = table.rows_hash
|
||||
params.each do |key, filename|
|
||||
params[key] = Rack::Test::UploadedFile.new(Rails.root.join('..', 'fixtures', filename))
|
||||
end
|
||||
do_api_request(request_type, url, { base_key => params })
|
||||
end
|
||||
|
||||
Then /^I print the json response$/ do
|
||||
puts %{JSON: "#{last_json}"}
|
||||
end
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
Given /^I have the following content assets:$/ do |table|
|
||||
site = Locomotive::Site.first
|
||||
table.hashes.each do |asset_hash|
|
||||
asset_hash['site'] = site
|
||||
asset_hash['source'] = FixturedAsset.open(asset_hash['file'])
|
||||
asset_hash.delete('file')
|
||||
|
||||
asset = FactoryGirl.build(:asset, asset_hash)
|
||||
asset.save.should be_true
|
||||
end
|
||||
end
|
|
@ -1,6 +1,9 @@
|
|||
Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
|
||||
def build_content_type(name)
|
||||
site = Locomotive::Site.first
|
||||
content_type = FactoryGirl.build(:content_type, :site => site, :name => name, :order_by => '_position')
|
||||
FactoryGirl.build(:content_type, :site => site, :name => name, :order_by => '_position')
|
||||
end
|
||||
|
||||
def set_custom_fields_from_table(content_type, fields)
|
||||
fields.hashes.each do |field|
|
||||
# found a belongs_to association
|
||||
if field['type'] == 'belongs_to'
|
||||
|
@ -12,6 +15,19 @@ Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
|
|||
|
||||
content_type.entries_custom_fields.build field
|
||||
end
|
||||
end
|
||||
|
||||
Given %r{^I have a custom model named "([^"]*)" with id "([^"]*)" and$} do |name, id, fields|
|
||||
content_type = build_content_type(name)
|
||||
content_type.id = BSON::ObjectId(id)
|
||||
set_custom_fields_from_table(content_type, fields)
|
||||
content_type.valid?
|
||||
content_type.save.should be_true
|
||||
end
|
||||
|
||||
Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
|
||||
content_type = build_content_type(name)
|
||||
set_custom_fields_from_table(content_type, fields)
|
||||
content_type.valid?
|
||||
content_type.save.should be_true
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
Given /^I have accounts:$/ do |accounts_table|
|
||||
accounts_table.hashes.each do |account_hash|
|
||||
FactoryGirl.create(:account, account_hash)
|
||||
end
|
||||
end
|
||||
|
||||
Given /^I have memberships:$/ do |members_table|
|
||||
members_table.hashes.each do |member_hash|
|
||||
email = member_hash[:email]
|
||||
account = Locomotive::Account.where(:email => email).first \
|
||||
|| FactoryGirl.create(:account, :email => email)
|
||||
|
||||
member_hash.delete(:email)
|
||||
member_hash.merge!({ :account => account, :site => @site })
|
||||
|
||||
FactoryGirl.create(:membership, member_hash)
|
||||
end
|
||||
end
|
|
@ -38,4 +38,19 @@ end
|
|||
|
||||
When /^I reload the page$/ do
|
||||
visit current_path
|
||||
end
|
||||
end
|
||||
|
||||
Given /^I enable the CSRF protection for public submission requests$/ do
|
||||
Locomotive.config.csrf_protection = true
|
||||
Locomotive::Public::ContentEntriesController.any_instance.stubs(:protect_against_forgery?).returns(true)
|
||||
end
|
||||
|
||||
Given /^I disable the CSRF protection for public submission requests$/ do
|
||||
Locomotive.config.csrf_protection = false
|
||||
# pending # express the regexp above with the code you wish you had
|
||||
end
|
||||
|
||||
Then /^it returns a (\d+) error page$/ do |code|
|
||||
puts page.status_code
|
||||
page.status_code.should == code.to_i
|
||||
end
|
||||
|
|
|
@ -2,9 +2,16 @@
|
|||
|
||||
# helps create a simple content page (parent: "index") with a slug, contents, and template
|
||||
def create_content_page(page_slug, page_contents, template = nil)
|
||||
@home = @site.pages.where(:slug => "index").first || FactoryGirl.create(:page)
|
||||
page = @site.pages.create(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :raw_template => template)
|
||||
page = new_content_page(page_slug, page_contents, template)
|
||||
page.should be_valid
|
||||
page.save!
|
||||
page
|
||||
end
|
||||
|
||||
# build page without saving
|
||||
def new_content_page(page_slug, page_contents, template = nil)
|
||||
@home = @site.pages.where(:slug => "index").first || FactoryGirl.create(:page)
|
||||
page = @site.pages.new(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :raw_template => template)
|
||||
page
|
||||
end
|
||||
|
||||
|
@ -17,6 +24,12 @@ Given /^a page named "([^"]*)" with the template:$/ do |page_slug, template|
|
|||
@page = create_content_page(page_slug, '', template)
|
||||
end
|
||||
|
||||
Given /^a page named "([^"]*)" with id "([^"]*)"$/ do |page_slug, id|
|
||||
@page = new_content_page(page_slug, '')
|
||||
@page.id = BSON::ObjectId(id)
|
||||
@page.save!
|
||||
end
|
||||
|
||||
# change the title
|
||||
When /^I change the page title to "([^"]*)"$/ do |page_title|
|
||||
page.evaluate_script "window.prompt = function() { return '#{page_title}'; }"
|
||||
|
@ -35,10 +48,16 @@ When /^I update the "([^"]*)" page with the template:$/ do |page_slug, template|
|
|||
page.save!
|
||||
end
|
||||
|
||||
Given /^I delete the following code "([^"]*)" from the "([^"]*)" page$/ do |code, page_slug|
|
||||
page = @site.pages.where(:slug => page_slug).first
|
||||
page.raw_template = page.raw_template.gsub(code, '')
|
||||
page.save!
|
||||
end
|
||||
|
||||
# try to render a page by slug
|
||||
When /^I view the rendered page at "([^"]*)"$/ do |path|
|
||||
# If we're running selenium then we need to use a differnt port
|
||||
if Capybara.current_driver == :selenium
|
||||
# If we're running poltergeist then we need to use a different port
|
||||
if Capybara.current_driver == :poltergeist
|
||||
visit "http://#{@site.domains.first}:#{Capybara.server_port}#{path}"
|
||||
else
|
||||
visit "http://#{@site.domains.first}#{path}"
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
### Snippets
|
||||
|
||||
# helps create a simple snippet with a slug and template
|
||||
def new_snippet(name, template = nil)
|
||||
@site.snippets.new(:name => name, :template => template)
|
||||
end
|
||||
|
||||
def create_snippet(name, template = nil)
|
||||
snippet = @site.snippets.create(:name => name, :template => template)
|
||||
snippet.should be_valid
|
||||
snippet = new_snippet(name, template)
|
||||
snippet.save!
|
||||
snippet
|
||||
end
|
||||
|
||||
|
@ -13,6 +17,12 @@ Given /^a snippet named "([^"]*)" with the template:$/ do |name, template|
|
|||
@snippet = create_snippet(name, template)
|
||||
end
|
||||
|
||||
Given /^a snippet named "([^"]*)" with id "([^"]*)" and template:$/ do |name, id, template|
|
||||
@snippet = new_snippet(name, template)
|
||||
@snippet.id = BSON::ObjectId(id)
|
||||
@snippet.save!
|
||||
end
|
||||
|
||||
When /^I change the snippet template to "([^"]*)"$/ do |code|
|
||||
page.evaluate_script "window.application_view.view.editor.setValue('#{code}')"
|
||||
end
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
### Theme assets
|
||||
|
||||
# helps create a theme asset
|
||||
def create_plain_text_asset(name, type)
|
||||
asset = FactoryGirl.build(:theme_asset, {
|
||||
def new_plain_text_asset(name, type)
|
||||
FactoryGirl.build(:theme_asset, {
|
||||
:site => @site,
|
||||
:plain_text_name => name,
|
||||
:plain_text => 'Lorem ipsum',
|
||||
:plain_text_type => type,
|
||||
:performing_plain_text => true
|
||||
})
|
||||
end
|
||||
|
||||
def create_plain_text_asset(name, type)
|
||||
asset = new_plain_text_asset(name, type)
|
||||
asset.save!
|
||||
end
|
||||
|
||||
|
@ -19,10 +22,22 @@ Given /^a javascript asset named "([^"]*)"$/ do |name|
|
|||
@asset = create_plain_text_asset(name, 'javascript')
|
||||
end
|
||||
|
||||
Given /^a javascript asset named "([^"]*)" with id "([^"]*)"$/ do |name, id|
|
||||
@asset = new_plain_text_asset(name, 'javascript')
|
||||
@asset.id = BSON::ObjectId(id)
|
||||
@asset.save!
|
||||
end
|
||||
|
||||
Given /^a stylesheet asset named "([^"]*)"$/ do |name|
|
||||
@asset = create_plain_text_asset(name, 'stylesheet')
|
||||
end
|
||||
|
||||
Given /^a stylesheet asset named "([^"]*)" with id "([^"]*)"$/ do |name, id|
|
||||
@asset = new_plain_text_asset(name, 'stylesheet')
|
||||
@asset.id = BSON::ObjectId(id)
|
||||
@asset.save!
|
||||
end
|
||||
|
||||
Given /^I have an image theme asset named "([^"]*)"$/ do |name|
|
||||
@asset = FactoryGirl.create(:theme_asset, :site => @site, :source => File.open(Rails.root.join('..', 'fixtures', 'assets', '5k.png')))
|
||||
@asset.source_filename = name
|
||||
|
|
|
@ -18,6 +18,7 @@ require 'capybara'
|
|||
require 'capybara/rails'
|
||||
require 'capybara/cucumber'
|
||||
require 'capybara/session'
|
||||
require 'capybara/poltergeist'
|
||||
|
||||
require 'json_spec/cucumber'
|
||||
|
||||
|
@ -44,7 +45,7 @@ end
|
|||
|
||||
Capybara.default_wait_time = 5
|
||||
|
||||
# Capybara.javascript_driver = :rack_test
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
|
||||
# Stop endless errors like
|
||||
# ~/.rvm/gems/ruby-1.9.2-p0@global/gems/rack-1.2.1/lib/rack/utils.rb:16:
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
module HTTPHelpers
|
||||
|
||||
attr_accessor :default_params
|
||||
|
||||
def add_default_params(params)
|
||||
default_params.merge!(params)
|
||||
end
|
||||
|
||||
def do_request(type, base_url, url, params)
|
||||
request_method = type.downcase.to_sym
|
||||
send(request_method, "#{base_url}/#{url}", default_params.merge(params))
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_params
|
||||
@default_params ||= {}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
World(HTTPHelpers)
|
|
@ -22,11 +22,11 @@ Locomotive.configure do |config|
|
|||
# :max_content_types => 4
|
||||
# }
|
||||
|
||||
# default locale (for now, only en, de, fr, pt-BR and it are supported)
|
||||
# default locale (for now, only en, de, fr, pt-BR, it and nb are supported)
|
||||
config.default_locale = :en
|
||||
|
||||
# available locales suggested to "localize" a site. You will have to pick up at least one among that list.
|
||||
# config.site_locales = %w{en de fr pt-BR it nl no es ru}
|
||||
# config.site_locales = %w{en de fr pt-BR it nl nb es ru}
|
||||
|
||||
# tell if logs are enabled. Useful for debug purpose.
|
||||
config.enable_logs = true
|
||||
|
@ -48,6 +48,13 @@ Locomotive.configure do |config|
|
|||
# add extra classes other than the defined content types among a site which will potentially used by the templatized pages.
|
||||
# config.models_for_templatization = %w(Product)
|
||||
|
||||
# "Public" forms can be protected from Cross-Site Request Forgery (CSRF) attacks.
|
||||
# By default, that protection is disabled (false) in order to keep backwards compatibility with the existing public forms.
|
||||
#
|
||||
# Note: we strongly recommend to enable it. See the documentation about the "csrf_param" liquid tag.
|
||||
#
|
||||
# config.csrf_protection = true
|
||||
|
||||
# Rack-cache settings, mainly used for the inline resizing image module. Default options:
|
||||
# config.rack_cache = {
|
||||
# :verbose => true,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
require 'locomotive/version'
|
||||
require 'locomotive/core_ext'
|
||||
require 'locomotive/configuration'
|
||||
require 'locomotive/devise'
|
||||
require 'locomotive/logger'
|
||||
require 'locomotive/haml'
|
||||
require 'locomotive/formtastic'
|
||||
|
@ -12,6 +13,7 @@ require 'locomotive/carrierwave'
|
|||
require 'locomotive/custom_fields'
|
||||
require 'locomotive/httparty'
|
||||
require 'locomotive/action_controller'
|
||||
require 'locomotive/rails'
|
||||
require 'locomotive/routing'
|
||||
require 'locomotive/regexps'
|
||||
require 'locomotive/render'
|
||||
|
|
|
@ -7,8 +7,8 @@ module Locomotive
|
|||
:reserved_subdomains => %w{www admin email blog webmail mail support help site sites},
|
||||
# :forbidden_paths => %w{layouts snippets stylesheets javascripts assets admin system api},
|
||||
:reserved_slugs => %w{stylesheets javascripts assets admin locomotive images api pages edit},
|
||||
:locales => %w{en de fr pt-BR it nl no es ru},
|
||||
:site_locales => %w{en de fr pt-BR it nl no es ru},
|
||||
:locales => %w{en de fr pt-BR it nl nb es ru},
|
||||
:site_locales => %w{en de fr pt-BR it nl nb es ru},
|
||||
:cookie_key => '_locomotive_session',
|
||||
:enable_logs => false,
|
||||
:delayed_job => false,
|
||||
|
@ -27,7 +27,8 @@ module Locomotive
|
|||
},
|
||||
:devise_modules => [:rememberable, :database_authenticatable, :token_authenticatable, :recoverable, :trackable, :validatable, :encryptable, { :encryptor => :sha1 }],
|
||||
:context_assign_extensions => { },
|
||||
:models_for_templatization => []
|
||||
:models_for_templatization => [],
|
||||
:csrf_protection => false
|
||||
}
|
||||
|
||||
cattr_accessor :settings
|
||||
|
|
|
@ -22,6 +22,7 @@ module CustomFields
|
|||
module Types
|
||||
|
||||
module File
|
||||
|
||||
class FileUploader < ::CarrierWave::Uploader::Base
|
||||
|
||||
# Set correct paths
|
||||
|
@ -34,6 +35,7 @@ module CustomFields
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ require 'mongoid/railtie'
|
|||
require 'mongoid/tree'
|
||||
require 'devise'
|
||||
require 'devise/orm/mongoid'
|
||||
require 'devise-encryptable'
|
||||
require 'kaminari'
|
||||
require 'haml'
|
||||
require 'liquid'
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue