lc_alchemy_cms 3.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.
- checksums.yaml +7 -0
- data/.editorconfig +23 -0
- data/.gitignore +21 -0
- data/.hound.yml +2 -0
- data/.rspec +1 -0
- data/.rubocop.yml +861 -0
- data/.teatro.yml +7 -0
- data/.travis.yml +27 -0
- data/.yardopts +5 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +73 -0
- data/Gemfile +34 -0
- data/LICENSE +27 -0
- data/README.md +297 -0
- data/Rakefile +48 -0
- data/alchemy_cms.gemspec +81 -0
- data/app/assets/fonts/alchemy/icons.eot +0 -0
- data/app/assets/fonts/alchemy/icons.svg +71 -0
- data/app/assets/fonts/alchemy/icons.ttf +0 -0
- data/app/assets/fonts/alchemy/icons.woff +0 -0
- data/app/assets/images/alchemy/alchemy-logo.svg +70 -0
- data/app/assets/images/alchemy/favicon.ico +0 -0
- data/app/assets/images/alchemy/icon.svg +14 -0
- data/app/assets/images/alchemy/icons.png +0 -0
- data/app/assets/images/alchemy/lupe.cur +0 -0
- data/app/assets/images/alchemy/ui-icons_666666_256x240.png +0 -0
- data/app/assets/images/sassy-ie-overlay.png +0 -0
- data/app/assets/javascripts/alchemy/alchemy.autocomplete.js.coffee +30 -0
- data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +142 -0
- data/app/assets/javascripts/alchemy/alchemy.browser.js.coffee +22 -0
- data/app/assets/javascripts/alchemy/alchemy.buttons.js.coffee +32 -0
- data/app/assets/javascripts/alchemy/alchemy.char_counter.js.coffee +19 -0
- data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +85 -0
- data/app/assets/javascripts/alchemy/alchemy.custom.js +1 -0
- data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +31 -0
- data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +266 -0
- data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +70 -0
- data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +84 -0
- data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +138 -0
- data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +89 -0
- data/app/assets/javascripts/alchemy/alchemy.file_progress.js.coffee +63 -0
- data/app/assets/javascripts/alchemy/alchemy.growler.js.coffee +27 -0
- data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +22 -0
- data/app/assets/javascripts/alchemy/alchemy.hotkeys.js.coffee +49 -0
- data/app/assets/javascripts/alchemy/alchemy.html5.js +22 -0
- data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +26 -0
- data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +44 -0
- data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +63 -0
- data/app/assets/javascripts/alchemy/alchemy.jquery_loader.js +42 -0
- data/app/assets/javascripts/alchemy/alchemy.js +52 -0
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +250 -0
- data/app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee +49 -0
- data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +48 -0
- data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +106 -0
- data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +58 -0
- data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +50 -0
- data/app/assets/javascripts/alchemy/alchemy.spinner.js.coffee +49 -0
- data/app/assets/javascripts/alchemy/alchemy.string_extension.js.coffee +11 -0
- data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +66 -0
- data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +132 -0
- data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +102 -0
- data/app/assets/javascripts/alchemy/alchemy.windows.js.coffee +42 -0
- data/app/assets/javascripts/alchemy/menubar.js.coffee +8 -0
- data/app/assets/javascripts/alchemy/preview.js +1 -0
- data/app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js +19 -0
- data/app/assets/stylesheets/alchemy/_defaults.scss +8 -0
- data/app/assets/stylesheets/alchemy/_extends.scss +93 -0
- data/app/assets/stylesheets/alchemy/_mixins.scss +112 -0
- data/app/assets/stylesheets/alchemy/_variables.scss +61 -0
- data/app/assets/stylesheets/alchemy/admin.scss +31 -0
- data/app/assets/stylesheets/alchemy/archive.scss +436 -0
- data/app/assets/stylesheets/alchemy/base.scss +609 -0
- data/app/assets/stylesheets/alchemy/buttons.scss +259 -0
- data/app/assets/stylesheets/alchemy/custom.scss +1 -0
- data/app/assets/stylesheets/alchemy/dashboard.scss +104 -0
- data/app/assets/stylesheets/alchemy/dialogs.scss +214 -0
- data/app/assets/stylesheets/alchemy/elements.scss +772 -0
- data/app/assets/stylesheets/alchemy/errors.scss +39 -0
- data/app/assets/stylesheets/alchemy/flash.scss +65 -0
- data/app/assets/stylesheets/alchemy/form_fields.scss +89 -0
- data/app/assets/stylesheets/alchemy/forms.scss +193 -0
- data/app/assets/stylesheets/alchemy/frame.scss +301 -0
- data/app/assets/stylesheets/alchemy/icon-font.scss +67 -0
- data/app/assets/stylesheets/alchemy/icons.scss +324 -0
- data/app/assets/stylesheets/alchemy/jquery-ui.scss +1511 -0
- data/app/assets/stylesheets/alchemy/menubar.scss +81 -0
- data/app/assets/stylesheets/alchemy/modules.scss +33 -0
- data/app/assets/stylesheets/alchemy/notices.scss +64 -0
- data/app/assets/stylesheets/alchemy/pagination.scss +65 -0
- data/app/assets/stylesheets/alchemy/print.scss +34 -0
- data/app/assets/stylesheets/alchemy/search.scss +73 -0
- data/app/assets/stylesheets/alchemy/selects.scss +235 -0
- data/app/assets/stylesheets/alchemy/sitemap.scss +385 -0
- data/app/assets/stylesheets/alchemy/tables.scss +218 -0
- data/app/assets/stylesheets/alchemy/toolbar.scss +146 -0
- data/app/assets/stylesheets/alchemy/upload.scss +121 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +90 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/readme.md +1 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.eot +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.svg +175 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.ttf +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.woff +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.eot +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.svg +153 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.ttf +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.woff +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/anchor.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/loader.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/object.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/trans.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/wline.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/skin.ie7.min.css +1 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +1810 -0
- data/app/controllers/alchemy/admin/attachments_controller.rb +106 -0
- data/app/controllers/alchemy/admin/base_controller.rb +168 -0
- data/app/controllers/alchemy/admin/clipboard_controller.rb +51 -0
- data/app/controllers/alchemy/admin/contents_controller.rb +76 -0
- data/app/controllers/alchemy/admin/dashboard_controller.rb +89 -0
- data/app/controllers/alchemy/admin/elements_controller.rb +190 -0
- data/app/controllers/alchemy/admin/essence_files_controller.rb +47 -0
- data/app/controllers/alchemy/admin/essence_pictures_controller.rb +120 -0
- data/app/controllers/alchemy/admin/languages_controller.rb +17 -0
- data/app/controllers/alchemy/admin/layoutpages_controller.rb +19 -0
- data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +39 -0
- data/app/controllers/alchemy/admin/pages_controller.rb +359 -0
- data/app/controllers/alchemy/admin/pictures_controller.rb +168 -0
- data/app/controllers/alchemy/admin/resources_controller.rb +185 -0
- data/app/controllers/alchemy/admin/sites_controller.rb +6 -0
- data/app/controllers/alchemy/admin/tags_controller.rb +76 -0
- data/app/controllers/alchemy/admin/trash_controller.rb +27 -0
- data/app/controllers/alchemy/api/base_controller.rb +19 -0
- data/app/controllers/alchemy/api/contents_controller.rb +35 -0
- data/app/controllers/alchemy/api/elements_controller.rb +29 -0
- data/app/controllers/alchemy/api/pages_controller.rb +32 -0
- data/app/controllers/alchemy/attachments_controller.rb +35 -0
- data/app/controllers/alchemy/base_controller.rb +106 -0
- data/app/controllers/alchemy/elements_controller.rb +27 -0
- data/app/controllers/alchemy/messages_controller.rb +114 -0
- data/app/controllers/alchemy/pages_controller.rb +211 -0
- data/app/controllers/alchemy/pictures_controller.rb +82 -0
- data/app/helpers/alchemy/admin/attachments_helper.rb +12 -0
- data/app/helpers/alchemy/admin/base_helper.rb +471 -0
- data/app/helpers/alchemy/admin/contents_helper.rb +113 -0
- data/app/helpers/alchemy/admin/elements_helper.rb +134 -0
- data/app/helpers/alchemy/admin/essences_helper.rb +120 -0
- data/app/helpers/alchemy/admin/form_helper.rb +30 -0
- data/app/helpers/alchemy/admin/navigation_helper.rb +238 -0
- data/app/helpers/alchemy/admin/pages_helper.rb +70 -0
- data/app/helpers/alchemy/admin/pictures_helper.rb +30 -0
- data/app/helpers/alchemy/admin/tags_helper.rb +102 -0
- data/app/helpers/alchemy/base_helper.rb +81 -0
- data/app/helpers/alchemy/elements_block_helper.rb +162 -0
- data/app/helpers/alchemy/elements_helper.rb +291 -0
- data/app/helpers/alchemy/essences_helper.rb +138 -0
- data/app/helpers/alchemy/pages_helper.rb +417 -0
- data/app/helpers/alchemy/url_helper.rb +76 -0
- data/app/mailers/alchemy/messages.rb +15 -0
- data/app/models/alchemy.rb +7 -0
- data/app/models/alchemy/attachment.rb +129 -0
- data/app/models/alchemy/cell.rb +94 -0
- data/app/models/alchemy/content.rb +255 -0
- data/app/models/alchemy/content/factory.rb +190 -0
- data/app/models/alchemy/element.rb +513 -0
- data/app/models/alchemy/element/definitions.rb +52 -0
- data/app/models/alchemy/element/presenters.rb +87 -0
- data/app/models/alchemy/element_to_page.rb +7 -0
- data/app/models/alchemy/essence_boolean.rb +19 -0
- data/app/models/alchemy/essence_date.rb +24 -0
- data/app/models/alchemy/essence_file.rb +42 -0
- data/app/models/alchemy/essence_html.rb +23 -0
- data/app/models/alchemy/essence_link.rb +20 -0
- data/app/models/alchemy/essence_picture.rb +152 -0
- data/app/models/alchemy/essence_richtext.rb +47 -0
- data/app/models/alchemy/essence_select.rb +18 -0
- data/app/models/alchemy/essence_text.rb +22 -0
- data/app/models/alchemy/folded_page.rb +16 -0
- data/app/models/alchemy/language.rb +144 -0
- data/app/models/alchemy/language/code.rb +22 -0
- data/app/models/alchemy/legacy_page_url.rb +20 -0
- data/app/models/alchemy/message.rb +40 -0
- data/app/models/alchemy/page.rb +409 -0
- data/app/models/alchemy/page/page_cells.rb +71 -0
- data/app/models/alchemy/page/page_elements.rb +272 -0
- data/app/models/alchemy/page/page_naming.rb +122 -0
- data/app/models/alchemy/page/page_natures.rb +114 -0
- data/app/models/alchemy/page/page_scopes.rb +95 -0
- data/app/models/alchemy/page/page_users.rb +58 -0
- data/app/models/alchemy/picture.rb +220 -0
- data/app/models/alchemy/picture/sweeping.rb +17 -0
- data/app/models/alchemy/picture/transformations.rb +256 -0
- data/app/models/alchemy/site.rb +91 -0
- data/app/models/alchemy/site/layout.rb +38 -0
- data/app/models/alchemy/tag.rb +24 -0
- data/app/models/alchemy/translations.rb +7 -0
- data/app/models/alchemy/translations/essence_body_updater.rb +64 -0
- data/app/models/alchemy/translations/translation_pusher.rb +18 -0
- data/app/models/alchemy/tree_node.rb +4 -0
- data/app/serializers/alchemy/attachment_serializer.rb +15 -0
- data/app/serializers/alchemy/cell_serializer.rb +18 -0
- data/app/serializers/alchemy/content_serializer.rb +20 -0
- data/app/serializers/alchemy/element_serializer.rb +20 -0
- data/app/serializers/alchemy/essence_boolean_serializer.rb +11 -0
- data/app/serializers/alchemy/essence_date_serializer.rb +11 -0
- data/app/serializers/alchemy/essence_file_serializer.rb +12 -0
- data/app/serializers/alchemy/essence_html_serializer.rb +11 -0
- data/app/serializers/alchemy/essence_link_serializer.rb +14 -0
- data/app/serializers/alchemy/essence_picture_serializer.rb +28 -0
- data/app/serializers/alchemy/essence_richtext_serializer.rb +12 -0
- data/app/serializers/alchemy/essence_select_serializer.rb +11 -0
- data/app/serializers/alchemy/essence_text_serializer.rb +22 -0
- data/app/serializers/alchemy/legacy_element_serializer.rb +17 -0
- data/app/serializers/alchemy/page_serializer.rb +29 -0
- data/app/serializers/alchemy/picture_serializer.rb +16 -0
- data/app/views/alchemy/_menubar.html.erb +16 -0
- data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +32 -0
- data/app/views/alchemy/admin/attachments/_attachment.html.erb +63 -0
- data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +15 -0
- data/app/views/alchemy/admin/attachments/_files_list.html.erb +39 -0
- data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +11 -0
- data/app/views/alchemy/admin/attachments/_tag_list.html.erb +14 -0
- data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +7 -0
- data/app/views/alchemy/admin/attachments/create.js.erb +11 -0
- data/app/views/alchemy/admin/attachments/destroy.js.erb +1 -0
- data/app/views/alchemy/admin/attachments/edit.html.erb +10 -0
- data/app/views/alchemy/admin/attachments/index.html.erb +29 -0
- data/app/views/alchemy/admin/attachments/new.html.erb +14 -0
- data/app/views/alchemy/admin/attachments/show.html.erb +3 -0
- data/app/views/alchemy/admin/clipboard/clear.js.erb +3 -0
- data/app/views/alchemy/admin/clipboard/index.html.erb +22 -0
- data/app/views/alchemy/admin/clipboard/insert.js.erb +19 -0
- data/app/views/alchemy/admin/clipboard/remove.js.erb +10 -0
- data/app/views/alchemy/admin/contents/_missing.html.erb +19 -0
- data/app/views/alchemy/admin/contents/create.js.erb +56 -0
- data/app/views/alchemy/admin/contents/destroy.js.erb +4 -0
- data/app/views/alchemy/admin/contents/new.html.erb +11 -0
- data/app/views/alchemy/admin/contents/order.js.erb +3 -0
- data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +38 -0
- data/app/views/alchemy/admin/dashboard/_recent_pages.html.erb +22 -0
- data/app/views/alchemy/admin/dashboard/_sites.html.erb +23 -0
- data/app/views/alchemy/admin/dashboard/_users.html.erb +19 -0
- data/app/views/alchemy/admin/dashboard/help.html.erb +21 -0
- data/app/views/alchemy/admin/dashboard/index.html.erb +44 -0
- data/app/views/alchemy/admin/dashboard/info.html.erb +64 -0
- data/app/views/alchemy/admin/elements/_add_picture.html.erb +14 -0
- data/app/views/alchemy/admin/elements/_element.html.erb +23 -0
- data/app/views/alchemy/admin/elements/_element_foot.html.erb +36 -0
- data/app/views/alchemy/admin/elements/_element_head.html.erb +23 -0
- data/app/views/alchemy/admin/elements/_new_element_form.html.erb +26 -0
- data/app/views/alchemy/admin/elements/_picture_gallery_editor.html.erb +24 -0
- data/app/views/alchemy/admin/elements/_refresh_editor.js.erb +8 -0
- data/app/views/alchemy/admin/elements/create.js.erb +46 -0
- data/app/views/alchemy/admin/elements/fold.js.erb +28 -0
- data/app/views/alchemy/admin/elements/index.html.erb +26 -0
- data/app/views/alchemy/admin/elements/list.html.erb +16 -0
- data/app/views/alchemy/admin/elements/new.html.erb +25 -0
- data/app/views/alchemy/admin/elements/order.js.erb +14 -0
- data/app/views/alchemy/admin/elements/trash.js.erb +12 -0
- data/app/views/alchemy/admin/elements/update.js.erb +28 -0
- data/app/views/alchemy/admin/essence_files/assign.js.erb +9 -0
- data/app/views/alchemy/admin/essence_files/edit.html.erb +18 -0
- data/app/views/alchemy/admin/essence_pictures/assign.js.erb +18 -0
- data/app/views/alchemy/admin/essence_pictures/crop.html.erb +50 -0
- data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +24 -0
- data/app/views/alchemy/admin/essence_pictures/edit.html.erb +28 -0
- data/app/views/alchemy/admin/essence_pictures/save_link.js.erb +3 -0
- data/app/views/alchemy/admin/essence_pictures/update.js.erb +9 -0
- data/app/views/alchemy/admin/languages/_form.html.erb +14 -0
- data/app/views/alchemy/admin/languages/_language.html.erb +42 -0
- data/app/views/alchemy/admin/languages/_table.html.erb +37 -0
- data/app/views/alchemy/admin/languages/index.html.erb +23 -0
- data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +63 -0
- data/app/views/alchemy/admin/layoutpages/edit.html.erb +15 -0
- data/app/views/alchemy/admin/layoutpages/index.html.erb +41 -0
- data/app/views/alchemy/admin/leave.html.erb +11 -0
- data/app/views/alchemy/admin/legacy_page_urls/_form.html.erb +5 -0
- data/app/views/alchemy/admin/legacy_page_urls/_label.html.erb +1 -0
- data/app/views/alchemy/admin/legacy_page_urls/_legacy_page_url.html.erb +13 -0
- data/app/views/alchemy/admin/legacy_page_urls/_new.html.erb +20 -0
- data/app/views/alchemy/admin/legacy_page_urls/create.js.erb +10 -0
- data/app/views/alchemy/admin/legacy_page_urls/destroy.js.erb +6 -0
- data/app/views/alchemy/admin/legacy_page_urls/update.js.erb +2 -0
- data/app/views/alchemy/admin/pages/_create_language_form.html.erb +54 -0
- data/app/views/alchemy/admin/pages/_external_link.html.erb +31 -0
- data/app/views/alchemy/admin/pages/_file_link.html.erb +31 -0
- data/app/views/alchemy/admin/pages/_form.html.erb +62 -0
- data/app/views/alchemy/admin/pages/_internal_link.html.erb +41 -0
- data/app/views/alchemy/admin/pages/_legacy_urls.html.erb +23 -0
- data/app/views/alchemy/admin/pages/_locked_page.html.erb +24 -0
- data/app/views/alchemy/admin/pages/_new_page_form.html.erb +11 -0
- data/app/views/alchemy/admin/pages/_page.html.erb +112 -0
- data/app/views/alchemy/admin/pages/_page_for_links.html.erb +45 -0
- data/app/views/alchemy/admin/pages/_page_status.html.erb +14 -0
- data/app/views/alchemy/admin/pages/_sitemap.html.erb +8 -0
- data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +13 -0
- data/app/views/alchemy/admin/pages/configure.html.erb +16 -0
- data/app/views/alchemy/admin/pages/configure_external.html.erb +33 -0
- data/app/views/alchemy/admin/pages/destroy.js.erb +19 -0
- data/app/views/alchemy/admin/pages/edit.html.erb +206 -0
- data/app/views/alchemy/admin/pages/flush.js.erb +2 -0
- data/app/views/alchemy/admin/pages/fold.js.erb +3 -0
- data/app/views/alchemy/admin/pages/index.html.erb +101 -0
- data/app/views/alchemy/admin/pages/info.html.erb +43 -0
- data/app/views/alchemy/admin/pages/link.html.erb +16 -0
- data/app/views/alchemy/admin/pages/locked.html.erb +3 -0
- data/app/views/alchemy/admin/pages/new.html.erb +26 -0
- data/app/views/alchemy/admin/pages/show.html.erb +1 -0
- data/app/views/alchemy/admin/pages/sort.js.erb +5 -0
- data/app/views/alchemy/admin/pages/unlock.js.erb +8 -0
- data/app/views/alchemy/admin/pages/update.js.erb +37 -0
- data/app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb +1 -0
- data/app/views/alchemy/admin/partials/_flash.html.erb +4 -0
- data/app/views/alchemy/admin/partials/_flash_notices.html.erb +5 -0
- data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +11 -0
- data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +12 -0
- data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +33 -0
- data/app/views/alchemy/admin/partials/_routes.html.erb +25 -0
- data/app/views/alchemy/admin/partials/_search_form.html.erb +20 -0
- data/app/views/alchemy/admin/partials/_sub_navigation.html.erb +8 -0
- data/app/views/alchemy/admin/partials/_toolbar_button.html.erb +25 -0
- data/app/views/alchemy/admin/partials/_upload_form.html.erb +67 -0
- data/app/views/alchemy/admin/pictures/_archive.html.erb +53 -0
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +14 -0
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +78 -0
- data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +33 -0
- data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +11 -0
- data/app/views/alchemy/admin/pictures/_picture.html.erb +87 -0
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +28 -0
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +16 -0
- data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +8 -0
- data/app/views/alchemy/admin/pictures/edit.html.erb +13 -0
- data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +30 -0
- data/app/views/alchemy/admin/pictures/flush.js.erb +2 -0
- data/app/views/alchemy/admin/pictures/index.html.erb +109 -0
- data/app/views/alchemy/admin/pictures/index.js.erb +3 -0
- data/app/views/alchemy/admin/pictures/info.html.erb +38 -0
- data/app/views/alchemy/admin/pictures/new.html.erb +16 -0
- data/app/views/alchemy/admin/pictures/show.html.erb +11 -0
- data/app/views/alchemy/admin/resources/_form.html.erb +13 -0
- data/app/views/alchemy/admin/resources/_resource.html.erb +30 -0
- data/app/views/alchemy/admin/resources/_table.html.erb +25 -0
- data/app/views/alchemy/admin/resources/edit.html.erb +1 -0
- data/app/views/alchemy/admin/resources/index.csv.erb +13 -0
- data/app/views/alchemy/admin/resources/index.html.erb +32 -0
- data/app/views/alchemy/admin/resources/new.html.erb +1 -0
- data/app/views/alchemy/admin/sites/index.html.erb +23 -0
- data/app/views/alchemy/admin/tags/_radio_tag.html.erb +6 -0
- data/app/views/alchemy/admin/tags/_tag.html.erb +30 -0
- data/app/views/alchemy/admin/tags/edit.html.erb +24 -0
- data/app/views/alchemy/admin/tags/index.html.erb +52 -0
- data/app/views/alchemy/admin/tags/new.html.erb +7 -0
- data/app/views/alchemy/admin/trash/clear.js.erb +4 -0
- data/app/views/alchemy/admin/trash/index.html.erb +29 -0
- data/app/views/alchemy/attachments/show.html.erb +1 -0
- data/app/views/alchemy/base/500.html.erb +26 -0
- data/app/views/alchemy/base/error_notice.html.erb +1 -0
- data/app/views/alchemy/base/error_notice.js.erb +2 -0
- data/app/views/alchemy/base/permission_denied.js.erb +3 -0
- data/app/views/alchemy/base/redirect.js.erb +12 -0
- data/app/views/alchemy/base/update.js.erb +5 -0
- data/app/views/alchemy/breadcrumb/_page.html.erb +16 -0
- data/app/views/alchemy/breadcrumb/_separator.html.erb +1 -0
- data/app/views/alchemy/breadcrumb/_wrapper.html.erb +13 -0
- data/app/views/alchemy/elements/_editor_not_found.html.erb +5 -0
- data/app/views/alchemy/elements/_view_not_found.html.erb +1 -0
- data/app/views/alchemy/elements/show.html.erb +1 -0
- data/app/views/alchemy/elements/show.js.erb +1 -0
- data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +16 -0
- data/app/views/alchemy/essences/_essence_boolean_view.html.erb +3 -0
- data/app/views/alchemy/essences/_essence_date_editor.html.erb +19 -0
- data/app/views/alchemy/essences/_essence_date_view.html.erb +11 -0
- data/app/views/alchemy/essences/_essence_file_editor.html.erb +57 -0
- data/app/views/alchemy/essences/_essence_file_view.html.erb +10 -0
- data/app/views/alchemy/essences/_essence_html_editor.html.erb +9 -0
- data/app/views/alchemy/essences/_essence_html_view.html.erb +3 -0
- data/app/views/alchemy/essences/_essence_link_editor.html.erb +25 -0
- data/app/views/alchemy/essences/_essence_link_view.html.erb +11 -0
- data/app/views/alchemy/essences/_essence_picture_editor.html.erb +59 -0
- data/app/views/alchemy/essences/_essence_picture_view.html.erb +5 -0
- data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +13 -0
- data/app/views/alchemy/essences/_essence_richtext_view.html.erb +5 -0
- data/app/views/alchemy/essences/_essence_select_editor.html.erb +25 -0
- data/app/views/alchemy/essences/_essence_select_view.html.erb +3 -0
- data/app/views/alchemy/essences/_essence_text_editor.html.erb +18 -0
- data/app/views/alchemy/essences/_essence_text_view.html.erb +18 -0
- data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +61 -0
- data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +19 -0
- data/app/views/alchemy/language_links/_language.html.erb +12 -0
- data/app/views/alchemy/language_links/_spacer.html.erb +1 -0
- data/app/views/alchemy/messages/contact_form_mail.de.text.erb +12 -0
- data/app/views/alchemy/messages/contact_form_mail.en.text.erb +12 -0
- data/app/views/alchemy/messages/contact_form_mail.es.text.erb +12 -0
- data/app/views/alchemy/messages/new.html.erb +1 -0
- data/app/views/alchemy/navigation/_image_link.html.erb +14 -0
- data/app/views/alchemy/navigation/_link.html.erb +20 -0
- data/app/views/alchemy/navigation/_renderer.html.erb +30 -0
- data/app/views/alchemy/pages/show.html.erb +1 -0
- data/app/views/alchemy/pages/show.rss.builder +20 -0
- data/app/views/alchemy/pages/sitemap.xml.erb +6 -0
- data/app/views/kaminari/alchemy/_first_page.html.erb +11 -0
- data/app/views/kaminari/alchemy/_gap.html.erb +8 -0
- data/app/views/kaminari/alchemy/_last_page.html.erb +11 -0
- data/app/views/kaminari/alchemy/_next_page.html.erb +13 -0
- data/app/views/kaminari/alchemy/_page.html.erb +14 -0
- data/app/views/kaminari/alchemy/_paginator.html.erb +23 -0
- data/app/views/kaminari/alchemy/_prev_page.html.erb +13 -0
- data/app/views/layouts/alchemy/admin.html.erb +109 -0
- data/app/views/layouts/alchemy/sitemap.xml.erb +4 -0
- data/bin/alchemy +267 -0
- data/bin/rails +8 -0
- data/config/alchemy/config.yml +189 -0
- data/config/alchemy/modules.yml +88 -0
- data/config/initializers/dragonfly.rb +25 -0
- data/config/initializers/simple_form.rb +144 -0
- data/config/locales/alchemy.de.yml +918 -0
- data/config/locales/alchemy.en.yml +920 -0
- data/config/locales/alchemy.es.yml +958 -0
- data/config/locales/alchemy.fr.yml +942 -0
- data/config/locales/alchemy.nl.yml +921 -0
- data/config/locales/alchemy.ru.yml +837 -0
- data/config/locales/simple_form.de.yml +26 -0
- data/config/locales/simple_form.en.yml +25 -0
- data/config/locales/simple_form.es.yml +6 -0
- data/config/locales/simple_form.fr.yml +26 -0
- data/config/locales/simple_form.nl.yml +25 -0
- data/config/locales/simple_form.ru.yml +25 -0
- data/config/routes.rb +164 -0
- data/db/migrate/20130827094554_alchemy_two_point_six.rb +380 -0
- data/db/migrate/20130828121054_remove_do_not_index_from_alchemy_essence_texts.rb +5 -0
- data/db/migrate/20130828121120_remove_do_not_index_from_alchemy_essence_richtexts.rb +5 -0
- data/db/migrate/20130918201742_add_published_at_to_alchemy_pages.rb +5 -0
- data/lib/alchemy/auth_accessors.rb +104 -0
- data/lib/alchemy/cache_digests/template_tracker.rb +65 -0
- data/lib/alchemy/config.rb +65 -0
- data/lib/alchemy/configuration_methods.rb +29 -0
- data/lib/alchemy/controller_actions.rb +138 -0
- data/lib/alchemy/engine.rb +104 -0
- data/lib/alchemy/errors.rb +82 -0
- data/lib/alchemy/essence.rb +232 -0
- data/lib/alchemy/filetypes.rb +33 -0
- data/lib/alchemy/forms/builder.rb +23 -0
- data/lib/alchemy/hints.rb +57 -0
- data/lib/alchemy/i18n.rb +70 -0
- data/lib/alchemy/kaminari/scoped_pagination_url_helper.rb +13 -0
- data/lib/alchemy/locale.rb +65 -0
- data/lib/alchemy/logger.rb +15 -0
- data/lib/alchemy/middleware/rescue_old_cookies.rb +27 -0
- data/lib/alchemy/modules.rb +75 -0
- data/lib/alchemy/mount_point.rb +47 -0
- data/lib/alchemy/name_conversions.rb +28 -0
- data/lib/alchemy/on_page_layout.rb +58 -0
- data/lib/alchemy/page_layout.rb +183 -0
- data/lib/alchemy/permissions.rb +221 -0
- data/lib/alchemy/picture_attributes.rb +29 -0
- data/lib/alchemy/resource.rb +238 -0
- data/lib/alchemy/resources_helper.rb +135 -0
- data/lib/alchemy/routing_constraints.rb +49 -0
- data/lib/alchemy/seeder.rb +53 -0
- data/lib/alchemy/shell.rb +102 -0
- data/lib/alchemy/ssl_protection.rb +30 -0
- data/lib/alchemy/tasks/helpers.rb +83 -0
- data/lib/alchemy/test_support/controller_requests.rb +73 -0
- data/lib/alchemy/test_support/essence_shared_examples.rb +286 -0
- data/lib/alchemy/test_support/factories.rb +147 -0
- data/lib/alchemy/test_support/integration_helpers.rb +33 -0
- data/lib/alchemy/tinymce.rb +68 -0
- data/lib/alchemy/touching.rb +41 -0
- data/lib/alchemy/upgrader.rb +80 -0
- data/lib/alchemy/upgrader/three_point_one.rb +54 -0
- data/lib/alchemy/upgrader/three_point_two.rb +69 -0
- data/lib/alchemy/upgrader/three_point_zero.rb +93 -0
- data/lib/alchemy/userstamp.rb +10 -0
- data/lib/alchemy/version.rb +7 -0
- data/lib/alchemy_cms.rb +5 -0
- data/lib/rails/generators/alchemy/base.rb +41 -0
- data/lib/rails/generators/alchemy/elements/elements_generator.rb +37 -0
- data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +14 -0
- data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +13 -0
- data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +12 -0
- data/lib/rails/generators/alchemy/elements/templates/view.html.erb +27 -0
- data/lib/rails/generators/alchemy/elements/templates/view.html.haml +20 -0
- data/lib/rails/generators/alchemy/elements/templates/view.html.slim +20 -0
- data/lib/rails/generators/alchemy/essence/essence_generator.rb +52 -0
- data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +17 -0
- data/lib/rails/generators/alchemy/essence/templates/view.html.erb +2 -0
- data/lib/rails/generators/alchemy/install/files/_article_editor.html.erb +5 -0
- data/lib/rails/generators/alchemy/install/files/_article_view.html.erb +7 -0
- data/lib/rails/generators/alchemy/install/files/_standard.html.erb +1 -0
- data/lib/rails/generators/alchemy/install/files/alchemy.de.yml +31 -0
- data/lib/rails/generators/alchemy/install/files/alchemy.elements.css.scss +30 -0
- data/lib/rails/generators/alchemy/install/files/alchemy.en.yml +31 -0
- data/lib/rails/generators/alchemy/install/files/alchemy.es.yml +31 -0
- data/lib/rails/generators/alchemy/install/files/application.html.erb +14 -0
- data/lib/rails/generators/alchemy/install/install_generator.rb +69 -0
- data/lib/rails/generators/alchemy/install/templates/elements.yml.tt +21 -0
- data/lib/rails/generators/alchemy/install/templates/page_layouts.yml.tt +10 -0
- data/lib/rails/generators/alchemy/module/module_generator.rb +30 -0
- data/lib/rails/generators/alchemy/module/templates/ability.rb.tt +11 -0
- data/lib/rails/generators/alchemy/module/templates/controller.rb.tt +2 -0
- data/lib/rails/generators/alchemy/module/templates/module_config.rb.tt +17 -0
- data/lib/rails/generators/alchemy/page_layouts/page_layouts_generator.rb +24 -0
- data/lib/rails/generators/alchemy/page_layouts/templates/layout.html.erb +1 -0
- data/lib/rails/generators/alchemy/page_layouts/templates/layout.html.haml +1 -0
- data/lib/rails/generators/alchemy/page_layouts/templates/layout.html.slim +1 -0
- data/lib/rails/generators/alchemy/site_layouts/site_layouts_generator.rb +23 -0
- data/lib/rails/generators/alchemy/site_layouts/templates/layout.html.erb +1 -0
- data/lib/rails/generators/alchemy/site_layouts/templates/layout.html.haml +1 -0
- data/lib/rails/generators/alchemy/site_layouts/templates/layout.html.slim +1 -0
- data/lib/rails/generators/alchemy/views/views_generator.rb +41 -0
- data/lib/rails/templates/alchemy.rb +7 -0
- data/lib/tasks/alchemy/convert.rake +39 -0
- data/lib/tasks/alchemy/db.rake +22 -0
- data/lib/tasks/alchemy/install.rake +61 -0
- data/lib/tasks/alchemy/tidy.rake +102 -0
- data/lib/tasks/alchemy/upgrade.rake +28 -0
- data/spec/controllers/admin/attachments_controller_spec.rb +211 -0
- data/spec/controllers/admin/base_controller_spec.rb +74 -0
- data/spec/controllers/admin/clipboard_controller_spec.rb +60 -0
- data/spec/controllers/admin/contents_controller_spec.rb +72 -0
- data/spec/controllers/admin/dashboard_controller_spec.rb +139 -0
- data/spec/controllers/admin/elements_controller_spec.rb +473 -0
- data/spec/controllers/admin/essence_files_controller_spec.rb +71 -0
- data/spec/controllers/admin/essence_pictures_controller_spec.rb +202 -0
- data/spec/controllers/admin/languages_controller_spec.rb +61 -0
- data/spec/controllers/admin/layoutpages_controller_spec.rb +27 -0
- data/spec/controllers/admin/pages_controller_spec.rb +553 -0
- data/spec/controllers/admin/pictures_controller_spec.rb +358 -0
- data/spec/controllers/admin/resources_controller_spec.rb +53 -0
- data/spec/controllers/admin/trash_controller_spec.rb +68 -0
- data/spec/controllers/alchemy/admin/tags_controller_spec.rb +63 -0
- data/spec/controllers/alchemy/api/contents_controller_spec.rb +126 -0
- data/spec/controllers/alchemy/api/elements_controller_spec.rb +125 -0
- data/spec/controllers/alchemy/api/pages_controller_spec.rb +134 -0
- data/spec/controllers/attachments_controller_spec.rb +64 -0
- data/spec/controllers/base_controller_spec.rb +51 -0
- data/spec/controllers/elements_controller_spec.rb +48 -0
- data/spec/controllers/messages_controller_spec.rb +199 -0
- data/spec/controllers/pages_controller_spec.rb +265 -0
- data/spec/controllers/pictures_controller_spec.rb +393 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/admin/events_controller.rb +3 -0
- data/spec/dummy/app/controllers/application_controller.rb +15 -0
- data/spec/dummy/app/controllers/login_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/ability.rb +9 -0
- data/spec/dummy/app/models/dummy_model.rb +3 -0
- data/spec/dummy/app/models/dummy_user.rb +11 -0
- data/spec/dummy/app/models/event.rb +10 -0
- data/spec/dummy/app/models/location.rb +3 -0
- data/spec/dummy/app/views/alchemy/elements/_all_you_can_eat_editor.html.erb +11 -0
- data/spec/dummy/app/views/alchemy/elements/_article_editor.html.erb +10 -0
- data/spec/dummy/app/views/alchemy/elements/_article_view.html.erb +25 -0
- data/spec/dummy/app/views/alchemy/elements/_headline_editor.html.erb +1 -0
- data/spec/dummy/app/views/alchemy/elements/_headline_view.html.erb +1 -0
- data/spec/dummy/app/views/alchemy/elements/_news_view.html.erb +11 -0
- data/spec/dummy/app/views/alchemy/page_layouts/_standard.html.erb +14 -0
- data/spec/dummy/app/views/layouts/application.html.erb +17 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/alchemy/cells.yml +5 -0
- data/spec/dummy/config/alchemy/elements.yml +112 -0
- data/spec/dummy/config/alchemy/page_layouts.yml +32 -0
- data/spec/dummy/config/application.rb +32 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +32 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +77 -0
- data/spec/dummy/config/environments/test.rb +43 -0
- data/spec/dummy/config/initializers/alchemy.rb +2 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/migrate/20121026104128_create_events.rb +20 -0
- data/spec/dummy/db/migrate/20130328101418_create_locations.rb +9 -0
- data/spec/dummy/db/migrate/20130827094554_alchemy_two_point_six.rb +380 -0
- data/spec/dummy/db/migrate/20130828121054_remove_do_not_index_from_alchemy_essence_texts.rb +5 -0
- data/spec/dummy/db/migrate/20130828121120_remove_do_not_index_from_alchemy_essence_richtexts.rb +5 -0
- data/spec/dummy/db/migrate/20130918201742_add_published_at_to_alchemy_pages.rb +5 -0
- data/spec/dummy/db/migrate/20131209225243_create_dummy_users.rb +9 -0
- data/spec/dummy/db/migrate/20150122213511_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb +31 -0
- data/spec/dummy/db/migrate/20150122213512_add_missing_unique_indices.acts_as_taggable_on_engine.rb +20 -0
- data/spec/dummy/db/migrate/20150122213513_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb +15 -0
- data/spec/dummy/db/migrate/20150122213514_add_missing_taggable_index.acts_as_taggable_on_engine.rb +10 -0
- data/spec/dummy/db/migrate/20150412103152_create_dummy_model.rb +7 -0
- data/spec/dummy/db/schema.rb +322 -0
- data/spec/dummy/db/seeds.rb +1 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/features/admin/dashboard_spec.rb +82 -0
- data/spec/features/admin/language_tree_feature_spec.rb +33 -0
- data/spec/features/admin/legacy_page_url_management_spec.rb +62 -0
- data/spec/features/admin/link_overlay_spec.rb +54 -0
- data/spec/features/admin/locale_select_feature_spec.rb +25 -0
- data/spec/features/admin/modules_integration_spec.rb +24 -0
- data/spec/features/admin/navigation_feature_spec.rb +13 -0
- data/spec/features/admin/page_creation_feature_spec.rb +51 -0
- data/spec/features/admin/page_editing_feature_spec.rb +135 -0
- data/spec/features/admin/picture_library_integration_spec.rb +62 -0
- data/spec/features/admin/resources_integration_spec.rb +133 -0
- data/spec/features/admin/site_select_feature_spec.rb +32 -0
- data/spec/features/admin/tinymce_feature_spec.rb +34 -0
- data/spec/features/navigation_spec.rb +9 -0
- data/spec/features/page_feature_spec.rb +287 -0
- data/spec/features/picture_security_spec.rb +35 -0
- data/spec/features/security_spec.rb +24 -0
- data/spec/features/translation_integration_spec.rb +51 -0
- data/spec/fixtures/500x500.png +0 -0
- data/spec/fixtures/80x60.png +0 -0
- data/spec/fixtures/image with spaces.png +0 -0
- data/spec/fixtures/image.png +0 -0
- data/spec/fixtures/image2.PNG +0 -0
- data/spec/fixtures/image3.jpeg +0 -0
- data/spec/helpers/admin/attachments_helper_spec.rb +15 -0
- data/spec/helpers/admin/base_helper_spec.rb +270 -0
- data/spec/helpers/admin/contents_helper_spec.rb +65 -0
- data/spec/helpers/admin/elements_helper_spec.rb +178 -0
- data/spec/helpers/admin/essences_helper_spec.rb +140 -0
- data/spec/helpers/admin/navigation_helper_spec.rb +288 -0
- data/spec/helpers/admin/pages_helper_spec.rb +95 -0
- data/spec/helpers/admin/pictures_helper_spec.rb +29 -0
- data/spec/helpers/admin/tags_helper_spec.rb +113 -0
- data/spec/helpers/base_helper_spec.rb +45 -0
- data/spec/helpers/elements_block_helper_spec.rb +135 -0
- data/spec/helpers/elements_helper_spec.rb +311 -0
- data/spec/helpers/essences_helper_spec.rb +156 -0
- data/spec/helpers/pages_helper_spec.rb +413 -0
- data/spec/helpers/picture_url_helpers_spec.rb +35 -0
- data/spec/helpers/url_helper_spec.rb +174 -0
- data/spec/javascripts/alchemy/dialog_spec.coffee +82 -0
- data/spec/javascripts/alchemy/link_overlay_spec.coffee +25 -0
- data/spec/javascripts/alchemy_integration_spec.coffee +3 -0
- data/spec/javascripts/fixtures/select.html +3 -0
- data/spec/javascripts/helpers/mock-ajax.js +199 -0
- data/spec/javascripts/helpers/test_responses/test_responses.js +1 -0
- data/spec/javascripts/support/jasmine.yml +29 -0
- data/spec/libraries/auth_accessors_spec.rb +40 -0
- data/spec/libraries/config_spec.rb +112 -0
- data/spec/libraries/controller_actions_spec.rb +133 -0
- data/spec/libraries/i18n_spec.rb +30 -0
- data/spec/libraries/kaminari/scoped_pagination_url_helper_spec.rb +30 -0
- data/spec/libraries/modules_spec.rb +67 -0
- data/spec/libraries/mount_point_spec.rb +77 -0
- data/spec/libraries/on_page_layout_spec.rb +112 -0
- data/spec/libraries/page_layout_spec.rb +144 -0
- data/spec/libraries/permissions_spec.rb +261 -0
- data/spec/libraries/resource_spec.rb +371 -0
- data/spec/libraries/resources_helper_spec.rb +144 -0
- data/spec/libraries/shell_spec.rb +125 -0
- data/spec/libraries/template_tracker_spec.rb +94 -0
- data/spec/libraries/tinymce_spec.rb +67 -0
- data/spec/libraries/userstamp_spec.rb +10 -0
- data/spec/mailers/messages_spec.rb +23 -0
- data/spec/models/attachment_spec.rb +227 -0
- data/spec/models/cell_spec.rb +102 -0
- data/spec/models/content_spec.rb +404 -0
- data/spec/models/dummy_model_spec.rb +11 -0
- data/spec/models/element_spec.rb +617 -0
- data/spec/models/element_to_page_spec.rb +14 -0
- data/spec/models/essence_boolean_spec.rb +10 -0
- data/spec/models/essence_date_spec.rb +29 -0
- data/spec/models/essence_file_spec.rb +43 -0
- data/spec/models/essence_html_spec.rb +18 -0
- data/spec/models/essence_link_spec.rb +10 -0
- data/spec/models/essence_picture_spec.rb +183 -0
- data/spec/models/essence_richtext_spec.rb +18 -0
- data/spec/models/essence_select_spec.rb +10 -0
- data/spec/models/essence_text_spec.rb +114 -0
- data/spec/models/language_spec.rb +123 -0
- data/spec/models/legacy_page_url_spec.rb +21 -0
- data/spec/models/message_spec.rb +55 -0
- data/spec/models/page_spec.rb +1896 -0
- data/spec/models/picture_spec.rb +330 -0
- data/spec/models/site_spec.rb +233 -0
- data/spec/models/tag_spec.rb +31 -0
- data/spec/routing/api_routing_spec.rb +150 -0
- data/spec/routing/routing_spec.rb +234 -0
- data/spec/spec_helper.rb +89 -0
- data/spec/support/ci/install_phantomjs +7 -0
- data/spec/support/hint_examples.rb +30 -0
- data/spec/support/rspec-activemodel-mocks_patch.rb +8 -0
- data/spec/support/test_tweaks.rb +31 -0
- data/spec/support/transformation_examples.rb +180 -0
- data/spec/tasks/helpers_spec.rb +219 -0
- data/spec/views/essences/essence_boolean_editor_spec.rb +33 -0
- data/spec/views/essences/essence_boolean_view_spec.rb +25 -0
- data/spec/views/essences/essence_date_view_spec.rb +39 -0
- data/spec/views/essences/essence_file_editor_spec.rb +61 -0
- data/spec/views/essences/essence_file_view_spec.rb +24 -0
- data/spec/views/essences/essence_html_view_spec.rb +22 -0
- data/spec/views/essences/essence_link_view_spec.rb +41 -0
- data/spec/views/essences/essence_picture_view_spec.rb +129 -0
- data/spec/views/essences/essence_richtext_view_spec.rb +32 -0
- data/spec/views/essences/essence_select_view_spec.rb +12 -0
- data/spec/views/essences/essence_text_view_spec.rb +52 -0
- data/vendor/assets/images/Jcrop.gif +0 -0
- data/vendor/assets/javascripts/fileupload/jquery.fileupload-process.js +175 -0
- data/vendor/assets/javascripts/fileupload/jquery.fileupload-validate.js +122 -0
- data/vendor/assets/javascripts/fileupload/jquery.fileupload.js +1467 -0
- data/vendor/assets/javascripts/fileupload/jquery.iframe-transport.js +217 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +22 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.floatThead.min.js +3 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.scrollTo.min.js +7 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +435 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +296 -0
- data/vendor/assets/javascripts/keymaster.js +296 -0
- data/vendor/assets/javascripts/requestAnimationFrame.js +31 -0
- data/vendor/assets/javascripts/spin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/langs/de.js +200 -0
- data/vendor/assets/javascripts/tinymce/langs/es.js +200 -0
- data/vendor/assets/javascripts/tinymce/langs/fr.js +200 -0
- data/vendor/assets/javascripts/tinymce/langs/nl.js +200 -0
- data/vendor/assets/javascripts/tinymce/langs/ru.js +200 -0
- data/vendor/assets/javascripts/tinymce/license.txt +504 -0
- data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/code/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/hr/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/link/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/tabfocus/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/plugins/table/plugin.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/themes/modern/theme.min.js +1 -0
- data/vendor/assets/javascripts/tinymce/tinymce.min.js +13 -0
- data/vendor/assets/stylesheets/jquery.Jcrop.min.css +28 -0
- metadata +1453 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
module Alchemy
|
|
5
|
+
describe Language do
|
|
6
|
+
let(:default_language) { Alchemy::Language.default }
|
|
7
|
+
let(:language) { FactoryGirl.create(:klingonian) }
|
|
8
|
+
let(:page) { FactoryGirl.create(:page, language: language) }
|
|
9
|
+
|
|
10
|
+
it "should return a label for code" do
|
|
11
|
+
expect(language.label(:code)).to eq('kl')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should return a label for name" do
|
|
15
|
+
expect(language.label(:name)).to eq('Klingonian')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "with language_code and empty country_code" do
|
|
19
|
+
it "#code should return language locale only" do
|
|
20
|
+
language.country_code = ''
|
|
21
|
+
expect(language.code).to eq('kl')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "adding a value for country code" do
|
|
25
|
+
it "#code should return a joined locale" do
|
|
26
|
+
language.country_code = 'cr'
|
|
27
|
+
expect(language.code).to eq('kl-cr')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should update all associated Pages with self.code as value for Page#language_code" do
|
|
31
|
+
page = FactoryGirl.create(:page, language: language)
|
|
32
|
+
language.country_code = 'cr'
|
|
33
|
+
language.save
|
|
34
|
+
page.reload; expect(page.language_code).to eq('kl-cr')
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "with country_code and_language_code" do
|
|
40
|
+
context "removing the country_code" do
|
|
41
|
+
it "should update all associated Pages´s language_code with Language#code" do
|
|
42
|
+
language = FactoryGirl.create(:language, country_code: 'kl')
|
|
43
|
+
language.country_code = ''
|
|
44
|
+
language.save
|
|
45
|
+
page.reload; expect(page.language_code).to eq("kl")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should not be deletable if it is the default language" do
|
|
51
|
+
expect {
|
|
52
|
+
default_language.destroy
|
|
53
|
+
}.to raise_error(DefaultLanguageNotDeletable)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "before save" do
|
|
57
|
+
describe "#remove_old_default if default attribute has changed to true" do
|
|
58
|
+
it "should unset the default status of the old default language" do
|
|
59
|
+
default_language
|
|
60
|
+
language.update_attributes(default: true)
|
|
61
|
+
default_language.reload
|
|
62
|
+
expect(default_language.default).to be_falsey
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context "after_update" do
|
|
68
|
+
describe "#set_pages_language if language´s code has changed" do
|
|
69
|
+
it "should update all its pages with the new code" do
|
|
70
|
+
@other_page = FactoryGirl.create(:page, language: language)
|
|
71
|
+
language.update_attributes(code: "fo")
|
|
72
|
+
language.reload; page.reload; @other_page.reload
|
|
73
|
+
expect([page.language_code, @other_page.language_code]).to eq([language.code, language.code])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe "#unpublish_pages" do
|
|
78
|
+
it "should set all pages to unpublic if it gets set to unpublic" do
|
|
79
|
+
page = FactoryGirl.create(:page, language: language)
|
|
80
|
+
@other_page = FactoryGirl.create(:page, language: language)
|
|
81
|
+
language.update_attributes(public: false)
|
|
82
|
+
language.reload; page.reload; @other_page.reload
|
|
83
|
+
expect([page.public?, @other_page.public?]).to eq([false, false])
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe '.find_by_code' do
|
|
89
|
+
context "with only the language code given" do
|
|
90
|
+
it "should find the language" do
|
|
91
|
+
expect(Language.find_by_code(language.code)).to eq(language)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context 'validations' do
|
|
97
|
+
let(:language) { Language.new(default: true, public: false) }
|
|
98
|
+
|
|
99
|
+
describe 'publicity_of_default_language' do
|
|
100
|
+
context 'if language is not published' do
|
|
101
|
+
it "should add an error to the object" do
|
|
102
|
+
expect(language.valid?).to eq(false)
|
|
103
|
+
expect(language.errors.messages).to have_key(:public)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe 'presence_of_default_language' do
|
|
109
|
+
context 'if no default language would exist anymore' do
|
|
110
|
+
before do
|
|
111
|
+
allow(Language).to receive(:default).and_return(language)
|
|
112
|
+
allow(language).to receive(:default_changed?).and_return(true)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should add an error to the object" do
|
|
116
|
+
expect(language.valid?).to eq(false)
|
|
117
|
+
expect(language.errors.messages).to have_key(:default)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Alchemy::LegacyPageUrl do
|
|
4
|
+
let(:page) { build_stubbed(:page) }
|
|
5
|
+
|
|
6
|
+
let(:page_url_with_parameters) do
|
|
7
|
+
Alchemy::LegacyPageUrl.new(urlname: 'index.php?id=2', page: page)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
let(:valid_page_url) do
|
|
11
|
+
Alchemy::LegacyPageUrl.new(urlname: 'my/0-work+is-nice_stuff', page: page)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'is only valid with correct urlname format' do
|
|
15
|
+
expect(valid_page_url).to be_valid
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'is also valid with get parameters in urlname' do
|
|
19
|
+
expect(page_url_with_parameters).to be_valid
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Alchemy
|
|
4
|
+
Config.get(:mailer)['fields'].push('email_of_my_boss')
|
|
5
|
+
Config.get(:mailer)['validate_fields'].push('email_of_my_boss')
|
|
6
|
+
|
|
7
|
+
describe Message do
|
|
8
|
+
let(:message) { Message.new }
|
|
9
|
+
|
|
10
|
+
describe '.config' do
|
|
11
|
+
it "should return the mailer config" do
|
|
12
|
+
expect(Config).to receive(:get).with(:mailer)
|
|
13
|
+
Message.config
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "has attributes writers and getters for all fields defined in mailer config" do
|
|
18
|
+
Config.get(:mailer)['fields'].each do |field|
|
|
19
|
+
expect(message).to respond_to(field)
|
|
20
|
+
expect(message).to respond_to("#{field}=")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "validation of" do
|
|
25
|
+
context "all fields defined in mailer config" do
|
|
26
|
+
it "adds errors on that fields" do
|
|
27
|
+
Config.get(:mailer)['validate_fields'].each do |field|
|
|
28
|
+
expect(message).to_not be_valid
|
|
29
|
+
expect(message.errors[field].size).to eq(1)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'field containing email in its name' do
|
|
35
|
+
context "when field has a value" do
|
|
36
|
+
before { message.email_of_my_boss = 'wrong email format' }
|
|
37
|
+
|
|
38
|
+
it "adds error notice (is invalid) to the field" do
|
|
39
|
+
expect(message).to_not be_valid
|
|
40
|
+
expect(message.errors[:email_of_my_boss]).to include("is invalid")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "when field is blank" do
|
|
45
|
+
before { message.email_of_my_boss = '' }
|
|
46
|
+
|
|
47
|
+
it "adds error notice (can't be blank) to the field" do
|
|
48
|
+
expect(message).to_not be_valid
|
|
49
|
+
expect(message.errors[:email_of_my_boss]).to include("can't be blank")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,1896 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module Alchemy
|
|
6
|
+
describe Page do
|
|
7
|
+
|
|
8
|
+
let(:rootpage) { Page.root }
|
|
9
|
+
let(:language) { Language.default }
|
|
10
|
+
let(:klingonian) { FactoryGirl.create(:klingonian) }
|
|
11
|
+
let(:language_root) { FactoryGirl.create(:language_root_page) }
|
|
12
|
+
let(:page) { mock_model(Page, page_layout: 'foo') }
|
|
13
|
+
let(:public_page) { FactoryGirl.create(:public_page) }
|
|
14
|
+
let(:news_page) { FactoryGirl.create(:public_page, page_layout: 'news', do_not_autogenerate: false) }
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Validations
|
|
18
|
+
|
|
19
|
+
context 'validations' do
|
|
20
|
+
context "Creating a normal content page" do
|
|
21
|
+
let(:contentpage) { FactoryGirl.build(:page) }
|
|
22
|
+
let(:with_same_urlname) { FactoryGirl.create(:page, urlname: "existing_twice") }
|
|
23
|
+
let(:global_with_same_urlname) { FactoryGirl.create(:page, urlname: "existing_twice", layoutpage: true) }
|
|
24
|
+
|
|
25
|
+
context "when its urlname exists as global page" do
|
|
26
|
+
before { global_with_same_urlname }
|
|
27
|
+
|
|
28
|
+
it "it should be possible to save." do
|
|
29
|
+
contentpage.urlname = "existing_twice"
|
|
30
|
+
expect(contentpage).to be_valid
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should validate the page_layout" do
|
|
35
|
+
contentpage.page_layout = nil
|
|
36
|
+
expect(contentpage).not_to be_valid
|
|
37
|
+
contentpage.valid?
|
|
38
|
+
expect(contentpage.errors[:page_layout].size).to eq(1)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should validate the parent_id" do
|
|
42
|
+
contentpage.parent_id = nil
|
|
43
|
+
expect(contentpage).not_to be_valid
|
|
44
|
+
contentpage.valid?
|
|
45
|
+
expect(contentpage.errors[:parent_id].size).to eq(1)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'with page having same urlname' do
|
|
49
|
+
before { with_same_urlname }
|
|
50
|
+
|
|
51
|
+
it "should not be valid" do
|
|
52
|
+
contentpage.urlname = 'existing_twice'
|
|
53
|
+
expect(contentpage).not_to be_valid
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context "with url_nesting set to true" do
|
|
58
|
+
let(:other_parent) { create(:page, parent_id: Page.root.id, visible: true) }
|
|
59
|
+
|
|
60
|
+
before do
|
|
61
|
+
allow(Config).to receive(:get).and_return(true)
|
|
62
|
+
with_same_urlname
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should only validate urlname dependent of parent" do
|
|
66
|
+
contentpage.urlname = 'existing_twice'
|
|
67
|
+
contentpage.parent_id = other_parent.id
|
|
68
|
+
expect(contentpage).to be_valid
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should validate urlname dependent of parent" do
|
|
72
|
+
contentpage.urlname = 'existing_twice'
|
|
73
|
+
expect(contentpage).not_to be_valid
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "creating the rootpage without parent_id and page_layout" do
|
|
79
|
+
let(:rootpage) { build(:page, parent_id: nil, page_layout: nil, name: 'Rootpage') }
|
|
80
|
+
|
|
81
|
+
before do
|
|
82
|
+
Page.delete_all
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should be valid" do
|
|
86
|
+
expect(rootpage).to be_valid
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
context "saving a systempage" do
|
|
91
|
+
let(:systempage) { build(:systempage) }
|
|
92
|
+
|
|
93
|
+
it "should not validate the page_layout" do
|
|
94
|
+
expect(systempage).to be_valid
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context 'saving an external page' do
|
|
99
|
+
let(:external_page) { build(:page, page_layout: 'external') }
|
|
100
|
+
|
|
101
|
+
it "does not pass with invalid url given" do
|
|
102
|
+
external_page.urlname = 'not, a valid page url'
|
|
103
|
+
expect(external_page).to_not be_valid
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "only be valid with correct url given" do
|
|
107
|
+
external_page.urlname = 'www.google.com&utf_src=alchemy;page_id=%20'
|
|
108
|
+
expect(external_page).to be_valid
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
context 'on create' do
|
|
112
|
+
it "is valid without urlname given" do
|
|
113
|
+
external_page.urlname = ''
|
|
114
|
+
expect(external_page).to be_valid
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
context 'on update' do
|
|
119
|
+
before { external_page.save! }
|
|
120
|
+
|
|
121
|
+
it "is not valid without urlname given" do
|
|
122
|
+
external_page.urlname = ''
|
|
123
|
+
expect(external_page).to_not be_valid
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# Callbacks
|
|
131
|
+
|
|
132
|
+
context 'callbacks' do
|
|
133
|
+
let(:page) do
|
|
134
|
+
FactoryGirl.create(:page, name: 'My Testpage', language: language, parent_id: language_root.id)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context 'before_save' do
|
|
138
|
+
it "should not set the title automatically if the name changed but title is not blank" do
|
|
139
|
+
page.name = "My Renaming Test"
|
|
140
|
+
page.save; page.reload
|
|
141
|
+
expect(page.title).to eq("My Testpage")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should not automatically set the title if it changed its value" do
|
|
145
|
+
page.title = "I like SEO"
|
|
146
|
+
page.save; page.reload
|
|
147
|
+
expect(page.title).to eq("I like SEO")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
context 'after_update' do
|
|
152
|
+
context "urlname has changed" do
|
|
153
|
+
it "should store legacy url if page is not redirect to external page" do
|
|
154
|
+
page.urlname = 'new-urlname'
|
|
155
|
+
page.save!
|
|
156
|
+
expect(page.legacy_urls).not_to be_empty
|
|
157
|
+
expect(page.legacy_urls.first.urlname).to eq('my-testpage')
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "should not store legacy url if page is redirect to external page" do
|
|
161
|
+
page.urlname = 'new-urlname'
|
|
162
|
+
page.page_layout = "external"
|
|
163
|
+
page.save!
|
|
164
|
+
expect(page.legacy_urls).to be_empty
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "should not store legacy url twice for same urlname" do
|
|
168
|
+
page.urlname = 'new-urlname'
|
|
169
|
+
page.save!
|
|
170
|
+
page.urlname = 'my-testpage'
|
|
171
|
+
page.save!
|
|
172
|
+
page.urlname = 'another-urlname'
|
|
173
|
+
page.save!
|
|
174
|
+
expect(page.legacy_urls.select { |u| u.urlname == 'my-testpage' }.size).to eq(1)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
context "urlname has not changed" do
|
|
179
|
+
it "should not store a legacy url" do
|
|
180
|
+
page.urlname = 'my-testpage'
|
|
181
|
+
page.save!
|
|
182
|
+
expect(page.legacy_urls).to be_empty
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
context "public has changed" do
|
|
187
|
+
it "should update published_at" do
|
|
188
|
+
expect {
|
|
189
|
+
page.update_attributes!(public: true)
|
|
190
|
+
}.to change {page.read_attribute(:published_at) }
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "should not update already set published_at" do
|
|
194
|
+
page.update_attributes!(published_at: 2.weeks.ago)
|
|
195
|
+
expect {
|
|
196
|
+
page.update_attributes!(public: true)
|
|
197
|
+
}.to_not change { page.read_attribute(:published_at) }
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
context "public has not changed" do
|
|
202
|
+
it "should not update published_at" do
|
|
203
|
+
page.update_attributes!(name: 'New Name')
|
|
204
|
+
expect(page.read_attribute(:published_at)).to be_nil
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
context 'after_move' do
|
|
210
|
+
let(:parent_1) { FactoryGirl.create(:page, name: 'Parent 1', visible: true) }
|
|
211
|
+
let(:parent_2) { FactoryGirl.create(:page, name: 'Parent 2', visible: true) }
|
|
212
|
+
let(:page) { FactoryGirl.create(:page, parent_id: parent_1.id, name: 'Page', visible: true) }
|
|
213
|
+
|
|
214
|
+
it "updates the urlname" do
|
|
215
|
+
expect(page.urlname).to eq('parent-1/page')
|
|
216
|
+
page.move_to_child_of parent_2
|
|
217
|
+
expect(page.urlname).to eq('parent-2/page')
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
context 'of an external page' do
|
|
221
|
+
let(:external) { FactoryGirl.create(:page, parent_id: parent_1.id, name: 'external', page_layout: 'external', urlname: 'http://google.com') }
|
|
222
|
+
|
|
223
|
+
it "the urlname does not get updated" do
|
|
224
|
+
external.move_to_child_of parent_2
|
|
225
|
+
expect(external.urlname).to eq('http://google.com')
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
context "a normal page" do
|
|
231
|
+
before do
|
|
232
|
+
@page = FactoryGirl.build(:page, language_code: nil, language: klingonian, do_not_autogenerate: false)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "should set the language code" do
|
|
236
|
+
@page.save
|
|
237
|
+
expect(@page.language_code).to eq("kl")
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "should autogenerate the elements" do
|
|
241
|
+
@page.save
|
|
242
|
+
expect(@page.elements).not_to be_empty
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
it "should not autogenerate elements that are already on the page" do
|
|
246
|
+
@page.elements << FactoryGirl.create(:element, name: 'header')
|
|
247
|
+
@page.save
|
|
248
|
+
expect(@page.elements.select { |e| e.name == 'header' }.length).to eq(1)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
context "with cells" do
|
|
252
|
+
before do
|
|
253
|
+
allow(@page).to receive(:definition).and_return({'name' => 'with_cells', 'cells' => ['header', 'main']})
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "should have the generated elements in their cells" do
|
|
257
|
+
allow(@page).to receive(:cell_definitions).and_return([{'name' => 'header', 'elements' => ['article']}])
|
|
258
|
+
@page.save
|
|
259
|
+
expect(@page.cells.where(name: 'header').first.elements).not_to be_empty
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
context "and no elements in cell definitions" do
|
|
263
|
+
it "should have the elements in the nil cell" do
|
|
264
|
+
allow(@page).to receive(:cell_definitions).and_return([{'name' => 'header', 'elements' => []}])
|
|
265
|
+
@page.save
|
|
266
|
+
expect(@page.cells.collect(&:elements).flatten).to be_empty
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
context "with children getting restricted set to true" do
|
|
272
|
+
before do
|
|
273
|
+
@page.save
|
|
274
|
+
@child1 = FactoryGirl.create(:page, name: 'Child 1', parent_id: @page.id)
|
|
275
|
+
@page.reload
|
|
276
|
+
@page.restricted = true
|
|
277
|
+
@page.save
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "should restrict all its children" do
|
|
281
|
+
@child1.reload
|
|
282
|
+
expect(@child1.restricted?).to be_truthy
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
context "with restricted parent gets created" do
|
|
287
|
+
before do
|
|
288
|
+
@page.save
|
|
289
|
+
@page.parent.update_attributes(restricted: true)
|
|
290
|
+
@new_page = FactoryGirl.create(:page, name: 'New Page', parent_id: @page.id)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it "should also be restricted" do
|
|
294
|
+
expect(@new_page.restricted?).to be_truthy
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
context "with do_not_autogenerate set to true" do
|
|
299
|
+
before do
|
|
300
|
+
@page.do_not_autogenerate = true
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "should not autogenerate the elements" do
|
|
304
|
+
@page.save
|
|
305
|
+
expect(@page.elements).to be_empty
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
context "a systempage" do
|
|
311
|
+
before do
|
|
312
|
+
@page = FactoryGirl.create(:systempage)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "should not get the language code for language" do
|
|
316
|
+
expect(@page.language_code).to be_nil
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
it "should not autogenerate the elements" do
|
|
320
|
+
expect(@page.elements).to be_empty
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
context "after changing the page layout" do
|
|
325
|
+
let(:news_element) { news_page.elements.find_by(name: 'news') }
|
|
326
|
+
|
|
327
|
+
it "all elements not allowed on this page should be trashed" do
|
|
328
|
+
expect(news_page.elements.trashed).to be_empty
|
|
329
|
+
news_page.update_attributes(page_layout: 'standard')
|
|
330
|
+
trashed = news_page.elements.trashed.pluck(:name)
|
|
331
|
+
expect(trashed).to eq(['news'])
|
|
332
|
+
expect(trashed).to_not include('article', 'header')
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
it "should autogenerate elements" do
|
|
336
|
+
news_page.update_attributes(page_layout: 'contact')
|
|
337
|
+
expect(news_page.elements.pluck(:name)).to include('contactform')
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
# ClassMethods (a-z)
|
|
344
|
+
|
|
345
|
+
describe '.all_from_clipboard_for_select' do
|
|
346
|
+
context "with clipboard holding pages having non unique page layout" do
|
|
347
|
+
it "should return the pages" do
|
|
348
|
+
page_1 = FactoryGirl.create(:page, language: language)
|
|
349
|
+
page_2 = FactoryGirl.create(:page, language: language, name: 'Another page')
|
|
350
|
+
clipboard = [
|
|
351
|
+
{'id' => page_1.id.to_s, 'action' => 'copy'},
|
|
352
|
+
{'id' => page_2.id.to_s, 'action' => 'copy'}
|
|
353
|
+
]
|
|
354
|
+
expect(Page.all_from_clipboard_for_select(clipboard, language.id)).to include(page_1, page_2)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
context "with clipboard holding a page having unique page layout" do
|
|
359
|
+
it "should not return any pages" do
|
|
360
|
+
page_1 = FactoryGirl.create(:page, language: language, page_layout: 'contact')
|
|
361
|
+
clipboard = [
|
|
362
|
+
{'id' => page_1.id.to_s, 'action' => 'copy'}
|
|
363
|
+
]
|
|
364
|
+
expect(Page.all_from_clipboard_for_select(clipboard, language.id)).to eq([])
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
context "with clipboard holding two pages. One having a unique page layout." do
|
|
369
|
+
it "should return one page" do
|
|
370
|
+
page_1 = FactoryGirl.create(:page, language: language, page_layout: 'standard')
|
|
371
|
+
page_2 = FactoryGirl.create(:page, name: 'Another page', language: language, page_layout: 'contact')
|
|
372
|
+
clipboard = [
|
|
373
|
+
{'id' => page_1.id.to_s, 'action' => 'copy'},
|
|
374
|
+
{'id' => page_2.id.to_s, 'action' => 'copy'}
|
|
375
|
+
]
|
|
376
|
+
expect(Page.all_from_clipboard_for_select(clipboard, language.id)).to eq([page_1])
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
describe '.all_locked' do
|
|
382
|
+
it "should return 1 page that is blocked by a user at the moment" do
|
|
383
|
+
FactoryGirl.create(:public_page, locked: true, name: 'First Public Child', parent_id: language_root.id, language: language)
|
|
384
|
+
expect(Page.all_locked.size).to eq(1)
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
describe '.all_locked_by' do
|
|
389
|
+
let(:user) { double(:user, id: 1, class: DummyUser) }
|
|
390
|
+
|
|
391
|
+
before do
|
|
392
|
+
FactoryGirl.create(:public_page, locked: true, locked_by: 53) # This page must not be part of the collection
|
|
393
|
+
allow(user.class)
|
|
394
|
+
.to receive(:primary_key)
|
|
395
|
+
.and_return('id')
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
it "should return the correct page collection blocked by a certain user" do
|
|
399
|
+
page = FactoryGirl.create(:public_page, locked: true, locked_by: 1)
|
|
400
|
+
expect(Page.all_locked_by(user).pluck(:id)).to eq([page.id])
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
context 'with user class having a different primary key' do
|
|
404
|
+
let(:user) { double(:user, user_id: 123, class: DummyUser) }
|
|
405
|
+
|
|
406
|
+
before do
|
|
407
|
+
allow(user.class)
|
|
408
|
+
.to receive(:primary_key)
|
|
409
|
+
.and_return('user_id')
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it "should return the correct page collection blocked by a certain user" do
|
|
413
|
+
page = FactoryGirl.create(:public_page, locked: true, locked_by: 123)
|
|
414
|
+
expect(Page.all_locked_by(user).pluck(:id)).to eq([page.id])
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
describe '.ancestors_for' do
|
|
420
|
+
let(:lang_root) { Page.language_root_for(Language.default.id) }
|
|
421
|
+
let(:parent) { create(:public_page) }
|
|
422
|
+
let(:page) { create(:public_page, parent_id: parent.id) }
|
|
423
|
+
|
|
424
|
+
it "returns an array of all parents including self" do
|
|
425
|
+
expect(Page.ancestors_for(page)).to eq([lang_root, parent, page])
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it "does not include the root page" do
|
|
429
|
+
expect(Page.ancestors_for(page)).not_to include(Page.root)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
context "with current page nil" do
|
|
433
|
+
it "should return an empty array" do
|
|
434
|
+
expect(Page.ancestors_for(nil)).to eq([])
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
describe '.contentpages' do
|
|
440
|
+
before do
|
|
441
|
+
layoutroot = Page.find_or_create_layout_root_for(klingonian.id)
|
|
442
|
+
@layoutpage = FactoryGirl.create(:public_page, name: 'layoutpage', layoutpage: true, parent_id: layoutroot.id, language: klingonian)
|
|
443
|
+
@klingonian_lang_root = FactoryGirl.create(:language_root_page, name: 'klingonian_lang_root', layoutpage: nil, language: klingonian)
|
|
444
|
+
@contentpage = FactoryGirl.create(:public_page, name: 'contentpage', parent_id: language_root.id, language: language)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
it "should return a collection of contentpages" do
|
|
448
|
+
expect(Page.contentpages.to_a).to include(language_root, @klingonian_lang_root, @contentpage)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
it "should not contain pages with attribute :layoutpage set to true" do
|
|
452
|
+
expect(Page.contentpages.to_a.select { |p| p.layoutpage == true }).to be_empty
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it "should contain pages with attribute :layoutpage set to nil" do
|
|
456
|
+
expect(Page.contentpages.to_a.select { |p| p.layoutpage == nil }).to include(@klingonian_lang_root)
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
describe '.copy' do
|
|
461
|
+
let(:page) { FactoryGirl.create(:page, name: 'Source') }
|
|
462
|
+
subject { Page.copy(page) }
|
|
463
|
+
|
|
464
|
+
it "the copy should have added (copy) to name" do
|
|
465
|
+
expect(subject.name).to eq("#{page.name} (Copy)")
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
context "page with tags" do
|
|
469
|
+
before { page.tag_list = 'red, yellow'; page.save }
|
|
470
|
+
|
|
471
|
+
it "the copy should have source tag_list" do
|
|
472
|
+
# The order of tags varies between postgresql and sqlite/mysql
|
|
473
|
+
# This is related to acts-as-taggable-on v.2.4.1
|
|
474
|
+
# To fix the spec we sort the tags until the issue is solved (https://github.com/mbleigh/acts-as-taggable-on/issues/363)
|
|
475
|
+
expect(subject.tag_list).not_to be_empty
|
|
476
|
+
expect(subject.tag_list.sort).to eq(page.tag_list.sort)
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
context "page with elements" do
|
|
481
|
+
before { page.elements << FactoryGirl.create(:element) }
|
|
482
|
+
|
|
483
|
+
it "the copy should have source elements" do
|
|
484
|
+
expect(subject.elements).not_to be_empty
|
|
485
|
+
expect(subject.elements.count).to eq(page.elements.count)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
context "page with trashed elements" do
|
|
490
|
+
before do
|
|
491
|
+
page.elements << FactoryGirl.create(:element)
|
|
492
|
+
page.elements.first.trash!
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
it "the copy should not hold a copy of the trashed elements" do
|
|
496
|
+
expect(subject.elements).to be_empty
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
context "page with cells" do
|
|
501
|
+
before { page.cells << FactoryGirl.create(:cell) }
|
|
502
|
+
|
|
503
|
+
it "the copy should have source cells" do
|
|
504
|
+
expect(subject.cells).not_to be_empty
|
|
505
|
+
expect(subject.cells.count).to eq(page.cells.length) # It must be length, because!
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
context "page with autogenerate elements" do
|
|
510
|
+
before do
|
|
511
|
+
page = FactoryGirl.create(:page)
|
|
512
|
+
allow(page).to receive(:definition).and_return({'name' => 'standard', 'elements' => ['headline'], 'autogenerate' => ['headline']})
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
it "the copy should not autogenerate elements" do
|
|
516
|
+
expect(subject.elements).to be_empty
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
context "with different page name given" do
|
|
521
|
+
subject { Page.copy(page, {name: 'Different name'}) }
|
|
522
|
+
it "should take this name" do
|
|
523
|
+
expect(subject.name).to eq('Different name')
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
describe '.create' do
|
|
529
|
+
context "before/after filter" do
|
|
530
|
+
it "should automatically set the title from its name" do
|
|
531
|
+
page = FactoryGirl.create(:page, name: 'My Testpage', language: language, parent_id: language_root.id)
|
|
532
|
+
expect(page.title).to eq('My Testpage')
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
it "should get a webfriendly urlname" do
|
|
536
|
+
page = FactoryGirl.create(:page, name: 'klingon$&stößel ', language: language, parent_id: language_root.id)
|
|
537
|
+
expect(page.urlname).to eq('klingon-stoessel')
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
context "with no name set" do
|
|
541
|
+
it "should not set a urlname" do
|
|
542
|
+
page = Page.create(name: '', language: language, parent_id: language_root.id)
|
|
543
|
+
expect(page.urlname).to be_blank
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
it "should generate a three letter urlname from two letter name" do
|
|
548
|
+
page = FactoryGirl.create(:page, name: 'Au', language: language, parent_id: language_root.id)
|
|
549
|
+
expect(page.urlname).to eq('-au')
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
it "should generate a three letter urlname from two letter name with umlaut" do
|
|
553
|
+
page = FactoryGirl.create(:page, name: 'Aü', language: language, parent_id: language_root.id)
|
|
554
|
+
expect(page.urlname).to eq('aue')
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
it "should generate a three letter urlname from one letter name" do
|
|
558
|
+
page = FactoryGirl.create(:page, name: 'A', language: language, parent_id: language_root.id)
|
|
559
|
+
expect(page.urlname).to eq('--a')
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
it "should add a user stamper" do
|
|
563
|
+
page = FactoryGirl.create(:page, name: 'A', language: language, parent_id: language_root.id)
|
|
564
|
+
expect(page.class.stamper_class.to_s).to eq('DummyUser')
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
context "with language given" do
|
|
568
|
+
it "does not set the language from parent" do
|
|
569
|
+
expect_any_instance_of(Page).not_to receive(:set_language_from_parent_or_default)
|
|
570
|
+
Page.create!(name: 'A', parent_id: language_root.id, page_layout: 'standard', language: language)
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
context "with no language given" do
|
|
575
|
+
it "sets the language from parent" do
|
|
576
|
+
expect_any_instance_of(Page).to receive(:set_language_from_parent_or_default)
|
|
577
|
+
Page.create!(name: 'A', parent_id: language_root.id, page_layout: 'standard')
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
describe '.find_or_create_layout_root_for' do
|
|
584
|
+
subject { Page.find_or_create_layout_root_for(language_id) }
|
|
585
|
+
|
|
586
|
+
let(:language) { mock_model('Language', name: 'English') }
|
|
587
|
+
let(:language_id) { language.id }
|
|
588
|
+
|
|
589
|
+
before { allow(Language).to receive(:find).and_return(language) }
|
|
590
|
+
|
|
591
|
+
context 'if no layout root page for given language id could be found' do
|
|
592
|
+
before do
|
|
593
|
+
expect(Page).to receive(:create!).and_return(page)
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
it "creates one" do
|
|
597
|
+
is_expected.to eq(page)
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
context 'if layout root page for given language id could be found' do
|
|
602
|
+
let(:page) { mock_model('Page') }
|
|
603
|
+
|
|
604
|
+
before do
|
|
605
|
+
expect(Page).to receive(:layout_root_for).and_return(page)
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
it "returns layout root page" do
|
|
609
|
+
is_expected.to eq(page)
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
describe '.language_roots' do
|
|
615
|
+
it "should return 1 language_root" do
|
|
616
|
+
FactoryGirl.create(:public_page, name: 'First Public Child', parent_id: language_root.id, language: language)
|
|
617
|
+
expect(Page.language_roots.size).to eq(1)
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
describe '.layoutpages' do
|
|
622
|
+
it "should return 1 layoutpage" do
|
|
623
|
+
FactoryGirl.create(:public_page, layoutpage: true, name: 'Layoutpage', parent_id: rootpage.id, language: language)
|
|
624
|
+
expect(Page.layoutpages.size).to eq(1)
|
|
625
|
+
end
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
describe '.not_locked' do
|
|
629
|
+
it "should return pages that are not blocked by a user at the moment" do
|
|
630
|
+
FactoryGirl.create(:public_page, locked: true, name: 'First Public Child', parent_id: language_root.id, language: language)
|
|
631
|
+
FactoryGirl.create(:public_page, name: 'Second Public Child', parent_id: language_root.id, language: language)
|
|
632
|
+
expect(Page.not_locked.size).to eq(3)
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
describe '.not_restricted' do
|
|
637
|
+
it "should return 2 accessible pages" do
|
|
638
|
+
FactoryGirl.create(:public_page, name: 'First Public Child', restricted: true, parent_id: language_root.id, language: language)
|
|
639
|
+
expect(Page.not_restricted.size).to eq(2)
|
|
640
|
+
end
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
describe '.public' do
|
|
644
|
+
it "should return pages that are public" do
|
|
645
|
+
FactoryGirl.create(:public_page, name: 'First Public Child', parent_id: language_root.id, language: language)
|
|
646
|
+
FactoryGirl.create(:public_page, name: 'Second Public Child', parent_id: language_root.id, language: language)
|
|
647
|
+
expect(Page.published.size).to eq(3)
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
describe '.restricted' do
|
|
652
|
+
it "should return 1 restricted page" do
|
|
653
|
+
FactoryGirl.create(:public_page, name: 'First Public Child', restricted: true, parent_id: language_root.id, language: language)
|
|
654
|
+
expect(Page.restricted.size).to eq(1)
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
describe '.rootpage' do
|
|
659
|
+
it "should contain one rootpage" do
|
|
660
|
+
expect(Page.rootpage).to be_instance_of(Page)
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
describe '.visible' do
|
|
665
|
+
it "should return 1 visible page" do
|
|
666
|
+
FactoryGirl.create(:public_page, name: 'First Public Child', visible: true, parent_id: language_root.id, language: language)
|
|
667
|
+
expect(Page.visible.size).to eq(1)
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
# InstanceMethods (a-z)
|
|
673
|
+
|
|
674
|
+
describe '#available_element_definitions' do
|
|
675
|
+
let(:page) { FactoryGirl.build_stubbed(:public_page) }
|
|
676
|
+
|
|
677
|
+
it "returns all element definitions of available elements" do
|
|
678
|
+
expect(page.available_element_definitions).to be_an(Array)
|
|
679
|
+
expect(page.available_element_definitions.collect { |e| e['name'] }).to include('header')
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
context "with unique elements already on page" do
|
|
683
|
+
let(:element) { FactoryGirl.build_stubbed(:unique_element) }
|
|
684
|
+
|
|
685
|
+
before do
|
|
686
|
+
allow(page)
|
|
687
|
+
.to receive(:elements)
|
|
688
|
+
.and_return double(not_trashed: double(pluck: [element.name]))
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
it "does not return unique element definitions" do
|
|
692
|
+
expect(page.available_element_definitions.collect { |e| e['name'] }).to include('article')
|
|
693
|
+
expect(page.available_element_definitions.collect { |e| e['name'] }).not_to include('header')
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
context 'limited amount' do
|
|
698
|
+
let(:page) { FactoryGirl.build_stubbed(:page, page_layout: 'columns') }
|
|
699
|
+
let(:unique_element) { FactoryGirl.build_stubbed(:unique_element, name: 'unique_headline') }
|
|
700
|
+
let(:element_1) { FactoryGirl.build_stubbed(:element, name: 'column_headline') }
|
|
701
|
+
let(:element_2) { FactoryGirl.build_stubbed(:element, name: 'column_headline') }
|
|
702
|
+
let(:element_3) { FactoryGirl.build_stubbed(:element, name: 'column_headline') }
|
|
703
|
+
|
|
704
|
+
before {
|
|
705
|
+
allow(Element).to receive(:definitions).and_return([
|
|
706
|
+
{
|
|
707
|
+
'name' => 'column_headline',
|
|
708
|
+
'amount' => 3,
|
|
709
|
+
'contents' => [{'name' => 'headline', 'type' => 'EssenceText'}]
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
'name' => 'unique_headline',
|
|
713
|
+
'unique' => true,
|
|
714
|
+
'amount' => 3,
|
|
715
|
+
'contents' => [{'name' => 'headline', 'type' => 'EssenceText'}]
|
|
716
|
+
}
|
|
717
|
+
])
|
|
718
|
+
allow(PageLayout).to receive(:get).and_return({
|
|
719
|
+
'name' => 'columns',
|
|
720
|
+
'elements' => ['column_headline', 'unique_headline'],
|
|
721
|
+
'autogenerate' => ['unique_headline', 'column_headline', 'column_headline', 'column_headline']
|
|
722
|
+
})
|
|
723
|
+
allow(page).to receive(:elements).and_return double(
|
|
724
|
+
not_trashed: double(pluck: [
|
|
725
|
+
unique_element.name,
|
|
726
|
+
element_1.name,
|
|
727
|
+
element_2.name,
|
|
728
|
+
element_3.name
|
|
729
|
+
])
|
|
730
|
+
)
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
it "should be readable" do
|
|
734
|
+
element = page.element_definitions_by_name('column_headline').first
|
|
735
|
+
expect(element['amount']).to be 3
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
it "should limit elements" do
|
|
739
|
+
expect(page.available_element_definitions.collect { |e| e['name'] }).not_to include('column_headline')
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
it "should be ignored if unique" do
|
|
743
|
+
expect(page.available_element_definitions.collect { |e| e['name'] }).not_to include('unique_headline')
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
describe '#available_element_names' do
|
|
749
|
+
let(:page) { FactoryGirl.build_stubbed(:page) }
|
|
750
|
+
|
|
751
|
+
it "returns all names of elements that could be placed on current page" do
|
|
752
|
+
page.available_element_names == %w(header article)
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
describe '#cache_key' do
|
|
757
|
+
let(:page) do
|
|
758
|
+
stub_model(Page, updated_at: Time.now, published_at: Time.now - 1.week)
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
subject { page.cache_key }
|
|
762
|
+
|
|
763
|
+
before do
|
|
764
|
+
expect(Page).to receive(:current_preview).and_return(preview)
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
context "when current page rendered in preview mode" do
|
|
768
|
+
let(:preview) { page }
|
|
769
|
+
|
|
770
|
+
it { is_expected.to eq("alchemy/pages/#{page.id}-#{page.updated_at}") }
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
context "when current page not in preview mode" do
|
|
774
|
+
let(:preview) { nil }
|
|
775
|
+
|
|
776
|
+
it { is_expected.to eq("alchemy/pages/#{page.id}-#{page.published_at}") }
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
describe '#cell_definitions' do
|
|
781
|
+
before do
|
|
782
|
+
@page = FactoryGirl.build(:page, page_layout: 'foo')
|
|
783
|
+
allow(@page).to receive(:definition).and_return({'name' => "foo", 'cells' => ["foo_cell"]})
|
|
784
|
+
@cell_descriptions = [{'name' => "foo_cell", 'elements' => ["1", "2"]}]
|
|
785
|
+
allow(Cell).to receive(:definitions).and_return(@cell_descriptions)
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
it "should return all cell definitions for its page_layout" do
|
|
789
|
+
expect(@page.cell_definitions).to eq(@cell_descriptions)
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
it "should return empty array if no cells defined in page layout" do
|
|
793
|
+
allow(@page).to receive(:definition).and_return({'name' => "foo"})
|
|
794
|
+
expect(@page.cell_definitions).to eq([])
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
describe '#destroy' do
|
|
799
|
+
context "with trashed but still assigned elements" do
|
|
800
|
+
before { news_page.elements.map(&:trash!) }
|
|
801
|
+
|
|
802
|
+
it "should not delete the trashed elements" do
|
|
803
|
+
news_page.destroy
|
|
804
|
+
expect(Element.trashed).not_to be_empty
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
describe '#element_definitions' do
|
|
810
|
+
let(:page) { FactoryGirl.build_stubbed(:page) }
|
|
811
|
+
subject { page.element_definitions }
|
|
812
|
+
before { expect(Element).to receive(:definitions).and_return([{'name' => 'article'}, {'name' => 'header'}]) }
|
|
813
|
+
|
|
814
|
+
it "returns all element definitions that could be placed on current page" do
|
|
815
|
+
is_expected.to include({'name' => 'article'})
|
|
816
|
+
is_expected.to include({'name' => 'header'})
|
|
817
|
+
end
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
describe '#element_definitions_by_name' do
|
|
821
|
+
let(:page) { FactoryGirl.build_stubbed(:public_page) }
|
|
822
|
+
|
|
823
|
+
context "with no name given" do
|
|
824
|
+
it "returns empty array" do
|
|
825
|
+
expect(page.element_definitions_by_name(nil)).to eq([])
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
context "with 'all' passed as name" do
|
|
830
|
+
it "returns all element definitions" do
|
|
831
|
+
expect(Element).to receive(:definitions)
|
|
832
|
+
page.element_definitions_by_name('all')
|
|
833
|
+
end
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
context "with :all passed as name" do
|
|
837
|
+
it "returns all element definitions" do
|
|
838
|
+
expect(Element).to receive(:definitions)
|
|
839
|
+
page.element_definitions_by_name(:all)
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
describe '#element_definition_names' do
|
|
845
|
+
let(:page) { FactoryGirl.build_stubbed(:public_page) }
|
|
846
|
+
|
|
847
|
+
context "with assigned elements from page and cell definition" do
|
|
848
|
+
before do
|
|
849
|
+
allow(page).to receive(:element_names_from_page_definition).and_return(['header', 'article'])
|
|
850
|
+
allow(page).to receive(:element_names_from_cell_definition).and_return(['search'])
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
it "returns the combined element names" do
|
|
854
|
+
expect(page.element_definition_names).to eq(%w(header article search))
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
context "when cell definition contains same element name as page definition" do
|
|
858
|
+
before do
|
|
859
|
+
allow(page).to receive(:element_names_from_page_definition).and_return(['header', 'article'])
|
|
860
|
+
allow(page).to receive(:element_names_from_cell_definition).and_return(['header', 'search'])
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
it "returns no duplicates" do
|
|
864
|
+
expect(page.element_definition_names).to eq(%w(header article search))
|
|
865
|
+
end
|
|
866
|
+
end
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
context "without assigned elements from page definition" do
|
|
870
|
+
before do
|
|
871
|
+
allow(page).to receive(:element_names_from_page_definition).and_return([])
|
|
872
|
+
allow(page).to receive(:element_names_from_cell_definition).and_return(['article'])
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
it "returns an array" do
|
|
876
|
+
expect(page.element_definition_names).to be_an(Array)
|
|
877
|
+
end
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
context "without assigned elements from cell definition" do
|
|
881
|
+
before do
|
|
882
|
+
allow(page).to receive(:element_names_from_page_definition).and_return(['article'])
|
|
883
|
+
allow(page).to receive(:element_names_from_cell_definition).and_return([])
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
it "returns an array" do
|
|
887
|
+
expect(page.element_definition_names).to be_an(Array)
|
|
888
|
+
end
|
|
889
|
+
end
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
describe "#element_names_from_page_definition" do
|
|
893
|
+
let(:page) { FactoryGirl.build_stubbed(:public_page) }
|
|
894
|
+
|
|
895
|
+
context "with assigned elements from page definition" do
|
|
896
|
+
before do
|
|
897
|
+
allow(page).to receive(:definition).and_return(
|
|
898
|
+
{'name' => 'test_page', 'elements' => ['article']}
|
|
899
|
+
)
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
it "returns an array of the page's element names" do
|
|
903
|
+
expect(page.element_names_from_page_definition).to eq(['article'])
|
|
904
|
+
end
|
|
905
|
+
end
|
|
906
|
+
|
|
907
|
+
context "without assigned elements from page definition" do
|
|
908
|
+
before do
|
|
909
|
+
allow(page).to receive(:definition).and_return({})
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
it "returns an array" do
|
|
913
|
+
expect(page.element_names_from_page_definition).to be_an(Array)
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
describe "#element_names_from_cell_definition" do
|
|
919
|
+
let(:page) { FactoryGirl.build_stubbed(:public_page) }
|
|
920
|
+
|
|
921
|
+
context "with assigned elements from cell definition" do
|
|
922
|
+
before do
|
|
923
|
+
allow(page).to receive(:cell_definitions).and_return([
|
|
924
|
+
{'name' => 'header', 'elements' => ['article']}
|
|
925
|
+
])
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
it "returns an array of the cell's element names" do
|
|
929
|
+
expect(page.element_names_from_cell_definition).to eq(['article'])
|
|
930
|
+
end
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
context "without assigned elements from cell definition" do
|
|
934
|
+
it "returns an array" do
|
|
935
|
+
expect(page.element_names_from_cell_definition).to be_an(Array)
|
|
936
|
+
end
|
|
937
|
+
end
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
describe '#elements_grouped_by_cells' do
|
|
941
|
+
let(:page) { FactoryGirl.create(:public_page, do_not_autogenerate: false) }
|
|
942
|
+
|
|
943
|
+
before do
|
|
944
|
+
allow(PageLayout).to receive(:get).and_return({
|
|
945
|
+
'name' => 'standard',
|
|
946
|
+
'cells' => ['header'],
|
|
947
|
+
'elements' => ['header', 'text'],
|
|
948
|
+
'autogenerate' => ['header', 'text']
|
|
949
|
+
})
|
|
950
|
+
allow(Cell).to receive(:definitions).and_return([{
|
|
951
|
+
'name' => "header",
|
|
952
|
+
'elements' => ["header"]
|
|
953
|
+
}])
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
it "should return elements grouped by cell" do
|
|
957
|
+
elements = page.elements_grouped_by_cells
|
|
958
|
+
expect(elements.keys.first).to be_instance_of(Cell)
|
|
959
|
+
expect(elements.values.first.first).to be_instance_of(Element)
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
it "should only include elements beeing in a cell " do
|
|
963
|
+
expect(page.elements_grouped_by_cells.keys).not_to include(nil)
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
describe '#feed_elements' do
|
|
968
|
+
it "should return all rss feed elements" do
|
|
969
|
+
expect(news_page.feed_elements).not_to be_empty
|
|
970
|
+
expect(news_page.feed_elements).to eq(Element.where(name: 'news').to_a)
|
|
971
|
+
end
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
describe '#find_elements' do
|
|
975
|
+
before do
|
|
976
|
+
FactoryGirl.create(:element, public: false, page: public_page)
|
|
977
|
+
FactoryGirl.create(:element, public: false, page: public_page)
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
context "with show_non_public argument TRUE" do
|
|
981
|
+
it "should return all elements from empty options" do
|
|
982
|
+
expect(public_page.find_elements({}, true).to_a).to eq(public_page.elements.to_a)
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
it "should only return the elements passed as options[:only]" do
|
|
986
|
+
expect(public_page.find_elements({only: ['article']}, true).to_a).to eq(public_page.elements.named('article').to_a)
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
it "should not return the elements passed as options[:except]" do
|
|
990
|
+
expect(public_page.find_elements({except: ['article']}, true).to_a).to eq(public_page.elements - public_page.elements.named('article').to_a)
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
it "should return elements offsetted" do
|
|
994
|
+
expect(public_page.find_elements({offset: 2}, true).to_a).to eq(public_page.elements.offset(2))
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
it "should return elements limitted in count" do
|
|
998
|
+
expect(public_page.find_elements({count: 1}, true).to_a).to eq(public_page.elements.limit(1))
|
|
999
|
+
end
|
|
1000
|
+
end
|
|
1001
|
+
|
|
1002
|
+
context "with options[:from_cell]" do
|
|
1003
|
+
let(:element) { FactoryGirl.build_stubbed(:element) }
|
|
1004
|
+
|
|
1005
|
+
context "given as String" do
|
|
1006
|
+
context 'with elements present' do
|
|
1007
|
+
before do
|
|
1008
|
+
expect(public_page.cells)
|
|
1009
|
+
.to receive(:find_by_name)
|
|
1010
|
+
.and_return double(elements: double(offset: double(limit: double(published: [element]))))
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
it "returns only the elements from given cell" do
|
|
1014
|
+
expect(public_page.find_elements(from_cell: 'A Cell').to_a).to eq([element])
|
|
1015
|
+
end
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
context "that can not be found" do
|
|
1019
|
+
let(:elements) {[]}
|
|
1020
|
+
|
|
1021
|
+
before do
|
|
1022
|
+
allow(elements)
|
|
1023
|
+
.to receive(:offset)
|
|
1024
|
+
.and_return double(limit: double(published: elements))
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
it "returns empty set" do
|
|
1028
|
+
expect(Element).to receive(:none).and_return(elements)
|
|
1029
|
+
expect(public_page.find_elements(from_cell: 'Lolo').to_a).to eq([])
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
it "loggs a warning" do
|
|
1033
|
+
expect(Rails.logger).to receive(:debug)
|
|
1034
|
+
public_page.find_elements(from_cell: 'Lolo')
|
|
1035
|
+
end
|
|
1036
|
+
end
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
context "given as cell object" do
|
|
1040
|
+
let(:cell) { FactoryGirl.build_stubbed(:cell, page: public_page) }
|
|
1041
|
+
|
|
1042
|
+
it "returns only the elements from given cell" do
|
|
1043
|
+
expect(cell)
|
|
1044
|
+
.to receive(:elements)
|
|
1045
|
+
.and_return double(offset: double(limit: double(published: [element])))
|
|
1046
|
+
|
|
1047
|
+
expect(public_page.find_elements(from_cell: cell).to_a).to eq([element])
|
|
1048
|
+
end
|
|
1049
|
+
end
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
context "with show_non_public argument FALSE" do
|
|
1053
|
+
it "should return all elements from empty arguments" do
|
|
1054
|
+
expect(public_page.find_elements().to_a).to eq(public_page.elements.published.to_a)
|
|
1055
|
+
end
|
|
1056
|
+
|
|
1057
|
+
it "should only return the public elements passed as options[:only]" do
|
|
1058
|
+
expect(public_page.find_elements(only: ['article']).to_a).to eq(public_page.elements.published.named('article').to_a)
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
it "should return all public elements except the ones passed as options[:except]" do
|
|
1062
|
+
expect(public_page.find_elements(except: ['article']).to_a).to eq(public_page.elements.published.to_a - public_page.elements.published.named('article').to_a)
|
|
1063
|
+
end
|
|
1064
|
+
|
|
1065
|
+
it "should return elements offsetted" do
|
|
1066
|
+
expect(public_page.find_elements({offset: 2}).to_a).to eq(public_page.elements.published.offset(2))
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
it "should return elements limitted in count" do
|
|
1070
|
+
expect(public_page.find_elements({count: 1}).to_a).to eq(public_page.elements.published.limit(1))
|
|
1071
|
+
end
|
|
1072
|
+
end
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
describe '#first_public_child' do
|
|
1076
|
+
before do
|
|
1077
|
+
FactoryGirl.create(:page, name: "First child", language: language, public: false, parent_id: language_root.id)
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
it "should return first_public_child" do
|
|
1081
|
+
first_public_child = FactoryGirl.create(:public_page, name: "First public child", language: language, parent_id: language_root.id)
|
|
1082
|
+
expect(language_root.first_public_child).to eq(first_public_child)
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
it "should return nil if no public child exists" do
|
|
1086
|
+
expect(language_root.first_public_child).to eq(nil)
|
|
1087
|
+
end
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
context 'folding' do
|
|
1091
|
+
let(:user) { mock_model('DummyUser') }
|
|
1092
|
+
|
|
1093
|
+
describe '#fold!' do
|
|
1094
|
+
context "with folded status set to true" do
|
|
1095
|
+
it "should create a folded page for user" do
|
|
1096
|
+
public_page.fold!(user.id, true)
|
|
1097
|
+
expect(public_page.folded_pages.first.user_id).to eq(user.id)
|
|
1098
|
+
end
|
|
1099
|
+
end
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
describe '#folded?' do
|
|
1103
|
+
let(:page) { Page.new }
|
|
1104
|
+
|
|
1105
|
+
context 'with user is a active record model' do
|
|
1106
|
+
before do
|
|
1107
|
+
expect(Alchemy.user_class).to receive(:'<').and_return(true)
|
|
1108
|
+
end
|
|
1109
|
+
|
|
1110
|
+
context 'if page is folded' do
|
|
1111
|
+
before do
|
|
1112
|
+
expect(page)
|
|
1113
|
+
.to receive(:folded_pages)
|
|
1114
|
+
.and_return double(where: double(any?: true))
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
it "should return true" do
|
|
1118
|
+
expect(page.folded?(user.id)).to eq(true)
|
|
1119
|
+
end
|
|
1120
|
+
end
|
|
1121
|
+
|
|
1122
|
+
context 'if page is not folded' do
|
|
1123
|
+
it "should return false" do
|
|
1124
|
+
expect(page.folded?(101093)).to eq(false)
|
|
1125
|
+
end
|
|
1126
|
+
end
|
|
1127
|
+
end
|
|
1128
|
+
end
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1131
|
+
describe '#get_language_root' do
|
|
1132
|
+
before { language_root }
|
|
1133
|
+
subject { public_page.get_language_root }
|
|
1134
|
+
|
|
1135
|
+
it "returns the language root page" do
|
|
1136
|
+
is_expected.to eq language_root
|
|
1137
|
+
end
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1140
|
+
describe '#layout_description' do
|
|
1141
|
+
context 'if the page layout could not be found in the definition file' do
|
|
1142
|
+
let(:page) { build_stubbed(:page, page_layout: 'notexisting') }
|
|
1143
|
+
|
|
1144
|
+
it "it loggs a warning." do
|
|
1145
|
+
expect(Alchemy::Logger).to receive(:warn)
|
|
1146
|
+
page.layout_description
|
|
1147
|
+
end
|
|
1148
|
+
|
|
1149
|
+
it "it returns empty hash." do
|
|
1150
|
+
expect(page.layout_description).to eq({})
|
|
1151
|
+
end
|
|
1152
|
+
end
|
|
1153
|
+
|
|
1154
|
+
context "for a language root page" do
|
|
1155
|
+
it "it returns the page layout description as hash." do
|
|
1156
|
+
expect(language_root.layout_description['name']).to eq('index')
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
it "it returns an empty hash for root page." do
|
|
1160
|
+
expect(rootpage.layout_description).to eq({})
|
|
1161
|
+
end
|
|
1162
|
+
end
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
describe '#lock_to!' do
|
|
1166
|
+
let(:page) { create(:page) }
|
|
1167
|
+
let(:user) { mock_model('DummyUser') }
|
|
1168
|
+
|
|
1169
|
+
it "should set locked to true" do
|
|
1170
|
+
page.lock_to!(user)
|
|
1171
|
+
page.reload
|
|
1172
|
+
expect(page.locked).to eq(true)
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
it "should not update the timestamps " do
|
|
1176
|
+
expect { page.lock!(user) }.to_not change(page, :updated_at)
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
it "should set locked_by to the users id" do
|
|
1180
|
+
page.lock_to!(user)
|
|
1181
|
+
page.reload
|
|
1182
|
+
expect(page.locked_by).to eq(user.id)
|
|
1183
|
+
end
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
describe '#copy_and_paste' do
|
|
1187
|
+
let(:source) { FactoryGirl.build_stubbed(:page) }
|
|
1188
|
+
let(:new_parent) { FactoryGirl.build_stubbed(:page) }
|
|
1189
|
+
let(:page_name) { "Pagename (pasted)" }
|
|
1190
|
+
let(:copied_page) { mock_model('Page') }
|
|
1191
|
+
|
|
1192
|
+
subject { Page.copy_and_paste(source, new_parent, page_name) }
|
|
1193
|
+
|
|
1194
|
+
it "should copy the source page with the given name to the new parent" do
|
|
1195
|
+
expect(Page).to receive(:copy).with(source, {
|
|
1196
|
+
parent_id: new_parent.id,
|
|
1197
|
+
language: new_parent.language,
|
|
1198
|
+
name: page_name,
|
|
1199
|
+
title: page_name
|
|
1200
|
+
})
|
|
1201
|
+
subject
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
it "should return the copied page" do
|
|
1205
|
+
allow(Page).to receive(:copy).and_return(copied_page)
|
|
1206
|
+
expect(subject).to be_a(copied_page.class)
|
|
1207
|
+
end
|
|
1208
|
+
|
|
1209
|
+
context "if source page has children" do
|
|
1210
|
+
it "should also copy and paste the children" do
|
|
1211
|
+
allow(Page).to receive(:copy).and_return(copied_page)
|
|
1212
|
+
allow(source).to receive(:children).and_return([mock_model('Page')])
|
|
1213
|
+
expect(source).to receive(:copy_children_to).with(copied_page)
|
|
1214
|
+
subject
|
|
1215
|
+
end
|
|
1216
|
+
end
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
context 'previous and next.' do
|
|
1220
|
+
let(:center_page) { FactoryGirl.create(:public_page, name: 'Center Page') }
|
|
1221
|
+
let(:next_page) { FactoryGirl.create(:public_page, name: 'Next Page') }
|
|
1222
|
+
let(:non_public_page) { FactoryGirl.create(:page, name: 'Not public Page') }
|
|
1223
|
+
let(:restricted_page) { FactoryGirl.create(:restricted_page, public: true) }
|
|
1224
|
+
|
|
1225
|
+
before do
|
|
1226
|
+
public_page
|
|
1227
|
+
restricted_page
|
|
1228
|
+
non_public_page
|
|
1229
|
+
center_page
|
|
1230
|
+
next_page
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
describe '#previous' do
|
|
1234
|
+
it "should return the previous page on the same level" do
|
|
1235
|
+
expect(center_page.previous).to eq(public_page)
|
|
1236
|
+
expect(next_page.previous).to eq(center_page)
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
context "no previous page on same level present" do
|
|
1240
|
+
it "should return nil" do
|
|
1241
|
+
expect(public_page.previous).to be_nil
|
|
1242
|
+
end
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
context "with options restricted" do
|
|
1246
|
+
context "set to true" do
|
|
1247
|
+
it "returns previous restricted page" do
|
|
1248
|
+
expect(center_page.previous(restricted: true)).to eq(restricted_page)
|
|
1249
|
+
end
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
context "set to false" do
|
|
1253
|
+
it "skips restricted page" do
|
|
1254
|
+
expect(center_page.previous(restricted: false)).to eq(public_page)
|
|
1255
|
+
end
|
|
1256
|
+
end
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1259
|
+
context "with options public" do
|
|
1260
|
+
context "set to true" do
|
|
1261
|
+
it "returns previous public page" do
|
|
1262
|
+
expect(center_page.previous(public: true)).to eq(public_page)
|
|
1263
|
+
end
|
|
1264
|
+
end
|
|
1265
|
+
|
|
1266
|
+
context "set to false" do
|
|
1267
|
+
it "skips public page" do
|
|
1268
|
+
expect(center_page.previous(public: false)).to eq(non_public_page)
|
|
1269
|
+
end
|
|
1270
|
+
end
|
|
1271
|
+
end
|
|
1272
|
+
end
|
|
1273
|
+
|
|
1274
|
+
describe '#next' do
|
|
1275
|
+
it "should return the next page on the same level" do
|
|
1276
|
+
expect(center_page.next).to eq(next_page)
|
|
1277
|
+
end
|
|
1278
|
+
|
|
1279
|
+
context "no next page on same level present" do
|
|
1280
|
+
it "should return nil" do
|
|
1281
|
+
expect(next_page.next).to be_nil
|
|
1282
|
+
end
|
|
1283
|
+
end
|
|
1284
|
+
end
|
|
1285
|
+
end
|
|
1286
|
+
|
|
1287
|
+
describe '#publish!' do
|
|
1288
|
+
let(:page) { FactoryGirl.build_stubbed(:page, public: false) }
|
|
1289
|
+
let(:current_time) { Time.now }
|
|
1290
|
+
|
|
1291
|
+
before do
|
|
1292
|
+
current_time
|
|
1293
|
+
allow(Time).to receive(:now).and_return(current_time)
|
|
1294
|
+
page.publish!
|
|
1295
|
+
end
|
|
1296
|
+
|
|
1297
|
+
it "sets public attribute to true" do
|
|
1298
|
+
expect(page.public).to eq(true)
|
|
1299
|
+
end
|
|
1300
|
+
|
|
1301
|
+
it "sets published_at attribute to current time" do
|
|
1302
|
+
expect(page.published_at).to eq(current_time)
|
|
1303
|
+
end
|
|
1304
|
+
end
|
|
1305
|
+
|
|
1306
|
+
describe '#set_language_from_parent_or_default' do
|
|
1307
|
+
let(:default_language) { mock_model('Language', code: 'es') }
|
|
1308
|
+
let(:page) { Page.new }
|
|
1309
|
+
|
|
1310
|
+
before { allow(page).to receive(:parent).and_return(parent) }
|
|
1311
|
+
|
|
1312
|
+
subject { page }
|
|
1313
|
+
|
|
1314
|
+
context "parent has a language" do
|
|
1315
|
+
let(:parent) { mock_model('Page', language: default_language, language_id: default_language.id, language_code: default_language.code) }
|
|
1316
|
+
|
|
1317
|
+
before do
|
|
1318
|
+
page.send(:set_language_from_parent_or_default)
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
describe '#language_id' do
|
|
1322
|
+
subject { super().language_id }
|
|
1323
|
+
it { is_expected.to eq(parent.language_id) }
|
|
1324
|
+
end
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
context "parent has no language" do
|
|
1328
|
+
let(:parent) { mock_model('Page', language: nil, language_id: nil, language_code: nil) }
|
|
1329
|
+
|
|
1330
|
+
before do
|
|
1331
|
+
allow(Language).to receive(:default).and_return(default_language)
|
|
1332
|
+
page.send(:set_language_from_parent_or_default)
|
|
1333
|
+
end
|
|
1334
|
+
|
|
1335
|
+
describe '#language_id' do
|
|
1336
|
+
subject { super().language_id }
|
|
1337
|
+
it { is_expected.to eq(default_language.id) }
|
|
1338
|
+
end
|
|
1339
|
+
end
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1342
|
+
describe '#taggable?' do
|
|
1343
|
+
context "definition has 'taggable' key with true value" do
|
|
1344
|
+
it "should return true" do
|
|
1345
|
+
page = FactoryGirl.build(:page)
|
|
1346
|
+
allow(page).to receive(:definition).and_return({'name' => 'standard', 'taggable' => true})
|
|
1347
|
+
expect(page.taggable?).to be_truthy
|
|
1348
|
+
end
|
|
1349
|
+
end
|
|
1350
|
+
|
|
1351
|
+
context "definition has 'taggable' key with foo value" do
|
|
1352
|
+
it "should return false" do
|
|
1353
|
+
page = FactoryGirl.build(:page)
|
|
1354
|
+
allow(page).to receive(:definition).and_return({'name' => 'standard', 'taggable' => 'foo'})
|
|
1355
|
+
expect(page.taggable?).to be_falsey
|
|
1356
|
+
end
|
|
1357
|
+
end
|
|
1358
|
+
|
|
1359
|
+
context "definition has no 'taggable' key" do
|
|
1360
|
+
it "should return false" do
|
|
1361
|
+
page = FactoryGirl.build(:page)
|
|
1362
|
+
allow(page).to receive(:definition).and_return({'name' => 'standard'})
|
|
1363
|
+
expect(page.taggable?).to be_falsey
|
|
1364
|
+
end
|
|
1365
|
+
end
|
|
1366
|
+
end
|
|
1367
|
+
|
|
1368
|
+
describe '#unlock!' do
|
|
1369
|
+
let(:page) { FactoryGirl.create(:page, locked: true, locked_by: 1) }
|
|
1370
|
+
|
|
1371
|
+
before do
|
|
1372
|
+
allow(page).to receive(:save).and_return(true)
|
|
1373
|
+
end
|
|
1374
|
+
|
|
1375
|
+
it "should set the locked status to false" do
|
|
1376
|
+
page.unlock!
|
|
1377
|
+
page.reload
|
|
1378
|
+
expect(page.locked).to eq(false)
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
it "should not update the timestamps " do
|
|
1382
|
+
expect { page.unlock! }.to_not change(page, :updated_at)
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
it "should set locked_by to nil" do
|
|
1386
|
+
page.unlock!
|
|
1387
|
+
page.reload
|
|
1388
|
+
expect(page.locked_by).to eq(nil)
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
it "sets current preview to nil" do
|
|
1392
|
+
Page.current_preview = page
|
|
1393
|
+
page.unlock!
|
|
1394
|
+
expect(Page.current_preview).to be_nil
|
|
1395
|
+
end
|
|
1396
|
+
end
|
|
1397
|
+
|
|
1398
|
+
context 'urlname updating' do
|
|
1399
|
+
let(:parentparent) { FactoryGirl.create(:page, name: 'parentparent', visible: true) }
|
|
1400
|
+
let(:parent) { FactoryGirl.create(:page, parent_id: parentparent.id, name: 'parent', visible: true) }
|
|
1401
|
+
let(:page) { FactoryGirl.create(:page, parent_id: parent.id, name: 'page', visible: true) }
|
|
1402
|
+
let(:invisible) { FactoryGirl.create(:page, parent_id: page.id, name: 'invisible', visible: false) }
|
|
1403
|
+
let(:contact) { FactoryGirl.create(:page, parent_id: invisible.id, name: 'contact', visible: true) }
|
|
1404
|
+
let(:external) { FactoryGirl.create(:page, parent_id: parent.id, name: 'external', page_layout: 'external', urlname: 'http://google.com') }
|
|
1405
|
+
let(:language_root) { parentparent.parent }
|
|
1406
|
+
|
|
1407
|
+
context "with activated url_nesting" do
|
|
1408
|
+
before { allow(Config).to receive(:get).and_return(true) }
|
|
1409
|
+
|
|
1410
|
+
it "should store all parents urlnames delimited by slash" do
|
|
1411
|
+
expect(page.urlname).to eq('parentparent/parent/page')
|
|
1412
|
+
end
|
|
1413
|
+
|
|
1414
|
+
it "should not include the root page" do
|
|
1415
|
+
Page.root.update_column(:urlname, 'root')
|
|
1416
|
+
language_root.update(urlname: 'new-urlname')
|
|
1417
|
+
expect(language_root.urlname).not_to match(/root/)
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
it "should not include the language root page" do
|
|
1421
|
+
expect(page.urlname).not_to match(/startseite/)
|
|
1422
|
+
end
|
|
1423
|
+
|
|
1424
|
+
it "should not include invisible pages" do
|
|
1425
|
+
expect(contact.urlname).not_to match(/invisible/)
|
|
1426
|
+
end
|
|
1427
|
+
|
|
1428
|
+
context "with an invisible parent" do
|
|
1429
|
+
before { parent.update_attribute(:visible, false) }
|
|
1430
|
+
|
|
1431
|
+
it "does not change if set_urlname is called" do
|
|
1432
|
+
expect { page.send(:set_urlname) }.not_to change { page.urlname }
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
it "does not change if update_urlname! is called" do
|
|
1436
|
+
expect { page.update_urlname! }.not_to change { page.urlname }
|
|
1437
|
+
end
|
|
1438
|
+
end
|
|
1439
|
+
|
|
1440
|
+
context "after changing page's urlname" do
|
|
1441
|
+
it "updates urlnames of descendants" do
|
|
1442
|
+
page
|
|
1443
|
+
parentparent.urlname = 'new-urlname'
|
|
1444
|
+
parentparent.save!
|
|
1445
|
+
page.reload
|
|
1446
|
+
expect(page.urlname).to eq('new-urlname/parent/page')
|
|
1447
|
+
end
|
|
1448
|
+
|
|
1449
|
+
context 'with descendants that are redirecting to external' do
|
|
1450
|
+
it "it skips this page" do
|
|
1451
|
+
external
|
|
1452
|
+
parent.urlname = 'new-urlname'
|
|
1453
|
+
parent.save!
|
|
1454
|
+
external.reload
|
|
1455
|
+
expect(external.urlname).to eq('http://google.com')
|
|
1456
|
+
end
|
|
1457
|
+
end
|
|
1458
|
+
|
|
1459
|
+
it "should create a legacy url" do
|
|
1460
|
+
allow(page).to receive(:slug).and_return('foo')
|
|
1461
|
+
page.update_urlname!
|
|
1462
|
+
expect(page.legacy_urls).not_to be_empty
|
|
1463
|
+
expect(page.legacy_urls.pluck(:urlname)).to include('parentparent/parent/page')
|
|
1464
|
+
end
|
|
1465
|
+
end
|
|
1466
|
+
|
|
1467
|
+
context "after updating my visibility" do
|
|
1468
|
+
it "should update urlnames of descendants" do
|
|
1469
|
+
page
|
|
1470
|
+
parentparent.visible = false
|
|
1471
|
+
parentparent.save!
|
|
1472
|
+
page.reload
|
|
1473
|
+
expect(page.urlname).to eq('parent/page')
|
|
1474
|
+
end
|
|
1475
|
+
end
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
context "with disabled url_nesting" do
|
|
1479
|
+
before { allow(Config).to receive(:get).and_return(false) }
|
|
1480
|
+
|
|
1481
|
+
it "should only store my urlname" do
|
|
1482
|
+
expect(page.urlname).to eq('page')
|
|
1483
|
+
end
|
|
1484
|
+
end
|
|
1485
|
+
end
|
|
1486
|
+
|
|
1487
|
+
describe "#update_node!" do
|
|
1488
|
+
|
|
1489
|
+
let(:original_url) { "sample-url" }
|
|
1490
|
+
let(:page) { FactoryGirl.create(:page, language: language, parent_id: language_root.id, urlname: original_url, restricted: false) }
|
|
1491
|
+
let(:node) { TreeNode.new(10, 11, 12, 13, "another-url", true) }
|
|
1492
|
+
|
|
1493
|
+
context "when nesting is enabled" do
|
|
1494
|
+
before { allow(Alchemy::Config).to receive(:get).with(:url_nesting) { true } }
|
|
1495
|
+
|
|
1496
|
+
context "when page is not external" do
|
|
1497
|
+
|
|
1498
|
+
before do
|
|
1499
|
+
expect(page).to receive(:redirects_to_external?).and_return(false)
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1502
|
+
it "should update all attributes" do
|
|
1503
|
+
page.update_node!(node)
|
|
1504
|
+
page.reload
|
|
1505
|
+
expect(page.lft).to eq(node.left)
|
|
1506
|
+
expect(page.rgt).to eq(node.right)
|
|
1507
|
+
expect(page.parent_id).to eq(node.parent)
|
|
1508
|
+
expect(page.depth).to eq(node.depth)
|
|
1509
|
+
expect(page.urlname).to eq(node.url)
|
|
1510
|
+
expect(page.restricted).to eq(node.restricted)
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
context "when url is the same" do
|
|
1514
|
+
let(:node) { TreeNode.new(10, 11, 12, 13, original_url, true) }
|
|
1515
|
+
|
|
1516
|
+
it "should not create a legacy url" do
|
|
1517
|
+
page.update_node!(node)
|
|
1518
|
+
page.reload
|
|
1519
|
+
expect(page.legacy_urls.size).to eq(0)
|
|
1520
|
+
end
|
|
1521
|
+
end
|
|
1522
|
+
|
|
1523
|
+
context "when url is not the same" do
|
|
1524
|
+
it "should create a legacy url" do
|
|
1525
|
+
page.update_node!(node)
|
|
1526
|
+
page.reload
|
|
1527
|
+
expect(page.legacy_urls.size).to eq(1)
|
|
1528
|
+
end
|
|
1529
|
+
end
|
|
1530
|
+
end
|
|
1531
|
+
|
|
1532
|
+
context "when page is external" do
|
|
1533
|
+
before do
|
|
1534
|
+
expect(page)
|
|
1535
|
+
.to receive(:redirects_to_external?)
|
|
1536
|
+
.and_return(true)
|
|
1537
|
+
end
|
|
1538
|
+
|
|
1539
|
+
it "should update all attributes except url" do
|
|
1540
|
+
page.update_node!(node)
|
|
1541
|
+
page.reload
|
|
1542
|
+
expect(page.lft).to eq(node.left)
|
|
1543
|
+
expect(page.rgt).to eq(node.right)
|
|
1544
|
+
expect(page.parent_id).to eq(node.parent)
|
|
1545
|
+
expect(page.depth).to eq(node.depth)
|
|
1546
|
+
expect(page.urlname).to eq(original_url)
|
|
1547
|
+
expect(page.restricted).to eq(node.restricted)
|
|
1548
|
+
end
|
|
1549
|
+
|
|
1550
|
+
it "should not create a legacy url" do
|
|
1551
|
+
page.update_node!(node)
|
|
1552
|
+
page.reload
|
|
1553
|
+
expect(page.legacy_urls.size).to eq(0)
|
|
1554
|
+
end
|
|
1555
|
+
end
|
|
1556
|
+
end
|
|
1557
|
+
|
|
1558
|
+
context "when nesting is disabled" do
|
|
1559
|
+
before do
|
|
1560
|
+
allow(Alchemy::Config).to receive(:get).with(:url_nesting) { false }
|
|
1561
|
+
end
|
|
1562
|
+
|
|
1563
|
+
context "when page is not external" do
|
|
1564
|
+
before do
|
|
1565
|
+
allow(page).to receive(:redirects_to_external?).and_return(false)
|
|
1566
|
+
end
|
|
1567
|
+
|
|
1568
|
+
it "should update all attributes except url" do
|
|
1569
|
+
page.update_node!(node)
|
|
1570
|
+
page.reload
|
|
1571
|
+
expect(page.lft).to eq(node.left)
|
|
1572
|
+
expect(page.rgt).to eq(node.right)
|
|
1573
|
+
expect(page.parent_id).to eq(node.parent)
|
|
1574
|
+
expect(page.depth).to eq(node.depth)
|
|
1575
|
+
expect(page.urlname).to eq(original_url)
|
|
1576
|
+
expect(page.restricted).to eq(node.restricted)
|
|
1577
|
+
end
|
|
1578
|
+
|
|
1579
|
+
it "should not create a legacy url" do
|
|
1580
|
+
page.update_node!(node)
|
|
1581
|
+
page.reload
|
|
1582
|
+
expect(page.legacy_urls.size).to eq(0)
|
|
1583
|
+
end
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
context "when page is external" do
|
|
1587
|
+
before do
|
|
1588
|
+
expect(Alchemy::Config).to receive(:get).and_return(true)
|
|
1589
|
+
allow(page).to receive(:redirects_to_external?).and_return(true)
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1592
|
+
it "should update all attributes except url" do
|
|
1593
|
+
page.update_node!(node)
|
|
1594
|
+
page.reload
|
|
1595
|
+
expect(page.lft).to eq(node.left)
|
|
1596
|
+
expect(page.rgt).to eq(node.right)
|
|
1597
|
+
expect(page.parent_id).to eq(node.parent)
|
|
1598
|
+
expect(page.depth).to eq(node.depth)
|
|
1599
|
+
expect(page.urlname).to eq(original_url)
|
|
1600
|
+
expect(page.restricted).to eq(node.restricted)
|
|
1601
|
+
end
|
|
1602
|
+
|
|
1603
|
+
it "should not create a legacy url" do
|
|
1604
|
+
page.update_node!(node)
|
|
1605
|
+
page.reload
|
|
1606
|
+
expect(page.legacy_urls.size).to eq(0)
|
|
1607
|
+
end
|
|
1608
|
+
end
|
|
1609
|
+
end
|
|
1610
|
+
end
|
|
1611
|
+
|
|
1612
|
+
describe '#slug' do
|
|
1613
|
+
context "with parents path saved in urlname" do
|
|
1614
|
+
let(:page) { FactoryGirl.build(:page, urlname: 'root/parent/my-name')}
|
|
1615
|
+
|
|
1616
|
+
it "should return the last part of the urlname" do
|
|
1617
|
+
expect(page.slug).to eq('my-name')
|
|
1618
|
+
end
|
|
1619
|
+
end
|
|
1620
|
+
|
|
1621
|
+
context "with single urlname" do
|
|
1622
|
+
let(:page) { FactoryGirl.build(:page, urlname: 'my-name')}
|
|
1623
|
+
|
|
1624
|
+
it "should return the last part of the urlname" do
|
|
1625
|
+
expect(page.slug).to eq('my-name')
|
|
1626
|
+
end
|
|
1627
|
+
end
|
|
1628
|
+
|
|
1629
|
+
context "with nil as urlname" do
|
|
1630
|
+
let(:page) { FactoryGirl.build(:page, urlname: nil)}
|
|
1631
|
+
|
|
1632
|
+
it "should return nil" do
|
|
1633
|
+
expect(page.slug).to be_nil
|
|
1634
|
+
end
|
|
1635
|
+
end
|
|
1636
|
+
end
|
|
1637
|
+
|
|
1638
|
+
describe '#external_urlname' do
|
|
1639
|
+
let(:external_page) { build(:page, page_layout: 'external') }
|
|
1640
|
+
|
|
1641
|
+
context 'with missing protocol' do
|
|
1642
|
+
before { external_page.urlname = 'google.com'}
|
|
1643
|
+
|
|
1644
|
+
it "returns an urlname prefixed with http://" do
|
|
1645
|
+
expect(external_page.external_urlname).to eq 'http://google.com'
|
|
1646
|
+
end
|
|
1647
|
+
end
|
|
1648
|
+
|
|
1649
|
+
context 'with protocol present' do
|
|
1650
|
+
before { external_page.urlname = 'ftp://google.com'}
|
|
1651
|
+
|
|
1652
|
+
it "returns the urlname" do
|
|
1653
|
+
expect(external_page.external_urlname).to eq 'ftp://google.com'
|
|
1654
|
+
end
|
|
1655
|
+
end
|
|
1656
|
+
|
|
1657
|
+
context 'beginngin with a slash' do
|
|
1658
|
+
before { external_page.urlname = '/internal-url'}
|
|
1659
|
+
|
|
1660
|
+
it "returns the urlname" do
|
|
1661
|
+
expect(external_page.external_urlname).to eq '/internal-url'
|
|
1662
|
+
end
|
|
1663
|
+
end
|
|
1664
|
+
end
|
|
1665
|
+
|
|
1666
|
+
context 'page status methods' do
|
|
1667
|
+
let(:page) { FactoryGirl.build(:page, public: true, visible: true, restricted: false, locked: false)}
|
|
1668
|
+
|
|
1669
|
+
describe '#status' do
|
|
1670
|
+
it "returns a combined status hash" do
|
|
1671
|
+
expect(page.status).to eq({public: true, visible: true, restricted: false, locked: false})
|
|
1672
|
+
end
|
|
1673
|
+
end
|
|
1674
|
+
|
|
1675
|
+
describe '#status_title' do
|
|
1676
|
+
it "returns a translated status string for public status" do
|
|
1677
|
+
expect(page.status_title(:public)).to eq('Page is published.')
|
|
1678
|
+
end
|
|
1679
|
+
|
|
1680
|
+
it "returns a translated status string for visible status" do
|
|
1681
|
+
expect(page.status_title(:visible)).to eq('Page is visible in navigation.')
|
|
1682
|
+
end
|
|
1683
|
+
|
|
1684
|
+
it "returns a translated status string for locked status" do
|
|
1685
|
+
expect(page.status_title(:locked)).to eq('')
|
|
1686
|
+
end
|
|
1687
|
+
|
|
1688
|
+
it "returns a translated status string for restricted status" do
|
|
1689
|
+
expect(page.status_title(:restricted)).to eq('Page is not restricted.')
|
|
1690
|
+
end
|
|
1691
|
+
end
|
|
1692
|
+
end
|
|
1693
|
+
|
|
1694
|
+
context 'indicate page editors' do
|
|
1695
|
+
let(:page) { Page.new }
|
|
1696
|
+
let(:user) { create(:alchemy_dummy_user, :as_editor) }
|
|
1697
|
+
|
|
1698
|
+
describe '#creator' do
|
|
1699
|
+
before { page.update(creator_id: user.id) }
|
|
1700
|
+
|
|
1701
|
+
it "returns the user that created the page" do
|
|
1702
|
+
expect(page.creator).to eq(user)
|
|
1703
|
+
end
|
|
1704
|
+
|
|
1705
|
+
context 'with user class having a different primary key' do
|
|
1706
|
+
before do
|
|
1707
|
+
allow(Alchemy.user_class)
|
|
1708
|
+
.to receive(:primary_key)
|
|
1709
|
+
.and_return('user_id')
|
|
1710
|
+
|
|
1711
|
+
allow(page)
|
|
1712
|
+
.to receive(:creator_id)
|
|
1713
|
+
.and_return(1)
|
|
1714
|
+
end
|
|
1715
|
+
|
|
1716
|
+
it "returns the user that created the page" do
|
|
1717
|
+
expect(Alchemy.user_class)
|
|
1718
|
+
.to receive(:find_by)
|
|
1719
|
+
.with({'user_id' => 1})
|
|
1720
|
+
|
|
1721
|
+
page.creator
|
|
1722
|
+
end
|
|
1723
|
+
end
|
|
1724
|
+
end
|
|
1725
|
+
|
|
1726
|
+
describe '#updater' do
|
|
1727
|
+
before { page.update(updater_id: user.id) }
|
|
1728
|
+
|
|
1729
|
+
it "returns the user that updated the page" do
|
|
1730
|
+
expect(page.updater).to eq(user)
|
|
1731
|
+
end
|
|
1732
|
+
|
|
1733
|
+
context 'with user class having a different primary key' do
|
|
1734
|
+
before do
|
|
1735
|
+
allow(Alchemy.user_class)
|
|
1736
|
+
.to receive(:primary_key)
|
|
1737
|
+
.and_return('user_id')
|
|
1738
|
+
|
|
1739
|
+
allow(page)
|
|
1740
|
+
.to receive(:updater_id)
|
|
1741
|
+
.and_return(1)
|
|
1742
|
+
end
|
|
1743
|
+
|
|
1744
|
+
it "returns the user that updated the page" do
|
|
1745
|
+
expect(Alchemy.user_class)
|
|
1746
|
+
.to receive(:find_by)
|
|
1747
|
+
.with({'user_id' => 1})
|
|
1748
|
+
|
|
1749
|
+
page.updater
|
|
1750
|
+
end
|
|
1751
|
+
end
|
|
1752
|
+
end
|
|
1753
|
+
|
|
1754
|
+
describe '#locker' do
|
|
1755
|
+
before { page.update(locked_by: user.id) }
|
|
1756
|
+
|
|
1757
|
+
it "returns the user that locked the page" do
|
|
1758
|
+
expect(page.locker).to eq(user)
|
|
1759
|
+
end
|
|
1760
|
+
|
|
1761
|
+
context 'with user class having a different primary key' do
|
|
1762
|
+
before do
|
|
1763
|
+
allow(Alchemy.user_class)
|
|
1764
|
+
.to receive(:primary_key)
|
|
1765
|
+
.and_return('user_id')
|
|
1766
|
+
|
|
1767
|
+
allow(page)
|
|
1768
|
+
.to receive(:locked_by)
|
|
1769
|
+
.and_return(1)
|
|
1770
|
+
end
|
|
1771
|
+
|
|
1772
|
+
it "returns the user that locked the page" do
|
|
1773
|
+
expect(Alchemy.user_class)
|
|
1774
|
+
.to receive(:find_by)
|
|
1775
|
+
.with({'user_id' => 1})
|
|
1776
|
+
|
|
1777
|
+
page.locker
|
|
1778
|
+
end
|
|
1779
|
+
end
|
|
1780
|
+
end
|
|
1781
|
+
|
|
1782
|
+
context 'with user that can not be found' do
|
|
1783
|
+
it 'does not raise not found error' do
|
|
1784
|
+
%w(creator updater locker).each do |user_type|
|
|
1785
|
+
expect {
|
|
1786
|
+
page.send(user_type)
|
|
1787
|
+
}.to_not raise_error
|
|
1788
|
+
end
|
|
1789
|
+
end
|
|
1790
|
+
end
|
|
1791
|
+
|
|
1792
|
+
context 'with user class having a name accessor' do
|
|
1793
|
+
let(:user) { double(name: 'Paul Page') }
|
|
1794
|
+
|
|
1795
|
+
describe '#creator_name' do
|
|
1796
|
+
before { allow(page).to receive(:creator).and_return(user) }
|
|
1797
|
+
|
|
1798
|
+
it "returns the name of the creator" do
|
|
1799
|
+
expect(page.creator_name).to eq('Paul Page')
|
|
1800
|
+
end
|
|
1801
|
+
end
|
|
1802
|
+
|
|
1803
|
+
describe '#updater_name' do
|
|
1804
|
+
before { allow(page).to receive(:updater).and_return(user) }
|
|
1805
|
+
|
|
1806
|
+
it "returns the name of the updater" do
|
|
1807
|
+
expect(page.updater_name).to eq('Paul Page')
|
|
1808
|
+
end
|
|
1809
|
+
end
|
|
1810
|
+
|
|
1811
|
+
describe '#locker_name' do
|
|
1812
|
+
before { allow(page).to receive(:locker).and_return(user) }
|
|
1813
|
+
|
|
1814
|
+
it "returns the name of the current page editor" do
|
|
1815
|
+
expect(page.locker_name).to eq('Paul Page')
|
|
1816
|
+
end
|
|
1817
|
+
end
|
|
1818
|
+
end
|
|
1819
|
+
|
|
1820
|
+
context 'with user class not having a name accessor' do
|
|
1821
|
+
let(:user) { Alchemy.user_class.new }
|
|
1822
|
+
|
|
1823
|
+
describe '#creator_name' do
|
|
1824
|
+
before { allow(page).to receive(:creator).and_return(user) }
|
|
1825
|
+
|
|
1826
|
+
it "returns unknown" do
|
|
1827
|
+
expect(page.creator_name).to eq('unknown')
|
|
1828
|
+
end
|
|
1829
|
+
end
|
|
1830
|
+
|
|
1831
|
+
describe '#updater_name' do
|
|
1832
|
+
before { allow(page).to receive(:updater).and_return(user) }
|
|
1833
|
+
|
|
1834
|
+
it "returns unknown" do
|
|
1835
|
+
expect(page.updater_name).to eq('unknown')
|
|
1836
|
+
end
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
describe '#locker_name' do
|
|
1840
|
+
before { allow(page).to receive(:locker).and_return(user) }
|
|
1841
|
+
|
|
1842
|
+
it "returns unknown" do
|
|
1843
|
+
expect(page.locker_name).to eq('unknown')
|
|
1844
|
+
end
|
|
1845
|
+
end
|
|
1846
|
+
end
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
describe '#controller_and_action' do
|
|
1850
|
+
let(:page) { Page.new }
|
|
1851
|
+
|
|
1852
|
+
context 'if the page has a custom controller defined in its description' do
|
|
1853
|
+
before do
|
|
1854
|
+
allow(page).to receive(:has_controller?).and_return(true)
|
|
1855
|
+
allow(page).to receive(:layout_description).and_return({'controller' => 'comments', 'action' => 'index'})
|
|
1856
|
+
end
|
|
1857
|
+
it "should return a Hash with controller and action key-value pairs" do
|
|
1858
|
+
expect(page.controller_and_action).to eq({controller: '/comments', action: 'index'})
|
|
1859
|
+
end
|
|
1860
|
+
end
|
|
1861
|
+
end
|
|
1862
|
+
|
|
1863
|
+
it_behaves_like "having a hint" do
|
|
1864
|
+
let(:subject) { Page.new }
|
|
1865
|
+
end
|
|
1866
|
+
|
|
1867
|
+
describe '#layout_partial_name' do
|
|
1868
|
+
let(:page) { Page.new(page_layout: 'Standard Page') }
|
|
1869
|
+
|
|
1870
|
+
it "returns a partial renderer compatible name" do
|
|
1871
|
+
expect(page.layout_partial_name).to eq('standard_page')
|
|
1872
|
+
end
|
|
1873
|
+
end
|
|
1874
|
+
|
|
1875
|
+
describe '#published_at' do
|
|
1876
|
+
context 'with published_at date set' do
|
|
1877
|
+
let(:published_at) { Time.now }
|
|
1878
|
+
let(:page) { build_stubbed(:page, published_at: published_at) }
|
|
1879
|
+
|
|
1880
|
+
it "returns the published_at value from database" do
|
|
1881
|
+
expect(page.published_at).to eq(published_at)
|
|
1882
|
+
end
|
|
1883
|
+
end
|
|
1884
|
+
|
|
1885
|
+
context 'with published_at is nil' do
|
|
1886
|
+
let(:updated_at) { Time.now }
|
|
1887
|
+
let(:page) { build_stubbed(:page, published_at: nil, updated_at: updated_at) }
|
|
1888
|
+
|
|
1889
|
+
it "returns the updated_at value" do
|
|
1890
|
+
expect(page.published_at).to eq(updated_at)
|
|
1891
|
+
end
|
|
1892
|
+
end
|
|
1893
|
+
end
|
|
1894
|
+
|
|
1895
|
+
end
|
|
1896
|
+
end
|