cmsimple 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +31 -0
- data/.rspec +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +20 -0
- data/Gemfile.ci +5 -0
- data/LICENSE +19 -0
- data/README.md +118 -0
- data/Rakefile +47 -0
- data/app/assets/javascripts/cmsimple.js +61 -0
- data/app/assets/javascripts/cmsimple/controllers/editor.coffee +102 -0
- data/app/assets/javascripts/cmsimple/lib/namespaces.coffee +3 -0
- data/app/assets/javascripts/cmsimple/lib/support.coffee +4 -0
- data/app/assets/javascripts/cmsimple/mercury/config.js +462 -0
- data/app/assets/javascripts/cmsimple/mercury/handlers.coffee +9 -0
- data/app/assets/javascripts/cmsimple/models/image.coffee +49 -0
- data/app/assets/javascripts/cmsimple/models/page.coffee +106 -0
- data/app/assets/javascripts/cmsimple/models/path.coffee +31 -0
- data/app/assets/javascripts/cmsimple/models/version.coffee +29 -0
- data/app/assets/javascripts/cmsimple/panels/images/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/images/list.coffee +48 -0
- data/app/assets/javascripts/cmsimple/panels/images/panel.coffee +69 -0
- data/app/assets/javascripts/cmsimple/panels/images/selection.coffee +52 -0
- data/app/assets/javascripts/cmsimple/panels/page_metadata.coffee +42 -0
- data/app/assets/javascripts/cmsimple/panels/publish.coffee +32 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/form.coffee +51 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/list.coffee +34 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/panel.coffee +39 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/panel.coffee +40 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/sortable.coffee +55 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/tree.coffee +61 -0
- data/app/assets/javascripts/cmsimple/panels/versions/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/versions/list.coffee +51 -0
- data/app/assets/javascripts/cmsimple/panels/versions/panel.coffee +53 -0
- data/app/assets/javascripts/cmsimple/views/image_library/_item.jst.hamlc +24 -0
- data/app/assets/javascripts/cmsimple/views/image_library/list.jst.hamlc +8 -0
- data/app/assets/javascripts/cmsimple/views/redirects/_path.jst.hamlc +6 -0
- data/app/assets/javascripts/cmsimple/views/redirects/list.jst.hamlc +19 -0
- data/app/assets/javascripts/cmsimple/views/sitemap/_page.jst.hamlc +9 -0
- data/app/assets/javascripts/cmsimple/views/sitemap/tree.jst.hamlc +5 -0
- data/app/assets/javascripts/cmsimple/views/versions/_item.jst.hamlc +6 -0
- data/app/assets/javascripts/cmsimple/views/versions/list.jst.hamlc +4 -0
- data/app/assets/stylesheets/cmsimple.css +15 -0
- data/app/assets/stylesheets/cmsimple/forms.css +10 -0
- data/app/assets/stylesheets/cmsimple/panels.css +399 -0
- data/app/assets/stylesheets/cmsimple/toolbar-images.css +27 -0
- data/app/assets/stylesheets/mercury_overrides.css +2 -0
- data/app/controllers/cmsimple/front_controller.rb +38 -0
- data/app/controllers/cmsimple/images_controller.rb +28 -0
- data/app/controllers/cmsimple/mercury_controller.rb +7 -0
- data/app/controllers/cmsimple/pages_controller.rb +89 -0
- data/app/controllers/cmsimple/paths_controller.rb +23 -0
- data/app/controllers/cmsimple/snippets_controller.rb +23 -0
- data/app/controllers/cmsimple/versions_controller.rb +17 -0
- data/app/helpers/cmsimple/regions_helper.rb +38 -0
- data/app/models/cmsimple/image.rb +19 -0
- data/app/models/cmsimple/page.rb +203 -0
- data/app/models/cmsimple/path.rb +63 -0
- data/app/models/cmsimple/region.rb +43 -0
- data/app/models/cmsimple/snippet.rb +64 -0
- data/app/models/cmsimple/version.rb +18 -0
- data/app/uploaders/image_attachment_uploader.rb +53 -0
- data/app/views/cmsimple/images/_form.html.haml +13 -0
- data/app/views/cmsimple/images/new.html.haml +5 -0
- data/app/views/cmsimple/pages/_form.html.haml +49 -0
- data/app/views/cmsimple/pages/_form_extras.html.haml +2 -0
- data/app/views/cmsimple/pages/edit.html.haml +3 -0
- data/app/views/cmsimple/pages/new.html.haml +3 -0
- data/app/views/cmsimple/pages/publish.html.haml +12 -0
- data/app/views/cmsimple/snippets/index.html.haml +5 -0
- data/app/views/cmsimple/templates/default.html.haml +4 -0
- data/app/views/layouts/editor.html.haml +12 -0
- data/app/views/layouts/panel.html.haml +9 -0
- data/cmsimple.gemspec +44 -0
- data/config.ru +4 -0
- data/config/application.rb +1 -0
- data/config/cucumber.yml +8 -0
- data/config/environment.rb +2 -0
- data/config/routes.rb +34 -0
- data/db/migrate/20120201221410_create_cmsimple_pages.rb +10 -0
- data/db/migrate/20120222185901_add_title_parent_id_and_position_to_pages.rb +10 -0
- data/db/migrate/20120229185214_add_slug_to_pages.rb +7 -0
- data/db/migrate/20120323200439_add_is_root_to_page.rb +5 -0
- data/db/migrate/20120328174339_add_meta_info_to_cmsimple_pages.rb +9 -0
- data/db/migrate/20120329172857_create_cmsimple_path.rb +11 -0
- data/db/migrate/20120407024752_create_cmsimple_images.rb +13 -0
- data/db/migrate/20120410041105_add_timestamps_to_cmsimple_pages.rb +7 -0
- data/db/migrate/20120425211937_add_published_at_to_cmsimple_pages.rb +6 -0
- data/db/migrate/20120430175047_create_cmsimple_versions.rb +13 -0
- data/db/migrate/20120831233927_rename_path_to_current_uri_on_paths.rb +5 -0
- data/features/create.feature +18 -0
- data/features/delete.feature +12 -0
- data/features/edit.feature +54 -0
- data/features/publishing.feature +31 -0
- data/features/redirects.feature +27 -0
- data/features/step_definitions/mercury_steps.rb +440 -0
- data/features/step_definitions/page_steps.rb +269 -0
- data/features/step_definitions/web_steps.rb +254 -0
- data/features/support/env.rb +77 -0
- data/features/support/mercury_content.rb +25 -0
- data/features/support/mercury_selectors.rb +148 -0
- data/features/support/paths.rb +16 -0
- data/features/support/selectors.rb +26 -0
- data/features/support/utils.rb +18 -0
- data/features/versioning.feature +27 -0
- data/features/visit.feature +7 -0
- data/lib/cmsimple.rb +22 -0
- data/lib/cmsimple/configuration.rb +65 -0
- data/lib/cmsimple/exts/to_bool.rb +25 -0
- data/lib/cmsimple/page_responder.rb +46 -0
- data/lib/cmsimple/rails.rb +5 -0
- data/lib/cmsimple/regions_proxy.rb +32 -0
- data/lib/cmsimple/template_resolver.rb +14 -0
- data/lib/cmsimple/template_responder.rb +12 -0
- data/lib/cmsimple/version.rb +3 -0
- data/lib/generators/cmsimple/install/install_generator.rb +46 -0
- data/lib/generators/cmsimple/install/templates/default.html.erb +10 -0
- data/lib/generators/cmsimple/install/templates/default.html.haml +6 -0
- data/lib/generators/cmsimple/install/templates/initializer.rb +22 -0
- data/lib/generators/cmsimple/snippet/snippet_generator.rb +56 -0
- data/lib/generators/cmsimple/snippet/templates/cell.rb +18 -0
- data/lib/generators/cmsimple/snippet/templates/display.html.erb +14 -0
- data/lib/generators/cmsimple/snippet/templates/display.html.haml +11 -0
- data/lib/generators/cmsimple/snippet/templates/options.html.erb +18 -0
- data/lib/generators/cmsimple/snippet/templates/options.html.haml +12 -0
- data/script/app +2 -0
- data/script/migrate +2 -0
- data/script/rails +8 -0
- data/spec/fixtures/rails.png +0 -0
- data/spec/helpers/regions_helper_spec.rb +62 -0
- data/spec/javascripts/controllers/editor_spec.coffee +57 -0
- data/spec/javascripts/models/image_geometry_spec.coffee +64 -0
- data/spec/javascripts/models/image_spec.coffee +4 -0
- data/spec/javascripts/models/page_spec.coffee +121 -0
- data/spec/javascripts/models/path_spec.coffee +39 -0
- data/spec/javascripts/models/version_spec.coffee +31 -0
- data/spec/javascripts/panels/images/selection_spec.coffee +104 -0
- data/spec/javascripts/panels/sitemap/panel_spec.coffee +10 -0
- data/spec/javascripts/panels/sitemap/sortable_spec.coffee +63 -0
- data/spec/javascripts/panels/sitemap/tree_spec.coffee +62 -0
- data/spec/javascripts/spec_helper.coffee +25 -0
- data/spec/javascripts/support/stubs.coffee +16 -0
- data/spec/lib/page_responder_spec.rb +58 -0
- data/spec/lib/regions_proxy_spec.rb +47 -0
- data/spec/models/image_spec.rb +46 -0
- data/spec/models/page_spec.rb +237 -0
- data/spec/models/path_spec.rb +71 -0
- data/spec/models/region_spec.rb +14 -0
- data/spec/models/snippet_spec.rb +57 -0
- data/spec/models/version_spec.rb +7 -0
- data/spec/rails_app/.gitignore +33 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +9 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +7 -0
- data/spec/rails_app/app/cells/example/display.html.haml +2 -0
- data/spec/rails_app/app/cells/example/options.html.haml +15 -0
- data/spec/rails_app/app/cells/example_cell.rb +19 -0
- data/spec/rails_app/app/cells/image_example/display.html.haml +4 -0
- data/spec/rails_app/app/cells/image_example/options.html.haml +15 -0
- data/spec/rails_app/app/cells/image_example_cell.rb +18 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.gitkeep +0 -0
- data/spec/rails_app/app/models/.gitkeep +0 -0
- data/spec/rails_app/app/views/cmsimple/_snippet_list.html.haml +8 -0
- data/spec/rails_app/app/views/cmsimple/templates/default.html.haml +19 -0
- data/spec/rails_app/app/views/cmsimple/templates/test.html.haml +2 -0
- data/spec/rails_app/app/views/layouts/application.html.haml +13 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +65 -0
- data/spec/rails_app/config/boot.rb +9 -0
- data/spec/rails_app/config/database.example.yml +22 -0
- data/spec/rails_app/config/database.travis.yml +8 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +30 -0
- data/spec/rails_app/config/environments/test.rb +39 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/cells.rb +1 -0
- data/spec/rails_app/config/initializers/cmsimple.rb +3 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/rails_app/config/initializers/teabag.rb +58 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +61 -0
- data/spec/rails_app/db/seeds.rb +11 -0
- data/spec/rails_app/lib/assets/.gitkeep +0 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +26 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/active_model_lint_example.rb +14 -0
- data/spec/teabag_env.rb +28 -0
- data/vendor/assets/images/sitemap/has-changes.png +0 -0
- data/vendor/assets/images/sitemap/published.png +0 -0
- data/vendor/assets/images/sitemap/unpublished.png +0 -0
- data/vendor/assets/images/toolbar/metadata.png +0 -0
- data/vendor/assets/images/toolbar/publish.png +0 -0
- data/vendor/assets/images/toolbar/redirect.png +0 -0
- data/vendor/assets/images/toolbar/sitemap.png +0 -0
- data/vendor/assets/images/toolbar/snippets.png +0 -0
- data/vendor/assets/images/toolbar/unpublished.png +0 -0
- data/vendor/assets/images/tree-line-horizontal-last.png +0 -0
- data/vendor/assets/images/tree-line-horizontal.png +0 -0
- data/vendor/assets/images/tree-line-vertical.png +0 -0
- data/vendor/assets/javascripts/jquery-serializeObject.js +107 -0
- data/vendor/assets/javascripts/jquery.to-json.js +74 -0
- data/vendor/assets/javascripts/jquery.ui.nestedSortable-1.3.4.js +391 -0
- data/vendor/assets/javascripts/moment-1.6.2.js +918 -0
- data/vendor/assets/javascripts/underscore-1.3.1.js +31 -0
- data/vendor/assets/stylesheets/jasmine-modified.css +216 -0
- metadata +686 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# You can require javascript files here. A good place to start is by requiring your application.js.
|
|
2
|
+
# require application
|
|
3
|
+
#
|
|
4
|
+
# Teabag includes some support files, but you can use anything from your own support path too.
|
|
5
|
+
# require support/jasmine-jquery
|
|
6
|
+
# require support/sinon
|
|
7
|
+
# require support/your-support-file
|
|
8
|
+
#
|
|
9
|
+
# Deferring execution
|
|
10
|
+
# If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call Teabag.execute()
|
|
11
|
+
# after everything has been loaded. Simple example of a timeout:
|
|
12
|
+
#
|
|
13
|
+
# Teabag.defer = true
|
|
14
|
+
# setTimeout(Teabag.execute, 1000)
|
|
15
|
+
#
|
|
16
|
+
# Matching files
|
|
17
|
+
# By default Teabag will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
|
|
18
|
+
# spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
|
|
19
|
+
# configuration in config/initializers/teabag.rb
|
|
20
|
+
#
|
|
21
|
+
# Manifest
|
|
22
|
+
# If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
|
|
23
|
+
# the configuration and use this file as a manifest.
|
|
24
|
+
#
|
|
25
|
+
# For more information: http://github.com/modeset/teabag
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@.stubs = {}
|
|
2
|
+
stubs.ajax = ->
|
|
3
|
+
jqXHR = $.Deferred()
|
|
4
|
+
|
|
5
|
+
$.extend jqXHR,
|
|
6
|
+
readyState: 0
|
|
7
|
+
setRequestHeader: -> @
|
|
8
|
+
getAllResponseHeaders: -> null
|
|
9
|
+
getResponseHeader: -> null
|
|
10
|
+
overrideMimeType: -> @
|
|
11
|
+
abort: -> @
|
|
12
|
+
success: jqXHR.done
|
|
13
|
+
error: jqXHR.fail
|
|
14
|
+
complete: jqXHR.done
|
|
15
|
+
|
|
16
|
+
spyOn($, "ajax").andReturn(jqXHR)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Cmsimple::PageResponder do
|
|
4
|
+
let(:controller) { OpenStruct.new request: OpenStruct.new(params: @params || {}),
|
|
5
|
+
current_page: @page,
|
|
6
|
+
in_editor_iframe?: @editable }
|
|
7
|
+
|
|
8
|
+
it 'raises ActiveRecord::RecordnotFound if the page is not viewable' do
|
|
9
|
+
responder = Cmsimple::PageResponder.new(controller)
|
|
10
|
+
responder.should_receive(:current_page_is_viewable?).and_return(false)
|
|
11
|
+
expect { responder.respond }.to raise_error(ActiveRecord::RecordNotFound)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe 'current page is viewable' do
|
|
15
|
+
let(:responder) { responder = Cmsimple::PageResponder.new(controller) }
|
|
16
|
+
it 'is viewable if the request is in the editor iframe' do
|
|
17
|
+
@editable = true
|
|
18
|
+
responder.current_page_is_viewable?.should be_true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'is viewable if the page is published' do
|
|
22
|
+
@editable = false
|
|
23
|
+
@page = mock('page', :published? => true)
|
|
24
|
+
responder.current_page_is_viewable?.should be_true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'is not viewable if the request is not the editor iframe and the page is not published' do
|
|
28
|
+
@editable = false
|
|
29
|
+
@page = mock('page', :published? => false)
|
|
30
|
+
responder.current_page_is_viewable?.should be_false
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe 'page for context' do
|
|
35
|
+
let(:responder) { responder = Cmsimple::PageResponder.new(controller) }
|
|
36
|
+
it 'tries to use the published version of the page if the app is not in edit mode' do
|
|
37
|
+
@editable = false
|
|
38
|
+
@page = mock('page', :published? => true)
|
|
39
|
+
@page.should_receive(:as_published!).and_return(true)
|
|
40
|
+
responder.page_for_context
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'tries to use the published version of the page if the app is not in edit mode' do
|
|
44
|
+
@editable = true
|
|
45
|
+
@page = mock('page', :published? => true)
|
|
46
|
+
@params = {version: 1}
|
|
47
|
+
@page.should_receive(:at_version!).and_return(true)
|
|
48
|
+
responder.page_for_context
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'uses the current draft version by default' do
|
|
52
|
+
@editable = true
|
|
53
|
+
@page = mock('page', :published? => false)
|
|
54
|
+
responder.should_receive(:draft_context?)
|
|
55
|
+
responder.page_for_context
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
describe Cmsimple::RegionsProxy do
|
|
3
|
+
|
|
4
|
+
describe 'region proxy' do
|
|
5
|
+
it 'defines instance methods for each region in the hash' do
|
|
6
|
+
regions = Cmsimple::RegionsProxy.new content: {value: 'hello'}
|
|
7
|
+
regions.should respond_to :content
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'defines instance methods for each region in the hash' do
|
|
11
|
+
regions = Cmsimple::RegionsProxy.new content: {value: 'hello'}
|
|
12
|
+
regions.content.should be_a(Cmsimple::Region)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'returns a NillRegion if no region present' do
|
|
16
|
+
regions = Cmsimple::RegionsProxy.new nil
|
|
17
|
+
regions.content.should be_a(Cmsimple::Region)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe '#snippets_hash' do
|
|
22
|
+
before do
|
|
23
|
+
@regions = Cmsimple::RegionsProxy.new(
|
|
24
|
+
content: {value: "<div>some content</div><div>[snippet_0/0]</div>",
|
|
25
|
+
snippets: {snippet_0: {name: 'example',
|
|
26
|
+
options: { first_name: 'Fred',
|
|
27
|
+
last_name: 'Flinstone'
|
|
28
|
+
}}}},
|
|
29
|
+
header: {value: "<div>some content</div><div>[snippet_1/0]</div>",
|
|
30
|
+
snippets: {snippet_1: {name: 'example',
|
|
31
|
+
options: { first_name: 'Fred',
|
|
32
|
+
last_name: 'Flinstone'
|
|
33
|
+
}}}}
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "pull each snippet up into a single hash" do
|
|
38
|
+
@regions.snippets_hash.should have_key(:snippet_1)
|
|
39
|
+
@regions.snippets_hash.should have_key(:snippet_0)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "has only the snippets in the hash" do
|
|
43
|
+
@regions.snippets_hash.keys.length.should == 2
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
describe Cmsimple::Image do
|
|
3
|
+
include CarrierWave::Test::Matchers
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@file_fixture_path = Cmsimple::Engine.root.join('spec', 'fixtures', 'rails.png')
|
|
7
|
+
@file_fixture = File.open(@file_fixture_path)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
after do
|
|
11
|
+
@file_fixture.close
|
|
12
|
+
Cmsimple::Image.all.each { |img| img.attachment.remove! }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
subject { Cmsimple::Image.new }
|
|
16
|
+
it { should validate_presence_of(:attachment) }
|
|
17
|
+
|
|
18
|
+
describe 'image attachment uploader' do
|
|
19
|
+
it 'has an uploader mounted to attachment' do
|
|
20
|
+
subject.attachment.should be_a(ImageAttachmentUploader)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe 'attachment attributes' do
|
|
25
|
+
before do
|
|
26
|
+
@image = Cmsimple::Image.new attachment: @file_fixture
|
|
27
|
+
@image.save!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'sets content_type from the file' do
|
|
31
|
+
@image.content_type.should == 'image/png'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'sets file_size from the file' do
|
|
35
|
+
@image.file_size.should == @file_fixture.size
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'sets width from the file' do
|
|
39
|
+
@image.width.should == 50
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'sets height from the file' do
|
|
43
|
+
@image.height.should == 64
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
describe Cmsimple::Page do
|
|
3
|
+
subject { Cmsimple::Page.new }
|
|
4
|
+
it {should validate_presence_of(:title) }
|
|
5
|
+
it {should have_many(:children)}
|
|
6
|
+
it {should belong_to(:parent)}
|
|
7
|
+
it {should have_many(:versions)}
|
|
8
|
+
|
|
9
|
+
describe '#update_content' do
|
|
10
|
+
before do
|
|
11
|
+
subject.uri = '/about'
|
|
12
|
+
subject.save
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "updates content to a hash when json is given to #update_content" do
|
|
16
|
+
subject.update_content({'content' => 'hello world'})
|
|
17
|
+
subject.content.should be_a Hash
|
|
18
|
+
subject.content['content'].should == 'hello world'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#descendants' do
|
|
23
|
+
before do
|
|
24
|
+
@childless = Cmsimple::Page.create(title: 'Misc', uri: '/Misc')
|
|
25
|
+
@page = Cmsimple::Page.create(title: 'Home', uri: '/')
|
|
26
|
+
@child = Cmsimple::Page.create(title: 'About', uri: '/about')
|
|
27
|
+
@page.children << @child
|
|
28
|
+
@descendant = Cmsimple::Page.create(title: 'Contact', uri: '/about/contact')
|
|
29
|
+
@child.children << @descendant
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'retrieves all the descendants for a page' do
|
|
33
|
+
@page.descendants.map(&:title).should =~ ['About', 'Contact']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'returns nothing for a page with no descendants' do
|
|
37
|
+
@childless.descendants.should be_empty
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe '.for_parent_select' do
|
|
41
|
+
it 'only returns pages that arent direct descendants' do
|
|
42
|
+
Cmsimple::Page.for_parent_select(@page).map(&:title).should =~ ['Misc']
|
|
43
|
+
Cmsimple::Page.for_parent_select(@child).map(&:title).should =~ ['Misc', 'Home']
|
|
44
|
+
Cmsimple::Page.for_parent_select(@childless).map(&:title).should =~ ['Home', 'About', 'Contact']
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#root' do
|
|
49
|
+
it "returns the root of the page tree" do
|
|
50
|
+
@descendant.root.id.should == @page.id
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "returns the current page if it is a root" do
|
|
54
|
+
@page.root.id.should == @page.id
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe 'path generation' do
|
|
60
|
+
|
|
61
|
+
it 'returns a default slug from the title' do
|
|
62
|
+
subject.title = 'About Us'
|
|
63
|
+
subject.slug.should == 'about-us'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "doesn't override the slug if it is manually set" do
|
|
67
|
+
subject.slug = 'about'
|
|
68
|
+
subject.title = 'About Us'
|
|
69
|
+
subject.slug.should == 'about'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'saves the default slug' do
|
|
73
|
+
subject.title = 'About Us'
|
|
74
|
+
subject.save
|
|
75
|
+
Cmsimple::Page.find(subject.id).slug.should == 'about-us'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'sets the path to the the slug on save if no parent' do
|
|
79
|
+
subject.title = 'About Us'
|
|
80
|
+
subject.save
|
|
81
|
+
Cmsimple::Page.find(subject.id).uri.should == '/about-us'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'sets the path to the the slug on save if no parent' do
|
|
85
|
+
about = Cmsimple::Page.create title: 'About'
|
|
86
|
+
subject.parent = about
|
|
87
|
+
subject.title = 'Contact Us'
|
|
88
|
+
subject.save
|
|
89
|
+
Cmsimple::Page.find(subject.id).uri.should == '/about/contact-us'
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe 'can only have one root page' do
|
|
94
|
+
before do
|
|
95
|
+
subject.title = 'About Us'
|
|
96
|
+
subject.is_root = true
|
|
97
|
+
subject.save
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'can only have one root' do
|
|
101
|
+
Cmsimple::Page.create title: 'About', is_root: true
|
|
102
|
+
Cmsimple::Page.where(is_root: true).count.should == 1
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'must have at least one root' do
|
|
106
|
+
subject.is_root = false
|
|
107
|
+
subject.should_not be_valid
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
describe 'paths' do
|
|
112
|
+
it 'creates a path after save' do
|
|
113
|
+
expect { Cmsimple::Page.create title: 'About' }.to change{ Cmsimple::Path.count }.by(1)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "doesn't create a path if one already exists with the same uri" do
|
|
117
|
+
Cmsimple::Path.create uri: '/about', redirect_uri: '/'
|
|
118
|
+
expect { Cmsimple::Page.create title: 'About' }.to change{ Cmsimple::Path.count }.by(0)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe 'publishing' do
|
|
123
|
+
let(:page) { Cmsimple::Page.create title: 'About' }
|
|
124
|
+
|
|
125
|
+
it "has published_at set to nil by default" do
|
|
126
|
+
page.published_at.should be_nil
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe '#publish!' do
|
|
130
|
+
it 'sets the published_at date to now' do
|
|
131
|
+
Timecop.freeze(Time.now) do
|
|
132
|
+
page.publish!
|
|
133
|
+
page.published_at.to_s.should == Time.zone.now.to_s
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'creates a new published verson' do
|
|
138
|
+
expect { page.publish! }.to change { page.versions.count }.by(1)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe '#unpublished_changes?' do
|
|
143
|
+
it 'has unpublished changes if it was never published' do
|
|
144
|
+
page.published_at.should be_nil
|
|
145
|
+
page.unpublished_changes?.should be_true
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'does not have unpublished changes once it is published' do
|
|
149
|
+
page.publish!
|
|
150
|
+
page.unpublished_changes?.should be_false
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
describe '#unpublish!' do
|
|
155
|
+
before do
|
|
156
|
+
page.publish!
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'sets published_at to nil' do
|
|
160
|
+
page.unpublish!
|
|
161
|
+
page.published_at.should be_nil
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe 'published scope' do
|
|
166
|
+
it 'returns the published page' do
|
|
167
|
+
page.publish!
|
|
168
|
+
Cmsimple::Page.published.first.should == page
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'does not return the page if it is not published' do
|
|
172
|
+
Cmsimple::Page.published.first.should be_nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'does not return the page if it is to be published in the future' do
|
|
176
|
+
page.published_at = 2.weeks.from_now
|
|
177
|
+
page.save!
|
|
178
|
+
Cmsimple::Page.published.first.should be_nil
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
describe 'consuming published content' do
|
|
183
|
+
before do
|
|
184
|
+
page.update_content({:content => {:value => 'content version 1'}})
|
|
185
|
+
page.publish!
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it 'returns puslished content when in published mode if there are unpublished changes' do
|
|
189
|
+
page.update_content({:content => {:value => 'content version 2'}})
|
|
190
|
+
page.as_published!
|
|
191
|
+
page.regions.content.to_s.should == 'content version 1'
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe 'versioning' do
|
|
197
|
+
let(:page) { Cmsimple::Page.create title: 'About' }
|
|
198
|
+
|
|
199
|
+
before do
|
|
200
|
+
page.update_content({:content => {:value => 'content version 1'}})
|
|
201
|
+
page.publish!
|
|
202
|
+
page.update_content({:content => {:value => 'content version 2'}})
|
|
203
|
+
page.publish!
|
|
204
|
+
page.update_content({:content => {:value => 'content version 3'}})
|
|
205
|
+
page.publish!
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe 'can return a page at a specific version' do
|
|
209
|
+
it 'returns the page with the content from the requested version' do
|
|
210
|
+
version = page.versions.first
|
|
211
|
+
page.at_version!(version.id)
|
|
212
|
+
page.regions.content.to_s.should == 'content version 1'
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it 'returns the page with the content from another requested version' do
|
|
216
|
+
version = page.versions.second
|
|
217
|
+
page.at_version!(version.id)
|
|
218
|
+
page.regions.content.to_s.should == 'content version 2'
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
describe 'reverting' do
|
|
223
|
+
it 'can revert to a specific version' do
|
|
224
|
+
version = page.versions.first
|
|
225
|
+
page.revert_to!(version.id)
|
|
226
|
+
Cmsimple::Page.find(page.id).regions.content.to_s.should == 'content version 1'
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it 'can not revert to a version that is not from the pages history' do
|
|
230
|
+
other_page = Cmsimple::Page.create title: 'Contact'
|
|
231
|
+
other_page.update_content({:content => {:value => 'content version 1'}})
|
|
232
|
+
other_page.publish!
|
|
233
|
+
expect{ page.revert_to!(other_page.versions.first.id) }.to raise_error(ActiveRecord::RecordNotFound)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
describe Cmsimple::Path do
|
|
3
|
+
subject { Cmsimple::Path.new }
|
|
4
|
+
it { should validate_presence_of(:uri) }
|
|
5
|
+
it { should belong_to(:page) }
|
|
6
|
+
|
|
7
|
+
it 'downcases its URI on save' do
|
|
8
|
+
page = Cmsimple::Page.create title: 'Test'
|
|
9
|
+
path = Cmsimple::Path.create page: page, uri: '/TestRedirect'
|
|
10
|
+
path.uri.should == '/testredirect'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe 'destination' do
|
|
14
|
+
|
|
15
|
+
it 'is required' do
|
|
16
|
+
subject.should_not be_valid
|
|
17
|
+
subject.errors[:destination].should_not be_empty
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'returns the destination path when a page is associated' do
|
|
21
|
+
subject.page = Cmsimple::Page.new uri: '/some-path'
|
|
22
|
+
subject.destination.uri.should == '/some-path'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'returns the destination path when it is a redirect' do
|
|
26
|
+
subject.redirect_uri = '/some-other-path'
|
|
27
|
+
subject.destination.uri.should == '/some-other-path'
|
|
28
|
+
subject.should be_redirect
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'returns a redirect if the path does not match the page path' do
|
|
32
|
+
subject.uri = '/path'
|
|
33
|
+
subject.page = Cmsimple::Page.new uri: '/some-other-path'
|
|
34
|
+
subject.destination.should be_a(Cmsimple::Path::Redirect)
|
|
35
|
+
subject.should be_redirect
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe 'from_request' do
|
|
41
|
+
|
|
42
|
+
it 'returns the path that has a uri mathing the request path' do
|
|
43
|
+
subject.uri = '/path'
|
|
44
|
+
subject.redirect_uri = '/some-other-path'
|
|
45
|
+
subject.save
|
|
46
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: '/path')).destination.uri.should == '/some-other-path'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "returns the path with the associated page" do
|
|
50
|
+
page = Cmsimple::Page.create title: 'About'
|
|
51
|
+
Cmsimple::Path.create uri: '/about', page: page
|
|
52
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: '/about')).destination.title.should == 'About'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "returns the path where the associated page is marked as root" do
|
|
56
|
+
page = Cmsimple::Page.create title: 'Home', is_root: true
|
|
57
|
+
Cmsimple::Path.create uri: '/home', page: page
|
|
58
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: '/')).destination.title.should == 'Home'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "normalizes the path before querying" do
|
|
62
|
+
subject.uri = '/path'
|
|
63
|
+
subject.redirect_uri = '/some-other-path'
|
|
64
|
+
subject.save
|
|
65
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: '//path')).destination.uri.should == '/some-other-path'
|
|
66
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: '//path/')).destination.uri.should == '/some-other-path'
|
|
67
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: 'path')).destination.uri.should == '/some-other-path'
|
|
68
|
+
Cmsimple::Path.from_request(OpenStruct.new(path: '/Path')).destination.uri.should == '/some-other-path'
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|